- TypeScript 90.2%
- CSS 5.7%
- HTML 4.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
- Feedback conversations run on GPT-Live (gpt-live-1, full duplex): the realtime listener writes notes on the run-through, a GPT-Live coach briefed with them, the slides and the points to work on opens the conversation, and the listener reads it back on resume; falls back to the listener coaching itself (live_coach = false to always do so) - The coach shows another slide itself (show_slide), inspects how slides look (look_at_slides) and changes them (edit_slides), via a backend model for GPT-Live and directly for the realtime coach - Slide changes by a GPT model with file tools (editor.ts), confined to presentation_repo: no paths outside it, through symlinks or into .git; editor_model, also picked in the slides menu - Podium loads the presentation from its URL; presentation_repo is only where changes are made - Pickers for the listener's model and the transcriber in the bar - Whole deck in the listener's context at the start of a session - Commands: more audio before each utterance (600 ms) so "Podium" isn't cut off, a lone "Podium." joins the next utterance, and no browser noise suppression on top of OpenAI's - Fix: jumping to a slide set the frame's URL relative to Podium's page and loaded Podium in the frame; only its hash changes now |
||
| assets | ||
| src | ||
| .gitignore | ||
| bun.lock | ||
| config.example.toml | ||
| editor.ts | ||
| package.json | ||
| README.md | ||
| server.ts | ||
| tsconfig.json | ||
Podium
Rehearse a talk out loud to an AI listener that answers with spoken feedback, built on the OpenAI Realtime API over WebRTC.
Run
bun install
mkdir -p ~/.config/podium && cp config.example.toml ~/.config/podium/config.toml
# put your key in openai_api_key, then:
bun dev
Open http://127.0.0.1:4400 and press Start. Podium listens without interrupting you until you ask for something:
- Feedback: a dialogue about what you said since the last round: the coach makes one point at
a time and hands the turn back; react, push back or ask about it, and just start talking to
interrupt it. It runs on GPT-Live (
gpt-live-1, full duplex, so it feels like talking with a person): the listener, which heard the run-through, writes its notes, and a GPT-Live coach briefed with them, the slides and your points to work on opens the conversation. The coach puts the slide to discuss on screen itself (next, previous, or by number) when you ask or it helps, and hears when you move to another slide yourself. Its slide changes go through a backend model (live_backend). When you resume, the listener reads the conversation.live_coach = false, or GPT-Live failing to start, has the listener coach instead. The audience and PA step out meanwhile. Press it again, or say "Podium, resume", to go back to presenting. - Work on (checklist): what to improve, kept per deck. After each piece of feedback the model folds it into the list and ranks it by relevance, in two parts: how you present, and what to change on the slides (by slide). Review slides checks the slides against what you actually say on them; Copy puts the slide changes on the clipboard, to apply in your deck. Tick a point off when you've got it. The coach hears your top points and says whether you improved.
- Changing the slides with the coach: Podium is an overlay on an HTML presentation it loads
from
slides_url. Withpresentation_reposet to the presentation's working copy (served at that URL, for instance with its own little server), the coach can have changes made while you talk feedback over ("make slide 3 three short cards"): a GPT model (editor_model, or "Changes by" in the slides menu) with file tools that reach only the working copy makes it; then the slides reload on the one shown and the coach tells you what changed. It can also answer questions about how slides look (look_at_slides). Nothing is committed, pushed or deployed: review withgit diffand publish yourself. - Demo: Podium gives the talk itself, slide by slide, from your slides, notes, your own words in rehearsals and the points you work on (slides as if the changes were made), spoken through the PA. "Podium, presenteer jij maar" starts it, "Podium, resume" takes the floor back.
- Tips (lightbulb): while you present, the coach writes the odd short tip in a panel at the bottom left, from your last 90 seconds of speech and the slide on screen: at most every 40 seconds, or none when all is fine. These are small separate requests that leave the spoken conversation alone.
- Q&A: Podium plays your audience and asks you questions, one at a time. You can interrupt it. Press it again to go back to presenting.
- Mute: takes you off the record. Podium still transcribes you, to hear "Podium, unmute", but drops what you said from the listener's memory, and doesn't answer in Q&A. Your audio still goes to OpenAI while muted.
- Slides: load slide exports as images (sorted by file name). Use ◀/▶, the arrow keys or a presentation clicker. Podium is shown each slide as you move to it.
- Web slides: open an HTML deck by its URL with the screen button in the bar (or set
slides_urlto open one at start; a deck you open in the bar wins). Podium serves it through/deck/so it can read the current slide; each slide's text and speaker notes reach the model once you stay on it for a moment. The deck must mark its slides.slideand the current one.active, with notes in a.noteselement. - Audience (people icon): a room full of people while you present. After Start a recorded
theatre audience murmurs until you begin speaking; then it hushes to the odd (synthesised) cough,
rustle or creaking chair until Stop. The recording is public domain; see
assets/CREDITS.md. - PA (microphone icon): hear yourself as through a speech mic and loudspeakers (narrower, mid-forward, a little gritty) in a damped, cinema-sized room, with only a hint of its echo. Both buttons switch their sound on and off at any time; Start brings back the ones you last had on, and Stop silences them. They play only to you; the listener still hears your plain microphone. Use headphones: through speakers the mic would pick them up, and feed back.
- Listener: changes who is listening (coach, skeptical executive, friendly colleague). You
can switch during a session. Beside it, the listener's model (the realtime models of your
account,
modelfrom the config by default); a change applies from the next Start. Then the transcriber, the separate model that writes your words in the transcript (the listener hears your audio itself): compare them on your own voice; a change applies at once. - Language (Auto, EN, NL, DE, FR, ES): the language you present in, so the transcript doesn't drift into others, and the one Podium speaks to you, even when your slides are in English. Switchable during a session; Podium remembers your last pick.
The slides fill the window with Podium's controls floating on top; the bar fades out while you
present and comes back when you move the mouse. F toggles full screen (Podium included), T
the transcript.
You can also say the actions, starting a sentence with "Podium": "Podium, feedback",
"Podium, questions", "Podium, resume" (back to presenting, from feedback or Q&A), "Podium, mute" /
"unmute", "Podium, stop", "Podium, next slide" / "previous slide". The same works in Dutch,
German, French and Spanish ("Podium, ga verder", "Podium, volgende", "Podium, geluid uit"),
whatever the language setting; see src/voice.ts.
Other wording works too: when you address Podium without a known phrase ("Podium, ga naar de slide
over Forgejo", "Podium, wat vond je tot nu toe?"), the model works out what you meant from your
words and voice, with the slide titles at hand, and Podium notes what it understood. That takes
about a second longer, and a small extra request that stays out of the rehearsal conversation. The
command takes effect once the transcript of that sentence comes in, about a second after you stop
talking.
The transcript on the right is for you and for the WPM count; the listener hears your audio itself, so a misheard line there doesn't mean Podium misheard you. WPM counts words per minute of actual speech, so pauses don't lower it. Transcription models tend to drop filler words, so Podium judges fillers from your audio, not from the transcript.
Configuration
Settings come from ~/.config/podium/config.toml (see config.example.toml). Environment
variables override the file.
| Config key | Variable | Default |
|---|---|---|
openai_api_key |
OPENAI_API_KEY |
(required) |
model |
PODIUM_MODEL |
gpt-realtime-2.1 |
voice |
PODIUM_VOICE |
marin |
transcribe_model |
PODIUM_TRANSCRIBE_MODEL |
gpt-transcribe |
language |
PODIUM_LANGUAGE |
Auto (the picker in the bar overrides it) |
microphone |
PODIUM_MICROPHONE |
far_field (near_field for a headset) |
port |
PORT |
4400 |
slides_url |
PODIUM_SLIDES_URL |
(none; the deck to open at start) |
live_coach |
PODIUM_LIVE_COACH |
true (feedback conversations on GPT-Live) |
live_backend |
PODIUM_LIVE_BACKEND |
gpt-6-luna (reasons and acts for the GPT-Live coach) |
live_voice |
PODIUM_LIVE_VOICE |
marin |
presentation_repo |
PODIUM_PRESENTATION_REPO |
(none; the presentation's working copy, for changes by the coach) |
editor_model |
PODIUM_EDITOR_MODEL |
gpt-6-luna (makes the coach's slide changes) |
presenter_voice |
PODIUM_PRESENTER_VOICE |
voice (for Demo; a custom voice by its voice_… id) |
Podium keeps your talk (slides, what you said on each) and the points to work on in your browser's IndexedDB; nothing of it leaves your machine except as part of a request during a session.
The server only listens on loopback (127.0.0.1) because every request to it spends your API
key, and only answers requests addressed to 127.0.0.1 or localhost, so a website can't reach it
through your browser by pointing its own hostname there.