Skip to content

Add built-in mock interview feature (client) #119

Description

@alpha5611331

Summary

Client half of the built-in Mock Interview feature (backend: PowerInterviewAI/backend#60).
The AI plays the interviewer: it generates questions from the candidate's CV/job context,
speaks them via the backend's Deepgram TTS proxy, listens over the existing ASR pipeline,
adaptively decides follow-ups, and produces a scored report at the end.

Scope

  • State machine (src/main/services/mock-interview.service.ts): Idle → Starting →
    Generating → Speaking/Listening → Evaluating → Scoring → Finished, with a generation-token
    guard against overlapping async calls and the terminal-state invariant use-assistant-service.ts
    documents for RunningState - whatever fails, the state always lands on Idle or Finished.
  • The transmit gate (src/renderer/services/mock-tts.service.ts): mutes the candidate's
    microphone track while the interviewer's TTS plays, so the ASR never transcribes the AI's own
    question as something the candidate said. Four independent layers guard against a stranded
    mute: a finally, a watchdog, a generation token, and a state-driven belt.
  • Mic-only capture (src/renderer/services/mock-transcription.service.ts): a sibling to
    LiveTranscriptionService, not a mode flag added to it, so the live path's source-level-tested
    race guards stay untouched. Never opens loopback capture, never touches the live transcript.
  • Guards: mutual exclusion with the live assistant, an explicit (not just emergent) block on
    action suggestions during a mock session, the close guard widened to cover mock content, and
    Ctrl+Shift+Q routed to end a mock session when one is running.
  • Setup/session/report screens under /mock-interview, deliberately the opposite visual
    contract from the live control bar - a centred column the user looks straight at, not a compact
    overlay for peripheral reading.
  • Export: a mock-interview report builder, wired into the existing save-history dialog by
    subject (live vs. mock), with all 28 languages' export labels filled in.
  • A product-wide change while in the area: the headphone notice no longer has "don't show
    again" - whether the call is on speakers is a property of the machine and the meeting, not a
    setting, and a permanent silence option contradicted the app's own stated reasoning for the
    notice being opt-out in the first place.

Test plan

  • pnpm lint - clean
  • pnpm build (tsc + vite) - clean
  • pnpm electron:build-main - clean
  • pnpm test:main - all checks pass, including 6 new test files covering the state machine,
    the transmit gate (source-level), mic/loopback isolation (source-level), the action-suggestion
    block, sentence chunking, and export label completeness
  • Manual: on speakers, confirm the interviewer's spoken question never appears in the answer
    transcript (not run in this environment - no audio hardware / real Deepgram key available)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions