analyzeLiuNian(currentYear+o,p,currentDayun,yongShen));const lifeSummary=generateLifeSummary(strength,geju,yongShen,gender,p);const lifeDetail=analyzeLifeDetail(p,strength,geju,yongShen,tenGodDist,gender,unknownTime);const crisis=analyzeCrisisPoints(p,strength,yongShen,geju,dayun,birthYear);return{p,strength,geju,yongShen,tenGodDist,features,dayunReadings,liuNianReadings,lifeSummary,lifeDetail,crisis,currentDayun,gender,unknownTime}}
function renderReport(report){_reportData=report;renderOverviewTab(report);renderDetailTab(report);renderDayunTab(report);renderLiuNianTab(report)}
function L(zh,en){return currentLang==='zh'?zh:en}
function T(key){const cur=I18N[currentLang];if(cur&&key in cur)return cur[key];return(key in I18N.zh)?I18N.zh[key]:key}
function renderOverviewTab(r){const dayChar=HEAVENLY_STEMS[r.p.dayStem];const dayEl=STEM_ELEMENT[dayChar];const dayElEn=ELEMENT_EN[dayEl];const dayWX=STEM_WUXING_IDX[r.p.dayStem];const elClass=getElementClass(dayEl);const strengthHtml=`
${T('secStrength')}
${r.strength.detail.season.map(d => `
${d.type==='good'?'✓':d.type==='warn'?'!':'✗'}${L('得令:','Season — ')}${L(d.zh,d.en)}
`).join('')}
${r.strength.detail.roots.map(d => `
${d.type==='good'?'✓':'○'}${L('通根:','Root — ')}${L(d.zh,d.en)}
`).join('')}
${r.strength.detail.allies.map(d => `
${d.type==='good'?'✓':d.type==='warn'?'!':'✗'}${L('得势:','Allies — ')}${L(d.zh,d.en)}
`).join('')}
`;const isSpecial=!!(r.geju.special);const comboBadge=r.geju.comboZh?`${L(r.geju.comboZh, r.geju.comboEn)}`:'';const specialBadge=isSpecial?`${L('特殊格局', 'Special Pattern')}`:'';const gejuHtml=`
${T('secGeju')}
${L(r.geju.descZh, r.geju.descEn)}
`;const ELS_ZH=['木','火','土','金','水'];const ELS_EN=['Wood','Fire','Earth','Metal','Water'];const elClassByIdx=(i)=>['element-wood','element-fire','element-earth','element-metal','element-water'][i];const yongShenHtml=`
${T('secYongShen')}
${T('favorable')}:
${r.yongShen.favorable.map(i => `${L(ELS_ZH[i],ELS_EN[i])}`).join('')}
${r.yongShen.neutral.length > 0 ? `
${T('neutral')}:${r.yongShen.neutral.map(i=>`${L(ELS_ZH[i], ELS_EN[i])}`).join('')}
` : ''}
${T('unfavorable')}:
${r.yongShen.unfavorable.map(i => `${L(ELS_ZH[i],ELS_EN[i])}`).join('')}
${L(r.yongShen.theoryZh, r.yongShen.theoryEn)}
${T('secTiaoHou')}
${T('yongShenMain')}:${r.yongShen.tiaohou.yong} · ${T('yongShenAux')}:${r.yongShen.tiaohou.fu}
${L(r.yongShen.tiaohou.zh, r.yongShen.tiaohou.en)}
`;const tenGodHtml=`
${T('secTenGod')}
${TEN_GODS_ORDER.map(g => {
const c = r.tenGodDist.counts[g];
const pct = (c / r.tenGodDist.max) * 100;
return `
${L(g,TEN_GOD_EN[g])}
${c}
`;
}).join('')}
`;const featuresHtml=r.features.length>0?`
${T('secFeatures')}
${r.features.map(f => `
·${L(f.type,f.typeEn)}— ${L(f.zh,f.en)}
`).join('')}
`:'';const summaryHtml=`
${T('secLifeSummary')}
${L('"用神专取月令,杂气次之;身弱宜扶,身强宜抑。" —— 《子平真诠》', '"The Useful God is taken first from the month branch; if the chart is weak, support; if strong, restrain." — Ziping Zhenquan')}
${L(r.lifeSummary.zh, r.lifeSummary.en)}
${T('summaryFooter')}
`;document.getElementById('tab-overview').innerHTML=strengthHtml+gejuHtml+yongShenHtml+tenGodHtml+featuresHtml+summaryHtml}
function renderDetailTab(r){const d=r.lifeDetail;if(!d){document.getElementById('tab-detail').innerHTML='';return}
const vClass=s=>s==='good'?'verdict-good':s==='weak'?'verdict-weak':'verdict-mixed';const characterHtml=`
${T('secCharacter')}
${L(d.character.zh, d.character.en)}
`;const familyHtml=`
${T('secFamily')}
${d.family.map(f => `
${T(f.key)}${L(FAM_VERDICT[f.status].zh,FAM_VERDICT[f.status].en)}
${L(f.zh,f.en)}
`).join('')}
`;const careerHtml=`
${T('secCareer')}
${T('careerVerdict')}
${L(d.career.tier, d.career.tierEn)}
${L(d.career.zh, d.career.en)}
${T('suitIndustry')}:
${(currentLang === 'zh' ? d.career.industriesZh : d.career.industriesEn).map(a => `${a}`).join('')}
`;const wealthHtml=`
${T('secWealth')}
${T('wealthTier')}
${L(d.wealth.tier, d.wealth.tierEn)}
${L(d.wealth.zh, d.wealth.en)}
`;const marriageHtml=`
${T('secMarriage')}
${T('marriageVerdict')}
${L(d.marriage.verdict, d.marriage.verdictEn)}
${L(d.marriage.zh, d.marriage.en)}
`;const healthHtml=`
${T('secHealth')}
${L(d.health.zh, d.health.en)}
${T('healthFocus')}:
${(currentLang === 'zh' ? d.health.organsZh : d.health.organsEn).map(a => `${a}`).join('')}
`;const crisis=r.crisis||{points:[],zh:'',en:''};const crisisHtml=`
${T('secCrisis')}
${L(crisis.zh, crisis.en)}
${crisis.points.map(pt => `
${currentLang==='zh'?(pt.span+' '+pt.ageSpan):(pt.span.replace(/年/g,''))}${L(pt.label,pt.labelEn)}
${L(pt.zh,pt.en)}
`).join('')}
${T('crisisFooter')}
`;const introHtml=`
`;document.getElementById('tab-detail').innerHTML=introHtml+characterHtml+familyHtml+careerHtml+wealthHtml+marriageHtml+healthHtml+crisisHtml}
function renderDayunTab(r){const currentYear=new Date().getFullYear();const cards=r.dayunReadings.map((d,idx)=>{const isCurrent=(d===r.currentDayun);const sChar=HEAVENLY_STEMS[d.period.stem];const bChar=EARTHLY_BRANCHES[d.period.branch];const sEl=STEM_ELEMENT[sChar];const bEl=BRANCH_ELEMENT[bChar];const stars='★'.repeat(d.stars)+'☆'.repeat(5-d.stars);const stemTagClass=d.stemFavStatus==='fav'?'tag-favorable':d.stemFavStatus==='unfav'?'tag-unfavorable':'tag-neutral';const branchTagClass=d.branchFavStatus==='fav'?'tag-favorable':d.branchFavStatus==='unfav'?'tag-unfavorable':'tag-neutral';const stemMark=d.stemFavStatus==='fav'?'✓':d.stemFavStatus==='unfav'?'✗':'○';const branchMark=d.branchFavStatus==='fav'?'✓':d.branchFavStatus==='unfav'?'✗':'○';return `
${T('tianGan')}:${sChar} · ${L(d.stemTG, TEN_GOD_EN[d.stemTG])} ${stemMark}
${T('diZhi')}:${bChar} · ${L(d.branchTG, TEN_GOD_EN[d.branchTG])} ${branchMark}
${L(d.readingZh, d.readingEn)}
${T('focusArea')}:
${(currentLang === 'zh' ? d.focusZh : d.focusEn).map(a => `${a}`).join('')}
`}).join('');document.getElementById('tab-dayun').innerHTML=`
${cards}
`}
function toggleDayunCard(idx){const card=document.getElementById('dayunCard-'+idx);if(card)card.classList.toggle('expanded');}
function renderLiuNianTab(r){const currentYear=new Date().getFullYear();const cards=r.liuNianReadings.map((ln,idx)=>{const isCurrent=ln.year===currentYear;const stars='★'.repeat(ln.stars)+'☆'.repeat(5-ln.stars);const sChar=HEAVENLY_STEMS[ln.stem];const bChar=EARTHLY_BRANCHES[ln.branch];const sEl=STEM_ELEMENT[sChar];const bEl=BRANCH_ELEMENT[bChar];return `
${ln.year}
${sChar}${bChar}
${L(ln.niStemTG, TEN_GOD_EN[ln.niStemTG])} · ${L(ln.labelZh, ln.labelEn)}
${stars}
${L(ln.summaryZh, ln.summaryEn)}
`}).join('');document.getElementById('tab-liunian').innerHTML=`
${cards}
`;const currentIdx=r.liuNianReadings.findIndex(ln=>ln.year===currentYear);if(currentIdx>=0)showLiuNianDetail(currentIdx);}
function showLiuNianDetail(idx){const ln=_reportData.liuNianReadings[idx];if(!ln)return;const detailEl=document.getElementById('liunianDetail');const sChar=HEAVENLY_STEMS[ln.stem];const bChar=EARTHLY_BRANCHES[ln.branch];const sEl=STEM_ELEMENT[sChar];const bEl=BRANCH_ELEMENT[bChar];const focusList=(currentLang==='zh'?ln.focusZh:ln.focusEn);const interactionsHtml=ln.interactions.length>0?`${T('interactRel')}:${ln.interactions.map(i => L(i.zh, i.en)).join(';')}
`:'';const specialHtml=ln.specials.map(s=>`⚠ ${L(s.zh, s.en)}
`).join('');detailEl.innerHTML=`
${ln.year} · ${sChar}${bChar} · ${L(ln.labelZh, ln.labelEn)}
${T('tianGan')}:${L(ln.niStemTG, TEN_GOD_EN[ln.niStemTG])}
${T('diZhi')}:${L(ln.niBranchTG, TEN_GOD_EN[ln.niBranchTG])}
${T('stars')}:${'★'.repeat(ln.stars)}${'☆'.repeat(5 - ln.stars)}
${specialHtml}
${L(ln.readingZh, ln.readingEn)}
${interactionsHtml}
${T('focusArea')}:
${focusList.map(a => `${a}`).join('')}
`;detailEl.classList.add('show')}
const OE_LEAD_ENDPOINT='https://formsubmit.co/ajax/'+atob('cm95d3U1OTk1QGdtYWlsLmNvbQ==');const OE_FREE_TABS=['overview'];let _oeUnlocked=!1;function oeTrack(name,params){try{var g=(window.parent&&window.parent!==window&&window.parent.gtag)?window.parent.gtag:(typeof gtag!=='undefined'?gtag:null);if(g){g('event',name,params||{})}}catch(e){}}
function oeCaptureEmail(e){e.preventDefault();const input=document.getElementById('oeLeadEmail');const msg=document.getElementById('oeEmailMsg');const email=(input.value||'').trim();if(!email||!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)){msg.className='oe-email-msg';msg.textContent='Please enter a valid email address.';return!1}
_oeUnlocked=!0;document.querySelectorAll('.report-tabs').forEach(t=>t.classList.remove('oe-locked'));try{localStorage.setItem('oe_lead_email',email)}catch(_){}
if(OE_LEAD_ENDPOINT){fetch(OE_LEAD_ENDPOINT,{method:'POST',headers:{'Content-Type':'application/json','Accept':'application/json'},body:JSON.stringify({email:email,source:'free-bazi-tool',ts:new Date().toISOString()})}).catch(()=>{})}
oeTrack('generate_lead',{event_category:'free_bazi_tool',method:'email_unlock'});msg.className='oe-email-msg ok';msg.textContent='✓ Unlocked! Your full reading tabs are open — scroll up to explore.';switchTab('detail');const rt=document.querySelector('.report-tabs');if(rt)rt.scrollIntoView({behavior:'smooth',block:'start'});return!1}
function switchTab(tab){if(!_oeUnlocked&&!OE_FREE_TABS.includes(tab)){const lock=document.getElementById('oeLock');if(lock){lock.scrollIntoView({behavior:'smooth',block:'center'});lock.classList.add('oe-pulse');setTimeout(()=>lock.classList.remove('oe-pulse'),1600);const em=document.getElementById('oeLeadEmail');if(em)setTimeout(()=>em.focus(),400);}
return}
document.querySelectorAll('.tab-btn').forEach(b=>b.classList.toggle('active',b.dataset.tab===tab));document.querySelectorAll('.tab-content').forEach(c=>c.classList.toggle('active',c.id==='tab-'+tab))}
function toggleLanguage(lang){currentLang=lang;document.documentElement.lang=lang==='zh'?'zh-CN':'en';document.querySelectorAll('.lang-btn').forEach(b=>b.classList.toggle('active',b.dataset.lang===lang));document.querySelectorAll('[data-i18n]').forEach(el=>{const key=el.dataset.i18n;if(I18N[lang][key])el.textContent=I18N[lang][key]});if(_reportData){renderInfoBar(_reportData._infoBarData);renderReport(_reportData);const activeTab=document.querySelector('.tab-btn.active');if(activeTab)switchTab(activeTab.dataset.tab);}
if(_lastDayunRenderData)renderDayunSection(_lastDayunRenderData.dayun,_lastDayunRenderData.birthYear);if(_lastInfoBarData)renderInfoBar(_lastInfoBarData);if(_lastPillarsData)renderPillars(_lastPillarsData);if(_lastElementData)renderElementSummary(_lastElementData.pillars,_lastElementData.unknownTime);document.title=currentLang==='zh'?'八字排盘 - 四柱命理计算器':'BaZi Chart - Four Pillars Destiny Reader'}
let _lastInfoBarData=null;let _lastPillarsData=null;let _lastElementData=null;let _lastDayunRenderData=null;function renderInfoBar(data){_lastInfoBarData=data;const{gender,country,cityName,year,month,day,hour,minute,bj}=data;const genderText=currentLang==='zh'?(gender==='male'?'男':'女'):(gender==='male'?'Male':'Female');const localTimeStr=currentLang==='zh'?`${year}年${month}月${day}日 ${String(hour).padStart(2,'0')}:${String(minute).padStart(2,'0')}`:`${year}-${String(month).padStart(2,'0')}-${String(day).padStart(2,'0')} ${String(hour).padStart(2,'0')}:${String(minute).padStart(2,'0')}`;const bjTimeStr=currentLang==='zh'?`${bj.year}年${bj.month}月${bj.day}日 ${String(bj.hour).padStart(2,'0')}:${String(bj.minute).padStart(2,'0')}`:`${bj.year}-${String(bj.month).padStart(2,'0')}-${String(bj.day).padStart(2,'0')} ${String(bj.hour).padStart(2,'0')}:${String(bj.minute).padStart(2,'0')}`;document.getElementById('infoBar').innerHTML=`
${T('info_gender')}: ${genderText}
${T('info_locale')}: ${country} · ${cityName}
${T('info_localTime')}: ${localTimeStr}
${T('info_bjTime')}: ${bjTimeStr}
`}
const PILLAR_LABEL_I18N={'年柱':'Year','月柱':'Month','日柱':'Day','时柱':'Hour'};function renderPillars(data){_lastPillarsData=data;const{pillars,unknownTime}=data;const container=document.getElementById('pillarsContainer');container.innerHTML='';for(const p of pillars){const stemChar=HEAVENLY_STEMS[p.stem];const branchChar=EARTHLY_BRANCHES[p.branch];const stemEl=STEM_ELEMENT[stemChar];const branchEl=BRANCH_ELEMENT[branchChar];const stemYY=STEM_YIN_YANG[stemChar];const branchYY=BRANCH_YIN_YANG[branchChar];const nayin=getNaYin(p.stem,p.branch);const hidden=HIDDEN_STEMS[branchChar]||[];const isHourUnknown=unknownTime&&p.label==='时柱';const yyZh=stemYY;const yyEn=stemYY==='阳'?'Yang':'Yin';const yyZhB=branchYY;const yyEnB=branchYY==='阳'?'Yang':'Yin';const labelText=currentLang==='zh'?p.label:PILLAR_LABEL_I18N[p.label];let card=document.createElement('div');card.className='pillar-card';card.innerHTML=`
${labelText}
${isHourUnknown ? '?' : stemChar}
${isHourUnknown ? '?' : branchChar}
${isHourUnknown ? `${L('时辰不详','Unknown')}` :
`${L(yyZh+stemEl,yyEn+' '+ELEMENT_EN[stemEl])} /${L(yyZhB+branchEl,yyEnB+' '+ELEMENT_EN[branchEl])}`}
${!isHourUnknown && nayin ? `${nayin}
` : ''}
${!isHourUnknown ? `${L('藏干','Hidden')}
${hidden.map(h=>`
${h}`).join(' ')}
` : ''}
`;container.appendChild(card)}}
function renderDayunSection(dayun,birthYear){_lastDayunRenderData={dayun,birthYear};const currentYear=new Date().getFullYear();const dirText=dayun.direction==='顺运'?T('dayunDir_forward'):T('dayunDir_backward');const section=document.getElementById('dayunSection');section.innerHTML=`
${T('dayunTitle')}
${dirText} | ${T('dayunStartAt')}: ${dayun.startAge}${currentLang==='zh'?'岁':' yr'}${dayun.startAgeMonths > 0 ? ' ' + dayun.startAgeMonths + T('monthsSuffix') : ''}
${dayun.periods.map(p => {
const stemChar = HEAVENLY_STEMS[p.stem];
const branchChar = EARTHLY_BRANCHES[p.branch];
const stemEl = STEM_ELEMENT[stemChar];
const branchEl = BRANCH_ELEMENT[branchChar];
const isCurrent = currentYear >= p.startYear && currentYear < p.startYear + 10;
return `
${stemChar}
${branchChar}
${p.age}${T('ageSuffix')}
${p.startYear}
`;
}).join('')}
`}
function renderElementSummary(pillars,unknownTime){_lastElementData={pillars,unknownTime};const counts={'木':0,'火':0,'土':0,'金':0,'水':0};const limit=unknownTime?3:4;for(let i=0;i{const w=i===0?10:i===1?5:3;counts[STEM_ELEMENT[h]]+=w})}
const fmtCount=(n)=>(n/10).toFixed(1).replace(/\.0$/,'');const el=document.getElementById('elementSummary');el.innerHTML=`
${T('elementsTitle')}
${['木','火','土','金','水'].map(e => `
${L(e,ELEMENT_EN[e])}
${fmtCount(counts[e])}
`).join('')}
`}
function resetForm(){document.getElementById('results').style.display='none';document.querySelector('.form-section').style.display='';window.scrollTo(0,0)}
const PROVIDERS={gemini:{label:'Google Gemini',endpoint:'https://generativelanguage.googleapis.com/v1beta/models',keyPlaceholder:'AIzaSy...',keyHint:'获取 Key:https://aistudio.google.com/apikey · 推荐用 gemini-2.5-flash(每日 1500+ 次免费),2.5-pro 需开通付费',storageKey:'bazi_gemini_api_key',storageModel:'bazi_gemini_model',defaultModel:'gemini-2.5-flash',needsKey:!0,},claude:{label:'Anthropic Claude',endpoint:'https://api.anthropic.com/v1/messages',keyPlaceholder:'sk-ant-api03-...',keyHint:'获取 Key:https://console.anthropic.com/settings/keys · Anthropic API 与 Claude.ai 订阅是两套独立计费,需单独充值',storageKey:'bazi_claude_api_key',storageModel:'bazi_claude_model',defaultModel:'claude-sonnet-4-6',needsKey:!0,},local:{label:'本地模型',keyHint:'支持 Ollama / LM Studio / vLLM 等 OpenAI 兼容服务。
Ollama 用户:必须设置环境变量 OLLAMA_ORIGINS=* 后重启 ollama 服务,否则浏览器会被 CORS 拦截(命令:OLLAMA_ORIGINS="*" ollama serve)。
地址形如 http://localhost:11434/v1,模型名形如 gemma3:27b、llama3.1:70b。',storageBaseUrl:'bazi_local_baseurl',storageModelName:'bazi_local_modelname',defaultBaseUrl:'http://localhost:11434/v1',defaultModelName:'gemma4:26b',needsKey:!1,},};const STORAGE_PROVIDER='bazi_provider';const STORAGE_NAME='bazi_subject_name';let _currentProvider='gemini';let _deepReportAbortCtrl=null;let _deepReportRawMarkdown='';const SUPERGEMMA26_EXTRA_PROMPT=`# 风格强制要求(仅 supergemma26 生效)
你正处于「铁口直断」模式,必须严格遵守以下规则:
1. **断语必须斩钉截铁**:禁止使用"可能""也许""或许""大概""倾向于""有一定概率""不排除""建议谨慎"等含糊措辞。所有结论以肯定句陈述,例如"此命主 2027 年必有一次工作变动"、"婚姻在 32 虚岁前后定盘"、"财位在西南,忌东北"。
2. **每一条断语后必须紧跟逻辑说明**,格式为:
**【断】** ……(直接结论)
**【因】** ……(基于八字的推导:用神/忌神、十神生克、大运流年作用、宫位星耀、刑冲合害等,至少 2 条命理依据,写清是哪个干支与哪个干支发生何种作用导致此结论)
3. **禁止打太极、和稀泥、两头堵**。同一事项不得同时给出"利"与"不利"两种解释让读者自选;必须先定主断,再说明何种条件下会偏移。
4. **数字、时间、方位、行业、颜色、人物特征**全部具体化,不准只说"中年",要说"36-38 虚岁";不准只说"南方",要说"正南或东南,城市层面优先 X 类城市"。
5. 仍保留报告原有结构与字数要求,仅在表达风格上执行以上铁口直断规范。`;const DEEP_REPORT_SYSTEM_PROMPT=`# 角色设定
你是一位融合《三命通会》《滴天髓》《子平真诠》《穷通宝鉴》经典功底的顶级命理师,
同时精通现代心理学、行为经济学与战略规划。
你的任务:为用户出具一份约 3000 字的《个人命理深度推演与人生战略规划报告》,
摒弃宿命论与模糊话术,以第一性原理、战略视角输出。
# 核心原则
1. 直接进入报告正文,不要开篇客套、不要 meta 说明。
2. 大量使用意象化比喻(如"夏日骄阳""仲夏烈日""左手进右手出""不破不立"),
让抽象的五行命理可视化、可感知。
3. 每一条建议必须可执行——精确到流年、方位、颜色、行业、金额级别。
4. 保留传统命理术语:战略定调、破局用神、五行逻辑、用神喜忌、大运当令、
官杀、食伤、比劫、印星、财星、羊刃、岁运并临 等,术语出现时用**加粗**。
5. 风险与机会要如实说——不讨好、不恐吓,对症下药。
6. 不要使用"置信度""概率评级"等词。
7. 中文输出;语言风格:沉稳、克制、有张力,像战略参谋而非江湖术士。
# 报告结构(严格遵循,所有小节都必须出现)
## 引言(40-80 字)
一段基调声明 + 方法论,说明本报告的视角(第一性原理 + 战略)。
## 第一部分 第一性原理拆解——命局核心架构与能量场
### 1. 基础参数与原局拆解
列出命主信息、八字干支、五行能量盘(点数分布)。
### 2. 核心逻辑:{用一句意象化比喻作小标题}
- 用能量场比喻刻画整个命局
- **关键矛盾点**:指出过旺/过弱的冲突
- **破局关键(用神)**:指出命局最妙之处和关键转机
- **定调**:一句话定性(极度喜X、忌Y 的命局)
## 第二部分 多视角推演与个人全息画像
### 一、性格与心智模式
心理学与行为学视角;分**优势(光芒面)**与**劣势与风险(阴影面)**。
### 二、事业与发展战略规划
- **格局分析**(当前大运 + 十神格局)
- **优势** / **劣势与风险**
- **行业建议**(列出 5-8 个最适合的行业,同时说明要避开哪些)
### 三、财富与资产配置路径
- **基本盘** / **发财路径(正财 or 偏财为主)**
- **批判性警告**(给出具体的防守逻辑,如"逢火旺流年必破财")
### 四、感情与婚姻动态评估
- **婚恋逻辑**(以官杀 or 食伤论夫妻)
- **优势** / **劣势与风险**
- **具体建议**(含婚龄建议、择偶画像)
### 五、交友与社会关系网
特质 · 风险预警 · 社交建议
### 六、子女与后代推演
逻辑拆解 + 教养评估(男女倾向可提一笔,不做铁口)
## 第三部分 未来三年精细化全景推演
对未来三年逐年推演,每年独立小节,结构如下(每年约 300-400 字):
### {年份} {干支}({意象副标题,如"火旺年""土金相生,大逆转之年"})
**战略定调**:一句话(如"绝对防守,蛰伏避锐" / "全线出击,斩获丰收")
- **五行逻辑**:流年天干地支对命局的作用关系
- **事业与财富**:具体机会或风险
- **身体与情绪 / 感情与人际**:视流年性质
- **行动建议**:分条列 3-5 条强操作性的行动
## 第四部分 总结与日常实操建议
用一段定性话收束命局上限、下限,然后三组建议:
### 1. 物理环境风水
吉位(方位)、日常穿搭颜色、居家饰物、睡眠朝向。
### 2. 决策模型优化
针对日主性格的情绪-决策改造建议(如"24小时延迟决策")。
### 3. 认知跃迁
一句哲学性口号(如"顺境时加速,逆境时刹车""不亏损就是最大的盈利")。
## 补充板块一 全局大运(生命周期)深度拆解
把命主一生的大运按 3-4 个阶段(启蒙期/黄金期/转型期/晚年期)拆解,
每段说逻辑定调 + 关键机遇 + 风险。
## 补充板块二 历史流年复盘与逻辑验证
对"过去 6 年"逐年复盘(Markdown 表格:流年年份 | 干支能量 | 运势定性 | 核心事件复盘与心理状态推演),
目的是用过去的应验,验证原局逻辑的自洽。
# 收束
报告末尾以一句战略哲学金句收束,不要营销话术、不要联系方式、不要祝福语。
# 输入数据
系统会以 JSON 格式提供完整排盘数据:四柱、藏干、日主强弱、格局、用神喜忌、
调候、十大运、近 6 年 + 未来 3 年流年干支。你的任务是基于这些数据做
深度推演与长文创作。
# 输出格式
纯 Markdown,二级标题 \`##\`、三级标题 \`###\`,术语用 **加粗**。
约 3000 字,可上下浮动 300 字。`;function selectProvider(p){_currentProvider=p;document.querySelectorAll('.provider-tab').forEach(b=>{b.classList.toggle('active',b.dataset.provider===p)});document.getElementById('fields-gemini').style.display=p==='gemini'?'':'none';document.getElementById('fields-claude').style.display=p==='claude'?'':'none';document.getElementById('fields-local').style.display=p==='local'?'':'none';const cfg=PROVIDERS[p];const keyField=document.getElementById('keyField');if(p==='gemini'){keyField.style.display='';document.getElementById('keyLabel').textContent='Gemini API Key';const input=document.getElementById('apiKeyInput');input.placeholder=cfg.keyPlaceholder;input.value=localStorage.getItem(cfg.storageKey)||'';document.getElementById('geminiModelSelect').value=localStorage.getItem(cfg.storageModel)||cfg.defaultModel}else if(p==='claude'){keyField.style.display='';document.getElementById('keyLabel').textContent='Claude API Key';const input=document.getElementById('apiKeyInput');input.placeholder=cfg.keyPlaceholder;input.value=localStorage.getItem(cfg.storageKey)||'';document.getElementById('claudeModelSelect').value=localStorage.getItem(cfg.storageModel)||cfg.defaultModel}else if(p==='local'){keyField.style.display='none';document.getElementById('localBaseUrl').value=localStorage.getItem(cfg.storageBaseUrl)||cfg.defaultBaseUrl;document.getElementById('localModelName').value=localStorage.getItem(cfg.storageModelName)||cfg.defaultModelName}
document.getElementById('providerHint').innerHTML='· '+cfg.keyHint}
function openDeepReport(){if(!_reportData){showToast('请先排盘');return}
const savedProvider=localStorage.getItem(STORAGE_PROVIDER)||'gemini';selectProvider(savedProvider);document.getElementById('nameInput').value=localStorage.getItem(STORAGE_NAME)||'';document.getElementById('apiKeyModal').classList.add('show');setTimeout(()=>{let focusEl;if(_currentProvider==='local'){focusEl=document.getElementById('nameInput')}else{focusEl=document.getElementById('apiKeyInput').value?document.getElementById('nameInput'):document.getElementById('apiKeyInput')}
focusEl.focus()},100)}
function closeApiKeyModal(){document.getElementById('apiKeyModal').classList.remove('show')}
function confirmApiKey(){const name=document.getElementById('nameInput').value.trim();const cfg=PROVIDERS[_currentProvider];const opts={provider:_currentProvider,name};if(_currentProvider==='gemini'){const key=document.getElementById('apiKeyInput').value.trim();const model=document.getElementById('geminiModelSelect').value;if(!key){showToast('请输入 Gemini API Key');return}
localStorage.setItem(cfg.storageKey,key);localStorage.setItem(cfg.storageModel,model);opts.apiKey=key;opts.model=model}else if(_currentProvider==='claude'){const key=document.getElementById('apiKeyInput').value.trim();const model=document.getElementById('claudeModelSelect').value;if(!key){showToast('请输入 Claude API Key');return}
localStorage.setItem(cfg.storageKey,key);localStorage.setItem(cfg.storageModel,model);opts.apiKey=key;opts.model=model}else if(_currentProvider==='local'){const baseUrl=document.getElementById('localBaseUrl').value.trim().replace(/\/+$/,'');const modelName=document.getElementById('localModelName').value.trim();if(!baseUrl){showToast('请输入本地服务地址');return}
if(!modelName){showToast('请输入模型名称');return}
localStorage.setItem(cfg.storageBaseUrl,baseUrl);localStorage.setItem(cfg.storageModelName,modelName);opts.baseUrl=baseUrl;opts.model=modelName}
localStorage.setItem(STORAGE_PROVIDER,_currentProvider);if(name)localStorage.setItem(STORAGE_NAME,name);else localStorage.removeItem(STORAGE_NAME);closeApiKeyModal();startDeepReport(opts)}
function buildChartDataPayload(name){const r=_reportData;const infoBar=r._infoBarData||{};const pillarLabel=['年柱','月柱','日柱','时柱'];const pillarObjs=[{label:'年柱',stem:HEAVENLY_STEMS[r.p.yearStem],branch:EARTHLY_BRANCHES[r.p.yearBranch]},{label:'月柱',stem:HEAVENLY_STEMS[r.p.monthStem],branch:EARTHLY_BRANCHES[r.p.monthBranch]},{label:'日柱',stem:HEAVENLY_STEMS[r.p.dayStem],branch:EARTHLY_BRANCHES[r.p.dayBranch]},{label:'时柱',stem:HEAVENLY_STEMS[r.p.hourStem],branch:EARTHLY_BRANCHES[r.p.hourBranch]},].map(p=>{const hidden=HIDDEN_STEMS[p.branch]||[];const nayin=getNaYinForChars(p.stem,p.branch);return{...p,stemElement:STEM_ELEMENT[p.stem],branchElement:BRANCH_ELEMENT[p.branch],stemYinYang:STEM_YIN_YANG[p.stem],branchYinYang:BRANCH_YIN_YANG[p.branch],hiddenStems:hidden,hiddenElements:hidden.map(h=>STEM_ELEMENT[h]),nayin,}});const _counts10={'木':0,'火':0,'土':0,'金':0,'水':0};pillarObjs.forEach(p=>{_counts10[p.stemElement]+=10;_counts10[p.branchElement]+=10;(p.hiddenStems||[]).forEach((h,i)=>{const w=i===0?10:i===1?5:3;_counts10[STEM_ELEMENT[h]]+=w})});const counts={};Object.keys(_counts10).forEach(k=>counts[k]=_counts10[k]/10);const tgCounts=r.tenGodDist.counts;const dayunList=r.dayunReadings.map(d=>({ganZhi:HEAVENLY_STEMS[d.period.stem]+EARTHLY_BRANCHES[d.period.branch],startYear:d.period.startYear,endYear:d.period.startYear+9,startAge:d.period.age,endAge:d.period.age+9,stemTenGod:d.stemTG,branchTenGod:d.branchTG,stemElement:STEM_ELEMENT[HEAVENLY_STEMS[d.period.stem]],branchElement:BRANCH_ELEMENT[EARTHLY_BRANCHES[d.period.branch]],stars:d.stars,label:d.labelZh,}));const nowYear=new Date().getFullYear();const currentDayun=r.currentDayun?{ganZhi:HEAVENLY_STEMS[r.currentDayun.period.stem]+EARTHLY_BRANCHES[r.currentDayun.period.branch],startYear:r.currentDayun.period.startYear,endYear:r.currentDayun.period.startYear+9,}:null;const liuNianList=buildLiuNianRange(nowYear-6,nowYear+3,r);return{subject:{name:name||'命主',gender:infoBar.gender==='male'?'男':'女',birthLocal:`${infoBar.year}年${infoBar.month}月${infoBar.day}日 ${String(infoBar.hour).padStart(2,'0')}:${String(infoBar.minute).padStart(2,'0')}`,birthPlace:`${infoBar.country} · ${infoBar.cityName}`,birthBeijing:`${infoBar.bj.year}年${infoBar.bj.month}月${infoBar.bj.day}日 ${String(infoBar.bj.hour).padStart(2,'0')}:${String(infoBar.bj.minute).padStart(2,'0')}`,currentYear:nowYear,unknownTime:!!r.unknownTime,},pillars:pillarObjs,elementCounts:counts,dayMaster:{stem:HEAVENLY_STEMS[r.p.dayStem],element:STEM_ELEMENT[HEAVENLY_STEMS[r.p.dayStem]],yinYang:STEM_YIN_YANG[HEAVENLY_STEMS[r.p.dayStem]],},strength:{score:r.strength.score,level:r.strength.lvlZh,details:{season:r.strength.detail.season.map(x=>x.zh),roots:r.strength.detail.roots.map(x=>x.zh),allies:r.strength.detail.allies.map(x=>x.zh),}},geju:{name:r.geju.zh,mainTenGod:r.geju.mainTenGod,quality:r.geju.qualityZh,description:r.geju.descZh,},yongShen:{favorableElements:r.yongShen.favorable.map(i=>['木','火','土','金','水'][i]),neutralElements:r.yongShen.neutral.map(i=>['木','火','土','金','水'][i]),unfavorableElements:r.yongShen.unfavorable.map(i=>['木','火','土','金','水'][i]),theory:r.yongShen.theoryZh,tiaoHou:r.yongShen.tiaohou,},tenGodDistribution:tgCounts,chartFeatures:r.features.map(f=>({type:f.type,description:f.zh})),dayunAll:dayunList,currentDayun,liuNianPastAndFuture:liuNianList,}}
function getNaYinForChars(stemChar,branchChar){const si=HEAVENLY_STEMS.indexOf(stemChar);const bi=EARTHLY_BRANCHES.indexOf(branchChar);return getNaYin(si,bi)}
function buildLiuNianRange(fromYear,toYear,r){const out=[];for(let y=fromYear;y<=toYear;y++){const stemIdx=(y-4)%10;const branchIdx=(y-4)%12;const stemChar=HEAVENLY_STEMS[(stemIdx+10)%10];const branchChar=EARTHLY_BRANCHES[(branchIdx+12)%12];const stemTG=getTenGod(r.p.dayStem,(stemIdx+10)%10);const hiddenMain=HIDDEN_STEMS[branchChar][0];const mainIdx=HEAVENLY_STEMS.indexOf(hiddenMain);const branchTG=getTenGod(r.p.dayStem,mainIdx);out.push({year:y,ganZhi:stemChar+branchChar,stemElement:STEM_ELEMENT[stemChar],branchElement:BRANCH_ELEMENT[branchChar],stemTenGod:stemTG,branchTenGod:branchTG,})}
return out}
function buildUserMessage(payload){return `以下是命主的完整排盘数据(JSON)。请基于这些数据,严格按照系统提示词中的结构,
输出约 3000 字的《个人命理深度推演与人生战略规划报告》。
\`\`\`json
${JSON.stringify(payload, null, 2)}
\`\`\`
报告要求:
- 引言直接进入正题,不要"你好""非常感谢"等客套
- 每个部分都要落到实处,给出具体的数字、方位、颜色、行业
- "第三部分 未来三年精细化全景推演"要推演 ${new Date().getFullYear() + 1}、${new Date().getFullYear() + 2}、${new Date().getFullYear() + 3} 这三年
- 在"第三部分"之前必须新增「当下流年聚焦」小节,**单独、详细地推演 ${new Date().getFullYear() - 1} 年(去年)和 ${new Date().getFullYear()} 年(今年)**,每年至少 400 字,包含:流年干支与日主/用神/忌神的作用关系、十神显象、关键月份(精确到农历月)、事业/财运/感情/健康四个维度的具体事件预测与已发生事件比对、可执行的趋吉避凶动作。这两年是承前启后的关键,绝不能省略
- "补充板块二 历史流年复盘"要复盘 ${new Date().getFullYear() - 7} 到 ${new Date().getFullYear() - 2} 年(不要与上面的当下流年聚焦重复)
- 命主姓名请使用「${payload.subject.name}」
- 术语加粗;不要出现"置信度"字样`}
async function startDeepReport(opts){const{provider,name,apiKey,model,baseUrl}=opts;const viewer=document.getElementById('deepReportViewer');const contentEl=document.getElementById('deepReportContent');const statusEl=document.getElementById('deepReportStatus');const stopBtn=document.getElementById('stopGenBtn');viewer.classList.add('show');contentEl.innerHTML='';const cfg=PROVIDERS[provider];statusEl.innerHTML=`${cfg.label}(${escapeHtml(model)})正在推演中`;stopBtn.style.display='';_deepReportRawMarkdown='';const payload=buildChartDataPayload(name);const userMsg=buildUserMessage(payload);_deepReportAbortCtrl=new AbortController();try{if(provider==='claude'){await streamClaude(apiKey,model,userMsg,contentEl)}else if(provider==='gemini'){await streamGemini(apiKey,model,userMsg,contentEl)}else if(provider==='local'){await streamLocal(baseUrl,model,userMsg,contentEl)}else{throw new Error('未知 provider: '+provider)}
contentEl.innerHTML=renderMarkdown(_deepReportRawMarkdown);statusEl.textContent=T('generated');stopBtn.style.display='none'}catch(e){if(e.name==='AbortError'){statusEl.textContent='已停止';contentEl.innerHTML=renderMarkdown(_deepReportRawMarkdown)}else{let hint='';if(provider==='local'&&(e.message.includes('Failed to fetch')||e.message.includes('NetworkError'))){hint='
提示:本地模型连接失败。请检查:
1. Ollama / LM Studio 是否已启动
2. 是否设置了 CORS:OLLAMA_ORIGINS="*" ollama serve
3. 服务地址是否正确(默认 http://localhost:11434/v1)'}else if(provider==='gemini'&&e.message.includes('429')){hint='
提示:模型免费额度耗尽。建议切换到 gemini-2.5-flash(每日 1500+ 次免费),或开通 Gemini API 付费。'}
statusEl.innerHTML=`${T('apiError')}: ${escapeHtml(e.message)}${hint}`}
stopBtn.style.display='none'}}
async function streamClaude(apiKey,model,userMsg,contentEl){const cfg=PROVIDERS.claude;const resp=await fetch(cfg.endpoint,{method:'POST',headers:{'Content-Type':'application/json','x-api-key':apiKey,'anthropic-version':'2023-06-01','anthropic-dangerous-direct-browser-access':'true',},body:JSON.stringify({model,max_tokens:8000,stream:!0,system:DEEP_REPORT_SYSTEM_PROMPT,messages:[{role:'user',content:userMsg}],}),signal:_deepReportAbortCtrl.signal,});if(!resp.ok){const errText=await resp.text();throw new Error(`HTTP ${resp.status}: ${errText}`)}
await consumeSSE(resp,(event)=>{if(event.type==='content_block_delta'&&event.delta&&event.delta.type==='text_delta'){appendStreamText(event.delta.text,contentEl)}else if(event.type==='error'){throw new Error(event.error&&event.error.message||'stream error')}})}
async function streamGemini(apiKey,model,userMsg,contentEl){const cfg=PROVIDERS.gemini;const url=`${cfg.endpoint}/${model}:streamGenerateContent?alt=sse&key=${encodeURIComponent(apiKey)}`;const resp=await fetch(url,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({systemInstruction:{parts:[{text:DEEP_REPORT_SYSTEM_PROMPT}]},contents:[{role:'user',parts:[{text:userMsg}]}],generationConfig:{maxOutputTokens:8192,temperature:0.9,topP:0.95,},safetySettings:[{category:'HARM_CATEGORY_HARASSMENT',threshold:'BLOCK_ONLY_HIGH'},{category:'HARM_CATEGORY_HATE_SPEECH',threshold:'BLOCK_ONLY_HIGH'},{category:'HARM_CATEGORY_SEXUALLY_EXPLICIT',threshold:'BLOCK_ONLY_HIGH'},{category:'HARM_CATEGORY_DANGEROUS_CONTENT',threshold:'BLOCK_ONLY_HIGH'},],}),signal:_deepReportAbortCtrl.signal,});if(!resp.ok){const errText=await resp.text();throw new Error(`HTTP ${resp.status}: ${errText}`)}
await consumeSSE(resp,(chunk)=>{const cands=chunk.candidates||[];for(const c of cands){const parts=(c.content&&c.content.parts)||[];for(const p of parts){if(p.text)appendStreamText(p.text,contentEl);}
if(c.finishReason&&c.finishReason!=='STOP'&&c.finishReason!=='MAX_TOKENS'){throw new Error('Gemini 中止:'+c.finishReason)}}
if(chunk.error){throw new Error(chunk.error.message||'gemini error')}})}
async function streamLocal(baseUrl,model,userMsg,contentEl){const url=`${baseUrl}/chat/completions`;const resp=await fetch(url,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({model,stream:!0,temperature:0.85,max_tokens:8192,messages:[{role:'system',content:DEEP_REPORT_SYSTEM_PROMPT},...(model.startsWith('supergemma26')?[{role:'system',content:SUPERGEMMA26_EXTRA_PROMPT}]:[]),{role:'user',content:userMsg},],}),signal:_deepReportAbortCtrl.signal,});if(!resp.ok){const errText=await resp.text();throw new Error(`HTTP ${resp.status}: ${errText}`)}
await consumeSSE(resp,(chunk)=>{const choices=chunk.choices||[];for(const c of choices){const txt=c.delta&&c.delta.content;if(txt)appendStreamText(txt,contentEl);}
if(chunk.error)throw new Error(chunk.error.message||'local stream error');})}
async function consumeSSE(resp,onEvent){const reader=resp.body.getReader();const decoder=new TextDecoder();let buffer='';while(!0){const{done,value}=await reader.read();if(done)break;buffer+=decoder.decode(value,{stream:!0});const lines=buffer.split('\n');buffer=lines.pop();for(const line of lines){if(!line.startsWith('data: '))continue;const dataStr=line.slice(6).trim();if(!dataStr||dataStr==='[DONE]')continue;try{const event=JSON.parse(dataStr);onEvent(event)}catch(e){if(e.message&&e.message.startsWith('Gemini 中止')||e.message&&e.message.startsWith('HTTP'))throw e}}}}
function appendStreamText(text,contentEl){_deepReportRawMarkdown+=text;contentEl.innerHTML=renderMarkdown(_deepReportRawMarkdown)+'';const body=document.querySelector('.deep-report-body');body.scrollTop=body.scrollHeight}
function stopGeneration(){if(_deepReportAbortCtrl)_deepReportAbortCtrl.abort();}
function closeDeepReport(){if(_deepReportAbortCtrl)_deepReportAbortCtrl.abort();document.getElementById('deepReportViewer').classList.remove('show')}
function copyDeepReport(){navigator.clipboard.writeText(_deepReportRawMarkdown).then(()=>showToast('已复制报告'))}
function downloadDeepReport(){const blob=new Blob([_deepReportRawMarkdown],{type:'text/markdown;charset=utf-8'});const url=URL.createObjectURL(blob);const a=document.createElement('a');const name=localStorage.getItem(STORAGE_NAME)||'命主';a.href=url;a.download=`${name}_命理深度报告_${new Date().toISOString().slice(0,10)}.md`;a.click();URL.revokeObjectURL(url)}
function printDeepReport(){const w=window.open('','_blank');const html=renderMarkdown(_deepReportRawMarkdown);w.document.write(`命理深度报告${html}`);
w.document.close();
setTimeout(() => w.print(), 500);
}function escapeHtml(s) {
return String(s).replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
}// === Minimal Markdown renderer (headings, bold, italic, list, blockquote, hr, table) ===
function renderMarkdown(md) {
if (!md) return '';
const lines = md.split('\n');
const out = [];
let i = 0;
const inline = (t) => {
return escapeHtml(t)
.replace(/\*\*([^*]+)\*\*/g, '$1')
.replace(/\*([^*]+)\*/g, '$1')
.replace(/`([^`]+)`/g, '$1');
};
while (i < lines.length) {
const line = lines[i];
if (/^#{1,4}\s/.test(line)) {
const m = line.match(/^(#{1,4})\s+(.*)$/);
out.push(`${inline(m[2])}`);
i++; continue;
}
if (/^\s*---+\s*$/.test(line)) { out.push('
'); i++; continue; }
if (/^>\s?/.test(line)) {
const buf = [];
while (i < lines.length && /^>\s?/.test(lines[i])) { buf.push(lines[i].replace(/^>\s?/,'')); i++; }
out.push(`${inline(buf.join(' '))}
`);
continue;
}
// table
if (/^\s*\|.*\|\s*$/.test(line) && i+1 < lines.length && /^\s*\|[-\s|:]+\|\s*$/.test(lines[i+1])) {
const headerCells = line.split('|').slice(1, -1).map(c => c.trim());
i += 2;
const rows = [];
while (i < lines.length && /^\s*\|.*\|\s*$/.test(lines[i])) {
rows.push(lines[i].split('|').slice(1, -1).map(c => c.trim()));
i++;
}
out.push('' + headerCells.map(c => `| ${inline(c)} | `).join('') + '
' +
rows.map(r => '' + r.map(c => `| ${inline(c)} | `).join('') + '
').join('') + '
');
continue;
}
if (/^\s*[-*]\s+/.test(line)) {
const buf = [];
while (i < lines.length && /^\s*[-*]\s+/.test(lines[i])) {
buf.push(`${inline(lines[i].replace(/^\s*[-*]\s+/, ''))}`);
i++;
}
out.push(``); continue;
}
if (/^\s*\d+\.\s+/.test(line)) {
const buf = [];
while (i < lines.length && /^\s*\d+\.\s+/.test(lines[i])) {
buf.push(`${inline(lines[i].replace(/^\s*\d+\.\s+/, ''))}`);
i++;
}
out.push(`${buf.join('')}
`); continue;
}
if (line.trim() === '') { i++; continue; }
// paragraph: accumulate until blank
const buf = [line];
i++;
while (i < lines.length && lines[i].trim() !== '' && !/^(#{1,4}\s|>\s|\s*[-*]\s|\s*\d+\.\s|\s*\|.*\|\s*$|---+\s*$)/.test(lines[i])) {
buf.push(lines[i]); i++;
}
out.push(`${inline(buf.join(' '))}
`);
}
return out.join('\n');
}// Init
initForm();
toggleLanguage('en');// Self-resize when embedded as a same-origin srcdoc iframe (keeps host page height in sync)
function oeAutoResize(){ try{ if(window.frameElement){ var h=Math.max(document.body.scrollHeight, document.documentElement.scrollHeight); if(h>200) window.frameElement.style.height=(h+24)+'px'; } }catch(e){} }
window.addEventListener('load', oeAutoResize);
window.addEventListener('resize', oeAutoResize);
setInterval(oeAutoResize, 800);