| | |
| | |
| | |
| | |
| | import crypto from 'crypto'; |
| | import { getDb, nowIso } from './database.js'; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | export const computeBaziHash = (yearPillar, monthPillar, dayPillar, hourPillar) => { |
| | const combined = `${yearPillar}|${monthPillar}|${dayPillar}|${hourPillar}`; |
| | return crypto.createHash('sha256').update(combined).digest('hex').substring(0, 16); |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | export const getCachedAnalysis = (baziHash, gender) => { |
| | const db = getDb(); |
| | const stmt = db.prepare(` |
| | SELECT * FROM bazi_analysis_cache |
| | WHERE bazi_hash = ? AND gender = ? |
| | `); |
| |
|
| | const row = stmt.get(baziHash, gender); |
| | if (!row) return null; |
| |
|
| | return { |
| | id: row.id, |
| | baziHash: row.bazi_hash, |
| | gender: row.gender, |
| | |
| | structuralData: JSON.parse(row.structural_data || '{}'), |
| | |
| | personalityCore: JSON.parse(row.personality_core || '{}'), |
| | careerCore: JSON.parse(row.career_core || '{}'), |
| | wealthCore: JSON.parse(row.wealth_core || '{}'), |
| | marriageCore: JSON.parse(row.marriage_core || '{}'), |
| | healthCore: JSON.parse(row.health_core || '{}'), |
| | |
| | klineData: JSON.parse(row.kline_data || '[]'), |
| | peakYears: JSON.parse(row.peak_years || '[]'), |
| | troughYears: JSON.parse(row.trough_years || '[]'), |
| | |
| | cryptoCore: JSON.parse(row.crypto_core || '{}'), |
| | monthlyFortune: JSON.parse(row.monthly_fortune || '{}'), |
| | yearlyFortune: JSON.parse(row.yearly_fortune || '{}'), |
| | luckyElements: JSON.parse(row.lucky_elements || '{}'), |
| | physicalTraits: JSON.parse(row.physical_traits || '{}'), |
| | keyDates: JSON.parse(row.key_dates || '{}'), |
| | pastEvents: JSON.parse(row.past_events || '[]'), |
| | futureEvents: JSON.parse(row.future_events || '[]'), |
| | |
| | modelUsed: row.model_used, |
| | version: row.version, |
| | createdAt: row.created_at, |
| | }; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | export const cacheAnalysis = (data) => { |
| | const db = getDb(); |
| | const id = `cache_${data.baziHash}_${data.gender}_${Date.now()}`; |
| |
|
| | const stmt = db.prepare(` |
| | INSERT OR REPLACE INTO bazi_analysis_cache ( |
| | id, bazi_hash, gender, |
| | structural_data, personality_core, career_core, wealth_core, |
| | marriage_core, health_core, kline_data, peak_years, trough_years, |
| | crypto_core, monthly_fortune, yearly_fortune, lucky_elements, |
| | physical_traits, key_dates, past_events, future_events, |
| | model_used, version, created_at |
| | ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) |
| | `); |
| |
|
| | stmt.run( |
| | id, |
| | data.baziHash, |
| | data.gender, |
| | JSON.stringify(data.structuralData || {}), |
| | JSON.stringify(data.personalityCore || {}), |
| | JSON.stringify(data.careerCore || {}), |
| | JSON.stringify(data.wealthCore || {}), |
| | JSON.stringify(data.marriageCore || {}), |
| | JSON.stringify(data.healthCore || {}), |
| | JSON.stringify(data.klineData || []), |
| | JSON.stringify(data.peakYears || []), |
| | JSON.stringify(data.troughYears || []), |
| | JSON.stringify(data.cryptoCore || {}), |
| | JSON.stringify(data.monthlyFortune || {}), |
| | JSON.stringify(data.yearlyFortune || {}), |
| | JSON.stringify(data.luckyElements || {}), |
| | JSON.stringify(data.physicalTraits || {}), |
| | JSON.stringify(data.keyDates || {}), |
| | JSON.stringify(data.pastEvents || []), |
| | JSON.stringify(data.futureEvents || []), |
| | data.modelUsed || 'unknown', |
| | data.version || 1, |
| | nowIso() |
| | ); |
| |
|
| | return id; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | export const extractCoreData = (analysisResult, chartData) => { |
| | |
| | const sortedByScore = [...(chartData || [])].sort((a, b) => b.score - a.score); |
| | const peakYears = sortedByScore.slice(0, 5).map(p => ({ year: p.year, age: p.age, score: p.score })); |
| | const troughYears = sortedByScore.slice(-5).reverse().map(p => ({ year: p.year, age: p.age, score: p.score })); |
| |
|
| | return { |
| | structuralData: { |
| | bazi: analysisResult.bazi, |
| | summaryScore: analysisResult.summaryScore, |
| | }, |
| | personalityCore: { |
| | content: analysisResult.personality, |
| | score: analysisResult.personalityScore, |
| | }, |
| | careerCore: { |
| | content: analysisResult.industry, |
| | score: analysisResult.industryScore, |
| | }, |
| | wealthCore: { |
| | content: analysisResult.wealth, |
| | score: analysisResult.wealthScore, |
| | }, |
| | marriageCore: { |
| | content: analysisResult.marriage, |
| | score: analysisResult.marriageScore, |
| | }, |
| | healthCore: { |
| | content: analysisResult.health, |
| | score: analysisResult.healthScore, |
| | bodyParts: analysisResult.healthBodyParts || [], |
| | }, |
| | klineData: chartData, |
| | peakYears, |
| | troughYears, |
| | cryptoCore: { |
| | content: analysisResult.crypto, |
| | score: analysisResult.cryptoScore, |
| | cryptoYear: analysisResult.cryptoYear, |
| | cryptoStyle: analysisResult.cryptoStyle, |
| | }, |
| | monthlyFortune: { |
| | content: analysisResult.monthlyFortune, |
| | highlights: analysisResult.monthlyHighlights || [], |
| | }, |
| | yearlyFortune: { |
| | content: analysisResult.yearlyFortune, |
| | keyEvents: analysisResult.yearlyKeyEvents || [], |
| | }, |
| | luckyElements: { |
| | colors: analysisResult.luckyColors || [], |
| | directions: analysisResult.luckyDirections || [], |
| | zodiac: analysisResult.luckyZodiac || [], |
| | numbers: analysisResult.luckyNumbers || [], |
| | }, |
| | physicalTraits: { |
| | appearance: analysisResult.appearance, |
| | bodyType: analysisResult.bodyType, |
| | skin: analysisResult.skin, |
| | characterSummary: analysisResult.characterSummary, |
| | }, |
| | keyDates: { |
| | thisYear: analysisResult.keyDatesThisYear || [], |
| | thisMonth: analysisResult.keyDatesThisMonth || [], |
| | }, |
| | pastEvents: analysisResult.pastEvents || [], |
| | futureEvents: analysisResult.futureEvents || [], |
| | }; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | export const mergeCachedWithFresh = (cachedData, freshPolish = null) => { |
| | |
| | const result = { |
| | bazi: cachedData.structuralData?.bazi || [], |
| | summary: freshPolish?.summary || cachedData.structuralData?.summary || '命理分析已从缓存加载', |
| | summaryScore: cachedData.structuralData?.summaryScore || 5, |
| |
|
| | personality: cachedData.personalityCore?.content || '', |
| | personalityScore: cachedData.personalityCore?.score || 5, |
| |
|
| | industry: cachedData.careerCore?.content || '', |
| | industryScore: cachedData.careerCore?.score || 5, |
| |
|
| | wealth: cachedData.wealthCore?.content || '', |
| | wealthScore: cachedData.wealthCore?.score || 5, |
| |
|
| | marriage: cachedData.marriageCore?.content || '', |
| | marriageScore: cachedData.marriageCore?.score || 5, |
| |
|
| | health: cachedData.healthCore?.content || '', |
| | healthScore: cachedData.healthCore?.score || 5, |
| | healthBodyParts: cachedData.healthCore?.bodyParts || [], |
| |
|
| | family: freshPolish?.family || cachedData.familyCore?.content || '', |
| | familyScore: cachedData.familyCore?.score || 5, |
| |
|
| | fengShui: freshPolish?.fengShui || cachedData.fengShuiCore?.content || '', |
| | fengShuiScore: cachedData.fengShuiCore?.score || 5, |
| |
|
| | crypto: cachedData.cryptoCore?.content || '', |
| | cryptoScore: cachedData.cryptoCore?.score || 5, |
| | cryptoYear: cachedData.cryptoCore?.cryptoYear || '待定', |
| | cryptoStyle: cachedData.cryptoCore?.cryptoStyle || '现货定投', |
| |
|
| | |
| | monthlyFortune: cachedData.monthlyFortune?.content || '', |
| | monthlyHighlights: cachedData.monthlyFortune?.highlights || [], |
| |
|
| | yearlyFortune: cachedData.yearlyFortune?.content || '', |
| | yearlyKeyEvents: cachedData.yearlyFortune?.keyEvents || [], |
| |
|
| | luckyColors: cachedData.luckyElements?.colors || [], |
| | luckyDirections: cachedData.luckyElements?.directions || [], |
| | luckyZodiac: cachedData.luckyElements?.zodiac || [], |
| | luckyNumbers: cachedData.luckyElements?.numbers || [], |
| |
|
| | appearance: cachedData.physicalTraits?.appearance || '', |
| | bodyType: cachedData.physicalTraits?.bodyType || '', |
| | skin: cachedData.physicalTraits?.skin || '', |
| | characterSummary: cachedData.physicalTraits?.characterSummary || '', |
| |
|
| | keyDatesThisYear: cachedData.keyDates?.thisYear || [], |
| | keyDatesThisMonth: cachedData.keyDates?.thisMonth || [], |
| |
|
| | pastEvents: cachedData.pastEvents || [], |
| | futureEvents: cachedData.futureEvents || [], |
| |
|
| | peakYears: cachedData.peakYears || [], |
| | troughYears: cachedData.troughYears || [], |
| | }; |
| |
|
| | return result; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | export const hasCachedAnalysis = (baziHash, gender) => { |
| | const db = getDb(); |
| | const stmt = db.prepare(` |
| | SELECT COUNT(*) as count FROM bazi_analysis_cache |
| | WHERE bazi_hash = ? AND gender = ? |
| | `); |
| | const row = stmt.get(baziHash, gender); |
| | return row.count > 0; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | export const getCacheStats = () => { |
| | const db = getDb(); |
| | const totalStmt = db.prepare('SELECT COUNT(*) as count FROM bazi_analysis_cache'); |
| | const total = totalStmt.get().count; |
| |
|
| | const recentStmt = db.prepare(` |
| | SELECT COUNT(*) as count FROM bazi_analysis_cache |
| | WHERE created_at > datetime('now', '-24 hours') |
| | `); |
| | const recent = recentStmt.get().count; |
| |
|
| | return { total, recentlyAdded: recent }; |
| | }; |
| |
|
| | export default { |
| | computeBaziHash, |
| | getCachedAnalysis, |
| | cacheAnalysis, |
| | extractCoreData, |
| | mergeCachedWithFresh, |
| | hasCachedAnalysis, |
| | getCacheStats, |
| | }; |
| |
|