ToonFlow最新版本 配置 Gemini AI 接口完整教程
ToonFlow 是一款强大的 AI 工作流工具,支持通过自定义适配器接入各种 AI 服务。本文将详细介绍如何在 ToonFlow 中配置。
·
ToonFlow最新版本 配置 Gemini AI 接口完整教程
前言
ToonFlow 是一款强大的 AI 工作流工具,支持通过自定义适配器接入各种 AI 服务。本文将详细介绍如何在 ToonFlow 中配置 Gemini AI 接口,实现:
- 💬 文本对话 - Gemini 3 Flash Preview
- 🎨 图像生成 - Gemini 2.5/3.1 Flash Image
- 🎬 视频生成 - Veo 2/3 系列模型
- 🔊 语音合成 - Gemini TTS(30+ 种音色)
准备工作
1. 获取 API 密钥
访问 32ai 平台 注册并获取 API Key。
2. 确认 ToonFlow 版本
确保 ToonFlow 已更新到支持自定义适配器的版本。为最新版本哦
配置文件
下载地址:点击
//如需遥测AI请使用在toonflow安装目录运行npx @ai-sdk/devtools (要求在其他设置中打开遥测功能,且toonflow有权限在安装目录创建.devtools文件夹)
// ==================== 类型定义 ====================
// 文本模型
interface TextModel {
name: string; // 显示名称
modelName: string;
type: "text";
think: boolean; // 前端显示用
}
// 图像模型
interface ImageModel {
name: string; // 显示名称
modelName: string;
type: "image";
mode: ("text" | "singleImage" | "multiReference")[];
}
// 视频模型
interface VideoModel {
name: string; // 显示名称
modelName: string; //全局唯一
type: "video";
mode: (
| "singleImage" // 单图
| "startEndRequired" // 首尾帧(两张都得有)
| "endFrameOptional" // 首尾帧(尾帧可选)
| "startFrameOptional" // 首尾帧(首帧可选)
| "text" // 文本生视频
| ("videoReference" | "imageReference" | "audioReference" | "textReference")[]
)[]; // 混合参考
audio: "optional" | false | true; // 音频配置
durationResolutionMap: { duration: number[]; resolution: string[] }[];
}
interface TTSModel {
name: string; // 显示名称
modelName: string;
type: "tts";
voices: {
title: string; //显示名称
voice: string; //说话人
}[];
}
// 供应商配置
interface VendorConfig {
id: string; //供应商唯一标识,必须全局唯一
author: string;
description?: string; //md5格式
name: string;
icon?: string; //仅支持base64格式
inputs: {
key: string;
label: string;
type: "text" | "password" | "url";
required: boolean;
placeholder?: string;
}[];
inputValues: Record<string, string>;
models: (TextModel | ImageModel | VideoModel | TTSModel)[];
}
// ==================== 全局工具函数 ====================
//Axios实例
//压缩图片大小(1MB = 1 * 1024 * 1024)
declare const zipImage: (completeBase64: string, size: number) => Promise<string>;
//压缩图片分辨率
declare const zipImageResolution: (completeBase64: string, width: number, height: number) => Promise<string>;
//多图拼接乘单图 maxSize 最大输出大小,默认为 10mb
declare const mergeImages: (completeBase64: string[], maxSize?: string) => Promise<string>;
//Url转Base64
declare const urlToBase64: (url: string) => Promise<string>;
//轮询函数
declare const pollTask: (
fn: () => Promise<{ completed: boolean; data?: string; error?: string }>,
interval?: number,
timeout?: number,
) => Promise<{ completed: boolean; data?: string; error?: string }>;
declare const axios: any;
declare const createOpenAI: any;
declare const createDeepSeek: any;
declare const createZhipu: any;
declare const createQwen: any;
declare const createAnthropic: any;
declare const createOpenAICompatible: any;
declare const createXai: any;
declare const createMinimax: any;
declare const createGoogleGenerativeAI: any;
declare const logger: (logstring: string) => void;
declare const jsonwebtoken: any;
// ==================== 公共配置 ====================
// 公共 TTS 语音配置
const commonTTSVoices = [
{ title: "Zephyr - 明亮", voice: "Zephyr" },
{ title: "Puck - 欢快", voice: "Puck" },
{ title: "Charon - 信息丰富", voice: "Charon" },
{ title: "Kore - Firm", voice: "Kore" },
{ title: "Fenrir - Excitable", voice: "Fenrir" },
{ title: "Leda - 青春", voice: "Leda" },
{ title: "Orus - 公司", voice: "Orus" },
{ title: "Aoede - Breezy", voice: "Aoede" },
{ title: "Callirrhoe - 轻松", voice: "Callirrhoe" },
{ title: "Autonoe - 明亮", voice: "Autonoe" },
{ title: "Enceladus - 气声", voice: "Enceladus" },
{ title: "Iapetus - 清晰", voice: "Iapetus" },
{ title: "Umbriel - 轻松愉快", voice: "Umbriel" },
{ title: "Algieba - 平滑", voice: "Algieba" },
{ title: "Despina - 平滑", voice: "Despina" },
{ title: "Erinome - 清除", voice: "Erinome" },
{ title: "Algenib - Gravelly", voice: "Algenib" },
{ title: "Rasalgethi - 信息丰富", voice: "Rasalgethi" },
{ title: "Laomedeia - 欢快", voice: "Laomedeia" },
{ title: "Achernar - 软", voice: "Achernar" },
{ title: "Alnilam - Firm", voice: "Alnilam" },
{ title: "Schedar - Even", voice: "Schedar" },
{ title: "Gacrux - 成熟", voice: "Gacrux" },
{ title: "Pulcherrima - 转发", voice: "Pulcherrima" },
{ title: "Achird - 友好", voice: "Achird" },
{ title: "Zubenelgenubi - 随意", voice: "Zubenelgenubi" },
{ title: "Vindemiatrix - 温和", voice: "Vindemiatrix" },
{ title: "Sadachbia - 活泼", voice: "Sadachbia" },
{ title: "Sadaltager - 知识渊博", voice: "Sadaltager" },
{ title: "Sulafat - 偏高", voice: "Sulafat" }
];
// ==================== 供应商数据 ====================
const vendor: VendorConfig = {
id: "32ai-gemini",
author: "32ai",
description: "32ai Gemini AI标准格式接口。",
name: "32ai-gemini",
icon: "https://lsky.zhongzhuan.chat/i/2026/02/05/69844b7fef18e.ico",
inputs: [
{ key: "apiKey", label: "API密钥", type: "password", required: true },
],
inputValues: {
apiKey: "",
baseUrl: "https://32ai.uk",
},
models: [
{
name: "gemini-3-flash-preview",
modelName: "gemini-3-flash-preview",
type: "text",
think: false
},
{
name: "gemini-2.5-flash-image",
type: "image",
modelName: "gemini-2.5-flash-image",
mode: ["text", "singleImage", "multiReference"]
},
{
name: "gemini-2.5-flash-image-preview",
type: "image",
modelName: "gemini-2.5-flash-image-preview",
mode: ["text", "singleImage", "multiReference"]
},
{
name: "gemini-3.1-flash-image-preview",
type: "image",
modelName: "gemini-3.1-flash-image-preview",
mode: ["text", "singleImage", "multiReference"]
},
{
name: "gemini-3-pro-image-preview",
type: "image",
modelName: "gemini-3-pro-image-preview",
mode: ["text", "singleImage", "multiReference"]
},
// {
// name: "gemini-2.5-flash-preview-tts",
// type: "tts",
// modelName: "gemini-2.5-flash-preview-tts",
// voices: commonTTSVoices
// },
// {
// name: "gemini-2.5-pro-preview-tts",
// type: "tts",
// modelName: "gemini-2.5-pro-preview-tts",
// voices: commonTTSVoices
// },
{
name: "veo3.1",
type: "video",
modelName: "veo3.1",
mode: ["text", "singleImage", "startEndRequired", "endFrameOptional"],
audio: "optional",
durationResolutionMap: [
{
duration: [8],
resolution: ["1080p"]
}
],
},
{
name: "veo3.1-4k",
type: "video",
modelName: "veo3.1-4k",
mode: ["text", "singleImage", "startEndRequired", "endFrameOptional"],
audio: "optional",
durationResolutionMap: [
{
duration: [8],
resolution: ["4k"]
}
],
},
{
name: "veo3.1-pro",
type: "video",
modelName: "veo3.1-pro",
mode: ["text", "singleImage", "startEndRequired", "endFrameOptional"],
audio: "optional",
durationResolutionMap: [
{
duration: [8],
resolution: ["1080p"]
}
],
},
{
name: "veo3.1-pro-4k",
type: "video",
modelName: "veo3.1-pro-4k",
mode: ["text", "singleImage", "startEndRequired", "endFrameOptional"],
audio: "optional",
durationResolutionMap: [
{
duration: [8],
resolution: ["4k"]
}
],
},
{
name: "veo3-pro-frames",
type: "video",
modelName: "veo3-pro-frames",
mode: ["text", "endFrameOptional"],
audio: "optional",
durationResolutionMap: [
{
duration: [8],
resolution: ["1080p"]
}
],
},
{
name: "veo3.1-components",
type: "video",
modelName: "veo3.1-components",
mode: [["imageReference"]],
audio: "optional",
durationResolutionMap: [
{
duration: [8],
resolution: ["1080p"]
}
],
},
{
name: "veo3.1-fast-components",
type: "video",
modelName: "veo3.1-fast-components",
mode: [["imageReference"]],
audio: "optional",
durationResolutionMap: [
{
duration: [8],
resolution: ["1080p"]
}
],
},
{
name: "veo3.1-fast",
type: "video",
modelName: "veo3.1-fast",
mode: ["text", "singleImage", "startEndRequired", "endFrameOptional"],
audio: "optional",
durationResolutionMap: [
{
duration: [8],
resolution: ["1080p"]
}
],
},
{
name: "veo3",
type: "video",
modelName: "veo3",
mode: ["text", "singleImage", "startEndRequired", "endFrameOptional"],
audio: "optional",
durationResolutionMap: [
{
duration: [8],
resolution: ["1080p"]
}
],
},
{
name: "veo3-fast",
type: "video",
modelName: "veo3-fast",
mode: ["text", "singleImage", "startEndRequired", "endFrameOptional"],
audio: "optional",
durationResolutionMap: [
{
duration: [8],
resolution: ["1080p"]
}
],
},
{
name: "veo3-fast-frames",
type: "video",
modelName: "veo3-fast-frames",
mode: ["text", "endFrameOptional"],
audio: "optional",
durationResolutionMap: [
{
duration: [8],
resolution: ["1080p"]
}
],
},
{
name: "veo3-frames",
type: "video",
modelName: "veo3-frames",
mode: ["text", "endFrameOptional"],
audio: "optional",
durationResolutionMap: [
{
duration: [8],
resolution: ["1080p"]
}
],
},
{
name: "veo3-pro",
type: "video",
modelName: "veo3-pro",
mode: ["text", "singleImage", "startEndRequired", "endFrameOptional"],
audio: "optional",
durationResolutionMap: [
{
duration: [8],
resolution: ["1080p"]
}
],
},
{
name: "veo2",
type: "video",
modelName: "veo2",
mode: ["text", "singleImage", "startEndRequired", "endFrameOptional"],
audio: "optional",
durationResolutionMap: [
{
duration: [5,6,7,8],
resolution: ["720p"]
}
],
},
{
name: "veo2-fast",
type: "video",
modelName: "veo2-fast",
mode: ["text", "singleImage", "startEndRequired", "endFrameOptional"],
audio: "optional",
durationResolutionMap: [
{
duration: [5,6,7,8],
resolution: ["720p"]
}
],
},
{
name: "veo2-fast-components",
type: "video",
modelName: "veo2-fast-components",
mode: [["imageReference"]],
audio: "optional",
durationResolutionMap: [
{
duration: [5,6,7,8],
resolution: ["720p"]
}
],
},
{
name: "veo2-fast-frames",
type: "video",
modelName: "veo2-fast-frames",
mode: ["text", "startEndRequired"],
audio: "optional",
durationResolutionMap: [
{
duration: [5,6,7,8],
resolution: ["720p"]
}
],
},
{
name: "veo2-pro",
type: "video",
modelName: "veo2-pro",
mode: ["text", "singleImage", "startEndRequired", "endFrameOptional"],
audio: "optional",
durationResolutionMap: [
{
duration: [5,6,7,8],
resolution: ["720p"]
}
],
},
{
name: "veo2-pro-components",
type: "video",
modelName: "veo2-pro-components",
mode: [["imageReference"]],
audio: "optional",
durationResolutionMap: [
{
duration: [5,6,7,8],
resolution: ["720p"]
}
],
},
],
};
exports.vendor = vendor;
// ==================== 适配器函数 ====================
// 文本请求函数
const textRequest: (textModel: TextModel) => { url: string; model: string } = (textModel) => {
if (!vendor.inputValues.apiKey) throw new Error("缺少API Key");
const apiKey = vendor.inputValues.apiKey.replace("Bearer ", "");
return createOpenAI({
baseURL: vendor.inputValues.baseUrl + "/v1",
apiKey: apiKey,
}).chat(textModel.modelName);
};
exports.textRequest = textRequest;
//图片请求函数
interface ImageConfig {
prompt: string; //图片提示词
imageBase64: string[]; //输入的图片提示词
size: "1K" | "2K" | "4K"; // 图片尺寸
aspectRatio: `${number}:${number}`; // 长宽比
}
const imageRequest = async (imageConfig: ImageConfig, imageModel: ImageModel) => {
if (!vendor.inputValues.apiKey) throw new Error("缺少API Key");
const apiKey = vendor.inputValues.apiKey.replace("Bearer ", "");
// 构建 Gemini 原生 API 请求 URL
const url = `${vendor.inputValues.baseUrl}/v1beta/models/${imageModel.modelName}:generateContent?key=${apiKey}`;
// 构建请求体
// 定义支持 imageSize 的模型列表
const supportsImageSizeModels = [
"gemini-3.1-flash-image-preview",
"gemini-3-pro-image-preview"
];
const imageConfigObj: any = {
aspectRatio: imageConfig.aspectRatio || "1:1"
};
// 只有特定模型支持 imageSize 参数
if (supportsImageSizeModels.includes(imageModel.modelName)) {
imageConfigObj.imageSize = imageConfig.size || "1K";
}
const requestBody: any = {
contents: [
{
role: "user",
parts: []
}
],
generationConfig: {
responseModalities: ["IMAGE"],
imageConfig: imageConfigObj
}
};
// 添加文本提示词
if (imageConfig.prompt) {
requestBody.contents[0].parts.push({
text: imageConfig.prompt
});
}
// 添加参考图片(如果有的话)
if (imageConfig.imageBase64 && imageConfig.imageBase64.length > 0) {
for (const base64Image of imageConfig.imageBase64) {
// 移除 base64 前缀(如果存在)
const cleanBase64 = base64Image.replace(/^data:image\/[^;]+;base64,/, "");
// 检测图片类型
const mimeType = base64Image.match(/^data:(image\/[^;]+);base64,/)?.[1] || "image/png";
requestBody.contents[0].parts.push({
inlineData: {
mimeType: mimeType,
data: cleanBase64
}
});
}
}
try {
const response = await axios.post(url, requestBody, {
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + apiKey
},
timeout: 600000 // 10分钟超时
});
// 解析响应,提取图片数据
const candidates = response.data?.candidates;
if (!candidates || candidates.length === 0) {
throw new Error("API 返回空响应");
}
const parts = candidates[0]?.content?.parts;
if (!parts || parts.length === 0) {
throw new Error("API 返回内容为空");
}
// 查找图片数据
for (const part of parts) {
if (part.inlineData && part.inlineData.data) {
// 返回 base64 图片数据
return part.inlineData.data;
}
}
throw new Error("API 响应中未找到图片数据");
} catch (error: any) {
if (error.response) {
throw new Error(`Gemini API 错误: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
}
throw error;
}
};
exports.imageRequest = imageRequest;
interface VideoConfig {
duration: number;
resolution: string;
aspectRatio: "16:9" | "9:16";
prompt: string;
imageBase64?: string[];
audio?: boolean;
mode:
| "singleImage" // 单图
| "multiImage" // 多图模式
| "gridImage" // 网格单图(传入一张图片,但该图片是网格图)
| "startEndRequired" // 首尾帧(两张都得有)
| "endFrameOptional" // 首尾帧(尾帧可选)
| "startFrameOptional" // 首尾帧(首帧可选)
| "text" // 文本生视频
| ("video" | "image" | "audio" | "text")[]; // 混合参考
}
const SUCCESS_TASK_STATUS = ["video_generation_completed", "succeeded", "completed", "success"];
const FAILED_TASK_STATUS = ["failed", "failure", "error", "canceled", "cancelled", "video_generation_failed"];
const videoRequest = async (videoConfig: VideoConfig, videoModel: VideoModel) => {
if (!vendor.inputValues.apiKey) throw new Error("缺少API Key");
const apiKey = vendor.inputValues.apiKey.replace("Bearer ", "");
// 定义只支持 16:9 的模型列表
const only16x9Models = ["veo3", "veo3-fast"];
// 构建请求体
const requestBody: any = {
prompt: videoConfig.prompt,
model: videoModel.modelName,
enhance_prompt: true,
enable_upsample: true,
aspect_ratio: only16x9Models.includes(videoModel.modelName) ? "16:9" : (videoConfig.aspectRatio || "16:9")
};
// 处理图片输入(首尾帧或单图),最多支持3张
if (videoConfig.imageBase64 && videoConfig.imageBase64.length > 0) {
const maxImages = 3;
const images = videoConfig.imageBase64.slice(0, maxImages);
requestBody.images = images;
}
// 创建视频任务
const createUrl = `${vendor.inputValues.baseUrl}/v1/video/create`;
const createResponse = await axios.post(createUrl, requestBody, {
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + apiKey
},
timeout: 600000 // 10分钟超时
});
const taskId = createResponse.data?.id;
if (!taskId) {
throw new Error(`视频任务创建失败: ${JSON.stringify(createResponse.data)}`);
}
// 轮询查询任务状态
const queryUrl = `${vendor.inputValues.baseUrl}/v1/video/query?id=${taskId}`;
const result = await pollTask(async () => {
const queryResponse = await axios.get(queryUrl, {
headers: {
"Authorization": "Bearer " + apiKey
},
timeout: 600000 // 10分钟超时
});
const data = queryResponse.data;
const status = (data?.detail?.status || data?.status)?.toLowerCase();
// 检查是否完成
if (SUCCESS_TASK_STATUS.includes(status)) {
const videoUrl = data?.detail?.video_url;
if (videoUrl) {
return { completed: true, data: videoUrl };
}
return { completed: true, error: "视频生成完成但未返回视频URL" };
}
// 检查是否失败
if (FAILED_TASK_STATUS.includes(status)) {
return { completed: true, error: `视频生成失败: ${JSON.stringify(data)}` };
}
// 仍在处理中
return { completed: false };
}, 5000, 600000); // 每5秒轮询一次,最长10分钟
if (result.error) {
throw new Error(result.error);
}
return result.data;
};
exports.videoRequest = videoRequest;
interface TTSConfig {
text: string;
voice: string;
speechRate: number;
pitchRate: number;
volume: number;
}
const ttsRequest = async (ttsConfig: TTSConfig, ttsModel: TTSModel) => {
if (!vendor.inputValues.apiKey) throw new Error("缺少API Key");
const apiKey = vendor.inputValues.apiKey.replace("Bearer ", "");
// 构建 Gemini 原生 API 请求 URL
const url = `${vendor.inputValues.baseUrl}/v1beta/models/${ttsModel.modelName}:generateContent?key=${apiKey}`;
// 构建请求体
const requestBody: any = {
contents: [
{
parts: [
{
text: ttsConfig.text
}
]
}
],
generationConfig: {
responseModalities: ["AUDIO"],
speechConfig: {
voiceConfig: {
prebuiltVoiceConfig: {
voiceName: ttsConfig.voice || "Kore"
}
}
}
},
model: ttsModel.modelName
};
try {
const response = await axios.post(url, requestBody, {
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + apiKey
},
timeout: 600000 // 10分钟超时
});
// 解析响应,提取音频数据
const candidates = response.data?.candidates;
if (!candidates || candidates.length === 0) {
throw new Error("API 返回空响应");
}
const parts = candidates[0]?.content?.parts;
if (!parts || parts.length === 0) {
throw new Error("API 返回内容为空");
}
// 查找音频数据
for (const part of parts) {
if (part.inlineData && part.inlineData.data) {
// 返回 base64 音频数据
return part.inlineData.data;
}
}
throw new Error("API 响应中未找到音频数据");
} catch (error: any) {
if (error.response) {
throw new Error(`Gemini API 错误: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
}
throw error;
}
};
exports.ttsRequest = ttsRequest;
原创声明:本文为原创教程,转载请注明出处。
欢迎在评论区交流讨论!
更多推荐




所有评论(0)