# 模型生成接口整理(按当前代码) 整理依据为当前源码,不沿用旧文档结论。主要代码入口: - `src/app/api/generate/route.ts` - `src/app/api/generate/providers/*.ts` - `src/app/api/generate/poll/route.ts` - `src/app/api/llm/route.ts` - `src/store/execution/*Executor.ts` ## 1. 项目内部接口 | 内部接口 | 方法 | 当前调用方 | 作用 | | --- | --- | --- | --- | | `/api/generate` | POST | `nanoBananaExecutor`、`generateVideoExecutor`、`generateAudioExecutor`、`generate3DExecutor` | 图片、视频、音频、3D 统一入口。按 `selectedModel.provider` 分发。 | | `/api/generate/poll` | POST | `pollTaskCompletion.ts` | 只用于 Kie.ai。`/api/generate` 返回 `polling: true` 后前端继续轮询。 | | `/api/llm` | POST | `llmGenerateExecutor.ts` | LLM Generate 节点文本生成,不走 `/api/generate`。 | | `/api/models` | GET | 模型选择/搜索 UI | 获取模型列表。 | | `/api/models/[modelId]?provider=...` | GET | 模型参数面板/动态输入 | 获取模型参数和输入 schema。 | ## 2. `/api/generate` 当前分发逻辑 `src/app/api/generate/route.ts` 当前按 `selectedModel.provider` 分发: | Provider | 调用函数 | 文件 | | --- | --- | --- | | `newapiwg` | `generateWithNewApiWG(...)` | `providers/newapiwg.ts` | | `replicate` | `generateWithReplicate(...)` | `providers/replicate.ts` | | `fal` | `generateWithFalQueue(...)` | `providers/fal.ts` | | `kie` | `submitKieTask(...)`,立即返回轮询信息 | `providers/kie.ts` | | `wavespeed` | `generateWithWaveSpeed(...)` | `providers/wavespeed.ts` | | 默认/`gemini` | `generateWithGemini(...)` 或 `generateWithGeminiVideo(...)` | `providers/gemini.ts` | `newapiwg` 会把 `aspectRatio`、`resolution` 合并进 `parameters`,再交给 provider 文件处理。其他 provider 基本保留 `images`、`prompt`、`parameters`、`dynamicInputs`,只过滤空值。 ## 3. 同步返回类接口 这里的“同步”指前端只调用一次项目内部接口。即使服务端内部轮询,也不会让前端调用 `/api/generate/poll`。 ### 3.1 Gemini 图片 代码:`src/app/api/generate/providers/gemini.ts` | 上游调用 | 方法 | 当前用途 | | --- | --- | --- | | `ai.models.generateContent(...)` | SDK | Gemini 图片生成。模型映射在 `MODEL_MAP`:`nano-banana`、`nano-banana-pro`、`nano-banana-2`。 | 请求要点: - `contents` 包含 prompt 和 inline image。 - `config.responseModalities = ["IMAGE", "TEXT"]`。 - `aspectRatio` 写入 `config.imageConfig.aspectRatio`。 - `nano-banana-pro`、`nano-banana-2` 的 `resolution` 写入 `config.imageConfig.imageSize`。 - `nano-banana-pro` 可用 `googleSearch`。 - `nano-banana-2` 可用 `googleSearch.searchTypes.webSearch/imageSearch`。 返回:直接返回 `image` data URL。 ### 3.2 Gemini Veo 视频 代码:`src/app/api/generate/providers/gemini.ts` | 上游调用 | 方法 | 当前用途 | | --- | --- | --- | | `ai.models.generateVideos(...)` | SDK | 提交 Veo 视频生成。 | | `ai.operations.getVideosOperation({ operation })` | SDK | 服务端内部轮询。 | | `&key=` | GET | 下载生成视频。 | 当前模型映射: | 项目模型 ID | Gemini API 模型 | | --- | --- | | `veo-3.1/text-to-video` | `veo-3.1-generate-preview` | | `veo-3.1/image-to-video` | `veo-3.1-generate-preview` | | `veo-3.1-fast/text-to-video` | `veo-3.1-fast-generate-preview` | | `veo-3.1-fast/image-to-video` | `veo-3.1-fast-generate-preview` | 服务端每 10 秒轮询一次,最多 5 分钟。前端不调用 `/api/generate/poll`。 ### 3.3 NewApiWG 代码:`src/app/api/generate/providers/newapiwg.ts` 当前 NewApiWG 不是所有图片都走 `images/generations`。`generateWithNewApiWG(...)` 的分流顺序如下: | 分流条件 | 实际上游接口 | 方法 | 说明 | | --- | --- | --- | --- | | 模型名匹配 Doubao chat-only | 无 | 无 | 直接返回错误:这是文本/聊天模型,不是生成模型。 | | `isAudio = !isVideo && capabilities.includes("text-to-audio")` | `{baseUrl}/audio/speech` | POST | 文本转音频。 | | 非视频、非音频,且 `isGeminiNativeImageModel(modelId)` | `{baseUrl}/models/{modelName}:generateContent` | POST | Gemini native 图片路径。`/v1` base URL 会转成 `/v1beta`。 | | 非视频、非音频,且 `isOpenAIChatImageModel(modelId)` | `{baseUrl}/chat/completions` | POST | chat 风格图片模型,例如 `sora-image`、`gpt-image-2-all`。 | | `isVideo` | `{baseUrl}/video/generations` | POST | 标准视频生成。 | | 以上都不满足 | `{baseUrl}/images/generations` | POST | 普通图片生成兜底路径。 | #### NewApiWG `images/generations` 当前请求体 只有“非视频、非音频、非 Gemini native、非 chat 图片模型”的普通图片会走: ```ts POST {baseUrl}/images/generations ``` 当前 body 结构: ```json { "model": "input.model.id", "prompt": "dynamicInputs.prompt 或 input.prompt", "n": 1, "...dynamicInputsWithoutPrompt": "...", "...mediaInputs": "...", "size": "resolveNewApiWGImageSize(parameters)", "response_format": "b64_json", "...imageParameters": "normalized parameters" } ``` 当前图片输入规则: | 来源 | 传给上游的字段 | | --- | --- | | `input.images` 为空 | 不加图片字段。 | | `input.images` 只有 1 张 | `image: string` | | `input.images` 多张 | `image: string[]` | 当前参数规则: - `size` 由 `resolveNewApiWGImageSize(parameters)` 计算。 - 如果 `parameters.imageSize` 或 `parameters.resolution` 是 `512`、`1K`、`2K`、`4K`,会结合 `aspectRatio/aspect_ratio` 计算成类似 `1024x1024` 的尺寸。 - `response_format` 固定为 `b64_json`。 - 透传参数会先删除这些字段:`size`、`image_size`、`output_size`、`dimensions`、`aspectRatio`、`aspect_ratio`、`resolution`、`imageSize`。 - `dynamicInputs.prompt` 不透传,因为 prompt 已经放到顶层 `prompt`。 #### NewApiWG `video/generations` 当前请求体 视频模型走: ```ts POST {baseUrl}/video/generations ``` 当前 body 结构: ```json { "model": "input.model.id", "prompt": "dynamicInputs.prompt 或 input.prompt", "n": 1, "...normalizedDynamicInputs": "...", "...mediaInputs": "...", "...parameters": "input.parameters" } ``` 视频动态媒体输入会被归一化: | dynamic input key | 归一化结果 | | --- | --- | | `image`、`images`、`image_url`、`image_urls`、`first_frame_url`、`last_frame_url`、`tail_image_url`、`reference_image_url(s)` 等 | `mediaInputs.images` | | `video`、`videos`、`video_url`、`video_urls`、`reference_video_url(s)` 等 | `mediaInputs.videos` | | `audio`、`audios`、`audio_url`、`audio_urls`、`reference_audio_url(s)` 等 | `mediaInputs.audios` | 视频返回处理: - 如果响应里直接有 URL,立即返回 `videoUrl`。 - 如果响应里只有 `task_id` 或 `id`,服务端调用 `{baseUrl}/video/generations/{taskId}` 内部轮询,最多 9 分钟。 - 前端不调用 `/api/generate/poll`。 ### 3.4 Replicate 代码:`src/app/api/generate/providers/replicate.ts` | 上游接口 | 方法 | 当前用途 | | --- | --- | --- | | `https://api.replicate.com/v1/models/{owner}/{name}` | GET | 获取 latest version 和 OpenAPI schema。 | | `https://api.replicate.com/v1/predictions` | POST | 创建 prediction。 | | `https://api.replicate.com/v1/predictions/{predictionId}` | GET | 服务端内部轮询。 | | `` | GET | 下载结果媒体。 | 请求体创建规则: - `selectedModel.modelId` 必须是 `owner/name`。 - `prediction.input` 会根据 Replicate schema 做字段映射和类型转换。 - 有 `dynamicInputs` 时,`dynamicInputs` 直接使用 schema 字段名,并根据 schema 决定数组/单值。 - 没有 `dynamicInputs` 时,用 schema 推断 prompt/image/参数字段名。 服务端轮询:1 秒一次;图片最多 5 分钟,视频最多 10 分钟。前端不调用 `/api/generate/poll`。 ### 3.5 fal.ai 代码:`src/app/api/generate/providers/fal.ts` | 上游接口 | 方法 | 当前用途 | | --- | --- | --- | | `https://api.fal.ai/v1/models?endpoint_id={modelId}&expand=openapi-3.0` | GET | 获取并缓存 schema 映射,缓存 30 分钟。 | | `https://rest.alpha.fal.ai/storage/upload/initiate?storage_type=fal-cdn-v3` | POST | base64 媒体上传前初始化。 | | `` | PUT | 上传到 fal CDN。 | | `https://queue.fal.run/{modelId}` | POST | 提交 fal 队列任务。 | | `status_url` 或 `https://queue.fal.run/{modelId}/requests/{requestId}/status` | GET | 服务端内部轮询状态。 | | `response_url` 或 `https://queue.fal.run/{modelId}/requests/{requestId}` | GET | 获取任务结果。 | | `` | GET | 下载结果媒体。 | 当前逻辑: - base64 图片/媒体会先上传到 fal CDN。 - 队列状态每 1 秒查一次,最多 10 分钟。 - 3D 直接返回 URL。 - 大视频超过 20MB 时返回 URL,不转 base64。 - 前端不调用 `/api/generate/poll`。 ### 3.6 WaveSpeed 代码:`src/app/api/generate/providers/wavespeed.ts` | 上游接口 | 方法 | 当前用途 | | --- | --- | --- | | `https://api.wavespeed.ai/api/v3/{modelId}` | POST | 提交任务。 | | `data.urls.get` 或 `https://api.wavespeed.ai/api/v3/predictions/{taskId}/result` | GET | 服务端内部轮询结果。 | | `` | GET | 下载结果媒体。 | 当前逻辑: - `modelId` 直接拼进 URL path,但会拒绝非法字符和 `..`。 - payload 先展开 `parameters`,再设置顶层 `prompt`。 - 有 `dynamicInputs` 时直接按 schema 字段名传;`images` 会包装成数组。 - 没有 `dynamicInputs` 且有图片时,第一张图放入 `image`。 - 轮询 1 秒一次,最多 5 分钟;`404` 视为结果未就绪继续等。 - 3D 直接返回 URL;大视频超过 20MB 返回 URL。 - 前端不调用 `/api/generate/poll`。 ## 4. 异步任务接口 这里的“异步”指前端会继续调用项目内部 `/api/generate/poll`。 ### 4.1 Kie.ai 提交代码:`src/app/api/generate/providers/kie.ts` 轮询代码:`src/app/api/generate/poll/route.ts` 提交阶段由 `/api/generate` 调用 `submitKieTask(...)`,不会等待最终媒体。 | 上游接口 | 方法 | 当前用途 | | --- | --- | --- | | `https://kieai.redpandaai.co/api/file-base64-upload` | POST | base64 图片、视频、音频上传为 URL。 | | `https://api.kie.ai/api/v1/jobs/createTask` | POST | 标准 Kie 模型提交任务。 | | `https://api.kie.ai/api/v1/veo/generate` | POST | Kie Veo 模型提交任务。 | `/api/generate` 对 Kie 当前返回: ```json { "success": true, "polling": true, "taskId": "...", "pollProvider": "kie", "pollModelId": "...", "pollModelName": "...", "pollMediaType": "image | video | audio | 3d" } ``` 前端 `pollGenerateTask(...)` 继续调用: ```ts POST /api/generate/poll ``` body: ```json { "taskId": "...", "provider": "kie", "modelId": "...", "modelName": "...", "mediaType": "..." } ``` `/api/generate/poll` 当前只支持 `provider === "kie"`。 | 查询类型 | 上游接口 | 方法 | | --- | --- | --- | | 标准 Kie 任务 | `https://api.kie.ai/api/v1/jobs/recordInfo?taskId={taskId}` | GET | | Kie Veo 任务 | `https://api.kie.ai/api/v1/veo/record-info?taskId={taskId}` | GET | | 结果媒体 | `` | GET | 前端轮询策略: - 初始间隔 3 秒。 - 每次增加 0.5 秒。 - 最高 8 秒。 - 最长 10 分钟。 - 连续 10 次临时错误后失败。 ## 5. LLM 文本生成接口 LLM Generate 节点不走 `/api/generate`,当前走 `POST /api/llm`。 代码:`src/app/api/llm/route.ts` | Provider | 上游接口/调用 | 方法 | | --- | --- | --- | | `google` | `ai.models.generateContent(...)` | SDK | | `openai` | `https://api.openai.com/v1/chat/completions` | POST | | `anthropic` | `https://api.anthropic.com/v1/messages` | POST | | `newapiwg` | `{baseUrl}/chat/completions` | POST | 当前没有 LLM 轮询接口,一次请求直接返回 `text`。 ## 6. 模型列表和 Schema ### 6.1 `/api/models` 代码:`src/app/api/models/route.ts` | Provider | 当前上游调用 | | --- | --- | | Gemini | 无上游调用,本地静态列表。 | | Kie.ai | 无上游调用,本地静态列表。 | | NewApiWG | `{baseUrl}/models` | | Replicate | `https://api.replicate.com/v1/models` | | fal.ai | `https://api.fal.ai/v1/models?status=active`,可带搜索参数。 | | WaveSpeed | `https://api.wavespeed.ai/api/v3/models` | ### 6.2 `/api/models/[modelId]?provider=...` 代码:`src/app/api/models/[modelId]/route.ts` | Provider | 当前上游调用 | | --- | --- | | Gemini | 无上游调用,本地静态 schema。 | | Kie.ai | 无上游调用,本地静态 schema。 | | NewApiWG | 无上游调用,根据模型 ID 推断 schema。 | | Replicate | `https://api.replicate.com/v1/models/{owner}/{name}` | | fal.ai | `https://api.fal.ai/v1/models?endpoint_id={modelId}&expand=openapi-3.0` | | WaveSpeed | 优先用缓存;缺失时调用 `https://api.wavespeed.ai/api/v3/models`。 | ## 7. Header ### 7.1 `/api/generate` 使用的 provider header | Provider | Header | 环境变量兜底 | | --- | --- | --- | | NewApiWG | `X-NewApiWG-Key`、`X-NewApiWG-Base-URL` | `NEWAPIWG_API_KEY`、`NEWAPIWG_BASE_URL` | | Gemini | `X-Gemini-API-Key` | `GEMINI_API_KEY` | | Replicate | `X-Replicate-API-Key` | `REPLICATE_API_KEY` | | fal.ai | `X-Fal-API-Key` | `FAL_API_KEY` | | Kie.ai | `X-Kie-Key` | `KIE_API_KEY` | | WaveSpeed | `X-WaveSpeed-Key` | `WAVESPEED_API_KEY` | ### 7.2 `/api/models` 和 `/api/models/[modelId]` 使用的 header 注意:模型列表/schema 接口里 Replicate、fal 的 header 名和 `/api/generate` 不完全一样。 | Provider | Header | | --- | --- | | NewApiWG | `X-NewApiWG-Key`、`X-NewApiWG-Base-URL` | | Replicate | `X-Replicate-Key` | | fal.ai | `X-Fal-Key` | | Kie.ai | `X-Kie-Key` | | WaveSpeed | `X-WaveSpeed-Key` | ### 7.3 `/api/llm` 使用的 header | Provider | Header | 环境变量兜底 | | --- | --- | --- | | Google/Gemini | `X-Gemini-API-Key` | `GEMINI_API_KEY` | | OpenAI | `X-OpenAI-API-Key` | `OPENAI_API_KEY` | | Anthropic | `X-Anthropic-API-Key` | `ANTHROPIC_API_KEY` | | NewApiWG | `X-NewApiWG-Key`、`X-NewApiWG-Base-URL` | `NEWAPIWG_API_KEY`、`NEWAPIWG_BASE_URL` | ## 8. 同步/异步总览 | 类型 | 前端是否调用 `/api/generate/poll` | 轮询位置 | | --- | --- | --- | | Gemini 图片 | 否 | 无。 | | Gemini Veo 视频 | 否 | 服务端内部 Gemini operation 轮询。 | | NewApiWG 普通图片 `images/generations` | 否 | 无。 | | NewApiWG Gemini native 图片 | 否 | 无。 | | NewApiWG chat 图片 | 否 | 无。 | | NewApiWG 音频 | 否 | 无。 | | NewApiWG 视频 | 否 | 可能服务端内部轮询 `{baseUrl}/video/generations/{taskId}`。 | | Replicate | 否 | 服务端内部轮询 prediction。 | | fal.ai | 否 | 服务端内部轮询 queue。 | | WaveSpeed | 否 | 服务端内部轮询 prediction result。 | | Kie.ai | 是 | 前端轮询 `/api/generate/poll`,服务端每次单次查询 Kie。 | | LLM 文本 | 否 | 无。 |