From 6750368bc84c8fb008bf3bce9c34cce52b9258bc Mon Sep 17 00:00:00 2001 From: 732642856 <732642856@qq.com> Date: Fri, 12 Jun 2026 07:21:00 +0800 Subject: [PATCH] =?UTF-8?q?v6.9.4:=20AI=E8=A7=A3=E8=AF=BB=E9=9B=86?= =?UTF-8?q?=E6=88=90=20=E2=80=94=20copse.top=20GPT=20=E4=B8=AD=E8=BD=AC?= =?UTF-8?q?=E6=8E=A5=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 架构重构 - 计算层: 纯本地 (SwissEph WASM 或 localhost:5200) - AI解读层: copse.top GPT API 生成个性化解读 - 清晰的职责分离 ## flow 1. 用户输入出生信息 → 本地计算星盘 2. 结构化数据 → copse.top → GPT 解读 3. AI 解读直接展示在星盘下方 ## 修改 - api-bridge.js v4.0: 全新架构 - main.js: triggerAIReading() 自动触发 - index.html: chart-summary 展示区 --- jyotish-app/api-bridge.js | 240 ++++++++++++++++++-------------------- jyotish-app/index.html | 4 + jyotish-app/main.js | 54 ++++++--- 3 files changed, 155 insertions(+), 143 deletions(-) diff --git a/jyotish-app/api-bridge.js b/jyotish-app/api-bridge.js index 2dd470f9..809f45d2 100644 --- a/jyotish-app/api-bridge.js +++ b/jyotish-app/api-bridge.js @@ -1,146 +1,138 @@ /** - * API Bridge v3.0 - * 自动检测环境:本地用 localhost:5200,云端用 copse.top - * 均不可达时回退到浏览器端 JS 引擎 + * API Bridge v4.0 + * + * 架构: + * 计算 → 纯本地 (SwissEph WASM 或 localhost:5200 Python API) + * AI解读 → copse.top (GPT API 中转) */ -const API_BASE = (() => { - const host = window.location.hostname; - if (host === 'localhost' || host === '127.0.0.1' || host.startsWith('192.168.')) { - return 'http://localhost:5200'; - } - return 'https://copse.top'; -})(); +const AI_BASE = 'https://copse.top'; +const AI_KEY = 'sk-828a787bd2bb69d2d4707e8c05ae5cfe81b13de7be1db7f85932d49ed72e4c6a'; -const API_KEY = 'sk-828a787bd2bb69d2d4707e8c05ae5cfe81b13de7be1db7f85932d49ed72e4c6a'; +// ═══════════════════════════════════════════════════════════════ +// 计算层 — 纯本地,不需要服务器 +// ═══════════════════════════════════════════════════════════════ -const API_CACHE = {}; -const CACHE_TTL = 300000; // 5分钟缓存 - -async function apiFetch(endpoint, body = {}) { - const cacheKey = endpoint + JSON.stringify(body); - if (API_CACHE[cacheKey] && Date.now() - API_CACHE[cacheKey].ts < CACHE_TTL) { - return API_CACHE[cacheKey].data; - } +async function computeWithPython(birthData) { try { - const resp = await fetch(`${API_BASE}${endpoint}`, { - method: body && Object.keys(body).length > 0 ? 'POST' : 'GET', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${API_KEY}`, - }, - body: body && Object.keys(body).length > 0 ? JSON.stringify(body) : undefined, + const resp = await fetch('http://localhost:5200/api/chart', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(birthData), }); const data = await resp.json(); - API_CACHE[cacheKey] = { data, ts: Date.now() }; - return data; - } catch (e) { - console.warn('[API] fetch failed:', e.message); - return null; + if (data.success) { + console.log('[Compute] ✅ Python API v' + data.version); + return data; + } + } catch(e) { + console.log('[Compute] Python API 不可用, 回退JS引擎'); + } + return null; +} + +// ═══════════════════════════════════════════════════════════════ +// AI 解读层 — 通过 copse.top 调用 GPT +// ═══════════════════════════════════════════════════════════════ + +async function aiReading(chartData, options = {}) { + const { style = 'deep', focus = '全部' } = options; + + const prompt = buildReadingPrompt(chartData, style, focus); + + try { + const resp = await fetch(AI_BASE + '/v1/chat/completions', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + AI_KEY, + }, + body: JSON.stringify({ + model: 'gpt-4', + messages: [ + { role: 'system', content: SYSTEM_PROMPT }, + { role: 'user', content: prompt }, + ], + temperature: 0.7, + max_tokens: 2000, + }), + }); + const data = await resp.json(); + const text = data?.choices?.[0]?.message?.content || ''; + return { success: true, reading: text, style, focus }; + } catch(e) { + console.warn('[AI] 解读失败:', e.message); + return { success: false, error: e.message }; } } -async function checkApiAvailable() { - const r = await apiFetch('/api/health'); - if (r && r.status === 'ok') { - console.log(`[API] ✅ Connected to Jyotish API v${r.version} (${r.modules})`); - return true; +const SYSTEM_PROMPT = `你是印度占星(Jyotish/Vedic Astrology)专业解盘师。 +基于提供的精确星盘数据,给出个性化、严谨、有深度的解读。 +规则: +- 每次判断必须引用星盘中的具体配置(行星-星座-宫位-Dasha) +- 避免刻板教条("土星落陷=不好"),必须结合多配置综合判断 +- 语气专业但不冷漠,像面对面交谈 +- 给出具体的时间窗口,不要说"未来几年" +- 如果某个配置有多种可能性,列出2-3种最可能的走向`; + +function buildReadingPrompt(chartData, style, focus) { + const asc = chartData.ascendant?.sign || '?'; + const planets = chartData.planets || {}; + const yogas = (chartData.yogas || []).slice(0, 15); + const dasha = chartData.dasha || {}; + + let prompt = `请基于以下星盘数据给出${style === 'quick' ? '简明' : '深度'}解读。\n\n`; + prompt += `【焦点领域】${focus}\n\n`; + prompt += `【上升星座】${asc}\n\n`; + prompt += `【行星落位】\n`; + for (const [name, data] of Object.entries(planets)) { + const sign = typeof data === 'object' ? (data.sign || '?') : data; + const house = typeof data === 'object' ? (data.house || '?') : '?'; + prompt += ` ${name}: ${sign} ${house}宫\n`; } - return false; -} -async function apiComputeFullChart(birthData) { - const result = await apiFetch('/api/chart', birthData); - if (!result || !result.success) { - throw new Error(result?.error || '计算失败,请检查输入信息'); + if (yogas.length > 0) { + prompt += `\n【主要Yoga】\n`; + for (const y of yogas) { + prompt += ` ${y.name || ''}: ${(y.combination || y.desc || '').slice(0, 60)}\n`; + } } - return result; + + if (dasha.current_md) { + prompt += `\n【当前大运】${dasha.current_md} (${dasha.current_ad || ''})\n`; + } + + prompt += `\n请分析:`; + if (focus === '事业' || focus === '全部') prompt += `\n1) 事业方向与关键时间节点`; + if (focus === '感情' || focus === '全部') prompt += `\n2) 感情婚姻特征与时机`; + if (focus === '健康' || focus === '全部') prompt += `\n3) 需注意的健康周期`; + if (focus === '全部') prompt += `\n4) 当前大运的核心主题`; + + return prompt; } -async function apiGetRemedies(chartData) { - return await apiFetch('/api/remedies', { - shadbala: chartData.planets || {}, - doshas: [], - dasha_lord: chartData.dasha?.current_md || '', - }); +// ═══════════════════════════════════════════════════════════════ +// 一键入口 +// ═══════════════════════════════════════════════════════════════ + +async function aiFullReading(chartData) { + const reading = await aiReading(chartData, { style: 'deep', focus: '全部' }); + return reading; } -async function apiGetKP(chartData) { - return await apiFetch('/api/kp', { - planets: chartData.planets || {}, - asc_sign_idx: chartData.ascendant?.sign_idx || 0, - }); +async function aiQuickInsight(chartData) { + const reading = await aiReading(chartData, { style: 'quick', focus: '全部' }); + return reading; } -async function apiGetSynastry(maleMoonDeg, femaleMoonDeg) { - return await apiFetch('/api/synastry', { male_moon: maleMoonDeg, female_moon: femaleMoonDeg }); -} - -async function apiGetSadeSati(chartData) { - return await apiFetch('/api/sade_sati', { - moon_degree: chartData.planets?.Moon?.lon || 0, - asc_degree: chartData.ascendant?.degree || 0, - saturn_degree: chartData.planets?.Saturn?.lon || 0, - }); -} - -async function apiGetPMC(chartData) { - return await apiFetch('/api/pancha_mahapurusha', { - planets: chartData.planets || {}, - sun_degree: chartData.planets?.Sun?.lon || 0, - }); -} - -async function apiGetCareer(chartData) { - return await apiFetch('/api/career', { - planets: chartData.planets || {}, - asc_sign: chartData.ascendant?.sign || 'Aries', - }); -} - -async function apiGetRelationship(chartData) { - return await apiFetch('/api/relationship', { - planets: chartData.planets || {}, - asc_sign: chartData.ascendant?.sign || 'Aries', - }); -} - -async function apiGetPrashna(chartData, question) { - return await apiFetch('/api/prashna', { - planets: chartData.planets || {}, - question: question || 'general', - }); -} - -// 🔥 一键全功能计算 -async function apiComputeAll(birthData) { - const chart = await apiComputeFullChart(birthData); - if (!chart || !chart.success) return chart; - - // 并行请求所有分析 - const [remedies, kp, sade_sati, pmc, career, relationship] = await Promise.all([ - apiGetRemedies(chart), - apiGetKP(chart), - apiGetSadeSati(chart), - apiGetPMC(chart), - apiGetCareer(chart), - apiGetRelationship(chart), - ]); - - chart._extended = { remedies, kp, sade_sati, pmc, career, relationship }; - return chart; -} +// ═══════════════════════════════════════════════════════════════ +// 对外接口 +// ═══════════════════════════════════════════════════════════════ window.JyotishAPI = { - checkAvailable: checkApiAvailable, - computeChart: apiComputeFullChart, - computeAll: apiComputeAll, - getRemedies: apiGetRemedies, - getKP: apiGetKP, - getSynastry: apiGetSynastry, - getSadeSati: apiGetSadeSati, - getPMC: apiGetPMC, - getCareer: apiGetCareer, - getRelationship: apiGetRelationship, - getPrashna: apiGetPrashna, - baseUrl: API_BASE, + // 计算 + computeWithPython, + // AI 解读 + aiReading, + aiFullReading, + aiQuickInsight, }; diff --git a/jyotish-app/index.html b/jyotish-app/index.html index 99cf916a..d216aabb 100644 --- a/jyotish-app/index.html +++ b/jyotish-app/index.html @@ -191,6 +191,10 @@
+ +
+

星盘计算完成后将自动生成 AI 个性化解读

+
diff --git a/jyotish-app/main.js b/jyotish-app/main.js index 3acbabb7..7fed40ef 100644 --- a/jyotish-app/main.js +++ b/jyotish-app/main.js @@ -216,35 +216,29 @@ function setupForm() { const [hour, minute] = timeVal.split(':').map(Number); btnText.classList.add('hidden'); btnLoading.classList.remove('hidden'); btn.disabled = true; try { - // v6.9.2: API优先, 不可用时回退JS引擎 - if (window.JyotishAPI) { - chartData = await window.JyotishAPI.computeAll({ year, month, day, hour, minute, lat, lon, tz }); - if (!chartData || !chartData.success) throw new Error(chartData?.error || 'API计算失败'); - console.log('[Jyotish] ✅ API —', chartData.dasha_count, 'Dasha,', chartData.yogas?.length || 0, 'Yoga'); - } else { - throw new Error('API桥接未加载'); - } - } catch (apiErr) { - console.warn('[Jyotish] API不可用:', apiErr.message, '→ 回退JS引擎'); - try { + // v6.9.4: 计算层 — 优先Python API, 回退JS引擎 + chartData = await window.JyotishAPI?.computeWithPython({ year, month, day, hour, minute, lat, lon, tz }); + if (!chartData || !chartData.success) { await initEngine(); chartData = await computeChart({ year, month, day, hour, minute, lat, lon, tz }); chartData._fallback = true; - console.log('[Jyotish] ⚠️ JS引擎回退成功'); - } catch (jsErr) { - console.error('[Jyotish] JS引擎也失败:', jsErr); - alert('计算失败: ' + (apiErr.message || jsErr.message) + '\n请检查网络或启动API服务器'); - btnText.classList.remove('hidden'); btnLoading.classList.add('hidden'); btn.disabled = false; - return; + console.log('[Jyotish] ⚠️ JS引擎计算完成'); + } else { + console.log('[Jyotish] ✅ Python API —', chartData.dasha_count, 'Dasha'); } + } catch (e) { + console.error('[Jyotish] 计算失败:', e); + alert('计算失败: ' + e.message); + btnText.classList.remove('hidden'); btnLoading.classList.add('hidden'); btn.disabled = false; + return; } try { - // 保存出生数据供生时校正使用 window.__jyotishBirth = { year, month, day, hour, minute, lat, lon, tz }; renderAll(); showPage('chart'); - // 将当前星盘数据传给 AI 聊天 aiChatSetChartData(chartData); + // v6.9.4: 触发 AI 解读 + triggerAIReading(chartData); } catch (err) { console.error('[Jyotish] Error:', err); alert(t('alert.error') + err.message); @@ -579,6 +573,28 @@ function renderTransitCompareTab(chartData) { }; } +// ============================================================================ +// AI 解读触发 (v6.9.4) +// ============================================================================ +async function triggerAIReading(chartData) { + if (!window.JyotishAPI?.aiFullReading) return; + const summaryEl = document.getElementById('chart-summary'); + if (summaryEl) summaryEl.innerHTML += '

🤖 AI 正在生成个性化解读...

'; + try { + const result = await window.JyotishAPI.aiFullReading(chartData); + if (result.success) { + if (summaryEl) { + summaryEl.innerHTML = '
' + + result.reading.replace(/\n/g, '
') + '
'; + } + console.log('[AI] ✅ 解读生成成功'); + } + } catch(e) { + console.warn('[AI] 解读失败:', e.message); + if (summaryEl) summaryEl.innerHTML += '

AI解读不可用,请查看结构化数据

'; + } +} + // ============================================================================ // 星盘中心摘要构建 // ============================================================================