1import{r as o,j as e,b as j,a2 as N,a3 as b,B as w,ac as v,a4 as k,I as A,S as D,a as S,y as R,L as l,al as I,F as U,bD as a,s as C}from"./index-BGGYiAn1.js";import{P as F}from"./PageSeo-C1_lRcjl.js";import{K}from"./key-round-DUjHNk2g.js";import{U as L}from"./upload-Bx5hitUR.js";const E=()=>{const[i,c]=o.useState(""),[m,u]=o.useState(!1),[n,p]=o.useState(null),[x,h]=o.useState(!1),[d,f]=o.useState(null),y=o.useRef(null);async function O(){if(!i.trim()){a.error("Paste your OpenRouter key first.");return}u(!0),p(null);const{data:s,error:t}=await C.functions.invoke("openrouter-import",{body:{api_key:i.trim()}});if(u(!1),t){a.error("Import failed",{description:t.message});return}if(s!=null&&s.error){a.error("Import failed",{description:s.error});return}p(s),c(""),a.success("OpenRouter spend imported",{description:`${s.imported} days of real cost added to your ledger.`})}async function B(s){h(!0),f(null);const t=await s.text(),{data:r,error:g}=await C.functions.invoke("switchyard-import",{body:t});if(h(!1),g){a.error("Upload failed",{description:g.message});return}if(r!=null&&r.error){a.error("Upload failed",{description:r.error});return}f(r),a.success("Switchyard calls metered",{description:`${r.imported} routed calls added to your ledger.`})}return e.jsxs(e.Fragment,{children:[e.jsx(F,{title:"Connect your AI runtime | Tokenomy",description:"Import real spend from OpenRouter and NVIDIA NeMo Switchyard so your AI cost, margin and forecasts are metered instead of modelled.",path:"/app/connect-runtime",noIndex:!0}),e.jsxs("main",{className:"container mx-auto px-4 py-10",children:[e.jsxs("header",{className:"mb-8",children:[e.jsx("h1",{className:"text-3xl font-bold",children:"Connect your AI runtime"}),e.jsx("p",{className:"mt-2 max-w-2xl text-muted-foreground",children:"Bring real calls and real charges into Tokenomy. Once they land, every margin, forecast and burn-down number stops being an estimate."})]}),e.jsxs("div",{className:"grid gap-6 [&>*]:min-w-0 lg:grid-cols-2",children:[e.jsxs(j,{children:[e.jsxs(N,{children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsxs(b,{className:"flex items-center gap-2",children:[e.jsx(K,{className:"h-5 w-5"}),"OpenRouter"]}),e.jsx(w,{variant:"secondary",children:"Live"})]}),e.jsx(v,{children:"Pull the last 30 days of what you actually paid, per model, per day."})]}),e.jsxs(k,{className:"space-y-4",children:[e.jsx(A,{type:"password",placeholder:"sk-or-...",value:i,onChange:s=>c(s.target.value),className:"max-w-full"}),e.jsxs("p",{className:"flex items-start gap-2 text-xs text-muted-foreground",children:[e.jsx(D,{className:"mt-0.5 h-4 w-4 shrink-0"}),"Your key is used for this one request and never saved. Re-running replaces the same days instead of double-counting."]}),e.jsxs(S,{onClick:O,disabled:m,children:[m?e.jsx(R,{className:"mr-2 h-4 w-4 animate-spin"}):null,"Import my OpenRouter spend"]}),n&&e.jsxs("div",{className:"rounded-lg border border-border bg-muted/40 p-4 text-sm",children:[e.jsxs("p",{className:"font-medium",children:[n.imported," entries · $",Number(n.spend_usd??0).toFixed(2)," of real spend"]}),e.jsxs("p",{className:"text-muted-foreground",children:[n.models??0," models across ",n.days??0," days."]}),e.jsxs(l,{to:"/app/usage-vs-market",className:"mt-2 inline-flex items-center gap-1 text-primary",children:["See it against market prices ",e.jsx(I,{className:"h-4 w-4"})]})]}),e.jsxs("div",{className:"rounded-lg border border-dashed border-border p-3 text-xs text-muted-foreground",children:[e.jsx("span",{className:"font-medium text-foreground",children:"Route live traffic too:"})," send calls to the Tokenomy endpoint with a model id like"," ",e.jsx("code",{className:"break-all",children:"openrouter/anthropic/claude-sonnet"})," and your"," ",e.jsx("code",{children:"X-OpenRouter-Key"})," header. Budgets and policy apply, and the real charge is metered."]})]})]}),e.jsxs(j,{children:[e.jsxs(N,{children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsxs(b,{className:"flex items-center gap-2",children:[e.jsx(L,{className:"h-5 w-5"}),"NVIDIA NeMo Switchyard"]}),e.jsx(w,{variant:"secondary",children:"Live"})]}),e.jsx(v,{children:"Switchyard picks the model; Tokenomy prices the decision. Upload its request log to meter every routed call."})]}),e.jsxs(k,{className:"space-y-4",children:[e.jsx("input",{ref:y,type:"file",accept:".json,.jsonl,.log,.txt",className:"hidden",onChange:s=>{var r;const t=(r=s.target.files)==null?void 0:r[0];t&&B(t),s.target.value=""}}),e.jsxs(S,{onClick:()=>{var s;return(s=y.current)==null?void 0:s.click()},disabled:x,children:[x?e.jsx(R,{className:"mr-2 h-4 w-4 animate-spin"}):null,"Upload Switchyard request log"]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Accepts a JSON array or newline-delimited JSON, up to 5000 records per upload."}),d&&e.jsxs("div",{className:"rounded-lg border border-border bg-muted/40 p-4 text-sm",children:[e.jsxs("p",{className:"font-medium",children:[d.imported," routed calls · $",Number(d.spend_usd??0).toFixed(2)]}),e.jsxs("p",{className:"text-muted-foreground",children:[d.models??0," models. ",d.note??""]}),e.jsxs(l,{to:"/finance/board-deck",className:"mt-2 inline-flex items-center gap-1 text-primary",children:["Open the board deck ",e.jsx(I,{className:"h-4 w-4"})]})]}),e.jsxs("div",{className:"rounded-lg border border-dashed border-border p-3 text-xs text-muted-foreground",children:[e.jsx("span",{className:"font-medium text-foreground",children:"Drive its routing from here:"})," open the"," ",e.jsx(l,{to:"/features/policy-governance",className:"text-primary",children:"routing policy editor"})," ","and choose âExport for NVIDIA Switchyardâ to download the ",e.jsx("code",{children:"routes.yaml"})," its proxy reads â so your cost rules decide where traffic goes."]})]})]})]})]}),e.jsx(U,{})]})};export{E 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.