working through the plan + UI/ UX
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
import { parseLlmJson, ensureArray, flattenValue } from "../lib/llm-parse";
|
||||
import { useState } from "react";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { addToLore } from "../lib/lore";
|
||||
import { useToast } from "./Toast";
|
||||
import { addGeneration, extractTitle, type Generation } from "../lib/generations";
|
||||
import { usePrefillEffect } from "../lib/usePrefill";
|
||||
|
||||
interface WorldResponse {
|
||||
name: string;
|
||||
@@ -11,11 +15,25 @@ interface WorldResponse {
|
||||
cultures: string[];
|
||||
}
|
||||
|
||||
export function WorldBuilder() {
|
||||
interface Props {
|
||||
prefill?: Generation | null;
|
||||
onPrefillConsumed?: () => void;
|
||||
}
|
||||
|
||||
export function WorldBuilder({ prefill, onPrefillConsumed }: Props = {}) {
|
||||
const [theme, setTheme] = useState("high fantasy");
|
||||
const [world, setWorld] = useState<WorldResponse | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const { addToast } = useToast();
|
||||
|
||||
usePrefillEffect(prefill ?? null, "world", () => onPrefillConsumed?.(), (g) => {
|
||||
const parsed = parseLlmJson<WorldResponse>(g.data);
|
||||
if (parsed) {
|
||||
setWorld(parsed);
|
||||
addToast(`Loaded "${g.title}" from history`, "info");
|
||||
}
|
||||
});
|
||||
|
||||
async function generate() {
|
||||
setLoading(true);
|
||||
@@ -38,16 +56,31 @@ IMPORTANT: Return ONLY a raw JSON object. NO markdown fences, NO code blocks, NO
|
||||
system: "You are a creative world-building DM. You MUST respond with ONLY valid JSON. No markdown fences, no code blocks, no explanation. Just the JSON object.",
|
||||
temperature: 0.9,
|
||||
max_tokens: 600,
|
||||
ragQuery: `fantasy world ${theme} regions landmarks cultures`,
|
||||
},
|
||||
});
|
||||
const parsed = parseLlmJson<WorldResponse>(result);
|
||||
if (parsed) {
|
||||
setWorld(parsed);
|
||||
addToast("World generated", "success");
|
||||
const title = extractTitle("world", result, theme);
|
||||
const source = `Theme: ${theme}`;
|
||||
void addGeneration({ kind: "world", title, data: result, source });
|
||||
const regions = ensureArray(parsed.regions).map(flattenValue).join("; ");
|
||||
const landmarks = ensureArray(parsed.landmarks).map(flattenValue).join("; ");
|
||||
const conflicts = ensureArray(parsed.conflicts).map(flattenValue).join("; ");
|
||||
const cultures = ensureArray(parsed.cultures).map(flattenValue).join("; ");
|
||||
void addToLore(
|
||||
`World: ${parsed.name || theme}`,
|
||||
`${parsed.name || "World"} (${theme}). ${parsed.description}\nRegions: ${regions}\nLandmarks: ${landmarks}\nConflicts: ${conflicts}\nCultures: ${cultures}`,
|
||||
);
|
||||
} else {
|
||||
setError("Could not parse LLM response. Try again or check your LLM connection.");
|
||||
addToast("LLM returned an unparseable response", "error");
|
||||
}
|
||||
} catch (e) {
|
||||
setError(String(e));
|
||||
addToast(`World generation failed: ${e}`, "error");
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -122,7 +155,7 @@ IMPORTANT: Return ONLY a raw JSON object. NO markdown fences, NO code blocks, NO
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)})
|
||||
)}
|
||||
|
||||
{/* Conflicts */}
|
||||
{world.conflicts?.length > 0 && (
|
||||
@@ -138,7 +171,7 @@ IMPORTANT: Return ONLY a raw JSON object. NO markdown fences, NO code blocks, NO
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)})
|
||||
)}
|
||||
|
||||
{/* Cultures */}
|
||||
{world.cultures?.length > 0 && (
|
||||
@@ -154,7 +187,7 @@ IMPORTANT: Return ONLY a raw JSON object. NO markdown fences, NO code blocks, NO
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)})
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user