import { Injectable, Logger } from '@nestjs/common' import { InjectModel } from '@nestjs/mongoose' import { Model } from 'mongoose' import { AiService } from '../ai/ai.service' import { HotPosition } from '../positions/positions.schema' export interface CareerProfile { major: string grade?: string interests?: string gpa?: string goal?: string } export interface CareerPath { name: string reason: string matchScore: number salary?: string } export interface ChatMessage { role: 'user' | 'assistant' content: string } @Injectable() export class CareerAdviceService { private readonly logger = new Logger(CareerAdviceService.name) constructor( @InjectModel(HotPosition.name) private positionModel: Model, private aiService: AiService, ) {} /** * Analyze user profile and return career advice with position recommendations. */ async analyze(profile: CareerProfile) { const positions = await this.positionModel.find({ active: true }) .sort({ sort: 1 }) .lean() .exec() const positionsContext = positions.map(p => `- ${p.name}${p.salary ? ` (薪资: ${p.salary})` : ''}${p.company ? ` - ${p.company}` : ''}` ).join('\n') const systemPrompt = `你是一位资深的中国大学生职业规划顾问。你的任务是根据学生的专业背景和个人情况,给出个性化的择业建议。 你的建议需要涵盖: 1. 该专业的典型职业方向和发展路径 2. "考研vs就业vs考公"的决策分析(基于学生具体情况) 3. 当前就业市场的真实形势(如AI对各行业的影响) 4. 具体可行动的建议(实习、技能提升等) 你需要从以下可用岗位中,推荐最匹配该学生的3-5个方向: ${positionsContext} 注意: - 你的回答要诚恳务实,不要画大饼 - 指出每个选择的利弊和风险 - 结合AI时代对各行业的影响给出建议 - 最后以JSON格式输出推荐岗位列表 回复格式: 先输出一段详细的个性化分析建议(中文,300-500字)。 然后在最后单独一行输出JSON数组(不要任何其他内容): ---JSON--- [{"name":"岗位名","reason":"推荐理由简要说明","matchScore":85,"salary":"薪资范围"},...] ---JSON---` const userMessage = this.buildProfileMessage(profile) const rawReply = await this.aiService.call({ systemPrompt, userMessage, temperature: 0.7, maxTokens: 2048, }) return this.parseResponse(rawReply, positions) } /** * Continue a chat conversation about career choices. */ async chat(message: string, history: ChatMessage[]) { const positions = await this.positionModel.find({ active: true }) .sort({ sort: 1 }) .lean() .exec() const positionsContext = positions.map(p => `- ${p.name}${p.salary ? ` (薪资: ${p.salary})` : ''}` ).join('\n') const systemPrompt = `你是一位资深的中国大学生职业规划顾问。继续与学生的对话,回答他们的择业相关问题。 可推荐的岗位列表: ${positionsContext} 注意: - 回答诚恳务实,结合AI时代背景 - 给出具体可操作的建议 - 如果学生提到具体岗位,可以从推荐列表中选择匹配的 - 保持对话亲切自然,用中文回复` const historyMessages = history.map(h => `${h.role === 'user' ? '学生' : '顾问'}: ${h.content}` ).join('\n') const userMessage = `对话历史:\n${historyMessages}\n\n学生最新提问: ${message}` const reply = await this.aiService.call({ systemPrompt, userMessage, temperature: 0.7, maxTokens: 1024, }) return { reply } } private buildProfileMessage(profile: CareerProfile): string { const parts: string[] = [`学生专业: ${profile.major}`] if (profile.grade) parts.push(`年级: ${profile.grade}`) if (profile.interests) parts.push(`兴趣方向: ${profile.interests}`) if (profile.gpa) parts.push(`GPA/成绩: ${profile.gpa}`) if (profile.goal) parts.push(`目标/困惑: ${profile.goal}`) return parts.join('\n') } private parseResponse(rawReply: string, allPositions: any[]): { reply: string careerPaths: CareerPath[] } { // Extract JSON array from ---JSON--- markers const jsonMatch = rawReply.match(/---JSON---\s*(\[[\s\S]*?\])\s*---JSON---/) let careerPaths: CareerPath[] = [] if (jsonMatch) { try { careerPaths = JSON.parse(jsonMatch[1]) } catch { this.logger.warn('Failed to parse career paths JSON') } } // Clean reply (remove --JSON-- markers) const reply = rawReply.replace(/---JSON---[\s\S]*?---JSON---/g, '').trim() return { reply, careerPaths } } /** Get hot positions (delegated from positions module) */ async getHotPositions() { return this.positionModel.find({ active: true }) .sort({ sort: 1 }) .lean() .exec() } }