Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d8a7872cd2 | |||
| 59fc35dad9 |
@@ -16,7 +16,7 @@ export class AllExceptionsFilter implements ExceptionFilter {
|
|||||||
|
|
||||||
const message = exception instanceof HttpException
|
const message = exception instanceof HttpException
|
||||||
? exception.getResponse()
|
? exception.getResponse()
|
||||||
: '服务器内部错误';
|
: (exception as Error)?.message || '服务器内部错误';
|
||||||
|
|
||||||
const errorResponse = {
|
const errorResponse = {
|
||||||
code: status,
|
code: status,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Injectable, HttpException, HttpStatus } from '@nestjs/common'
|
import { Injectable, HttpException, HttpStatus, Logger } from '@nestjs/common'
|
||||||
import { InjectModel } from '@nestjs/mongoose'
|
import { InjectModel } from '@nestjs/mongoose'
|
||||||
import { Model } from 'mongoose'
|
import { Model } from 'mongoose'
|
||||||
import { Interview, InterviewDocument } from './interview.schema'
|
import { Interview, InterviewDocument } from './interview.schema'
|
||||||
@@ -11,6 +11,8 @@ import { analyzeSpeech } from '../../common/utils/filler-words'
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class InterviewService {
|
export class InterviewService {
|
||||||
|
private readonly logger = new Logger(InterviewService.name)
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@InjectModel(Interview.name) private interviewModel: Model<InterviewDocument>,
|
@InjectModel(Interview.name) private interviewModel: Model<InterviewDocument>,
|
||||||
@InjectModel(Progress.name) private progressModel: Model<ProgressDocument>,
|
@InjectModel(Progress.name) private progressModel: Model<ProgressDocument>,
|
||||||
@@ -25,11 +27,17 @@ export class InterviewService {
|
|||||||
const cost = await this.quotaService.checkInterview(userId)
|
const cost = await this.quotaService.checkInterview(userId)
|
||||||
|
|
||||||
// Step 2: AI 生成第一个问题
|
// Step 2: AI 生成第一个问题
|
||||||
const firstQuestion = await this.aiService.call({
|
let firstQuestion: string
|
||||||
systemPrompt: `你是一位专业的${position}面试官。请针对校招该岗位提出第一个面试问题,要求具体且有针对性。直接输出问题,不要多余内容。`,
|
try {
|
||||||
userMessage: `请为${position}岗位的校招候选人提出第一个面试问题。`,
|
firstQuestion = await this.aiService.call({
|
||||||
temperature: 0.8,
|
systemPrompt: `你是一位专业的${position}面试官。请针对校招该岗位提出第一个面试问题,要求具体且有针对性。直接输出问题,不要多余内容。`,
|
||||||
})
|
userMessage: `请为${position}岗位的校招候选人提出第一个面试问题。`,
|
||||||
|
temperature: 0.8,
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`AI call failed for interview create: ${(e as Error).message}`)
|
||||||
|
throw new HttpException('AI 服务暂时不可用,请稍后重试', HttpStatus.SERVICE_UNAVAILABLE)
|
||||||
|
}
|
||||||
|
|
||||||
// Step 3: AI 调用成功后,扣除引力值并创建面试记录
|
// Step 3: AI 调用成功后,扣除引力值并创建面试记录
|
||||||
await this.quotaService.deductInterview(userId, cost)
|
await this.quotaService.deductInterview(userId, cost)
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ const startInterview = async () => {
|
|||||||
header: { 'Authorization': `Bearer ${token()}`, 'Content-Type': 'application/json' },
|
header: { 'Authorization': `Bearer ${token()}`, 'Content-Type': 'application/json' },
|
||||||
data: { position: position.value },
|
data: { position: position.value },
|
||||||
})
|
})
|
||||||
if (res.statusCode === 200 && res.data) {
|
if (res.statusCode >= 200 && res.statusCode < 300 && res.data) {
|
||||||
interviewId.value = res.data.id
|
interviewId.value = res.data.id
|
||||||
messages.value = res.data.messages || messages.value
|
messages.value = res.data.messages || messages.value
|
||||||
answeredCount.value = res.data.questionCount || 0
|
answeredCount.value = res.data.questionCount || 0
|
||||||
@@ -242,7 +242,8 @@ const startInterview = async () => {
|
|||||||
} else if (checkAuth(res)) {
|
} else if (checkAuth(res)) {
|
||||||
return // token 过期,已清除并跳转登录
|
return // token 过期,已清除并跳转登录
|
||||||
} else {
|
} else {
|
||||||
const msg = res.data?.message || '创建面试失败'
|
const errMsg = typeof res.data === 'string' ? res.data : (res.data?.message || '')
|
||||||
|
const msg = errMsg || `创建面试失败(${res.statusCode})`
|
||||||
messages.value.push({ role: 'ai', content: msg })
|
messages.value.push({ role: 'ai', content: msg })
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
@@ -273,7 +274,7 @@ const sendAnswer = async () => {
|
|||||||
header: { 'Authorization': `Bearer ${token()}`, 'Content-Type': 'application/json' },
|
header: { 'Authorization': `Bearer ${token()}`, 'Content-Type': 'application/json' },
|
||||||
data: avatarMode.value ? { answer, avatar: true } : { answer },
|
data: avatarMode.value ? { answer, avatar: true } : { answer },
|
||||||
})
|
})
|
||||||
if (res.statusCode === 200 && res.data?.messages) {
|
if (res.statusCode >= 200 && res.statusCode < 300 && res.data?.messages) {
|
||||||
const aiMsg = res.data.messages.find(m => m.role === 'ai')
|
const aiMsg = res.data.messages.find(m => m.role === 'ai')
|
||||||
// Only push AI messages from response to avoid duplicating the user message already added above
|
// Only push AI messages from response to avoid duplicating the user message already added above
|
||||||
const newAiMessages = res.data.messages.filter(m => m.role === 'ai')
|
const newAiMessages = res.data.messages.filter(m => m.role === 'ai')
|
||||||
|
|||||||
Reference in New Issue
Block a user