u
This commit is contained in:
@@ -5,7 +5,7 @@ Protected. Requires a valid session cookie (`credentials: 'include'`).
|
|||||||
Search images via Serper.dev and stream WebP thumbnails (SSE)
|
Search images via Serper.dev and stream WebP thumbnails (SSE)
|
||||||
|
|
||||||
Queries Google Image search via `https://google.serper.dev/images` using the
|
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`).
|
results via Server-Sent Events (`text/event-stream`).
|
||||||
|
|
||||||
1. First emits an `images` event with the full search result list (including `imageUrl`).
|
1. First emits an `images` event with the full search result list (including `imageUrl`).
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
import * as dbCompanySetting from '../../db/companysetting.js';
|
import * as dbCompanySetting from '../../db/companysetting.js';
|
||||||
import env from '../../config/env.js';
|
|
||||||
import { crawlAndProcessImage } from '../../services/imageCrop.js';
|
import { crawlAndProcessImage } from '../../services/imageCrop.js';
|
||||||
|
|
||||||
const CONCURRENCY = 6;
|
const CONCURRENCY = 6;
|
||||||
@@ -98,7 +97,7 @@ export function register(app, basePath = '') {
|
|||||||
* summary: Search images via Serper.dev and stream WebP thumbnails (SSE)
|
* summary: Search images via Serper.dev and stream WebP thumbnails (SSE)
|
||||||
* description: |
|
* description: |
|
||||||
* Queries Google Image search via `https://google.serper.dev/images` using the
|
* 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`).
|
* results via Server-Sent Events (`text/event-stream`).
|
||||||
*
|
*
|
||||||
* 1. First emits an `images` event with the full search result list (including `imageUrl`).
|
* 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;
|
let apiKey = null;
|
||||||
try {
|
try {
|
||||||
const setting = await dbCompanySetting.getByKey(req.user.id, 'keys.serper', { maskWriteonly: false });
|
const setting = await dbCompanySetting.getByKey(req.user.id, 'keys.serper', { maskWriteonly: false });
|
||||||
apiKey = setting?.value || env.serperApiKey;
|
apiKey = setting?.value?.trim() || null;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('Serper images: failed to read company setting keys.serper:', err?.message || err);
|
console.warn('Serper images: failed to read company setting keys.serper:', err?.message || err);
|
||||||
apiKey = env.serperApiKey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ export default {
|
|||||||
openrouterFreeKey: process.env.OPENROUTER_FREE_KEY,
|
openrouterFreeKey: process.env.OPENROUTER_FREE_KEY,
|
||||||
openrouterFreeModel: process.env.OPENROUTER_FREE_MODEL || 'openrouter/free',
|
openrouterFreeModel: process.env.OPENROUTER_FREE_MODEL || 'openrouter/free',
|
||||||
openrouterPaidModel: process.env.OPENROUTER_PAID_MODEL || 'openai/gpt-6-luna:floor',
|
openrouterPaidModel: process.env.OPENROUTER_PAID_MODEL || 'openai/gpt-6-luna:floor',
|
||||||
serperApiKey: process.env.SERPER_API_KEY,
|
|
||||||
sqlite: {
|
sqlite: {
|
||||||
filename: process.env.SQLITE_PATH || process.env.SQLITE_FILENAME || resolve(__dirname, '../../data/dash.db'),
|
filename: process.env.SQLITE_PATH || process.env.SQLITE_FILENAME || resolve(__dirname, '../../data/dash.db'),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -381,7 +381,10 @@ export function createAnalyzeImageTool({ googleAuthId, model }) {
|
|||||||
role: 'user',
|
role: 'user',
|
||||||
content: [
|
content: [
|
||||||
{ type: 'text', text },
|
{ 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')}` },
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import fs from 'fs';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
import { defineTool, ToolError } from 'libllmorbiter';
|
import { defineTool, ToolError } from 'libllmorbiter';
|
||||||
import env from '../config/env.js';
|
import * as dbCompanySetting from '../db/companysetting.js';
|
||||||
import { prepareVfs, syncVfsToDb } from './vfs.js';
|
import { prepareVfs, syncVfsToDb } from './vfs.js';
|
||||||
|
|
||||||
const SERPER_ENDPOINT = 'https://google.serper.dev/images';
|
const SERPER_ENDPOINT = 'https://google.serper.dev/images';
|
||||||
@@ -175,10 +175,17 @@ export function createSearchImagesTool({ googleAuthId }) {
|
|||||||
}
|
}
|
||||||
const wanted = Math.min(count, MAX_COUNT);
|
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) {
|
if (!apiKey) {
|
||||||
throw new ToolError(
|
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.'
|
'Use a direct image URL with javascript_execute instead.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user