multi-stage Dockerfile + player recap styles

Dockerfile: split into whisperx-base and runtime stages so app-only
changes skip the 10min pip install on rebuild. Example compose updated.

Player recap: replace hardcoded 'story so far' prompt with selectable
styles (story/diary/bullets/custom) via dropdown in Setup and Settings.

Settings: add NAT20_ONBOARDING_COMPLETED env var; fix merge logic so
env vars properly override defaults (not just empty DB values).
This commit is contained in:
KansaiGaijin
2026-07-10 16:25:52 +12:00
parent a261301638
commit babc0f58ef
9 changed files with 122 additions and 21 deletions

View File

@@ -52,12 +52,29 @@ Chunk summaries:
{summaries}
"""
PLAYER_FINAL_PROMPT = """Combine these chunk summaries into a single "previously on" style recap for the players, in-character perspective only.
PLAYER_FINAL_PROMPTS = {
"story": """Combine these chunk summaries into a single "previously on" style recap for the players, in-character perspective only.
Write it like a story recap they could reread before the next session. No GM secrets, no OOC content. Keep it engaging but concise.
Chunk summaries:
{summaries}
"""
""",
"diary": """Combine these chunk summaries into a "dear diary" style entry written from the collective party's first-person ("we") perspective.
Focus on the party's emotions, reactions, and personal reflections alongside the events.
No GM secrets, no OOC content.
Chunk summaries:
{summaries}
""",
"bullets": """Combine these chunk summaries into clean, scannable bullet points for the players.
Group related items under headers (Exploration, Combat, NPCs, Loot, Decisions).
Each bullet is one concise fact — no narrative fluff or transitions. No GM secrets, no OOC content.
Chunk summaries:
{summaries}
""",
}
def _call_ollama(host: str, model: str, prompt: str) -> str:
@@ -125,7 +142,9 @@ def make_llm_caller(settings: dict):
return lambda prompt: _call_ollama(host, model, prompt)
def summarize_session(turns: list[dict], settings: dict, progress_cb=None) -> tuple[str, str]:
def summarize_session(turns: list[dict], settings: dict, progress_cb=None,
player_recap_style: str | None = None,
player_recap_custom_prompt: str | None = None) -> tuple[str, str]:
call = make_llm_caller(settings)
ctx_path = settings.get("world_context_path") or ""
if ctx_path and Path(ctx_path).exists():
@@ -148,5 +167,13 @@ def summarize_session(turns: list[dict], settings: dict, progress_cb=None) -> tu
if progress_cb:
progress_cb("Writing final notes...")
dm_final = call(DM_FINAL_PROMPT.format(summaries="\n\n".join(dm_summaries)))
player_final = call(PLAYER_FINAL_PROMPT.format(summaries="\n\n".join(player_summaries)))
# Select player recap prompt based on style setting
style = (player_recap_style or settings.get("player_recap_style") or "story")
if style == "custom":
raw = (player_recap_custom_prompt or settings.get("player_recap_custom_prompt") or "").strip()
player_template = raw if raw else PLAYER_FINAL_PROMPTS["story"]
else:
player_template = PLAYER_FINAL_PROMPTS.get(style, PLAYER_FINAL_PROMPTS["story"])
player_final = call(player_template.format(summaries="\n\n".join(player_summaries)))
return dm_final, player_final