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

@@ -18,6 +18,8 @@ export interface AppSettings {
chunk_word_target: string;
world_context: string;
world_context_path: string;
player_recap_style: 'story' | 'diary' | 'bullets' | 'custom';
player_recap_custom_prompt: string;
}
export type JobStatus = 'queued' | 'running' | 'done' | 'error';

View File

@@ -62,6 +62,19 @@ export default function Settings() {
<input className="input w-full" value={settings.world_context_path} onChange={(e) => set("world_context_path", e.target.value)} placeholder="...or path to a file inside the container" />
</div>
<div className="card p-6 space-y-3 mb-6">
<h2 className="eyebrow">Player recap style</h2>
<select className="input w-full" value={settings.player_recap_style} onChange={(e) => set("player_recap_style", e.target.value)}>
<option value="story">Story Recap (previously on)</option>
<option value="diary">Dear Diary</option>
<option value="bullets">Bullet Points</option>
<option value="custom">Custom Prompt</option>
</select>
{settings.player_recap_style === "custom" && (
<textarea className="input w-full h-32" value={settings.player_recap_custom_prompt} onChange={(e) => set("player_recap_custom_prompt", e.target.value)} placeholder="Write your own final-combine prompt. Use {'{summaries}'} where the chunk summaries should be inserted." />
)}
</div>
<button className="btn-primary" onClick={save}>{saved ? "Saved" : "Save settings"}</button>
</div>
);

View File

@@ -15,6 +15,8 @@ const DEFAULT_SETTINGS: AppSettings = {
chunk_word_target: '2500',
world_context: '',
world_context_path: '',
player_recap_style: 'story',
player_recap_custom_prompt: '',
};
export default function Setup({ onComplete }: { onComplete: () => void }) {
@@ -189,6 +191,28 @@ export default function Setup({ onComplete }: { onComplete: () => void }) {
/>
</div>
<div className="border-t border-slate-700 pt-4 space-y-3">
<h3 className="text-sm font-semibold text-slate-300">Player recap style</h3>
<select
value={settings.player_recap_style}
onChange={e => setSettings({ ...settings, player_recap_style: e.target.value as AppSettings['player_recap_style'] })}
className="w-full bg-slate-900 border border-slate-700 rounded px-3 py-2"
>
<option value="story">Story Recap (previously on)</option>
<option value="diary">Dear Diary</option>
<option value="bullets">Bullet Points</option>
<option value="custom">Custom Prompt</option>
</select>
{settings.player_recap_style === 'custom' && (
<textarea
className="w-full bg-slate-900 border border-slate-700 rounded px-3 py-2 h-24 font-mono text-sm"
placeholder="Write your own final-combine prompt. Use {summaries} where the chunk summaries should be inserted."
value={settings.player_recap_custom_prompt}
onChange={e => setSettings({ ...settings, player_recap_custom_prompt: e.target.value })}
/>
)}
</div>
<div className="flex justify-between pt-4 border-t border-slate-700">
<button onClick={handleBack} className="bg-slate-700 hover:bg-slate-600 text-white px-5 py-2 rounded font-medium">
Back