smart-advisor / docs /PROJECT_FLOW.md
sajaahmed5
Deploy
35769d4
|
Raw
History Blame Contribute Delete
3.39 kB
# Project Flow โ€” How Smart Advisor Fits Together
A 5-minute map for the team. Not deeply technical โ€” just "who does what, and where does my
part plug in." For the deep-dive details, see the links at the bottom.
## What Smart Advisor does
A student asks an academic question โ€” by voice or by typing, in Arabic โ€” and gets back an
answer grounded in official UCAS documents, spoken back to them (or shown as text). No
hallucinated answers: if the system isn't confident, it says so instead of guessing.
## The end-to-end flow
```mermaid
flowchart LR
S(["๐ŸŽ™๏ธ Student asks a question"]) --> UI1["๐Ÿ–ฅ๏ธ UI โ€” Shahd\nrecords the audio"]
UI1 --> STT["๐ŸŽง Voice (STT) โ€” Saja\ntranscribe_audio(audio)"]
STT -->|MSA question text| RAG["๐Ÿง  RAG โ€” Fatema\nretrieve + generate the answer"]
RAG -->|MSA answer text| TTS["๐Ÿ”Š Voice (TTS) โ€” Saja\nsynthesize_speech(text)"]
TTS --> UI2["๐Ÿ–ฅ๏ธ UI โ€” Shahd\nplays the spoken answer"]
UI2 --> E(["โœ… Student hears/reads the answer"])
```
The **UI** wraps the whole loop โ€” it captures the recording at the start and plays
the result at the end. Everything in between is one pillar handing a plain value to the next:
audio โ†’ text โ†’ answer text โ†’ audio.
## How the pieces connect
The voice layer is exactly two functions.
```python
from voice import transcribe_audio, synthesize_speech, VoiceError
def voice_loop(audio):
try:
question = transcribe_audio(audio).text # <- Voice: speech to text
except VoiceError:
return None, "ู„ู… ุฃูู‡ู… ู…ุง ู‚ู„ุชู‡ุŒ ู…ู† ูุถู„ูƒ ุญุงูˆู„ ู…ุฑุฉ ุฃุฎุฑู‰." # "I didn't catch that"
# <<< Fatema's RAG pipeline plugs in right here >>>
answer_text = fatema_rag_pipeline(question)
try:
speech = synthesize_speech(answer_text) # <- Voice: text to speech
return speech.audio_path, answer_text
except VoiceError:
return None, answer_text # still show the text even if TTS failed
```
## Mock mode vs real mode
- **Build against mock mode** โ€” it's the default, needs zero setup (no models, no GPU, no API
key), and returns realistic-shaped fake data instantly. This is what you should develop and
test against day to day.
- **Flip one env var for real audio**: `VOICE_BACKEND=real`. The exact same code runs โ€” same
two functions, same return fields, same exceptions โ€” just with real Whisper transcription
and real spoken audio (Azure or offline Piper) instead of placeholders.
- **The voice models are done and real mode works today.** You don't need to wait for
anything โ€” build against mock now, flip the switch whenever you want to hear it for real.
## Getting started for teammates
- [ ] Clone the repo
- [ ] Nothing to install for mock mode โ€” `from voice import ...` just works
- [ ] Open and run [`docs/voice_usage_guide.ipynb`](voice_usage_guide.ipynb) top to bottom
- [ ] In your own code: `from voice import transcribe_audio, synthesize_speech, VoiceError`
- [ ] Wrap every call in `try/except VoiceError`
- [ ] Only if you need real audio: `pip install -r requirements-voice.txt` and set the env
vars described in `src/voice/CONTRACT.md`
## Want more detail?
- [`docs/voice_usage_guide.ipynb`](voice_usage_guide.ipynb) โ€” a runnable, teaching notebook:
the same examples above, plus async variants and picking a male/female voice.