Skip to content

Latest commit

Β 

History

65 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ‡©πŸ‡ͺ German Tutor πŸ‡©πŸ‡ͺ

German Tutor started as an AI-powered German language learning assistant that helps users improve their German vocabulary, sentence structure, and grammar.

Now it is a multi-lingual language learning assistant that can also be used as a general assistant. It uses speech recognition, large language models (LLMs), text-to-speech (TTS), and RAG (retrieval-augmented generation) to provide corrections, explanations, and up-to-date answers.


Examples

1. Speaking German

Speaking German

2. Asking a question in German

Asking a question in German

3. Asking a question in English

Asking a question in English

4. Session termination (with end phrase)

Session termination (with end phrase)

Latest Model: German Tutor V3.1

German Tutor V3.1 is rebuilt around a LangGraph ReAct pipeline with full session memory.

Memory example

memory

V3.1 updates:

  • Text mode: the assistant can now be used entirely from the terminal, no microphone, no wake word required. Toggle between text and audio mode with toggle_text_mode in config.yaml.
  • LangGraph ReAct pipeline: the LLM now runs as a proper ReAct agent, it reasons, decides whether to call a tool, receives the result, and loops until it's ready to respond.
  • ReAct pipeline: separated into a react_agent node (LLM reasoning) and a retriever_agent node (tool execution), connected via LangGraph's conditional edges.
  • Session memory: conversation history is persisted across turns using LangGraph's MemorySaver checkpointer, the model remembers everything said earlier in the session.
  • TTS interruption: TTS now runs in a background thread and can be interrupted mid-speech by pressing the enter key (in both text and audio modes).

Previous: German Tutor V3.0

German Tutor V3 introduced multi-language support and general assistant capabilities.

V3.0 updates:

  • RAG integration for up-to-date answers using live web search.
  • Modular and organized codebase for easier maintenance and customization.
  • All options, including language settings, can be modified in the config.yaml file.

V3.0 major improvements:

  • Faster and more accurate STT: now using faster-whisper with configurable model sizes (replacing sound_recognition).
  • Real-time TTS: mpv + edge-tts for faster synthesis without temporary files (previous method still available if needed).
  • LLM upgrade: openai/gpt-oss-120b from Groq (default and recommended), offering more free daily API calls. Users can choose any other Groq LLM by changing the model in the config.yaml file.
  • Improved TUI for a smoother user experience.

New RAG Feature

German Tutor V3 now supports two RAG modes (retrieval-augmented generation):

  • Online RAG (tavily_rag.py): live web search via Tavily AI, good for current events, up-to-date grammar references, and anything not in your local books.
  • Offline RAG (offline_rag.py): searches a local vector database built from your own books/documents, works without internet and is faster for static reference material.

The ReAct agent decides which tool to use (or neither) based on the question.

Here's a visual comparison of RAG vs no RAG:

1. Without RAG

No RAG

2. With online RAG

With RAG

3. With offline RAG

With RAG


Features & Complete Architecture

NOTE: Anything with an asterisk* can be customized in the .yaml file.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                       USER INPUT                            β”‚
β”‚       (German, any other language, or any question)         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚                          β”‚
    toggle_text_mode: False    toggle_text_mode: True
               β”‚                          β”‚
               ↓                          ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   AUDIO MODE             β”‚  β”‚   TEXT MODE                   β”‚
β”‚ - Wake word*: "Jarvis"   β”‚  β”‚ - Type directly in terminal   β”‚
β”‚ - Record until silence   β”‚  β”‚ - Press Enter to send         β”‚
β”‚ - Whisper STT            β”‚  β”‚ - Press Enter to stop TTS     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚                              β”‚
               ↓                              β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                  β”‚
β”‚  SPEECH-TO-TEXT          β”‚                  β”‚
β”‚  (Faster-Whisper)        β”‚                  β”‚
β”‚  - Model*: tiny β†’ large  β”‚                  β”‚
β”‚  - Language*: auto/manualβ”‚                  β”‚
β”‚  - Output: USER TEXT     β”‚                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                  β”‚
               β”‚                              β”‚
               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              LANGGRAPH ReAct PIPELINE (with session memory)         β”‚
β”‚                                                                     β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚   β”‚  react_agent node (LLM)                                     β”‚   β”‚
β”‚   β”‚   - Receives full conversation history (MemorySaver)        β”‚   β”‚
β”‚   β”‚   - Reasons about the input                                 β”‚   β”‚
β”‚   β”‚   - Decides: answer directly OR call a tool                 β”‚   β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚            tool call? β”‚                 β”‚ no β†’ final answer         β”‚
β”‚                       ↓                 ↓                           β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚   β”‚  retriever_agent node     β”‚    β”‚  END β†’ response to user     β”‚  β”‚
β”‚   β”‚  Tool options:            β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚   β”‚  - Tavily web search      β”‚                                     β”‚
β”‚   β”‚  - Offline book search    β”‚                                     β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                     β”‚
β”‚              β”‚ tool result loops back to react_agent                β”‚
β”‚              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                TEXT-TO-SPEECH (Edge-TTS + mpv)              β”‚
β”‚   - Runs in background thread (non-blocking)                β”‚
β”‚   - Interruptible mid-speech                                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                AUDIO PLAYBACK β†’ Loop or Exit                β”‚
β”‚            (using end phrases like: close, bye)             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

File Structure

German-Tutor/
β”‚
β”œβ”€β”€ german_tutor_V3.py            # main entry point
β”‚
β”œβ”€β”€ MODEL_3/                       
β”‚   β”œβ”€β”€ graph.py                  # LangGraph pipeline (ReAct loop + memory)
β”‚   β”œβ”€β”€ config.yaml
β”‚   β”‚
β”‚   β”œβ”€β”€ audio/              
β”‚   β”‚   β”œβ”€β”€ wake_word.py        
β”‚   β”‚   β”œβ”€β”€ audio_io.py  
β”‚   β”‚   β”œβ”€β”€ stt.py  
β”‚   β”‚   β”œβ”€β”€ tts.py           
β”‚   β”‚   └── end_phrase.py      
β”‚   β”‚
β”‚   β”œβ”€β”€ LLM/              
β”‚   β”‚   β”œβ”€β”€ react_agent.py        # ReAct agent node + AgentState
β”‚   β”‚   β”œβ”€β”€ response_formatter.py         
β”‚   β”‚   └── prompt_templates.py 
β”‚   β”‚
β”‚   β”œβ”€β”€ RAG/                       
β”‚   β”‚   β”œβ”€β”€ tavily_rag.py         # live web search tool
β”‚   β”‚   └── offline_rag.py        # local book search tool
β”‚   β”‚
β”‚   └── experiments/ 
β”‚
β”œβ”€β”€ README.md                 
β”‚
└── Archived Models/             # contains versions 1 and 2

Getting Started

Absolute requirements:

  • faster-whisper
  • edge-tts
  • groq
  • langchain-groq
  • langgraph
  • rich
  • tavily
  • chromadb

Only required for audio mode:

  • pvporcupine
  • pyaudio

For the best performance, install:

  • mpv (if not possible, then ffmpeg, but it will be slower)

You will also need access keys for:

  • groq β†’ GROQ_API_KEY
  • pvporcupine β†’ PORCUPINE_ACCESS_KEY
  • tavily -> TAVILY_API_KEY

Add them to a .env file.


License

MIT License See LICENSE for details.


About

Voice-activated, multi-lingual tutor using speech recognition, LLM feedback, RAG, and text-to-speech to help users practice and improve languages, including German.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages