const config = require('./config'); const REQUEST_TIMEOUT_MS = 120000; const REQUEST_TIMEOUT_IMG_MS = 180000; module.exports.REQUEST_TIMEOUT_MS = REQUEST_TIMEOUT_MS; module.exports.REQUEST_TIMEOUT_IMG_MS = REQUEST_TIMEOUT_IMG_MS; function request(path, body, timeoutMs) { const baseUrl = (config.BASE_URL || '').replace(/\/$/, ''); const url = path.startsWith('http') ? path : `${baseUrl}/${path.replace(/^\//, '')}`; const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeoutMs); return fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${config.API_KEY || ''}` }, body: JSON.stringify(body), signal: controller.signal }) .then((res) => { clearTimeout(timeoutId); return res.json().catch(() => ({})).then((data) => { if (!res.ok) throw new Error(data.error?.message || data.error || `HTTP ${res.status}`); return data; }); }) .catch((e) => { clearTimeout(timeoutId); if (e.name === 'AbortError') throw new Error(`请求超时 (${timeoutMs / 1000} 秒)`); throw e; }); } function doubaoRequest(path, body, timeoutMs) { const baseUrl = (config.DOUBAO_BASE_URL || '').replace(/\/$/, ''); const url = path.startsWith('http') ? path : `${baseUrl}/${path.replace(/^\//, '')}`; const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeoutMs); return fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${config.DOUBAO_API_KEY || ''}` }, body: JSON.stringify(body), signal: controller.signal }) .then((res) => { clearTimeout(timeoutId); return res.json().catch(() => ({})).then((data) => { if (!res.ok) throw new Error(data.error?.message || data.error || `HTTP ${res.status}`); return data; }); }) .catch((e) => { clearTimeout(timeoutId); if (e.name === 'AbortError') throw new Error(`请求超时 (${timeoutMs / 1000} 秒)`); throw e; }); } const text2text = require('./request/text2text'); const img2text = require('./request/img2text'); const text2img = require('./request/text2img'); const img2img = require('./request/img2img'); const REQ = { text2text, img2text, text2img, img2img }; async function run(action, ...args) { if (action.startsWith('doubao_')) { return await doRequest(action.substring(7), true, args); } return await doRequest(action, false, args); } /** 从 request 模块取参数,在 ai.js 内发请求 */ async function doRequest(action, isDoubao, args) { const req = REQ[action]; if (!req) return { success: false, error: 'Unknown action: ' + action }; if (isDoubao && (!config.DOUBAO_MODEL || !config.DOUBAO_MODEL.trim())) { return { success: false, error: '豆包未配置:请在 nodejs/ai/config.js 中设置 DOUBAO_MODEL 为你在火山引擎控制台创建的模型接入点 ID(endpoint ID),或设置环境变量 DOUBAO_MODEL' }; } const path = req.path; const timeoutMs = req.timeoutMs; const body = action === 'text2text' ? (isDoubao ? req.getDoubaoBody(args[0]) : req.getBody(args[0])) : (isDoubao ? req.getDoubaoBody(args[0], args[1]) : req.getBody(args[0], args[1])); try { const data = isDoubao ? await doubaoRequest(path, body, timeoutMs) : await request(path, body, timeoutMs); return { success: true, data }; } catch (e) { const msg = e && (e.message || String(e)); const cause = e && e.cause && (e.cause.message || String(e.cause)); const err = cause ? `${msg} (${cause})` : msg; return { success: false, error: err || '网络请求失败' }; } } module.exports.run = run; module.exports.request = request; module.exports.REQUEST_TIMEOUT_MS = REQUEST_TIMEOUT_MS; module.exports.REQUEST_TIMEOUT_IMG_MS = REQUEST_TIMEOUT_IMG_MS;