Skip to content

Commit a86b85c

Browse files
authored
Fix image generation using FLUX.2 via AI Gateway (#23)
* Fix image generation by using gpt-image-1 via ai gateway * Update model to bfl/flux-2-pro * Remove dalle 2 and 3 support * Remove flash image and its preview * Replace open api key with ai gateway api key * Add example usage of experimental_generateImage for 1024x1024 image --------- Co-authored-by: Chris Tate <ctate@users.noreply.github.com>
1 parent 4cffb3a commit a86b85c

File tree

8 files changed

+45
-42
lines changed

8 files changed

+45
-42
lines changed

app/api/ai/generate/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ Action types:
183183
- Database Query: {"actionType": "Database Query", "dbQuery": "SELECT * FROM table", "dbTable": "table"}
184184
- HTTP Request: {"actionType": "HTTP Request", "httpMethod": "POST", "endpoint": "https://api.example.com", "httpHeaders": "{}", "httpBody": "{}"}
185185
- Generate Text: {"actionType": "Generate Text", "aiModel": "gpt-5", "aiFormat": "text", "aiPrompt": "Your prompt here"}
186-
- Generate Image: {"actionType": "Generate Image", "imageModel": "openai/dall-e-3", "imagePrompt": "Image description"}
186+
- Generate Image: {"actionType": "Generate Image", "imageModel": "bfl/flux-2-pro", "imagePrompt": "Image description"}
187187
- Condition: {"actionType": "Condition", "condition": "{{@nodeId:Label.field}} === 'value'"}
188188
189189
CRITICAL ABOUT CONDITION NODES:

components/workflow/config/action-config.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -501,20 +501,13 @@ function GenerateImageFields({
501501
<Select
502502
disabled={disabled}
503503
onValueChange={(value) => onUpdateConfig("imageModel", value)}
504-
value={(config?.imageModel as string) || "openai/dall-e-3"}
504+
value={(config?.imageModel as string) || "bfl/flux-2-pro"}
505505
>
506506
<SelectTrigger className="w-full" id="imageModel">
507507
<SelectValue placeholder="Select model" />
508508
</SelectTrigger>
509509
<SelectContent>
510-
<SelectItem value="openai/dall-e-3">OpenAI DALL-E 3</SelectItem>
511-
<SelectItem value="openai/dall-e-2">OpenAI DALL-E 2</SelectItem>
512-
<SelectItem value="google/gemini-2.5-flash-image">
513-
Google Gemini 2.5 Flash Image
514-
</SelectItem>
515-
<SelectItem value="google/gemini-2.5-flash-image-preview">
516-
Google Gemini 2.5 Flash Image Preview
517-
</SelectItem>
510+
<SelectItem value="bfl/flux-2-pro">FLUX.2 Pro</SelectItem>
518511
</SelectContent>
519512
</Select>
520513
</div>

lib/codegen-templates/generate-image.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,24 @@
22
* Code template for Generate Image action step
33
* This is a string template used for code generation - keep as string export
44
*/
5-
export default `import OpenAI from 'openai';
5+
export default `import { experimental_generateImage as generateImage } from 'ai';
66
77
export async function generateImageStep(input: {
88
model: string;
99
prompt: string;
1010
}) {
1111
"use step";
1212
13-
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
14-
15-
const response = await openai.images.generate({
16-
model: input.model,
13+
const result = await generateImage({
14+
model: input.model as any,
1715
prompt: input.prompt,
18-
n: 1,
19-
response_format: 'b64_json',
16+
size: '1024x1024',
17+
providerOptions: {
18+
openai: {
19+
apiKey: process.env.AI_GATEWAY_API_KEY,
20+
},
21+
},
2022
});
2123
22-
return { base64: response.data[0].b64_json };
24+
return { base64: result.image.toString() };
2325
}`;

lib/credential-fetcher.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ export type WorkflowCredentials = {
2424
LINEAR_TEAM_ID?: string;
2525
SLACK_API_KEY?: string;
2626
AI_GATEWAY_API_KEY?: string;
27-
OPENAI_API_KEY?: string;
2827
DATABASE_URL?: string;
2928
};
3029

@@ -71,9 +70,6 @@ function mapAiGatewayConfig(config: IntegrationConfig): WorkflowCredentials {
7170
if (config.apiKey) {
7271
creds.AI_GATEWAY_API_KEY = config.apiKey;
7372
}
74-
if (config.openaiApiKey) {
75-
creds.OPENAI_API_KEY = config.openaiApiKey;
76-
}
7773
return creds;
7874
}
7975

lib/steps/generate-image.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77
import "server-only";
88

9-
import OpenAI from "openai";
9+
import { experimental_generateImage as generateImage } from "ai";
1010
import { fetchCredentials } from "../credential-fetcher";
1111

1212
export async function generateImageStep(input: {
@@ -20,26 +20,32 @@ export async function generateImageStep(input: {
2020
? await fetchCredentials(input.integrationId)
2121
: {};
2222

23-
const apiKey = credentials.OPENAI_API_KEY || credentials.AI_GATEWAY_API_KEY;
23+
const apiKey = credentials.AI_GATEWAY_API_KEY;
2424

2525
if (!apiKey) {
2626
throw new Error(
27-
"OPENAI_API_KEY or AI_GATEWAY_API_KEY is not configured. Please add it in Project Integrations."
27+
"AI_GATEWAY_API_KEY is not configured. Please add it in Project Integrations."
2828
);
2929
}
3030

31-
const openai = new OpenAI({ apiKey });
32-
33-
const response = await openai.images.generate({
34-
model: input.model,
31+
const result = await generateImage({
32+
// biome-ignore lint/suspicious/noExplicitAny: model string needs type coercion for ai package
33+
model: input.model as any,
3534
prompt: input.prompt,
36-
n: 1,
37-
response_format: "b64_json",
35+
size: "1024x1024",
36+
providerOptions: {
37+
openai: {
38+
apiKey,
39+
},
40+
},
3841
});
3942

40-
if (!response.data?.[0]) {
43+
if (!result.image) {
4144
throw new Error("Failed to generate image");
4245
}
4346

44-
return { base64: response.data[0].b64_json };
47+
// Convert the GeneratedFile to base64 string
48+
const base64 = result.image.toString();
49+
50+
return { base64 };
4551
}

lib/steps/generate-text.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ export async function generateTextStep(input: {
6363
? await fetchCredentials(input.integrationId)
6464
: {};
6565

66-
const apiKey = credentials.AI_GATEWAY_API_KEY || credentials.OPENAI_API_KEY;
66+
const apiKey = credentials.AI_GATEWAY_API_KEY;
6767

6868
if (!apiKey) {
6969
throw new Error(
70-
"AI_GATEWAY_API_KEY or OPENAI_API_KEY is not configured. Please add it in Project Integrations."
70+
"AI_GATEWAY_API_KEY is not configured. Please add it in Project Integrations."
7171
);
7272
}
7373

lib/workflow-codegen-sdk.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -304,14 +304,14 @@ function _generateGenerateImageStepBody(
304304
const imagePrompt = (config.imagePrompt as string) || "";
305305
const convertedImagePrompt = convertTemplateToJS(imagePrompt);
306306

307-
return ` const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
307+
return ` const openai = new OpenAI({ apiKey: process.env.AI_GATEWAY_API_KEY });
308308
309309
// Use template literal with dynamic values from outputs
310310
const imagePrompt = \`${escapeForTemplateLiteral(convertedImagePrompt)}\`;
311311
const finalPrompt = (input.imagePrompt as string) || imagePrompt;
312312
313313
const response = await openai.images.generate({
314-
model: '${config.imageModel || "dall-e-3"}',
314+
model: '${config.imageModel || "bfl/flux-2-pro"}',
315315
prompt: finalPrompt,
316316
n: 1,
317317
response_format: 'b64_json',
@@ -503,12 +503,15 @@ export function generateWorkflowSDKCode(
503503
}
504504

505505
function buildAIImageParams(config: Record<string, unknown>): string[] {
506-
imports.add("import OpenAI from 'openai';");
507-
const imageModel = (config.imageModel as string) || "dall-e-3";
506+
imports.add(
507+
"import { experimental_generateImage as generateImage } from 'ai';"
508+
);
509+
const imageModel = (config.imageModel as string) || "bfl/flux-2-pro";
508510
return [
509511
`model: "${imageModel}"`,
510512
`prompt: \`${convertTemplateToJS((config.imagePrompt as string) || "")}\``,
511-
"apiKey: process.env.OPENAI_API_KEY!",
513+
'size: "1024x1024"',
514+
"providerOptions: { openai: { apiKey: process.env.AI_GATEWAY_API_KEY! } }",
512515
];
513516
}
514517

lib/workflow-codegen.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,17 +438,20 @@ export function generateWorkflowCode(
438438
indent: string,
439439
varName: string
440440
): string[] {
441-
imports.add("import { generateImage } from './integrations/ai';");
441+
imports.add(
442+
"import { experimental_generateImage as generateImage } from 'ai';"
443+
);
442444
const imagePrompt =
443445
(node.data.config?.imagePrompt as string) || "A beautiful landscape";
444446
const imageModel =
445-
(node.data.config?.imageModel as string) || "openai/dall-e-3";
447+
(node.data.config?.imageModel as string) || "bfl/flux-2-pro";
446448

447449
return [
448450
`${indent}// Generate image using AI`,
449451
`${indent}const ${varName} = await generateImage({`,
450452
`${indent} model: "${imageModel}",`,
451453
`${indent} prompt: \`${imagePrompt}\`,`,
454+
`${indent} size: "1024x1024",`,
452455
`${indent}});`,
453456
];
454457
}

0 commit comments

Comments
 (0)