Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { defineTool } from '@tool/type';
import { FlowNodeInputTypeEnum, WorkflowIOValueTypeEnum } from '@tool/type/fastgpt';

export default defineTool({
name: {
'zh-CN': 'Nano Banana 文生图',
en: 'Nano Banana Text-to-Image'
},
description: {
'zh-CN': '使用Nano Banana模型将文本描述转换为图像。',
en: 'Convert text descriptions to images using Nano Banana models.'
},
toolDescription: 'Convert text descriptions to images using Nano Banana models.',
versionList: [
{
value: '0.1.0',
description: 'Default version',
inputs: [
{
key: 'text',
label: '提示词',
description: '生成图片的提示词',
toolDescription: '生成图片的提示词',
placeholder: '描述图片内容, 如: 生成一个关于人工智能的图片',
renderTypeList: [FlowNodeInputTypeEnum.input, FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.string,
required: true
},
{
key: 'aspect_ratio',
label: '宽高比',
description: '图像的宽高比,例如 "1:1", "16:9", "3:4" 等,支持从 1:1 到 21:9',
renderTypeList: [FlowNodeInputTypeEnum.select, FlowNodeInputTypeEnum.reference],
defaultValue: '1:1',
valueType: WorkflowIOValueTypeEnum.string,
required: true,
list: [
{ label: '1:1', value: '1:1' },
{ label: '2:3', value: '2:3' },
{ label: '3:2', value: '3:2' },
{ label: '3:4', value: '3:4' },
{ label: '4:3', value: '4:3' },
{ label: '4:5', value: '4:5' },
{ label: '5:4', value: '5:4' },
{ label: '9:16', value: '9:16' },
{ label: '16:9', value: '16:9' },
{ label: '21:9', value: '21:9' }
]
}
],
outputs: [
{
valueType: WorkflowIOValueTypeEnum.string,
key: 'imageUrl',
label: '图片',
description: '生成的图片'
}
]
}
]
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import config from './config';
import { InputType, OutputType, tool as toolCb } from './src';
import { exportTool } from '@tool/utils/tool';

export default exportTool({
toolCb,
InputType,
OutputType,
config
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { z } from 'zod';
import { POST } from '@tool/utils/request';
import { uploadFile } from '@tool/utils/uploadFile';

export const InputType = z.object({
apiKey: z.string(),
text: z.string(),
aspect_ratio: z.enum(['1:1', '2:3', '3:4', '4:3', '2:1', '3:2', '16:9', '9:16', '21:9', '9:21'])
});

export const OutputType = z.object({
imageUrl: z.string()
});

const OPENROUTER_BASE_URL = 'https://openrouter.ai/api/v1/chat/completions';

export async function tool({
apiKey,
text,
aspect_ratio
}: z.infer<typeof InputType>): Promise<z.infer<typeof OutputType>> {
const token = `Bearer ${apiKey}`;
const { data } = await POST(
OPENROUTER_BASE_URL,
{
model: 'google/gemini-2.5-flash-image-preview',
messages: [
{
role: 'user',
content: text,
modalities: ['image', 'text'],
image_config: {
aspect_ratio: aspect_ratio
}
}
]
},
{
headers: {
Authorization: token,
'Content-Type': 'application/json'
}
}
);

// modal response is a base64 string
const dataUrl = data.choices[0].message.images[0].image_url.url;
if (!dataUrl || !dataUrl.startsWith('data:')) {
return Promise.reject('Failed to generate image');
}

const match = dataUrl.match(/^data:([^;]+);base64,/);
const mime = match?.[1];
const ext = (() => {
const m = mime.split('/')[1];
return m && m.length > 0 ? m : 'png';
})();
const defaultFilename = `image.${ext}`;

const meta = await uploadFile({ base64: dataUrl, defaultFilename });
if (!meta.accessUrl) {
return Promise.reject('Failed to upload image');
}
return {
imageUrl: meta.accessUrl
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { expect, test } from 'vitest';
import tool from '../index';

test(async () => {
expect(tool.name).toBeDefined();
expect(tool.description).toBeDefined();
expect(tool.cb).toBeDefined();
});
25 changes: 25 additions & 0 deletions modules/tool/packages/openrouterMultiModal/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { defineToolSet } from '@tool/type';
import { ToolTypeEnum } from '@tool/type/tool';

export default defineToolSet({
name: {
'zh-CN': 'OpenRouter 多模态',
en: 'OpenRouter Multi-Modal'
},
courseUrl: 'https://openrouter.ai/docs/quickstart',
type: ToolTypeEnum.multimodal,
description: {
'zh-CN': '这是一个OpenRouter 多模态工具集,支持调用多种OpenRouter平台提供的模型服务',
en: 'This is an OpenRouter multi-modal tool set, supporting various model services provided by the OpenRouter platform'
},
toolDescription:
'This is an OpenRouter multi-modal tool set, supporting various model services provided by the OpenRouter platform',
secretInputConfig: [
{
key: 'apiKey',
label: 'API Key',
required: true,
inputType: 'secret'
}
]
});
8 changes: 8 additions & 0 deletions modules/tool/packages/openrouterMultiModal/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// You should not modify this file, if you need to modify the tool set configuration, please modify the config.ts file

import config from './config';
import { exportToolSet } from '@tool/utils/tool';

export default exportToolSet({
config
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions modules/tool/packages/openrouterMultiModal/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@fastgpt-plugins/tool-openrouter-multi-modal",
"module": "index.ts",
"type": "module",
"scripts": {
"build": "bun ../../../../scripts/build.ts"
},
"devDependencies": {
"@types/bun": "latest"
},
"peerDependencies": {
"typescript": "^5.0.0"
},
"dependencies": {
"zod": "^3.24.2"
}
}