From ce14d15ba32855cb0f8e8f0daa6503f02f025474 Mon Sep 17 00:00:00 2001 From: yyhhyyyyyy Date: Wed, 27 Aug 2025 13:03:50 +0800 Subject: [PATCH] feat: support openrouter gemini 2.5 flash image preview (#9587) * feat: support openrouter gemini 2.5 flash image preview * feat: improve image content handling with type safety * fix: code fmt --- .../aiCore/clients/openai/OpenAIApiClient.ts | 18 +++++++++++++++++- src/renderer/src/types/sdk.ts | 9 +++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts b/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts index c8a4ff82d0..228398fea7 100644 --- a/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts +++ b/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts @@ -881,7 +881,9 @@ export class OpenAIAPIClient extends OpenAIBaseClient< (typeof choice.delta.content === 'string' && choice.delta.content !== '') || (typeof (choice.delta as any).reasoning_content === 'string' && (choice.delta as any).reasoning_content !== '') || - (typeof (choice.delta as any).reasoning === 'string' && (choice.delta as any).reasoning !== '')) + (typeof (choice.delta as any).reasoning === 'string' && (choice.delta as any).reasoning !== '') || + ((choice.delta as OpenAISdkRawContentSource).images && + Array.isArray((choice.delta as OpenAISdkRawContentSource).images))) ) { contentSource = choice.delta } else if ('message' in choice) { @@ -979,6 +981,20 @@ export class OpenAIAPIClient extends OpenAIBaseClient< accumulatingText = false } + // 处理图片内容 (e.g. from OpenRouter Gemini image generation models) + if (contentSource.images && Array.isArray(contentSource.images)) { + controller.enqueue({ + type: ChunkType.IMAGE_CREATED + }) + controller.enqueue({ + type: ChunkType.IMAGE_COMPLETE, + image: { + type: 'base64', + images: contentSource.images.map((image) => image.image_url?.url || '') + } + }) + } + // 处理工具调用 if (contentSource.tool_calls) { for (const toolCall of contentSource.tool_calls) { diff --git a/src/renderer/src/types/sdk.ts b/src/renderer/src/types/sdk.ts index 4c7fa299d4..70387045a8 100644 --- a/src/renderer/src/types/sdk.ts +++ b/src/renderer/src/types/sdk.ts @@ -22,6 +22,7 @@ import { Tool } from '@google/genai' import OpenAI, { AzureOpenAI } from 'openai' +import { ChatCompletionContentPartImage } from 'openai/resources' import { Stream } from 'openai/streaming' import { EndpointType } from './index' @@ -107,8 +108,12 @@ export type OpenAISdkRawChunk = export type OpenAISdkRawOutput = Stream | OpenAI.ChatCompletion export type OpenAISdkRawContentSource = - | OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta - | OpenAI.Chat.Completions.ChatCompletionMessage + | (OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta & { + images?: ChatCompletionContentPartImage[] + }) + | (OpenAI.Chat.Completions.ChatCompletionMessage & { + images?: ChatCompletionContentPartImage[] + }) export type OpenAISdkMessageParam = OpenAI.Chat.Completions.ChatCompletionMessageParam