Voice-first interview practice app for the Gemini hackathon.
License: All rights reserved. Source available for viewing and evaluation only.
./run.sh install
./run.sh uiDeveloper guide: DEVELOPER_GUIDE.md
- Python 3.11+
- Node.js 20+ and npm
cat > .env <<'EOF'
INTERVIEW_ADAPTER=mock
VOICE_MODE=turn
PORT=8000
EOF
./run.sh install
./run.sh uicat > .env <<'EOF'
INTERVIEW_ADAPTER=gemini
GEMINI_API_KEY=your-gemini-key
OPENAI_API_KEY=your-openai-key
VOICE_MODE=turn
VOICE_TTS_ENABLED=1
VOICE_TTS_PROVIDER=openai
OPENAI_TTS_MODEL=gpt-4o-mini-tts
GEMINI_TTS_MODEL=gemini-2.5-flash-native-audio-preview-12-2025
GEMINI_TTS_MODEL_FALLBACKS=gemini-2.5-pro-preview-tts
PORT=8000
EOF
./run.sh install
./run.sh uicurl -sS http://127.0.0.1:8000/healthThen open:
- App:
http://127.0.0.1:8000 - API docs:
http://127.0.0.1:8000/docs
Script modes (./run.sh):
./run.sh install: create venv + install Python deps + npm install./run.sh ui: start the app./run.sh test: run Vitest UI tests./run.sh e2e: run Playwright E2E tests
Adapter modes (set in .env):
INTERVIEW_ADAPTER=mock: mock questions, transcript, scoringINTERVIEW_ADAPTER=gemini: Gemini text + turn-based TTS coaching (requiresGEMINI_API_KEY; supports OpenAI or Gemini TTS providers)
INTERVIEW_ADAPTER:mock(default) orgeminiGEMINI_API_KEY: AI Studio Gemini API key (required whenINTERVIEW_ADAPTER=gemini)GOOGLE_API_KEY: optional fallback ifGEMINI_API_KEYis not setGEMINI_LIVE_MODEL: reserved for live streaming (feature branch only)GEMINI_LIVE_MODEL_FALLBACKS: comma-separated fallback live audio models (feature branch only)GEMINI_INTERVIEW_TEXT_MODEL: override text model for question generation + scoring (defaultgemini-3-pro-preview)GEMINI_TEXT_MODEL: override text model for turn-based coaching (defaultgemini-2.5-flash)VOICE_MODE:turnonly onmain(live streaming is disabled)VOICE_TTS_ENABLED: enable server TTS for turn mode (default1whenINTERVIEW_ADAPTER=gemini, else0)VOICE_TTS_PROVIDER: turn-mode TTS provider order (openai,gemini, orauto; defaultopenai)GEMINI_TTS_MODEL: turn-mode TTS model (defaultgemini-2.5-flash-native-audio-preview-12-2025)GEMINI_TTS_MODEL_FALLBACKS: comma-separated fallback TTS models (defaultgemini-2.5-pro-preview-tts)GEMINI_TTS_VOICE: voice selection for turn TTS (defaultKore)GEMINI_TTS_LANGUAGE: language code for turn TTS (defaulten-US)OPENAI_API_KEY: OpenAI API key for OpenAI TTS (VOICE_TTS_PROVIDER=openaiorauto)OPENAI_TTS_MODEL: OpenAI TTS model (defaultgpt-4o-mini-tts)OPENAI_TTS_VOICE: OpenAI voice (defaultalloy)OPENAI_TTS_FORMAT: OpenAI audio format (defaultwav)OPENAI_TTS_TIMEOUT_MS: OpenAI TTS timeout override (defaultVOICE_TTS_TIMEOUT_MS)VOICE_TTS_TIMEOUT_MS: per-TTS request timeout (default20000)VOICE_TTS_WAIT_MS: max wait before returning text-only (default2500)VOICE_TURN_END_DELAY_MS: minimum answer time before enabling submit / checking if the candidate is done (default10000)VOICE_TURN_COMPLETION_CONFIDENCE: confidence threshold for prompting “Are you done?” (default0.9)VOICE_TURN_COMPLETION_COOLDOWN_MS: minimum delay between completion checks (default0)VOICE_OUTPUT_MODE:browser,server, orautofor turn audio output (defaultautowhenINTERVIEW_ADAPTER=gemini, elsebrowser)UI_DEV_MODE: reserved for feature-branch debug controls (ignored onmain)GEMINI_LIVE_RESUME: live session resumption (feature branch only)APP_API_BASE: API base path for the UI (default/api)SESSION_STORE_DIR: session storage directory (defaultapp/session_store)APP_USER_ID: default user id for session storage (defaultlocal)LOG_DIR: directory for archived logs (defaultlogs)GA4_MEASUREMENT_ID: optional Google Analytics 4 measurement id (enables server-side telemetry forwarding)GA4_API_SECRET: optional GA4 Measurement Protocol API secret (must be set withGA4_MEASUREMENT_ID)PORT: backend server port (default8000)UI_PORT: static UI port when no backend is present (default5173)RELOAD: set to0to disable uvicorn reload in./run.sh uiE2E_BASE_URL: override Playwright base URL (defaulthttp://localhost:8000)E2E_LIVE: set to1to run the optional live Gemini Playwright test
Example .env for turn mode with server TTS (OpenAI first, Gemini fallback):
GEMINI_API_KEY=your-key
OPENAI_API_KEY=your-openai-key
INTERVIEW_ADAPTER=gemini
GEMINI_INTERVIEW_TEXT_MODEL=gemini-3-pro-preview
GEMINI_TEXT_MODEL=gemini-2.5-flash
VOICE_MODE=turn
VOICE_TTS_ENABLED=1
VOICE_TTS_PROVIDER=openai
VOICE_TTS_TIMEOUT_MS=20000
VOICE_TTS_WAIT_MS=2500
VOICE_TURN_END_DELAY_MS=10000
VOICE_TURN_COMPLETION_CONFIDENCE=0.9
VOICE_TURN_COMPLETION_COOLDOWN_MS=0
OPENAI_TTS_MODEL=gpt-4o-mini-tts
OPENAI_TTS_VOICE=alloy
OPENAI_TTS_FORMAT=wav
GEMINI_TTS_MODEL=gemini-2.5-flash-native-audio-preview-12-2025
GEMINI_TTS_MODEL_FALLBACKS=gemini-2.5-pro-preview-tts
GEMINI_TTS_VOICE=Kore
GEMINI_TTS_LANGUAGE=en-US
VOICE_OUTPUT_MODE=auto
APP_API_BASE=/api
PORT=8000Turn mode flow: the UI enables Submit Answer as soon as the coach finishes speaking and there is draft text. Completion checks still run in the background to assess whether the response looks attempted or complete.
Provider fallback behavior:
VOICE_TTS_PROVIDER=openai: OpenAI first, Gemini fallbackVOICE_TTS_PROVIDER=gemini: Gemini first, OpenAI fallbackVOICE_TTS_PROVIDER=auto: OpenAI first whenOPENAI_API_KEYis set, otherwise Gemini first
PrepTalk emits client-side journey events to POST /api/telemetry and logs event=journey_kpi in logs/app.log.
Tracked funnel events:
journey_app_openjourney_resume_loadedjourney_job_loadedjourney_questions_requestedjourney_questions_generatedjourney_session_startedjourney_candidate_spokejourney_answer_submittedjourney_help_requestedjourney_score_generatedjourney_export_requestedjourney_export_completed
Enable GA4 forwarding (optional):
GA4_MEASUREMENT_ID=G-XXXXXXXXXX
GA4_API_SECRET=your_measurement_protocol_secretWhen enabled, telemetry events are forwarded server-side to GA4 using Measurement Protocol.
See docs/ai-studio-setup.md for AI Studio project/key setup and shared endpoint notes.
See docs/cloud-run-deploy.md for Cloud Run deployment steps and update options.
See docs/analytics-kpi.md for KPI event mapping and GA4 setup.
- Base:
http://localhost:8000(orPORTif overridden) - Health:
http://localhost:8000/health - Docs:
http://localhost:8000/docs
Install the lnav helpers (format + SQL view):
./tools/logs/lnav/setup.shOpen logs:
lnav logs/app.logExample queries (run in lnav with ;):
select event, status, count(*) from preptalk_log group by event, status order by count(*) desc;
select event, percentile(duration_ms, 95) from preptalk_log where duration_ms is not null group by event;
select interview_id, count(*) from preptalk_log group by interview_id order by count(*) desc;
select event, count(*) from preptalk_log where upper(log_level) = 'ERROR' or status = 'error' group by event;UI component tests (Vitest):
./run.sh testAPI tests (pytest):
./.venv/bin/python -m pytestE2E tests (Playwright, starts the app automatically):
npm run test:e2eOptional live Gemini E2E (feature branch only):
E2E_LIVE=1 GEMINI_API_KEY=your-key npm run test:e2eE2E via helper script (same harness as above):
./run.sh e2eIf Playwright browsers are missing:
PLAYWRIGHT_INSTALL=1 ./run.sh e2eAll rights reserved. Source available for viewing and evaluation only. See LICENSE for details.