Commit graph

18 commits

Author SHA1 Message Date
vrubelroman
8aeca230bc Fix TTS overlap deterministically, preserve message order, fix flaky Google login button
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 29s
Overlay display duration is now computed server-side from estimated
reading time (text length / speaking rate), not from the audio
element's 'ended' event — edge-tts streams MP3 without a duration
header, and OBS's embedded browser fires 'ended' unreliably for that,
which is why the earlier event-based fix didn't hold up.

Per-streamer broadcasts are now serialized through a queue, so a
message waiting on an AI reply can no longer be overtaken by a later
message from a different viewer that doesn't need one.

Also fix the Google Sign-In button intermittently not rendering: the
GSI script tag is async/defer, and both index.html and send.html/js
called google.accounts.id.initialize() without waiting for it to
actually finish loading — a race that failed silently until the
script was cached from a previous load.
2026-07-08 18:21:57 +00:00
vrubelroman
b669c2d0b7 Add streamer dashboard stats; fix TTS overlap race properly
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 30s
Dashboard now shows unique visitors (via sender link), total messages,
and unique senders per streamer, tracked via new viewer_visits/messages
tables.

The previous overlay TTS-overlap fix had a race: audio not having
arrived yet was treated the same as "no audio at all", letting the
queue advance before slow-to-synthesize audio (e.g. a long question)
ever started playing. Now "not arrived yet" is explicitly distinct
from "finished playing", with a grace-period fallback for genuine TTS
failures.

Also drop the hardcoded AI name from ai-prompt.txt since it's now
injected dynamically from the streamer's configured ai_name.
2026-07-08 18:04:02 +00:00
vrubelroman
ec6d8c4cfe Let streamers name their AI assistant; fix overlay TTS audio overlap
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 30s
Streamer dashboard gains an editable AI assistant name (default
"Альтушка Ирина"), stored per-streamer and used for the overlay label,
TTS intro, and DeepSeek system prompt. Also fixes a bug where a long
message's TTS audio could still be playing when the next queued
message started its own audio — the overlay queue now waits for the
current audio to actually finish (not just the configured display
duration) before advancing.
2026-07-08 17:28:36 +00:00
vrubelroman
fec77e2737 Name the AI persona "Альтушка Ирина"
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 29s
Rename overlay/checkbox labels and update ai-prompt.txt so the AI
knows its own name.
2026-07-08 16:50:30 +00:00
vrubelroman
9ec6a9d1df Add README and ARCHITECTURE docs
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 28s
README.md for humans (setup, config, deploy). ARCHITECTURE.md for
future AI sessions — data model, message flow, and a "gotchas"
section documenting real bugs/incidents from this session (session
capture timing, broken edge-tts-node package, OAuth origin/client-id
mixups, docker compose restart vs up -d, self-matching pkill) so they
don't get rediscovered the hard way.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 18:11:53 +00:00
vrubelroman
fd6aa24a1d Tweak AI reply prompt (rarer cat mentions, narrower defense trigger)
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 29s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 18:07:25 +00:00
vrubelroman
620c1e5427 Censor profanity: "..." on screen, spoken as "beep"
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 29s
New profanity.js does whole-word matching against a Russian/English
root list (avoids false positives like "победа", "тебя", "сукно").
Applied once per message before it's used anywhere downstream
(display, TTS, AI reply input) — screen shows "..." in place of a
censored word, while the TTS text uses "бип" so it's heard as a beep
instead of read literally.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 18:01:36 +00:00
vrubelroman
f56b829054 Tweak AI reply prompt (sass allowed, occasional cat mentions)
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 29s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 17:43:18 +00:00
vrubelroman
729f6eb47e Hold viewer message until AI reply is ready, when requested
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 30s
Previously the viewer's message displayed immediately and the AI
reply showed up whenever DeepSeek happened to respond, landing with
an awkward gap. Now, when the AI checkbox is checked, both texts are
fetched/prepared before anything is broadcast, so the original
message and the AI reply queue back-to-back on the overlay. Falls
back to just showing the original message if the AI call fails.
Behavior without the checkbox is unchanged (still immediate).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 17:39:33 +00:00
vrubelroman
ad78436ae2 Retry CI/CD after transient buildkit snapshot error on runner
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 35s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 17:32:07 +00:00
vrubelroman
2799dfdf42 Add optional AI reply via DeepSeek
Some checks failed
CI/CD Pipeline / build-and-deploy (push) Failing after 3s
Viewers can check a box on the send page to get a short AI-generated
reply to their message, voiced with a distinct TTS voice and queued
on the overlay after the original message. The system prompt lives
in ai-prompt.txt (editable without touching code) instead of being
hardcoded. TTS for both viewer messages and AI replies now announces
who it's from ("Сообщение от X." / "Ответ от ИИ.") before the text.
No-ops entirely if DEEPSEEK_API_KEY isn't set.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 17:23:41 +00:00
vrubelroman
03a3a4c4af Queue overlay messages instead of interrupting the current one
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 31s
Messages now play one at a time for their full configured duration
before the next one appears, instead of a new message immediately
replacing whatever was on screen. TTS audio is tagged with the same
message id as its text so it stays in sync even though it's
generated and delivered asynchronously after the text broadcast.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 17:05:01 +00:00
vrubelroman
f4d023c695 Let streamers set how long messages stay on screen
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 29s
Adds display_duration_seconds to the streamers table (default 10s,
with an idempotent migration for existing rows), a dashboard control
to change it, and wires the value through to the overlay via the
display_message payload instead of a hardcoded 10s.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 16:56:49 +00:00
vrubelroman
fab55cde1d Let viewers set a per-streamer display name
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 29s
Viewers can type a custom name shown to the streamer instead of
their Google account name. It's saved per (streamer, viewer) pair
in SQLite and pre-filled on future visits to the same send link.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 16:49:51 +00:00
vrubelroman
ed2b051c91 Retry CI/CD pipeline after fixing prod .env path
All checks were successful
CI/CD Pipeline / build-and-deploy (push) Successful in 18s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 16:02:36 +00:00
vrubelroman
16cbab4b6d Retry CI/CD pipeline
Some checks failed
CI/CD Pipeline / build-and-deploy (push) Failing after 34s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 15:59:33 +00:00
vrubelroman
9c91966730 Multi-tenant platform: per-streamer overlay/sender links + CI/CD
Some checks failed
CI/CD Pipeline / build-and-deploy (push) Failing after 2s
Streamers log in with Google on a new landing page and get a
dashboard with two auto-generated, permanent links: one for their
OBS/StreamLabs Browser Source, one to share with viewers. Messages
are now scoped to the right streamer via Socket.IO rooms instead of
broadcasting globally. Streamer records and tokens are persisted in
SQLite (node:sqlite) so links survive restarts/redeploys.

Also adds a Forgejo Actions pipeline mirroring t2sTelegramBot's:
build, smoke-test, push to the local registry, then deploy to the
prod host over SSH.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 15:53:07 +00:00
vrubelroman
7882db1f37 Initial commit: overlay + sender pages for StreamLabs browser source
Express + Socket.IO backend with Google login on the sender page,
a transparent overlay page for OBS/StreamLabs Browser Source, and
TTS voice-over via the edge-tts Python CLI (same engine as
t2sTelegramBot). Dockerized for deployment.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 15:17:25 +00:00