OpenRouter: Add Google image output parsing
| @@ -5237,7 +5237,13 @@ function extractImageFromData(data, { mainApi = null, chatCompletionSource = nul | |||
| 5237 | return `data:${inlineData.mimeType};base64,${inlineData.data}`; | 5237 | return `data:${inlineData.mimeType};base64,${inlineData.data}`; |
| 5238 | } | 5238 | } |
| 5239 | } break; | 5239 | } break; |
| 5240 | 5240 | case chat_completion_sources.OPENROUTER: { | |
| 5241 | const imageUrl = data?.choices[0]?.message?.images?.find(x => x.type === 'image_url')?.image_url?.url; | ||
| 5242 | if (isDataURL(imageUrl)) { | ||
| 5243 | return imageUrl; | ||
| 5244 | } | ||
| 5245 | // TODO: Handle remote URLs | ||
| 5246 | } | ||
| 5241 | } | 5247 | } |
| 5242 | } break; | 5248 | } break; |
| 5243 | } | 5249 | } |
| @@ -2466,6 +2466,10 @@ export function getStreamingReply(data, state, { chatCompletionSource = null, ov | |||
| 2466 | } | 2466 | } |
| 2467 | return data.choices?.[0]?.delta?.content || ''; | 2467 | return data.choices?.[0]?.delta?.content || ''; |
| 2468 | } else if (chat_completion_source === chat_completion_sources.OPENROUTER) { | 2468 | } else if (chat_completion_source === chat_completion_sources.OPENROUTER) { |
| 2469 | const imageUrl = data?.choices?.[0]?.delta?.images?.find(x => x.type === 'image_url')?.image_url?.url; | ||
| 2470 | if (imageUrl) { | ||
| 2471 | state.image = imageUrl; | ||
| 2472 | } | ||
| 2469 | if (show_thoughts) { | 2473 | if (show_thoughts) { |
| 2470 | state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning)?.[0]?.delta?.reasoning || ''); | 2474 | state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning)?.[0]?.delta?.reasoning || ''); |
| 2471 | } | 2475 | } |
| @@ -5495,7 +5499,7 @@ export function isImageInliningSupported() { | |||
| 5495 | case chat_completion_sources.CLAUDE: | 5499 | case chat_completion_sources.CLAUDE: |
| 5496 | return visionSupportedModels.some(model => oai_settings.claude_model.includes(model)); | 5500 | return visionSupportedModels.some(model => oai_settings.claude_model.includes(model)); |
| 5497 | case chat_completion_sources.OPENROUTER: | 5501 | case chat_completion_sources.OPENROUTER: |
| 5498 | return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.openrouter_model)?.architecture?.modality === 'text+image->text'); | 5502 | return (Array.isArray(model_list) && ['text+image->text+image', 'text+image->text'].includes(model_list.find(m => m.id === oai_settings.openrouter_model)?.architecture?.modality)); |
| 5499 | case chat_completion_sources.CUSTOM: | 5503 | case chat_completion_sources.CUSTOM: |
| 5500 | return true; | 5504 | return true; |
| 5501 | case chat_completion_sources.MISTRALAI: | 5505 | case chat_completion_sources.MISTRALAI: |
| @@ -47,7 +47,7 @@ router.post('/models/multimodal', async (_req, res) => { | |||
| 47 | /** @type {any} */ | 47 | /** @type {any} */ |
| 48 | const data = await response.json(); | 48 | const data = await response.json(); |
| 49 | const models = data?.data || []; | 49 | const models = data?.data || []; |
| 50 | const multimodalModels = models.filter(m => m?.architecture?.modality === 'text+image->text').map(m => m.id); | 50 | const multimodalModels = models.filter(m => ['text+image->text+image', 'text+image->text'].includes(m?.architecture?.modality)).map(m => m.id); |
| 51 | 51 | ||
| 52 | return res.json(multimodalModels); | 52 | return res.json(multimodalModels); |
| 53 | } catch (error) { | 53 | } catch (error) { |