/** * AI 命盘解读云函数 * * 接收命盘数据,调用 LLM API 生成数字能量学解读 * 支持 DeepSeek / OpenAI 兼容接口 * 通过云调用鉴权,不在前端暴露 API Key */ const cloud = require('wx-server-sdk'); cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }); // LLM API 配置(通过云托管环境变量配置,不硬编码密钥) const LLM_API_KEY = process.env.LLM_API_KEY || 'YOUR_API_KEY'; const LLM_API_URL = process.env.LLM_API_URL || 'https://api.deepseek.com/v1/chat/completions'; const LLM_MODEL = process.env.LLM_MODEL || 'deepseek-chat'; // 系统提示词 — 设定 AI 的角色和行为 const SYSTEM_PROMPT = `你是一位专业的数字能量学解读师,精通生命密码(数字能量学)。你的任务是基于用户的三角形命盘数据,提供专业、准确、有洞见的解读。 解读风格要求: 1. 专业但不晦涩,让普通人也能理解 2. 每段解读 100-200 字,言简意赅 3. 结合数字能量学理论,给出性格特质、优势、成长建议 4. 语气温和正向,避免恐吓或绝对化表述 5. 以 "你" 称呼用户,亲切自然 重要原则: - 解读必须基于命盘中的实际数字,不能编造 - 避免宿命论,强调个人选择和发展的可能性 - 所有解读最后加一句 "仅供参考" 的提示`; function buildPrompt(chartData, name) { const { positions, zones, mainCharacter, isMasterNumber } = chartData; let prompt = `请为以下命盘生成解读。\n\n`; prompt += `姓名:${name || '用户'}\n`; prompt += `主性格数字:${mainCharacter}${isMasterNumber ? '(卓越数)' : ''}\n\n`; prompt += `完整命盘数据:\n`; prompt += `底层:A=${positions.A} B=${positions.B} C=${positions.C} D=${positions.D} E=${positions.E}\n`; prompt += `第二层:F=${positions.F} G=${positions.G} H=${positions.H} I=${positions.I}\n`; prompt += `第三层:J=${positions.J} K=${positions.K} L=${positions.L}\n`; prompt += `第四层:M=${positions.M} N=${positions.N}\n`; prompt += `顶端:O=${positions.O}\n\n`; prompt += `请以 JSON 格式返回,包含以下字段:\n`; prompt += `{ "mainCharacter": "主性格解读(重点突出${mainCharacter}号人的核心特质、优势、适合的发展方向)", "fatherSource": "父源区解读(F=${positions.F}, J=${positions.J} 的含义和影响)", "motherSource": "母源区解读(I=${positions.I}, L=${positions.L} 的含义和影响)", "leftZone": "左区(0-20岁)解读", "middleZone": "中区(20-40岁)解读", "rightZone": "右区(40-60岁)解读" }\n\n`; prompt += `请只返回 JSON,不要包含其他文字。`; return prompt; } exports.main = async (event, context) => { const { chartData, name } = event; if (!chartData || !chartData.positions) { return { code: 400, error: '缺少命盘数据' }; } try { const userPrompt = buildPrompt(chartData, name); const response = await fetch(LLM_API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${LLM_API_KEY}`, }, body: JSON.stringify({ model: LLM_MODEL, messages: [ { role: 'system', content: SYSTEM_PROMPT }, { role: 'user', content: userPrompt }, ], temperature: 0.7, max_tokens: 2000, }), }); const data = await response.json(); if (!data.choices || !data.choices[0]) { console.error('LLM API error:', data); return { code: 500, error: 'AI 服务异常', reading: null }; } const content = data.choices[0].message.content; // Try to parse JSON from the response try { // Find JSON in the response (handle cases where model wraps in markdown) const jsonMatch = content.match(/\{[\s\S]*\}/); const jsonStr = jsonMatch ? jsonMatch[0] : content; const reading = JSON.parse(jsonStr); return { code: 0, reading: { mainCharacter: reading.mainCharacter || '', fatherSource: reading.fatherSource || '', motherSource: reading.motherSource || '', leftZone: reading.leftZone || '', middleZone: reading.middleZone || '', rightZone: reading.rightZone || '', }, }; } catch (parseErr) { // If JSON parsing fails, return raw text return { code: 0, reading: { mainCharacter: content, fatherSource: '解读生成中,请稍后再试', motherSource: '解读生成中,请稍后再试', leftZone: '解读生成中,请稍后再试', middleZone: '解读生成中,请稍后再试', rightZone: '解读生成中,请稍后再试', }, }; } } catch (err) { console.error('Cloud function error:', err); return { code: 500, error: err.message, reading: null }; } };