feat: add CW-026 Local Voice plugin

This commit is contained in:
Bryan Gilliom
2026-07-27 00:33:25 +08:00
commit 5d680928b9
29 changed files with 2697 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
Three warning lights all trace back to one loose connector. That is not three failures; it is one design flaw wearing three different hats.
Replace the connector, document the root cause, and stop blaming the operator for what the hardware did.
Fix the system once... and that is pretty cool.
+5
View File
@@ -0,0 +1,5 @@
Good morning. Overnight, the service team closed the kiosk alert and confirmed the replacement controller is stable.
One decision remains: approve the revised field schedule before noon so the Monday installation stays on track.
That is the whole story. Handle the schedule, then enjoy the quiet.
+5
View File
@@ -0,0 +1,5 @@
Morning. We have one little weather problem parked on the runway.
The supplier missed the shipment, the field crew is waiting, and somebody scheduled the backup truck for the wrong county. Find the truck before I have to drop the sun on the dispatch board.
That is all. Now get out of my briefing room before something starts leaking hydraulic fluid.
+9
View File
@@ -0,0 +1,9 @@
**PRODUCER GUY:** So, you have a Monday briefing for me?
**WRITER GUY:** Yes sir, I do! The Phoenix hardware shipped, but the final quantity approval is still missing!
**PRODUCER GUY:** Oh, paperwork blocking shipped hardware is tight!
**PRODUCER GUY:** Is it going to be hard to clear that before noon?
**WRITER GUY:** Actually, it's gonna be super easy, barely an inconvenience! Oh, really?
+7
View File
@@ -0,0 +1,7 @@
Morning, Tracy.
The Phoenix installation is ready, but the final quantity approval remains unsigned. The hardware is already moving, so paperwork is the only gentleman still blocking the road.
The engineering team settled yesterday's controller affair and documented the root cause. A clean ending, for once.
Sign the quantity approval before noon. Say when.
+181
View File
@@ -0,0 +1,181 @@
#!/usr/bin/env python3
"""Create and optionally render fresh Local Voice acceptance plans."""
from __future__ import annotations
import argparse
import json
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
RENDERER = ROOT / "scripts" / "local_voice.py"
CASES = (
"donna",
"chris-engineer",
"grandpa-bomber",
"val-holiday",
"ryan-pitch-meeting",
)
def run(command: list[str]) -> None:
subprocess.run(command, check=True)
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--runtime-root", required=True, type=Path)
parser.add_argument("--output-dir", required=True, type=Path)
parser.add_argument("--device", choices=("metal", "cpu", "cuda"), default="metal")
parser.add_argument("--render", action="store_true")
parser.add_argument(
"--voices",
help="Comma-separated subset of profile IDs; defaults to every case.",
)
args = parser.parse_args()
args.output_dir.mkdir(parents=True, exist_ok=True)
selected_cases = (
tuple(item.strip() for item in args.voices.split(",") if item.strip())
if args.voices
else CASES
)
unknown = sorted(set(selected_cases) - set(CASES))
if unknown:
parser.error("Unknown acceptance voice(s): " + ", ".join(unknown))
results = []
for voice in selected_cases:
script = ROOT / "tests" / "acceptance" / f"{voice}.md"
plan = args.output_dir / f"{voice}.json"
audio = args.output_dir / f"{voice}.mp3"
job_id = f"acceptance-v9-{voice}"
run(
[
sys.executable,
str(RENDERER),
"plan",
"--voice",
voice,
"--script",
str(script),
"--output-plan",
str(plan),
"--output-audio",
str(audio),
"--job-id",
job_id,
]
)
if voice == "ryan-pitch-meeting":
data = json.loads(plan.read_text(encoding="utf-8"))
data["segments"] = [
{
"id": "01-producer",
"role": "producer",
"text": "So, you have a Monday briefing for me?",
"context_after": "Yes sir, I do!",
"pause_after_ms": 95,
},
{
"id": "02-yes-sir",
"role": "writer",
"text": "Yes sir, I do!",
"fixed_asset": (
"voices/ryan-pitch-meeting/signature-exchanges/"
"yes-sir-i-do/lotr_two_towers.wav"
),
"pause_after_ms": 55,
},
{
"id": "03-writer",
"role": "writer",
"text": (
"The Phoenix hardware shipped, but the final quantity "
"approval is still missing!"
),
"context_before": "Yes sir, I do!",
"context_after": (
"Oh, paperwork blocking shipped hardware is tight!"
),
"pause_after_ms": 95,
},
{
"id": "04-tight",
"role": "producer",
"text": "Oh, paperwork blocking shipped hardware is tight!",
"tts_text": "Oh, paperwork blocking shipped hardware",
"context_before": (
"The final quantity approval is still missing!"
),
"context_after": "It sure is!",
"suffix_asset": (
"voices/ryan-pitch-meeting/signature-exchanges/"
"tight-endings/is/disclosure.wav"
),
"suffix_gap_ms": 130,
"pause_after_ms": 95,
},
{
"id": "05-producer",
"role": "producer",
"text": (
"Is it going to be hard to clear that before noon?"
),
"context_before": (
"Oh, paperwork blocking shipped hardware is tight!"
),
"context_after": (
"Actually, it's gonna be super easy, barely an "
"inconvenience! Oh, really?"
),
"pause_after_ms": 95,
},
{
"id": "06-super-easy",
"role": "writer",
"text": (
"Actually, it's gonna be super easy, barely an "
"inconvenience! Oh, really?"
),
"fixed_asset": (
"voices/ryan-pitch-meeting/signature-exchanges/"
"super_easy_oh_really.wav"
),
"pause_after_ms": 95,
},
]
plan.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
run([sys.executable, str(RENDERER), "validate", str(plan)])
if args.render:
run(
[
sys.executable,
str(RENDERER),
"render",
str(plan),
"--runtime-root",
str(args.runtime_root),
"--device",
args.device,
"--resume",
]
)
results.append({"voice": voice, "plan": str(plan), "audio": str(audio)})
summary = args.output_dir / "acceptance-summary.json"
existing = []
if summary.exists():
existing = json.loads(summary.read_text(encoding="utf-8"))
merged = {item["voice"]: item for item in existing}
merged.update({item["voice"]: item for item in results})
summary.write_text(
json.dumps([merged[key] for key in sorted(merged)], indent=2) + "\n",
encoding="utf-8",
)
print(f"Acceptance summary: {summary}")
return 0
if __name__ == "__main__":
raise SystemExit(main())