feat: 集成 DeepSeek AI 服务

- 新增 backend 服务 (Express + TypeScript)
- 前端表单提交改为调用后端 API
- DeepSeek 增强分析结果,本地规则作为 fallback
- Docker 双容器部署:web (Nginx) + backend
- Nginx 反向代理 /api 到后端服务
- 本地开发支持 Vite 代理 + backend:dev 脚本

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jowe
2026-03-28 01:37:52 +08:00
parent 7fe1586dc0
commit 3c0fbd5059
22 changed files with 909 additions and 352 deletions

262
shared/fortune.ts Normal file
View File

@@ -0,0 +1,262 @@
import type {
UserInput,
FortuneResult,
FortuneProfile,
CompanyRecommendation,
JobRecommendation,
StageAdvice,
} from './types';
function calculateWuxing(birthDate: string): { wuxing: FortuneProfile['wuxing']; wuxingLabel: string } {
const date = new Date(birthDate);
const year = date.getFullYear();
const tiangan = year % 10;
const tianganMap: Record<number, string> = {
0: 'metal',
1: 'metal',
2: 'water',
3: 'water',
4: 'wood',
5: 'wood',
6: 'fire',
7: 'fire',
8: 'earth',
9: 'earth',
};
const wuxingKey = tianganMap[tiangan] || 'earth';
const labelMap: Record<string, string> = {
wood: '木',
fire: '火',
earth: '土',
metal: '金',
water: '水',
};
return {
wuxing: wuxingKey as FortuneProfile['wuxing'],
wuxingLabel: labelMap[wuxingKey] || '土',
};
}
function generateProfile(wuxing: FortuneProfile['wuxing'], wuxingLabel: string): FortuneProfile {
const profiles: Record<string, Partial<FortuneProfile>> = {
wood: {
personality: ['有生发之力', '善于规划与成长', '追求目标坚定'],
strengths: ['领导力', '规划能力', '适应力'],
weaknesses: ['有时过于刚硬', '易忽略细节'],
developmentRhythm: 'growth',
},
fire: {
personality: ['热情洋溢', '执行力强', '喜欢表达'],
strengths: ['创造力', '感染力', '行动力'],
weaknesses: ['易急躁', '缺乏耐心'],
developmentRhythm: 'breakthrough',
},
earth: {
personality: ['稳重务实', '注重规则', '善于协调'],
strengths: ['稳定性', '执行力', '资源整合'],
weaknesses: ['过于保守', '创新不足'],
developmentRhythm: 'stable',
},
metal: {
personality: ['刚毅果断', '追求效率', '原则性强'],
strengths: ['决断力', '专业度', '抗压能力'],
weaknesses: ['过于严厉', '不够灵活'],
developmentRhythm: 'accumulation',
},
water: {
personality: ['灵活变通', '善于沟通', '适应力强'],
strengths: ['沟通力', '学习力', '洞察力'],
weaknesses: ['易动摇', '缺乏坚持'],
developmentRhythm: 'growth',
},
};
const profile = profiles[wuxing] || profiles.earth;
return {
wuxing,
wuxingLabel,
personality: profile.personality || [],
strengths: profile.strengths || [],
weaknesses: profile.weaknesses || [],
developmentRhythm: profile.developmentRhythm || 'stable',
};
}
function generateCompanyRecommendations(profile: FortuneProfile): CompanyRecommendation[] {
const { developmentRhythm } = profile;
const companyTypes: CompanyRecommendation[] = [
{
type: '一线大厂',
matchScore: 85,
reasons: ['资源丰富,平台稳定', '制度完善,适合长期发展', '能发挥你的专业能力'],
suitableFor: ['追求稳定发展', '希望积累大平台经验'],
notSuitableFor: ['渴望快速晋升', '喜欢灵活工作方式'],
stageAdvice: developmentRhythm === 'stable' ? '适合进入积累期' : '可考虑内部晋升机会',
},
{
type: '独角兽公司',
matchScore: 78,
reasons: ['成长空间大', '能接触核心业务', '晋升机会多'],
suitableFor: ['渴望快速成长', '愿意承担风险'],
notSuitableFor: ['追求极度稳定', '不喜欢不确定性'],
stageAdvice: developmentRhythm === 'growth' ? '非常适合当前阶段' : '需评估团队稳定性',
},
{
type: '高增长创业公司',
matchScore: 72,
reasons: ['决策灵活', '成长速度快', '能全面锻炼能力'],
suitableFor: ['敢于冒险', '希望快速晋升'],
notSuitableFor: ['喜欢按部就班', '需要明确指引'],
stageAdvice: '适合寻求突破的年轻人',
},
{
type: '强技术驱动型公司',
matchScore: 80,
reasons: ['重视技术能力', '氛围开放', '创新机会多'],
suitableFor: ['技术导向', '喜欢钻研'],
notSuitableFor: ['销售导向', '不喜欢深度工作'],
stageAdvice: '技术路线发展的理想选择',
},
{
type: '强产品驱动型公司',
matchScore: 76,
reasons: ['用户体验为核心', '重视创新', '成长空间大'],
suitableFor: ['产品思维', '用户导向'],
notSuitableFor: ['纯执行导向', '不喜欢思考'],
stageAdvice: '产品路线发展的好平台',
},
{
type: '稳定流程型组织',
matchScore: 68,
reasons: ['工作稳定', '流程规范', '压力适中'],
suitableFor: ['追求工作生活平衡', '喜欢清晰职责'],
notSuitableFor: ['渴望快速变化', '喜欢创新'],
stageAdvice: developmentRhythm === 'stable' ? '适合当前阶段' : '可能限制发展',
},
];
return companyTypes.sort((a, b) => b.matchScore - a.matchScore).slice(0, 4);
}
function generateJobRecommendations(profile: FortuneProfile): JobRecommendation[] {
const jobTypes: JobRecommendation[] = [
{
category: '技术研发',
matchScore: 88,
reasons: ['你的特质适合深耕技术', '需要专业能力和持续学习'],
suitableWorkStyle: ['独立钻研', '解决复杂问题'],
notSuitableFor: ['频繁社交', '简单重复工作'],
},
{
category: '产品经理',
matchScore: 82,
reasons: ['需要平衡多方需求', '注重规划和沟通'],
suitableWorkStyle: ['协调资源', '用户洞察'],
notSuitableFor: ['纯技术执行', '不喜欢沟通'],
},
{
category: '运营',
matchScore: 79,
reasons: ['需要数据分析能力', '注重用户增长'],
suitableWorkStyle: ['数据分析', '活动策划'],
notSuitableFor: ['极度内向', '不喜欢变化'],
},
{
category: '销售商务',
matchScore: 75,
reasons: ['需要人际沟通能力', '结果导向'],
suitableWorkStyle: ['人际交往', '资源整合'],
notSuitableFor: ['不喜欢竞争', '害怕被拒绝'],
},
{
category: '设计',
matchScore: 77,
reasons: ['需要审美和创造力', '注重用户体验'],
suitableWorkStyle: ['视觉表达', '创意工作'],
notSuitableFor: ['不喜欢抽象思维', '追求确定答案'],
},
{
category: '管理岗',
matchScore: 73,
reasons: ['需要领导力和规划能力', '注重团队发展'],
suitableWorkStyle: ['团队管理', '战略规划'],
notSuitableFor: ['喜欢独立工作', '不喜欢处理人事'],
},
];
if (profile.wuxing === 'wood') {
jobTypes.find((j) => j.category === '管理岗')!.matchScore += 5;
jobTypes.find((j) => j.category === '产品经理')!.matchScore += 3;
} else if (profile.wuxing === 'fire') {
jobTypes.find((j) => j.category === '销售商务')!.matchScore += 5;
jobTypes.find((j) => j.category === '运营')!.matchScore += 3;
} else if (profile.wuxing === 'water') {
jobTypes.find((j) => j.category === '运营')!.matchScore += 5;
jobTypes.find((j) => j.category === '产品经理')!.matchScore += 3;
} else if (profile.wuxing === 'metal') {
jobTypes.find((j) => j.category === '技术研发')!.matchScore += 5;
jobTypes.find((j) => j.category === '管理岗')!.matchScore += 3;
} else if (profile.wuxing === 'earth') {
jobTypes.find((j) => j.category === '运营')!.matchScore += 3;
jobTypes.find((j) => j.category === '管理岗')!.matchScore += 5;
}
return jobTypes.sort((a, b) => b.matchScore - a.matchScore).slice(0, 4);
}
function generateStageAdvice(profile: FortuneProfile): StageAdvice {
const { developmentRhythm, wuxingLabel } = profile;
const adviceMap: Record<string, StageAdvice> = {
stable: {
overall: `你目前处于稳定积累期,五行属${wuxingLabel},适合稳扎稳打。`,
careerDirection: '建议在现有岗位上深耕,积累专业能力。',
jobChangeTiming: '当前不建议频繁变动,保持稳定是更好的选择。',
platformPreference: '优先选择成熟稳定的大平台。',
keyObservations: ['关注岗位的成长空间而非只看薪资', '建立专业壁垒是关键', '可以开始培养管理能力'],
},
growth: {
overall: `你目前处于成长期,五行属${wuxingLabel},有较强的上升动力。`,
careerDirection: '适合寻求晋升机会或承担更大责任。',
jobChangeTiming: '可以开始关注外部机会,但不要急于变动。',
platformPreference: '独角兽或高速成长公司可能更适合你。',
keyObservations: ['主动争取项目机会', '扩大影响力范围', '开始建立个人品牌'],
},
breakthrough: {
overall: `你目前处于突破期,五行属${wuxingLabel},适合做出重大改变。`,
careerDirection: '可以考虑转型或创业的机会。',
jobChangeTiming: '现在是尝试新方向的好时机。',
platformPreference: '创业公司或新业务部门可能更适合你。',
keyObservations: ['勇敢尝试新领域', '不要害怕失败', '整合资源是关键'],
},
accumulation: {
overall: `你目前处于沉淀期,五行属${wuxingLabel},需要耐心积累。`,
careerDirection: '适合深耕现有领域,等待时机。',
jobChangeTiming: '建议先完成当前阶段的积累。',
platformPreference: '稳定平台更适合当前状态。',
keyObservations: ['专注提升专业深度', '建立行业人脉', '等待合适的机会'],
},
};
return adviceMap[developmentRhythm] || adviceMap.stable;
}
export function analyzeFortune(input: UserInput): FortuneResult {
const { wuxing, wuxingLabel } = calculateWuxing(input.birthDate);
const profile = generateProfile(wuxing, wuxingLabel);
const companyRecommendations = generateCompanyRecommendations(profile);
const jobRecommendations = generateJobRecommendations(profile);
const stageAdvice = generateStageAdvice(profile);
return {
profile,
companyRecommendations,
jobRecommendations,
stageAdvice,
};
}