This commit is contained in:
seb
2026-10-05 14:54:23 +02:00
parent 5f9231f8fd
commit f55990c25e
5 changed files with 17 additions and 10 deletions

View File

@@ -5,7 +5,7 @@ Protected. Requires a valid session cookie (`credentials: 'include'`).
Search images via Serper.dev and stream WebP thumbnails (SSE)
Queries Google Image search via `https://google.serper.dev/images` using the
company setting `keys.serper` (or server `SERPER_API_KEY`), and streams the
company setting `keys.serper`, and streams the
results via Server-Sent Events (`text/event-stream`).
1. First emits an `images` event with the full search result list (including `imageUrl`).

View File

@@ -1,6 +1,5 @@
import sharp from 'sharp';
import * as dbCompanySetting from '../../db/companysetting.js';
import env from '../../config/env.js';
import { crawlAndProcessImage } from '../../services/imageCrop.js';
const CONCURRENCY = 6;
@@ -98,7 +97,7 @@ export function register(app, basePath = '') {
* summary: Search images via Serper.dev and stream WebP thumbnails (SSE)
* description: |
* Queries Google Image search via `https://google.serper.dev/images` using the
* company setting `keys.serper` (or server `SERPER_API_KEY`), and streams the
* company setting `keys.serper`, and streams the
* results via Server-Sent Events (`text/event-stream`).
*
* 1. First emits an `images` event with the full search result list (including `imageUrl`).
@@ -204,10 +203,9 @@ export function register(app, basePath = '') {
let apiKey = null;
try {
const setting = await dbCompanySetting.getByKey(req.user.id, 'keys.serper', { maskWriteonly: false });
apiKey = setting?.value || env.serperApiKey;
apiKey = setting?.value?.trim() || null;
} catch (err) {
console.warn('Serper images: failed to read company setting keys.serper:', err?.message || err);
apiKey = env.serperApiKey;
}
if (!apiKey) {

View File

@@ -29,7 +29,6 @@ export default {
openrouterFreeKey: process.env.OPENROUTER_FREE_KEY,
openrouterFreeModel: process.env.OPENROUTER_FREE_MODEL || 'openrouter/free',
openrouterPaidModel: process.env.OPENROUTER_PAID_MODEL || 'openai/gpt-6-luna:floor',
serperApiKey: process.env.SERPER_API_KEY,
sqlite: {
filename: process.env.SQLITE_PATH || process.env.SQLITE_FILENAME || resolve(__dirname, '../../data/dash.db'),
},

View File

@@ -381,7 +381,10 @@ export function createAnalyzeImageTool({ googleAuthId, model }) {
role: 'user',
content: [
{ type: 'text', text },
{ type: 'image_url', imageUrl: { url: `data:image/webp;base64,${webp.toString('base64')}` } },
{
type: 'image_url',
image_url: { url: `data:image/webp;base64,${webp.toString('base64')}` },
},
],
},
],

View File

@@ -2,7 +2,7 @@ import fs from 'fs';
import path from 'path';
import sharp from 'sharp';
import { defineTool, ToolError } from 'libllmorbiter';
import env from '../config/env.js';
import * as dbCompanySetting from '../db/companysetting.js';
import { prepareVfs, syncVfsToDb } from './vfs.js';
const SERPER_ENDPOINT = 'https://google.serper.dev/images';
@@ -175,10 +175,17 @@ export function createSearchImagesTool({ googleAuthId }) {
}
const wanted = Math.min(count, MAX_COUNT);
const apiKey = env.serperApiKey?.trim();
let apiKey = null;
try {
const setting = await dbCompanySetting.getByKey(googleAuthId, 'keys.serper', { maskWriteonly: false });
apiKey = setting?.value?.trim() || null;
} catch (err) {
console.warn('search_images: failed to read company setting keys.serper:', err?.message || err);
}
if (!apiKey) {
throw new ToolError(
'search_images is unavailable: SERPER_API_KEY is not configured on the server. ' +
'search_images is unavailable: Serper API key not configured (companysetting: keys.serper). ' +
'Use a direct image URL with javascript_execute instead.'
);
}