返回 presentation-ai
generate.ts
根目录 / src / app / _actions / apps / image-studio / generate.ts
1 "use server";
2
3 import { utapi } from "@/app/api/uploadthing/core";
4 import {
5 DEFAULT_IMAGE_MODEL,
6 getFalImageGenerationInput,
7 type ImageAspectRatio,
8 type ImageModelList,
9 } from "@/constants/image-models";
10 import { env } from "@/env";
11 import { requireOptionalIntegration } from "@/lib/env/optional-integrations";
12 import { auth } from "@/server/auth";
13 import { db } from "@/server/db";
14 import { fal } from "@fal-ai/client";
15 import { UTFile } from "uploadthing/server";
16
17 async function persistGeneratedImage(
18 imageUrl: string,
19 prompt: string,
20 userId: string,
21 filePrefix: string,
22 ) {
23 const imageResponse = await fetch(imageUrl);
24 if (!imageResponse.ok) {
25 throw new Error("Failed to download generated image");
26 }
27
28 const imageBlob = await imageResponse.blob();
29 const imageBuffer = await imageBlob.arrayBuffer();
30 const filename = `${filePrefix}_${Date.now()}.png`;
31 const utFile = new UTFile([new Uint8Array(imageBuffer)], filename);
32 const uploadResult = await utapi.uploadFiles([utFile]);
33
34 if (!uploadResult[0]?.data?.ufsUrl) {
35 throw new Error("Failed to upload generated image");
36 }
37
38 return db.generatedImage.create({
39 data: {
40 url: uploadResult[0].data.ufsUrl,
41 prompt,
42 userId,
43 },
44 });
45 }
46
47 async function generateFalImage(
48 prompt: string,
49 model: ImageModelList,
50 userId: string,
51 aspectRatio: ImageAspectRatio,
52 ) {
53 const falConfig = requireOptionalIntegration({
54 integration: "FAL",
55 envVar: "FAL_API_KEY",
56 value: env.FAL_API_KEY,
57 feature: "AI image generation",
58 });
59
60 if (!falConfig.ok) {
61 return {
62 success: false,
63 error: falConfig.error,
64 };
65 }
66
67 fal.config({
68 credentials: falConfig.value,
69 });
70
71 const result = await fal.subscribe(model, {
72 input: getFalImageGenerationInput({ model, prompt, aspectRatio }),
73 });
74
75 const imageUrl = result.data?.images?.[0]?.url;
76 if (!imageUrl) {
77 throw new Error("Failed to generate image");
78 }
79
80 const image = await persistGeneratedImage(imageUrl, prompt, userId, "image");
81
82 return {
83 success: true,
84 image,
85 };
86 }
87
88 export async function generateImageAction(
89 prompt: string,
90 model: ImageModelList = DEFAULT_IMAGE_MODEL,
91 aspectRatio: ImageAspectRatio = "16:9",
92 ) {
93 const session = await auth();
94
95 if (!session?.user?.id) {
96 return {
97 success: false,
98 error: "You must be logged in to generate images",
99 };
100 }
101
102 try {
103 const actualModel = session.user.isAdmin ? model : DEFAULT_IMAGE_MODEL;
104 return await generateFalImage(
105 prompt,
106 actualModel,
107 session.user.id,
108 aspectRatio,
109 );
110 } catch (error) {
111 console.error("Error generating image:", error);
112 return {
113 success: false,
114 error:
115 error instanceof Error ? error.message : "Failed to generate image",
116 };
117 }
118 }
119
119 lines TYPESCRIPT