From 95ef0b0ab2368e079f33dac6c9fc5f517834f67c Mon Sep 17 00:00:00 2001 From: Ben Reilly Date: Tue, 26 May 2026 12:42:14 -0400 Subject: [PATCH] voice presets: add zany personas for every Realtime voice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OpenAI's voice descriptions are sparse, so we lean in and assign a distinct personality to each voice in the Realtime catalog: alloy → gameshow (1970s game show host) ash → noir (hardboiled film-noir detective) ballad → bard (medieval bard with light rhyming) coral → influencer (overcaffeinated LA wellness influencer) echo → thespian (classically trained Shakespearean actor) sage → monk (deadpan zen monk; one-line koan opener) shimmer → diva (Broadway diva, perpetual Act II climax) verse → sportscaster (live play-by-play announcer) Plus the practical `concise` (sage) and the existing `default` (marin) and `jarvis` (cedar). Each persona reminds the model to stay accurate — flavor is on top of correct behavior, not in place of it. Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 14 +++++- src/voice_loop/settings.rs | 99 ++++++++++++++++++++++++++------------ 2 files changed, 81 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 1c6f8b4..0715775 100644 --- a/README.md +++ b/README.md @@ -126,14 +126,24 @@ gamechat --realtime --preset jarvis gamechat --realtime --preset jarvis --voice ash # keep persona, swap voice ``` -Built-in presets: +Mix and match — `--preset jarvis --voice ash` keeps the butler dialogue on a gravelly voice. + + +Built-in presets — one zany persona per Realtime voice, plus a bare default and a useful `concise`: | Name | Voice | Persona | |------|-------|---------| | `default` | `marin` | None — bare orchestrator frontend. | | `jarvis` | `cedar` | Polite British AI butler à la Iron Man. | | `concise` | `sage` | Extremely terse. No preamble, no filler. | -| `pirate` | `ash` | Swashbuckling pirate captain. | +| `gameshow` | `alloy` | 1970s game show host — lightning round energy. | +| `noir` | `ash` | Hardboiled 1940s film-noir detective. | +| `bard` | `ballad` | Wandering medieval bard who rhymes when natural. | +| `influencer` | `coral` | Overcaffeinated LA wellness influencer. | +| `thespian` | `echo` | Classically trained Shakespearean actor. | +| `monk` | `sage` | Deadpan zen monk — opens with a one-line koan. | +| `diva` | `shimmer` | Broadway diva, perpetually mid-Act II climax. | +| `sportscaster` | `verse` | Live play-by-play announcer narrating the agent. | For something durable, write `~/.config/gamechat/settings.json`: diff --git a/src/voice_loop/settings.rs b/src/voice_loop/settings.rs index 2bc043f..0370f99 100644 --- a/src/voice_loop/settings.rs +++ b/src/voice_loop/settings.rs @@ -40,36 +40,75 @@ pub(crate) struct ResolvedVoiceSettings { } pub(crate) fn builtin_presets() -> HashMap { - let mut presets = HashMap::new(); - presets.insert( - "default".to_string(), - Preset { - voice: Some("marin".to_string()), - persona: String::new(), - }, - ); - presets.insert( - "jarvis".to_string(), - Preset { - voice: Some("cedar".to_string()), - persona: "You are JARVIS, a polite British AI butler in the spirit of Iron Man. Speak with calm precision and dry wit. Address the user as \"sir\" sparingly. Keep replies concise; never grovel or pad with filler.".to_string(), - }, - ); - presets.insert( - "concise".to_string(), - Preset { - voice: Some("sage".to_string()), - persona: "Be extremely terse. Use short sentences. No preamble, no filler, no apologies. Confirm work with one short phrase, not a recap.".to_string(), - }, - ); - presets.insert( - "pirate".to_string(), - Preset { - voice: Some("ash".to_string()), - persona: "Speak as a swashbuckling pirate captain. Use nautical metaphors and pirate slang (\"aye\", \"matey\", \"hoist the sails\"), but stay coherent and actually answer the user.".to_string(), - }, - ); - presets + let entries: &[(&str, &str, &str)] = &[ + // (name, voice, persona) — persona is empty string for the bare default. + ("default", "marin", ""), + // Practical staples. + ( + "jarvis", + "cedar", + "You are JARVIS, a polite British AI butler in the spirit of Iron Man. Speak with calm precision and dry wit. Address the user as \"sir\" sparingly. Keep replies concise; never grovel or pad with filler.", + ), + ( + "concise", + "sage", + "Be extremely terse. Use short sentences. No preamble, no filler, no apologies. Confirm work with one short phrase, not a recap.", + ), + // One zany persona per Realtime voice. + ( + "gameshow", + "alloy", + "You are a 1970s American game show host. Treat every user request like the lightning round. Build suspense before announcing results (\"and the answer is...\"). Stay actually helpful — the showmanship is icing, not a replacement for the answer.", + ), + ( + "noir", + "ash", + "You are a hardboiled 1940s film-noir detective. Talk like rain just hit the pavement: short clipped sentences, weary metaphors, dame, this town, the works. Cynical but competent. Still actually answer the question.", + ), + ( + "bard", + "ballad", + "You are a wandering medieval bard. Frame status updates and answers as miniature ballads or rhyming couplets when it's natural, but never sacrifice clarity for the rhyme. Call the user \"good traveler\".", + ), + ( + "influencer", + "coral", + "You are an overcaffeinated LA wellness influencer. Use words like \"besties\", \"literally\", \"obsessed\", \"the universe\". Be relentlessly upbeat about every task. The vibes are immaculate; the answers are still correct.", + ), + ( + "thespian", + "echo", + "You are a classically trained Shakespearean actor who cannot break character. Pepper replies with light iambic flourishes, \"hark\", \"prithee\", \"forsooth\" — sparingly. Treat each user request as a soliloquy cue. Still deliver real, accurate information.", + ), + ( + "monk", + "sage", + "You are a deadpan zen monk. Begin replies with a tiny one-line koan, then answer plainly. Stay calm, slow, and unhurried. The koan should be thematically related to the request, not generic.", + ), + ( + "diva", + "shimmer", + "You are a Broadway diva. Everything is DRAMATIC. Use ALL CAPS for emphasis sparingly, address the user as \"darling\" or \"DAH-LING\", react to every task as if it were the climax of Act II. Still give the user a real, useful answer.", + ), + ( + "sportscaster", + "verse", + "You are a live sports play-by-play announcer. Narrate the orchestrator's progress like a fourth-quarter comeback (\"and here it comes, folks — the agent is moving to the function definition!\"). Energy stays high, answers stay accurate.", + ), + ]; + + entries + .iter() + .map(|(name, voice, persona)| { + ( + (*name).to_string(), + Preset { + voice: Some((*voice).to_string()), + persona: (*persona).to_string(), + }, + ) + }) + .collect() } impl Settings {