export function extractFinalJson(text) { if (!text) return null; if (text.includes("")) text = text.split("").at(-1); text = text.replace(/```(?:json)?\s*/g, ""); const blocks = []; for (let i = 0; i < text.length; i++) { if (text[i] !== "{") continue; let depth = 0; for (let j = i; j < text.length; j++) { if (text[j] === "{") depth++; else if (text[j] === "}") { depth--; if (depth === 0) { blocks.push(text.slice(i, j + 1)); break; } } } } for (let b = blocks.length - 1; b >= 0; b--) { try { return JSON.parse(blocks[b]); } catch { /* try next */ } } return null; } export function filterVerbatim(answer, text) { const out = {}; for (const [k, v] of Object.entries(answer ?? {})) { if (typeof v === "string" && v && text.includes(v)) out[k] = v; } return out; } export function buildPrompt(text, mention) { return ( "Extract attributes of this data mention. Output ONLY a JSON object with " + "keys producer, year, geography, acronym. Each value must be an exact " + "substring of the text; omit keys that are absent.\n\n" + `Mention: "${mention}"\n\nText: ${text}` ); } export function buildUsageImpactPrompt(mention, usage, context) { return ( "Classify the usage and impact of this data mention. Output ONLY a JSON " + "object with keys data_type, usage_action, impact_label, usage_summary. " + "usage_summary is one sentence in your own words, derived from the labels; " + "do not invent specifics not present in the text.\n\n" + `Mention: "${mention}"\n\nUsage: "${usage}"\n\nText: ${context}` ); } export function sentenceContaining(text, mention) { const idx = text.indexOf(mention); if (idx < 0) return text; const re = /[.!?](?=\s|$)/g; let start = 0; let end = text.length; let m; while ((m = re.exec(text)) !== null) { if (m.index < idx) start = m.index + 1; else { end = m.index + 1; break; } } return text.slice(start, end).trim(); }