This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
The problem
Table Topics is the impromptu round of Toastmasters: you get a prompt you've never seen, and you stand up and speak for one to two minutes. No notes, no prep.
I'm competing soon, and my weakness is exactly that - I ramble, I overrun the time, and I can't hear my own filler words. A human coach costs money per session and can't sit with me at 11pm the week before a contest. The feedback tools that exist want my audio on their servers and charge per minute, which is exactly wrong for daily drills.
So I built Confident Speaker Coach: open a link, get a topic, speak, and get scored on the actual Toastmasters ballot - Content 55, Delivery 30, Language 15 - plus one audience-member's honest reaction, the single biggest fix, and one concrete upgrade. The coach reads the verdict back to me out loud.
Demo
- Video walkthrough: https://youtu.be/bNixwmELWNo - one full round: the topic 'What is overrated, and what is underrated?', a real 2:01 speech, and the coach's scored verdict.
- Source: https://github.com/viveknshah/confident-speaker-coach
No hosted demo, on purpose: the whole point is that it runs on your machine, so the demo is the repo plus the video. It takes one command:
Run it yourself
git clone https://github.com/viveknshah/confident-speaker-coach
cd confident-speaker-coach
docker compose up # pulls qwen2.5:3b-instruct (~1.9 GB) on first run
# open http://localhost:3000 - Chrome or Edge for the mic
No Docker? ollama pull qwen2.5:3b-instruct && node server.js - Node 18+, zero npm dependencies. Swap the model with OLLAMA_MODEL (I used gemma3:4b for a while). Once the model is pulled, the coaching loop runs locally - note the typed fallback is the fully-offline input path; Chrome's live transcription uses the browser's speech service.
What it does
- Gives you a Table Topics prompt.
- Runs a contest timer with the official 1:00-2:30 window, and transcribes your speech live in the browser (Web Speech API; typed fallback in other browsers).
- Scores the speech: the app measures length, words per minute and filler words in code - those are facts, and I don't trust a model to guess them. A local open-weight model judges the content, structure and language, and its ballot scores get clamped to the real 55/30/15 weights.
- Tells you the verdict the way my club's coaches do: length first, then the ballot, then how it landed for an audience member, then the one biggest fix and one concrete upgrade for your next attempt.
- Speaks a 3-sentence verdict back out loud, so practice feels like a person is in the room. It uses the browser's built-in voice by default; set an ElevenLabs key and it upgrades to a natural voice, with the key kept server-side.
The open-source AI at the core
The coach is an open-weight model - qwen2.5:3b-instruct - running in Ollama on the server. Remove it and the product is a kitchen timer. Every part of the feedback that requires judgment (ballot scoring, the audience reaction, the fix, the rewritten beat) comes from that model, constrained to strict JSON so the UI can render it directly.
Why a 3B model: it's small enough for a cheap 4 GB CPU box, and it's reliable at structured output for its size, which matters because the UI renders the fields it returns. Don't like my choice? OLLAMA_MODEL=gemma3:4b docker compose up - the whole coaching brain is one environment variable.
The division of labour is deliberate:
| Measured in code (facts) | Judged by the model (opinion) |
|---|---|
| Speech length vs the 1:00-2:30 contest rule | Content and structure quality |
| Words per minute | Language and word choice |
| Filler-word counts | Audience reaction, biggest fix, one upgrade |
Small models are generous graders. Mine can't inflate the numbers, because the numbers come from a stopwatch and a word counter.
Why open innovation is what makes this work
- Cost is why the business works. Unlimited practice is the product. A club of 30 members running 10 drills a week each is thousands of model calls a month - free on open weights, a growing invoice on a per-token API. The subscription math only closes at zero marginal cost.
- Privacy is a feature, not a compliance line. Table Topics speeches are personal - people talk about their jobs, their families, their failures. On a self-hosted club instance, the transcripts and scores never leave infrastructure the club controls. (One honest caveat: if you use the mic, Chrome's live transcription uses the browser's speech service - the typed fallback keeps everything on the box.)
- No lock-in. The model, the prompt and the scoring rules are all in the repo. A club can fine-tune for its own contest format, swap models as better open weights land, and never renegotiate with me or anyone else.
Who pays
Toastmasters has over 265,000 members across 13,800+ clubs, and every one of them practices Table Topics weekly with no good way to get feedback between meetings. Clubs pay a monthly subscription for the hosted version - shared practice, member progress, their own topics. Individuals self-host free; the whole thing is one docker compose up, because the people who most need speaking practice are often the people least able to pay per session.
First user: me, the night I built it. I gave it a real Table Topics attempt - "What is overrated, and what is underrated?" - and rambled for two minutes about movie hype. The coach scored me 28/100 and it was right: it clocked my 37-words-per-minute crawl (I was thinking, not speaking), called the speech disjointed, and its one fix was "define overrated vs underrated up front, then structure around it." That's exactly what a human evaluator would have told me, at 11pm, for free, with the audio never leaving my laptop.
How it's built
Zero-dependency Node 18 server (no npm install), static frontend, Docker compose with Ollama and the model pull baked in:
Browser (mic, live STT, timer) --> Node server --> Ollama (qwen2.5:3b-instruct, strict JSON)
|
+--> optional ElevenLabs TTS (browser voice by default)
/api/topic, /api/coach, /api/speak (optional rate-limited ElevenLabs proxy; browser voice when unset). Tests cover the timing rules, filler measurement, score clamping and the API in mock mode.
What's honestly rough
- A 3B model is a decent club coach, not a world champion judge. The measured facts keep it honest; the prose feedback is where bigger open models (or a fine-tune on real ballots) would help.
- Live transcription uses the browser's Web Speech API, so Chrome/Edge only for now - swapping in local Whisper is the obvious next step, and it's open-weight too.
- What broke in my real run: this laptop's Ollama GPU runner was broken - every coaching call failed with
CUDA error: shared object initialization failed- so the verified setup is a CPU-only Ollama server. Related: gemma3:4b on CPU managed ~1.3 tok/s (a verdict would take 6+ minutes), which is why the demo ships qwen2.5:3b-instruct (~3 tok/s warm, ~3 min per verdict - the video captions the thinking pause instead of editing it out).
My Agent Session
Prize Categories
Entering overall judging only. ElevenLabs stays in the code as an optional voice upgrade, but the demo ships on the browser voice - no partner category claim.
Built with Ollama + qwen2.5.













