diff --git a/server.js b/server.js index 89d0e80..0f2f098 100644 --- a/server.js +++ b/server.js @@ -107,29 +107,6 @@ function saveAiConfig(apiKey) { fs.writeFileSync(AI_CONFIG_FILE, JSON.stringify({ apiKeyEnc: encrypt(apiKey) }, null, 2), 'utf8'); } -const REGION_LABELS = { - africa: 'Africa', middle_east: 'Middle East', australia: 'Australia/Oceania', - europe: 'Europe', sea: 'Southeast Asia', other: 'Other', -}; - -function buildCustomerContext(c) { - const lines = []; - lines.push(`Company: ${c.company || '(unknown / not on file)'}`); - if (c.contact) lines.push(`Contact person: ${c.contact}`); - const place = [c.country, REGION_LABELS[c.region]].filter(Boolean).join(', '); - if (place) lines.push(`Location: ${place}`); - if (c.productLines && c.productLines.length) lines.push(`Product interest: ${c.productLines.join(', ')}`); - if (c.intendedModel || c.intendedQty) { - lines.push(`Specific model interest: ${c.intendedModel || '(model unspecified)'}${c.intendedQty ? `, quantity: ${c.intendedQty}` : ''}`); - } - if (c.lastContact) lines.push(`Last contact date: ${c.lastContact}`); - if (c.notes) lines.push(`Background research on this customer: ${c.notes}`); - if (c.tags) lines.push(`Additional remarks: ${c.tags}`); - if (c.isVip) lines.push('This is a VIP / priority customer — extra attentive tone.'); - if (c.hasOrdered) lines.push('This customer has already placed an order before — this follow-up is with an existing buyer, not a cold lead.'); - return lines.join('\n'); -} - async function callDeepSeek(apiKey, messages, opts) { const { maxTokens = 600, temperature = 0.7, model = 'deepseek-v4-flash' } = opts || {}; const resp = await fetch(`${DEEPSEEK_API_BASE}/chat/completions`, { @@ -384,49 +361,6 @@ const aiLimiter = rateLimit({ message: { error: 'too many AI requests, please slow down' }, }); -app.post('/api/ai/draft', requireAuth, aiLimiter, async (req, res) => { - const body = req.body || {}; - const customerId = body.customerId; - const channel = body.channel; - if (!customerId || !['email', 'whatsapp'].includes(channel)) { - return res.status(400).json({ error: 'invalid request' }); - } - const cfg = loadAiConfig(); - if (!cfg.apiKey) return res.status(400).json({ error: 'DeepSeek API key not configured' }); - - const data = readData(); - let customers = []; - try { customers = JSON.parse(data['crm:customers'] || '[]'); } catch (e) {} - const customer = customers.find((c) => c.id === customerId); - if (!customer) return res.status(404).json({ error: 'customer not found' }); - - const context = buildCustomerContext(customer); - const systemPrompt = 'You are a sales assistant helping a B2B export salesperson at a Chinese power-equipment company (UPS systems, rectifiers, solar inverters, battery storage) write natural, professional follow-up outreach to overseas customers. Always write in English. Never sound like a generic template, reference specifics from the customer info given. Output only the requested content, with no meta-commentary, explanations, or markdown formatting.'; - - const userPrompt = channel === 'email' - ? `Customer info:\n${context}\n\nWrite a short, warm but professional follow-up email to this customer. Respond in EXACTLY this format with no extra text:\nSUBJECT: \nBODY:\n` - : `Customer info:\n${context}\n\nWrite a short, casual WhatsApp message to check in with this customer (2-4 sentences, friendly tone, no formal greeting like "Dear", a light emoji is fine if it feels natural). Respond with ONLY the message text, nothing else.`; - - try { - const content = await callDeepSeek(cfg.apiKey, [ - { role: 'system', content: systemPrompt }, - { role: 'user', content: userPrompt }, - ]); - if (channel === 'email') { - const subjectMatch = content.match(/SUBJECT:\s*(.+)/i); - const bodyMatch = content.match(/BODY:\s*([\s\S]*)/i); - res.json({ - subject: subjectMatch ? subjectMatch[1].trim() : 'Following up', - body: bodyMatch ? bodyMatch[1].trim() : content.trim(), - }); - } else { - res.json({ body: content.trim() }); - } - } catch (e) { - res.status(502).json({ error: e.message }); - } -}); - /* --------------------------- ai catalog import --------------------------- */ // 上传一份/多份PDF或图片形式的产品目录(可能包含多个型号),做OCR文字识别后交给 // DeepSeek解析成结构化的产品字段数组,前端拿到后先给用户一个预览/确认页面,