OpenRouter: Add Google image output parsing
| @@ -5237,7 +5237,13 @@ function extractImageFromData(data, { mainApi = null, chatCompletionSource = nul | ||
| 5237 | 5237 | return `data:${inlineData.mimeType};base64,${inlineData.data}`; |
| 5238 | 5238 | } |
| 5239 | 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 | 5248 | } break; |
| 5243 | 5249 | } |
| @@ -2466,6 +2466,10 @@ export function getStreamingReply(data, state, { chatCompletionSource = null, ov | ||
| 2466 | 2466 | } |
| 2467 | 2467 | return data.choices?.[0]?.delta?.content || ''; |
| 2468 | 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 | 2473 | if (show_thoughts) { |
| 2470 | 2474 | state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning)?.[0]?.delta?.reasoning || ''); |
| 2471 | 2475 | } |
| @@ -5495,7 +5499,7 @@ export function isImageInliningSupported() { | ||
| 5495 | 5499 | case chat_completion_sources.CLAUDE: |
| 5496 | 5500 | return visionSupportedModels.some(model => oai_settings.claude_model.includes(model)); |
| 5497 | 5501 | case chat_completion_sources.OPENROUTER: |
| 5498 | 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 === 'text+image->text')); |
| 5499 | 5503 | case chat_completion_sources.CUSTOM: |
| 5500 | 5504 | return true; |
| 5501 | 5505 | case chat_completion_sources.MISTRALAI: |
| @@ -47,7 +47,7 @@ router.post('/models/multimodal', async (_req, res) => { | ||
| 47 | 47 | /** @type {any} */ |
| 48 | 48 | const data = await response.json(); |
| 49 | 49 | const models = data?.data || []; |
| 50 | 50 | const multimodalModels = models.filter(m => m?.architecture?.modality === ['text+image->text+image', 'text+image->text'].includes(m?.architecture?.modality)).map(m => m.id); |
| 51 | 51 | |
| 52 | 52 | return res.json(multimodalModels); |
| 53 | 53 | } catch (error) { |