4cd889c081
New backend module 'interview-review' provides: - Audio upload (50MB limit, MP3/M4A/WAV/AAC/OGG/MP4/WebM) - Text transcript submission - whisper.cpp local ASR integration (tiny + base models) - AI analysis (4-dimension scoring: logic/expression/professionalism/stability) - Speech analysis (filler words detection, pace, duration) - Async processing pipeline with status polling - Graceful fallback to mock ASR when whisper unavailable New frontend page 'pages/review/review.vue' with 3 modes: - List mode: review history with status indicators - Upload mode: audio file upload or text paste - Report mode: score radar, dimension bars, analysis details Docs updated: PROJECT-STATUS.md v4.4, FEATURE-LIST.md v4.2, ROADMAP.md v4.2
80 lines
1.7 KiB
TypeScript
80 lines
1.7 KiB
TypeScript
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
|
|
import { Document, Types } from 'mongoose'
|
|
|
|
export type InterviewReviewDocument = InterviewReview & Document
|
|
|
|
@Schema({ timestamps: true })
|
|
export class InterviewReview {
|
|
@Prop({ type: Types.ObjectId, ref: 'User', required: true })
|
|
userId: Types.ObjectId
|
|
|
|
@Prop({ required: true })
|
|
position: string
|
|
|
|
@Prop({ default: '' })
|
|
company: string
|
|
|
|
@Prop({ default: 'processing' })
|
|
status: 'processing' | 'completed' | 'failed'
|
|
|
|
@Prop({ type: Object, default: null })
|
|
audioFile?: {
|
|
hash: string
|
|
filePath: string
|
|
duration: number
|
|
size: number
|
|
mimeType: string
|
|
}
|
|
|
|
@Prop({ type: Object, default: null })
|
|
transcript?: {
|
|
fullText: string
|
|
segments: {
|
|
startTime: number
|
|
endTime: number
|
|
speaker: 'interviewer' | 'candidate'
|
|
text: string
|
|
}[]
|
|
}
|
|
|
|
@Prop({ type: Object, default: null })
|
|
analysis?: {
|
|
overallScore: number
|
|
dimensions: {
|
|
logic: number
|
|
expression: number
|
|
professionalism: number
|
|
stability: number
|
|
}
|
|
strengths: string[]
|
|
weaknesses: string[]
|
|
suggestions: string[]
|
|
questionBreakdown: {
|
|
question: string
|
|
answer: string
|
|
score: number
|
|
comment: string
|
|
suggestedAnswer: string
|
|
}[]
|
|
}
|
|
|
|
@Prop({ type: Object, default: null })
|
|
speechAnalysis?: {
|
|
fillerWords: { word: string; count: number }[]
|
|
fillerScore: number
|
|
fillerDensity: number
|
|
pace: string
|
|
totalDuration: number
|
|
totalChars: number
|
|
}
|
|
|
|
@Prop({ default: 0 })
|
|
retryCount: number
|
|
|
|
readonly createdAt?: Date
|
|
readonly updatedAt?: Date
|
|
}
|
|
|
|
export const InterviewReviewSchema = SchemaFactory.createForClass(InterviewReview)
|
|
InterviewReviewSchema.index({ userId: 1, createdAt: -1 })
|