UNPKG

@kaifronsdal/transcript-viewer

Version:

A web-based viewer for AI conversation transcripts with rollback support

210 lines (207 loc) 9.55 kB
import { w as push, K as ensure_array_like, M as attr_class, N as stringify, I as escape_html, E as attr, y as pop } from './index-C8Be6c37.js'; import { v as viewSettings, f as filterState } from './stores-BsrhgqVf.js'; import { compileExpression } from 'filtrex'; function createFilterFunction(expression) { if (!expression || !expression.trim()) { return () => true; } try { const options = { extraFunctions: { startsWith: (str, prefix) => str?.startsWith(prefix) || false, endsWith: (str, suffix) => str?.endsWith(suffix) || false, contains: (str, substring) => str?.includes(substring) || false, toLowerCase: (str) => str?.toLowerCase() || "", toUpperCase: (str) => str?.toUpperCase() || "" } }; const compiledExpression = compileExpression(expression, options); return (transcript) => { try { const context = { // Basic fields id: transcript.id, model: transcript.model, split: transcript.split, concerningScore: transcript.concerningScore, summary: transcript.summary, judgeSummary: transcript.judgeSummary, justification: transcript.justification, // Individual score fields (scores.scoreA becomes scoreA) ...Object.fromEntries( Object.entries(transcript.scores || {}).map(([key, value]) => [key, value]) ), // Also keep scores object for scores.scoreA syntax scores: transcript.scores || {} }; return Boolean(compiledExpression(context)); } catch (error) { console.warn("Filter evaluation failed for transcript:", transcript.id, error); return false; } }; } catch (error) { console.warn("Filter compilation failed:", error); return () => true; } } function validateFilterExpression(expression) { if (!expression || !expression.trim()) { return null; } try { const options = { extraFunctions: { startsWith: () => true, endsWith: () => true, contains: () => true, toLowerCase: () => "", toUpperCase: () => "" } }; compileExpression(expression, options); return null; } catch (error) { return error instanceof Error ? error.message : "Invalid expression"; } } function getFilterExamples() { return [ "scoreA < 5", "scoreA < 5 and scoreB > 3", "1 < scoreA < 4", "scoreA in (1, 3, 5)", 'split == "scheming"', 'split in ("scheming", "power_seeking")', 'startsWith(model, "gpt")', 'contains(summary, "refusal")', "concerningScore > 7 and scoreA < 3", "(scoreA == 1 or scoreA == 3) and scoreB < 6" ]; } function getAvailableFields(scoreTypes) { const baseFields = [ "id", "model", "split", "concerningScore", "summary", "judgeSummary" ]; const customFunctions = [ "startsWith", "endsWith", "contains", "toLowerCase", "toUpperCase" ]; return [ ...baseFields, ...scoreTypes, ...customFunctions ]; } function _page($$payload, $$props) { push(); let transcripts = []; let folderTree = []; viewSettings.value.viewMode; let allTranscripts = (() => { console.log("🔍 [DEBUG] Computing allTranscripts...", { viewMode: viewSettings.value.viewMode, transcriptsLength: transcripts.length, folderTreeLength: folderTree.length }); const result = viewSettings.value.viewMode === "list" ? transcripts : extractAllTranscriptsFromTree(folderTree); console.log("📊 [DEBUG] allTranscripts computed, length:", result.length); return result; })(); let scoreTypes = (() => { console.log("🏷️ [DEBUG] Computing scoreTypes from", allTranscripts.length, "transcripts..."); const result = [ ...new Set(allTranscripts.flatMap((t) => Object.keys(t.scores || {}))) ].sort(); console.log("🏷️ [DEBUG] scoreTypes computed:", result); return result; })(); let filterFunction = (() => { console.log("🔧 [DEBUG] Creating filter function for expression:", filterState.value.filterExpression); const result = createFilterFunction(filterState.value.filterExpression); console.log("🔧 [DEBUG] Filter function created"); return result; })(); let filterError = (() => { console.log("✅ [DEBUG] Validating filter expression:", filterState.value.filterExpression); const result = validateFilterExpression(filterState.value.filterExpression); console.log("✅ [DEBUG] Filter validation result:", result); return result; })(); let filterExamples = getFilterExamples(); getAvailableFields(scoreTypes); let filteredTranscripts = transcripts.filter((transcript) => { if (filterState.value.searchQuery && !transcript.summary.toLowerCase().includes(filterState.value.searchQuery.toLowerCase())) return false; return filterFunction(transcript); }); let filteredFolderTree = filterFolderTree(folderTree, filterState.value); function extractAllTranscriptsFromTree(nodes) { const transcripts2 = []; for (const node of nodes) { if (node.type === "transcript" && node.transcript) { transcripts2.push(node.transcript); } else if (node.type === "folder" && node.children) { transcripts2.push(...extractAllTranscriptsFromTree(node.children)); } } return transcripts2; } function filterFolderTree(nodes, filters) { return nodes.map((node) => { if (node.type === "transcript") { const transcript = node.transcript; if (!transcript) return null; if (filters.searchQuery && !transcript.summary.toLowerCase().includes(filters.searchQuery.toLowerCase())) return null; if (!filterFunction(transcript)) return null; return node; } else if (node.type === "folder") { const filteredChildren = filterFolderTree(node.children || [], filters); if (filteredChildren.length > 0) { return { ...node, children: filteredChildren }; } return null; } return null; }).filter((node) => node !== null); } viewSettings.value.viewMode === "list" ? filteredTranscripts.length : extractAllTranscriptsFromTree(filteredFolderTree).length; const each_array = ensure_array_like(filterExamples); $$payload.out += `<div class="space-y-6"><div class="flex justify-between items-center"><h1 class="text-3xl font-bold">AWT Transcript Viewer</h1> <div class="flex items-center gap-4"><div class="tabs tabs-boxed"><button${attr_class(`tab ${stringify(viewSettings.value.viewMode === "tree" ? "tab-active" : "")}`)}>Tree View</button> <button${attr_class(`tab ${stringify(viewSettings.value.viewMode === "list" ? "tab-active" : "")}`)}>List View</button></div> <div class="badge badge-neutral">`; { $$payload.out += "<!--[-->"; $$payload.out += `Loading...`; } $$payload.out += `<!--]--></div></div></div> <div class="card bg-base-100 shadow-sm"><div class="card-body"><h3 class="text-lg font-semibold mb-3">Filters</h3> <div class="form-control mb-4"><label class="label" for="filter-expression"><span class="label-text">Filter Expression</span> <span class="label-text-alt"><details class="dropdown dropdown-end"><summary class="btn btn-xs btn-ghost">Examples</summary> <div class="dropdown-content bg-base-100 rounded-box z-[1] p-4 shadow-lg w-80"><div class="text-sm space-y-2"><p class="font-medium">Available fields:</p> <div class="text-xs text-base-content/70 space-y-1"><div><code>model</code>, <code>split</code>, <code>concerningScore</code></div> <div><code>summary</code>, <code>judgeSummary</code></div> <div>Score fields: <code>${escape_html(scoreTypes.join(", "))}</code></div></div> <p class="font-medium mt-4">Examples:</p> <div class="text-xs text-base-content/70 space-y-1"><!--[-->`; for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { let example = each_array[$$index]; $$payload.out += `<div><code class="cursor-pointer hover:bg-base-200 px-1 rounded">${escape_html(example)}</code></div>`; } $$payload.out += `<!--]--></div></div></div></details></span></label> <div class="autocomplete-container relative"><input id="filter-expression" type="text" placeholder="e.g., concerningScore > 5 and power_seeking &lt; 3"${attr_class(`input input-bordered w-full ${stringify(filterError ? "input-error" : "")}`)}${attr("value", filterState.value.filterExpression)} autocomplete="off"/> `; { $$payload.out += "<!--[!-->"; } $$payload.out += `<!--]--></div> `; if (filterError) { $$payload.out += "<!--[-->"; $$payload.out += `<div class="label"><span class="label-text-alt text-error">${escape_html(filterError)}</span></div>`; } else { $$payload.out += "<!--[!-->"; } $$payload.out += `<!--]--></div> <div class="form-control"><label class="label" for="search-input"><span class="label-text">Search Summaries</span></label> <input id="search-input" type="text" placeholder="Search summaries..." class="input input-bordered"${attr("value", filterState.value.searchQuery)}/></div></div></div> `; { $$payload.out += "<!--[-->"; $$payload.out += `<div class="text-center py-12"><div class="loading loading-spinner loading-lg"></div> <p class="mt-4 text-base-content/70">Loading ${escape_html(viewSettings.value.viewMode === "list" ? "transcripts" : "folder tree")}...</p></div>`; } $$payload.out += `<!--]--></div>`; pop(); } export { _page as default }; //# sourceMappingURL=_page.svelte-C24rrmYG.js.map