1import{d as ke,O as he,k as r,e as k,D as ge,W as we,E as _e,a as n,o,f as e,g as y,j as c,t as a,i as w,u,n as L,w as S,bS as $,F as _,r as C,aa as Ce,a6 as oe,bc as p,m as Se,bw as q,aG as xe,_ as Le}from"./index-CfV0kGTY.js";import{m as $e}from"./vue3-apexcharts-BMI_dvvJ.js";import{D as Fe}from"./download-B0Vaqgpx.js";import{R as Re}from"./refresh-cw-W-I7-sQZ.js";const Ne={class:"llm-costs-view"},Te={class:"header"},Ue={class:"subtitle"},Pe={key:0,class:"live-badge"},De={class:"header-actions"},ze=["disabled"],Ee={class:"filters"},Ve={class:"filter-group"},Ae={class:"filter-group"},Me=["value"],Oe={class:"filter-group"},je=["value"],Ie={class:"filter-group"},Be=["value"],Ke={class:"filter-group"},Je={class:"filter-group"},We=["value"],Ge={class:"filter-group"},Qe={key:0,class:"error-banner"},Xe={key:1,class:"cards"},qe={class:"card"},He={class:"card-value"},Ye={class:"card"},Ze={class:"card-value"},el={class:"card"},ll={class:"card-sub"},sl={class:"card"},tl={class:"card-value"},al={class:"card"},ol={class:"card-value"},nl={class:"card"},il={class:"card-value"},dl={key:2,class:"chart-section"},rl={key:0,class:"anomaly-tag"},ul={key:3,class:"breakdowns"},cl={class:"breakdown-header"},vl={class:"group-by-tabs"},pl=["onClick"],yl={class:"breakdown-table"},fl=["onClick"],ml=["title"],bl={key:0},kl={key:4,class:"drill-overlay"},hl={class:"drill-modal"},gl={class:"drill-head"},wl={class:"drill-dim"},_l={class:"drill-key"},Cl={key:0,class:"drill-state"},Sl={key:1,class:"drill-state error"},xl={key:2,class:"drill-state"},Ll={key:3,class:"drill-body"},$l={class:"drill-list"},Fl={class:"drill-list-head"},Rl=["onClick"],Nl={class:"dli-time"},Tl={class:"dli-meta"},Ul={key:0,class:"dli-fail"},Pl={key:0,class:"drill-detail"},Dl={class:"drill-stats"},zl={key:0,class:"error-block"},El={class:"error-reason"},Vl={key:0,class:"payload error-body"},Al={class:"payload-block"},Ml={key:0,class:"payload"},Ol={key:1,class:"payload empty-payload"},jl={class:"payload-block"},Il={key:0,class:"payload"},Bl={key:1,class:"payload empty-payload"},Kl={class:"raw"},Jl={class:"raw-table"},Wl=["onClick"],Gl={class:"nowrap"},Ql=["title"],Xl={class:"feature-cell"},ql={class:"nowrap"},Hl={key:0,class:"ok"},Yl={key:1,class:"fail"},Zl={key:0},es={class:"pagination"},ls=["disabled"],ss=["disabled"],ts=ke({__name:"LlmCostsView",setup(as){const ne=$e,{isDark:ie}=he(),i=r(null),I=r([]),F=r({providers:[],kinds:[],accounts:[],features:[],models:[],engines:[]}),D=r(!1),R=r(null),B=r(7),z=r(""),E=r(""),V=r(""),A=r(""),H=r(""),M=r(""),O=r(""),m=r(1),K=r(50),j=r(0),h=r("byFeature"),N=r(!1),T=r(!1),x=r(null),J=r(""),W=r(""),g=r([]),U=r(0),v=k(()=>g.value[U.value]??null),Y=k(()=>{var l;const t=v.value;return!t||t.success?null:((l=t.metadata)==null?void 0:l.error)||"Call failed â no error detail was recorded."}),Z=k(()=>{const t=v.value;if(!t||t.success||!t.rawResponse)return null;try{return JSON.stringify(JSON.parse(t.rawResponse),null,2)}catch{return t.rawResponse}}),G=k(()=>{const t=new URLSearchParams;return t.set("days",String(B.value)),z.value&&t.set("accountId",z.value),E.value&&t.set("provider",E.value),V.value&&t.set("kind",V.value),A.value&&t.set("feature",A.value),H.value&&t.set("engineKey",H.value),M.value&&t.set("modelName",M.value),O.value==="success"&&t.set("success","true"),O.value==="failed"&&t.set("failed","true"),t.toString()}),ee=k(()=>i.value?i.value.breakdowns[h.value]??[]:[]),de=k(()=>{if(!i.value)return[];const t=new Set;for(const l of i.value.trend)for(const d of l.byProvider)t.add(d.provider);return[...t].sort()}),re=k(()=>i.value?de.value.map(t=>({name:t,data:i.value.trend.map(l=>{const d=l.byProvider.find(s=>s.provider===t);return{x:l.day,y:Number(((d==null?void 0:d.cost)??0).toFixed(4))}})})):[]),ue=k(()=>({chart:{type:"bar",stacked:!0,toolbar:{show:!1},fontFamily:"inherit"},plotOptions:{bar:{columnWidth:"60%",borderRadius:4}},dataLabels:{enabled:!1},legend:{position:"top"},xaxis:{type:"category",labels:{style:{fontSize:"11px"}}},yaxis:{labels:{formatter:t=>`$${t.toFixed(2)}`,style:{fontSize:"11px"}},title:{text:"Spend USD",style:{fontSize:"11px"}}},tooltip:{theme:ie.value?"dark":"light",y:{formatter:t=>`$${t.toFixed(4)}`}},colors:["#6366f1","#ec4899","#22c55e","#f59e0b","#06b6d4","#a855f7"],grid:{strokeDashArray:3}})),le=k(()=>
1{if(!i.value||i.value.trend.length<8)return new Set;const t=i.value.trend.map(d=>d.totalCost),l=new Set;for(let d=7;d<t.length;d++){const s=t.slice(d-7,d),f=s.reduce((P,be)=>P+be,0)/s.length;f>0&&t[d]>f*2&&l.add(i.value.trend[d].day)}return l});async function ce(){D.value=!0,R.value=null;try{const t=await fetch(`/api/admin/llm-costs/summary?${G.value}`,{credentials:"include"});if(!t.ok)throw new Error(`Summary fetch failed: ${t.status}`);i.value=await t.json()}catch(t){R.value=t.message}finally{D.value=!1}}async function se(){try{const t=new URLSearchParams(G.value);t.set("page",String(m.value)),t.set("pageSize",String(K.value));const l=await fetch(`/api/admin/llm-costs/rows?${t.toString()}`,{credentials:"include"});if(!l.ok)throw new Error(`Rows fetch failed: ${l.status}`);const d=await l.json();I.value=d.rows,j.value=d.total}catch(t){R.value=t.message}}async function ve(t){N.value=!0,T.value=!0,x.value=null,g.value=[],U.value=0,J.value=t.label||t.key||"(none)",W.value=h.value.replace("by","");try{const l=new URLSearchParams(G.value);l.set("dim",h.value),l.set("key",t.key||"(none)"),l.set("limit","25");const d=await fetch(`/api/admin/llm-costs/calls?${l.toString()}`,{credentials:"include"});if(!d.ok)throw new Error(`Calls fetch failed: ${d.status}`);const s=await d.json();g.value=s.calls}catch(l){x.value=l.message}finally{T.value=!1}}async function pe(t){N.value=!0,T.value=!0,x.value=null,g.value=[],U.value=0,J.value=t.feature||t._id,W.value="Raw call";try{const l=await fetch(`/api/admin/llm-costs/call/${t._id}`,{credentials:"include"});if(!l.ok)throw new Error(`Call fetch failed: ${l.status}`);const d=await l.json();g.value=[d.call]}catch(l){x.value=l.message}finally{T.value=!1}}function Q(){N.value=!1}function te(t){t.key==="Escape"&&N.value&&(t.stopPropagation(),Q())}async function ye(){try{const t=await fetch("/api/admin/llm-costs/filters",{credentials:"include"});if(!t.ok)return;F.value=await t.json()}catch{}}async function b(){m.value=1,await Promise.all([ce(),se()])}function fe(){if(!i.value)return;const t=[];t.push("day,provider,cost");for(const f of i.value.trend)for(const P of f.byProvider)t.push(`${f.day},${P.provider},${P.cost.toFixed(6)}`);const l=new Blob([t.join(` 2`)],{type:"text/csv"}),d=URL.createObjectURL(l),s=document.createElement("a");s.href=d,s.download=`llm-costs-trend-${new Date().toISOString().slice(0,10)}.csv`,document.body.appendChild(s),s.click(),document.body.removeChild(s),URL.revokeObjectURL(d)}function X(t){return`$${t.toFixed(4)}`}function me(t){return`${(t*100).toFixed(1)}%`}function ae(t){return new Date(t).toLocaleString()}return ge(()=>{ye(),b(),window.addEventListener("keydown",te)}),we(()=>window.removeEventListener("keydown",te)),_e(m,()=>se()),(t,l)=>{var d;return o(),n("div",Ne,[e("header",Te,[e("div",null,[l[10]||(l[10]=e("h1",null,"LLM Cost Dashboard",-1)),e("p",Ue,[l[9]||(l[9]=c(" Internal spend tracker across all AI / LLM features. ",-1)),(d=i.value)!=null&&d.window.liveDay?(o(),n("span",Pe," today live: "+a(i.value.window.liveDay),1)):y("",!0)])]),e("div",De,[e("button",{onClick:fe,class:"btn-secondary"},[w(u(Fe),{size:16}),l[11]||(l[11]=c(" Export CSV ",-1))]),e("button",{onClick:b,class:"btn-primary",disabled:D.value},[w(u(Re),{size:16,class:L({spin:D.value})},null,8,["class"]),l[12]||(l[12]=c(" Refresh ",-1))],8,ze)])]),e("section",Ee,[e("div",Ve,[l[14]||(l[14]=e("label",{for:"llmcosts-range"},"Range",-1)),S(e("select",{id:"llmcosts-range","onUpdate:modelValue":l[0]||(l[0]=s=>B.value=s),onChange:b},[...l[13]||(l[13]=[e("option",{value:1},"Today",-1),e("option",{value:7},"Last 7d",-1),e("option",{value:14},"Last 14d",-1),e("option",{value:30},"Last 30d",-1),e("option",{value:90},"Last 90d",-1)])],544),[[$,B.value,void 0,{number:!0}]])]),e("div",Ae,[l[16]||(l[16]=e("label",{for:"llmcosts-account"},"Account",-1)),S(e("select",{id:"llmcosts-account","onUpdate:modelValue":l[1]||(l[1]=s=>z.value=s),onChange:b},[l[15]||(l[15]=e("option",{value:""},"All",-1)),(o(!0),n(_,null,C(F.value.accounts,s=>(o(),n("option",{key:s.id,value:s.id},a(s.name),9,Me))),128))],544),[[$,z.value]])]),e("div",Oe,[l[18]||(l[18]=e("label",{for:"llmcosts-provider"},"Provider",-1)),S(e("select",{id:"llmcosts-provider","onUpdate:modelValue":l[2]||(l[2]=s=>E.value=s),onChange:b},[l[17]||(l[17]=e("option",{value:""},"All",-1)),(o(!0),n(_,null,C(F.value.providers,s=>(o(),n("option",{key:s,value:s},a(s),9,je))),128))],544),[[$,E.value]])]),e("div",Ie,[l[20]||(l[20]=e("label",{for:"llmcosts-kind"},"Kind",-1)),S(e("select",{id:"llmcosts-kind","onUpdate:modelValue":l[3]||(l[3]=s=>V.value=s),onChange:b},[l[19]||(l[19]=e("option",{value:""},"All",-1)),(o(!0),n(_,null,C(F.value.kinds,s=>(o(),n("option",{key:s,value:s},a(s),9,Be))),128))],544),[[$,V.value]])]),e("div",Ke,[l[21]||(l[21]=e("label",{for:"llmcosts-feature"},"Feature",-1)),S(e("input",{id:"llmcosts-feature","onUpdate:modelValue":l[4]||(l[4]=s=>A.value=s),onChange:b,placeholder:"substring filter"},null,544),[[Ce,A.value]])]),e("div",Je,[l[23]||(l[23]=e("label",{for:"llmcosts-model"},"Model",-1)),S(e("select",{id:"llmcosts-model","onUpdate:modelValue":l[5]||(l[5]=s=>M.value=s),onChange:b},[l[22]||(l[22]=e("option",{value:""},"All",-1)),(o(!0),n(_,null,C(F.value.models,s=>(o(),n("option",{key:s,value:s},a(s),9,We))),128))],544),[[$,M.value]])]),e("div",Ge,[l[25]||(l[25]=e("label",{for:"llmcosts-status"},"Status",-1)),S(e("select",{id:"llmcosts-status","onUpdate:modelValue":l[6]||(l[6]=s=>O.value=s),onChange:b},[...l[24]||(l[24]=[e("option",{value:""},"All",-1),e("option",{value:"success"},"Successful only",-1),e("option",{value:"failed"},"Failed only (retry burn)",-1)])],544),[[$,O.value]])])]),R.value?(o(),n("div",Qe,[w(u(oe),{size:16}),c(" "+a(R.value),1)])):y("",!0),i.value?(o(),n("section",Xe,[e("div",qe,[l[26]||(l[26]=e("div",{class:"card-label"},"Total spend",-1)),e("div",He,"$"+a(i.value.headline.cost.toFixed(4)),1)]),e("div",Ye,[l[27]||(l[27]=e("div",{class:"card-label"},"Calls",-1)),e("div",Ze,a(u(p)(i.value.headline.calls)),1)]),e("div",el,[l[28]||(l[28]=e("div",{class:"card-label"},"Failed",-1)),e("div",{class:L(["card-value",{warn:i.value.headline.failedCalls>0}])},[c(a(u(p)(i.value.headline.failedCalls))+" ",1),e("span",ll," ("+a(i.value.headline.calls>0?me(i.value.headline.failedCalls/i.value.headline.calls):"0%")+") ",1)],2)]),e("div",sl,[l[29]||(l[29]=e("div",{class:"card-label"},"Avg latency",-1)),e("div",tl,a(u(p)(i.value.headline.avgLatencyMs))+" ms",1)]),e("div",al,[l[30]||(l[30]=e("div",{class:"card-label"},"Input tokens",-1)),e("div",ol,a(u(p)(i.value.headline.inputTokens)),1)]),e("div",nl,[l[31]||(l[31]=e("div",{class:"card-label"},"Output tokens",-1)),e("div",il,a(u(p)(i.value.headline.outputTokens)),1)])])):y("",!0),i.value&&i.value.trend.length>0?(o(),n("section",dl,[e("h2",null,[l[32]||(l[32]=c(" Daily spend by provider ",-1)),le.value.size>0?(o(),n("span",rl,[w(u(oe),{size:14}),c(" "+a(u(p)(le.value.size))+" anomaly day(s) detected ",1)])):y("",!0)]),w(u(ne),{type:"bar",height:"320",options:ue.value,series:re.value},null,8,["options","series"])])):y("",!0),i.value?(o(),n("section",ul,[e("div",cl,[l[33]||(l[33]=e("h2",null,"Breakdown",-1)),e("div",vl,[(o(),n(_,null,C(["byFeature","byAccount","byProvider","byKind","byModel","byEngine"],s=>e("button",{key:s,onClick:f=>h.value=s,class:L({active:h.value===s})},a(s.replace("by","")),11,pl)),64))])]),e("table",yl,[e("thead",null,[e("tr",null,[e("th",
2null,a(h.value.replace("by","")),1),l[34]||(l[34]=e("th",null,"Calls",-1)),l[35]||(l[35]=e("th",null,"Spend",-1)),l[36]||(l[36]=e("th",null,"$ / call",-1))])]),e("tbody",null,[(o(!0),n(_,null,C(ee.value,s=>(o(),n("tr",{key:s.key,class:"clickable",onClick:f=>ve(s),title:"View the prompts sent and responses returned for this group"},[e("td",{class:"key-cell",title:s.label?s.key:""},[(h.value==="byProvider"||h.value==="byEngine")&&s.key?(o(),Se(q,{key:0,engine:s.key,size:13,class:"cell-logo"},null,8,["engine"])):y("",!0),c(a(s.label||s.key||"(none)"),1)],8,ml),e("td",null,a(u(p)(s.calls)),1),e("td",null,a(X(s.cost)),1),e("td",null,"$"+a(s.calls>0?(s.cost/s.calls).toFixed(6):"0"),1)],8,fl))),128)),ee.value.length===0?(o(),n("tr",bl,[...l[37]||(l[37]=[e("td",{colspan:"4",class:"empty"},"No data in this window.",-1)])])):y("",!0)])])])):y("",!0),N.value?(o(),n("div",kl,[e("div",{class:"overlay-hit","aria-hidden":"true",onClick:Q}),e("div",hl,[e("header",gl,[e("div",null,[e("span",wl,a(W.value),1),e("h2",_l,a(J.value),1)]),e("button",{class:"drill-close",onClick:Q},[w(u(xe),{size:18})])]),T.value?(o(),n("div",Cl,"Loading callsâ¦")):x.value?(o(),n("div",Sl,a(x.value),1)):g.value.length===0?(o(),n("div",xl,[...l[38]||(l[38]=[c(" No raw calls with payloads found for this group in the selected window. ",-1),e("p",{class:"drill-note"}," Payloads are only retained on live/recent raw rows â older calls may have been pruned. ",-1)])])):(o(),n("div",Ll,[e("aside",$l,[e("div",Fl,a(u(p)(g.value.length))+" most recent call(s)",1),(o(!0),n(_,null,C(g.value,(s,f)=>(o(),n("button",{key:s._id,class:L(["drill-list-item",{active:f===U.value,failed:!s.success}]),onClick:P=>U.value=f},[e("span",Nl,a(ae(s.createdAt)),1),e("span",Tl,[c(a(s.modelName)+" · "+a(X(s.costUsd))+" ",1),s.success?y("",!0):(o(),n("span",Ul,"â failed"))])],10,Rl))),128))]),v.value?(o(),n("div",Pl,[e("div",Dl,[e("span",null,[l[39]||(l[39]=e("b",null,"Feature",-1)),c(" "+a(v.value.feature),1)]),e("span",null,[l[40]||(l[40]=e("b",null,"Provider",-1)),l[41]||(l[41]=c()),w(q,{engine:v.value.provider,size:12,class:"cell-logo"},null,8,["engine"]),c(a(v.value.provider),1)]),e("span",null,[l[42]||(l[42]=e("b",null,"Model",-1)),c(" "+a(v.value.modelName),1)]),e("span",null,[l[43]||(l[43]=e("b",null,"Tokens",-1)),c(" "+a(u(p)(v.value.inputTokens))+" in / "+a(u(p)(v.value.outputTokens))+" out",1)]),e("span",null,[l[44]||(l[44]=e("b",null,"Cost",-1)),c(" "+a(X(v.value.costUsd)),1)]),e("span",null,[l[45]||(l[45]=e("b",null,"Latency",-1)),c(" "+a(u(p)(v.value.latencyMs))+"ms",1)]),e("span",null,[l[46]||(l[46]=e("b",null,"Status",-1)),l[47]||(l[47]=c()),e("span",{class:L(v.value.success?"status-ok":"status-fail")},a(v.value.success?"OK":"Failed"),3)])]),Y.value?(o(),n("div",zl,[l[48]||(l[48]=e("div",{class:"error-label"},"Failure reason",-1)),e("div",El,a(Y.value),1),Z.value?(o(),n("pre",Vl,a(Z.value),1)):y("",!0)])):y("",!0),e("div",Al,[l[49]||(l[49]=e("div",{class:"payload-label"},"Prompt sent",-1)),v.value.promptText?(o(),n("pre",Ml,a(v.value.promptText),1)):(o(),n("div",Ol,"No prompt payload stored for this call."))]),e("div",jl,[l[50]||(l[50]=e("div",{class:"payload-label"},"Response",-1)),v.value.responseText?(o(),n("pre",Il,a(v.value.responseText),1)):(o(),n("div",Bl,"No response payload stored for this call."))])])):y("",!0)]))])])):y("",!0),e("section",Kl,[e("h2",null,"Raw calls ("+a(u(p)(j.value))+" rows)",1),e("table",Jl,[l[52]||(l[52]=e("thead",null,[e("tr",null,[e("th",null,"Time"),e("th",null,"Account"),e("th",null,"Feature"),e("th",null,"Provider"),e("th",null,"Model"),e("th",null,"In"),e("th",null,"Out"),e("th",null,"Cost"),e("th",null,"Latency"),e("th",null,"OK")])],-1)),e("tbody",null,[(o(!0),n(_,null,C(I.value,s=>(o(),n("tr",{key:s._id,class:L(["clickable",{failed:!s.success}]),onClick:f=>pe(s),title:"View the prompt sent and response returned for this call"},[e("td",Gl,a(ae(s.createdAt)),1),e("td",{title:s.accountId||""},a(s.accountName||s.accountId||"â"),9,Ql),e("td",Xl,a(s.feature),1),e("td",ql,[w(q,{engine:s.provider,size:13,class:"cell-logo"},null,8,["engine"]),c(a(s.provider),1)]),e("td",null,a(s.modelName),1),e("td",null,a(u(p)(s.inputTokens)),1),e("td",null,a(u(p)(s.outputTokens)),1),e("td",null,"$"+a(s.costUsd.toFixed(4)),1),e("td",null,a(u(p)(s.latencyMs))+"ms",1),e("td",null,[s.success?(o(),n("span",Hl,"â")):(o(),n("span",Yl,"â"))])],10,Wl))),128)),I.value.length===0?(o(),n("tr",Zl,[...l[51]||(l[51]=[e("td",{colspan:"10",class:"empty"},"No rows.",-1)])])):y("",!0)])]),e("div",es,[e("button",{disabled:m.value===1,onClick:l[7]||(l[7]=s=>m.value=m.value-1)},"Prev",8,ls),e("span",null,"Page "+a(m.value)+" of "+a(Math.max(1,Math.ceil(j.value/K.value))),1),e("button",{disabled:m.value*K.value>=j.value,onClick:l[8]||(l[8]=s=>m.value=m.value+1)},"Next",8,ss)])])])}}}),rs=Le(ts,[["__scopeId","data-v-28f71fd7"]]);export{rs as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.