ORION is a full-stack interview and viva practice platform. A candidate signs in, gets a question, answers on camera, and receives feedback and a progress history. The backend scores each answer on three channels (what was said, how it was said, and how the candidate presented) and fuses them into one evaluation.
Status: working prototype. Authentication, the interview session flow,
and text-based scoring and feedback are fully implemented end to end. Audio
and video analysis are still placeholders that return null and are left
out of the fused score rather than faked. See What works today
for the exact breakdown.
Recorded answer
├── Audio ─────► analyze_audio() ──┐ filler %, pauses, speech rate (placeholder)
├── Video ─────► analyze_video() ──┼─► fuse_results() ─► overall score
└── Transcript ► analyze_text() ──┘ relevance, coverage, coherence (implemented)
│
└─► generate_feedback()
analyze_text embeds the candidate's transcript and the question's reference
key points with a Sentence-Transformers model and scores relevance, key-point
coverage, coherence, and completeness. fuse_results renormalizes its weights
around whichever channels actually produced a score, so a missing audio/video
channel doesn't silently drag the overall score down.
| Layer | Technology |
|---|---|
| Frontend | React 19, Vite, React Router, Chart.js (react-chartjs-2) |
| Browser media | getUserMedia and MediaRecorder for webcam and mic capture; Web Speech API for live transcription (Chrome/Edge), manual textarea fallback elsewhere |
| Backend | Python, FastAPI, Uvicorn, Pydantic |
| Auth | bcrypt password hashing, JWT (PyJWT) bearer tokens |
| Scoring | Sentence-Transformers embeddings (all-MiniLM-L6-v2 by default) |
| Database | SQLAlchemy engine, SQLite by default (DATABASE_URL overrides) |
ORION/
├── backend/
│ ├── requirements.txt
│ ├── .env.example
├── uploads/
│ └── app/
│ ├── main.py # FastAPI app; mounts /auth, /users, /interview, /analysis; CORS
│ ├── config.py # env-driven settings: DATABASE_URL, SECRET_KEY, CORS_ORIGINS, ...
│ ├── database.py # SQLAlchemy engine and session factory
│ ├── db_models.py # User, InterviewSession tables
│ ├── auth/ # signup/login models, routes, password hashing, JWT
│ ├── users/ # profile model and route
│ ├── interview/ # question bank + key points, /start and /submit routes, session manager
│ ├── analysis/ # nlp_analysis (implemented), audio/video (placeholder), fusion, feedback, pipeline
│ ├── storage/ # result schema and save/fetch helpers
│ └── utils/ # helpers, logger
├── frontend/
│ └── src/
│ ├── App.jsx # routes: /, /auth, /dashboard, /interview, /feedback
│ ├── components/ # Home, Auth, Dashboard, InterviewRoom, Feedback, ProgressGraphs
│ └── services/api.js # fetch wrapper: token storage, JSON + multipart requests, typed errors
├── ml/
│ ├── training/ # train_nlp.py, train_audio.py, train_video.py
│ └── evaluation/ # evaluate_models.py
└── scripts/ # seed_questions.py, create_user_data.py
cd backend
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env # then set SECRET_KEY (see below)
uvicorn app.main:app --reload # http://localhost:8000
Generate a SECRET_KEY with:
python -c "import secrets; print(secrets.token_urlsafe(48))"
If SECRET_KEY is left unset, the app runs with a random key generated at
startup and logs a warning — every login is invalidated on restart, so this
is fine for a quick check but not for real use.
Other environment variables (all optional, see .env.example):
| Variable | Default | Purpose |
|---|---|---|
DATABASE_URL |
sqlite:///./orion.db |
Database connection string |
ACCESS_TOKEN_EXPIRE_MINUTES |
1440 |
JWT lifetime |
CORS_ORIGINS |
http://localhost:5173,http://127.0.0.1:5173 |
Comma-separated allowed frontend origins |
UPLOAD_DIR |
./uploads |
Where submitted recordings are stored |
MAX_UPLOAD_MB |
100 |
Upload size limit |
EMBEDDING_MODEL |
sentence-transformers/all-MiniLM-L6-v2 |
Model used by analyze_text |
The embedding model downloads on first use (a few hundred MB), so the first
/interview/submit call after a fresh install takes longer than later ones.
cd frontend
npm install
npm run dev
The frontend expects the API at http://localhost:8000 (set in
src/services/api.js).
| Method | Path | State |
|---|---|---|
| GET | / |
Health message |
| POST | /auth/signup |
Implemented: hashes the password, stores the user, returns a JWT |
| POST | /auth/login |
Implemented: verifies the password, returns a JWT |
| GET | /users/me |
Implemented: returns the authenticated user's profile |
| GET | /interview/questions/{domain} |
Working: returns questions from the in-memory bank |
| POST | /interview/start |
Implemented: creates a session, returns a question and session_id |
| POST | /interview/submit |
Implemented: accepts the recording + transcript, runs analysis, stores and returns the result |
| GET | /analysis/latest |
Implemented: most recent completed session's report |
| GET | /analysis/history |
Implemented: overall scores across past sessions, for the progress chart |
All routes except /, /auth/*, and /interview/questions/{domain} require
a bearer token from signup/login.
| Area | State |
|---|---|
| Frontend routing and pages (Home, Auth, Dashboard, Interview room, Feedback) | Implemented |
| Interview room: webcam and mic capture, live speech-to-text, 60-second countdown, upload on finish | Implemented |
| Progress chart (Chart.js line chart of overall scores) | Implemented, pulls from /analysis/history |
| Question bank by domain (tech, business), with reference key points per question | Working, small sample set |
| Auth form | Implemented, connected to the backend |
| Auth backend | Implemented: bcrypt hashing, JWT issuance and verification, persisted users |
Interview session flow (/interview/start, /interview/submit) |
Implemented |
| Text/NLP analysis | Implemented: embedding-based relevance, key-point coverage, coherence, completeness |
| Fusion engine | Implemented: weights renormalize around whichever channels produced a score |
| Feedback generator | Implemented for the text channel; extend with audio/video rules once those channels are real |
| Audio and video analysis | Still placeholder functions with fixed outputs, and left out of the fused score |
| ML scripts | Calibration scaffolds; they read optional JSON feature files and fall back to defaults |
| CORS | Implemented, configurable via CORS_ORIGINS |
| Tests | Backend has integration tests for the auth and interview flow |
- Real audio features (speech rate, pauses, filler words) and video features (gaze, head movement) to replace the two remaining placeholder channels
- Feedback rules for the audio/video channels once they're real
- Calibrate the
nlp_analysis.pythresholds (RELEVANCE_RANGE,COHERENCE_RANGE,COVERAGE_THRESHOLD) against a larger set of real answers - Expand the question bank and key points beyond the tech/business sample set
- Docker and deployment setup
Interview recordings and transcripts are sensitive. A real deployment needs secure authentication, encrypted transport, explicit recording consent and minimal data retention. ORION is meant for practice and feedback, not for automated hiring decisions.