diff --git a/dungeonGenerator.js b/dungeonGenerator.js index fed8688..8849715 100644 --- a/dungeonGenerator.js +++ b/dungeonGenerator.js @@ -130,7 +130,7 @@ function extractCanonicalNames(dungeonData) { // Extract faction names from core concepts (if available) if (dungeonData.coreConcepts) { - const factionMatch = dungeonData.coreConcepts.match(/Primary Faction[:\s]+([^\.]+)/i); + const factionMatch = dungeonData.coreConcepts.match(/Primary Faction[:\s]+([^.]+)/i); if (factionMatch) { names.factions.push(factionMatch[1].trim()); } @@ -472,7 +472,7 @@ Output as five separate numbered lists with these exact labels: "Locations:", "E // Step 6: Player Choices and Consequences const npcNamesList = npcs.map(n => n.name).join(", "); - const factionName = coreConcepts.match(/Primary Faction[:\s]+([^\.]+)/i)?.[1]?.trim() || "the primary faction"; + const factionName = coreConcepts.match(/Primary Faction[:\s]+([^.]+)/i)?.[1]?.trim() || "the primary faction"; const plotResolutionsRaw = await callOllama( `Based on all of the following elements, suggest 4-5 possible, non-conflicting story climaxes or plot resolutions for adventurers exploring this location. Each resolution must provide a meaningful choice with a tangible consequence, directly related to the Central Conflict, the Primary Faction, or the NPCs. diff --git a/dungeonTemplate.js b/dungeonTemplate.js index d17a6e8..b571022 100644 --- a/dungeonTemplate.js +++ b/dungeonTemplate.js @@ -19,13 +19,6 @@ export function dungeonTemplate(data) { "'Playfair Display', serif" ]; - const tableFonts = [ - "'Alegreya Sans', sans-serif", - "'Cabin', sans-serif", - "'IBM Plex Sans', sans-serif", - "'Cormorant Garamond', serif" - ]; - const quoteFonts = [ "'Playfair Display', serif", "'Libre Baskerville', serif", @@ -34,7 +27,6 @@ export function dungeonTemplate(data) { const bodyFont = pickRandom(bodyFonts); const headingFont = pickRandom(headingFonts); - const tableFont = pickRandom(tableFonts); const quoteFont = pickRandom(quoteFonts); // Check if we have a map image to include diff --git a/generatePDF.js b/generatePDF.js index 1bbab77..43f9f86 100644 --- a/generatePDF.js +++ b/generatePDF.js @@ -26,7 +26,7 @@ export async function generatePDF(data, outputPath = "dungeon.pdf") { const imageData = data.map ? await readImageData(data.map) : null; const dataWithImage = imageData ? { ...data, map: imageData } - : (({ map, ...rest }) => rest)(data); + : (({ map, ...rest }) => rest)(data); // eslint-disable-line no-unused-vars const html = dungeonTemplate(dataWithImage); await page.setContent(html, { waitUntil: "networkidle0" }); diff --git a/imageGenerator.js b/imageGenerator.js index c50e5ec..acba029 100644 --- a/imageGenerator.js +++ b/imageGenerator.js @@ -167,6 +167,9 @@ async function waitForImage(promptId, timeout = 900000) { while (Date.now() - start < timeout) { const res = await fetch(`${COMFYUI_URL}/history`); + if (!res.ok) { + throw new Error(`ComfyUI history request failed: ${res.status} ${res.statusText}`); + } const data = await res.json(); const historyEntry = data[promptId]; @@ -206,7 +209,7 @@ async function generateImageViaComfyUI(prompt, filename) { }); if (!res.ok) { - throw new Error(`ComfyUI error: ${res.statusText}`); + throw new Error(`ComfyUI error: ${res.status} ${res.statusText}`); } const { prompt_id } = await res.json(); diff --git a/ollamaClient.js b/ollamaClient.js index 7954589..229fadf 100644 --- a/ollamaClient.js +++ b/ollamaClient.js @@ -12,7 +12,10 @@ function cleanText(str) { } function inferApiType(url) { - return url?.includes("/api/chat/completions") ? "open-webui" : "direct"; + if (!url) return "ollama-generate"; + if (url.includes("/api/chat/completions")) return "open-webui"; + if (url.includes("/api/chat")) return "ollama-chat"; + return "ollama-generate"; } async function sleep(ms) { @@ -21,6 +24,7 @@ async function sleep(ms) { async function callOllamaBase(prompt, model, retries, stepName, apiType) { const isUsingOpenWebUI = apiType === "open-webui"; + const isUsingOllamaChat = apiType === "ollama-chat"; for (let attempt = 1; attempt <= retries; attempt++) { try { @@ -39,7 +43,7 @@ async function callOllamaBase(prompt, model, retries, stepName, apiType) { headers["Authorization"] = `Bearer ${OLLAMA_API_KEY}`; } - const body = isUsingOpenWebUI + const body = isUsingOpenWebUI || isUsingOllamaChat ? { model, messages: [{ role: "user", content: prompt }] } : { model, prompt, stream: false }; @@ -49,15 +53,25 @@ async function callOllamaBase(prompt, model, retries, stepName, apiType) { body: JSON.stringify(body), }); - if (!response.ok) + if (!response.ok) { + let errorDetails = ""; + try { + const errorData = await response.text(); + errorDetails = errorData ? `: ${errorData}` : ""; + } catch { + // Ignore errors reading error response + } throw new Error( - `Ollama request failed: ${response.status} ${response.statusText}`, + `Ollama request failed: ${response.status} ${response.statusText}${errorDetails}`, ); + } const data = await response.json(); const rawText = isUsingOpenWebUI ? data.choices?.[0]?.message?.content - : data.response; + : isUsingOllamaChat + ? data.message?.content + : data.response; if (!rawText) throw new Error("No response from Ollama"); @@ -92,7 +106,7 @@ export async function callOllamaExplicit( model = OLLAMA_MODEL, retries = 5, stepName = "unknown", - apiType = "direct", + apiType = "ollama-generate", ) { return callOllamaBase(prompt, model, retries, stepName, apiType); }