@kaifronsdal/transcript-viewer
Version:
A web-based viewer for AI conversation transcripts with rollback support
210 lines (207 loc) • 9.55 kB
JavaScript
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 < 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