| ---
|
| title: Kush Digital Twin
|
| emoji: ποΈ
|
| colorFrom: indigo
|
| colorTo: blue
|
| sdk: gradio
|
| sdk_version: 6.18.0
|
| app_file: app.py
|
| pinned: false
|
| ---
|
|
|
| # Digital Twin MultiModal (Voice and Text)
|
|
|
| A multimodal digital twin chatbot with **text** and **voice** input, powered by OpenAI (LLM + RAG + tool calling), Deepgram (speech-to-text and text-to-speech), ChromaDB (vector retrieval), and Gradio (web UI).
|
|
|
| Converted from the `digital-twin.ipynb` notebook in the AI Engineering course.
|
|
|
| ## Architecture
|
|
|
| 
|
|
|
| **High-level flow:**
|
|
|
| 1. **Text path** β user types β embed query β ChromaDB retrieval β OpenAI chat (with tools) β reply in chat
|
| 2. **Voice path** β user records β Deepgram STT β same RAG + chat pipeline β Deepgram TTS β autoplay reply audio
|
|
|
| **RAG pipeline:**
|
|
|
| 1. Knowledge lives in `knowledge/*.md` (identity, career, technical stack)
|
| 2. `chunking.py` splits documents with overlap at sentence/paragraph boundaries
|
| 3. OpenAI `text-embedding-3-small` embeds each chunk
|
| 4. Vectors are stored in a local ChromaDB collection (`chroma_db_twin/`)
|
| 5. Each user message retrieves the top-N similar chunks and injects them as **Context** in the system prompt
|
|
|
| **Tools available to the LLM:**
|
|
|
| - `send_notification` β Pushover alert to your phone (optional)
|
| - `roll_dice` β simulated dice roll
|
|
|
| **Dynamic context:** keywords in the user's message (`2011`, `dishes`, `sports`, `vacation`) inject extra persona context from `knowledge.md`.
|
|
|
| ## Prerequisites
|
|
|
| - Python 3.10+
|
| - API keys:
|
| - [OpenAI](https://platform.openai.com/api-keys) (required)
|
| - [Deepgram](https://console.deepgram.com/) (required)
|
| - [Pushover](https://pushover.net/) (optional, for notification tool)
|
|
|
| ## Quick start
|
|
|
| ```bash
|
| # Clone or cd into this directory
|
| cd digital-twin-voice
|
|
|
| # Create a virtual environment (recommended)
|
| python -m venv .venv
|
| source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
|
| # Install dependencies
|
| pip install -r requirements.txt
|
|
|
| # Configure environment
|
| cp .env.example .env
|
| # Edit .env and add your API keys
|
|
|
| # Build the vector index (also runs automatically on first app launch if empty)
|
| python build_rag_index.py
|
|
|
| # Run the app
|
| python app.py
|
| ```
|
|
|
| Gradio opens at `http://127.0.0.1:7860` (port may vary). Use the text box or microphone to chat.
|
|
|
| ## Deploy to Hugging Face Spaces
|
|
|
| This repo is ready to deploy as a [Gradio Space](https://huggingface.co/docs/hub/spaces-sdks-gradio). The YAML header at the top of this README configures the Space (`sdk: gradio`, `sdk_version: 6.18.0`, `app_file: app.py`).
|
|
|
| 1. Create a new Space on Hugging Face and choose **Gradio** as the SDK.
|
| 2. Push this repository (or connect your GitHub repo).
|
| 3. In **Settings β Variables and secrets**, add:
|
| - `OPENAI_API_KEY` (required β chat + RAG embeddings)
|
| - `DEEPGRAM_API_KEY` (required for voice input/output)
|
| - Optional: `PUSHOVER_USER`, `PUSHOVER_TOKEN`, model overrides from `.env.example`
|
| 4. On first load, the app builds the ChromaDB index from `knowledge/*.md` (uses OpenAI embeddings). Cold starts on free Spaces may take ~30s.
|
|
|
| For faster restarts, enable [Persistent Storage](https://huggingface.co/docs/hub/spaces-storage) and set `CHROMA_PATH=/data/chroma_db_twin`, then run `python build_rag_index.py` once in the Space terminal.
|
|
|
| ## Project layout
|
|
|
| ```
|
| digital-twin-voice/
|
| βββ app.py # Entry point
|
| βββ build_rag_index.py # Rebuild ChromaDB from knowledge files
|
| βββ chunking.py # Text chunking with overlap
|
| βββ rag.py # Embeddings, ChromaDB, retrieval
|
| βββ config.py # Environment variables and API clients
|
| βββ knowledge/ # Source documents for RAG
|
| β βββ identity.md
|
| β βββ career.md
|
| β βββ technical.md
|
| βββ knowledge.md # Keyword topic triggers only
|
| βββ prompts.py # System prompt + topic loading
|
| βββ tools.py # Pushover + dice tools, tool-call handler
|
| βββ chat.py # OpenAI chat loop with RAG + tool calling
|
| βββ voice.py # Deepgram STT / TTS
|
| βββ ui.py # Gradio interface
|
| βββ requirements.txt
|
| βββ .env.example
|
| βββ docs/
|
| βββ Flow-chart.png
|
| βββ digital-twin-voice-flow.excalidraw
|
| ```
|
|
|
| ## Customization
|
|
|
| - **Persona facts:** edit files in `knowledge/`, then run `python build_rag_index.py`
|
| - **Topic keywords:** edit `knowledge.md` under `## Topics`
|
| - **Chunking:** adjust `RAG_CHUNK_SIZE` and `RAG_CHUNK_OVERLAP` in `.env`
|
| - **Retrieval depth:** set `RAG_N_RESULTS` in `.env` (default: 3)
|
| - **Tools:** add functions in `tools.py` and register them in `TOOLS`
|
| - **Models:** set `OPENAI_MODEL`, `EMBEDDING_MODEL`, `DEEPGRAM_STT_MODEL`, and `DEEPGRAM_TTS_MODEL` in `.env`
|
|
|
| ## Environment variables
|
|
|
| | Variable | Required | Description |
|
| |----------|----------|-------------|
|
| | `OPENAI_API_KEY` | Yes | OpenAI API key |
|
| | `DEEPGRAM_API_KEY` | Yes | Deepgram API key |
|
| | `OPENAI_MODEL` | No | Chat model (default: `gpt-4.1-mini`) |
|
| | `EMBEDDING_MODEL` | No | Embedding model (default: `text-embedding-3-small`) |
|
| | `RAG_N_RESULTS` | No | Chunks retrieved per query (default: `3`) |
|
| | `RAG_CHUNK_SIZE` | No | Chunk size in characters (default: `500`) |
|
| | `RAG_CHUNK_OVERLAP` | No | Overlap between chunks (default: `50`) |
|
| | `RAG_DEBUG` | No | Print retrieved chunk sources to console |
|
| | `CHROMA_PATH` | No | ChromaDB directory (default: `chroma_db_twin`) |
|
| | `DEEPGRAM_STT_MODEL` | No | Speech-to-text model (default: `nova-3`) |
|
| | `DEEPGRAM_TTS_MODEL` | No | Text-to-speech model (default: `aura-2-thalia-en`) |
|
| | `PUSHOVER_USER` | No | Pushover user key (for notification tool) |
|
| | `PUSHOVER_TOKEN` | No | Pushover app token (for notification tool) |
|
|
|
| ## License
|
|
|
| Educational project from the AI Engineering course.
|
|
|