Telegram bot that turns a voice message or an audio file into clean, ready-to-send text: speech-to-text, then an LLM "formulator" pass that removes filler and shapes the result according to a chosen mode, output template, and optional translation.
▶ Live bot: t.me/voice_formulator_bot
About this repository. This is a curated, public subset of a production bot, published to show architecture, code structure, and engineering patterns. The billing/payments layer, growth/marketing automation, operator dashboards, and the tuned production prompts have been removed. No secrets or credentials are included — configuration is supplied entirely through environment variables (see
.env.example).
Voice message in → clean, ready-to-send text out. The animation source is
docs/preview.html (a self-contained HTML/CSS/JS mockup).
The app runs two cooperating async tasks from a single process (app/main.py):
- an aiogram long-polling dispatcher for the Telegram bot, and
- a FastAPI sidecar (
app/web) that exposes/health,/ready, and/metrics.
Dependencies are assembled once into an AppServices container and injected into
handlers and background services, which keeps wiring explicit and the units testable.
Telegram update
│
▼
app/bot/handlers ── aiogram routers (voice, modes, formats, templates, translations,
│ batch, merge, suggestions, help, start, fallback)
▼
app/services ───── audio (ffmpeg) → STT (faster-whisper / Groq) → LLM formulator
│ + ProcessingLimiter (concurrency & per-user queue)
│ + prompt_builder (system+mode composition, JSON output contract)
▼
app/db/repo ────── async SQLAlchemy data layer (users, quota, transcripts,
│ voice requests, events, suggestions)
▼
SQLite / PostgreSQL
| Path | Responsibility |
|---|---|
app/main.py |
Process entrypoint; builds services, starts polling + web server, graceful shutdown |
app/config.py |
Typed settings via pydantic-settings, loaded from env |
app/bot/handlers/ |
aiogram routers, one module per feature area |
app/bot/keyboards.py, texts.py |
Inline keyboards and user-facing copy |
app/services/ |
Audio decode, STT, LLM routing, concurrency limiter, prompt building, formats/templates/translations |
app/db/models.py, repo.py |
ORM models and the async data-access layer |
app/web/ |
FastAPI app and readiness/metrics checks |
tests/ |
pytest unit tests for the pure logic |
- Provider abstraction with key-pool failover.
services/llm.pyandservices/stt.pyrotate over a comma-separated pool of API keys, fall back across models, and place a key on temporary cooldown after429responses. The primary LLM model can be pinned or resolved dynamically from a ranking source. - Backpressure via a concurrency limiter.
services/processing.pybounds concurrent STT jobs, queues waiters, and enforces one active job per user, so a slow transcription can't exhaust resources or let a single user monopolize the worker. - Plan-aware quota engine.
repo.quota_decision/quota_snapshotgrade each request against the user's plan and remaining allowance as a pure function of(user, settings), which makes the rules straightforward to unit-test. - Prompt assembly as a contract.
services/prompt_builder.pycomposes a common system prompt with a per-mode or per-template instruction and requires a strict JSON response (status/final_text/reason_code), with explicit prompt-injection hardening (the transcript is treated as data, never instructions). The tuned production prompt text is intentionally omitted from this public version; the assembly structure remains. - Result shaping. Output formats (message vs. file) and output templates (todo list, meeting minutes, brief, …) are pluggable transforms over the same pipeline.
- Observability.
/readyaggregates DB/LLM/STT/queue health;/metricsreports queue stats, per-key/per-model call telemetry, and the active model route.
Prerequisites: Python 3.11+, ffmpeg, a Telegram bot token, and a Groq (and/or OpenRouter) API key.
python -m venv .venv
. .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env # then fill in TELEGRAM_BOT_TOKEN and GROQ_API_KEYS
python scripts/init_db.py
python -m app.mainHealth endpoints once running:
http://127.0.0.1:8791/healthhttp://127.0.0.1:8791/readyhttp://127.0.0.1:8791/metrics
pip install -r requirements-dev.txt
ruff check app tests
python -m pytestBoth commands run in CI on Python 3.11 and 3.12 for every push.
Python 3.11 · aiogram 3 · FastAPI · SQLAlchemy 2 (async) · pydantic-settings · faster-whisper / Groq for STT · Groq / OpenRouter for the LLM · Docker.
CC BY-NC 4.0 © 2026 Anton Antonov.
Read it, learn from it, quote it with attribution. Commercial reuse of this code is not granted — the bot it was extracted from is a running commercial product.
