tts_warm: Spionens replikker (--only spion)
Spionens faste replikker (de faste, reglerne, temaerne, rundernes nummer og
starten for 4-10 spillere) står i budget-køen efter Tegn og Gæts og før Fup
og Fakta's spørgsmål; de generiske står sammen med de andre spils generiske,
og menuen har en intro mere. Samme tekst i to spil er ét klip ("Temaet er
Dyr."). --dry-run uden nøgle:
menuens intro 3 klip/854 tegn; generiske 360/19195; Tegn og Gæt 286/11771;
Spionen 166/7152; Fup og Fakta faste 167/9227; fest 56/2657.
--only spion: intro 1/283, generiske 99/5010, faste 166/7152.
Replikken med ordet ved resultatet forvarmes ikke (et klip pr. ord og
variant); uden live-stemme siges den generiske.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ from fupogfakta.models import Category, Question
|
||||
from party import games, tts
|
||||
from party.narrator import (GENERIC, GENERIC_COMMON, LINES, TEASES, TEASES_FEST, Narrator, generic_texts,
|
||||
speakable_prompt)
|
||||
from party.spion import warm_generic as spion_generic, warm_texts as spion_texts
|
||||
from party.tegn import warm_generic as tegn_generic, warm_texts as tegn_texts
|
||||
|
||||
|
||||
@@ -32,7 +33,8 @@ class Command(BaseCommand):
|
||||
parser.add_argument("--budget", type=int, default=0, help="højst så mange nye tegn ud over de faste replikker")
|
||||
parser.add_argument("--reserve", type=int, default=40000,
|
||||
help="rør ikke de sidste så mange credits i perioden (de skal bruges til spil)")
|
||||
parser.add_argument("--only", choices=["fof", "tegn"], help="kun ét spil (fof = Fup og Fakta, tegn = Tegn og Gæt)")
|
||||
parser.add_argument("--only", choices=["fof", "tegn", "spion"],
|
||||
help="kun ét spil (fof = Fup og Fakta, tegn = Tegn og Gæt, spion = Spionen)")
|
||||
parser.add_argument("--dry-run", action="store_true",
|
||||
help="tæl klip og tegn uden at kalde ElevenLabs (virker også uden nøgle)")
|
||||
|
||||
@@ -43,14 +45,16 @@ class Command(BaseCommand):
|
||||
fest = settings.FEST_VOICE_ID or None
|
||||
# (navn, tekster, stemme). Tegn og Gæt (almindelig speaker) laves kun under --budget, først i køen,
|
||||
# så forvarmningen aldrig bruger af reserven; i --dry-run tælles de med her.
|
||||
tegn = tegn_texts() if only != "fof" else []
|
||||
tegn = tegn_texts() if only in (None, "tegn") else []
|
||||
spion = spion_texts() if only in (None, "spion") else [] # efter Tegn og Gæt i budget-køen
|
||||
# menuens intro pr. spil (standardstemmen, som /host/intro/<spil>); med --only kun det spils
|
||||
intros = [g.intro() for g in games.GAMES.values() if only in (None, g.key)]
|
||||
generic = self._generic(only, fest) # [(tekst, stemme)]: det rummene siger, når en replik ikke kan laves
|
||||
first = [("menuens intro-replikker", intros), ("Tegn og Gæt", tegn)]
|
||||
first = [("menuens intro-replikker", intros), ("Tegn og Gæt", tegn), ("Spionen", spion)]
|
||||
groups = [("menuens intro-replikker", intros, None)] if dry_run else []
|
||||
groups += [("faste Tegn og Gæt-replikker", tegn, None)] if tegn and dry_run else []
|
||||
if only != "tegn":
|
||||
groups += [("faste Spionen-replikker", spion, None)] if spion and dry_run else []
|
||||
if only in (None, "fof"):
|
||||
static = [line for k, variants in LINES.items() if not k.endswith("_fest")
|
||||
for line in variants if not re.search(r"\{\w+\}", line)]
|
||||
static += TEASES
|
||||
@@ -65,7 +69,7 @@ class Command(BaseCommand):
|
||||
fest_static = [t for t in fest_static if t not in set(static)]
|
||||
groups.append(("faste fest-replikker", fest_static, fest))
|
||||
if dry_run:
|
||||
# i budget-køens rækkefølge: intro, generiske (hver med sin stemme), Tegn og Gæt, Fup og Fakta's faste
|
||||
# i budget-køens rækkefølge: intro, generiske (hver med sin stemme), Tegn og Gæt, Spionen, Fup og Fakta's
|
||||
rows = [(name, [(t, voice) for t in texts]) for name, texts, voice in groups]
|
||||
rows.insert(1, ("generiske replikker", generic))
|
||||
for name, pairs in rows:
|
||||
@@ -73,7 +77,7 @@ class Command(BaseCommand):
|
||||
missing = [t for t, v in pairs if not tts.is_cached(t, v)]
|
||||
self.stdout.write(f"{name}: {len(texts)} klip, {sum(map(len, texts))} tegn; "
|
||||
f"mangler i cachen: {len(missing)} klip, {sum(map(len, missing))} tegn.")
|
||||
if budget > 0 and only != "tegn":
|
||||
if budget > 0 and only in (None, "fof"):
|
||||
self.stdout.write("Spørgsmål og kategori-replikker (--budget) tælles ikke i --dry-run.")
|
||||
return
|
||||
for name, texts, voice in groups:
|
||||
@@ -95,8 +99,8 @@ class Command(BaseCommand):
|
||||
if budget <= 0:
|
||||
return
|
||||
|
||||
queue = [(t, None) for t in intros] + generic + [(t, None) for t in tegn]
|
||||
queue += self._fof_queue(fest) if only != "tegn" else []
|
||||
queue = [(t, None) for t in intros] + generic + [(t, None) for t in tegn + spion]
|
||||
queue += self._fof_queue(fest) if only in (None, "fof") else []
|
||||
|
||||
spent = made = cached = 0
|
||||
for text, voice in queue:
|
||||
@@ -114,14 +118,16 @@ class Command(BaseCommand):
|
||||
|
||||
@staticmethod
|
||||
def _generic(only, fest) -> list[tuple[str, str | None]]:
|
||||
"""De generiske replikker for de valgte spil; de fælles (velkomst, antal) bruges af begge."""
|
||||
common = GENERIC_COMMON if only != "tegn" else { # fest findes kun i Fup og Fakta
|
||||
"""De generiske replikker for de valgte spil; de fælles (velkomst, antal) bruges af dem alle."""
|
||||
common = GENERIC_COMMON if only in (None, "fof") else { # fest findes kun i Fup og Fakta
|
||||
k: v for k, v in GENERIC_COMMON.items() if not k.endswith("_fest")}
|
||||
out = generic_texts(common, fest)
|
||||
if only != "tegn":
|
||||
if only in (None, "fof"):
|
||||
out += generic_texts(GENERIC, fest)
|
||||
if only != "fof":
|
||||
if only in (None, "tegn"):
|
||||
out += [(t, None) for t in tegn_generic()]
|
||||
if only in (None, "spion"):
|
||||
out += [(t, None) for t in spion_generic()]
|
||||
return list(dict.fromkeys(out))
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -181,7 +181,9 @@ class TtsWarmCommandTests(SimpleTestCase):
|
||||
|
||||
def test_budget_makes_intros_and_tegn_first_then_the_fof_queue(self):
|
||||
calls, voices, out = self.run_cmd("--budget", "100000", credits=10**6)
|
||||
self.assertEqual(calls, fof_static() + INTROS + generic() + warm_texts() + [t for t, _ in FOF_QUEUE])
|
||||
from party.spion import warm_texts as spion_texts
|
||||
want = fof_static() + INTROS + generic() + warm_texts() + spion_texts() + [t for t, _ in FOF_QUEUE]
|
||||
self.assertEqual(calls, list(dict.fromkeys(want))) # samme tekst i to spil er ét klip ("Temaet er Dyr.")
|
||||
self.assertEqual(voices, {None}) # samme stemme som rummet
|
||||
|
||||
def test_budget_stops_tegn_at_the_budget(self):
|
||||
@@ -247,3 +249,24 @@ class GenericWarmTests(SimpleTestCase):
|
||||
for ri in n.variants("reveal_intro"):
|
||||
for t in tegn.first_chain_generics(n, ri):
|
||||
self.assertIn((t, None), warm)
|
||||
|
||||
|
||||
class SpionWarmTests(SimpleTestCase):
|
||||
def test_only_spion_and_every_line_the_room_can_say(self):
|
||||
from party import spion
|
||||
from party.management.commands.tts_warm import Command
|
||||
warm = {t for t, _ in Command._generic("spion", None)} | set(spion.warm_texts())
|
||||
n = Narrator(lines=spion.LINES, generic=spion.GENERIC)
|
||||
for event, variants in spion.LINES.items():
|
||||
holders = {p for v in variants for p in re.findall(r"\{(\w+)\}", v)}
|
||||
if not holders:
|
||||
self.assertLessEqual(set(n.variants(event)), warm, event) # de faste er forvarmet
|
||||
else:
|
||||
for k in range(4, 11):
|
||||
for t in n.generic_variants(event, antal_spillere=k): # ellers er afløseren
|
||||
self.assertIn(t, warm, event)
|
||||
out = io.StringIO()
|
||||
with override_settings(ELEVENLABS_API_KEY=""):
|
||||
call_command("tts_warm", "--dry-run", "--only", "spion", stdout=out)
|
||||
self.assertIn(f"faste Spionen-replikker: {len(spion.warm_texts())} klip", out.getvalue())
|
||||
self.assertNotIn("Tegn og Gæt", out.getvalue())
|
||||
|
||||
Reference in New Issue
Block a user