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;




原创声明:本文为原创教程,转载请注明出处。

欢迎在评论区交流讨论!

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐