IdeYad (ایدهیاد) — Persian Voice-AI Knowledge Base
A Persian-language, voice-first personal knowledge base: record a voice note, and it's transcribed, classified, embedded, and made searchable in natural language, shipped as both a Telegram bot and an installable PWA.
Overview
IdeYad (ایدهیاد, “Idea Reminder”) is a Persian-language, voice-first personal knowledge base I designed, built, and shipped end-to-end. The core loop is simple: record a short voice note, and an async worker pipeline transcribes it, classifies it into one of four types (task, idea, decision, or learning), stores it with a semantic embedding, and later answers natural-language questions in Persian over your own entries via vector search and LLM synthesis. It started as a Telegram bot MVP and has since grown into a production, installable PWA (app.ideyad.com) served off the same backend, with a marketing site at ideyad.com, phone-based OTP login, and a gamified “Forest of Thoughts” visualization for browsing entries.
The Problem
I capture a lot of scattered ideas, tasks, and half-formed thoughts throughout the day, usually while doing something else, and typing them out was always the friction point that made me not bother. I wanted something closer to thinking out loud: talk for a few seconds, and have it captured, categorized, and searchable later without manual filing. Existing note apps assume typing; I wanted voice to be the primary interface, in Persian, with recall by meaning rather than exact keyword.
Architecture
Shared Backend, Two Frontends — one FastAPI backend and a Postgres/pgvector database serve the Telegram webhook, the JSON API, and the PWA simultaneously, sharing the same job queue, quotas, and data store rather than running as separate systems.
Async Processing Pipeline — voice notes and text entries are picked up by a background worker pool for transcription (Soniox STT), classification into task/idea/decision/learning (DeepSeek via OpenRouter), and semantic embedding (OpenAI text-embedding-3-small), so capture never blocks on processing.
Channel Abstraction — the same delivery logic sends results to Telegram or to the PWA, which stays in sync via lightweight polling. This gives reliable, resumable delivery without needing extra real-time infrastructure.
Authentication — phone-based OTP login with support for multiple SMS providers, and secure, revocable sessions with a “log out everywhere” option.
Frontend / PWA — React 18, TypeScript, Vite, Tailwind, with a fully RTL-native Persian interface (Vazirmatn font, Persian digits, Jalali dates). It’s installable with offline-capable caching and captures voice directly in the browser, with live status updates and no page reloads.
Forest of Thoughts — a hand-built, dependency-free 2.5D visualization (pure CSS/SVG) where each captured thought plants a colored tree in a quadrant matching its type; clicking a tree reveals the entry. No image assets, no 3D library, just hand-rolled perspective and rendering for cross-browser reliability.
Deployment — Docker Compose behind Caddy for TLS, PostgreSQL with the pgvector extension, and a multi-stage Docker build for a lean production footprint.
Results
- Evolved from a Telegram bot MVP into a production, installable PWA sharing one backend, queue, and data store
- Two live, deployed hosts (ideyad.com marketing site, app.ideyad.com PWA) behind a single backend
- A dependency-free, hand-built data visualization feature (Forest of Thoughts) with no CSS-3D or image assets
- OTP authentication with revocable sessions and fully server-enforced quotas and rate limits
Technical Challenges
Choosing a channel-agnostic delivery model was the core design problem: I needed the same event (a stored entry, a clarifying question, an answer) to reach either Telegram or the PWA without maintaining two separate code paths. Solving this without adding heavier real-time infrastructure kept the system simple to operate.
On the language side, Persian required first-class treatment rather than an afterthought: right-to-left layout, Persian digits, and Jalali date handling all needed to be correct in the UI, and I fixed a handful of production bugs specific to RTL rendering and event handling along the way.
Stack
FastAPI, PostgreSQL + pgvector (HNSW), asyncpg, DeepSeek (via OpenRouter), OpenAI text-embedding-3-small, Soniox STT, ffmpeg, Docker Compose, Caddy, React 18, TypeScript, Vite, Tailwind CSS, zustand.