PageSourceSearch

https://tesana.com/assets/GameInsightsPage-ChbdBqhZ.js

js tesana.com collected 2026-10-09 22:40:46 UTC 12,869 bytes, 7 lines download raw bytes

1import{j as e}from"./vendor-motion-hRg_q8lq.js";import{r as x}from"./vendor-react-E98sgxjj.js";import{du as A}from"./vendor-fa-Bn2dnpnC.js";import{useGameSettings as T}from"./GameSettingsLayout-D9S5c2Df.js";import{u as R}from"./vendor-query-bOUN_gKe.js";import{U as I,b as O,a9 as K,u as P}from"./index-BKzE8EQ8.js";import{a as q}from"./plansApi-C_2vGYRm.js";import{M as F}from"./Markdown-BgzYVg9N.js";import{D as G,u as L}from"./DeckBarChart-CPvCFwi6.js";import"./StreamingWords-Ds3Ch0UQ.js";import"./index-DtA29OOy.js";import"./index-Cq7f-X06.js";const B="https://api.tesana.ai/api",C={overview:async s=>(await I.get(`/games/${s}/insights/`)).data,streamMessage:async(s,t,r,o,a)=>{const h={"Content-Type":"application/json",Accept:"text/event-stream"};try{const n=localStorage.getItem("auth_token");n&&(h.Authorization=`Token ${n}`);const f=localStorage.getItem("onetap_anon_id");f&&(h["X-Anon-Id"]=f)}catch{}const u=r.filter(n=>n.content.trim()).map(({role:n,content:f})=>({role:n,content:f})),m=await fetch(`${B}/games/${s}/insights/messages/`,{method:"POST",headers:h,body:JSON.stringify({content:t,history:u,stream:!0}),signal:a});if(!m.ok||!m.body){let n=null;try{n=await m.json()}catch{}throw{response:{status:m.status,data:n}}}const g=m.body.getReader(),l=new TextDecoder;let i="";for(;;){const{done:n,value:f}=await g.read();if(n)break;i+=l.decode(f,{stream:!0});let b=i.indexOf(`
2
3`);for(;b!==-1;){const w=i.slice(0,b);i=i.slice(b+2);const y=E(w);y&&o(y),b=i.indexOf(`
4
5`)}}const c=E(i);c&&o(c)}};function E(s){const t=q(s);if(t)return t.type==="delta"?{type:"delta",text:t.text}:t.type==="message"?{type:"message",message:t.message}:t.type==="error"?{type:"error",error:t.error,message:t.message,ref:t.ref}:null;let r="";const o=[];for(const a of s.split(`
6`))!a||a.startsWith(":")||(a.startsWith("event:")?r=a.slice(6).trim():a.startsWith("data:")&&o.push(a.slice(5).trimStart()));if(r!=="chart")return null;try{return{type:"chart",chart:JSON.parse(o.join(`
7`))}}catch{return null}}function U(){const{isAuthenticated:s}=O(),{data:t,isSuccess:r,isError:o}=R({queryKey:["user-usage"],queryFn:K.getUsage,enabled:s});return{available:!!t?.game_insights_available,ready:r||o}}const W=s=>["game-insights",s];
7function H(s){const[t,r]=x.useState([]),[o,a]=x.useState(null),[h,u]=x.useState([]),[m,g]=x.useState(!1),[l,i]=x.useState(null),c=x.useRef(null),n=x.useRef(!1),f=R({queryKey:W(s),queryFn:()=>C.overview(s),enabled:!!s,refetchOnWindowFocus:!1});x.useEffect(()=>{r([]),a(null),u([]),i(null)},[s]),x.useEffect(()=>()=>c.current?.abort(),[]);const b=x.useCallback(async y=>{const N=y.trim();if(!s||!N||n.current)return!1;n.current=!0,g(!0),i(null);const p={role:"user",content:N},k=t;r(d=>[...d,p]),a(""),u([]);const M=new AbortController;c.current=M;let S="",v=[],_=!1;try{return await C.streamMessage(s,N,k,d=>{d.type==="delta"?(S+=d.text,a(j=>(j??"")+d.text)):d.type==="chart"?v.some(j=>j.kind===d.chart.kind&&j.title===d.chart.title)||(v=[...v,d.chart],u(v)):d.type==="message"?(S=d.message.content||S,v=d.message.charts?.length?d.message.charts:v,_=!!d.message.failed):d.type==="error"&&i({status:500,code:d.error,message:d.message,ref:d.ref})},M.signal),!0}catch(d){if(M.signal.aborted)return!1;const j=d;return i({status:j?.response?.status??0,code:j?.response?.data?.error??"network_error",message:j?.response?.data?.message??"",ref:j?.response?.data?.ref}),!1}finally{(S||v.length)&&r(d=>[...d,{role:"assistant",content:S.trim(),charts:v,failed:_}]),a(null),u([]),g(!1),n.current=!1,c.current=null}},[s,t]),w=x.useCallback(()=>{c.current?.abort(),r([]),a(null),u([]),i(null)},[]);return{overview:f.data,isLoading:f.isLoading,loadError:f.error,refetchOverview:f.refetch,messages:t,streamingText:o,streamingCharts:h,sending:m,error:l,clearError:()=>i(null),send:b,reset:w}}function V(s){if(Math.abs(s)>=1e3){const t=s/1e3;return`${t>=10?Math.round(t):t.toFixed(1)}k`}return String(Math.round(s))}function z({chart:s}){const{palette:t}=L(),{buckets:r,cells:o,total:a,title:h}=s,u=x.useMemo(()=>Math.max(1,...o.map(l=>l.count)),[o]),m=x.useMemo(()=>{const l=new Map;for(const i of o)l.set(`${i.x}:${i.y}`,i.count);return l},[o]);if(a===0)return e.jsxs("div",{className:"rounded-lg border border-border bg-card p-4 text-sm text-muted-foreground",children:[h,": no deaths with recorded positions."]});const g=Array.from({length:r},(l,i)=>r-1-i);return e.jsxs("div",{className:"rounded-lg border border-border bg-card p-4",children:[e.jsxs("div",{className:"mb-3 flex items-baseline justify-between",children:[e.jsx("h4",{className:"text-sm font-medium text-foreground",children:h}),e.jsxs("span",{className:"text-xs text-muted-foreground tabular-nums",children:[a," ",a===1?"death":"deaths"]})]}),e.jsx("div",{className:"grid gap-px rounded-md overflow-hidden border border-border",style:{gridTemplateColumns:`repeat(${r}, minmax(0, 1fr))`},children:g.flatMap(l=>Array.from({length:r},(i,c)=>{const n=m.get(`${c}:${l}`)??0,f=n===0?0:.18+.82*(n/u);return e.jsx("div",{title:n?`${n} ${n===1?"death":"deaths"}`:"no deaths",className:"aspect-square",style:{backgroundColor:n?`color-mix(in srgb, ${t.danger} ${Math.round(f*100)}%, ${t.card})`:t.border}},`${c}:${l}`)}))}),s.top_clusters.length>0&&e.jsx("ul",{className:"mt-3 space-y-1 text-xs text-muted-foreground",children:s.top_clusters.slice(0,3).map(l=>e.jsxs("li",{className:"tabular-nums",children:[l.share_pct,"% of deaths in one spot (",l.count,")"]},`${l.x}:${l.y}`))})]})}function J({chart:s}){const{columns:t,rows:r,title:o}=s;return r.length?e.jsxs("div",{className:"rounded-lg border border-border bg-card overflow-hidden",children:[e.jsx("div",{className:"px-4 py-3 border-b border-border",children:e.jsx("h4",{className:"text-sm font-medium text-foreground",children:o})}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsx("tr",{className:"text-left text-xs text-muted-foreground",children:t.map(a=>e.jsx("th",{className:"px-4 py-2 font-medium whitespace-nowrap",children:a.label},a.key))})}),e.jsx("tbody",{children:r.slice(0,50).map((a,h)=>e.jsx("tr",{className:"border-t border-border",children:t.map(u=>{const m=a[u.key];return e.jsx("td",{className:u.type==="number"?"px-4 py-2 tabular-nums text-foreground whitespace-nowrap":"px-4 py-2 text-foreground whitespace-nowrap",children:m==null||m===""?"—":String(m)},u.key)})},h))})]})})]}):e.jsxs("div",{className:"rounded-lg border border-border bg-card p-4 text-sm text-muted-foreground",children:[o,": nothing to show yet."]})}function Q({chart:s}){return s.kind==="heatmap"?e.jsx(z,{chart:s}):s.kind==="table"?e.jsx(J,{chart:s}):s.points.length?e.jsxs("div",{className:"rounded-lg border border-border bg-card p-4",children:[e.jsxs("div",{className:"mb-2 flex items-baseline justify-between",children:[e.jsx("h4",{className:"text-sm font-medium text-foreground",children:s.title}),s.unit&&e.jsx("span",{className:"text-xs text-muted-foreground",children:s.unit})]}),e.jsx("div",{className:"h-56",children:e.jsx(G,{points:s.points.map(t=>({label:t.label,value:t.value,fullLabel:t.label})),formatValue:V,showGrowth:!1,barScale:"blue",padding:.35})})]}):e.jsxs("div",{className:"rounded-lg border border-border bg-card p-4 text-sm text-muted-foreground",children:[s.title,": nothing to show yet."]})}function D({message:s,streaming:t=!1}){const r=s.role==="user";return e.jsx("div",{className:r?"flex justify-end":"flex justify-start",children:e.jsxs("div",{className:r?"max-w-[80%]":"w-full max-w-[92%] space-y-3",children:[e.jsx("div",{className:r?"rounded-2xl rounded-br-sm bg-primary text-primary-foreground px-4 py-2.5 text-sm":"rounded-2xl rounded-bl-sm bg-card border border-border px-4 py-3 text-sm",children:r?e.jsx("p",{className:"whitespace-pre-wrap",children:s.content}):e.jsx(F,{streaming:t,children:s.content})}),!r&&s.charts&&s.charts.length>0&&e.jsx("div",{className:"space-y-3",children:s.charts.map((o,a)=>e.jsx(Q,{chart:o},`${o.kind}-${o.title}-${a}`))})]})})}function X({messages:s,streamingText:t,streamingCharts:r,sending:o,starters:a,onAsk:h}){const u=x.useRef(null),m=x.useRef(null),[g,l]=x.useState(!0),i=s.length===0&&t===null;return x.useEffect(()=>{g&&u.current?.scrollIntoView({block:"end"})},[s.length,t,r.length,g]),e.jsxs("div",{ref:m,onScroll:c=>{const n=c.currentTarget;l(n.scrollHeight-n.scrollTop-n.clientHeight<80)},className:"flex-1 overflow-y-auto px-4 py-5 space-y-5",children:[i&&e.jsxs("div",{className:"flex flex-col items-center justify-center text-center py-10",children:[e.jsx(A,{icon:["far","message-lines"],className:"text-2xl text-muted-foreground mb-3"}),e.jsx("p",{className:"text-sm text-muted-foreground mb-4 max-w-sm",children:"Ask anything about how players are playing this game. Answers are computed from the events the game reports, and the charts beside them are the same numbers."}),e.jsx("div",{className:"flex flex-wrap justify-center gap-2 max-w-lg",children:a.map(c=>e.jsx("button",{type:"button",onClick:()=>h(c),className:"rounded-full border border-border bg-card px-3 py-1.5 text-xs text-foreground hover:border-primary/60 transition-colors",children:c},c))})]}),s.map((c,n)=>e.jsx(D,{message:c},n)),t!==null&&e.jsx(D,{streaming:!0,message:{role:"assistant",content:t,charts:r}}),o&&t===""&&e.jsxs("div",{className:"flex items-center gap-2 text-xs text-muted-foreground pl-1",children:[e.jsx("span",{className:"spinner w-3 h-3 border"}),"Reading the data…"]}),e.jsx("div",{ref:u})]})}function ue(){const{game:s}=T(),{t}=P("game"),{available:r,ready:o}=U(),{overview:a,isLoading:h,messages:u,streamingText:m,streamingCharts:g,sending:l,error:i,clearError:c,send:n}
7=H(s.id),[f,b]=x.useState(""),w=p=>{const k=p.trim();!k||l||(b(""),n(k))};if(!o)return e.jsx("div",{className:"min-h-[40vh] flex items-center justify-center",children:e.jsx("div",{className:"spinner w-6 h-6 border-2"})});if(!r)return e.jsx("p",{className:"text-muted-foreground",children:t("gameSettings.insights.unavailable","Insights aren't available on this account yet.")});if(h)return e.jsx("div",{className:"min-h-[40vh] flex items-center justify-center",children:e.jsx("div",{className:"spinner w-6 h-6 border-2"})});const y=a?.digest,N=a?.has_data??!1;return e.jsxs("div",{className:"flex flex-col rounded-xl border border-border bg-background overflow-hidden h-[calc(100vh-15rem)] min-h-[28rem]",children:[e.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-4 gap-px bg-border border-b border-border",children:[e.jsx($,{label:t("gameSettings.insights.statSessions","Sessions"),value:y?.sessions??0}),e.jsx($,{label:t("gameSettings.insights.statPlayers","Players"),value:y?.players??0}),e.jsx($,{label:t("gameSettings.insights.statMedian","Median session"),value:Y(y?.median_session_seconds??0)}),e.jsx($,{label:t("gameSettings.insights.statEvents","Events"),value:y?.events??0})]}),!N&&e.jsx("div",{className:"border-b border-border bg-card px-4 py-3 text-xs text-muted-foreground",children:t("gameSettings.insights.noData","This game has not reported any play data yet. It starts reporting once it is played after being built with the current SDK — deaths, level starts and session ends.")}),i&&e.jsxs("div",{className:"flex items-start justify-between gap-3 border-b border-border bg-destructive/10 px-4 py-3 text-xs",children:[e.jsxs("span",{className:"text-destructive",children:[i.message||t("gameSettings.insights.error","Something went wrong. Try again."),i.ref?` (ref ${i.ref})`:""]}),e.jsx("button",{type:"button",onClick:c,className:"text-muted-foreground hover:text-foreground",children:e.jsx(A,{icon:["fas","xmark"]})})]}),e.jsx(X,{messages:u,streamingText:m,streamingCharts:g,sending:l,starters:a?.starter_questions??[],onAsk:w}),e.jsxs("form",{className:"border-t border-border p-3 flex items-end gap-2",onSubmit:p=>{p.preventDefault(),w(f)},children:[e.jsx("textarea",{value:f,onChange:p=>b(p.target.value),onKeyDown:p=>{p.key==="Enter"&&!p.shiftKey&&(p.preventDefault(),w(f))},rows:1,placeholder:t("gameSettings.insights.placeholder","Ask about your game…"),className:"flex-1 resize-none rounded-lg border border-border bg-card px-3 py-2 text-sm text-foreground focus:outline-none focus:ring-1 focus:ring-primary max-h-40"}),e.jsx("button",{type:"submit",disabled:l||!f.trim(),className:"rounded-lg bg-primary text-primary-foreground px-3.5 py-2 text-sm font-medium disabled:opacity-40","aria-label":t("gameSettings.insights.send","Send"),children:e.jsx(A,{icon:["fas","paper-plane"]})})]})]})}function $({label:s,value:t}){return e.jsxs("div",{className:"bg-background px-4 py-3",children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:s}),e.jsx("div",{className:"text-lg text-foreground tabular-nums",children:t})]})}function Y(s){const t=Math.max(0,Math.round(s));if(t<60)return`${t}s`;const r=Math.floor(t/60),o=t%60;return o?`${r}m ${o}s`:`${r}m`}export{ue 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.