llmxray 0.4.5 → 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +25 -1
  2. package/dist/assets/{AITrainingPage-CTbiKR4o.js → AITrainingPage-CsvXVCl4.js} +1 -1
  3. package/dist/assets/{AnalyticsPage-L3-8eM5L.js → AnalyticsPage-vkaPSUTM.js} +1 -1
  4. package/dist/assets/{BenchmarkPage-Cp2LdW1Y.js → BenchmarkPage-D0OBLy2p.js} +6 -6
  5. package/dist/assets/{ComparisonPage-F2QFxXKK.js → ComparisonPage-yjlQyMSr.js} +1 -1
  6. package/dist/assets/{CostDashboardPage-CmkI6RhJ.js → CostDashboardPage--NlorE5h.js} +1 -1
  7. package/dist/assets/DashboardPage-C7HpWzo0.js +114 -0
  8. package/dist/assets/{EmbeddingsPage-Dhn69cMU.js → EmbeddingsPage-BjI-MRAa.js} +1 -1
  9. package/dist/assets/FimPlaygroundPage-DFbVhKk_.js +7 -0
  10. package/dist/assets/{GoogleCallbackPage-BPOipV3I.js → GoogleCallbackPage-CtnaMbov.js} +1 -1
  11. package/dist/assets/{JsonTreeNode-C5Z9FiUn.js → JsonTreeNode-D4tXijI2.js} +1 -1
  12. package/dist/assets/{ModelCapabilityIcons.vue_vue_type_script_setup_true_lang-BYJHAYcE.js → ModelCapabilityIcons.vue_vue_type_script_setup_true_lang-Cj2LskB0.js} +1 -1
  13. package/dist/assets/ProtocolObservatoryPage-BCBMa4BZ.js +2 -0
  14. package/dist/assets/{RAGPage-CsjbL5YH.js → RAGPage-DhajwBAP.js} +1 -1
  15. package/dist/assets/{SessionPage-B36k_j6J.js → SessionPage-D9yVmDvL.js} +1 -1
  16. package/dist/assets/{SettingsPage-tCYrEuZu.js → SettingsPage-CMAnCevk.js} +1 -1
  17. package/dist/assets/{StatusBadge.vue_vue_type_script_setup_true_lang-l4RPMSub.js → StatusBadge.vue_vue_type_script_setup_true_lang-n7TTYhNJ.js} +1 -1
  18. package/dist/assets/{StorageGauge.vue_vue_type_style_index_0_lang-BZ0xe8a5.js → StorageGauge.vue_vue_type_style_index_0_lang-BKb4VKNU.js} +1 -1
  19. package/dist/assets/{SystemPage-DbM1asxH.js → SystemPage-D4Zziyum.js} +2 -2
  20. package/dist/assets/{TabBar.vue_vue_type_script_setup_true_lang-DvNMmBew.js → TabBar.vue_vue_type_script_setup_true_lang-DQpdkass.js} +1 -1
  21. package/dist/assets/{TokenStreamDisplay.vue_vue_type_script_setup_true_lang-DbSc7oKx.js → TokenStreamDisplay.vue_vue_type_script_setup_true_lang-Bkp4Zqzc.js} +1 -1
  22. package/dist/assets/{ToolWorkshopPage-DlvGbnXA.js → ToolWorkshopPage-Bi-P9pPj.js} +1 -1
  23. package/dist/assets/{agent-store-BAbxPyGG.js → agent-store-uNRCwO3m.js} +1 -1
  24. package/dist/assets/{canvas-ai-db-DNjr8LU-.js → canvas-ai-db-vwusn4PB.js} +1 -1
  25. package/dist/assets/{download-C1Met8Ds.js → download-CE6FVTgu.js} +1 -1
  26. package/dist/assets/{generate-service-VZbSAJDg.js → generate-service-CYQ8kwVP.js} +1 -1
  27. package/dist/assets/{google-auth-store-DkdmpAZx.js → google-auth-store-Dz06BePf.js} +1 -1
  28. package/dist/assets/index-BwnEclbR.js +36 -0
  29. package/dist/assets/{index-BAH6vZD2.js → index-Dv-x214f.js} +1 -1
  30. package/dist/assets/{index-JwzhZrFR.js → index-FRDa6LAg.js} +1 -1
  31. package/dist/assets/{index-B0RKZCO8.css → index-aU4tMz4Z.css} +1 -1
  32. package/dist/assets/{info-L1PieSf1.js → info-DnW3KRin.js} +1 -1
  33. package/dist/assets/{metrics-store-CTvzJiqS.js → metrics-store-BDn0738m.js} +1 -1
  34. package/dist/assets/{papaparse.min-_t35gVwJ.js → papaparse.min-DzDO_wBU.js} +1 -1
  35. package/dist/assets/{pencil-CyyRcZEK.js → pencil-clhQxwX0.js} +1 -1
  36. package/dist/assets/play-4DIDJWWS.js +1 -0
  37. package/dist/assets/{rag-store-BenIN46q.js → rag-store-Do5yRDAH.js} +3 -3
  38. package/dist/assets/{session-store-CUrHUAx1.js → session-store-DRoQgYmX.js} +1 -1
  39. package/dist/assets/{share-2-yHQTyFhw.js → share-2-DmfX3XRE.js} +1 -1
  40. package/dist/assets/square-BSrc21IW.js +1 -0
  41. package/dist/assets/{storage-store-BVMT_hD6.js → storage-store-BNeLgzhr.js} +1 -1
  42. package/dist/assets/{stream-handler-aBc67cBl.js → stream-handler-m2cr76ko.js} +2 -2
  43. package/dist/assets/{tool-workshop-store-BMnfrBeR.js → tool-workshop-store-CvrmwDRz.js} +1 -1
  44. package/dist/assets/{toolcall-store-BaQPfRpR.js → toolcall-store-EOcmOTQ4.js} +1 -1
  45. package/dist/assets/{trash-2-DAcbs__v.js → trash-2-DghOHCMp.js} +1 -1
  46. package/dist/index.html +2 -2
  47. package/package.json +1 -1
  48. package/dist/assets/DashboardPage-BsQXjnwn.js +0 -116
  49. package/dist/assets/index-BSSjp86R.js +0 -8
package/README.md CHANGED
@@ -99,6 +99,12 @@ Embed text, visualize vectors, measure cosine similarity. Build a local knowledg
99
99
  ### Tool Workshop (Visual Canvas)
100
100
  Drag-and-drop node canvas for building tool definitions. Bidirectional code sync (edit nodes or TypeScript — both update). Probe APIs, auto-generate schemas, test with live execution.
101
101
 
102
+ ### Fill-in-the-Middle Playground *(new in v0.4.7)*
103
+ Code completion for Qwen-Coder, CodeLlama, Codestral, DeepSeek-Coder, and StarCoder. Two textareas (prefix / suffix), the model fills the gap. Uses Ollama's `suffix` field on `/api/generate`. Stitched preview shows the result as it would appear in your editor.
104
+
105
+ ### Protocol Observatory *(new in v0.4.7)*
106
+ Fire the same prompt through Ollama's three serving protocols — **native** `/api/chat`, **OpenAI-compat** `/v1/chat/completions`, and **Anthropic-compat** `/v1/messages` — in parallel against your local model. Side-by-side streaming, per-protocol metrics, and an envelope-diff tab that shows how each protocol frames finish reasons, token counts, and error envelopes. No cloud, no API keys — all three endpoints are local on `localhost:11434`.
107
+
102
108
  ### AI Training Pipeline
103
109
  Curate training data from your conversations. Tag, review, and export as JSONL for fine-tuning.
104
110
 
@@ -106,7 +112,25 @@ Curate training data from your conversations. Tag, review, and export as JSONL f
106
112
  Every experiment (benchmarks, comparisons, chats, training pairs) is automatically archived in a queryable IndexedDB database with filters, trends, exports, and retention policies.
107
113
 
108
114
  ### Multilingual
109
- Full translations in English, French, Chinese, and Arabic. RTL layout support. Community scaffolds for Hebrew and Japanese.
115
+ Full translations in English, French, Serbian (Latin + Cyrillic), Chinese, and Arabic. RTL layout support. Community scaffolds for Hebrew and Japanese.
116
+
117
+ ---
118
+
119
+ ## Ollama Compatibility
120
+
121
+ Tested and verified against **Ollama 0.24.0** (the current latest stable as of May 2026). LLMxRay uses these Ollama endpoints:
122
+
123
+ | Endpoint | Used for |
124
+ |---|---|
125
+ | `/api/chat` | Streaming chat (NDJSON, with `tools`, `think`, `format` schema) |
126
+ | `/api/generate` | Generation + Fill-in-the-Middle via `suffix` |
127
+ | `/api/tags`, `/api/show` | Model list + capability detection (`thinking`, `tools`, `vision`) |
128
+ | `/api/embed` | Vector embeddings for RAG |
129
+ | `/api/pull`, `/api/delete`, `/api/ps`, `/api/version` | Model management + status |
130
+ | `/v1/chat/completions` | OpenAI-compat path used by Surgical Benchmark for real logprobs |
131
+ | `/v1/messages` | Anthropic-compat path used by Protocol Observatory |
132
+
133
+ **Compatible with:** Ollama 0.20 and newer (older versions work for chat/generate but lack `think` and JSON-schema `format`). **Recommended:** Ollama 0.24+ for full feature parity including the Anthropic-compat endpoint (added in 0.23) and the `think: "max"` mode (added in 0.21.3).
110
134
 
111
135
  ---
112
136
 
@@ -1 +1 @@
1
- import{d as Z,r as $,a as D,b as N,e as m,f as e,t as o,q as R,u as c,i as w,l as G,F as P,k as S,g as k,j as p,h as H,p as j,X as Q,C as E,D as U,v as W,Z as V,B as Y}from"./index-BSSjp86R.js";import{canvasAiDB as B}from"./canvas-ai-db-DNjr8LU-.js";import{b as _,d as z}from"./format-BqVZ9rwM.js";import{_ as ee}from"./StorageGauge.vue_vue_type_style_index_0_lang-BZ0xe8a5.js";const te=Z("training",()=>{const t=$([]),n=$(!1),g=$(new Set),l=$(null),r=$({phase:null,model:null,accepted:null,toolName:null,tag:null,search:"",sortBy:"timestamp",sortDir:"desc"}),f=D(()=>{let i=[...t.value];const u=r.value;if(u.phase&&(i=i.filter(x=>x.phase===u.phase)),u.model&&(i=i.filter(x=>x.model===u.model)),u.accepted!==null&&(i=i.filter(x=>x.accepted===u.accepted)),u.toolName&&(i=i.filter(x=>x.toolName===u.toolName)),u.tag&&(i=i.filter(x=>x.tags?.includes(u.tag)??!1)),u.search){const x=u.search.toLowerCase();i=i.filter(b=>b.userPrompt.toLowerCase().includes(x)||b.response.toLowerCase().includes(x)||b.toolName.toLowerCase().includes(x))}return i.sort((x,b)=>{let y=0;return u.sortBy==="timestamp"?y=x.timestamp-b.timestamp:u.sortBy==="phase"?y=x.phase.localeCompare(b.phase):u.sortBy==="model"&&(y=x.model.localeCompare(b.model)),u.sortDir==="desc"?-y:y}),i}),d=D(()=>{const i=t.value,u=new Map,x=new Map;let b=0,y=0;for(const A of i)A.accepted&&b++,u.set(A.phase,(u.get(A.phase)??0)+1),x.set(A.model,(x.get(A.model)??0)+1),y+=A.systemPrompt.length+A.userPrompt.length+A.response.length;return{total:i.length,accepted:b,rejected:i.length-b,phaseBreakdown:u,modelBreakdown:x,estimatedBytes:y*2}}),a=D(()=>{const i=new Set;for(const u of t.value)for(const x of u.tags??[])i.add(x);return[...i].sort()}),s=D(()=>[...new Set(t.value.map(i=>i.model))].sort()),v=D(()=>[...new Set(t.value.map(i=>i.toolName))].sort());async function C(){n.value=!0;try{t.value=await B.getAllPairs()}catch(i){console.error("Failed to load training pairs:",i)}finally{n.value=!1}}async function M(i,u){await B.updatePairResponse(i,u);const x=t.value.find(b=>b.id===i);x&&(x.response=u)}async function h(i,u){await B.updatePairTags(i,u);const x=t.value.find(b=>b.id===i);x&&(x.tags=u)}async function T(i){const u=t.value.find(b=>b.id===i);if(!u)return;const x=!u.accepted;await B.updateAccepted(i,x),u.accepted=x}async function I(i){await B.deletePairs(i);const u=new Set(i);t.value=t.value.filter(x=>!u.has(x.id));for(const x of i)g.value.delete(x);l.value&&u.has(l.value)&&(l.value=null)}async function L(i,u){for(const x of i){await B.updateAccepted(x,u);const b=t.value.find(y=>y.id===x);b&&(b.accepted=u)}}async function F(i,u){for(const x of i){const b=t.value.find(A=>A.id===x);if(!b)continue;const y=[...b.tags??[]];y.includes(u)||(y.push(u),await B.updatePairTags(x,y),b.tags=y)}}function K(i){B.exportSelectedAsJsonl(i)}function q(i){const u=new Set(g.value);u.has(i)?u.delete(i):u.add(i),g.value=u}function J(){g.value=new Set(f.value.map(i=>i.id))}function O(){g.value=new Set}function X(i){l.value=l.value===i?null:i}return{pairs:t,loading:n,selectedIds:g,expandedId:l,filters:r,filteredPairs:f,stats:d,allTags:a,allModels:s,allToolNames:v,loadPairs:C,updateResponse:M,updateTags:h,toggleAccepted:T,deletePairs:I,bulkSetAccepted:L,bulkAddTag:F,exportSelected:K,toggleSelection:q,selectAll:J,deselectAll:O,setExpanded:X}}),se={class:"grid grid-cols-2 gap-3 lg:grid-cols-4"},ae={class:"rounded-lg border border-border-default bg-surface-raised p-3 space-y-2"},oe={class:"text-[10px] text-text-muted uppercase tracking-wider"},ne={class:"text-xl font-bold text-text-primary"},le={class:"rounded-lg border border-border-default bg-surface-raised p-3 space-y-2"},re={class:"text-[10px] text-text-muted uppercase tracking-wider"},de={class:"text-xl font-bold text-text-primary"},ie={class:"flex items-center gap-2 text-[10px]"},ue={class:"text-success"},ce={class:"text-error"},pe={key:0,class:"h-1.5 rounded-full bg-surface-overlay overflow-hidden"},xe={class:"rounded-lg border border-border-default bg-surface-raised p-3 space-y-2"},ge={class:"text-[10px] text-text-muted uppercase tracking-wider"},me={class:"flex flex-wrap gap-1.5"},fe={class:"rounded-lg border border-border-default bg-surface-raised p-3 space-y-2"},be={class:"text-[10px] text-text-muted uppercase tracking-wider"},ve={key:0,class:"space-y-1"},ye={class:"text-text-secondary truncate"},he={class:"text-text-muted shrink-0"},$e={key:1,class:"text-[10px] text-text-muted italic"},ke=N({__name:"TrainingDashboard",props:{stats:{}},setup(t){const n=t,g=D(()=>["draft","insights","automap","fix"].map(a=>({key:a,count:n.stats.phaseBreakdown.get(a)??0}))),l=D(()=>[...n.stats.modelBreakdown.entries()].sort((d,a)=>a[1]-d[1]).slice(0,3)),r=D(()=>n.stats.total>0?Math.round(n.stats.accepted/n.stats.total*100):0),f={draft:"bg-blue-500/20 text-blue-400",insights:"bg-amber-500/20 text-amber-400",automap:"bg-emerald-500/20 text-emerald-400",fix:"bg-rose-500/20 text-rose-400"};return(d,a)=>(p(),m("div",se,[e("div",ae,[e("p",oe,o(d.$t("training.dashboard.trainingPairs")),1),e("p",ne,o(t.stats.total),1),t.stats.estimatedBytes>0?(p(),R(ee,{key:0,used:t.stats.estimatedBytes,total:t.stats.estimatedBytes*5,compact:"",label:`~${c(_)(t.stats.estimatedBytes)} dataset`},null,8,["used","total","label"])):w("",!0)]),e("div",le,[e("p",re,o(d.$t("training.dashboard.acceptanceRate")),1),e("p",de,o(r.value)+"%",1),e("div",ie,[e("span",ue,o(t.stats.accepted)+" "+o(d.$t("training.dashboard.accepted")),1),a[0]||(a[0]=e("span",{class:"text-text-muted"},"/",-1)),e("span",ce,o(t.stats.rejected)+" "+o(d.$t("training.dashboard.rejected")),1)]),t.stats.total>0?(p(),m("div",pe,[e("div",{class:"h-full rounded-full bg-success transition-all duration-500",style:G({width:`${r.value}%`})},null,4)])):w("",!0)]),e("div",xe,[e("p",ge,o(d.$t("training.dashboard.byPhase")),1),e("div",me,[(p(!0),m(P,null,S(g.value,s=>(p(),m("span",{key:s.key,class:k(["rounded-full px-2 py-0.5 text-[10px] font-medium",f[s.key]])},o(s.key)+" "+o(s.count),3))),128))])]),e("div",fe,[e("p",be,o(d.$t("training.dashboard.topModels")),1),l.value.length>0?(p(),m("div",ve,[(p(!0),m(P,null,S(l.value,([s,v])=>(p(),m("div",{key:s,class:"flex items-center justify-between text-[10px]"},[e("span",ye,o(s),1),e("span",he,o(v),1)]))),128))])):(p(),m("p",$e,o(d.$t("common.empty.noData")),1))])]))}}),we={class:"flex flex-wrap items-center gap-2"},Ce=["value"],Te=["value"],Ae=["value"],Pe=["value"],Se=["value"],Be=["value"],De={class:"flex rounded-lg border border-border-default overflow-hidden"},Ie=["value"],Ne=["value"],je=["value","placeholder"],Me=["value"],Re=["title"],Ee=N({__name:"TrainingFilters",props:{filters:{},models:{},toolNames:{},tags:{}},emits:["update:filters"],setup(t,{emit:n}){const g=t,l=n;function r(d){l("update:filters",{...g.filters,...d})}const f=[{value:"",label:"All phases"},{value:"draft",label:"Draft"},{value:"insights",label:"Insights"},{value:"automap",label:"Auto-map"},{value:"fix",label:"Fix"}];return(d,a)=>(p(),m("div",we,[e("select",{value:t.filters.phase??"",class:"rounded-lg border border-border-default bg-surface px-2.5 py-1.5 text-xs text-text-primary outline-none focus:border-accent",onChange:a[0]||(a[0]=s=>r({phase:s.target.value||null}))},[(p(),m(P,null,S(f,s=>e("option",{key:s.label,value:s.value},o(s.label),9,Te)),64))],40,Ce),e("select",{value:t.filters.model??"",class:"rounded-lg border border-border-default bg-surface px-2.5 py-1.5 text-xs text-text-primary outline-none focus:border-accent",onChange:a[1]||(a[1]=s=>r({model:s.target.value||null}))},[a[10]||(a[10]=e("option",{value:""},"All models",-1)),(p(!0),m(P,null,S(t.models,s=>(p(),m("option",{key:s,value:s},o(s),9,Pe))),128))],40,Ae),e("select",{value:t.filters.toolName??"",class:"rounded-lg border border-border-default bg-surface px-2.5 py-1.5 text-xs text-text-primary outline-none focus:border-accent",onChange:a[2]||(a[2]=s=>r({toolName:s.target.value||null}))},[a[11]||(a[11]=e("option",{value:""},"All tools",-1)),(p(!0),m(P,null,S(t.toolNames,s=>(p(),m("option",{key:s,value:s},o(s),9,Be))),128))],40,Se),e("div",De,[e("button",{class:k(["px-2.5 py-1.5 text-[10px] transition-colors",t.filters.accepted===null?"bg-accent/10 text-accent":"bg-surface text-text-muted hover:text-text-primary"]),onClick:a[3]||(a[3]=s=>r({accepted:null}))},"All",2),e("button",{class:k(["px-2.5 py-1.5 text-[10px] transition-colors border-l border-border-default",t.filters.accepted===!0?"bg-success/10 text-success":"bg-surface text-text-muted hover:text-text-primary"]),onClick:a[4]||(a[4]=s=>r({accepted:!0}))},"Accepted",2),e("button",{class:k(["px-2.5 py-1.5 text-[10px] transition-colors border-l border-border-default",t.filters.accepted===!1?"bg-error/10 text-error":"bg-surface text-text-muted hover:text-text-primary"]),onClick:a[5]||(a[5]=s=>r({accepted:!1}))},"Rejected",2)]),t.tags.length>0?(p(),m("select",{key:0,value:t.filters.tag??"",class:"rounded-lg border border-border-default bg-surface px-2.5 py-1.5 text-xs text-text-primary outline-none focus:border-accent",onChange:a[6]||(a[6]=s=>r({tag:s.target.value||null}))},[a[12]||(a[12]=e("option",{value:""},"All tags",-1)),(p(!0),m(P,null,S(t.tags,s=>(p(),m("option",{key:s,value:s},o(s),9,Ne))),128))],40,Ie)):w("",!0),e("input",{value:t.filters.search,type:"text",placeholder:d.$t("training.filters.searchPrompts"),class:"flex-1 min-w-[150px] rounded-lg border border-border-default bg-surface px-2.5 py-1.5 text-xs text-text-primary placeholder-text-muted outline-none focus:border-accent",onInput:a[7]||(a[7]=s=>r({search:s.target.value}))},null,40,je),e("select",{value:t.filters.sortBy,class:"rounded-lg border border-border-default bg-surface px-2.5 py-1.5 text-xs text-text-primary outline-none focus:border-accent",onChange:a[8]||(a[8]=s=>r({sortBy:s.target.value}))},[...a[13]||(a[13]=[e("option",{value:"timestamp"},"Sort by time",-1),e("option",{value:"phase"},"Sort by phase",-1),e("option",{value:"model"},"Sort by model",-1)])],40,Me),e("button",{class:"rounded-lg border border-border-default bg-surface px-2 py-1.5 text-xs text-text-muted hover:text-text-primary transition-colors",title:t.filters.sortDir==="desc"?"Newest first":"Oldest first",onClick:a[9]||(a[9]=s=>r({sortDir:t.filters.sortDir==="desc"?"asc":"desc"}))},o(t.filters.sortDir==="desc"?"↓":"↑"),9,Re)]))}}),Ue={class:"flex flex-wrap items-center gap-1.5"},Ve=["onClick"],ze=["placeholder"],Le=N({__name:"TrainingTagEditor",props:{tags:{},allTags:{}},emits:["update:tags"],setup(t,{emit:n}){const g=n,l=$("");function r(d,a){if(d.key==="Enter"||d.key===","){d.preventDefault();const s=l.value.trim().toLowerCase();s&&!a.includes(s)&&g("update:tags",[...a,s]),l.value=""}}function f(d,a){g("update:tags",d.filter(s=>s!==a))}return(d,a)=>(p(),m("div",Ue,[(p(!0),m(P,null,S(t.tags,s=>(p(),m("span",{key:s,class:"flex items-center gap-1 rounded-full bg-accent/10 px-2 py-0.5 text-[10px] text-accent"},[H(o(s)+" ",1),e("button",{class:"text-accent/60 hover:text-accent transition-colors",onClick:v=>f(t.tags,s)},[j(c(Q),{class:"h-2.5 w-2.5","stroke-width":3})],8,Ve)]))),128)),E(e("input",{"onUpdate:modelValue":a[0]||(a[0]=s=>l.value=s),type:"text",placeholder:d.$t("training.tags.addPlaceholder"),class:"w-20 bg-transparent text-[10px] text-text-primary placeholder-text-muted outline-none",onKeydown:a[1]||(a[1]=s=>r(s,t.tags))},null,40,ze),[[U,l.value]])]))}}),Fe={class:"rounded-lg border border-accent/30 bg-surface-raised p-4 space-y-4"},Ke={class:"flex items-center justify-between"},qe={class:"flex items-center gap-2"},Je={class:"text-xs text-text-secondary"},Oe={class:"text-[10px] text-text-muted"},Xe={class:"text-[10px] text-text-muted"},Ze={class:"flex items-center gap-2"},Ge={class:"mb-1 text-[10px] font-medium uppercase tracking-wider text-text-muted"},He={class:"max-h-32 overflow-auto rounded-lg bg-surface p-3 text-xs text-text-secondary whitespace-pre-wrap font-mono"},Qe={class:"mb-1 text-[10px] font-medium uppercase tracking-wider text-text-muted"},We={class:"max-h-32 overflow-auto rounded-lg bg-surface p-3 text-xs text-text-secondary whitespace-pre-wrap font-mono"},Ye={key:0},_e={class:"mb-1 text-[10px] font-medium uppercase tracking-wider text-accent"},et={class:"max-h-40 overflow-auto rounded-lg bg-accent/5 border border-accent/20 p-3 text-xs text-text-secondary whitespace-pre-wrap font-mono italic"},tt={class:"mb-1 flex items-center justify-between"},st={class:"text-[10px] font-medium uppercase tracking-wider text-text-muted"},at={key:1,class:"max-h-64 overflow-auto rounded-lg bg-surface p-3 text-xs text-text-secondary whitespace-pre-wrap font-mono"},ot={key:2,class:"mt-2 flex gap-2"},nt={class:"mb-1.5 text-[10px] font-medium uppercase tracking-wider text-text-muted"},lt={class:"flex items-center justify-end border-t border-border-default pt-3"},rt=N({__name:"TrainingDetailPanel",props:{pair:{},allTags:{}},emits:["close","update:response","update:tags","toggle-accepted","delete"],setup(t,{emit:n}){const g=t,l=n,r=$(!1),f=$(""),d=$(!1);function a(){f.value=g.pair.response,r.value=!0}function s(){l("update:response",g.pair.id,f.value),r.value=!1}function v(){r.value=!1}function C(){d.value?(l("delete",g.pair.id),d.value=!1):(d.value=!0,setTimeout(()=>{d.value=!1},3e3))}const M={draft:"bg-blue-500/20 text-blue-400",insights:"bg-amber-500/20 text-amber-400",automap:"bg-emerald-500/20 text-emerald-400",fix:"bg-rose-500/20 text-rose-400"};return(h,T)=>(p(),m("div",Fe,[e("div",Ke,[e("div",qe,[e("span",{class:k(["rounded-full px-2 py-0.5 text-[10px] font-medium",M[t.pair.phase]])},o(t.pair.phase),3),e("span",Je,o(t.pair.toolName),1),e("span",Oe,o(t.pair.model),1),e("span",Xe,o(c(z)(t.pair.timestamp)),1)]),e("div",Ze,[e("button",{class:k(["rounded px-2 py-1 text-[10px] transition-colors",t.pair.accepted?"bg-success/10 text-success":"bg-error/10 text-error"]),onClick:T[0]||(T[0]=I=>l("toggle-accepted",t.pair.id))},o(t.pair.accepted?h.$t("training.detail.accepted"):h.$t("training.detail.rejected")),3),e("button",{class:"text-text-muted hover:text-text-primary transition-colors text-xs","aria-label":"Close panel",onClick:T[1]||(T[1]=I=>l("close"))}," ✕ ")])]),e("div",null,[e("p",Ge,o(h.$t("training.detail.systemPrompt")),1),e("pre",He,o(t.pair.systemPrompt),1)]),e("div",null,[e("p",Qe,o(h.$t("training.detail.userPrompt")),1),e("pre",We,o(t.pair.userPrompt),1)]),t.pair.reasoning?(p(),m("div",Ye,[e("p",_e,o(h.$t("training.detail.reasoning")),1),e("pre",et,o(t.pair.reasoning),1)])):w("",!0),e("div",null,[e("div",tt,[e("p",st,o(h.$t("training.detail.aiResponse")),1),r.value?w("",!0):(p(),m("button",{key:0,class:"text-[10px] text-accent hover:underline",onClick:a},o(h.$t("training.detail.editResponse")),1))]),r.value?E((p(),m("textarea",{key:0,"onUpdate:modelValue":T[2]||(T[2]=I=>f.value=I),rows:"8",class:"w-full rounded-lg border border-accent bg-surface px-3 py-2 text-xs text-text-primary font-mono outline-none resize-y"},null,512)),[[U,f.value]]):(p(),m("pre",at,o(t.pair.response),1)),r.value?(p(),m("div",ot,[e("button",{class:"rounded-lg bg-accent px-3 py-1 text-xs text-white hover:bg-accent-hover transition-colors",onClick:s},o(h.$t("common.actions.save")),1),e("button",{class:"rounded-lg px-3 py-1 text-xs text-text-muted hover:text-text-primary transition-colors",onClick:v},o(h.$t("common.actions.cancel")),1)])):w("",!0)]),e("div",null,[e("p",nt,o(h.$t("training.detail.tags")),1),j(Le,{tags:t.pair.tags??[],"all-tags":t.allTags,"onUpdate:tags":T[3]||(T[3]=I=>l("update:tags",t.pair.id,I))},null,8,["tags","all-tags"])]),e("div",lt,[e("button",{class:k(["rounded-lg px-3 py-1 text-xs transition-colors",d.value?"bg-error/10 text-error":"text-text-muted hover:text-error"]),onClick:C},o(d.value?h.$t("training.detail.confirmDelete"):h.$t("training.detail.deletePair")),3)])]))}}),dt={key:0,class:"rounded-lg bg-surface-overlay p-8 text-center"},it={class:"text-sm text-text-muted"},ut={key:1,class:"space-y-1"},ct=["onClick"],pt=["onClick"],xt={key:0,class:"text-[8px]"},gt={class:"shrink-0 text-text-secondary w-24 truncate"},mt={class:"shrink-0 text-text-muted w-28 truncate"},ft={class:"flex items-center gap-1 shrink-0"},bt={key:0,class:"text-[8px] text-text-muted"},vt={class:"flex-1 min-w-0 truncate text-text-muted"},yt={class:"shrink-0 text-[10px] text-text-muted"},ht=N({__name:"TrainingTable",props:{pairs:{},selectedIds:{},expandedId:{},allTags:{}},emits:["toggle-selection","set-expanded","update:response","update:tags","toggle-accepted","delete"],setup(t,{emit:n}){const g=n,l={draft:"bg-blue-500/20 text-blue-400",insights:"bg-amber-500/20 text-amber-400",automap:"bg-emerald-500/20 text-emerald-400",fix:"bg-rose-500/20 text-rose-400"};return(r,f)=>t.pairs.length===0?(p(),m("div",dt,[e("p",it,o(r.$t("training.table.noResults")),1)])):(p(),m("div",ut,[(p(!0),m(P,null,S(t.pairs,d=>(p(),m("div",{key:d.id},[e("div",{class:k(["flex items-center gap-3 rounded-lg border border-border-default bg-surface-raised px-3 py-2.5 text-xs transition-colors cursor-pointer hover:border-accent/30",t.expandedId===d.id?"border-accent/50":""]),onClick:a=>g("set-expanded",d.id)},[e("button",{class:k(["flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors",t.selectedIds.has(d.id)?"border-accent bg-accent text-white":"border-border-default hover:border-accent"]),onClick:W(a=>g("toggle-selection",d.id),["stop"])},[t.selectedIds.has(d.id)?(p(),m("span",xt,"✓")):w("",!0)],10,pt),e("span",{class:k(["shrink-0 rounded-full px-2 py-0.5 text-[9px] font-medium",l[d.phase]])},o(d.phase),3),e("span",gt,o(d.toolName),1),e("span",mt,o(d.model),1),e("span",{class:k(["shrink-0 rounded-full px-1.5 py-0.5 text-[9px]",d.accepted?"bg-success/10 text-success":"bg-error/10 text-error"])},o(d.accepted?r.$t("training.dashboard.accepted"):r.$t("training.dashboard.rejected")),3),e("div",ft,[(p(!0),m(P,null,S((d.tags??[]).slice(0,2),a=>(p(),m("span",{key:a,class:"rounded-full bg-accent/10 px-1.5 py-0.5 text-[8px] text-accent"},o(a),1))),128)),(d.tags??[]).length>2?(p(),m("span",bt,"+"+o((d.tags??[]).length-2),1)):w("",!0)]),e("span",vt,o(d.userPrompt.slice(0,80))+o(d.userPrompt.length>80?"...":""),1),e("span",yt,o(c(z)(d.timestamp)),1)],10,ct),t.expandedId===d.id?(p(),R(rt,{key:0,pair:d,"all-tags":t.allTags,class:"mt-1 ms-7",onClose:f[0]||(f[0]=a=>g("set-expanded",null)),"onUpdate:response":f[1]||(f[1]=(a,s)=>g("update:response",a,s)),"onUpdate:tags":f[2]||(f[2]=(a,s)=>g("update:tags",a,s)),onToggleAccepted:f[3]||(f[3]=a=>g("toggle-accepted",a)),onDelete:f[4]||(f[4]=a=>g("delete",a))},null,8,["pair","all-tags"])):w("",!0)]))),128))]))}}),$t={class:"flex items-center gap-2 rounded-lg border border-accent/30 bg-surface-raised px-4 py-2.5"},kt={class:"text-xs font-medium text-accent"},wt={class:"ms-auto flex items-center gap-2"},Ct={key:0,class:"flex items-center gap-1"},Tt=["placeholder"],At=N({__name:"TrainingBulkActions",props:{selectedCount:{}},emits:["export","mark-accepted","mark-rejected","add-tag","delete","deselect-all"],setup(t,{emit:n}){const g=n,l=$(!1),r=$(""),f=$(!1);function d(){const s=r.value.trim().toLowerCase();s&&(g("add-tag",s),r.value="",l.value=!1)}function a(){f.value?(g("delete"),f.value=!1):(f.value=!0,setTimeout(()=>{f.value=!1},3e3))}return(s,v)=>(p(),m("div",$t,[e("span",kt,o(s.$t("training.bulk.selected",{count:t.selectedCount})),1),e("div",wt,[e("button",{class:"rounded-lg bg-surface-overlay px-3 py-1 text-[10px] text-text-secondary hover:text-text-primary transition-colors",onClick:v[0]||(v[0]=C=>g("export"))},o(s.$t("training.bulk.exportJsonl")),1),e("button",{class:"rounded-lg bg-success/10 px-3 py-1 text-[10px] text-success hover:bg-success/20 transition-colors",onClick:v[1]||(v[1]=C=>g("mark-accepted"))},o(s.$t("training.bulk.markAccepted")),1),e("button",{class:"rounded-lg bg-error/10 px-3 py-1 text-[10px] text-error hover:bg-error/20 transition-colors",onClick:v[2]||(v[2]=C=>g("mark-rejected"))},o(s.$t("training.bulk.markRejected")),1),l.value?(p(),m("div",Ct,[E(e("input",{"onUpdate:modelValue":v[3]||(v[3]=C=>r.value=C),type:"text",placeholder:s.$t("training.bulk.tagPlaceholder"),class:"w-24 rounded border border-accent bg-surface px-2 py-0.5 text-[10px] text-text-primary outline-none",onKeydown:[V(d,["enter"]),v[4]||(v[4]=V(C=>l.value=!1,["escape"]))]},null,40,Tt),[[U,r.value]]),e("button",{class:"text-[10px] text-accent hover:underline",onClick:d},o(s.$t("common.actions.add")),1)])):(p(),m("button",{key:1,class:"rounded-lg bg-accent/10 px-3 py-1 text-[10px] text-accent hover:bg-accent/20 transition-colors",onClick:v[5]||(v[5]=C=>l.value=!0)},o(s.$t("training.bulk.addTag")),1)),e("button",{class:k(["rounded-lg px-3 py-1 text-[10px] transition-colors",f.value?"bg-error/10 text-error":"text-text-muted hover:text-error"]),onClick:a},o(f.value?s.$t("training.bulk.confirm"):s.$t("training.bulk.delete")),3),e("button",{class:"text-[10px] text-text-muted hover:text-text-primary transition-colors",onClick:v[6]||(v[6]=C=>g("deselect-all"))},o(s.$t("training.bulk.deselectAll")),1)])]))}}),Pt={class:"mx-auto max-w-6xl space-y-6"},St={class:"text-lg font-semibold text-text-primary"},Bt={class:"text-sm text-text-muted"},Dt={key:1,class:"flex items-center gap-3"},It={class:"text-[10px] text-text-muted"},Nt={key:2,class:"rounded-lg border border-border-default bg-surface-raised p-8 text-center"},jt={class:"text-sm text-text-muted mb-2"},Mt={class:"text-xs text-text-muted"},zt=N({__name:"AITrainingPage",setup(t){const n=te();return Y(()=>{n.loadPairs()}),(g,l)=>(p(),m("div",Pt,[e("div",null,[e("h2",St,o(g.$t("training.title")),1),e("p",Bt,o(g.$t("training.subtitle")),1)]),j(ke,{stats:c(n).stats},null,8,["stats"]),j(Ee,{filters:c(n).filters,models:c(n).allModels,"tool-names":c(n).allToolNames,tags:c(n).allTags,"onUpdate:filters":l[0]||(l[0]=r=>c(n).filters=r)},null,8,["filters","models","tool-names","tags"]),c(n).selectedIds.size>0?(p(),R(At,{key:0,"selected-count":c(n).selectedIds.size,onExport:l[1]||(l[1]=r=>c(n).exportSelected([...c(n).selectedIds])),onMarkAccepted:l[2]||(l[2]=r=>c(n).bulkSetAccepted([...c(n).selectedIds],!0)),onMarkRejected:l[3]||(l[3]=r=>c(n).bulkSetAccepted([...c(n).selectedIds],!1)),onAddTag:l[4]||(l[4]=r=>c(n).bulkAddTag([...c(n).selectedIds],r)),onDelete:l[5]||(l[5]=r=>c(n).deletePairs([...c(n).selectedIds])),onDeselectAll:l[6]||(l[6]=r=>c(n).deselectAll())},null,8,["selected-count"])):w("",!0),c(n).filteredPairs.length>0?(p(),m("div",Dt,[e("button",{class:"text-[10px] text-text-muted hover:text-accent transition-colors",onClick:l[7]||(l[7]=r=>c(n).selectedIds.size===c(n).filteredPairs.length?c(n).deselectAll():c(n).selectAll())},o(c(n).selectedIds.size===c(n).filteredPairs.length?g.$t("training.table.deselectAll"):g.$t("training.table.selectAll")+" "+c(n).filteredPairs.length),1),e("span",It,o(g.$t("training.table.pairsShown",{shown:c(n).filteredPairs.length,total:c(n).pairs.length})),1)])):w("",!0),j(ht,{pairs:c(n).filteredPairs,"selected-ids":c(n).selectedIds,"expanded-id":c(n).expandedId,"all-tags":c(n).allTags,onToggleSelection:l[8]||(l[8]=r=>c(n).toggleSelection(r)),onSetExpanded:l[9]||(l[9]=r=>c(n).setExpanded(r)),"onUpdate:response":l[10]||(l[10]=(r,f)=>c(n).updateResponse(r,f)),"onUpdate:tags":l[11]||(l[11]=(r,f)=>c(n).updateTags(r,f)),onToggleAccepted:l[12]||(l[12]=r=>c(n).toggleAccepted(r)),onDelete:l[13]||(l[13]=r=>c(n).deletePairs([r]))},null,8,["pairs","selected-ids","expanded-id","all-tags"]),c(n).pairs.length===0&&!c(n).loading?(p(),m("div",Nt,[e("p",jt,o(g.$t("training.empty.title")),1),e("p",Mt,o(g.$t("training.empty.description")),1)])):w("",!0)]))}});export{zt as default};
1
+ import{d as Z,r as $,a as D,b as N,e as m,f as e,t as o,q as R,u as c,i as w,l as G,F as P,k as S,g as k,j as p,h as H,p as j,X as Q,C as E,D as U,v as W,Z as V,B as Y}from"./index-BwnEclbR.js";import{canvasAiDB as B}from"./canvas-ai-db-vwusn4PB.js";import{b as _,d as z}from"./format-BqVZ9rwM.js";import{_ as ee}from"./StorageGauge.vue_vue_type_style_index_0_lang-BKb4VKNU.js";const te=Z("training",()=>{const t=$([]),n=$(!1),g=$(new Set),l=$(null),r=$({phase:null,model:null,accepted:null,toolName:null,tag:null,search:"",sortBy:"timestamp",sortDir:"desc"}),f=D(()=>{let i=[...t.value];const u=r.value;if(u.phase&&(i=i.filter(x=>x.phase===u.phase)),u.model&&(i=i.filter(x=>x.model===u.model)),u.accepted!==null&&(i=i.filter(x=>x.accepted===u.accepted)),u.toolName&&(i=i.filter(x=>x.toolName===u.toolName)),u.tag&&(i=i.filter(x=>x.tags?.includes(u.tag)??!1)),u.search){const x=u.search.toLowerCase();i=i.filter(b=>b.userPrompt.toLowerCase().includes(x)||b.response.toLowerCase().includes(x)||b.toolName.toLowerCase().includes(x))}return i.sort((x,b)=>{let y=0;return u.sortBy==="timestamp"?y=x.timestamp-b.timestamp:u.sortBy==="phase"?y=x.phase.localeCompare(b.phase):u.sortBy==="model"&&(y=x.model.localeCompare(b.model)),u.sortDir==="desc"?-y:y}),i}),d=D(()=>{const i=t.value,u=new Map,x=new Map;let b=0,y=0;for(const A of i)A.accepted&&b++,u.set(A.phase,(u.get(A.phase)??0)+1),x.set(A.model,(x.get(A.model)??0)+1),y+=A.systemPrompt.length+A.userPrompt.length+A.response.length;return{total:i.length,accepted:b,rejected:i.length-b,phaseBreakdown:u,modelBreakdown:x,estimatedBytes:y*2}}),a=D(()=>{const i=new Set;for(const u of t.value)for(const x of u.tags??[])i.add(x);return[...i].sort()}),s=D(()=>[...new Set(t.value.map(i=>i.model))].sort()),v=D(()=>[...new Set(t.value.map(i=>i.toolName))].sort());async function C(){n.value=!0;try{t.value=await B.getAllPairs()}catch(i){console.error("Failed to load training pairs:",i)}finally{n.value=!1}}async function M(i,u){await B.updatePairResponse(i,u);const x=t.value.find(b=>b.id===i);x&&(x.response=u)}async function h(i,u){await B.updatePairTags(i,u);const x=t.value.find(b=>b.id===i);x&&(x.tags=u)}async function T(i){const u=t.value.find(b=>b.id===i);if(!u)return;const x=!u.accepted;await B.updateAccepted(i,x),u.accepted=x}async function I(i){await B.deletePairs(i);const u=new Set(i);t.value=t.value.filter(x=>!u.has(x.id));for(const x of i)g.value.delete(x);l.value&&u.has(l.value)&&(l.value=null)}async function L(i,u){for(const x of i){await B.updateAccepted(x,u);const b=t.value.find(y=>y.id===x);b&&(b.accepted=u)}}async function F(i,u){for(const x of i){const b=t.value.find(A=>A.id===x);if(!b)continue;const y=[...b.tags??[]];y.includes(u)||(y.push(u),await B.updatePairTags(x,y),b.tags=y)}}function K(i){B.exportSelectedAsJsonl(i)}function q(i){const u=new Set(g.value);u.has(i)?u.delete(i):u.add(i),g.value=u}function J(){g.value=new Set(f.value.map(i=>i.id))}function O(){g.value=new Set}function X(i){l.value=l.value===i?null:i}return{pairs:t,loading:n,selectedIds:g,expandedId:l,filters:r,filteredPairs:f,stats:d,allTags:a,allModels:s,allToolNames:v,loadPairs:C,updateResponse:M,updateTags:h,toggleAccepted:T,deletePairs:I,bulkSetAccepted:L,bulkAddTag:F,exportSelected:K,toggleSelection:q,selectAll:J,deselectAll:O,setExpanded:X}}),se={class:"grid grid-cols-2 gap-3 lg:grid-cols-4"},ae={class:"rounded-lg border border-border-default bg-surface-raised p-3 space-y-2"},oe={class:"text-[10px] text-text-muted uppercase tracking-wider"},ne={class:"text-xl font-bold text-text-primary"},le={class:"rounded-lg border border-border-default bg-surface-raised p-3 space-y-2"},re={class:"text-[10px] text-text-muted uppercase tracking-wider"},de={class:"text-xl font-bold text-text-primary"},ie={class:"flex items-center gap-2 text-[10px]"},ue={class:"text-success"},ce={class:"text-error"},pe={key:0,class:"h-1.5 rounded-full bg-surface-overlay overflow-hidden"},xe={class:"rounded-lg border border-border-default bg-surface-raised p-3 space-y-2"},ge={class:"text-[10px] text-text-muted uppercase tracking-wider"},me={class:"flex flex-wrap gap-1.5"},fe={class:"rounded-lg border border-border-default bg-surface-raised p-3 space-y-2"},be={class:"text-[10px] text-text-muted uppercase tracking-wider"},ve={key:0,class:"space-y-1"},ye={class:"text-text-secondary truncate"},he={class:"text-text-muted shrink-0"},$e={key:1,class:"text-[10px] text-text-muted italic"},ke=N({__name:"TrainingDashboard",props:{stats:{}},setup(t){const n=t,g=D(()=>["draft","insights","automap","fix"].map(a=>({key:a,count:n.stats.phaseBreakdown.get(a)??0}))),l=D(()=>[...n.stats.modelBreakdown.entries()].sort((d,a)=>a[1]-d[1]).slice(0,3)),r=D(()=>n.stats.total>0?Math.round(n.stats.accepted/n.stats.total*100):0),f={draft:"bg-blue-500/20 text-blue-400",insights:"bg-amber-500/20 text-amber-400",automap:"bg-emerald-500/20 text-emerald-400",fix:"bg-rose-500/20 text-rose-400"};return(d,a)=>(p(),m("div",se,[e("div",ae,[e("p",oe,o(d.$t("training.dashboard.trainingPairs")),1),e("p",ne,o(t.stats.total),1),t.stats.estimatedBytes>0?(p(),R(ee,{key:0,used:t.stats.estimatedBytes,total:t.stats.estimatedBytes*5,compact:"",label:`~${c(_)(t.stats.estimatedBytes)} dataset`},null,8,["used","total","label"])):w("",!0)]),e("div",le,[e("p",re,o(d.$t("training.dashboard.acceptanceRate")),1),e("p",de,o(r.value)+"%",1),e("div",ie,[e("span",ue,o(t.stats.accepted)+" "+o(d.$t("training.dashboard.accepted")),1),a[0]||(a[0]=e("span",{class:"text-text-muted"},"/",-1)),e("span",ce,o(t.stats.rejected)+" "+o(d.$t("training.dashboard.rejected")),1)]),t.stats.total>0?(p(),m("div",pe,[e("div",{class:"h-full rounded-full bg-success transition-all duration-500",style:G({width:`${r.value}%`})},null,4)])):w("",!0)]),e("div",xe,[e("p",ge,o(d.$t("training.dashboard.byPhase")),1),e("div",me,[(p(!0),m(P,null,S(g.value,s=>(p(),m("span",{key:s.key,class:k(["rounded-full px-2 py-0.5 text-[10px] font-medium",f[s.key]])},o(s.key)+" "+o(s.count),3))),128))])]),e("div",fe,[e("p",be,o(d.$t("training.dashboard.topModels")),1),l.value.length>0?(p(),m("div",ve,[(p(!0),m(P,null,S(l.value,([s,v])=>(p(),m("div",{key:s,class:"flex items-center justify-between text-[10px]"},[e("span",ye,o(s),1),e("span",he,o(v),1)]))),128))])):(p(),m("p",$e,o(d.$t("common.empty.noData")),1))])]))}}),we={class:"flex flex-wrap items-center gap-2"},Ce=["value"],Te=["value"],Ae=["value"],Pe=["value"],Se=["value"],Be=["value"],De={class:"flex rounded-lg border border-border-default overflow-hidden"},Ie=["value"],Ne=["value"],je=["value","placeholder"],Me=["value"],Re=["title"],Ee=N({__name:"TrainingFilters",props:{filters:{},models:{},toolNames:{},tags:{}},emits:["update:filters"],setup(t,{emit:n}){const g=t,l=n;function r(d){l("update:filters",{...g.filters,...d})}const f=[{value:"",label:"All phases"},{value:"draft",label:"Draft"},{value:"insights",label:"Insights"},{value:"automap",label:"Auto-map"},{value:"fix",label:"Fix"}];return(d,a)=>(p(),m("div",we,[e("select",{value:t.filters.phase??"",class:"rounded-lg border border-border-default bg-surface px-2.5 py-1.5 text-xs text-text-primary outline-none focus:border-accent",onChange:a[0]||(a[0]=s=>r({phase:s.target.value||null}))},[(p(),m(P,null,S(f,s=>e("option",{key:s.label,value:s.value},o(s.label),9,Te)),64))],40,Ce),e("select",{value:t.filters.model??"",class:"rounded-lg border border-border-default bg-surface px-2.5 py-1.5 text-xs text-text-primary outline-none focus:border-accent",onChange:a[1]||(a[1]=s=>r({model:s.target.value||null}))},[a[10]||(a[10]=e("option",{value:""},"All models",-1)),(p(!0),m(P,null,S(t.models,s=>(p(),m("option",{key:s,value:s},o(s),9,Pe))),128))],40,Ae),e("select",{value:t.filters.toolName??"",class:"rounded-lg border border-border-default bg-surface px-2.5 py-1.5 text-xs text-text-primary outline-none focus:border-accent",onChange:a[2]||(a[2]=s=>r({toolName:s.target.value||null}))},[a[11]||(a[11]=e("option",{value:""},"All tools",-1)),(p(!0),m(P,null,S(t.toolNames,s=>(p(),m("option",{key:s,value:s},o(s),9,Be))),128))],40,Se),e("div",De,[e("button",{class:k(["px-2.5 py-1.5 text-[10px] transition-colors",t.filters.accepted===null?"bg-accent/10 text-accent":"bg-surface text-text-muted hover:text-text-primary"]),onClick:a[3]||(a[3]=s=>r({accepted:null}))},"All",2),e("button",{class:k(["px-2.5 py-1.5 text-[10px] transition-colors border-l border-border-default",t.filters.accepted===!0?"bg-success/10 text-success":"bg-surface text-text-muted hover:text-text-primary"]),onClick:a[4]||(a[4]=s=>r({accepted:!0}))},"Accepted",2),e("button",{class:k(["px-2.5 py-1.5 text-[10px] transition-colors border-l border-border-default",t.filters.accepted===!1?"bg-error/10 text-error":"bg-surface text-text-muted hover:text-text-primary"]),onClick:a[5]||(a[5]=s=>r({accepted:!1}))},"Rejected",2)]),t.tags.length>0?(p(),m("select",{key:0,value:t.filters.tag??"",class:"rounded-lg border border-border-default bg-surface px-2.5 py-1.5 text-xs text-text-primary outline-none focus:border-accent",onChange:a[6]||(a[6]=s=>r({tag:s.target.value||null}))},[a[12]||(a[12]=e("option",{value:""},"All tags",-1)),(p(!0),m(P,null,S(t.tags,s=>(p(),m("option",{key:s,value:s},o(s),9,Ne))),128))],40,Ie)):w("",!0),e("input",{value:t.filters.search,type:"text",placeholder:d.$t("training.filters.searchPrompts"),class:"flex-1 min-w-[150px] rounded-lg border border-border-default bg-surface px-2.5 py-1.5 text-xs text-text-primary placeholder-text-muted outline-none focus:border-accent",onInput:a[7]||(a[7]=s=>r({search:s.target.value}))},null,40,je),e("select",{value:t.filters.sortBy,class:"rounded-lg border border-border-default bg-surface px-2.5 py-1.5 text-xs text-text-primary outline-none focus:border-accent",onChange:a[8]||(a[8]=s=>r({sortBy:s.target.value}))},[...a[13]||(a[13]=[e("option",{value:"timestamp"},"Sort by time",-1),e("option",{value:"phase"},"Sort by phase",-1),e("option",{value:"model"},"Sort by model",-1)])],40,Me),e("button",{class:"rounded-lg border border-border-default bg-surface px-2 py-1.5 text-xs text-text-muted hover:text-text-primary transition-colors",title:t.filters.sortDir==="desc"?"Newest first":"Oldest first",onClick:a[9]||(a[9]=s=>r({sortDir:t.filters.sortDir==="desc"?"asc":"desc"}))},o(t.filters.sortDir==="desc"?"↓":"↑"),9,Re)]))}}),Ue={class:"flex flex-wrap items-center gap-1.5"},Ve=["onClick"],ze=["placeholder"],Le=N({__name:"TrainingTagEditor",props:{tags:{},allTags:{}},emits:["update:tags"],setup(t,{emit:n}){const g=n,l=$("");function r(d,a){if(d.key==="Enter"||d.key===","){d.preventDefault();const s=l.value.trim().toLowerCase();s&&!a.includes(s)&&g("update:tags",[...a,s]),l.value=""}}function f(d,a){g("update:tags",d.filter(s=>s!==a))}return(d,a)=>(p(),m("div",Ue,[(p(!0),m(P,null,S(t.tags,s=>(p(),m("span",{key:s,class:"flex items-center gap-1 rounded-full bg-accent/10 px-2 py-0.5 text-[10px] text-accent"},[H(o(s)+" ",1),e("button",{class:"text-accent/60 hover:text-accent transition-colors",onClick:v=>f(t.tags,s)},[j(c(Q),{class:"h-2.5 w-2.5","stroke-width":3})],8,Ve)]))),128)),E(e("input",{"onUpdate:modelValue":a[0]||(a[0]=s=>l.value=s),type:"text",placeholder:d.$t("training.tags.addPlaceholder"),class:"w-20 bg-transparent text-[10px] text-text-primary placeholder-text-muted outline-none",onKeydown:a[1]||(a[1]=s=>r(s,t.tags))},null,40,ze),[[U,l.value]])]))}}),Fe={class:"rounded-lg border border-accent/30 bg-surface-raised p-4 space-y-4"},Ke={class:"flex items-center justify-between"},qe={class:"flex items-center gap-2"},Je={class:"text-xs text-text-secondary"},Oe={class:"text-[10px] text-text-muted"},Xe={class:"text-[10px] text-text-muted"},Ze={class:"flex items-center gap-2"},Ge={class:"mb-1 text-[10px] font-medium uppercase tracking-wider text-text-muted"},He={class:"max-h-32 overflow-auto rounded-lg bg-surface p-3 text-xs text-text-secondary whitespace-pre-wrap font-mono"},Qe={class:"mb-1 text-[10px] font-medium uppercase tracking-wider text-text-muted"},We={class:"max-h-32 overflow-auto rounded-lg bg-surface p-3 text-xs text-text-secondary whitespace-pre-wrap font-mono"},Ye={key:0},_e={class:"mb-1 text-[10px] font-medium uppercase tracking-wider text-accent"},et={class:"max-h-40 overflow-auto rounded-lg bg-accent/5 border border-accent/20 p-3 text-xs text-text-secondary whitespace-pre-wrap font-mono italic"},tt={class:"mb-1 flex items-center justify-between"},st={class:"text-[10px] font-medium uppercase tracking-wider text-text-muted"},at={key:1,class:"max-h-64 overflow-auto rounded-lg bg-surface p-3 text-xs text-text-secondary whitespace-pre-wrap font-mono"},ot={key:2,class:"mt-2 flex gap-2"},nt={class:"mb-1.5 text-[10px] font-medium uppercase tracking-wider text-text-muted"},lt={class:"flex items-center justify-end border-t border-border-default pt-3"},rt=N({__name:"TrainingDetailPanel",props:{pair:{},allTags:{}},emits:["close","update:response","update:tags","toggle-accepted","delete"],setup(t,{emit:n}){const g=t,l=n,r=$(!1),f=$(""),d=$(!1);function a(){f.value=g.pair.response,r.value=!0}function s(){l("update:response",g.pair.id,f.value),r.value=!1}function v(){r.value=!1}function C(){d.value?(l("delete",g.pair.id),d.value=!1):(d.value=!0,setTimeout(()=>{d.value=!1},3e3))}const M={draft:"bg-blue-500/20 text-blue-400",insights:"bg-amber-500/20 text-amber-400",automap:"bg-emerald-500/20 text-emerald-400",fix:"bg-rose-500/20 text-rose-400"};return(h,T)=>(p(),m("div",Fe,[e("div",Ke,[e("div",qe,[e("span",{class:k(["rounded-full px-2 py-0.5 text-[10px] font-medium",M[t.pair.phase]])},o(t.pair.phase),3),e("span",Je,o(t.pair.toolName),1),e("span",Oe,o(t.pair.model),1),e("span",Xe,o(c(z)(t.pair.timestamp)),1)]),e("div",Ze,[e("button",{class:k(["rounded px-2 py-1 text-[10px] transition-colors",t.pair.accepted?"bg-success/10 text-success":"bg-error/10 text-error"]),onClick:T[0]||(T[0]=I=>l("toggle-accepted",t.pair.id))},o(t.pair.accepted?h.$t("training.detail.accepted"):h.$t("training.detail.rejected")),3),e("button",{class:"text-text-muted hover:text-text-primary transition-colors text-xs","aria-label":"Close panel",onClick:T[1]||(T[1]=I=>l("close"))}," ✕ ")])]),e("div",null,[e("p",Ge,o(h.$t("training.detail.systemPrompt")),1),e("pre",He,o(t.pair.systemPrompt),1)]),e("div",null,[e("p",Qe,o(h.$t("training.detail.userPrompt")),1),e("pre",We,o(t.pair.userPrompt),1)]),t.pair.reasoning?(p(),m("div",Ye,[e("p",_e,o(h.$t("training.detail.reasoning")),1),e("pre",et,o(t.pair.reasoning),1)])):w("",!0),e("div",null,[e("div",tt,[e("p",st,o(h.$t("training.detail.aiResponse")),1),r.value?w("",!0):(p(),m("button",{key:0,class:"text-[10px] text-accent hover:underline",onClick:a},o(h.$t("training.detail.editResponse")),1))]),r.value?E((p(),m("textarea",{key:0,"onUpdate:modelValue":T[2]||(T[2]=I=>f.value=I),rows:"8",class:"w-full rounded-lg border border-accent bg-surface px-3 py-2 text-xs text-text-primary font-mono outline-none resize-y"},null,512)),[[U,f.value]]):(p(),m("pre",at,o(t.pair.response),1)),r.value?(p(),m("div",ot,[e("button",{class:"rounded-lg bg-accent px-3 py-1 text-xs text-white hover:bg-accent-hover transition-colors",onClick:s},o(h.$t("common.actions.save")),1),e("button",{class:"rounded-lg px-3 py-1 text-xs text-text-muted hover:text-text-primary transition-colors",onClick:v},o(h.$t("common.actions.cancel")),1)])):w("",!0)]),e("div",null,[e("p",nt,o(h.$t("training.detail.tags")),1),j(Le,{tags:t.pair.tags??[],"all-tags":t.allTags,"onUpdate:tags":T[3]||(T[3]=I=>l("update:tags",t.pair.id,I))},null,8,["tags","all-tags"])]),e("div",lt,[e("button",{class:k(["rounded-lg px-3 py-1 text-xs transition-colors",d.value?"bg-error/10 text-error":"text-text-muted hover:text-error"]),onClick:C},o(d.value?h.$t("training.detail.confirmDelete"):h.$t("training.detail.deletePair")),3)])]))}}),dt={key:0,class:"rounded-lg bg-surface-overlay p-8 text-center"},it={class:"text-sm text-text-muted"},ut={key:1,class:"space-y-1"},ct=["onClick"],pt=["onClick"],xt={key:0,class:"text-[8px]"},gt={class:"shrink-0 text-text-secondary w-24 truncate"},mt={class:"shrink-0 text-text-muted w-28 truncate"},ft={class:"flex items-center gap-1 shrink-0"},bt={key:0,class:"text-[8px] text-text-muted"},vt={class:"flex-1 min-w-0 truncate text-text-muted"},yt={class:"shrink-0 text-[10px] text-text-muted"},ht=N({__name:"TrainingTable",props:{pairs:{},selectedIds:{},expandedId:{},allTags:{}},emits:["toggle-selection","set-expanded","update:response","update:tags","toggle-accepted","delete"],setup(t,{emit:n}){const g=n,l={draft:"bg-blue-500/20 text-blue-400",insights:"bg-amber-500/20 text-amber-400",automap:"bg-emerald-500/20 text-emerald-400",fix:"bg-rose-500/20 text-rose-400"};return(r,f)=>t.pairs.length===0?(p(),m("div",dt,[e("p",it,o(r.$t("training.table.noResults")),1)])):(p(),m("div",ut,[(p(!0),m(P,null,S(t.pairs,d=>(p(),m("div",{key:d.id},[e("div",{class:k(["flex items-center gap-3 rounded-lg border border-border-default bg-surface-raised px-3 py-2.5 text-xs transition-colors cursor-pointer hover:border-accent/30",t.expandedId===d.id?"border-accent/50":""]),onClick:a=>g("set-expanded",d.id)},[e("button",{class:k(["flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors",t.selectedIds.has(d.id)?"border-accent bg-accent text-white":"border-border-default hover:border-accent"]),onClick:W(a=>g("toggle-selection",d.id),["stop"])},[t.selectedIds.has(d.id)?(p(),m("span",xt,"✓")):w("",!0)],10,pt),e("span",{class:k(["shrink-0 rounded-full px-2 py-0.5 text-[9px] font-medium",l[d.phase]])},o(d.phase),3),e("span",gt,o(d.toolName),1),e("span",mt,o(d.model),1),e("span",{class:k(["shrink-0 rounded-full px-1.5 py-0.5 text-[9px]",d.accepted?"bg-success/10 text-success":"bg-error/10 text-error"])},o(d.accepted?r.$t("training.dashboard.accepted"):r.$t("training.dashboard.rejected")),3),e("div",ft,[(p(!0),m(P,null,S((d.tags??[]).slice(0,2),a=>(p(),m("span",{key:a,class:"rounded-full bg-accent/10 px-1.5 py-0.5 text-[8px] text-accent"},o(a),1))),128)),(d.tags??[]).length>2?(p(),m("span",bt,"+"+o((d.tags??[]).length-2),1)):w("",!0)]),e("span",vt,o(d.userPrompt.slice(0,80))+o(d.userPrompt.length>80?"...":""),1),e("span",yt,o(c(z)(d.timestamp)),1)],10,ct),t.expandedId===d.id?(p(),R(rt,{key:0,pair:d,"all-tags":t.allTags,class:"mt-1 ms-7",onClose:f[0]||(f[0]=a=>g("set-expanded",null)),"onUpdate:response":f[1]||(f[1]=(a,s)=>g("update:response",a,s)),"onUpdate:tags":f[2]||(f[2]=(a,s)=>g("update:tags",a,s)),onToggleAccepted:f[3]||(f[3]=a=>g("toggle-accepted",a)),onDelete:f[4]||(f[4]=a=>g("delete",a))},null,8,["pair","all-tags"])):w("",!0)]))),128))]))}}),$t={class:"flex items-center gap-2 rounded-lg border border-accent/30 bg-surface-raised px-4 py-2.5"},kt={class:"text-xs font-medium text-accent"},wt={class:"ms-auto flex items-center gap-2"},Ct={key:0,class:"flex items-center gap-1"},Tt=["placeholder"],At=N({__name:"TrainingBulkActions",props:{selectedCount:{}},emits:["export","mark-accepted","mark-rejected","add-tag","delete","deselect-all"],setup(t,{emit:n}){const g=n,l=$(!1),r=$(""),f=$(!1);function d(){const s=r.value.trim().toLowerCase();s&&(g("add-tag",s),r.value="",l.value=!1)}function a(){f.value?(g("delete"),f.value=!1):(f.value=!0,setTimeout(()=>{f.value=!1},3e3))}return(s,v)=>(p(),m("div",$t,[e("span",kt,o(s.$t("training.bulk.selected",{count:t.selectedCount})),1),e("div",wt,[e("button",{class:"rounded-lg bg-surface-overlay px-3 py-1 text-[10px] text-text-secondary hover:text-text-primary transition-colors",onClick:v[0]||(v[0]=C=>g("export"))},o(s.$t("training.bulk.exportJsonl")),1),e("button",{class:"rounded-lg bg-success/10 px-3 py-1 text-[10px] text-success hover:bg-success/20 transition-colors",onClick:v[1]||(v[1]=C=>g("mark-accepted"))},o(s.$t("training.bulk.markAccepted")),1),e("button",{class:"rounded-lg bg-error/10 px-3 py-1 text-[10px] text-error hover:bg-error/20 transition-colors",onClick:v[2]||(v[2]=C=>g("mark-rejected"))},o(s.$t("training.bulk.markRejected")),1),l.value?(p(),m("div",Ct,[E(e("input",{"onUpdate:modelValue":v[3]||(v[3]=C=>r.value=C),type:"text",placeholder:s.$t("training.bulk.tagPlaceholder"),class:"w-24 rounded border border-accent bg-surface px-2 py-0.5 text-[10px] text-text-primary outline-none",onKeydown:[V(d,["enter"]),v[4]||(v[4]=V(C=>l.value=!1,["escape"]))]},null,40,Tt),[[U,r.value]]),e("button",{class:"text-[10px] text-accent hover:underline",onClick:d},o(s.$t("common.actions.add")),1)])):(p(),m("button",{key:1,class:"rounded-lg bg-accent/10 px-3 py-1 text-[10px] text-accent hover:bg-accent/20 transition-colors",onClick:v[5]||(v[5]=C=>l.value=!0)},o(s.$t("training.bulk.addTag")),1)),e("button",{class:k(["rounded-lg px-3 py-1 text-[10px] transition-colors",f.value?"bg-error/10 text-error":"text-text-muted hover:text-error"]),onClick:a},o(f.value?s.$t("training.bulk.confirm"):s.$t("training.bulk.delete")),3),e("button",{class:"text-[10px] text-text-muted hover:text-text-primary transition-colors",onClick:v[6]||(v[6]=C=>g("deselect-all"))},o(s.$t("training.bulk.deselectAll")),1)])]))}}),Pt={class:"mx-auto max-w-6xl space-y-6"},St={class:"text-lg font-semibold text-text-primary"},Bt={class:"text-sm text-text-muted"},Dt={key:1,class:"flex items-center gap-3"},It={class:"text-[10px] text-text-muted"},Nt={key:2,class:"rounded-lg border border-border-default bg-surface-raised p-8 text-center"},jt={class:"text-sm text-text-muted mb-2"},Mt={class:"text-xs text-text-muted"},zt=N({__name:"AITrainingPage",setup(t){const n=te();return Y(()=>{n.loadPairs()}),(g,l)=>(p(),m("div",Pt,[e("div",null,[e("h2",St,o(g.$t("training.title")),1),e("p",Bt,o(g.$t("training.subtitle")),1)]),j(ke,{stats:c(n).stats},null,8,["stats"]),j(Ee,{filters:c(n).filters,models:c(n).allModels,"tool-names":c(n).allToolNames,tags:c(n).allTags,"onUpdate:filters":l[0]||(l[0]=r=>c(n).filters=r)},null,8,["filters","models","tool-names","tags"]),c(n).selectedIds.size>0?(p(),R(At,{key:0,"selected-count":c(n).selectedIds.size,onExport:l[1]||(l[1]=r=>c(n).exportSelected([...c(n).selectedIds])),onMarkAccepted:l[2]||(l[2]=r=>c(n).bulkSetAccepted([...c(n).selectedIds],!0)),onMarkRejected:l[3]||(l[3]=r=>c(n).bulkSetAccepted([...c(n).selectedIds],!1)),onAddTag:l[4]||(l[4]=r=>c(n).bulkAddTag([...c(n).selectedIds],r)),onDelete:l[5]||(l[5]=r=>c(n).deletePairs([...c(n).selectedIds])),onDeselectAll:l[6]||(l[6]=r=>c(n).deselectAll())},null,8,["selected-count"])):w("",!0),c(n).filteredPairs.length>0?(p(),m("div",Dt,[e("button",{class:"text-[10px] text-text-muted hover:text-accent transition-colors",onClick:l[7]||(l[7]=r=>c(n).selectedIds.size===c(n).filteredPairs.length?c(n).deselectAll():c(n).selectAll())},o(c(n).selectedIds.size===c(n).filteredPairs.length?g.$t("training.table.deselectAll"):g.$t("training.table.selectAll")+" "+c(n).filteredPairs.length),1),e("span",It,o(g.$t("training.table.pairsShown",{shown:c(n).filteredPairs.length,total:c(n).pairs.length})),1)])):w("",!0),j(ht,{pairs:c(n).filteredPairs,"selected-ids":c(n).selectedIds,"expanded-id":c(n).expandedId,"all-tags":c(n).allTags,onToggleSelection:l[8]||(l[8]=r=>c(n).toggleSelection(r)),onSetExpanded:l[9]||(l[9]=r=>c(n).setExpanded(r)),"onUpdate:response":l[10]||(l[10]=(r,f)=>c(n).updateResponse(r,f)),"onUpdate:tags":l[11]||(l[11]=(r,f)=>c(n).updateTags(r,f)),onToggleAccepted:l[12]||(l[12]=r=>c(n).toggleAccepted(r)),onDelete:l[13]||(l[13]=r=>c(n).deletePairs([r]))},null,8,["pairs","selected-ids","expanded-id","all-tags"]),c(n).pairs.length===0&&!c(n).loading?(p(),m("div",Nt,[e("p",jt,o(g.$t("training.empty.title")),1),e("p",Mt,o(g.$t("training.empty.description")),1)])):w("",!0)]))}});export{zt as default};
@@ -1 +1 @@
1
- import{C as v,a as R,L as D,P as T,b as L,p as $,c as k,d as C,i as H,e as O,B as F,f as B,A as K,D as Y,S as G}from"./index-JwzhZrFR.js";import{u as S}from"./metrics-store-CTvzJiqS.js";import{b as x,e as c,f as l,t as m,p as _,u as y,a as p,j as d,F as w,i as U,l as J,k as E,g as q,I as X}from"./index-BSSjp86R.js";import{u as W}from"./session-store-CUrHUAx1.js";function P(u,n){if(u.length===0)return 0;const o=n/100*(u.length-1),a=Math.floor(o),r=Math.ceil(o);return a===r?u[a]:u[a]+(u[r]-u[a])*(o-a)}function N(u){const n=[...u].sort((o,a)=>o-a);return{p50:P(n,50),p95:P(n,95),p99:P(n,99)}}function V(u,n=10){if(u.length<n){if(u.length===0)return[];const r=N(u.map(f=>f.value));return[{label:new Date(u[u.length-1].timestamp).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}),...r}]}const o=[],a=Math.max(1,Math.floor(u.length/20));for(let r=n-1;r<u.length;r+=a){const f=u.slice(Math.max(0,r-n+1),r+1),s=N(f.map(t=>t.value));o.push({label:new Date(u[r].timestamp).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}),...s})}return o}const Z={class:"rounded-lg border border-border-default bg-surface-raised p-4"},tt={class:"mb-3 text-sm font-medium text-text-secondary"},et={key:0,class:"h-48"},st={key:1,class:"py-6 text-center text-xs text-text-muted"},ot=x({__name:"LatencyPercentilesChart",setup(u){v.register(R,D,T,L,$,k,C,H);const n=S(),o=p(()=>{const s=n.metricsHistory.map(t=>({timestamp:t.startedAt,value:t.totalDurationMs}));return V(s)}),a=p(()=>({labels:o.value.map(s=>s.label),datasets:[{label:"P50",data:o.value.map(s=>s.p50),borderColor:"#34d399",backgroundColor:"transparent",borderWidth:1.5,pointRadius:2,tension:.3},{label:"P95",data:o.value.map(s=>s.p95),borderColor:"#fbbf24",backgroundColor:"transparent",borderWidth:1.5,pointRadius:2,tension:.3},{label:"P99",data:o.value.map(s=>s.p99),borderColor:"#ef4444",backgroundColor:"transparent",borderWidth:1.5,pointRadius:2,tension:.3}]})),r={responsive:!0,maintainAspectRatio:!1,interaction:{mode:"index",intersect:!1},plugins:{legend:{position:"bottom",labels:{color:"#94a3b8",font:{size:10},usePointStyle:!0,pointStyle:"line"}},tooltip:{callbacks:{label:s=>`${s.dataset.label??""}: ${(s.parsed.y??0).toFixed(0)}ms`}}},scales:{x:{ticks:{color:"#94a3b8",font:{size:10},maxRotation:45},grid:{color:"rgba(71, 85, 105, 0.3)"}},y:{ticks:{color:"#94a3b8",font:{size:10},callback:s=>`${s}ms`},grid:{color:"rgba(71, 85, 105, 0.3)"}}}},f=p(()=>o.value.length>0);return(s,t)=>(d(),c("div",Z,[l("h3",tt,m(s.$t("cost.percentiles.latencyTitle")),1),f.value?(d(),c("div",et,[_(y(O),{data:a.value,options:r},null,8,["data"])])):(d(),c("p",st,m(s.$t("cost.percentiles.noData")),1))]))}}),at={class:"rounded-lg border border-border-default bg-surface-raised p-4"},nt={class:"mb-3 text-sm font-medium text-text-secondary"},rt={key:0,class:"h-48"},lt={key:1,class:"py-6 text-center text-xs text-text-muted"},it=x({__name:"TtftPercentilesChart",setup(u){v.register(R,D,T,L,$,k,C,H);const n=S(),o=p(()=>{const s=n.metricsHistory.map(t=>({timestamp:t.startedAt,value:t.ttftMs}));return V(s)}),a=p(()=>({labels:o.value.map(s=>s.label),datasets:[{label:"P50",data:o.value.map(s=>s.p50),borderColor:"#34d399",backgroundColor:"transparent",borderWidth:1.5,pointRadius:2,tension:.3},{label:"P95",data:o.value.map(s=>s.p95),borderColor:"#fbbf24",backgroundColor:"transparent",borderWidth:1.5,pointRadius:2,tension:.3},{label:"P99",data:o.value.map(s=>s.p99),borderColor:"#ef4444",backgroundColor:"transparent",borderWidth:1.5,pointRadius:2,tension:.3}]})),r={responsive:!0,maintainAspectRatio:!1,interaction:{mode:"index",intersect:!1},plugins:{legend:{position:"bottom",labels:{color:"#94a3b8",font:{size:10},usePointStyle:!0,pointStyle:"line"}},tooltip:{callbacks:{label:s=>`${s.dataset.label??""}: ${(s.parsed.y??0).toFixed(0)}ms`}}},scales:{x:{ticks:{color:"#94a3b8",font:{size:10},maxRotation:45},grid:{color:"rgba(71, 85, 105, 0.3)"}},y:{ticks:{color:"#94a3b8",font:{size:10},callback:s=>`${s}ms`},grid:{color:"rgba(71, 85, 105, 0.3)"}}}},f=p(()=>o.value.length>0);return(s,t)=>(d(),c("div",at,[l("h3",nt,m(s.$t("cost.percentiles.ttftTitle")),1),f.value?(d(),c("div",rt,[_(y(O),{data:a.value,options:r},null,8,["data"])])):(d(),c("p",lt,m(s.$t("cost.percentiles.noData")),1))]))}}),ct={class:"rounded-lg border border-border-default bg-surface-raised p-4"},dt={class:"mb-3 text-sm font-medium text-text-secondary"},ut={class:"h-48"},mt={class:"mt-2 text-[10px] text-text-muted"},pt={key:1,class:"py-6 text-center text-xs text-text-muted"},bt=x({__name:"InterTokenLatencyHistogram",setup(u){v.register(R,D,F,$,k,C);const n=S(),o=[10,25,50,75,100,150,200,300,400,500,750,1e3],a=p(()=>{const t=[];for(const b of n.metricsHistory)for(const g of b.tokenLatencies)t.push(g);if(t.length===0)return null;const e=new Array(o.length+1).fill(0);for(const b of t){let g=!1;for(let h=0;h<o.length;h++)if(b<=o[h]){e[h]++,g=!0;break}g||e[o.length]++}const i=o.map((b,g)=>g===0?`0-${b}`:`${o[g-1]}-${b}`);return i.push(`>${o[o.length-1]}`),{labels:i,counts:e,total:t.length}}),r=p(()=>a.value?{labels:a.value.labels,datasets:[{label:"Tokens",data:a.value.counts,backgroundColor:"#818cf8"}]}:{labels:[],datasets:[]}),f={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1},tooltip:{callbacks:{label:t=>{const e=t.parsed.y??0,i=a.value?.total??1;return`${e} tokens (${(e/i*100).toFixed(1)}%)`}}}},scales:{x:{ticks:{color:"#94a3b8",font:{size:9},maxRotation:45},grid:{display:!1},title:{display:!0,text:"ms",color:"#94a3b8",font:{size:10}}},y:{ticks:{color:"#94a3b8",font:{size:10}},grid:{color:"rgba(71, 85, 105, 0.3)"},title:{display:!0,text:"Count",color:"#94a3b8",font:{size:10}}}}},s=p(()=>a.value!==null);return(t,e)=>(d(),c("div",ct,[l("h3",dt,m(t.$t("cost.percentiles.histogramTitle")),1),s.value?(d(),c(w,{key:0},[l("div",ut,[_(y(B),{data:r.value,options:f},null,8,["data"])]),l("p",mt,m(t.$t("cost.percentiles.histogramHint")),1)],64)):(d(),c("p",pt,m(t.$t("cost.percentiles.noData")),1))]))}}),ft={class:"rounded-lg border border-border-default bg-surface-raised p-4"},gt={class:"mb-3 flex items-center justify-between"},_t={class:"text-sm font-medium text-text-secondary"},ht={key:0,class:"rounded-full bg-warning/15 px-2 py-0.5 text-[9px] font-medium text-warning"},xt={class:"h-48"},yt={class:"mt-2 text-[10px] text-text-muted"},vt={key:1,class:"py-6 text-center text-xs text-text-muted"},$t=500,kt=x({__name:"LoadDurationTrendChart",setup(u){v.register(R,D,T,L,$,k,C,H);const n=S(),o=p(()=>n.metricsHistory.slice(-50).map(e=>({label:new Date(e.startedAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}),loadMs:e.loadDurationMs,model:e.model,isCold:e.loadDurationMs>$t}))),a=p(()=>({labels:o.value.map(t=>t.label),datasets:[{label:"Load Duration (ms)",data:o.value.map(t=>t.loadMs),borderColor:"#a855f7",backgroundColor:"rgba(168, 85, 247, 0.1)",fill:!0,tension:.3,pointBackgroundColor:o.value.map(t=>t.isCold?"#f97316":"#a855f7"),pointRadius:o.value.map(t=>t.isCold?4:2)}]})),r={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1},tooltip:{callbacks:{label:t=>{const e=o.value[t.dataIndex],i=t.parsed.y??0;return`${e?.model??""}: ${i.toFixed(0)}ms${e?.isCold?" (cold start)":""}`}}}},scales:{x:{ticks:{color:"#94a3b8",font:{size:10},maxRotation:45},grid:{color:"rgba(71, 85, 105, 0.3)"}},y:{ticks:{color:"#94a3b8",font:{size:10},callback:t=>`${t}ms`},grid:{color:"rgba(71, 85, 105, 0.3)"}}}},f=p(()=>o.value.length>0),s=p(()=>o.value.filter(t=>t.isCold).length);return(t,e)=>(d(),c("div",ft,[l("div",gt,[l("h3",_t,m(t.$t("cost.loadDuration.title")),1),s.value>0?(d(),c("span",ht,m(s.value)+" "+m(t.$t("cost.loadDuration.coldStarts")),1)):U("",!0)]),f.value?(d(),c(w,{key:0},[l("div",xt,[_(y(O),{data:a.value,options:r},null,8,["data"])]),l("p",yt,m(t.$t("cost.loadDuration.hint")),1)],64)):(d(),c("p",vt,m(t.$t("cost.loadDuration.noData")),1))]))}}),Ct=[[/connection refused|ECONNREFUSED|fetch failed|network error|Failed to fetch/i,"connection","Connection refused"],[/timed?\s*out|ETIMEDOUT|deadline exceeded/i,"timeout","Timeout"],[/model.*not found|no such model|unknown model|pull.*first/i,"model_not_found","Model not found"],[/context length|context window|too long|maximum context|num_ctx/i,"context_exceeded","Context exceeded"],[/out of memory|OOM|CUDA.*memory|not enough memory|VRAM/i,"oom","Out of memory"],[/cancel|abort/i,"cancelled","Cancelled"],[/tool.*no implementation|tool.*failed|tool.*error/i,"tool_error","Tool error"]];function j(u){for(const[n,o,a]of Ct)if(n.test(u))return{category:o,label:a,original:u};return{category:"unknown",label:"Unknown error",original:u}}const Dt={connection:"#ef4444",timeout:"#f97316",model_not_found:"#eab308",context_exceeded:"#a855f7",oom:"#dc2626",cancelled:"#6b7280",tool_error:"#f472b6",unknown:"#94a3b8"},St={class:"rounded-lg border border-border-default bg-surface-raised p-4"},wt={class:"mb-3 text-sm font-medium text-text-secondary"},Rt={key:1,class:"py-6 text-center text-xs text-text-muted"},Mt=x({__name:"ErrorRateByModelChart",setup(u){v.register(R,D,F,$,k,C);const n=W(),o=p(()=>{const e=new Map;for(const i of n.sessions.values()){const b=i.model,g=e.get(b)??{total:0,errors:0,byCategory:{}};if(g.total++,i.status==="error"&&i.error){g.errors++;const{category:h}=j(i.error);g.byCategory[h]=(g.byCategory[h]??0)+1}e.set(b,g)}return[...e.entries()].map(([i,b])=>({model:i,...b,rate:b.total>0?b.errors/b.total:0})).filter(i=>i.total>0).sort((i,b)=>b.rate-i.rate)}),a=["connection","timeout","model_not_found","context_exceeded","oom","tool_error","cancelled","unknown"],r={connection:"Connection",timeout:"Timeout",model_not_found:"Not found",context_exceeded:"Context exceeded",oom:"Out of memory",tool_error:"Tool error",cancelled:"Cancelled",unknown:"Unknown"},f=p(()=>({labels:o.value.map(e=>e.model),datasets:a.filter(e=>o.value.some(i=>(i.byCategory[e]??0)>0)).map(e=>({label:r[e],data:o.value.map(i=>i.byCategory[e]??0),backgroundColor:Dt[e]}))})),s={indexAxis:"y",responsive:!0,maintainAspectRatio:!1,plugins:{legend:{position:"bottom",labels:{color:"#94a3b8",font:{size:10}}}},scales:{x:{stacked:!0,ticks:{color:"#94a3b8",font:{size:10},stepSize:1},grid:{color:"rgba(71, 85, 105, 0.3)"}},y:{stacked:!0,ticks:{color:"#94a3b8",font:{size:11}},grid:{display:!1}}}},t=p(()=>o.value.some(e=>e.errors>0));return(e,i)=>(d(),c("div",St,[l("h3",wt,m(e.$t("cost.errors.title")),1),t.value?(d(),c("div",{key:0,style:J({height:Math.max(100,o.value.length*36)+"px"})},[_(y(B),{data:f.value,options:s},null,8,["data"])],4)):(d(),c("p",Rt,m(e.$t("cost.errors.noErrors")),1))]))}}),Tt={class:"rounded-lg border border-border-default bg-surface-raised p-4"},zt={class:"mb-3 text-sm font-medium text-text-secondary"},At={key:0,class:"h-48"},Lt={key:1,class:"py-6 text-center text-xs text-text-muted"},Ot=x({__name:"ErrorTimelineChart",setup(u){v.register(R,D,T,L,$,k,C);const n=W(),o=p(()=>{const t=[];for(const e of n.sessions.values())if(e.status==="error"&&e.error){const{category:i,label:b}=j(e.error);t.push({date:new Date(e.createdAt).toISOString().slice(0,10),category:i,model:e.model,error:b})}return t.sort((e,i)=>e.date.localeCompare(i.date))}),a=p(()=>{const t=new Map;for(const e of o.value)t.set(e.date,(t.get(e.date)??0)+1);return[...t.entries()].sort((e,i)=>e[0].localeCompare(i[0]))}),r=p(()=>({labels:a.value.map(([t])=>t),datasets:[{label:"Errors",data:a.value.map(([,t])=>t),borderColor:"#ef4444",backgroundColor:"rgba(239, 68, 68, 0.1)",fill:!0,tension:.3,pointRadius:3}]})),f={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1}},scales:{x:{ticks:{color:"#94a3b8",font:{size:10}},grid:{color:"rgba(71, 85, 105, 0.3)"}},y:{ticks:{color:"#94a3b8",font:{size:10},stepSize:1},grid:{color:"rgba(71, 85, 105, 0.3)"}}}},s=p(()=>a.value.length>0);return(t,e)=>(d(),c("div",Tt,[l("h3",zt,m(t.$t("analytics.errors.timelineTitle")),1),s.value?(d(),c("div",At,[_(y(O),{data:r.value,options:f},null,8,["data"])])):(d(),c("p",Lt,m(t.$t("analytics.errors.noErrors")),1))]))}}),Et={class:"rounded-lg border border-border-default bg-surface-raised p-4"},Ht={class:"mb-3 text-sm font-medium text-text-secondary"},Pt={key:0,class:"h-48"},qt={key:1,class:"py-6 text-center text-xs text-text-muted"},Ft=x({__name:"RequestVolumeChart",setup(u){v.register(R,D,F,$,k,C);const n=S(),o=p(()=>{const s=new Map;for(const t of n.metricsHistory){const e=new Date(t.startedAt).toISOString().slice(0,10);s.set(e,(s.get(e)??0)+1)}return[...s.entries()].sort((t,e)=>t[0].localeCompare(e[0]))}),a=p(()=>({labels:o.value.map(([s])=>s),datasets:[{label:"Requests",data:o.value.map(([,s])=>s),backgroundColor:"#818cf8"}]})),r={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1}},scales:{x:{ticks:{color:"#94a3b8",font:{size:10}},grid:{display:!1}},y:{ticks:{color:"#94a3b8",font:{size:10},stepSize:1},grid:{color:"rgba(71, 85, 105, 0.3)"}}}},f=p(()=>o.value.length>0);return(s,t)=>(d(),c("div",Et,[l("h3",Ht,m(s.$t("analytics.usage.requestVolume")),1),f.value?(d(),c("div",Pt,[_(y(B),{data:a.value,options:r},null,8,["data"])])):(d(),c("p",qt,m(s.$t("analytics.usage.noData")),1))]))}}),Bt={class:"rounded-lg border border-border-default bg-surface-raised p-4"},Wt={class:"mb-3 text-sm font-medium text-text-secondary"},It={key:0,class:"h-48"},Nt={key:1,class:"py-6 text-center text-xs text-text-muted"},Ut=x({__name:"ModelDistributionChart",setup(u){v.register(K,$,k,C);const n=S(),o=["#818cf8","#a855f7","#34d399","#fbbf24","#f472b6","#fb923c","#60a5fa","#c084fc"],a=p(()=>{const t=new Map;for(const e of n.metricsHistory)t.set(e.model,(t.get(e.model)??0)+1);return[...t.entries()].sort((e,i)=>i[1]-e[1])}),r=p(()=>({labels:a.value.map(([t])=>t),datasets:[{data:a.value.map(([,t])=>t),backgroundColor:a.value.map((t,e)=>o[e%o.length]),borderWidth:0}]})),f={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{position:"right",labels:{color:"#94a3b8",font:{size:10},padding:12}}}},s=p(()=>a.value.length>0);return(t,e)=>(d(),c("div",Bt,[l("h3",Wt,m(t.$t("analytics.usage.modelDistribution")),1),s.value?(d(),c("div",It,[_(y(Y),{data:r.value,options:f},null,8,["data"])])):(d(),c("p",Nt,m(t.$t("analytics.usage.noData")),1))]))}}),Vt={class:"rounded-lg border border-border-default bg-surface-raised p-4"},jt={class:"mb-3 text-sm font-medium text-text-secondary"},Qt={key:0,class:"overflow-x-auto"},Kt={class:"min-w-[600px]"},Yt={class:"flex items-center"},Gt={class:"w-10 shrink-0 text-[10px] text-text-muted"},Jt=["title"],Xt={key:1,class:"py-6 text-center text-xs text-text-muted"},Zt=x({__name:"ActiveHoursHeatmap",setup(u){const n=S(),o=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],a=Array.from({length:24},(t,e)=>e),r=p(()=>{const t=Array.from({length:7},()=>new Array(24).fill(0));let e=0;for(const i of n.metricsHistory){const b=new Date(i.startedAt),g=(b.getDay()+6)%7,h=b.getHours();t[g][h]++,t[g][h]>e&&(e=t[g][h])}return{counts:t,max:e}});function f(t){if(t===0)return"bg-surface-overlay/30";const e=r.value.max>0?t/r.value.max:0;return e>.75?"bg-accent":e>.5?"bg-accent/70":e>.25?"bg-accent/40":"bg-accent/20"}const s=p(()=>n.metricsHistory.length>0);return(t,e)=>(d(),c("div",Vt,[l("h3",jt,m(t.$t("analytics.usage.activeHours")),1),s.value?(d(),c("div",Qt,[l("div",Kt,[l("div",Yt,[e[0]||(e[0]=l("div",{class:"w-10 shrink-0"},null,-1)),(d(!0),c(w,null,E(y(a),i=>(d(),c("div",{key:i,class:"flex-1 text-center text-[8px] text-text-muted"},m(i),1))),128))]),(d(),c(w,null,E(o,(i,b)=>l("div",{key:i,class:"flex items-center gap-0.5 mt-0.5"},[l("div",Gt,m(i),1),(d(!0),c(w,null,E(y(a),g=>(d(),c("div",{key:g,class:q(["flex-1 aspect-square rounded-sm transition-colors",f(r.value.counts[b][g])]),title:`${i} ${g}:00 — ${r.value.counts[b][g]} requests`},null,10,Jt))),128))])),64))])])):(d(),c("p",Xt,m(t.$t("analytics.usage.noData")),1))]))}}),te={class:"rounded-lg border border-border-default bg-surface-raised p-4"},ee={class:"mb-3 text-sm font-medium text-text-secondary"},se={class:"h-48"},oe={class:"mt-2 text-[10px] text-text-muted"},ae={key:1,class:"py-6 text-center text-xs text-text-muted"},ne=x({__name:"SettingsImpactScatter",setup(u){v.register(D,T,$,k,C);const n=W(),o=S(),a=p(()=>{const t=[];for(const e of n.sessions.values()){const i=e.options?.temperature;if(i===void 0)continue;const b=o.getMetrics(e.id);b&&t.push({x:i,y:b.tokensPerSecond,model:e.model})}return t}),r=p(()=>({datasets:[{label:"Temperature vs Speed",data:a.value.map(t=>({x:t.x,y:t.y})),backgroundColor:"#818cf880",borderColor:"#818cf8",pointRadius:5}]})),f={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1},tooltip:{callbacks:{label:t=>`${a.value[t.dataIndex]?.model??""}: temp=${(t.parsed.x??0).toFixed(1)} → ${(t.parsed.y??0).toFixed(1)} tok/s`}}},scales:{x:{title:{display:!0,text:"Temperature",color:"#94a3b8",font:{size:10}},ticks:{color:"#94a3b8",font:{size:10}},grid:{color:"rgba(71, 85, 105, 0.3)"}},y:{title:{display:!0,text:"Tokens/sec",color:"#94a3b8",font:{size:10}},ticks:{color:"#94a3b8",font:{size:10}},grid:{color:"rgba(71, 85, 105, 0.3)"}}}},s=p(()=>a.value.length>=2);return(t,e)=>(d(),c("div",te,[l("h3",ee,m(t.$t("analytics.settings.title")),1),s.value?(d(),c(w,{key:0},[l("div",se,[_(y(G),{data:r.value,options:f},null,8,["data"])]),l("p",oe,m(t.$t("analytics.settings.hint")),1)],64)):(d(),c("p",ae,m(t.$t("analytics.settings.noData")),1))]))}}),re={class:"rounded-lg border border-border-default bg-surface-raised p-4"},le={class:"mb-3 text-sm font-medium text-text-secondary"},ie={key:0,class:"max-h-64 overflow-y-auto"},ce={class:"text-[10px] text-text-muted w-14 shrink-0"},de={class:"text-xs text-text-primary truncate flex-1"},ue={key:0,class:"rounded-full bg-warning/15 px-1.5 py-0.5 text-[8px] font-medium text-warning shrink-0"},me={key:1,class:"py-6 text-center text-xs text-text-muted"},pe=500,be=x({__name:"ModelLoadHistory",setup(u){const n=S(),o=p(()=>n.metricsHistory.slice(-30).map(r=>({time:new Date(r.startedAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}),date:new Date(r.startedAt).toLocaleDateString(),model:r.model,loadMs:r.loadDurationMs,isCold:r.loadDurationMs>pe}))),a=p(()=>o.value.length>0);return(r,f)=>(d(),c("div",re,[l("h3",le,m(r.$t("analytics.modelLoad.title")),1),a.value?(d(),c("div",ie,[(d(!0),c(w,null,E(o.value,(s,t)=>(d(),c("div",{key:t,class:"flex items-center gap-3 border-b border-border-default/30 py-1.5 last:border-0"},[l("div",{class:q(["h-2 w-2 shrink-0 rounded-full",s.isCold?"bg-warning":"bg-success"])},null,2),l("span",ce,m(s.time),1),l("span",de,m(s.model),1),l("span",{class:q(["text-[10px] font-mono shrink-0",s.isCold?"text-warning":"text-text-muted"])},m(s.loadMs.toFixed(0))+"ms ",3),s.isCold?(d(),c("span",ue,m(r.$t("analytics.modelLoad.cold")),1)):U("",!0)]))),128))])):(d(),c("p",me,m(r.$t("analytics.modelLoad.noData")),1))]))}});function fe(u,n){const o=[];for(let a=0;a<=u.length-n;a++)o.push(u.slice(a,a+n).join(" "));return o}function ge(u,n,o){const a=u.trim().split(/\s+/).filter(Boolean),r=a.length,s=u.split(/[.!?]+/).filter(M=>M.trim().length>0).length,t=new Set(a.map(M=>M.toLowerCase())),e=r>0?t.size/r:0;let i=0;if(a.length>=8){const M=fe(a.map(z=>z.toLowerCase()),4);if(M.length>0){const z=new Map;for(const A of M)z.set(A,(z.get(A)??0)+1);let I=0;for(const A of z.values())A>1&&(I+=A);i=I/M.length}}const b=Math.min(r/50,1)*.4,g=e*.3,h=(1-i)*.3,Q=Math.min(5,Math.max(0,(b+g+h)*5));return{turnIndex:n,role:o,wordCount:r,sentenceCount:s,uniqueWordRatio:e,repetitionRatio:i,score:Q}}function _e(u){return u.filter(n=>n.role==="user"||n.role==="assistant").map((n,o)=>ge(n.content.replace(/<think>[\s\S]*?<\/think>/g,"").trim(),o,n.role))}const he={class:"rounded-lg border border-border-default bg-surface-raised p-4"},xe={class:"mb-3 text-sm font-medium text-text-secondary"},ye={class:"h-48"},ve={class:"mt-2 text-[10px] text-text-muted"},$e={key:1,class:"py-6 text-center text-xs text-text-muted"},ke=x({__name:"QualityOverTurnsChart",setup(u){v.register(R,D,T,L,$,k,C,H);const n=X(),o=p(()=>{const t=n.activeConversation;return!t||t.messages.length<2?[]:_e(t.messages)}),a=p(()=>o.value.filter(t=>t.role==="assistant")),r=p(()=>({labels:a.value.map((t,e)=>`Turn ${e+1}`),datasets:[{label:"Quality Score",data:a.value.map(t=>t.score),borderColor:"#818cf8",backgroundColor:"rgba(129, 140, 248, 0.1)",fill:!0,tension:.3,pointBackgroundColor:a.value.map(t=>t.score>=3.5?"#34d399":t.score>=2?"#fbbf24":"#ef4444"),pointRadius:4}]})),f={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1},tooltip:{callbacks:{label:t=>{const e=a.value[t.dataIndex];return`Score: ${(t.parsed.y??0).toFixed(1)}/5 (${e?.wordCount??0} words)`}}}},scales:{x:{ticks:{color:"#94a3b8",font:{size:10}},grid:{color:"rgba(71, 85, 105, 0.3)"}},y:{min:0,max:5,ticks:{color:"#94a3b8",font:{size:10},stepSize:1},grid:{color:"rgba(71, 85, 105, 0.3)"}}}},s=p(()=>a.value.length>=2);return(t,e)=>(d(),c("div",he,[l("h3",xe,m(t.$t("analytics.quality.title")),1),s.value?(d(),c(w,{key:0},[l("div",ye,[_(y(O),{data:r.value,options:f},null,8,["data"])]),l("p",ve,m(t.$t("analytics.quality.hint")),1)],64)):(d(),c("p",$e,m(t.$t("analytics.quality.noData")),1))]))}}),Ce={class:"h-full overflow-y-auto p-6"},De={class:"mb-6 text-lg font-semibold text-text-primary"},Se={class:"mb-8"},we={class:"mb-4 text-sm font-semibold uppercase tracking-wide text-text-muted"},Re={class:"mb-8"},Me={class:"mb-4 text-sm font-semibold uppercase tracking-wide text-text-muted"},Te={class:"grid gap-6 lg:grid-cols-2"},ze={class:"mt-6"},Ae={class:"mb-8"},Le={class:"mb-4 text-sm font-semibold uppercase tracking-wide text-text-muted"},Oe={class:"grid gap-6 lg:grid-cols-2"},Ee={class:"mt-6"},He={class:"mb-8"},Pe={class:"mb-4 text-sm font-semibold uppercase tracking-wide text-text-muted"},qe={class:"grid gap-6 lg:grid-cols-2"},Fe={class:"mt-6"},Be={class:"mb-8"},We={class:"mb-4 text-sm font-semibold uppercase tracking-wide text-text-muted"},Ie={class:"mb-4 text-sm font-semibold uppercase tracking-wide text-text-muted"},Qe=x({__name:"AnalyticsPage",setup(u){return(n,o)=>(d(),c("div",Ce,[l("h1",De,m(n.$t("analytics.title")),1),l("section",Se,[l("h2",we,m(n.$t("analytics.sections.quality")),1),_(ke)]),l("section",Re,[l("h2",Me,m(n.$t("analytics.sections.latency")),1),l("div",Te,[_(ot),_(it)]),l("div",ze,[_(bt)])]),l("section",Ae,[l("h2",Le,m(n.$t("analytics.sections.reliability")),1),l("div",Oe,[_(Mt),_(Ot)]),l("div",Ee,[_(kt)])]),l("section",He,[l("h2",Pe,m(n.$t("analytics.sections.usage")),1),l("div",qe,[_(Ft),_(Ut)]),l("div",Fe,[_(Zt)])]),l("section",Be,[l("h2",We,m(n.$t("analytics.sections.settings")),1),_(ne)]),l("section",null,[l("h2",Ie,m(n.$t("analytics.sections.modelMemory")),1),_(be)])]))}});export{Qe as default};
1
+ import{C as v,a as R,L as D,P as T,b as L,p as $,c as k,d as C,i as H,e as O,B as F,f as B,A as K,D as Y,S as G}from"./index-FRDa6LAg.js";import{u as S}from"./metrics-store-BDn0738m.js";import{b as x,e as c,f as l,t as m,p as _,u as y,a as p,j as d,F as w,i as U,l as J,k as E,g as q,I as X}from"./index-BwnEclbR.js";import{u as W}from"./session-store-DRoQgYmX.js";function P(u,n){if(u.length===0)return 0;const o=n/100*(u.length-1),a=Math.floor(o),r=Math.ceil(o);return a===r?u[a]:u[a]+(u[r]-u[a])*(o-a)}function N(u){const n=[...u].sort((o,a)=>o-a);return{p50:P(n,50),p95:P(n,95),p99:P(n,99)}}function V(u,n=10){if(u.length<n){if(u.length===0)return[];const r=N(u.map(f=>f.value));return[{label:new Date(u[u.length-1].timestamp).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}),...r}]}const o=[],a=Math.max(1,Math.floor(u.length/20));for(let r=n-1;r<u.length;r+=a){const f=u.slice(Math.max(0,r-n+1),r+1),s=N(f.map(t=>t.value));o.push({label:new Date(u[r].timestamp).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}),...s})}return o}const Z={class:"rounded-lg border border-border-default bg-surface-raised p-4"},tt={class:"mb-3 text-sm font-medium text-text-secondary"},et={key:0,class:"h-48"},st={key:1,class:"py-6 text-center text-xs text-text-muted"},ot=x({__name:"LatencyPercentilesChart",setup(u){v.register(R,D,T,L,$,k,C,H);const n=S(),o=p(()=>{const s=n.metricsHistory.map(t=>({timestamp:t.startedAt,value:t.totalDurationMs}));return V(s)}),a=p(()=>({labels:o.value.map(s=>s.label),datasets:[{label:"P50",data:o.value.map(s=>s.p50),borderColor:"#34d399",backgroundColor:"transparent",borderWidth:1.5,pointRadius:2,tension:.3},{label:"P95",data:o.value.map(s=>s.p95),borderColor:"#fbbf24",backgroundColor:"transparent",borderWidth:1.5,pointRadius:2,tension:.3},{label:"P99",data:o.value.map(s=>s.p99),borderColor:"#ef4444",backgroundColor:"transparent",borderWidth:1.5,pointRadius:2,tension:.3}]})),r={responsive:!0,maintainAspectRatio:!1,interaction:{mode:"index",intersect:!1},plugins:{legend:{position:"bottom",labels:{color:"#94a3b8",font:{size:10},usePointStyle:!0,pointStyle:"line"}},tooltip:{callbacks:{label:s=>`${s.dataset.label??""}: ${(s.parsed.y??0).toFixed(0)}ms`}}},scales:{x:{ticks:{color:"#94a3b8",font:{size:10},maxRotation:45},grid:{color:"rgba(71, 85, 105, 0.3)"}},y:{ticks:{color:"#94a3b8",font:{size:10},callback:s=>`${s}ms`},grid:{color:"rgba(71, 85, 105, 0.3)"}}}},f=p(()=>o.value.length>0);return(s,t)=>(d(),c("div",Z,[l("h3",tt,m(s.$t("cost.percentiles.latencyTitle")),1),f.value?(d(),c("div",et,[_(y(O),{data:a.value,options:r},null,8,["data"])])):(d(),c("p",st,m(s.$t("cost.percentiles.noData")),1))]))}}),at={class:"rounded-lg border border-border-default bg-surface-raised p-4"},nt={class:"mb-3 text-sm font-medium text-text-secondary"},rt={key:0,class:"h-48"},lt={key:1,class:"py-6 text-center text-xs text-text-muted"},it=x({__name:"TtftPercentilesChart",setup(u){v.register(R,D,T,L,$,k,C,H);const n=S(),o=p(()=>{const s=n.metricsHistory.map(t=>({timestamp:t.startedAt,value:t.ttftMs}));return V(s)}),a=p(()=>({labels:o.value.map(s=>s.label),datasets:[{label:"P50",data:o.value.map(s=>s.p50),borderColor:"#34d399",backgroundColor:"transparent",borderWidth:1.5,pointRadius:2,tension:.3},{label:"P95",data:o.value.map(s=>s.p95),borderColor:"#fbbf24",backgroundColor:"transparent",borderWidth:1.5,pointRadius:2,tension:.3},{label:"P99",data:o.value.map(s=>s.p99),borderColor:"#ef4444",backgroundColor:"transparent",borderWidth:1.5,pointRadius:2,tension:.3}]})),r={responsive:!0,maintainAspectRatio:!1,interaction:{mode:"index",intersect:!1},plugins:{legend:{position:"bottom",labels:{color:"#94a3b8",font:{size:10},usePointStyle:!0,pointStyle:"line"}},tooltip:{callbacks:{label:s=>`${s.dataset.label??""}: ${(s.parsed.y??0).toFixed(0)}ms`}}},scales:{x:{ticks:{color:"#94a3b8",font:{size:10},maxRotation:45},grid:{color:"rgba(71, 85, 105, 0.3)"}},y:{ticks:{color:"#94a3b8",font:{size:10},callback:s=>`${s}ms`},grid:{color:"rgba(71, 85, 105, 0.3)"}}}},f=p(()=>o.value.length>0);return(s,t)=>(d(),c("div",at,[l("h3",nt,m(s.$t("cost.percentiles.ttftTitle")),1),f.value?(d(),c("div",rt,[_(y(O),{data:a.value,options:r},null,8,["data"])])):(d(),c("p",lt,m(s.$t("cost.percentiles.noData")),1))]))}}),ct={class:"rounded-lg border border-border-default bg-surface-raised p-4"},dt={class:"mb-3 text-sm font-medium text-text-secondary"},ut={class:"h-48"},mt={class:"mt-2 text-[10px] text-text-muted"},pt={key:1,class:"py-6 text-center text-xs text-text-muted"},bt=x({__name:"InterTokenLatencyHistogram",setup(u){v.register(R,D,F,$,k,C);const n=S(),o=[10,25,50,75,100,150,200,300,400,500,750,1e3],a=p(()=>{const t=[];for(const b of n.metricsHistory)for(const g of b.tokenLatencies)t.push(g);if(t.length===0)return null;const e=new Array(o.length+1).fill(0);for(const b of t){let g=!1;for(let h=0;h<o.length;h++)if(b<=o[h]){e[h]++,g=!0;break}g||e[o.length]++}const i=o.map((b,g)=>g===0?`0-${b}`:`${o[g-1]}-${b}`);return i.push(`>${o[o.length-1]}`),{labels:i,counts:e,total:t.length}}),r=p(()=>a.value?{labels:a.value.labels,datasets:[{label:"Tokens",data:a.value.counts,backgroundColor:"#818cf8"}]}:{labels:[],datasets:[]}),f={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1},tooltip:{callbacks:{label:t=>{const e=t.parsed.y??0,i=a.value?.total??1;return`${e} tokens (${(e/i*100).toFixed(1)}%)`}}}},scales:{x:{ticks:{color:"#94a3b8",font:{size:9},maxRotation:45},grid:{display:!1},title:{display:!0,text:"ms",color:"#94a3b8",font:{size:10}}},y:{ticks:{color:"#94a3b8",font:{size:10}},grid:{color:"rgba(71, 85, 105, 0.3)"},title:{display:!0,text:"Count",color:"#94a3b8",font:{size:10}}}}},s=p(()=>a.value!==null);return(t,e)=>(d(),c("div",ct,[l("h3",dt,m(t.$t("cost.percentiles.histogramTitle")),1),s.value?(d(),c(w,{key:0},[l("div",ut,[_(y(B),{data:r.value,options:f},null,8,["data"])]),l("p",mt,m(t.$t("cost.percentiles.histogramHint")),1)],64)):(d(),c("p",pt,m(t.$t("cost.percentiles.noData")),1))]))}}),ft={class:"rounded-lg border border-border-default bg-surface-raised p-4"},gt={class:"mb-3 flex items-center justify-between"},_t={class:"text-sm font-medium text-text-secondary"},ht={key:0,class:"rounded-full bg-warning/15 px-2 py-0.5 text-[9px] font-medium text-warning"},xt={class:"h-48"},yt={class:"mt-2 text-[10px] text-text-muted"},vt={key:1,class:"py-6 text-center text-xs text-text-muted"},$t=500,kt=x({__name:"LoadDurationTrendChart",setup(u){v.register(R,D,T,L,$,k,C,H);const n=S(),o=p(()=>n.metricsHistory.slice(-50).map(e=>({label:new Date(e.startedAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}),loadMs:e.loadDurationMs,model:e.model,isCold:e.loadDurationMs>$t}))),a=p(()=>({labels:o.value.map(t=>t.label),datasets:[{label:"Load Duration (ms)",data:o.value.map(t=>t.loadMs),borderColor:"#a855f7",backgroundColor:"rgba(168, 85, 247, 0.1)",fill:!0,tension:.3,pointBackgroundColor:o.value.map(t=>t.isCold?"#f97316":"#a855f7"),pointRadius:o.value.map(t=>t.isCold?4:2)}]})),r={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1},tooltip:{callbacks:{label:t=>{const e=o.value[t.dataIndex],i=t.parsed.y??0;return`${e?.model??""}: ${i.toFixed(0)}ms${e?.isCold?" (cold start)":""}`}}}},scales:{x:{ticks:{color:"#94a3b8",font:{size:10},maxRotation:45},grid:{color:"rgba(71, 85, 105, 0.3)"}},y:{ticks:{color:"#94a3b8",font:{size:10},callback:t=>`${t}ms`},grid:{color:"rgba(71, 85, 105, 0.3)"}}}},f=p(()=>o.value.length>0),s=p(()=>o.value.filter(t=>t.isCold).length);return(t,e)=>(d(),c("div",ft,[l("div",gt,[l("h3",_t,m(t.$t("cost.loadDuration.title")),1),s.value>0?(d(),c("span",ht,m(s.value)+" "+m(t.$t("cost.loadDuration.coldStarts")),1)):U("",!0)]),f.value?(d(),c(w,{key:0},[l("div",xt,[_(y(O),{data:a.value,options:r},null,8,["data"])]),l("p",yt,m(t.$t("cost.loadDuration.hint")),1)],64)):(d(),c("p",vt,m(t.$t("cost.loadDuration.noData")),1))]))}}),Ct=[[/connection refused|ECONNREFUSED|fetch failed|network error|Failed to fetch/i,"connection","Connection refused"],[/timed?\s*out|ETIMEDOUT|deadline exceeded/i,"timeout","Timeout"],[/model.*not found|no such model|unknown model|pull.*first/i,"model_not_found","Model not found"],[/context length|context window|too long|maximum context|num_ctx/i,"context_exceeded","Context exceeded"],[/out of memory|OOM|CUDA.*memory|not enough memory|VRAM/i,"oom","Out of memory"],[/cancel|abort/i,"cancelled","Cancelled"],[/tool.*no implementation|tool.*failed|tool.*error/i,"tool_error","Tool error"]];function j(u){for(const[n,o,a]of Ct)if(n.test(u))return{category:o,label:a,original:u};return{category:"unknown",label:"Unknown error",original:u}}const Dt={connection:"#ef4444",timeout:"#f97316",model_not_found:"#eab308",context_exceeded:"#a855f7",oom:"#dc2626",cancelled:"#6b7280",tool_error:"#f472b6",unknown:"#94a3b8"},St={class:"rounded-lg border border-border-default bg-surface-raised p-4"},wt={class:"mb-3 text-sm font-medium text-text-secondary"},Rt={key:1,class:"py-6 text-center text-xs text-text-muted"},Mt=x({__name:"ErrorRateByModelChart",setup(u){v.register(R,D,F,$,k,C);const n=W(),o=p(()=>{const e=new Map;for(const i of n.sessions.values()){const b=i.model,g=e.get(b)??{total:0,errors:0,byCategory:{}};if(g.total++,i.status==="error"&&i.error){g.errors++;const{category:h}=j(i.error);g.byCategory[h]=(g.byCategory[h]??0)+1}e.set(b,g)}return[...e.entries()].map(([i,b])=>({model:i,...b,rate:b.total>0?b.errors/b.total:0})).filter(i=>i.total>0).sort((i,b)=>b.rate-i.rate)}),a=["connection","timeout","model_not_found","context_exceeded","oom","tool_error","cancelled","unknown"],r={connection:"Connection",timeout:"Timeout",model_not_found:"Not found",context_exceeded:"Context exceeded",oom:"Out of memory",tool_error:"Tool error",cancelled:"Cancelled",unknown:"Unknown"},f=p(()=>({labels:o.value.map(e=>e.model),datasets:a.filter(e=>o.value.some(i=>(i.byCategory[e]??0)>0)).map(e=>({label:r[e],data:o.value.map(i=>i.byCategory[e]??0),backgroundColor:Dt[e]}))})),s={indexAxis:"y",responsive:!0,maintainAspectRatio:!1,plugins:{legend:{position:"bottom",labels:{color:"#94a3b8",font:{size:10}}}},scales:{x:{stacked:!0,ticks:{color:"#94a3b8",font:{size:10},stepSize:1},grid:{color:"rgba(71, 85, 105, 0.3)"}},y:{stacked:!0,ticks:{color:"#94a3b8",font:{size:11}},grid:{display:!1}}}},t=p(()=>o.value.some(e=>e.errors>0));return(e,i)=>(d(),c("div",St,[l("h3",wt,m(e.$t("cost.errors.title")),1),t.value?(d(),c("div",{key:0,style:J({height:Math.max(100,o.value.length*36)+"px"})},[_(y(B),{data:f.value,options:s},null,8,["data"])],4)):(d(),c("p",Rt,m(e.$t("cost.errors.noErrors")),1))]))}}),Tt={class:"rounded-lg border border-border-default bg-surface-raised p-4"},zt={class:"mb-3 text-sm font-medium text-text-secondary"},At={key:0,class:"h-48"},Lt={key:1,class:"py-6 text-center text-xs text-text-muted"},Ot=x({__name:"ErrorTimelineChart",setup(u){v.register(R,D,T,L,$,k,C);const n=W(),o=p(()=>{const t=[];for(const e of n.sessions.values())if(e.status==="error"&&e.error){const{category:i,label:b}=j(e.error);t.push({date:new Date(e.createdAt).toISOString().slice(0,10),category:i,model:e.model,error:b})}return t.sort((e,i)=>e.date.localeCompare(i.date))}),a=p(()=>{const t=new Map;for(const e of o.value)t.set(e.date,(t.get(e.date)??0)+1);return[...t.entries()].sort((e,i)=>e[0].localeCompare(i[0]))}),r=p(()=>({labels:a.value.map(([t])=>t),datasets:[{label:"Errors",data:a.value.map(([,t])=>t),borderColor:"#ef4444",backgroundColor:"rgba(239, 68, 68, 0.1)",fill:!0,tension:.3,pointRadius:3}]})),f={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1}},scales:{x:{ticks:{color:"#94a3b8",font:{size:10}},grid:{color:"rgba(71, 85, 105, 0.3)"}},y:{ticks:{color:"#94a3b8",font:{size:10},stepSize:1},grid:{color:"rgba(71, 85, 105, 0.3)"}}}},s=p(()=>a.value.length>0);return(t,e)=>(d(),c("div",Tt,[l("h3",zt,m(t.$t("analytics.errors.timelineTitle")),1),s.value?(d(),c("div",At,[_(y(O),{data:r.value,options:f},null,8,["data"])])):(d(),c("p",Lt,m(t.$t("analytics.errors.noErrors")),1))]))}}),Et={class:"rounded-lg border border-border-default bg-surface-raised p-4"},Ht={class:"mb-3 text-sm font-medium text-text-secondary"},Pt={key:0,class:"h-48"},qt={key:1,class:"py-6 text-center text-xs text-text-muted"},Ft=x({__name:"RequestVolumeChart",setup(u){v.register(R,D,F,$,k,C);const n=S(),o=p(()=>{const s=new Map;for(const t of n.metricsHistory){const e=new Date(t.startedAt).toISOString().slice(0,10);s.set(e,(s.get(e)??0)+1)}return[...s.entries()].sort((t,e)=>t[0].localeCompare(e[0]))}),a=p(()=>({labels:o.value.map(([s])=>s),datasets:[{label:"Requests",data:o.value.map(([,s])=>s),backgroundColor:"#818cf8"}]})),r={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1}},scales:{x:{ticks:{color:"#94a3b8",font:{size:10}},grid:{display:!1}},y:{ticks:{color:"#94a3b8",font:{size:10},stepSize:1},grid:{color:"rgba(71, 85, 105, 0.3)"}}}},f=p(()=>o.value.length>0);return(s,t)=>(d(),c("div",Et,[l("h3",Ht,m(s.$t("analytics.usage.requestVolume")),1),f.value?(d(),c("div",Pt,[_(y(B),{data:a.value,options:r},null,8,["data"])])):(d(),c("p",qt,m(s.$t("analytics.usage.noData")),1))]))}}),Bt={class:"rounded-lg border border-border-default bg-surface-raised p-4"},Wt={class:"mb-3 text-sm font-medium text-text-secondary"},It={key:0,class:"h-48"},Nt={key:1,class:"py-6 text-center text-xs text-text-muted"},Ut=x({__name:"ModelDistributionChart",setup(u){v.register(K,$,k,C);const n=S(),o=["#818cf8","#a855f7","#34d399","#fbbf24","#f472b6","#fb923c","#60a5fa","#c084fc"],a=p(()=>{const t=new Map;for(const e of n.metricsHistory)t.set(e.model,(t.get(e.model)??0)+1);return[...t.entries()].sort((e,i)=>i[1]-e[1])}),r=p(()=>({labels:a.value.map(([t])=>t),datasets:[{data:a.value.map(([,t])=>t),backgroundColor:a.value.map((t,e)=>o[e%o.length]),borderWidth:0}]})),f={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{position:"right",labels:{color:"#94a3b8",font:{size:10},padding:12}}}},s=p(()=>a.value.length>0);return(t,e)=>(d(),c("div",Bt,[l("h3",Wt,m(t.$t("analytics.usage.modelDistribution")),1),s.value?(d(),c("div",It,[_(y(Y),{data:r.value,options:f},null,8,["data"])])):(d(),c("p",Nt,m(t.$t("analytics.usage.noData")),1))]))}}),Vt={class:"rounded-lg border border-border-default bg-surface-raised p-4"},jt={class:"mb-3 text-sm font-medium text-text-secondary"},Qt={key:0,class:"overflow-x-auto"},Kt={class:"min-w-[600px]"},Yt={class:"flex items-center"},Gt={class:"w-10 shrink-0 text-[10px] text-text-muted"},Jt=["title"],Xt={key:1,class:"py-6 text-center text-xs text-text-muted"},Zt=x({__name:"ActiveHoursHeatmap",setup(u){const n=S(),o=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],a=Array.from({length:24},(t,e)=>e),r=p(()=>{const t=Array.from({length:7},()=>new Array(24).fill(0));let e=0;for(const i of n.metricsHistory){const b=new Date(i.startedAt),g=(b.getDay()+6)%7,h=b.getHours();t[g][h]++,t[g][h]>e&&(e=t[g][h])}return{counts:t,max:e}});function f(t){if(t===0)return"bg-surface-overlay/30";const e=r.value.max>0?t/r.value.max:0;return e>.75?"bg-accent":e>.5?"bg-accent/70":e>.25?"bg-accent/40":"bg-accent/20"}const s=p(()=>n.metricsHistory.length>0);return(t,e)=>(d(),c("div",Vt,[l("h3",jt,m(t.$t("analytics.usage.activeHours")),1),s.value?(d(),c("div",Qt,[l("div",Kt,[l("div",Yt,[e[0]||(e[0]=l("div",{class:"w-10 shrink-0"},null,-1)),(d(!0),c(w,null,E(y(a),i=>(d(),c("div",{key:i,class:"flex-1 text-center text-[8px] text-text-muted"},m(i),1))),128))]),(d(),c(w,null,E(o,(i,b)=>l("div",{key:i,class:"flex items-center gap-0.5 mt-0.5"},[l("div",Gt,m(i),1),(d(!0),c(w,null,E(y(a),g=>(d(),c("div",{key:g,class:q(["flex-1 aspect-square rounded-sm transition-colors",f(r.value.counts[b][g])]),title:`${i} ${g}:00 — ${r.value.counts[b][g]} requests`},null,10,Jt))),128))])),64))])])):(d(),c("p",Xt,m(t.$t("analytics.usage.noData")),1))]))}}),te={class:"rounded-lg border border-border-default bg-surface-raised p-4"},ee={class:"mb-3 text-sm font-medium text-text-secondary"},se={class:"h-48"},oe={class:"mt-2 text-[10px] text-text-muted"},ae={key:1,class:"py-6 text-center text-xs text-text-muted"},ne=x({__name:"SettingsImpactScatter",setup(u){v.register(D,T,$,k,C);const n=W(),o=S(),a=p(()=>{const t=[];for(const e of n.sessions.values()){const i=e.options?.temperature;if(i===void 0)continue;const b=o.getMetrics(e.id);b&&t.push({x:i,y:b.tokensPerSecond,model:e.model})}return t}),r=p(()=>({datasets:[{label:"Temperature vs Speed",data:a.value.map(t=>({x:t.x,y:t.y})),backgroundColor:"#818cf880",borderColor:"#818cf8",pointRadius:5}]})),f={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1},tooltip:{callbacks:{label:t=>`${a.value[t.dataIndex]?.model??""}: temp=${(t.parsed.x??0).toFixed(1)} → ${(t.parsed.y??0).toFixed(1)} tok/s`}}},scales:{x:{title:{display:!0,text:"Temperature",color:"#94a3b8",font:{size:10}},ticks:{color:"#94a3b8",font:{size:10}},grid:{color:"rgba(71, 85, 105, 0.3)"}},y:{title:{display:!0,text:"Tokens/sec",color:"#94a3b8",font:{size:10}},ticks:{color:"#94a3b8",font:{size:10}},grid:{color:"rgba(71, 85, 105, 0.3)"}}}},s=p(()=>a.value.length>=2);return(t,e)=>(d(),c("div",te,[l("h3",ee,m(t.$t("analytics.settings.title")),1),s.value?(d(),c(w,{key:0},[l("div",se,[_(y(G),{data:r.value,options:f},null,8,["data"])]),l("p",oe,m(t.$t("analytics.settings.hint")),1)],64)):(d(),c("p",ae,m(t.$t("analytics.settings.noData")),1))]))}}),re={class:"rounded-lg border border-border-default bg-surface-raised p-4"},le={class:"mb-3 text-sm font-medium text-text-secondary"},ie={key:0,class:"max-h-64 overflow-y-auto"},ce={class:"text-[10px] text-text-muted w-14 shrink-0"},de={class:"text-xs text-text-primary truncate flex-1"},ue={key:0,class:"rounded-full bg-warning/15 px-1.5 py-0.5 text-[8px] font-medium text-warning shrink-0"},me={key:1,class:"py-6 text-center text-xs text-text-muted"},pe=500,be=x({__name:"ModelLoadHistory",setup(u){const n=S(),o=p(()=>n.metricsHistory.slice(-30).map(r=>({time:new Date(r.startedAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}),date:new Date(r.startedAt).toLocaleDateString(),model:r.model,loadMs:r.loadDurationMs,isCold:r.loadDurationMs>pe}))),a=p(()=>o.value.length>0);return(r,f)=>(d(),c("div",re,[l("h3",le,m(r.$t("analytics.modelLoad.title")),1),a.value?(d(),c("div",ie,[(d(!0),c(w,null,E(o.value,(s,t)=>(d(),c("div",{key:t,class:"flex items-center gap-3 border-b border-border-default/30 py-1.5 last:border-0"},[l("div",{class:q(["h-2 w-2 shrink-0 rounded-full",s.isCold?"bg-warning":"bg-success"])},null,2),l("span",ce,m(s.time),1),l("span",de,m(s.model),1),l("span",{class:q(["text-[10px] font-mono shrink-0",s.isCold?"text-warning":"text-text-muted"])},m(s.loadMs.toFixed(0))+"ms ",3),s.isCold?(d(),c("span",ue,m(r.$t("analytics.modelLoad.cold")),1)):U("",!0)]))),128))])):(d(),c("p",me,m(r.$t("analytics.modelLoad.noData")),1))]))}});function fe(u,n){const o=[];for(let a=0;a<=u.length-n;a++)o.push(u.slice(a,a+n).join(" "));return o}function ge(u,n,o){const a=u.trim().split(/\s+/).filter(Boolean),r=a.length,s=u.split(/[.!?]+/).filter(M=>M.trim().length>0).length,t=new Set(a.map(M=>M.toLowerCase())),e=r>0?t.size/r:0;let i=0;if(a.length>=8){const M=fe(a.map(z=>z.toLowerCase()),4);if(M.length>0){const z=new Map;for(const A of M)z.set(A,(z.get(A)??0)+1);let I=0;for(const A of z.values())A>1&&(I+=A);i=I/M.length}}const b=Math.min(r/50,1)*.4,g=e*.3,h=(1-i)*.3,Q=Math.min(5,Math.max(0,(b+g+h)*5));return{turnIndex:n,role:o,wordCount:r,sentenceCount:s,uniqueWordRatio:e,repetitionRatio:i,score:Q}}function _e(u){return u.filter(n=>n.role==="user"||n.role==="assistant").map((n,o)=>ge(n.content.replace(/<think>[\s\S]*?<\/think>/g,"").trim(),o,n.role))}const he={class:"rounded-lg border border-border-default bg-surface-raised p-4"},xe={class:"mb-3 text-sm font-medium text-text-secondary"},ye={class:"h-48"},ve={class:"mt-2 text-[10px] text-text-muted"},$e={key:1,class:"py-6 text-center text-xs text-text-muted"},ke=x({__name:"QualityOverTurnsChart",setup(u){v.register(R,D,T,L,$,k,C,H);const n=X(),o=p(()=>{const t=n.activeConversation;return!t||t.messages.length<2?[]:_e(t.messages)}),a=p(()=>o.value.filter(t=>t.role==="assistant")),r=p(()=>({labels:a.value.map((t,e)=>`Turn ${e+1}`),datasets:[{label:"Quality Score",data:a.value.map(t=>t.score),borderColor:"#818cf8",backgroundColor:"rgba(129, 140, 248, 0.1)",fill:!0,tension:.3,pointBackgroundColor:a.value.map(t=>t.score>=3.5?"#34d399":t.score>=2?"#fbbf24":"#ef4444"),pointRadius:4}]})),f={responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1},tooltip:{callbacks:{label:t=>{const e=a.value[t.dataIndex];return`Score: ${(t.parsed.y??0).toFixed(1)}/5 (${e?.wordCount??0} words)`}}}},scales:{x:{ticks:{color:"#94a3b8",font:{size:10}},grid:{color:"rgba(71, 85, 105, 0.3)"}},y:{min:0,max:5,ticks:{color:"#94a3b8",font:{size:10},stepSize:1},grid:{color:"rgba(71, 85, 105, 0.3)"}}}},s=p(()=>a.value.length>=2);return(t,e)=>(d(),c("div",he,[l("h3",xe,m(t.$t("analytics.quality.title")),1),s.value?(d(),c(w,{key:0},[l("div",ye,[_(y(O),{data:r.value,options:f},null,8,["data"])]),l("p",ve,m(t.$t("analytics.quality.hint")),1)],64)):(d(),c("p",$e,m(t.$t("analytics.quality.noData")),1))]))}}),Ce={class:"h-full overflow-y-auto p-6"},De={class:"mb-6 text-lg font-semibold text-text-primary"},Se={class:"mb-8"},we={class:"mb-4 text-sm font-semibold uppercase tracking-wide text-text-muted"},Re={class:"mb-8"},Me={class:"mb-4 text-sm font-semibold uppercase tracking-wide text-text-muted"},Te={class:"grid gap-6 lg:grid-cols-2"},ze={class:"mt-6"},Ae={class:"mb-8"},Le={class:"mb-4 text-sm font-semibold uppercase tracking-wide text-text-muted"},Oe={class:"grid gap-6 lg:grid-cols-2"},Ee={class:"mt-6"},He={class:"mb-8"},Pe={class:"mb-4 text-sm font-semibold uppercase tracking-wide text-text-muted"},qe={class:"grid gap-6 lg:grid-cols-2"},Fe={class:"mt-6"},Be={class:"mb-8"},We={class:"mb-4 text-sm font-semibold uppercase tracking-wide text-text-muted"},Ie={class:"mb-4 text-sm font-semibold uppercase tracking-wide text-text-muted"},Qe=x({__name:"AnalyticsPage",setup(u){return(n,o)=>(d(),c("div",Ce,[l("h1",De,m(n.$t("analytics.title")),1),l("section",Se,[l("h2",we,m(n.$t("analytics.sections.quality")),1),_(ke)]),l("section",Re,[l("h2",Me,m(n.$t("analytics.sections.latency")),1),l("div",Te,[_(ot),_(it)]),l("div",ze,[_(bt)])]),l("section",Ae,[l("h2",Le,m(n.$t("analytics.sections.reliability")),1),l("div",Oe,[_(Mt),_(Ot)]),l("div",Ee,[_(kt)])]),l("section",He,[l("h2",Pe,m(n.$t("analytics.sections.usage")),1),l("div",qe,[_(Ft),_(Ut)]),l("div",Fe,[_(Zt)])]),l("section",Be,[l("h2",We,m(n.$t("analytics.sections.settings")),1),_(ne)]),l("section",null,[l("h2",Ie,m(n.$t("analytics.sections.modelMemory")),1),_(be)])]))}});export{Qe as default};