Speakerens manuskript: 170 replikker til 28 begivenheder
CI / test (push) Successful in 16s

Klar til oplæsning med ElevenLabs. En test håndhæver reglerne fra
manuskript-prompten: tilladte pladsholdere og lyd-tags pr. begivenhed,
højst 20 ord, ingen tankestreger og tal skrevet med bogstaver.

Claude-Session: https://claude.ai/code/session_01JmhJG6JnhXfzNiKv8f2vHu
This commit is contained in:
agw
2026-10-01 21:54:37 +02:00
parent ec9758ada0
commit 2d75c4ce5a
2 changed files with 276 additions and 0 deletions
+228
View File
@@ -0,0 +1,228 @@
{
"lobby_welcome": [
"Velkommen til Fup og Fakta. Find telefonen frem. Samvittigheden kan blive i lommen.",
"Her må du lyve. Vi har endda lavet en pointtavle til det.",
"Velkommen. Her bliver familiehistorier endelig vurderet efter, hvor godt de snyder.",
"[excited] Fup og Fakta! Find telefonen frem. Jeg har allerede gjort sandheden nervøs.",
"Et spil om sandhed og løgn. Altså en familiefest med lidt tydeligere regler."
],
"lobby_join": [
"{navn} er med. Så har vi en mere at stole lidt for meget på.",
"Velkommen, {navn}. Jeg stoler på dig. Det plejer at gå galt.",
"Der kom {navn}. Endnu et navn til min kommende samling af bortforklaringer.",
"{navn}, dejligt. Jeg skriver dig på listen over mistænkeligt hyggelige mennesker.",
"[suspicious] {navn} er med. Den tavshed tager jeg som en tilståelse.",
"Plads til {navn}. Telefonen er nu officielt et redskab til familieintriger.",
"{navn}, du kom præcis i tide til at tage fejl sammen med os.",
"[impressed] {navn} fandt ind. Første opgave løst. Desværre giver den ingen point.",
"Nu er {navn} her. Så kan vi snart få sandheden nedstemt.",
"{navn}, sæt dig godt. Dine forklaringer kommer til at stå på egne ben."
],
"lobby_waiting": [
"{vip}, når du er klar, kan vi begynde. Jeg har løgne, der skal luftes.",
"Hvis vi venter længere, {vip}, bliver mine løgne til gamle familiehistorier.",
"{vip}, giv os et tegn. Helst startknappen. Røgsignaler virker dårligt i stuen.",
"Jeg er klar, {vip}. Det siger jeg også før møder. Her mener jeg det.",
"[whispers] {vip}, jeg har snart brugt min eneste replik om vejret."
],
"game_start": [
"{antal_spillere} spillere og én sandhed. Det bliver en helt almindelig familiefest.",
"{antal_spillere} spillere. Gæt sandheden, og nar de andre. Begge dele giver point.",
"{antal_spillere} spillere. Tilliden i sofaen skal nu testes med helt frivillige løgne.",
"[excited] Vi er i gang! {antal_spillere} spillere, samlet om noget mistænkeligt. Helt lovligt.",
"{antal_spillere} spillere. Point for sandheden og gode løgne. Familiefortælleren får endelig lidt anerkendelse."
],
"round1_intro": [
"Første runde. Almindelige point, ualmindeligt tvivlsomme forklaringer.",
"Vi begynder med normale point. Se det som en høflig prøve på familiens tillid.",
"Runde ét. Pointene er normale. Det er resten af det her sjældent.",
"Første runde, normale point. Jeg starter med fuld tillid. Det plejer at være en kort fornøjelse.",
"Vi starter stille med normale point. I får rigelig mulighed for at råbe senere."
],
"round2_intro": [
"Nu giver vi dobbelt point. {foerende}, din føring får brug for en sikkerhedssele.",
"Runde to, dobbelt point. Nu får selv en lille løgn lidt vokseværk.",
"Vi fordobler pointene. {foerende} fører, men sofaen har endnu ikke kronet nogen.",
"Dobbelt point! Nu er det dyrere at stole på familie og venner.",
"[excited] Runde to giver dobbelt point. Jeg føler mig allerede dobbelt så vigtig."
],
"final_intro": [
"Finale med tredobbelt point. {foerende} fører, men ingen har fået lov at holde takketale.",
"{sidst}, nu giver vi tredobbelt point. Tid til at pynte på regnskabet.",
"{foerende}, finalen giver tredobbelt point. Føringer tæller bedst, når de holder hele vejen.",
"[dramatic] Tredobbelt point i finalen. Nu kan en mavefornemmelse flytte rundt på hele stillingen.",
"Sidste runde. Tre gange pointene. Jeg har allerede øvet min overraskede stemme."
],
"category_choose": [
"{navn}, vælg en kategori. Gerne noget, du kan lyve selvsikkert om.",
"Valget er dit, {navn}. Hele sofaen får naturligvis lov at brokke sig bagefter.",
"Hvad skal vi høre om, {navn}? Du har ordet. Jeg beholder opmærksomheden.",
"{navn}, peg på en kategori. Her er mavefornemmelsen faktisk kvalificeret.",
"{navn}, hvilken kategori? Du behøver kun vælge én. Gem resten til ønskesedlen."
],
"category_timeout": [
"{navn} tog betænkningstid. Vi tog {kategori}. Så kom der da en beslutning.",
"Det blev {kategori}. {navn}, stilhed er åbenbart også en måde at vælge på.",
"[sighs] {navn}, tiden løb. Nu hedder kategorien {kategori}. Den kunne heldigvis beslutte sig.",
"{kategori} er valgt. {navn}, vi kalder det delegering. Det lyder pænere.",
"{navn}, universet har valgt {kategori}. Universet arbejder åbenbart hurtigere end vores familie."
],
"lie_start": [
"Nu gælder det {kategori}. Skriv en løgn, der kunne få sit eget leksikonopslag.",
"{kategori}. Skriv en løgn, der føles som noget, man har hørt før.",
"Skriv en løgn om {kategori}. Giv den en parkeringsvagts selvtillid.",
"{kategori} er emnet. Skriv noget opdigtet. Hunden har lovet at tage skylden.",
"Opfind et svar om {kategori}. En lille detalje kan gøre løgnen stor.",
"Vi skal digte om {kategori}. Gør gerne løgnen kedelig. Det virker overraskende godt.",
"[mischievously] Nu handler det om {kategori}. Skriv en løgn, du kunne sige helt alvorligt.",
"Skriv en løgn om {kategori}. Husets dårlige ry kan godt bruge hjælp.",
"{kategori}. Opfind et svar, som selv familiens skeptiker kunne købe.",
"{kategori}. Skriv en troværdig løgn. Du må gerne rette stavefejl i virkeligheden."
],
"lie_hurry": [
"Ti sekunder. En lille løgn er bedre end en stor tænkepause.",
"Ti sekunder tilbage. Afsted med løgnen. Den behøver kun overleve ét spørgsmål.",
"Der er ti sekunder. Giv fantasien albuer, og send noget afsted.",
"Ti sekunder! Selv en halvbagt løgn kan serveres med overbevisning.",
"Kun ti sekunder. Din indre forfatter må godt springe korrekturen over."
],
"lie_all_done": [
"Alle løgne er afleveret. Sikke vi kan arbejde, når sandheden bliver valgfri.",
"Alle har skrevet. Jeg gemmer bunken til næste gang, nogen kalder sig ærlige.",
"Nu har vi alle løgnene. Det er som et familiereferat, bare hurtigere.",
"[impressed] Alle er færdige. Sikke et samarbejde om at gøre hinanden mistænksomme.",
"Tak for løgnene. Det er en hilsen, jeg sjældent bruger hos bageren."
],
"lie_was_truth": [
"Det var faktisk sandheden. Prøv igen, med lidt mindre ærlighed.",
"Sandheden kom ind ad bagdøren. Send den ud igen, og skriv en løgn.",
"[impressed] Nogen har skrevet sandheden. Så ved vi i det mindste, at den findes.",
"Det svar var sandt. En sjælden tastefejl. Prøv med en løgn.",
"Du ramte sandheden. Gem den slags talenter til gættefasen."
],
"guess_start": [
"Find sandheden. Den har klædt sig ud som endnu en dårlig idé.",
"Vælg det sande svar. Selvtillid er desværre en dårlig kildehenvisning.",
"Nu skal I gætte sandheden. Tænk efter, før familieanekdoterne tager over.",
"Hvilket svar er sandt? Lad maven bestemme. Den træffer jo allerede aftensmadsbeslutninger.",
"Vælg sandheden. Mine løgne er også med. De er lavet med kærlighed.",
"Find det rigtige svar. Virkeligheden har en ret løs opfattelse af, hvad der er rimeligt.",
"Ét af svarene passer. Vælg det. Resten sælger vi på næste loppemarked.",
"Vælg sandheden. Publikum gætter med. Nu kan endnu flere blande sig.",
"Find sandheden, og giv gerne sjove løgne et hjerte. Også bedragere har følelser.",
"[suspicious] Ét svar er sandt. Vælg med omhu. De andre har bare øvet sig."
],
"guess_hurry": [
"Fem sekunder. Vælg et svar. Det hjælper sjældent at stirre vredt på telefonen.",
"Fem sekunder tilbage. Din mavefornemmelse har nu sidste ord.",
"Der er fem sekunder. Tvivlen får desværre ingen point.",
"Fem sekunder! Vælg et svar, før din store overvejelse bliver en meget lille aflevering.",
"Kun fem sekunder. Sandheden venter. Den er åbenbart bedre opdraget end mig."
],
"reveal_lie_fooled": [
"{forfatter} opfandt {svar}. {ofre} købte den. Kvitteringen er desværre forsvundet.",
"{ofre} faldt for {svar}. {forfatter}, din fantasi har nu fået selskab.",
"Det var {forfatter}, der fandt på {svar}. {ofre} blev dagens forsøgskaniner.",
"[chuckles] {svar} var en løgn fra {forfatter}. Tak for støtten, {ofre}.",
"{forfatter} skrev {svar}, og {ofre} tog imod. Meget høfligt. Meget forkert.",
"{svar} kom fra {forfatter}. {ofre} lod sig overbevise. Selvtilliden fik åbenbart ordet først.",
"{ofre} troede på {svar}. {forfatter} har lige bevist, at en god historie kan springe køen over.",
"{forfatter}, {svar} virkede på {ofre}. Den løgn slap godt fra middagsbordet.",
"{svar}, sagde {forfatter}. Ja tak, sagde {ofre}. Og sådan fik fantasien sin belønning.",
"{svar} var en løgn fra {forfatter}. {ofre}, det bliver mellem os og hele stuen."
],
"reveal_lie_fooled_many": [
"{antal} troede på {svar}. {forfatter}, du har nok til at stifte en forening.",
"{forfatter} fik {antal} til at vælge {svar}. Sofaen har dannet fælles front mod fakta.",
"[impressed] {svar} narrede {antal}. {forfatter}, jeg bøjer mig. Mest for at gemme min jalousi.",
"{antal} hoppede på {svar}. {forfatter}, du kan starte en bølge uden at rejse dig.",
"{svar} narrede {antal}. {forfatter}, din fantasi har flere tilhængere end min madplan."
],
"reveal_lie_shared": [
"{forfattere} skrev begge {svar}. To hjerner, én fælles omvej.",
"{forfattere} leverede {svar}. To løgnere for én. Det kan tilbudsavisen lide.",
"{forfattere} fandt på {svar}. Samme løgn. Fantasien må have en kopimaskine.",
"{svar}, fra {forfattere}. En løgn med to underskrifter. Næsten klar til kommunen.",
"[suspicious] {forfattere} skrev {svar}. Jeg siger bare, at telepati burde stå i reglerne."
],
"reveal_house_lie": [
"{svar} var min løgn. Tak, {ofre}. Dejligt, at kunst bliver værdsat.",
"[mischievously] {ofre} valgte {svar}. Husets løgn. Jeg modtager gerne stående bifald fra sofaen.",
"Jeg opfandt {svar}. {ofre} troede på den. Det kalder jeg godt samarbejde.",
"{ofre}, {svar} var min. Så ved vi, hvem der bestemmer over rygterne.",
"{ofre} købte {svar}. Min opskrift. Tillid er åbenbart den hemmelige ingrediens.",
"{svar} kom fra huset. {ofre}, den forklaring kan give næste middag ekstra samtalestof.",
"{ofre} troede på {svar}. Jeg skrev den helt uden hjælp fra virkeligheden.",
"Min løgn var {svar}. {ofre}, jeg kan mærke min dårlige samvittighed tage fri.",
"{svar} snød {ofre}. Den var min. Jeg øver lige mit ydmyge nik.",
"Huset opfandt {svar}. {ofre} faldt for den. Så sparede vi penge på specialeffekter."
],
"reveal_truth_found": [
"Sandheden er {sandhed}. {navne} fandt den. Så fik virkeligheden lidt opbakning.",
"{navne} valgte sandheden, {sandhed}. Gem lige øjeblikket til næste familiediskussion.",
"[impressed] Svaret er {sandhed}. {navne} gennemskuede os. Irriterende godt arbejde.",
"{sandhed}, det er sandheden. {navne} ramte rigtigt. Meget upraktisk for løgnerne.",
"{sandhed} er svaret. {navne} har tilladelse til ét lille, bedrevidende nik.",
"{navne} ramte rigtigt med {sandhed}. Nogen har åbenbart læst bagsiden af mælkekartonen.",
"Sandheden var {sandhed}. Godt fanget, {navne}. Den viden fortjente sin egen fest.",
"{navne} valgte {sandhed}. Korrekt. Skepsissen kan lige lægge benene op.",
"{navne} fandt sandheden, {sandhed}. Mavefornemmelsen har lige fået en lønforhøjelse.",
"Svaret er {sandhed}. Point til {navne}. Jeg vidste det selvfølgelig også. Næsten."
],
"reveal_truth_nobody": [
"Svaret var {sandhed}. Ingen fandt det. Vi lader som om, det her var opvarmning.",
"Sandheden var {sandhed}. Hele sofaen tog fejl. Sikke en sjælden form for enighed.",
"[sighs] Sandheden var {sandhed}. Den stod lige der. Jeg giver virkeligheden et trøstende kram.",
"Ingen valgte {sandhed}. Det var ellers sandheden. Den må arbejde lidt på sin troværdighed.",
"Sandheden var {sandhed}. Ingen fandt den. Jeg havde ellers væddet min sidste småkage på jer."
],
"reveal_truth_everyone": [
"Svaret var {sandhed}. Alle fandt det. Jeg får åbenbart brug for bedre løgne.",
"Sandheden var {sandhed}. Enighed i sofaen. Nogen burde tage et billede.",
"[impressed] Alle valgte {sandhed}. Korrekt. Det her bliver svært at forklare som held.",
"{sandhed} var sandheden. Alle ramte rigtigt. Jeg havde ellers reserveret tid til en forklaring.",
"Alle fandt sandheden, {sandhed}. Pointtavlen bliver lige så spændende som fælles opvask."
],
"scores_intro": [
"{foerende} fører, og {sidst} ligger sidst. Pointtavlen har åbenbart fået holdninger.",
"{foerende} fører. Jubel med omtanke. Der skal stadig være plads til alle i sofaen.",
"{foerende} øverst, {sidst} nederst. Klager modtages på en serviet efter middagen.",
"{foerende} ligger først, {sidst} sidst. Jeg kontrollerede tallene med et ansvarligt nik.",
"Pointtavlen er klar. {foerende} fører. Dejligt med tal. De afbryder mig sjældent."
],
"winner": [
"{vinder} vinder med {point} point. Det skal sofaen nok høre om igen.",
"[cheering] Tillykke, {vinder}! {point} point. Æren er din. Fjernbetjeningen kræver stadig en forhandling.",
"Sejren går til {vinder}, med {point} point. Takketalen må gerne indeholde noget sandt.",
"Med {point} point vinder {vinder}. Min oplæring har tydeligvis været fuldstændig afgørende.",
"{vinder} vinder med {point} point. Præmiebudgettet gik desværre til mit meget velfortjente honorar."
],
"award_biggest_liar": [
"Største løgner, {navn}. {antal} vellykkede bedrag. Prisen overrækkes med et mistænksomt håndtryk.",
"{navn} er største løgner, med {antal} vellykkede bedrag. Tillid kan åbenbart genbruges.",
"{navn} narrede andre {antal} gange. Største løgner! Vi springer forklaringen over.",
"[impressed] Største løgner er {navn}. {antal} gange blev nogen narret. Din fantasi har fået faste kunder.",
"{antal} vellykkede bedrag. Prisen for største løgner går til {navn}. Pokalen er ægte. Tror jeg."
],
"award_truth_seeker": [
"{navn} er sandhedsjæger med {antal} rigtige gæt. En meget irriterende person at diskutere med.",
"Flest rigtige gæt, {navn}, med {antal}. Virkeligheden har åbenbart fået sin egen rådgiver.",
"Sandhedsprisen går til {navn}. {antal} rigtige gæt. Endelig kom den mærkelige viden til nytte.",
"{navn} fandt sandheden {antal} gange. Vi springer høfligt diskussionen om held over.",
"{navn} er sandhedsjæger. {antal} rigtige gæt. Den titel har vi faktisk undersøgt, før vi fandt på den."
],
"award_most_liked": [
"Hjerteprisen går til {navn}, med {antal}. Løgn med charme er åbenbart en disciplin.",
"{antal} hjerter til {navn}. Sofaens yndling. Blomsterhandleren har lige mistet en kunde.",
"{navn} får hjerteprisen med {antal}. Anbefalingen bliver mærkelig. Lyver virkelig underholdende.",
"[cheering] Flest hjerter, {navn}, med {antal}. Vi har målt din morsomhed med tommelfingre.",
"{navn} vandt {antal} hjerter. Sjældent har en bunke løgne fået så varm en modtagelse."
],
"play_again": [
"En omgang mere! Vi nulstiller pointene. Mistanken gemmer familien selv.",
"I vil spille igen. Det tager jeg som ros og et meget svagt ønske om sandhed.",
"[excited] Så tager vi en til. Nye løgne, samme sofa. Den har efterhånden hørt lidt af hvert.",
"Vi spiller igen. Jeg henter flere fakta. I kan bare genbruge jeres selvtillid.",
"En ny omgang. Jeg er glad for tilliden. Især fordi jeg tydeligvis ikke har fortjent den."
]
}
+48
View File
@@ -0,0 +1,48 @@
"""Speakerens replikker (fupogfakta/narrator/lines.json) skal overholde manuskriptreglerne."""
import json
import re
from pathlib import Path
from django.test import SimpleTestCase
LINES = Path(__file__).resolve().parents[1] / "narrator" / "lines.json"
# begivenhed -> tilladte pladsholdere (samme tabel som i prompten til manuskriptet)
EVENTS = {
"lobby_welcome": set(), "lobby_join": {"navn"}, "lobby_waiting": {"vip"},
"game_start": {"antal_spillere"}, "round1_intro": set(), "round2_intro": {"foerende"},
"final_intro": {"foerende", "sidst"}, "category_choose": {"navn"}, "category_timeout": {"navn", "kategori"},
"lie_start": {"kategori"}, "lie_hurry": set(), "lie_all_done": set(), "lie_was_truth": set(),
"guess_start": set(), "guess_hurry": set(),
"reveal_lie_fooled": {"svar", "forfatter", "ofre"}, "reveal_lie_fooled_many": {"svar", "forfatter", "antal"},
"reveal_lie_shared": {"svar", "forfattere"}, "reveal_house_lie": {"svar", "ofre"},
"reveal_truth_found": {"sandhed", "navne"}, "reveal_truth_nobody": {"sandhed"},
"reveal_truth_everyone": {"sandhed"}, "scores_intro": {"foerende", "sidst"},
"winner": {"vinder", "point"}, "award_biggest_liar": {"navn", "antal"},
"award_truth_seeker": {"navn", "antal"}, "award_most_liked": {"navn", "antal"}, "play_again": set(),
}
TAGS = {"laughs", "chuckles", "sighs", "whispers", "excited", "sarcastic", "dramatic", "pause",
"mischievously", "impressed", "disappointed", "suspicious", "cheering"}
class NarratorLinesTests(SimpleTestCase):
def setUp(self):
self.lines = json.loads(LINES.read_text(encoding="utf-8"))
def test_all_events_present_with_variants(self):
self.assertEqual(set(self.lines), set(EVENTS))
for event, variants in self.lines.items():
self.assertGreaterEqual(len(variants), 5, event)
self.assertEqual(len(variants), len(set(variants)), f"dubletter i {event}")
def test_placeholders_tags_and_style(self):
for event, variants in self.lines.items():
for line in variants:
with self.subTest(event=event, line=line):
self.assertLessEqual(set(re.findall(r"\{(\w+)\}", line)), EVENTS[event])
self.assertLessEqual(set(re.findall(r"\[([a-z ]+)\]", line)), TAGS)
spoken = re.sub(r"\[[a-z ]+\]", "", line)
self.assertLessEqual(len(spoken.split()), 20)
self.assertNotRegex(line, r"—|–| - ", "ingen tankestreger")
self.assertNotRegex(line, r"\d", "tal skrives med bogstaver")