|
Download database_schema.md from Gaykar/AIService: direct link, hf CLI and curl.
- Browser
- Download file 3.59 kB
-
https://huggingface.co/spaces/Gaykar/AIService/resolve/main/database_schema.md
- Command line
-
hf download hf://spaces/Gaykar/AIService/database_schema.md
-
curl -L -o database_schema.md https://huggingface.co/spaces/Gaykar/AIService/resolve/main/database_schema.md
3.59 kB
Database Schema β Voice Chat (STT/TTS) System
1. users
| Column | Type | Notes |
|---|---|---|
| id | PK |
2. threads
Represents a conversation session β groups multiple messages together.
| Column | Type | Notes |
|---|---|---|
| id | PK | internal DB primary key |
| client_thread_id | UUID | client-generated thread identifier β Column(UUID(as_uuid=True), default=uuid.uuid4, unique=True, index=True, nullable=False). This is what the client sends and what's used to build the thread_abc-equivalent folder name in the S3 path below β decoupled from id so the internal PK never has to be exposed to or generated by the client. |
| user_id | FK β users.id | |
| created_at | timestamp | session start |
3. messages
One row per audio event (STT input turn or TTS output turn). The type column determines which direction the conversion runs.
| Column | Type | Notes |
|---|---|---|
| id | PK | internal DB primary key |
| client_msg_id | UUID | client-generated message identifier β Column(UUID(as_uuid=True), default=uuid.uuid4, unique=True, index=True, nullable=False). The client generates this before uploading, uses it as the S3 filename (msg_<client_msg_id>.wav), and sends it along with the DB write β this is what enables direct client β S3 presigned-URL uploads, bypassing your backend for the audio bytes entirely. |
| thread_id | FK β threads.id | internal join β resolved server-side by looking up the row matching the client's client_thread_id |
| user_id | FK β users.id | denormalized β avoids a join for ownership checks |
| type | enum: stt | tts |
direction of conversion |
| audio_storage_path | text | S3/Supabase path β built from client_thread_id + client_msg_id, see layout below |
| text_content | text | transcript (STT output) or source text (TTS input) |
| created_at | timestamp | for ordering turns within a thread |
How type works:
type = sttβaudio_storage_pathis the input,text_contentis the model output (transcript)type = ttsβtext_contentis the input,audio_storage_pathis the model output (generated audio)
Why two IDs per row (id vs. client_*_id):
id is the internal relational PK β small, sequential, used for all server-side joins and never exposed to or generated by the client. client_thread_id / client_msg_id are what the client actually generates, sends, and uses to name S3 objects β this lets the client build a valid, unique S3 path and request a presigned upload URL before your backend has even created a DB row, without ever needing to know or influence the internal PK.
S3 / Supabase Bucket Layout
bucket/
βββ user_id_123/
βββ stt/
β βββ {client_thread_id}/
β βββ msg_{client_msg_id}.wav β input (spoken query)
β
βββ tts/
βββ {client_thread_id}/
βββ msg_{client_msg_id}.wav β output (spoken response)
- The folder/file names in this path are the client-generated
client_thread_idandclient_msg_idβ not the internalidcolumns. audio_storage_pathin themessagestable stores this exact path, so it can be used directly for S3 reads/writes without reconstructing it.- Split by
stt/andtts/at the top level (not by thread) so each pipeline can have independent lifecycle/retention rules. {client_thread_id}/nested underneath keeps all audio for one conversation together for easy per-thread cleanup or export.
