ChristophSchuhmann's picture
Publish study artifacts 1-150 of 1487
2219798 verified
Raw History Blame Contribute Delete
4.12 kB
"""Luna writes both words and direction; manual prompts bypass the director."""
import json
import time
import httpx
import settings
from actor_prompt import SYSTEM
class Director:
def __init__(self):
self.client = httpx.AsyncClient(timeout=httpx.Timeout(30, connect=10))
async def close(self):
await self.client.aclose()
async def direct(self, message, fmt, language, mode, history):
key = settings.luna_key()
if not key:
raise ValueError("Luna API-Key fehlt. Manuellen Prompt verwenden oder SMALL_LUNA_API_KEY konfigurieren.")
context = [{"role": "system", "content": SYSTEM}]
for item in history[-16:]:
if item.get("role") in {"user", "assistant"} and isinstance(item.get("content"), str):
context.append({"role": item["role"], "content": item["content"][:3000]})
task = ("The entire input below is fixed spoken text. Perform these words EXACTLY, without any extra words."
if mode == "perform" else
"Answer conversationally, or actually enact the user's acting brief. Interpret the scene; do not echo the assignment or describe your performance. Preserve words explicitly supplied to be spoken.")
context.append({"role": "user", "content": f"Format: {fmt}. Spoken language: {language}. {task}\n{message}"})
started = time.monotonic()
for attempt in range(2):
try:
response = await self.client.post(settings.LUNA_BASE.rstrip("/") + "/v1/chat/completions",
headers={"Authorization": f"Bearer {key}"},
json={"model": settings.LUNA_MODEL, "messages": context,
"reasoning_effort": "none", "max_completion_tokens": 2400,
"response_format": {"type": "json_object"}})
except httpx.TimeoutException as exc:
raise RuntimeError("Luna hat nicht rechtzeitig geantwortet. Bitte erneut senden oder einen manuellen Prompt verwenden.") from exc
except httpx.RequestError as exc:
raise RuntimeError("Luna API ist momentan nicht erreichbar. Bitte erneut versuchen.") from exc
if response.status_code >= 400:
raise RuntimeError(f"Luna API antwortet mit HTTP {response.status_code}.")
raw = response.json()["choices"][0]["message"].get("content") or ""
try:
result = json.loads(raw)
if not all(k in result for k in ("text", "general", "script", "caption", "tags", "language")):
raise ValueError("Unvollständige Regie-Antwort")
if not all(isinstance(result[k], str) for k in ("text", "general", "script", "caption", "language")) or not isinstance(result["tags"], list) or not all(isinstance(tag, str) for tag in result["tags"]):
raise ValueError("Ungültige Regie-Antwort")
from prompting import plain_script
spoken = plain_script(result["script"]) if fmt == "structured" else " ".join(result["text"].split())
if not spoken:
raise ValueError("Leeres gesprochenes Skript")
if mode == "perform" and spoken != " ".join(message.split()):
raise ValueError("Luna hat die vorgegebenen Worte geändert")
# As in the existing demo, SCRIPT is authoritative for chat.
# A duplicate text field drifting in punctuation must not
# reject an otherwise valid acting script.
result["text"] = spoken
return result, round((time.monotonic() - started) * 1000)
except (ValueError, TypeError):
if attempt:
raise ValueError("Luna lieferte zweimal keine gültige, wortgetreue Regie. Bitte erneut versuchen.")
context.append({"role": "assistant", "content": raw[:5000]})
context.append({"role": "user", "content": "Correct the JSON. Keep text and spoken script identical; preserve any exact requested transcript."})