const config = require('../config'); const PATH = 'chat/completions'; /** 读图较慢,与 ai.js REQUEST_TIMEOUT_IMG_MS 对齐 */ const TIMEOUT_MS = 180000; /** * 将单 URL 或 URL 数组规范为字符串数组(OpenAI 兼容:同一 user 消息里多段 image_url = 多图) */ function normalizeImageUrls (imageUrlOrUrls) { if (Array.isArray(imageUrlOrUrls)) { return imageUrlOrUrls.map((u) => String(u || '').trim()).filter(Boolean); } const s = String(imageUrlOrUrls || '').trim(); return s ? [s] : []; } function buildUserContent (prompt, imageUrlOrUrls) { const urls = normalizeImageUrls(imageUrlOrUrls); const content = [{ type: 'text', text: String(prompt || '') }]; for (const url of urls) { content.push({ type: 'image_url', image_url: { url, detail: 'high' }, }); } return content; } function resolveModel (modelOverride) { return ( (modelOverride && String(modelOverride).trim()) || (config.IMG2TEXT_MODEL && String(config.IMG2TEXT_MODEL).trim()) || config.MODEL_NAME || 'gpt-4o' ); } /** 截图 ROI(img-center):默认读 config.IMG_CENTER_MODEL,与 img2text 默认解耦 */ function resolveImgCenterModel (modelOverride) { return ( (modelOverride && String(modelOverride).trim()) || (config.IMG_CENTER_MODEL && String(config.IMG_CENTER_MODEL).trim()) || (config.IMG2TEXT_MODEL && String(config.IMG2TEXT_MODEL).trim()) || config.MODEL_NAME || 'gpt-5.4' ); } /** * OpenAI 兼容 POST /v1/chat/completions * @param {string} prompt * @param {string|string[]} imageUrlOrUrls 单张 data URL / https URL,或多张(多附件) * @param {string} [modelOverride] */ function getBody (prompt, imageUrlOrUrls, modelOverride) { const urls = normalizeImageUrls(imageUrlOrUrls); if (urls.length === 0) { throw new Error('img2text: 至少提供一张图片(字符串 URL 或 URL 数组)'); } const model = resolveModel(modelOverride); const content = buildUserContent(prompt, imageUrlOrUrls); return { model, messages: [{ role: 'user', content }], // 勿与 max_completion_tokens 同时传:部分聚合网关(如 ChatAnywhere)会报错 max_tokens: 1024, stream: false, }; } function getDoubaoBody (prompt, imageUrlOrUrls, modelOverride) { const urls = normalizeImageUrls(imageUrlOrUrls); if (urls.length === 0) { throw new Error('img2text: 至少提供一张图片'); } const model = (modelOverride && String(modelOverride).trim()) || config.DOUBAO_MODEL; const content = buildUserContent(prompt, imageUrlOrUrls); return { model, messages: [{ role: 'user', content }], max_tokens: 1024, stream: false, }; } module.exports = { path: PATH, getBody, getDoubaoBody, /** img-center:无 override 时用 config.IMG_CENTER_MODEL(环境变量 IMG_CENTER_MODEL) */ resolveImgCenterModel, timeoutMs: TIMEOUT_MS, /** 测试/调试:看 content 结构 */ buildUserContent, normalizeImageUrls, };