/** * Vision产品特征提取器 * 支持超时重试 + 缓存 */ const axios = require('axios'); const fs = require('fs'); const path = require('path'); const API_KEY = 'G9rXx3Ag2Xfa7Gs8zou6t6HqeZ'; const API_BASE = 'https://api.wuyinkeji.com/api'; // Vision提取Prompt const VISION_EXTRACT_PROMPT = `Analyze this pet product image in EXTREME detail. Output ONLY a valid JSON object (no markdown, no explanation, no thinking): { "color": { "primary": "", "name": "", "secondary": "" }, "shape": { "type": "", "petal_count": , "opening": "", "description": "" }, "material": { "type": "", "finish": "", "texture": "" }, "edge_binding": { "color": "", "material": "" }, "closure": { "type": "", "color": "", "position": "" }, "logo": { "text": "", "style": "", "position": "" }, "unique_features": [""], "overall_description": "<2-3 sentence summary for image generation>" }`; /** * 调用Vision API提取产品特征 * @param {string} imageUrl - 图片URL * @param {object} options - 配置选项 * @returns {object|null} - 提取的产品特征JSON */ async function extractProductFeatures(imageUrl, options = {}) { const { maxRetries = 3, timeout = 120000, // 120秒 retryDelay = 5000, cacheDir = null, cacheKey = null } = options; // 检查缓存 if (cacheDir && cacheKey) { const cachePath = path.join(cacheDir, `vision-cache-${cacheKey}.json`); if (fs.existsSync(cachePath)) { try { const cached = JSON.parse(fs.readFileSync(cachePath, 'utf-8')); if (cached && cached.color) { console.log(' 📦 使用缓存的Vision结果'); return cached; } } catch (e) { // 缓存无效,继续请求 } } } let lastError = null; for (let attempt = 1; attempt <= maxRetries; attempt++) { console.log(` 🔍 Vision分析 (尝试 ${attempt}/${maxRetries})...`); try { const response = await axios.post(`${API_BASE}/chat/index`, { key: API_KEY, model: 'gemini-3-pro', content: VISION_EXTRACT_PROMPT, image_url: imageUrl }, { timeout }); const content = response.data.data?.choices?.[0]?.message?.content || response.data.data?.content; if (!content) { throw new Error('Vision响应为空'); } // 提取JSON(跳过thinking部分) let jsonStr = content; // 如果有标签,跳过它 const thinkEnd = content.indexOf(''); if (thinkEnd !== -1) { jsonStr = content.substring(thinkEnd + 8); } // 提取JSON const jsonMatch = jsonStr.match(/\{[\s\S]*\}/); if (jsonMatch) { const parsed = JSON.parse(jsonMatch[0]); // 验证必要字段 if (parsed.color && parsed.shape) { console.log(' ✓ Vision提取成功'); // 保存缓存 if (cacheDir && cacheKey) { const cachePath = path.join(cacheDir, `vision-cache-${cacheKey}.json`); fs.writeFileSync(cachePath, JSON.stringify(parsed, null, 2)); } return parsed; } } throw new Error('无法解析有效的JSON'); } catch (error) { lastError = error; console.log(` ⚠️ 尝试 ${attempt} 失败: ${error.message}`); if (attempt < maxRetries) { console.log(` ⏳ ${retryDelay/1000}秒后重试...`); await new Promise(r => setTimeout(r, retryDelay)); } } } console.error(` ❌ Vision提取最终失败: ${lastError?.message}`); return null; } /** * 将Vision结果转换为Golden Description */ function buildGoldenDescription(visionResult, productType = 'pet recovery cone') { if (!visionResult) { return ` PRODUCT: ${productType} - Shape: Soft flower/petal shape with C-shaped opening - Material: Soft waterproof fabric - Closure: Velcro strap - Comfortable design for pets CRITICAL: Follow the reference image EXACTLY for product shape and color. `; } const r = visionResult; return ` EXACT PRODUCT APPEARANCE (MUST MATCH REFERENCE IMAGE): - Shape: ${r.shape?.petal_count || '7-8'}-PETAL ${(r.shape?.type || 'flower').toUpperCase()} shape - Opening: ${r.shape?.opening || 'C-shaped'} (NOT a full circle) - Color: ${(r.color?.name || 'ice blue').toUpperCase()} (${r.color?.primary || '#C3E6E8'}) - Material: ${r.material?.finish || 'Soft'} ${r.material?.type || 'waterproof fabric'} with ${r.material?.texture || 'padded'} texture - Edge binding: ${r.edge_binding?.color || 'Matching color'} ${r.edge_binding?.material || 'ribbed elastic'} around inner neck hole - Closure: ${r.closure?.color || 'White'} ${r.closure?.type || 'velcro'} on ${r.closure?.position || 'one segment'} - Logo: "${r.logo?.text || 'TOUCHDOG'}" ${r.logo?.style || 'embroidered'} on ${r.logo?.position || 'one petal'} UNIQUE FEATURES: ${(r.unique_features || ['Scalloped petal edges', 'Radial stitching', 'Soft padded construction']).map(f => `- ${f}`).join('\n')} OVERALL: ${r.overall_description || 'A soft, comfortable pet recovery cone with flower-petal design.'} CRITICAL PROHIBITIONS: - ❌ NO printed colorful patterns (solid color only unless reference shows otherwise) - ❌ NO hard plastic transparent cones - ❌ NO fully circular/closed shapes (must match reference C-opening) - ❌ NO random brand logos - ❌ MUST match reference image product EXACTLY `.trim(); } module.exports = { extractProductFeatures, buildGoldenDescription, VISION_EXTRACT_PROMPT };