Skip to content

Ads: generated spots render every tag in the station voice — the worker never writes a voice plan #702

Description

@genwave-radio

What airs

All 12 demo spots: ANNOUNCER, VOICE1 and VOICE2 in one voice. Kokoro log for spot #11 (2026-09-05 20:28:37–44Z): four POST /v1/audio/speech, all af_alloy. station.ad_spot.voice_plan is NULL on every generated row.

Why

  • src/GenWave.Ads/AdRenderService.cs:123-127 — null/empty plan ⇒ every tag → stationIdentity.Current.Voice.
  • src/GenWave.Tts/AdScriptWriteRequest.cs:44-51 carries no voice fields; AdScriptWriter.cs:397-398 says so: "for a generated spot every tag maps to the station voice anyway". Only the editor's voicePlan field or the API can set one.
  • Per-line voice switching already works when a plan exists (CrosstalkAssembler.cs:208-216, 393-403), so this is a plan-building gap, not a render gap.

Ruling (Dean, 2026-09-06)

A separate ad cast pool, distinct from the DJ personas; the owner can set the ANNOUNCER voice (default Station:Voice).

Fix

  • Settings: Ads:AnnouncerVoice (empty = station voice), Ads:CastVoices (list of Kokoro voice ids; ships with a small mixed default set distinct from the persona defaults). Live settings, help keys.
  • Worker/refill: after the validator passes, build the plan — ANNOUNCER → announcer voice; VOICE1/VOICE2 → two distinct pool voices picked deterministically per spot (seeded by spot id + brand so a regeneration re-casts the same way), never equal to the announcer; persist as voice_plan (AdVoicePlanEntry(Tag, VoiceId, Pace) jsonb). Owner drafts with an explicit plan keep it.
  • Editor/rows: show the cast as read-only chips so approval sees who says what; a cast picker is a later rider (Ads: the spot editor's Brief field is a dead end, and briefs want a "Suggest a brief" button #691 territory).

Acceptance

Kokoro's log for a rendered spot shows ≥ 2 distinct voices when the script has ≥ 2 tags; voice_plan non-null on worker-written rows; SPEC F161.2 rider.

Epic: #380

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium prioritybugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions