commit 13e12e7740783c76975ab09869458b843eac8e68 Author: pleb Date: Tue Jul 14 13:44:32 2026 -0700 Init repo diff --git a/docs/idea-01.md b/docs/idea-01.md new file mode 100644 index 0000000..7aad277 --- /dev/null +++ b/docs/idea-01.md @@ -0,0 +1,107 @@ +This is a good fit for a local TypeScript CLI. + +The clean architecture is: + +1. Watch the EverQuest log file. +2. Parse incoming chat/dialog lines into events. +3. Resolve a stable speaker identity. +4. Look up or assign a voice for that speaker. +5. Send the text to Kokoro-FastAPI. +6. Play the returned audio locally. +7. Persist the speaker-to-voice mapping so the same NPC or guild member keeps the same voice. + +A CLI can absolutely emit sound. It just needs to hand audio to something that can play it. On Linux and Windows, the most portable pattern is: have the CLI request WAV/MP3 from your TTS backend, then either play it through a Node audio library or spawn a bundled player such as `ffplay` or `mpv`. + +A practical design would be: + +* `watcher`: tails the EQ log +* `parser`: classifies lines as NPC speech, guild chat, tells, combat spam, system text +* `speaker-store`: `speakers.json` or SQLite +* `voice-selector`: deterministic initial assignment plus manual overrides +* `tts-client`: calls Kokoro-FastAPI over HTTP +* `audio-out`: queues and plays audio +* `config`: filters, volume, rate limits, voice pool, per-channel rules + +For voice reuse, do not key only on raw display text. Use a normalized speaker key such as: + +* `npc:` +* `player:guild:` +* optionally `zone:` if the game reuses names across contexts + +Then store something like: + +```json +{ + "npc:guard_thom": { + "voice": "en_female_04", + "last_seen": "2026-07-14T19:22:10" + }, + "player:guild:sysadmin": { + "voice": "en_male_07" + } +} +``` + +For assignment, a good default is deterministic hashing: + +* first encounter of a speaker hashes to one voice from a fixed pool +* manual overrides can replace that later +* the same speaker always gets the same voice on every machine if the voice pool matches + +That gives you consistency without needing to curate every NPC by hand. + +For NPC dialog versus guild chat, I would split policies: + +* NPCs: one stable voice per NPC +* guild chat: one stable voice per guild member +* system/combat spam: usually ignore +* unknown speakers: assign a temporary voice and persist only if it repeats + +A few implementation choices matter: + +* Use a long-running local HTTP TTS server, not shelling out per line to generate everything from scratch. +* Add a queue so overlapping lines do not talk over each other. +* Cache generated clips for repeated lines. +* Add line deduping, because MMOs often repeat log lines. +* Add optional “interrupt” behavior for urgent lines, and “drop” behavior for spam. + +For the TypeScript stack, I would use: + +* `commander` or `oclif` for the CLI +* `chokidar` or a small tailing library for file watching +* `zod` for config validation +* `better-sqlite3` if you want a durable speaker database +* `execa` to invoke an audio player if you keep playback external + +For cross-platform sharing, a CLI is still fine. The main constraint is audio playback. The simplest distribution path is: + +* package the CLI as an npm tool +* have it talk to a locally running Kokoro-FastAPI instance +* require either `ffmpeg`/`mpv` installed, or bundle a playback method +* ship platform-specific startup scripts for Linux and Windows + +If you want the widest compatibility, keep the core app platform-neutral and avoid Linux-only assumptions like PipeWire-specific commands. Generate standard WAV and play it with a cross-platform backend. + +The likely best prototype is: + +```text +eq-tts watch --log ~/.wine/drive_c/.../eqlog.txt --voice-mode hash --playback mpv +``` + +Then expand it with: + +```text +eq-tts map npc "Guard Thomas" --voice en_male_03 +eq-tts mute "combat" +eq-tts channel guild --enabled +eq-tts export-speakers +``` + +My recommendation: build the first version as a Node/TypeScript CLI with three boundaries only: + +* file tailing +* speaker/voice mapping +* audio playback + +Keep the Kokoro integration behind a single HTTP client. That will make it easy to swap in another local TTS backend later, and easy for Windows users to run the same app. +