Overview
A browser-based assistant driven by speech as well as text. Recognition and synthesis are isolated behind dedicated hooks, conversation history is persisted per authenticated user, and an admin surface exposes prompt, model, voice and general settings as configuration rather than as constants buried in the code.
Problem
A text-only assistant is the wrong interface when someone's hands or eyes are occupied, and a voice interface built directly against the browser speech APIs leaks their statefulness through the whole application.
Assistant behaviour also needs to change without a deployment. If the system prompt and voice settings are constants in source, every adjustment becomes an engineering task.
Business context
Assistant behaviour is tuned continuously after launch, mostly by people who are not going to open a pull request. Treating the prompt as configuration is what makes that iteration possible.
Conversation history serves two purposes: continuity for the user, and a record that makes it possible to see what people actually ask rather than what was assumed.
Solution
Speech recognition and speech synthesis are each confined to their own hook, with shared types and utilities beside them, so the rest of the application consumes a stable interface instead of the browser's event-driven API surface.
A single assistant context owns conversation state, which keeps chat views presentational and prevents the session from being reconstructed in several places.
Authentication and persistence run on Supabase: accounts, verification and per-user history without operating a separate backend for what is a well-solved problem.
Prompt, API, voice and general settings live in an admin surface, and analytics views surface query volume and the most frequent queries.
Architecture
Input
Speech recognition
Web Speech API hook
Text input
Chat composer
Session
Assistant context
Conversation state
History context
Persisted transcripts
Configuration
Prompt settings
Behaviour without redeploy
Voice settings
Synthesis parameters
API settings
Provider configuration
Platform
Supabase auth
Accounts and verification
Supabase data
History per user
Output
Speech synthesis
Spoken response
Analytics
Volume and top queries
Implementation
Recognition and synthesis are separated because they fail independently: a browser may support one and not the other, and permission handling applies only to input. Combining them would force the application to reason about both at once.
Forms are validated with Zod schemas through React Hook Form, so settings that reach the assistant are shape-checked before they are stored.
Server state is handled by React Query rather than by hand-rolled effects, which removes an entire category of stale-data and race bugs from the history and analytics views.
The component layer is built on Radix primitives, so keyboard interaction and focus management in dialogs, menus and popovers come from accessible primitives rather than from bespoke implementations.
Engineering challenges
Browser speech APIs are stateful and inconsistent
Recognition sessions start, end and error asynchronously, and support varies by browser. Confining that behind hooks keeps the inconsistency in one place instead of spreading it through every component that speaks or listens.
Behaviour that must change without a deploy
Prompts are tuned far more often than code ships. Storing them as configuration turns a release into a settings change.
Conversation state in several views at once
Chat, history and analytics all read the same session. A single owning context prevents three subtly different copies of the truth.
Key decisions
- A managed platform for auth and persistence
- Accounts, verification and per-user storage are solved problems. Building them again would add operational load without adding anything a user notices.
- Prompt as configuration, not as code
- It moves iteration out of the deployment pipeline and to the people actually tuning the assistant.
- Accessible primitives for the interface
- Keyboard and focus behaviour is easy to get wrong by hand and expensive to retrofit.
Results
No production metrics are published for this project yet. I would rather show nothing here than a number I cannot stand behind — the architecture and the decisions above are the part worth reviewing.
Technology
Application
- React
- Vite
- TypeScript
- React Router
Voice
- Web Speech API
- Speech recognition
- Speech synthesis
Platform
- Supabase auth
- Supabase persistence
State & contracts
- React Query
- React Hook Form
- Zod
Interface
- shadcn/ui
- Radix UI
- Tailwind CSS
- Recharts
Links
Contact
Have an AI product or workflow worth building?
Send me the problem — not the spec. If it’s a fit I’ll tell you how I’d approach it; if it isn’t, I’ll say so.
Faisalabad, Pakistan · PKT (UTC+5) · Working remotely