mirror of
https://github.com/wahyd4/links.git
synced 2026-08-08 21:04:53 +10:00
- Add jbot Django app (jbot/__init__.py, apps.py, urls.py, api_urls.py) - Python backend (jbot/views.py): TTS 2.0, ASR 1.0 BigASR, LLM/memory via OpenRouter - React SPA frontend at /jbot/ (static_src/jbot/): RobotFace, ChatPanel, expressions, voices, push-to-talk, history, memory, settings pages - Vite entry jbot: static_src/jbot/main.jsx → dist/jbot.js + dist/jbot.css - react-router-dom added; BrowserRouter basename=/jbot for SPA routing - core/settings.py: added jbot to INSTALLED_APPS - core/urls.py: /jbot/ + /api/jbot/ URL includes - pyproject.toml: websocket-client>=1.9.0 for BigASR binary WS protocol - Dockerfile: ffmpeg added to production apt-get for WebM→PCM audio conversion - k8s/manifest.yaml: VOLC_APP_ID, VOLC_ACCESS_TOKEN, OPENROUTER_API_KEY env vars via jbot-credentials Secret; LLM_MODEL, VOLC_TTS_VOICE, VOLC_ASR_RESOURCE defaults Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
13 lines
65 KiB
JavaScript
13 lines
65 KiB
JavaScript
import{r as l,j as d,c as tn}from"./client-DS0SU7Jy.js";/**
|
||
* react-router v7.15.1
|
||
*
|
||
* Copyright (c) Remix Software Inc.
|
||
*
|
||
* This source code is licensed under the MIT license found in the
|
||
* LICENSE.md file in the root directory of this source tree.
|
||
*
|
||
* @license MIT
|
||
*/var mt="popstate";function pt(e){return typeof e=="object"&&e!=null&&"pathname"in e&&"search"in e&&"hash"in e&&"state"in e&&"key"in e}function nn(e={}){function t(r,a){var c;let o=(c=a.state)==null?void 0:c.masked,{pathname:s,search:u,hash:i}=o||r.location;return qe("",{pathname:s,search:u,hash:i},a.state&&a.state.usr||null,a.state&&a.state.key||"default",o?{pathname:r.location.pathname,search:r.location.search,hash:r.location.hash}:void 0)}function n(r,a){return typeof a=="string"?a:ve(a)}return an(t,n,null,e)}function T(e,t){if(e===!1||e===null||typeof e>"u")throw new Error(t)}function K(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function rn(){return Math.random().toString(36).substring(2,10)}function gt(e,t){return{usr:e.state,key:e.key,idx:t,masked:e.mask?{pathname:e.pathname,search:e.search,hash:e.hash}:void 0}}function qe(e,t,n=null,r,a){return{pathname:typeof e=="string"?e:e.pathname,search:"",hash:"",...typeof t=="string"?ue(t):t,state:n,key:t&&t.key||r||rn(),mask:a}}function ve({pathname:e="/",search:t="",hash:n=""}){return t&&t!=="?"&&(e+=t.charAt(0)==="?"?t:"?"+t),n&&n!=="#"&&(e+=n.charAt(0)==="#"?n:"#"+n),e}function ue(e){let t={};if(e){let n=e.indexOf("#");n>=0&&(t.hash=e.substring(n),e=e.substring(0,n));let r=e.indexOf("?");r>=0&&(t.search=e.substring(r),e=e.substring(0,r)),e&&(t.pathname=e)}return t}function an(e,t,n,r={}){let{window:a=document.defaultView,v5Compat:o=!1}=r,s=a.history,u="POP",i=null,c=h();c==null&&(c=0,s.replaceState({...s.state,idx:c},""));function h(){return(s.state||{idx:null}).idx}function f(){u="POP";let g=h(),v=g==null?null:g-c;c=g,i&&i({action:u,location:p.location,delta:v})}function m(g,v){u="PUSH";let w=pt(g)?g:qe(p.location,g,v);c=h()+1;let E=gt(w,c),N=p.createHref(w.mask||w);try{s.pushState(E,"",N)}catch($){if($ instanceof DOMException&&$.name==="DataCloneError")throw $;a.location.assign(N)}o&&i&&i({action:u,location:p.location,delta:1})}function b(g,v){u="REPLACE";let w=pt(g)?g:qe(p.location,g,v);c=h();let E=gt(w,c),N=p.createHref(w.mask||w);s.replaceState(E,"",N),o&&i&&i({action:u,location:p.location,delta:0})}function y(g){return on(g)}let p={get action(){return u},get location(){return e(a,s)},listen(g){if(i)throw new Error("A history only accepts one active listener");return a.addEventListener(mt,f),i=g,()=>{a.removeEventListener(mt,f),i=null}},createHref(g){return t(a,g)},createURL:y,encodeLocation(g){let v=y(g);return{pathname:v.pathname,search:v.search,hash:v.hash}},push:m,replace:b,go(g){return s.go(g)}};return p}function on(e,t=!1){let n="http://localhost";typeof window<"u"&&(n=window.location.origin!=="null"?window.location.origin:window.location.href),T(n,"No window.location.(origin|href) available to create URL");let r=typeof e=="string"?e:ve(e);return r=r.replace(/ $/,"%20"),!t&&r.startsWith("//")&&(r=n+r),new URL(r,n)}function jt(e,t,n="/"){return sn(e,t,n,!1)}function sn(e,t,n,r,a){let o=typeof t=="string"?ue(t):t,s=Z(o.pathname||"/",n);if(s==null)return null;let u=ln(e),i=null,c=wn(s);for(let h=0;i==null&&h<u.length;++h)i=vn(u[h],c,r);return i}function ln(e){let t=Pt(e);return un(t),t}function Pt(e,t=[],n=[],r="",a=!1){let o=(s,u,i=a,c)=>{let h={relativePath:c===void 0?s.path||"":c,caseSensitive:s.caseSensitive===!0,childrenIndex:u,route:s};if(h.relativePath.startsWith("/")){if(!h.relativePath.startsWith(r)&&i)return;T(h.relativePath.startsWith(r),`Absolute route path "${h.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),h.relativePath=h.relativePath.slice(r.length)}let f=V([r,h.relativePath]),m=n.concat(h);s.children&&s.children.length>0&&(T(s.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${f}".`),Pt(s.children,t,m,f,i)),!(s.path==null&&!s.index)&&t.push({path:f,score:gn(f,s.index),routesMeta:m})};return e.forEach((s,u)=>{var i;if(s.path===""||!((i=s.path)!=null&&i.includes("?")))o(s,u);else for(let c of Mt(s.path))o(s,u,!0,c)}),t}function Mt(e){let t=e.split("/");if(t.length===0)return[];let[n,...r]=t,a=n.endsWith("?"),o=n.replace(/\?$/,"");if(r.length===0)return a?[o,""]:[o];let s=Mt(r.join("/")),u=[];return u.push(...s.map(i=>i===""?o:[o,i].join("/"))),a&&u.push(...s),u.map(i=>e.startsWith("/")&&i===""?"/":i)}function un(e){e.sort((t,n)=>t.score!==n.score?n.score-t.score:yn(t.routesMeta.map(r=>r.childrenIndex),n.routesMeta.map(r=>r.childrenIndex)))}var cn=/^:[\w-]+$/,dn=3,hn=2,fn=1,mn=10,pn=-2,yt=e=>e==="*";function gn(e,t){let n=e.split("/"),r=n.length;return n.some(yt)&&(r+=pn),t&&(r+=hn),n.filter(a=>!yt(a)).reduce((a,o)=>a+(cn.test(o)?dn:o===""?fn:mn),r)}function yn(e,t){return e.length===t.length&&e.slice(0,-1).every((r,a)=>r===t[a])?e[e.length-1]-t[t.length-1]:0}function vn(e,t,n=!1){let{routesMeta:r}=e,a={},o="/",s=[];for(let u=0;u<r.length;++u){let i=r[u],c=u===r.length-1,h=o==="/"?t:t.slice(o.length)||"/",f=Te({path:i.relativePath,caseSensitive:i.caseSensitive,end:c},h),m=i.route;if(!f&&c&&n&&!r[r.length-1].route.index&&(f=Te({path:i.relativePath,caseSensitive:i.caseSensitive,end:!1},h)),!f)return null;Object.assign(a,f.params),s.push({params:a,pathname:V([o,f.pathname]),pathnameBase:Sn(V([o,f.pathnameBase])),route:m}),f.pathnameBase!=="/"&&(o=V([o,f.pathnameBase]))}return s}function Te(e,t){typeof e=="string"&&(e={path:e,caseSensitive:!1,end:!0});let[n,r]=bn(e.path,e.caseSensitive,e.end),a=t.match(n);if(!a)return null;let o=a[0],s=o.replace(/(.)\/+$/,"$1"),u=a.slice(1);return{params:r.reduce((c,{paramName:h,isOptional:f},m)=>{if(h==="*"){let y=u[m]||"";s=o.slice(0,o.length-y.length).replace(/(.)\/+$/,"$1")}const b=u[m];return f&&!b?c[h]=void 0:c[h]=(b||"").replace(/%2F/g,"/"),c},{}),pathname:o,pathnameBase:s,pattern:e}}function bn(e,t=!1,n=!0){K(e==="*"||!e.endsWith("*")||e.endsWith("/*"),`Route path "${e}" will be treated as if it were "${e.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${e.replace(/\*$/,"/*")}".`);let r=[],a="^"+e.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(s,u,i,c,h)=>{if(r.push({paramName:u,isOptional:i!=null}),i){let f=h.charAt(c+s.length);return f&&f!=="/"?"/([^\\/]*)":"(?:/([^\\/]*))?"}return"/([^\\/]+)"}).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return e.endsWith("*")?(r.push({paramName:"*"}),a+=e==="*"||e==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?a+="\\/*$":e!==""&&e!=="/"&&(a+="(?:(?=\\/|$))"),[new RegExp(a,t?void 0:"i"),r]}function wn(e){try{return e.split("/").map(t=>decodeURIComponent(t).replace(/\//g,"%2F")).join("/")}catch(t){return K(!1,`The URL path "${e}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${t}).`),e}}function Z(e,t){if(t==="/")return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith("/")?t.length-1:t.length,r=e.charAt(n);return r&&r!=="/"?null:e.slice(n)||"/"}var En=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;function xn(e,t="/"){let{pathname:n,search:r="",hash:a=""}=typeof e=="string"?ue(e):e,o;return n?(n=$t(n),n.startsWith("/")?o=vt(n.substring(1),"/"):o=vt(n,t)):o=t,{pathname:o,search:kn(r),hash:Cn(a)}}function vt(e,t){let n=$e(t).split("/");return e.split("/").forEach(a=>{a===".."?n.length>1&&n.pop():a!=="."&&n.push(a)}),n.length>1?n.join("/"):"/"}function He(e,t,n,r){return`Cannot include a '${e}' character in a manually specified \`to.${t}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${n}\` field. Alternatively you may provide the full path as a string in <Link to="..."> and the router will parse it for you.`}function Rn(e){return e.filter((t,n)=>n===0||t.route.path&&t.route.path.length>0)}function Tt(e){let t=Rn(e);return t.map((n,r)=>r===t.length-1?n.pathname:n.pathnameBase)}function Ze(e,t,n,r=!1){let a;typeof e=="string"?a=ue(e):(a={...e},T(!a.pathname||!a.pathname.includes("?"),He("?","pathname","search",a)),T(!a.pathname||!a.pathname.includes("#"),He("#","pathname","hash",a)),T(!a.search||!a.search.includes("#"),He("#","search","hash",a)));let o=e===""||a.pathname==="",s=o?"/":a.pathname,u;if(s==null)u=n;else{let f=t.length-1;if(!r&&s.startsWith("..")){let m=s.split("/");for(;m[0]==="..";)m.shift(),f-=1;a.pathname=m.join("/")}u=f>=0?t[f]:"/"}let i=xn(a,u),c=s&&s!=="/"&&s.endsWith("/"),h=(o||s===".")&&n.endsWith("/");return!i.pathname.endsWith("/")&&(c||h)&&(i.pathname+="/"),i}var $t=e=>e.replace(/\/\/+/g,"/"),V=e=>$t(e.join("/")),$e=e=>e.replace(/\/+$/,""),Sn=e=>$e(e).replace(/^\/*/,"/"),kn=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,Cn=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e,Nn=class{constructor(e,t,n,r=!1){this.status=e,this.statusText=t||"",this.internal=r,n instanceof Error?(this.data=n.toString(),this.error=n):this.data=n}};function jn(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.internal=="boolean"&&"data"in e}function Pn(e){let t=e.map(n=>n.route.path).filter(Boolean);return V(t)||"/"}var Lt=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function It(e,t){let n=e;if(typeof n!="string"||!En.test(n))return{absoluteURL:void 0,isExternal:!1,to:n};let r=n,a=!1;if(Lt)try{let o=new URL(window.location.href),s=n.startsWith("//")?new URL(o.protocol+n):new URL(n),u=Z(s.pathname,t);s.origin===o.origin&&u!=null?n=u+s.search+s.hash:a=!0}catch{K(!1,`<Link to="${n}"> contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:r,isExternal:a,to:n}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");var _t=["POST","PUT","PATCH","DELETE"];new Set(_t);var Mn=["GET",..._t];new Set(Mn);var ce=l.createContext(null);ce.displayName="DataRouter";var Ie=l.createContext(null);Ie.displayName="DataRouterState";var Bt=l.createContext(!1);function Tn(){return l.useContext(Bt)}var Ft=l.createContext({isTransitioning:!1});Ft.displayName="ViewTransition";var $n=l.createContext(new Map);$n.displayName="Fetchers";var Ln=l.createContext(null);Ln.displayName="Await";var H=l.createContext(null);H.displayName="Navigation";var be=l.createContext(null);be.displayName="Location";var ee=l.createContext({outlet:null,matches:[],isDataRoute:!1});ee.displayName="Route";var et=l.createContext(null);et.displayName="RouteError";var At="REACT_ROUTER_ERROR",In="REDIRECT",_n="ROUTE_ERROR_RESPONSE";function Bn(e){if(e.startsWith(`${At}:${In}:{`))try{let t=JSON.parse(e.slice(28));if(typeof t=="object"&&t&&typeof t.status=="number"&&typeof t.statusText=="string"&&typeof t.location=="string"&&typeof t.reloadDocument=="boolean"&&typeof t.replace=="boolean")return t}catch{}}function Fn(e){if(e.startsWith(`${At}:${_n}:{`))try{let t=JSON.parse(e.slice(40));if(typeof t=="object"&&t&&typeof t.status=="number"&&typeof t.statusText=="string")return new Nn(t.status,t.statusText,t.data)}catch{}}function An(e,{relative:t}={}){T(we(),"useHref() may be used only in the context of a <Router> component.");let{basename:n,navigator:r}=l.useContext(H),{hash:a,pathname:o,search:s}=xe(e,{relative:t}),u=o;return n!=="/"&&(u=o==="/"?n:V([n,o])),r.createHref({pathname:u,search:s,hash:a})}function we(){return l.useContext(be)!=null}function te(){return T(we(),"useLocation() may be used only in the context of a <Router> component."),l.useContext(be).location}var Ot="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function Ut(e){l.useContext(H).static||l.useLayoutEffect(e)}function Ee(){let{isDataRoute:e}=l.useContext(ee);return e?Xn():On()}function On(){T(we(),"useNavigate() may be used only in the context of a <Router> component.");let e=l.useContext(ce),{basename:t,navigator:n}=l.useContext(H),{matches:r}=l.useContext(ee),{pathname:a}=te(),o=JSON.stringify(Tt(r)),s=l.useRef(!1);return Ut(()=>{s.current=!0}),l.useCallback((i,c={})=>{if(K(s.current,Ot),!s.current)return;if(typeof i=="number"){n.go(i);return}let h=Ze(i,JSON.parse(o),a,c.relative==="path");e==null&&t!=="/"&&(h.pathname=h.pathname==="/"?t:V([t,h.pathname])),(c.replace?n.replace:n.push)(h,c.state,c)},[t,n,o,a,e])}l.createContext(null);function xe(e,{relative:t}={}){let{matches:n}=l.useContext(ee),{pathname:r}=te(),a=JSON.stringify(Tt(n));return l.useMemo(()=>Ze(e,JSON.parse(a),r,t==="path"),[e,a,r,t])}function Un(e,t){return Dt(e,t)}function Dt(e,t,n){var g;T(we(),"useRoutes() may be used only in the context of a <Router> component.");let{navigator:r}=l.useContext(H),{matches:a}=l.useContext(ee),o=a[a.length-1],s=o?o.params:{},u=o?o.pathname:"/",i=o?o.pathnameBase:"/",c=o&&o.route;{let v=c&&c.path||"";Ht(u,!c||v.endsWith("*")||v.endsWith("*?"),`You rendered descendant <Routes> (or called \`useRoutes()\`) at "${u}" (under <Route path="${v}">) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render.
|
||
|
||
Please change the parent <Route path="${v}"> to <Route path="${v==="/"?"*":`${v}/*`}">.`)}let h=te(),f;if(t){let v=typeof t=="string"?ue(t):t;T(i==="/"||((g=v.pathname)==null?void 0:g.startsWith(i)),`When overriding the location using \`<Routes location>\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${i}" but pathname "${v.pathname}" was given in the \`location\` prop.`),f=v}else f=h;let m=f.pathname||"/",b=m;if(i!=="/"){let v=i.replace(/^\//,"").split("/");b="/"+m.replace(/^\//,"").split("/").slice(v.length).join("/")}let y=n&&n.state.matches.length?n.state.matches.map(v=>Object.assign(v,{route:n.manifest[v.route.id]||v.route})):jt(e,{pathname:b});K(c||y!=null,`No routes matched location "${f.pathname}${f.search}${f.hash}" `),K(y==null||y[y.length-1].route.element!==void 0||y[y.length-1].route.Component!==void 0||y[y.length-1].route.lazy!==void 0,`Matched leaf route at location "${f.pathname}${f.search}${f.hash}" does not have an element or Component. This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.`);let p=Vn(y&&y.map(v=>Object.assign({},v,{params:Object.assign({},s,v.params),pathname:V([i,r.encodeLocation?r.encodeLocation(v.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:v.pathname]),pathnameBase:v.pathnameBase==="/"?i:V([i,r.encodeLocation?r.encodeLocation(v.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:v.pathnameBase])})),a,n);return t&&p?l.createElement(be.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",mask:void 0,...f},navigationType:"POP"}},p):p}function Dn(){let e=Gn(),t=jn(e)?`${e.status} ${e.statusText}`:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,r="rgba(200,200,200, 0.5)",a={padding:"0.5rem",backgroundColor:r},o={padding:"2px 4px",backgroundColor:r},s=null;return console.error("Error handled by React Router default ErrorBoundary:",e),s=l.createElement(l.Fragment,null,l.createElement("p",null,"💿 Hey developer 👋"),l.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",l.createElement("code",{style:o},"ErrorBoundary")," or"," ",l.createElement("code",{style:o},"errorElement")," prop on your route.")),l.createElement(l.Fragment,null,l.createElement("h2",null,"Unexpected Application Error!"),l.createElement("h3",{style:{fontStyle:"italic"}},t),n?l.createElement("pre",{style:a},n):null,s)}var zn=l.createElement(Dn,null),zt=class extends l.Component{constructor(e){super(e),this.state={location:e.location,revalidation:e.revalidation,error:e.error}}static getDerivedStateFromError(e){return{error:e}}static getDerivedStateFromProps(e,t){return t.location!==e.location||t.revalidation!=="idle"&&e.revalidation==="idle"?{error:e.error,location:e.location,revalidation:e.revalidation}:{error:e.error!==void 0?e.error:t.error,location:t.location,revalidation:e.revalidation||t.revalidation}}componentDidCatch(e,t){this.props.onError?this.props.onError(e,t):console.error("React Router caught the following error during render",e)}render(){let e=this.state.error;if(this.context&&typeof e=="object"&&e&&"digest"in e&&typeof e.digest=="string"){const n=Fn(e.digest);n&&(e=n)}let t=e!==void 0?l.createElement(ee.Provider,{value:this.props.routeContext},l.createElement(et.Provider,{value:e,children:this.props.component})):this.props.children;return this.context?l.createElement(Hn,{error:e},t):t}};zt.contextType=Bt;var We=new WeakMap;function Hn({children:e,error:t}){let{basename:n}=l.useContext(H);if(typeof t=="object"&&t&&"digest"in t&&typeof t.digest=="string"){let r=Bn(t.digest);if(r){let a=We.get(t);if(a)throw a;let o=It(r.location,n);if(Lt&&!We.get(t))if(o.isExternal||r.reloadDocument)window.location.href=o.absoluteURL||o.to;else{const s=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(o.to,{replace:r.replace}));throw We.set(t,s),s}return l.createElement("meta",{httpEquiv:"refresh",content:`0;url=${o.absoluteURL||o.to}`})}}return e}function Wn({routeContext:e,match:t,children:n}){let r=l.useContext(ce);return r&&r.static&&r.staticContext&&(t.route.errorElement||t.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=t.route.id),l.createElement(ee.Provider,{value:e},n)}function Vn(e,t=[],n){let r=n==null?void 0:n.state;if(e==null){if(!r)return null;if(r.errors)e=r.matches;else if(t.length===0&&!r.initialized&&r.matches.length>0)e=r.matches;else return null}let a=e,o=r==null?void 0:r.errors;if(o!=null){let h=a.findIndex(f=>f.route.id&&(o==null?void 0:o[f.route.id])!==void 0);T(h>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(o).join(",")}`),a=a.slice(0,Math.min(a.length,h+1))}let s=!1,u=-1;if(n&&r){s=r.renderFallback;for(let h=0;h<a.length;h++){let f=a[h];if((f.route.HydrateFallback||f.route.hydrateFallbackElement)&&(u=h),f.route.id){let{loaderData:m,errors:b}=r,y=f.route.loader&&!m.hasOwnProperty(f.route.id)&&(!b||b[f.route.id]===void 0);if(f.route.lazy||y){n.isStatic&&(s=!0),u>=0?a=a.slice(0,u+1):a=[a[0]];break}}}}let i=n==null?void 0:n.onError,c=r&&i?(h,f)=>{var m,b;i(h,{location:r.location,params:((b=(m=r.matches)==null?void 0:m[0])==null?void 0:b.params)??{},pattern:Pn(r.matches),errorInfo:f})}:void 0;return a.reduceRight((h,f,m)=>{let b,y=!1,p=null,g=null;r&&(b=o&&f.route.id?o[f.route.id]:void 0,p=f.route.errorElement||zn,s&&(u<0&&m===0?(Ht("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),y=!0,g=null):u===m&&(y=!0,g=f.route.hydrateFallbackElement||null)));let v=t.concat(a.slice(0,m+1)),w=()=>{let E;return b?E=p:y?E=g:f.route.Component?E=l.createElement(f.route.Component,null):f.route.element?E=f.route.element:E=h,l.createElement(Wn,{match:f,routeContext:{outlet:h,matches:v,isDataRoute:r!=null},children:E})};return r&&(f.route.ErrorBoundary||f.route.errorElement||m===0)?l.createElement(zt,{location:r.location,revalidation:r.revalidation,component:p,error:b,children:w(),routeContext:{outlet:null,matches:v,isDataRoute:!0},onError:c}):w()},null)}function tt(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function Jn(e){let t=l.useContext(ce);return T(t,tt(e)),t}function qn(e){let t=l.useContext(Ie);return T(t,tt(e)),t}function Kn(e){let t=l.useContext(ee);return T(t,tt(e)),t}function nt(e){let t=Kn(e),n=t.matches[t.matches.length-1];return T(n.route.id,`${e} can only be used on routes that contain a unique "id"`),n.route.id}function Yn(){return nt("useRouteId")}function Gn(){var r;let e=l.useContext(et),t=qn("useRouteError"),n=nt("useRouteError");return e!==void 0?e:(r=t.errors)==null?void 0:r[n]}function Xn(){let{router:e}=Jn("useNavigate"),t=nt("useNavigate"),n=l.useRef(!1);return Ut(()=>{n.current=!0}),l.useCallback(async(a,o={})=>{K(n.current,Ot),n.current&&(typeof a=="number"?await e.navigate(a):await e.navigate(a,{fromRouteId:t,...o}))},[e,t])}var bt={};function Ht(e,t,n){!t&&!bt[e]&&(bt[e]=!0,K(!1,n))}l.memo(Qn);function Qn({routes:e,manifest:t,future:n,state:r,isStatic:a,onError:o}){return Dt(e,void 0,{manifest:t,state:r,isStatic:a,onError:o})}function je(e){T(!1,"A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.")}function Zn({basename:e="/",children:t=null,location:n,navigationType:r="POP",navigator:a,static:o=!1,useTransitions:s}){T(!we(),"You cannot render a <Router> inside another <Router>. You should never have more than one in your app.");let u=e.replace(/^\/*/,"/"),i=l.useMemo(()=>({basename:u,navigator:a,static:o,useTransitions:s,future:{}}),[u,a,o,s]);typeof n=="string"&&(n=ue(n));let{pathname:c="/",search:h="",hash:f="",state:m=null,key:b="default",mask:y}=n,p=l.useMemo(()=>{let g=Z(c,u);return g==null?null:{location:{pathname:g,search:h,hash:f,state:m,key:b,mask:y},navigationType:r}},[u,c,h,f,m,b,r,y]);return K(p!=null,`<Router basename="${u}"> is not able to match the URL "${c}${h}${f}" because it does not start with the basename, so the <Router> won't render anything.`),p==null?null:l.createElement(H.Provider,{value:i},l.createElement(be.Provider,{children:t,value:p}))}function er({children:e,location:t}){return Un(Ke(e),t)}function Ke(e,t=[]){let n=[];return l.Children.forEach(e,(r,a)=>{if(!l.isValidElement(r))return;let o=[...t,a];if(r.type===l.Fragment){n.push.apply(n,Ke(r.props.children,o));return}T(r.type===je,`[${typeof r.type=="string"?r.type:r.type.name}] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>`),T(!r.props.index||!r.props.children,"An index route cannot have child routes.");let s={id:r.props.id||o.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,middleware:r.props.middleware,loader:r.props.loader,action:r.props.action,hydrateFallbackElement:r.props.hydrateFallbackElement,HydrateFallback:r.props.HydrateFallback,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.hasErrorBoundary===!0||r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(s.children=Ke(r.props.children,o)),n.push(s)}),n}var Pe="get",Me="application/x-www-form-urlencoded";function _e(e){return typeof HTMLElement<"u"&&e instanceof HTMLElement}function tr(e){return _e(e)&&e.tagName.toLowerCase()==="button"}function nr(e){return _e(e)&&e.tagName.toLowerCase()==="form"}function rr(e){return _e(e)&&e.tagName.toLowerCase()==="input"}function ar(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function or(e,t){return e.button===0&&(!t||t==="_self")&&!ar(e)}var ke=null;function sr(){if(ke===null)try{new FormData(document.createElement("form"),0),ke=!1}catch{ke=!0}return ke}var ir=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function Ve(e){return e!=null&&!ir.has(e)?(K(!1,`"${e}" is not a valid \`encType\` for \`<Form>\`/\`<fetcher.Form>\` and will default to "${Me}"`),null):e}function lr(e,t){let n,r,a,o,s;if(nr(e)){let u=e.getAttribute("action");r=u?Z(u,t):null,n=e.getAttribute("method")||Pe,a=Ve(e.getAttribute("enctype"))||Me,o=new FormData(e)}else if(tr(e)||rr(e)&&(e.type==="submit"||e.type==="image")){let u=e.form;if(u==null)throw new Error('Cannot submit a <button> or <input type="submit"> without a <form>');let i=e.getAttribute("formaction")||u.getAttribute("action");if(r=i?Z(i,t):null,n=e.getAttribute("formmethod")||u.getAttribute("method")||Pe,a=Ve(e.getAttribute("formenctype"))||Ve(u.getAttribute("enctype"))||Me,o=new FormData(u,e),!sr()){let{name:c,type:h,value:f}=e;if(h==="image"){let m=c?`${c}.`:"";o.append(`${m}x`,"0"),o.append(`${m}y`,"0")}else c&&o.append(c,f)}}else{if(_e(e))throw new Error('Cannot submit element that is not <form>, <button>, or <input type="submit|image">');n=Pe,r=null,a=Me,s=e}return o&&a==="text/plain"&&(s=o,o=void 0),{action:r,method:n.toLowerCase(),encType:a,formData:o,body:s}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");function rt(e,t){if(e===!1||e===null||typeof e>"u")throw new Error(t)}function Wt(e,t,n,r){let a=typeof e=="string"?new URL(e,typeof window>"u"?"server://singlefetch/":window.location.origin):e;return n?a.pathname.endsWith("/")?a.pathname=`${a.pathname}_.${r}`:a.pathname=`${a.pathname}.${r}`:a.pathname==="/"?a.pathname=`_root.${r}`:t&&Z(a.pathname,t)==="/"?a.pathname=`${$e(t)}/_root.${r}`:a.pathname=`${$e(a.pathname)}.${r}`,a}async function ur(e,t){if(e.id in t)return t[e.id];try{let n=await import(e.module);return t[e.id]=n,n}catch(n){return console.error(`Error loading route module \`${e.module}\`, reloading page...`),console.error(n),window.__reactRouterContext&&window.__reactRouterContext.isSpaMode,window.location.reload(),new Promise(()=>{})}}function cr(e){return e==null?!1:e.href==null?e.rel==="preload"&&typeof e.imageSrcSet=="string"&&typeof e.imageSizes=="string":typeof e.rel=="string"&&typeof e.href=="string"}async function dr(e,t,n){let r=await Promise.all(e.map(async a=>{let o=t.routes[a.route.id];if(o){let s=await ur(o,n);return s.links?s.links():[]}return[]}));return pr(r.flat(1).filter(cr).filter(a=>a.rel==="stylesheet"||a.rel==="preload").map(a=>a.rel==="stylesheet"?{...a,rel:"prefetch",as:"style"}:{...a,rel:"prefetch"}))}function wt(e,t,n,r,a,o){let s=(i,c)=>n[c]?i.route.id!==n[c].route.id:!0,u=(i,c)=>{var h;return n[c].pathname!==i.pathname||((h=n[c].route.path)==null?void 0:h.endsWith("*"))&&n[c].params["*"]!==i.params["*"]};return o==="assets"?t.filter((i,c)=>s(i,c)||u(i,c)):o==="data"?t.filter((i,c)=>{var f;let h=r.routes[i.route.id];if(!h||!h.hasLoader)return!1;if(s(i,c)||u(i,c))return!0;if(i.route.shouldRevalidate){let m=i.route.shouldRevalidate({currentUrl:new URL(a.pathname+a.search+a.hash,window.origin),currentParams:((f=n[0])==null?void 0:f.params)||{},nextUrl:new URL(e,window.origin),nextParams:i.params,defaultShouldRevalidate:!0});if(typeof m=="boolean")return m}return!0}):[]}function hr(e,t,{includeHydrateFallback:n}={}){return fr(e.map(r=>{let a=t.routes[r.route.id];if(!a)return[];let o=[a.module];return a.clientActionModule&&(o=o.concat(a.clientActionModule)),a.clientLoaderModule&&(o=o.concat(a.clientLoaderModule)),n&&a.hydrateFallbackModule&&(o=o.concat(a.hydrateFallbackModule)),a.imports&&(o=o.concat(a.imports)),o}).flat(1))}function fr(e){return[...new Set(e)]}function mr(e){let t={},n=Object.keys(e).sort();for(let r of n)t[r]=e[r];return t}function pr(e,t){let n=new Set;return new Set(t),e.reduce((r,a)=>{let o=JSON.stringify(mr(a));return n.has(o)||(n.add(o),r.push({key:o,link:a})),r},[])}function at(){let e=l.useContext(ce);return rt(e,"You must render this element inside a <DataRouterContext.Provider> element"),e}function gr(){let e=l.useContext(Ie);return rt(e,"You must render this element inside a <DataRouterStateContext.Provider> element"),e}var ot=l.createContext(void 0);ot.displayName="FrameworkContext";function st(){let e=l.useContext(ot);return rt(e,"You must render this element inside a <HydratedRouter> element"),e}function yr(e,t){let n=l.useContext(ot),[r,a]=l.useState(!1),[o,s]=l.useState(!1),{onFocus:u,onBlur:i,onMouseEnter:c,onMouseLeave:h,onTouchStart:f}=t,m=l.useRef(null);l.useEffect(()=>{if(e==="render"&&s(!0),e==="viewport"){let p=v=>{v.forEach(w=>{s(w.isIntersecting)})},g=new IntersectionObserver(p,{threshold:.5});return m.current&&g.observe(m.current),()=>{g.disconnect()}}},[e]),l.useEffect(()=>{if(r){let p=setTimeout(()=>{s(!0)},100);return()=>{clearTimeout(p)}}},[r]);let b=()=>{a(!0)},y=()=>{a(!1),s(!1)};return n?e!=="intent"?[o,m,{}]:[o,m,{onFocus:fe(u,b),onBlur:fe(i,y),onMouseEnter:fe(c,b),onMouseLeave:fe(h,y),onTouchStart:fe(f,b)}]:[!1,m,{}]}function fe(e,t){return n=>{e&&e(n),n.defaultPrevented||t(n)}}function vr({page:e,...t}){let n=Tn(),{router:r}=at(),a=l.useMemo(()=>jt(r.routes,e,r.basename),[r.routes,e,r.basename]);return a?n?l.createElement(wr,{page:e,matches:a,...t}):l.createElement(Er,{page:e,matches:a,...t}):null}function br(e){let{manifest:t,routeModules:n}=st(),[r,a]=l.useState([]);return l.useEffect(()=>{let o=!1;return dr(e,t,n).then(s=>{o||a(s)}),()=>{o=!0}},[e,t,n]),r}function wr({page:e,matches:t,...n}){let r=te(),{future:a}=st(),{basename:o}=at(),s=l.useMemo(()=>{if(e===r.pathname+r.search+r.hash)return[];let u=Wt(e,o,a.unstable_trailingSlashAwareDataRequests,"rsc"),i=!1,c=[];for(let h of t)typeof h.route.shouldRevalidate=="function"?i=!0:c.push(h.route.id);return i&&c.length>0&&u.searchParams.set("_routes",c.join(",")),[u.pathname+u.search]},[o,a.unstable_trailingSlashAwareDataRequests,e,r,t]);return l.createElement(l.Fragment,null,s.map(u=>l.createElement("link",{key:u,rel:"prefetch",as:"fetch",href:u,...n})))}function Er({page:e,matches:t,...n}){let r=te(),{future:a,manifest:o,routeModules:s}=st(),{basename:u}=at(),{loaderData:i,matches:c}=gr(),h=l.useMemo(()=>wt(e,t,c,o,r,"data"),[e,t,c,o,r]),f=l.useMemo(()=>wt(e,t,c,o,r,"assets"),[e,t,c,o,r]),m=l.useMemo(()=>{if(e===r.pathname+r.search+r.hash)return[];let p=new Set,g=!1;if(t.forEach(w=>{var N;let E=o.routes[w.route.id];!E||!E.hasLoader||(!h.some($=>$.route.id===w.route.id)&&w.route.id in i&&((N=s[w.route.id])!=null&&N.shouldRevalidate)||E.hasClientLoader?g=!0:p.add(w.route.id))}),p.size===0)return[];let v=Wt(e,u,a.unstable_trailingSlashAwareDataRequests,"data");return g&&p.size>0&&v.searchParams.set("_routes",t.filter(w=>p.has(w.route.id)).map(w=>w.route.id).join(",")),[v.pathname+v.search]},[u,a.unstable_trailingSlashAwareDataRequests,i,r,o,h,t,e,s]),b=l.useMemo(()=>hr(f,o),[f,o]),y=br(f);return l.createElement(l.Fragment,null,m.map(p=>l.createElement("link",{key:p,rel:"prefetch",as:"fetch",href:p,...n})),b.map(p=>l.createElement("link",{key:p,rel:"modulepreload",href:p,...n})),y.map(({key:p,link:g})=>l.createElement("link",{key:p,nonce:n.nonce,...g,crossOrigin:g.crossOrigin??n.crossOrigin})))}function xr(...e){return t=>{e.forEach(n=>{typeof n=="function"?n(t):n!=null&&(n.current=t)})}}var Rr=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";try{Rr&&(window.__reactRouterVersion="7.15.1")}catch{}function Sr({basename:e,children:t,useTransitions:n,window:r}){let a=l.useRef();a.current==null&&(a.current=nn({window:r,v5Compat:!0}));let o=a.current,[s,u]=l.useState({action:o.action,location:o.location}),i=l.useCallback(c=>{n===!1?u(c):l.startTransition(()=>u(c))},[n]);return l.useLayoutEffect(()=>o.listen(i),[o,i]),l.createElement(Zn,{basename:e,children:t,location:s.location,navigationType:s.action,navigator:o,useTransitions:n})}var Vt=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,Jt=l.forwardRef(function({onClick:t,discover:n="render",prefetch:r="none",relative:a,reloadDocument:o,replace:s,mask:u,state:i,target:c,to:h,preventScrollReset:f,viewTransition:m,defaultShouldRevalidate:b,...y},p){let{basename:g,navigator:v,useTransitions:w}=l.useContext(H),E=typeof h=="string"&&Vt.test(h),N=It(h,g);h=N.to;let $=An(h,{relative:a}),j=te(),J=null;if(u){let W=Ze(u,[],j.mask?j.mask.pathname:"/",!0);g!=="/"&&(W.pathname=W.pathname==="/"?g:V([g,W.pathname])),J=v.createHref(W)}let[ne,re,de]=yr(r,y),Ue=jr(h,{replace:s,mask:u,state:i,target:c,preventScrollReset:f,relative:a,viewTransition:m,defaultShouldRevalidate:b,useTransitions:w});function De(W){t&&t(W),W.defaultPrevented||Ue(W)}let ae=!(N.isExternal||o),oe=l.createElement("a",{...y,...de,href:(ae?J:void 0)||N.absoluteURL||$,onClick:ae?De:t,ref:xr(p,re),target:c,"data-discover":!E&&n==="render"?"true":void 0});return ne&&!E?l.createElement(l.Fragment,null,oe,l.createElement(vr,{page:$})):oe});Jt.displayName="Link";var kr=l.forwardRef(function({"aria-current":t="page",caseSensitive:n=!1,className:r="",end:a=!1,style:o,to:s,viewTransition:u,children:i,...c},h){let f=xe(s,{relative:c.relative}),m=te(),b=l.useContext(Ie),{navigator:y,basename:p}=l.useContext(H),g=b!=null&&Lr(f)&&u===!0,v=y.encodeLocation?y.encodeLocation(f).pathname:f.pathname,w=m.pathname,E=b&&b.navigation&&b.navigation.location?b.navigation.location.pathname:null;n||(w=w.toLowerCase(),E=E?E.toLowerCase():null,v=v.toLowerCase()),E&&p&&(E=Z(E,p)||E);const N=v!=="/"&&v.endsWith("/")?v.length-1:v.length;let $=w===v||!a&&w.startsWith(v)&&w.charAt(N)==="/",j=E!=null&&(E===v||!a&&E.startsWith(v)&&E.charAt(v.length)==="/"),J={isActive:$,isPending:j,isTransitioning:g},ne=$?t:void 0,re;typeof r=="function"?re=r(J):re=[r,$?"active":null,j?"pending":null,g?"transitioning":null].filter(Boolean).join(" ");let de=typeof o=="function"?o(J):o;return l.createElement(Jt,{...c,"aria-current":ne,className:re,ref:h,style:de,to:s,viewTransition:u},typeof i=="function"?i(J):i)});kr.displayName="NavLink";var Cr=l.forwardRef(({discover:e="render",fetcherKey:t,navigate:n,reloadDocument:r,replace:a,state:o,method:s=Pe,action:u,onSubmit:i,relative:c,preventScrollReset:h,viewTransition:f,defaultShouldRevalidate:m,...b},y)=>{let{useTransitions:p}=l.useContext(H),g=Tr(),v=$r(u,{relative:c}),w=s.toLowerCase()==="get"?"get":"post",E=typeof u=="string"&&Vt.test(u),N=$=>{if(i&&i($),$.defaultPrevented)return;$.preventDefault();let j=$.nativeEvent.submitter,J=(j==null?void 0:j.getAttribute("formmethod"))||s,ne=()=>g(j||$.currentTarget,{fetcherKey:t,method:J,navigate:n,replace:a,state:o,relative:c,preventScrollReset:h,viewTransition:f,defaultShouldRevalidate:m});p&&n!==!1?l.startTransition(()=>ne()):ne()};return l.createElement("form",{ref:y,method:w,action:v,onSubmit:r?i:N,...b,"data-discover":!E&&e==="render"?"true":void 0})});Cr.displayName="Form";function Nr(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function qt(e){let t=l.useContext(ce);return T(t,Nr(e)),t}function jr(e,{target:t,replace:n,mask:r,state:a,preventScrollReset:o,relative:s,viewTransition:u,defaultShouldRevalidate:i,useTransitions:c}={}){let h=Ee(),f=te(),m=xe(e,{relative:s});return l.useCallback(b=>{if(or(b,t)){b.preventDefault();let y=n!==void 0?n:ve(f)===ve(m),p=()=>h(e,{replace:y,mask:r,state:a,preventScrollReset:o,relative:s,viewTransition:u,defaultShouldRevalidate:i});c?l.startTransition(()=>p()):p()}},[f,h,m,n,r,a,t,e,o,s,u,i,c])}var Pr=0,Mr=()=>`__${String(++Pr)}__`;function Tr(){let{router:e}=qt("useSubmit"),{basename:t}=l.useContext(H),n=Yn(),r=e.fetch,a=e.navigate;return l.useCallback(async(o,s={})=>{let{action:u,method:i,encType:c,formData:h,body:f}=lr(o,t);if(s.navigate===!1){let m=s.fetcherKey||Mr();await r(m,n,s.action||u,{defaultShouldRevalidate:s.defaultShouldRevalidate,preventScrollReset:s.preventScrollReset,formData:h,body:f,formMethod:s.method||i,formEncType:s.encType||c,flushSync:s.flushSync})}else await a(s.action||u,{defaultShouldRevalidate:s.defaultShouldRevalidate,preventScrollReset:s.preventScrollReset,formData:h,body:f,formMethod:s.method||i,formEncType:s.encType||c,replace:s.replace,state:s.state,fromRouteId:n,flushSync:s.flushSync,viewTransition:s.viewTransition})},[r,a,t,n])}function $r(e,{relative:t}={}){let{basename:n}=l.useContext(H),r=l.useContext(ee);T(r,"useFormAction must be used inside a RouteContext");let[a]=r.matches.slice(-1),o={...xe(e||".",{relative:t})},s=te();if(e==null){o.search=s.search;let u=new URLSearchParams(o.search),i=u.getAll("index");if(i.some(h=>h==="")){u.delete("index"),i.filter(f=>f).forEach(f=>u.append("index",f));let h=u.toString();o.search=h?`?${h}`:""}}return(!e||e===".")&&a.route.index&&(o.search=o.search?o.search.replace(/^\?/,"?index&"):"?index"),n!=="/"&&(o.pathname=o.pathname==="/"?n:V([n,o.pathname])),ve(o)}function Lr(e,{relative:t}={}){let n=l.useContext(Ft);T(n!=null,"`useViewTransitionState` must be used within `react-router-dom`'s `RouterProvider`. Did you accidentally import `RouterProvider` from `react-router`?");let{basename:r}=qt("useViewTransitionState"),a=xe(e,{relative:t});if(!n.isTransitioning)return!1;let o=Z(n.currentLocation.pathname,r)||n.currentLocation.pathname,s=Z(n.nextLocation.pathname,r)||n.nextLocation.pathname;return Te(a.pathname,s)!=null||Te(a.pathname,o)!=null}const _=6,se=2.6,q=240,X={LE:[10,13],RE:[29,13],MO:[20,27]};function Y(e,t,n){const r=[],a=Math.ceil(n);for(let o=-a;o<=a;o++)for(let s=-a;s<=a;s++)o*o+s*s<=n*n&&r.push([e+o,t+s]);return r}function F(e,t,n,r,a,o=5){const s=[],u=new Set;for(let i=r;i<=a;i+=o){const c=i*Math.PI/180,h=Math.round(e+n*Math.cos(c)),f=Math.round(t+n*Math.sin(c)),m=`${h},${f}`;u.has(m)||(u.add(m),s.push([h,f]))}return s}function G(e,t,n){const r=[];for(let a=Math.round(e-n);a<=Math.round(e+n);a++)r.push([a,Math.round(t)]);return r}function Ye(e,t,n,r){const a=[],o=new Set,s=Math.round(n);for(let u=-s;u<=s;u++){const i=u/s*Math.PI,c=Math.round(t+r*Math.sin(i)),h=`${e+u},${c}`;o.has(h)||(o.add(h),a.push([e+u,c]))}return a}function Ir(e,t,n,r){const a=[],o=Math.round(n);for(let s=-o;s<=o;s++){const u=s+o;a.push([e+s,Math.round(t+(u%4<2?r:-r))])}return a}function Et(e,t){return[[-1,-2],[1,-2],[-2,-1],[-1,-1],[0,-1],[1,-1],[2,-1],[-2,0],[-1,0],[0,0],[1,0],[2,0],[-1,1],[0,1],[1,1],[0,2]].map(([n,r])=>[e+n,t+r])}function xt(e,t,n,r){const a=[],o=new Set,s=Math.round(r*2*Math.PI*8);for(let u=0;u<=s;u++){const i=u/s*r*2*Math.PI,c=u/s*n,h=Math.round(e+c*Math.cos(i)),f=Math.round(t+c*Math.sin(i)),m=`${h},${f}`;o.has(m)||(o.add(m),a.push([h,f]))}return a}function Je(e,t){return[[e-1,t-1],[e,t-1],[e+1,t-1],[e,t],[e-1,t+1],[e,t+1],[e+1,t+1]]}function Rt(e,t){return[...F(e,t-1,1.5,200,360,30),[e,t+1],[e,t+3]]}function Q(e,t){return{iris:Y(e,t,3),pupil:Y(e,t,1.5),hl:[[e-1,t-1]],lash:G(e,t-3,3)}}function z(e,t){return{iris:Y(e,t,4),pupil:Y(e,t,2),hl:[[e-1,t-1],[e-2,t-2]],lash:G(e,t-4,4)}}function le(e,t){return{iris:Y(e,t,3).filter(([,r])=>r>=t-1&&r<=t+1),pupil:[[e,t]],lash:G(e,t-1,2)}}function ie(e,t){return{iris:Y(e,t,3).filter(([,r])=>r>=t),pupil:[[e-1,t],[e,t],[e+1,t]],lash:G(e,t,3)}}function Ce(e,t){return{iris:Y(e,t+1,3),pupil:Y(e,t+2,1.5),hl:[[e-1,t]],lash:G(e,t-2,2)}}function Ne(e,t,n=2){return{iris:Y(e,t,3),pupil:Y(e+n,t,1.5),hl:[[e+n-1,t-1]],lash:G(e,t-3,3)}}function _r(e,t){return{wink:F(e,t+1,3,200,340,15)}}function ge(e,t){return F(e,t,5,25,155)}function Ge(e,t){return F(e,t,7,15,165)}function St(e,t){return G(e,t,5)}function Br(e,t){const n=F(e-2,t,4,30,120,10),r=F(e+3,t+2,2.5,270,360,15),a=new Set(n.map(([o,s])=>`${o},${s}`));return[...n,...r.filter(([o,s])=>!a.has(`${o},${s}`))]}function Fr(e,t){const n=F(e-2,t,2,200,340,20),r=F(e+2,t,2,200,340,20),a=G(e,t+2,3),o=new Set(n.map(([s,u])=>`${s},${u}`));return[...n,...r.filter(([s,u])=>!o.has(`${s},${u}`)),...a]}function Ar(e,t,n){const r=Math.abs(Math.sin(n*1.4));if(r<.25)return F(e,t,4,20,160,8);const a=r<.65?1:2,o=F(e,t-a,3.5,190,350,8),s=F(e,t+a,3,10,170,8),u=new Set(o.map(([i,c])=>`${i},${c}`));return[...o,...s.filter(([i,c])=>!u.has(`${i},${c}`))]}const[R,S]=X.LE,[k,C]=X.RE,[P,M]=X.MO,B="#22CCFF",Or=[{id:"idle",label:"😐 待机",color:"#00FFEE",category:"interaction",canBlink:!0,leftEye:Q(R,S),rightEye:Q(k,C),mouth:ge(P,M)},{id:"listening",label:"👂 聆听",color:"#44AAFF",category:"interaction",canBlink:!0,leftEye:z(R,S),rightEye:z(k,C),mouth:F(P,M,3,0,180)},{id:"thinking",label:"🤔 思考",color:"#FFCC00",category:"interaction",canBlink:!0,leftEye:le(R,S),rightEye:Q(k,C),mouth:Ye(P,M,5,1),extras:[{dots:Rt(R-1,S-6),color:"#FFCC00",alpha:.75}]},{id:"speaking",label:"💬 说话",color:"#FFFFFF",pupilColor:"#002233",category:"interaction",canBlink:!0,leftEye:Q(R,S),rightEye:Q(k,C),speakingMouth:!0},{id:"happy",label:"😊 开心",color:"#FF44AA",category:"interaction",canBlink:!0,leftEye:{heart:Et(R,S)},rightEye:{heart:Et(k,C)},mouth:Ge(P,M)},{id:"error",label:"😵 错误",color:"#FF4400",category:"interaction",canBlink:!0,leftEye:{spiral:xt(R,S,4,2)},rightEye:{spiral:xt(k,C,4,2)},mouth:Ir(P,M,5,1.5)},{id:"confused",label:"😕 困惑",color:"#BB44FF",category:"interaction",canBlink:!0,leftEye:z(R,S),rightEye:le(k,C),mouth:Ye(P,M,5,1.5),extras:[{dots:Rt(k+1,C-6),color:"#BB44FF",alpha:.75}]},{id:"dreaming",label:"💤 做梦",color:"#5566FF",category:"interaction",canBlink:!0,leftEye:ie(R,S),rightEye:ie(k,C),mouth:ge(P,M),extras:[{dots:Je(24,10),color:"#5566FF",alpha:.85,zzzIndex:0},{dots:Je(28,7),color:"#7788FF",alpha:.75,zzzIndex:1},{dots:Je(32,4),color:"#99AAFF",alpha:.65,zzzIndex:2}]}],Kt=[{id:"natural_smile",label:"01 自然微笑",color:B,category:"auto",canBlink:!0,leftEye:Q(R,S),rightEye:Q(k,C),mouth:ge(P,M)},{id:"calm_relax",label:"02 平静放松",color:B,category:"auto",canBlink:!0,leftEye:ie(R,S),rightEye:ie(k,C),mouth:St(P,M)},{id:"curious_observe",label:"03 好奇观察",color:B,category:"auto",canBlink:!0,leftEye:z(R,S),rightEye:z(k,C),mouth:F(P,M,4,30,150,8)},{id:"light_joy",label:"04 轻松愉悦",color:B,category:"auto",canBlink:!0,leftEye:le(R,S),rightEye:le(k,C),mouth:Ge(P,M)},{id:"side_think",label:"05 侧目思考",color:B,category:"auto",canBlink:!0,leftEye:Ne(R,S,2),rightEye:Ne(k,C,2),mouth:Ye(P,M,4,1)},{id:"warm_friendly",label:"06 温和友善",color:B,category:"auto",canBlink:!0,leftEye:Ce(R,S),rightEye:Ce(k,C),mouth:ge(P,M)},{id:"quiet_listen",label:"07 静静聆听",color:B,category:"auto",canBlink:!0,leftEye:Q(R,S),rightEye:Q(k,C),mouth:G(P,M,4)},{id:"focus_gaze",label:"08 专注注视",color:B,category:"auto",canBlink:!0,leftEye:z(R,S),rightEye:z(k,C),mouth:St(P,M)},{id:"quiet_wait",label:"09 安静等待",color:B,category:"auto",canBlink:!0,leftEye:ie(R,S),rightEye:ie(k,C),mouth:F(P,M,4,30,150,8)},{id:"slow_blink",label:"10 慢眨眼",color:B,category:"auto",canBlink:!0,leftEye:le(R,S),rightEye:le(k,C),mouth:ge(P,M)},{id:"look_around",label:"11 左右扫视",color:B,category:"auto",canBlink:!0,leftEye:Ne(R,S,-2),rightEye:Ne(k,C,-2),mouth:G(P,M,4)},{id:"playful",label:"12 小小调皮",color:B,category:"auto",canBlink:!1,leftEye:_r(R,S),rightEye:z(k,C),mouth:Br(P,M)},{id:"joyful_wait",label:"13 愉悦期待",color:B,category:"auto",canBlink:!0,leftEye:z(R,S),rightEye:z(k,C),mouth:Ge(P,M)},{id:"slight_surprise",label:"14 轻微惊喜",color:B,category:"auto",canBlink:!0,leftEye:z(R,S),rightEye:z(k,C),mouth:F(P,M,3,0,180,10)},{id:"gentle_gaze",label:"15 温柔注视",color:B,category:"auto",canBlink:!0,leftEye:Ce(R,S),rightEye:Ce(k,C),mouth:F(P,M,4,30,150,8)},{id:"spaceout",label:"16 发呆放空",color:B,category:"auto",canBlink:!0,leftEye:ie(R,S),rightEye:ie(k,C),mouth:Fr(P,M)}],it=[...Or,...Kt],me=Kt.map(e=>e.id),Xe=Object.fromEntries(it.map(e=>[e.id,e]));function U(e,t,n,r,a=null){if(!(!t||t.length===0)){if(e.save(),a==null){e.globalAlpha=Math.max(0,Math.min(1,r)),e.shadowBlur=14,e.shadowColor=n,e.fillStyle=n,e.beginPath();for(const[o,s]of t){const u=o*_+_/2,i=s*_+_/2;e.moveTo(u+se,i),e.arc(u,i,se,0,Math.PI*2)}e.fill(),e.shadowBlur=0,e.fillStyle="rgba(255,255,255,0.55)",e.beginPath();for(const[o,s]of t){const u=o*_+_/2,i=s*_+_/2;e.moveTo(u+se*.38,i),e.arc(u,i,se*.38,0,Math.PI*2)}e.fill()}else{const o=[],s=[];for(const[i,c]of t){const h=(i*7.3+c*13.1)*.31;(Math.sin(a*1.1+h)>0?o:s).push([i,c])}const u=(i,c,h)=>{if(i.length){e.globalAlpha=Math.max(0,Math.min(1,c)),e.shadowBlur=h,e.shadowColor=n,e.fillStyle=n,e.beginPath();for(const[f,m]of i){const b=f*_+_/2,y=m*_+_/2;e.moveTo(b+se,y),e.arc(b,y,se,0,Math.PI*2)}e.fill()}};u(s,r*.68,7),u(o,r,20),e.globalAlpha=Math.max(0,Math.min(1,r*.55)),e.shadowBlur=0,e.fillStyle="rgba(255,255,255,0.55)",e.beginPath();for(const[i,c]of t){const h=i*_+_/2,f=c*_+_/2;e.moveTo(h+se*.38,f),e.arc(h,f,se*.38,0,Math.PI*2)}e.fill()}e.restore()}}function pe(e,t,n){return n>=1?e:e.map(([r,a])=>[r,t+(a-t)*n])}function Ur(e,t){if(e===null)return 1;const n=t-e;return n<120?1-n/120:n<220?0:n<340?(n-220)/120:1}function kt(e,t,n,r,a,o,s,u,i){if(!t)return;const c=o||"#001020";t.iris?(U(e,pe(t.iris,r,u),a,s,i),U(e,pe(t.pupil,r,u),c,s,null),t.hl&&U(e,pe(t.hl,r,u),"#ffffff",s*.9,null),t.lash&&U(e,pe(t.lash,r,u),a,s,null)):t.closed!==void 0?(U(e,t.closed,a,s,i),t.lash&&U(e,t.lash,a,s,null)):t.wink?U(e,t.wink,a,s,i):t.heart?U(e,t.heart,a,s,i):t.spiral?U(e,t.spiral,a,s,i):t.star?U(e,t.star,a,s,i):t.pts&&U(e,pe(t.pts,r,u),a,s,i)}function Dr({expressionId:e,scale:t=2}){const n=l.useRef(null),r=l.useRef({currentId:e,previousId:null,transitionStart:null,blinkStart:null,nextBlink:performance.now()+2e3+Math.random()*2e3,t:0,raf:null});return l.useEffect(()=>{const a=r.current;e!==a.currentId&&(a.previousId=a.currentId,a.currentId=e,a.transitionStart=performance.now(),a.blinkStart=null)},[e]),l.useEffect(()=>{const o=n.current.getContext("2d"),s=r.current;function u(c,h,f,m){if(!c)return;kt(o,c.leftEye,X.LE[0],X.LE[1],c.color,c.pupilColor,h,f,m),kt(o,c.rightEye,X.RE[0],X.RE[1],c.color,c.pupilColor,h,f,m);const b=c.speakingMouth?Ar(X.MO[0],X.MO[1],s.t):c.mouth;if(b&&U(o,b,c.color,h,m),c.extras)for(const y of c.extras){let p=h*y.alpha;if(y.zzzIndex!==void 0){const g=s.t-y.zzzIndex*1.2;p*=.35+.65*(Math.sin(g)*.5+.5)}U(o,y.dots,y.color,p,null)}}function i(){const c=performance.now();s.t+=.04,o.clearRect(0,0,q,q),o.fillStyle="#000",o.fillRect(0,0,q,q);let h=1,f=0;if(s.transitionStart!==null){const p=c-s.transitionStart;if(p>=380)s.transitionStart=null,s.previousId=null;else{const g=p/380,v=g<.5?2*g*g:1-(-2*g+2)**2/2;h=v,f=1-v}}const m=Xe[s.currentId];!s.blinkStart&&s.transitionStart===null&&(m!=null&&m.canBlink)&&c>=s.nextBlink&&(s.blinkStart=c,s.nextBlink=c+2500+Math.random()*2500),s.blinkStart!==null&&c-s.blinkStart>=340&&(s.blinkStart=null);const b=Ur(s.blinkStart,c);s.previousId&&u(Xe[s.previousId],f,1,null);const y=s.transitionStart===null?s.t:null;u(m,h,b,y),o.save(),o.globalAlpha=.04,o.fillStyle="#000";for(let p=0;p<q;p+=2)o.fillRect(0,p+1,q,1);o.restore(),s.raf=requestAnimationFrame(i)}return s.raf=requestAnimationFrame(i),()=>cancelAnimationFrame(s.raf)},[]),d.jsx("canvas",{ref:n,width:q,height:q,style:{width:q*t,height:q*t,imageRendering:"pixelated",borderRadius:14,boxShadow:"0 0 40px rgba(0,255,200,0.2)",display:"block"}})}function zr({base64:e,mimeType:t="audio/mp3",label:n="🔊"}){const r=e?`data:${t};base64,${e}`:null;return r?d.jsx("audio",{className:"audio-btn",controls:!0,src:r,title:n,preload:"none"}):null}function Hr({role:e,text:t,audioBase64:n,audioMime:r}){const a=e==="user";return d.jsxs("div",{className:`bubble ${a?"bubble-user":"bubble-bot"}`,children:[d.jsx("div",{className:"bubble-label",children:a?"你":"JBOT"}),d.jsx("div",{className:"bubble-text",children:t}),n&&d.jsx(zr,{base64:n,mimeType:r||"audio/mp3"})]})}function Wr({messages:e,voiceStatus:t}){const n=l.useRef(null),r=Ee();return l.useEffect(()=>{var a;(a=n.current)==null||a.scrollIntoView({behavior:"smooth"})},[e]),d.jsxs("section",{className:"chat-panel",children:[d.jsxs("div",{className:"chat-header",children:[d.jsx("span",{className:"chat-title",children:"对话"}),d.jsx("button",{className:"history-link",onClick:()=>r("/history"),children:"历史记录 →"})]}),t&&d.jsx("div",{className:`voice-status voice-status-${t.type}`,children:t.text}),d.jsxs("div",{className:"chat-messages",children:[e.length===0?d.jsx("p",{className:"chat-empty",children:"按住 Space 开始说话…"}):e.map(a=>d.jsx(Hr,{role:a.role,text:a.text,audioBase64:a.audioBase64,audioMime:a.audioMime},a.id)),d.jsx("div",{ref:n})]})]})}const Be="jbot_memory",Vr=100;function ye(){try{return JSON.parse(localStorage.getItem(Be)||"[]")}catch{return[]}}function Jr(e){const t=ye(),n=e.toLowerCase().trim();if(t.some(a=>a.text.toLowerCase().trim()===n))return null;const r={id:crypto.randomUUID(),text:e.trim(),createdAt:Date.now()};return localStorage.setItem(Be,JSON.stringify([r,...t].slice(0,Vr))),r}function qr(e){localStorage.setItem(Be,JSON.stringify(ye().filter(t=>t.id!==e)))}function Kr(){localStorage.removeItem(Be)}function Yr({memories:e,onMemoriesChange:t}){const[n,r]=l.useState(!1),a=s=>{qr(s),t()},o=()=>{window.confirm("清空所有记忆?")&&(Kr(),t())};return d.jsxs("div",{className:"memory-panel",children:[d.jsxs("button",{className:"memory-toggle",onClick:()=>r(s=>!s),children:[d.jsx("span",{children:"🧠 长期记忆"}),d.jsx("span",{className:"memory-badge",children:e.length}),d.jsx("span",{className:"memory-arrow",children:n?"▲":"▼"})]}),n&&d.jsx("div",{className:"memory-body",children:e.length===0?d.jsx("p",{className:"memory-empty",children:"对话后会自动记住关于你的信息"}):d.jsxs(d.Fragment,{children:[d.jsx("ul",{className:"memory-list",children:e.map(s=>d.jsxs("li",{className:"memory-item",children:[d.jsx("span",{className:"memory-text",children:s.text}),d.jsx("button",{className:"memory-del",onClick:()=>a(s.id),title:"删除",children:"×"})]},s.id))}),d.jsx("button",{className:"memory-clear",onClick:o,children:"清空全部"})]})})]})}const Fe="/api/jbot";async function Gr(e,t=[],n={}){const r=await fetch(`${Fe}/chat/`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({messages:e,memories:t,settings:n})});if(!r.ok){const a=await r.json().catch(()=>({}));throw new Error(a.error||`HTTP ${r.status}`)}return r.json()}async function Xr(e,t="audio/webm"){const n=await fetch(`${Fe}/asr/`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({audioBase64:e,format:t})});if(!n.ok){const r=await n.json().catch(()=>({}));throw new Error(r.error||`HTTP ${n.status}`)}return n.json()}async function Qr(e,t){const n=await fetch(`${Fe}/tts/`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({text:e,voice:t})});if(!n.ok){const r=await n.json().catch(()=>({}));throw new Error(r.error||`HTTP ${n.status}`)}return n.json()}async function Zr(e,t){try{const n=await fetch(`${Fe}/memory/extract/`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userText:e,botText:t})});if(!n.ok)return[];const{facts:r=[]}=await n.json();return r}catch{return[]}}function ea(){const[e,t]=l.useState(!1),n=l.useRef(null),r=l.useRef(null),a=l.useRef(null),o=l.useRef([]),s=l.useRef(""),u=l.useCallback(async()=>{var m;if(e)return;o.current=[],s.current="",(m=n.current)!=null&&m.active||(n.current=await navigator.mediaDevices.getUserMedia({audio:!0}));const c=MediaRecorder.isTypeSupported("audio/webm;codecs=opus")?"audio/webm;codecs=opus":"audio/webm",h=new MediaRecorder(n.current,{mimeType:c});h.ondataavailable=b=>{b.data.size>0&&o.current.push(b.data)},h.start(100),r.current=h;const f=window.SpeechRecognition||window.webkitSpeechRecognition;if(f){const b=new f;b.lang="zh-CN",b.interimResults=!0,b.continuous=!0,b.onresult=y=>{let p="";for(const g of y.results)g.isFinal&&(p+=g[0].transcript);p&&(s.current=p)},b.onerror=y=>{console.warn("SpeechRecognition error:",y.error)},b.start(),a.current=b}t(!0)},[e]),i=l.useCallback(()=>new Promise(c=>{var m,b;t(!1);const h=s.current;try{(m=a.current)==null||m.stop()}catch{}a.current=null,(b=n.current)==null||b.getTracks().forEach(y=>y.stop()),n.current=null;const f=r.current;if(!f)return c({transcript:h,audioBase64:null,mimeType:null});f.onstop=async()=>{const y=f.mimeType;if(o.current.length===0)return c({transcript:h,audioBase64:null,mimeType:y});const p=new Blob(o.current,{type:y}),g=new FileReader;g.onloadend=()=>{c({transcript:h,audioBase64:g.result.split(",")[1],mimeType:y})},g.readAsDataURL(p)},f.stop(),r.current=null}),[]);return{isRecording:e,start:u,stop:i}}const Ae="jbot_history",ta=200;function Le(){try{return JSON.parse(localStorage.getItem(Ae)||"[]")}catch{return[]}}function na(e){const t=Le(),n=[{id:crypto.randomUUID(),timestamp:Date.now(),...e},...t];return localStorage.setItem(Ae,JSON.stringify(n.slice(0,ta))),n[0]}function ra(){localStorage.removeItem(Ae)}function aa(e){localStorage.setItem(Ae,JSON.stringify(Le().filter(t=>t.id!==e)))}const Yt=[{id:"zh_female_vv_uranus_bigtts",label:"灵儿",lang:"中文",gender:"女",style:"亲切"},{id:"zh_female_tianmei_conversation_bigtts",label:"甜美",lang:"中文",gender:"女",style:"温柔"},{id:"zh_female_linjing_conversation_bigtts",label:"琳静",lang:"中文",gender:"女",style:"知性"},{id:"zh_female_qingxin_conversation_bigtts",label:"清新",lang:"中文",gender:"女",style:"清新"},{id:"zh_male_m191_uranus_bigtts",label:"豪远",lang:"中文",gender:"男",style:"标准"},{id:"zh_male_haoran_conversation_bigtts",label:"豪然",lang:"中文",gender:"男",style:"稳重"},{id:"zh_male_m372_conversation_bigtts",label:"温和男声",lang:"中文",gender:"男",style:"温和"},{id:"en_female_sarah_jupiter_bigtts",label:"Sarah",lang:"EN",gender:"女",style:"Warm"},{id:"en_male_adam_mars_bigtts",label:"Adam",lang:"EN",gender:"男",style:"Clear"}],Gt="zh_female_vv_uranus_bigtts";function oa(e){const t=Yt.find(n=>n.id===e);return t?`${t.label} · ${t.lang} ${t.gender}`:e}const lt="jbot_settings",Qe={robotName:"JBOT",robotPersonality:"你是一个友好、简洁、偶尔幽默的AI机器人助手。回复控制在80字以内。",language:"auto",voiceId:Gt,customVoiceId:"",responseMaxWords:80};function Oe(){try{const e=JSON.parse(localStorage.getItem(lt)||"{}");return{...Qe,...e}}catch{return{...Qe}}}function sa(e){const n={...Oe(),...e};return localStorage.setItem(lt,JSON.stringify(n)),n}function ia(){return localStorage.removeItem(lt),{...Qe}}function Ct(e=null){var n;const t=e||Oe();return((n=t.customVoiceId)==null?void 0:n.trim())||t.voiceId||Gt}const la=it.filter(e=>e.category==="interaction"),ua=it.filter(e=>e.category==="auto"),ca={1:"idle",2:"listening",3:"thinking",4:"speaking",5:"happy",6:"error",7:"confused",8:"dreaming",q:"natural_smile",w:"calm_relax",e:"curious_observe",r:"light_joy",t:"side_think",y:"warm_friendly",u:"quiet_listen",i:"focus_gaze"};async function da(e,t="audio/mp3"){return new Promise(n=>{const r=new Audio(`data:${t};base64,${e}`);r.onended=n,r.onerror=n,r.play().catch(n)})}function ha(e){return new Promise(t=>{if(!window.speechSynthesis)return t();const n=new SpeechSynthesisUtterance(e);n.lang="zh-CN",n.rate=1.05,n.onend=t,n.onerror=t,window.speechSynthesis.speak(n)})}function fa(){var ht;const e=Ee(),[t,n]=l.useState(me[0]),[r,a]=l.useState(!0),[o,s]=l.useState(1),[u,i]=l.useState(1e4),c=l.useRef(null),h=l.useRef(!0),f=l.useRef(me[0]),m=l.useRef(null),b=l.useRef(1e4);l.useEffect(()=>{h.current=r},[r]),l.useEffect(()=>{f.current=t},[t]),l.useEffect(()=>{b.current=u},[u]);const y=l.useCallback(()=>{clearTimeout(c.current),c.current=null},[]);m.current=()=>{if(y(),!h.current)return;const x=1+(Math.random()-.5)*.3;c.current=setTimeout(()=>{var I;const D=me.filter(O=>O!==f.current),L=D[Math.floor(Math.random()*D.length)];n(L),(I=m.current)==null||I.call(m)},b.current*x)};const p=l.useCallback(()=>{var x;return(x=m.current)==null?void 0:x.call(m)},[]);l.useEffect(()=>(r?p():y(),y),[r,p,y]);const g=l.useCallback(x=>{y(),n(x),h.current&&p()},[y,p]),{start:v,stop:w}=ea(),[E,N]=l.useState("idle"),[$,j]=l.useState(null),[J,ne]=l.useState([]),[re,de]=l.useState([]),[Ue,De]=l.useState(()=>ye()),ae=l.useRef("idle"),oe=l.useRef(!1),W=l.useCallback(()=>De(ye()),[]);l.useEffect(()=>{ae.current=E},[E]);const ut=(x,D,L,I)=>{const O={id:crypto.randomUUID(),role:x,text:D,audioBase64:L,audioMime:I};return ne(ze=>[...ze.slice(-29),O]),O},ct=l.useCallback(async()=>{if(!(oe.current||ae.current!=="idle")){oe.current=!0,y(),N("acquiring"),j({type:"acquiring",text:"⏳ 麦克风准备中…"});try{await v()}catch(x){console.warn("[PTT] Mic acquisition failed:",x.message),oe.current=!1,N("idle"),j({type:"error",text:"⚠ 麦克风不可用"}),setTimeout(()=>j(null),2500),p();return}n("listening"),N("listening"),j({type:"listening",text:"🎙 请讲话 · 松开 Space 结束"})}},[y,v,p]),dt=l.useCallback(async()=>{if(!oe.current)return;if(oe.current=!1,ae.current==="acquiring"){N("idle"),j(null),p();return}if(ae.current!=="listening")return;N("thinking"),n("thinking"),j({type:"thinking",text:"⚙ 识别中…"});const{transcript:x,audioBase64:D,mimeType:L}=await w();let I="";if(D)try{j({type:"thinking",text:"⚙ 识别中…"});const{text:A}=await Xr(D,L||"audio/webm");I=(A==null?void 0:A.trim())||""}catch(A){console.warn("[ASR] Volcengine failed, using browser transcript:",A.message)}if(I||(I=x.trim()),!I){N("idle"),n("idle"),j(null);return}ut("user",I,D,L),j({type:"thinking",text:"⚙ 思考中…"});let O="";try{const A=ye().map(en=>en.text),Re=Oe(),Se=[...re,{role:"user",content:I}],{text:Zt}=await Gr(Se.slice(-10),A,Re);O=Zt,de([...Se,{role:"assistant",content:O}].slice(-20))}catch(A){O=`对话出错: ${A.message}`}n("speaking"),N("speaking"),j({type:"speaking",text:"🔊 播放中…"});const ze=Ct();let he=null,ft=!1;try{const{audioBase64:A}=await Qr(O,ze);he=A}catch(A){console.warn("[TTS] Volcengine unavailable, using browser TTS:",A.message),ft=!0}ft&&j({type:"speaking",text:"🔊 播放中… (浏览器语音)"}),ut("bot",O,he,"audio/mp3"),na({userText:I,botText:O,userAudioBase64:D,userAudioMime:L,botAudioBase64:he,botAudioMime:"audio/mp3"}),Zr(I,O).then(A=>{let Re=!1;A.forEach(Se=>{Jr(Se)&&(Re=!0)}),Re&&W()}).catch(()=>{}),he?await da(he,"audio/mp3"):await ha(O),N("idle"),j(null);const Qt=me[Math.floor(Math.random()*me.length)];n(Qt),p()},[w,re,p]);l.useEffect(()=>{function x(L){if(!(L.target.tagName==="INPUT"||L.target.tagName==="TEXTAREA")){if(L.code==="Space"&&!L.repeat){L.preventDefault(),ct();return}if(ae.current==="idle"){const I=ca[L.key.toLowerCase()];I&&g(I)}}}function D(L){L.code==="Space"&&(L.preventDefault(),dt())}return window.addEventListener("keydown",x),window.addEventListener("keyup",D),()=>{window.removeEventListener("keydown",x),window.removeEventListener("keyup",D)}},[ct,dt,g]);const Xt=oa(Ct());return d.jsxs("div",{className:"app",children:[d.jsxs("header",{className:"hdr",children:[d.jsxs("h1",{children:["J",d.jsx("span",{className:"accent",children:"BOT"})]}),d.jsx("p",{className:"subtitle",children:"AI Robot Face · 240×240"}),d.jsxs("nav",{className:"hdr-nav",children:[d.jsx("button",{className:"hdr-link",onClick:()=>e("/history"),children:"历史"}),d.jsx("button",{className:"hdr-link",onClick:()=>e("/settings"),children:"设置"})]})]}),d.jsxs("div",{className:"page-body",children:[d.jsxs("aside",{className:"left-col",children:[d.jsxs("section",{className:"screen-wrap",children:[d.jsxs("div",{className:"scale-controls",children:[d.jsx("button",{className:`scale-btn${o===1?" active":""}`,onClick:()=>s(1),children:"1×"}),d.jsx("button",{className:`scale-btn${o===2?" active":""}`,onClick:()=>s(2),children:"2×"})]}),d.jsx("div",{className:"bezel",children:d.jsx(Dr,{expressionId:t,scale:o})}),d.jsx("div",{className:"expr-label",children:(ht=Xe[t])==null?void 0:ht.label})]}),d.jsxs("section",{className:"panel",children:[d.jsxs("div",{className:"panel-section",children:[d.jsxs("h3",{children:["交互状态 ",d.jsx("span",{className:"key-hint",children:"1 – 8"})]}),d.jsx("div",{className:"btn-grid",children:la.map(x=>d.jsx("button",{className:`ebtn${t===x.id?" active":""}`,style:{"--c":x.color},onClick:()=>g(x.id),children:x.label},x.id))})]}),d.jsxs("div",{className:"panel-section",children:[d.jsxs("h3",{children:["微表情 ",d.jsx("span",{className:"key-hint",children:"Q–I · 自动"})]}),d.jsx("div",{className:"btn-grid btn-grid-4",children:ua.map(x=>d.jsx("button",{className:`ebtn${t===x.id?" active":""}`,style:{"--c":x.color},onClick:()=>g(x.id),children:x.label},x.id))})]}),d.jsxs("label",{className:"toggle",children:[d.jsx("input",{type:"checkbox",checked:r,onChange:x=>a(x.target.checked)}),d.jsx("span",{children:"自动轮换微表情"})]}),d.jsxs("div",{className:"switch-interval",children:[d.jsxs("div",{className:"switch-interval-label",children:["切换间隔 ",d.jsxs("span",{className:"interval-val",children:[Math.round(u/1e3)," 秒"]})]}),d.jsx("input",{type:"range",min:"3",max:"30",step:"1",value:Math.round(u/1e3),onChange:x=>i(Number(x.target.value)*1e3)}),d.jsxs("div",{className:"interval-ticks",children:[d.jsx("span",{children:"3s"}),d.jsx("span",{children:"30s"})]})]}),d.jsxs("p",{className:"hint",children:["按住 ",d.jsx("kbd",{children:"Space"})," 说话 · 松开发送 · ",d.jsx("button",{className:"hist-inline-link",onClick:()=>e("/history"),children:"历史记录"})]}),d.jsxs("p",{className:"hint voice-hint",children:["🔊 音色: ",d.jsx("button",{className:"hist-inline-link",onClick:()=>e("/settings"),children:Xt})]}),d.jsx(Yr,{memories:Ue,onMemoriesChange:W})]})]}),d.jsx("div",{className:"right-col",children:d.jsx(Wr,{messages:J,voiceStatus:$})})]})]})}function Nt({base64:e,mimeType:t="audio/mp3"}){return e?d.jsx("audio",{className:"hist-audio",controls:!0,src:`data:${t};base64,${e}`,preload:"none"}):null}function ma({entry:e,onDelete:t}){const r=new Date(e.timestamp).toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"});return d.jsxs("article",{className:"hist-entry",children:[d.jsxs("div",{className:"hist-meta",children:[d.jsx("span",{className:"hist-time",children:r}),d.jsx("button",{className:"hist-del",onClick:()=>t(e.id),title:"删除",children:"✕"})]}),d.jsxs("div",{className:"hist-row hist-row-user",children:[d.jsx("div",{className:"hist-role",children:"你"}),d.jsxs("div",{className:"hist-body",children:[d.jsx("p",{className:"hist-text",children:e.userText||"(语音消息)"}),d.jsx(Nt,{base64:e.userAudioBase64,mimeType:e.userAudioMime||"audio/webm"})]})]}),d.jsxs("div",{className:"hist-row hist-row-bot",children:[d.jsx("div",{className:"hist-role",children:"JBOT"}),d.jsxs("div",{className:"hist-body",children:[d.jsx("p",{className:"hist-text",children:e.botText||""}),d.jsx(Nt,{base64:e.botAudioBase64,mimeType:"audio/mp3"})]})]})]})}function pa(){const[e,t]=l.useState(()=>Le()),n=Ee(),r=o=>{aa(o),t(Le())},a=()=>{window.confirm("确认清空所有历史记录?")&&(ra(),t([]))};return d.jsxs("div",{className:"hist-page",children:[d.jsxs("div",{className:"hist-toolbar",children:[d.jsx("button",{className:"hist-back",onClick:()=>n("/"),children:"← 返回"}),d.jsx("h1",{className:"hist-heading",children:"历史对话"}),d.jsx("button",{className:"hist-clear",onClick:a,disabled:e.length===0,children:"清空"})]}),e.length===0?d.jsx("p",{className:"hist-empty",children:"暂无历史记录"}):d.jsx("div",{className:"hist-list",children:e.map(o=>d.jsx(ma,{entry:o,onDelete:r},o.id))})]})}function ga(){const e=Ee(),[t,n]=l.useState(()=>Oe()),[r,a]=l.useState(!1),o=(i,c)=>{n(h=>({...h,[i]:c})),a(!1)},s=()=>{sa(t),a(!0),setTimeout(()=>a(!1),2e3)},u=()=>{if(window.confirm("重置所有设置为默认值?")){const i=ia();n(i),a(!1)}};return d.jsxs("div",{className:"settings-page",children:[d.jsxs("div",{className:"settings-toolbar",children:[d.jsx("button",{className:"settings-back",onClick:()=>e("/"),children:"← 返回"}),d.jsx("h1",{className:"settings-heading",children:"全局设置"}),d.jsx("button",{className:"settings-save",onClick:s,children:r?"✓ 已保存":"保存"})]}),d.jsxs("div",{className:"settings-body",children:[d.jsxs("section",{className:"settings-section",children:[d.jsx("h2",{className:"settings-section-title",children:"🤖 机器人身份"}),d.jsxs("label",{className:"settings-label",children:["名字",d.jsx("input",{className:"settings-input",value:t.robotName,onChange:i=>o("robotName",i.target.value),placeholder:"JBOT"})]}),d.jsxs("label",{className:"settings-label",children:["人格描述 ",d.jsx("span",{className:"settings-hint",children:"会注入到每轮对话的系统提示"}),d.jsx("textarea",{className:"settings-textarea",rows:3,value:t.robotPersonality,onChange:i=>o("robotPersonality",i.target.value),placeholder:"你是一个友好、简洁、偶尔幽默的AI机器人助手。回复控制在80字以内。"})]})]}),d.jsxs("section",{className:"settings-section",children:[d.jsx("h2",{className:"settings-section-title",children:"👤 用户背景"}),d.jsxs("label",{className:"settings-label",children:["关于你 ",d.jsx("span",{className:"settings-hint",children:"机器人会了解你的背景,更好地回答"}),d.jsx("textarea",{className:"settings-textarea",rows:3,value:t.extraContext||"",onChange:i=>o("extraContext",i.target.value),placeholder:"例如:我叫小明,是一名软件工程师,在上海工作,对AI和嵌入式系统感兴趣。"})]})]}),d.jsxs("section",{className:"settings-section",children:[d.jsx("h2",{className:"settings-section-title",children:"🌐 语言"}),d.jsx("div",{className:"settings-radio-group",children:[{value:"auto",label:"自动(跟随用户语言)"},{value:"zh-CN",label:"中文"},{value:"en-US",label:"English"}].map(i=>d.jsxs("label",{className:"settings-radio-label",children:[d.jsx("input",{type:"radio",name:"language",value:i.value,checked:t.language===i.value,onChange:()=>o("language",i.value)}),i.label]},i.value))})]}),d.jsxs("section",{className:"settings-section",children:[d.jsx("h2",{className:"settings-section-title",children:"🔊 语音音色"}),d.jsx("div",{className:"settings-voice-grid",children:Yt.map(i=>d.jsxs("button",{className:`settings-voice-btn ${!t.customVoiceId&&t.voiceId===i.id?"active":""}`,onClick:()=>{o("voiceId",i.id),o("customVoiceId","")},children:[d.jsx("span",{className:"voice-btn-label",children:i.label}),d.jsxs("span",{className:"voice-btn-meta",children:[i.lang," · ",i.gender," · ",i.style]})]},i.id))}),d.jsxs("label",{className:"settings-label settings-label-mt",children:["自定义音色 ID ",d.jsx("span",{className:"settings-hint",children:"填写后会覆盖上方选择"}),d.jsx("input",{className:"settings-input",value:t.customVoiceId||"",onChange:i=>o("customVoiceId",i.target.value),placeholder:"例如 zh_female_vv_uranus_bigtts"})]}),d.jsxs("p",{className:"settings-hint-block",children:["完整音色列表见"," ",d.jsx("a",{href:"https://www.volcengine.com/docs/6561/1257544",target:"_blank",rel:"noreferrer",children:"火山引擎 TTS 音色文档"})]})]}),d.jsxs("section",{className:"settings-section settings-section-danger",children:[d.jsx("h2",{className:"settings-section-title",children:"⚠️ 重置"}),d.jsx("button",{className:"settings-reset-btn",onClick:u,children:"重置为默认设置"})]})]})]})}tn.createRoot(document.getElementById("jbot-root")).render(d.jsx(l.StrictMode,{children:d.jsx(Sr,{basename:"/jbot",children:d.jsxs(er,{children:[d.jsx(je,{path:"/",element:d.jsx(fa,{})}),d.jsx(je,{path:"/history",element:d.jsx(pa,{})}),d.jsx(je,{path:"/settings",element:d.jsx(ga,{})})]})})}));
|