| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- /**
- * 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 };
- }
- };
|