Files
links/static/dist/jbot.js
T
junvandCopilot bb3fe1b554 jbot: disable local memory in Hermes Agent mode
In Hermes mode JBOT is a pure voice UI — memory is owned by the Agent:
- Backend: sys prompt excludes local memories when backend_mode=hermes
- Backend: config_view now returns backendMode so the frontend can adapt
- Frontend: App.jsx loads backendMode on mount via apiConfig()
- Frontend: memories not passed to apiChat() when isHermesMode
- Frontend: memory extraction (apiExtractMemory) skipped when isHermesMode
- Frontend: MemoryPanel hidden in Hermes mode; replaced by subtle
  '🧠 Hermes Agent 模式 · 记忆由 Agent 管理' badge

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-17 14:13:37 +10:00

13 lines
71 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import{r as l,j as i,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 yt="popstate";function vt(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 d;let s=(d=a.state)==null?void 0:d.masked,{pathname:o,search:u,hash:c}=s||r.location;return Ye("",{pathname:o,search:u,hash:c},a.state&&a.state.usr||null,a.state&&a.state.key||"default",s?{pathname:r.location.pathname,search:r.location.search,hash:r.location.hash}:void 0)}function n(r,a){return typeof a=="string"?a:we(a)}return an(t,n,null,e)}function T(e,t){if(e===!1||e===null||typeof e>"u")throw new Error(t)}function q(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 bt(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 Ye(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 we({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:s=!1}=r,o=a.history,u="POP",c=null,d=m();d==null&&(d=0,o.replaceState({...o.state,idx:d},""));function m(){return(o.state||{idx:null}).idx}function h(){u="POP";let f=m(),y=f==null?null:f-d;d=f,c&&c({action:u,location:b.location,delta:y})}function p(f,y){u="PUSH";let w=vt(f)?f:Ye(b.location,f,y);d=m()+1;let x=bt(w,d),A=b.createHref(w.mask||w);try{o.pushState(x,"",A)}catch(R){if(R instanceof DOMException&&R.name==="DataCloneError")throw R;a.location.assign(A)}s&&c&&c({action:u,location:b.location,delta:1})}function g(f,y){u="REPLACE";let w=vt(f)?f:Ye(b.location,f,y);d=m();let x=bt(w,d),A=b.createHref(w.mask||w);o.replaceState(x,"",A),s&&c&&c({action:u,location:b.location,delta:0})}function v(f){return sn(f)}let b={get action(){return u},get location(){return e(a,o)},listen(f){if(c)throw new Error("A history only accepts one active listener");return a.addEventListener(yt,h),c=f,()=>{a.removeEventListener(yt,h),c=null}},createHref(f){return t(a,f)},createURL:v,encodeLocation(f){let y=v(f);return{pathname:y.pathname,search:y.search,hash:y.hash}},push:p,replace:g,go(f){return o.go(f)}};return b}function sn(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:we(e);return r=r.replace(/ $/,"%20"),!t&&r.startsWith("//")&&(r=n+r),new URL(r,n)}function At(e,t,n="/"){return on(e,t,n,!1)}function on(e,t,n,r,a){let s=typeof t=="string"?ue(t):t,o=ee(s.pathname||"/",n);if(o==null)return null;let u=ln(e),c=null,d=wn(o);for(let m=0;c==null&&m<u.length;++m)c=vn(u[m],d,r);return c}function ln(e){let t=Pt(e);return cn(t),t}function Pt(e,t=[],n=[],r="",a=!1){let s=(o,u,c=a,d)=>{let m={relativePath:d===void 0?o.path||"":d,caseSensitive:o.caseSensitive===!0,childrenIndex:u,route:o};if(m.relativePath.startsWith("/")){if(!m.relativePath.startsWith(r)&&c)return;T(m.relativePath.startsWith(r),`Absolute route path "${m.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),m.relativePath=m.relativePath.slice(r.length)}let h=V([r,m.relativePath]),p=n.concat(m);o.children&&o.children.length>0&&(T(o.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${h}".`),Pt(o.children,t,p,h,c)),!(o.path==null&&!o.index)&&t.push({path:h,score:gn(h,o.index),routesMeta:p})};return e.forEach((o,u)=>{var c;if(o.path===""||!((c=o.path)!=null&&c.includes("?")))s(o,u);else for(let d of It(o.path))s(o,u,!0,d)}),t}function It(e){let t=e.split("/");if(t.length===0)return[];let[n,...r]=t,a=n.endsWith("?"),s=n.replace(/\?$/,"");if(r.length===0)return a?[s,""]:[s];let o=It(r.join("/")),u=[];return u.push(...o.map(c=>c===""?s:[s,c].join("/"))),a&&u.push(...o),u.map(c=>e.startsWith("/")&&c===""?"/":c)}function cn(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 un=/^:[\w-]+$/,dn=3,hn=2,fn=1,mn=10,pn=-2,wt=e=>e==="*";function gn(e,t){let n=e.split("/"),r=n.length;return n.some(wt)&&(r+=pn),t&&(r+=hn),n.filter(a=>!wt(a)).reduce((a,s)=>a+(un.test(s)?dn:s===""?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={},s="/",o=[];for(let u=0;u<r.length;++u){let c=r[u],d=u===r.length-1,m=s==="/"?t:t.slice(s.length)||"/",h=Le({path:c.relativePath,caseSensitive:c.caseSensitive,end:d},m),p=c.route;if(!h&&d&&n&&!r[r.length-1].route.index&&(h=Le({path:c.relativePath,caseSensitive:c.caseSensitive,end:!1},m)),!h)return null;Object.assign(a,h.params),o.push({params:a,pathname:V([s,h.pathname]),pathnameBase:Sn(V([s,h.pathnameBase])),route:p}),h.pathnameBase!=="/"&&(s=V([s,h.pathnameBase]))}return o}function Le(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 s=a[0],o=s.replace(/(.)\/+$/,"$1"),u=a.slice(1);return{params:r.reduce((d,{paramName:m,isOptional:h},p)=>{if(m==="*"){let v=u[p]||"";o=s.slice(0,s.length-v.length).replace(/(.)\/+$/,"$1")}const g=u[p];return h&&!g?d[m]=void 0:d[m]=(g||"").replace(/%2F/g,"/"),d},{}),pathname:s,pathnameBase:o,pattern:e}}function bn(e,t=!1,n=!0){q(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,(o,u,c,d,m)=>{if(r.push({paramName:u,isOptional:c!=null}),c){let h=m.charAt(d+o.length);return h&&h!=="/"?"/([^\\/]*)":"(?:/([^\\/]*))?"}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 q(!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 ee(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 xn=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;function En(e,t="/"){let{pathname:n,search:r="",hash:a=""}=typeof e=="string"?ue(e):e,s;return n?(n=Lt(n),n.startsWith("/")?s=xt(n.substring(1),"/"):s=xt(n,t)):s=t,{pathname:s,search:kn(r),hash:Nn(a)}}function xt(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 Ke(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 _t(e){let t=Rn(e);return t.map((n,r)=>r===t.length-1?n.pathname:n.pathnameBase)}function nt(e,t,n,r=!1){let a;typeof e=="string"?a=ue(e):(a={...e},T(!a.pathname||!a.pathname.includes("?"),Ke("?","pathname","search",a)),T(!a.pathname||!a.pathname.includes("#"),Ke("#","pathname","hash",a)),T(!a.search||!a.search.includes("#"),Ke("#","search","hash",a)));let s=e===""||a.pathname==="",o=s?"/":a.pathname,u;if(o==null)u=n;else{let h=t.length-1;if(!r&&o.startsWith("..")){let p=o.split("/");for(;p[0]==="..";)p.shift(),h-=1;a.pathname=p.join("/")}u=h>=0?t[h]:"/"}let c=En(a,u),d=o&&o!=="/"&&o.endsWith("/"),m=(s||o===".")&&n.endsWith("/");return!c.pathname.endsWith("/")&&(d||m)&&(c.pathname+="/"),c}var Lt=e=>e.replace(/\/\/+/g,"/"),V=e=>Lt(e.join("/")),$e=e=>e.replace(/\/+$/,""),Sn=e=>$e(e).replace(/^\/*/,"/"),kn=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,Nn=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e,Cn=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 Mn(e){let t=e.map(n=>n.route.path).filter(Boolean);return V(t)||"/"}var $t=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function Bt(e,t){let n=e;if(typeof n!="string"||!xn.test(n))return{absoluteURL:void 0,isExternal:!1,to:n};let r=n,a=!1;if($t)try{let s=new URL(window.location.href),o=n.startsWith("//")?new URL(s.protocol+n):new URL(n),u=ee(o.pathname,t);o.origin===s.origin&&u!=null?n=u+o.search+o.hash:a=!0}catch{q(!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 Ft=["POST","PUT","PATCH","DELETE"];new Set(Ft);var Tn=["GET",...Ft];new Set(Tn);var de=l.createContext(null);de.displayName="DataRouter";var Fe=l.createContext(null);Fe.displayName="DataRouterState";var Ot=l.createContext(!1);function An(){return l.useContext(Ot)}var Dt=l.createContext({isTransitioning:!1});Dt.displayName="ViewTransition";var Pn=l.createContext(new Map);Pn.displayName="Fetchers";var In=l.createContext(null);In.displayName="Await";var W=l.createContext(null);W.displayName="Navigation";var Ee=l.createContext(null);Ee.displayName="Location";var te=l.createContext({outlet:null,matches:[],isDataRoute:!1});te.displayName="Route";var rt=l.createContext(null);rt.displayName="RouteError";var Ut="REACT_ROUTER_ERROR",_n="REDIRECT",Ln="ROUTE_ERROR_RESPONSE";function $n(e){if(e.startsWith(`${Ut}:${_n}:{`))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 Bn(e){if(e.startsWith(`${Ut}:${Ln}:{`))try{let t=JSON.parse(e.slice(40));if(typeof t=="object"&&t&&typeof t.status=="number"&&typeof t.statusText=="string")return new Cn(t.status,t.statusText,t.data)}catch{}}function Fn(e,{relative:t}={}){T(Re(),"useHref() may be used only in the context of a <Router> component.");let{basename:n,navigator:r}=l.useContext(W),{hash:a,pathname:s,search:o}=ke(e,{relative:t}),u=s;return n!=="/"&&(u=s==="/"?n:V([n,s])),r.createHref({pathname:u,search:o,hash:a})}function Re(){return l.useContext(Ee)!=null}function ne(){return T(Re(),"useLocation() may be used only in the context of a <Router> component."),l.useContext(Ee).location}var Ht="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function zt(e){l.useContext(W).static||l.useLayoutEffect(e)}function Se(){let{isDataRoute:e}=l.useContext(te);return e?Xn():On()}function On(){T(Re(),"useNavigate() may be used only in the context of a <Router> component.");let e=l.useContext(de),{basename:t,navigator:n}=l.useContext(W),{matches:r}=l.useContext(te),{pathname:a}=ne(),s=JSON.stringify(_t(r)),o=l.useRef(!1);return zt(()=>{o.current=!0}),l.useCallback((c,d={})=>{if(q(o.current,Ht),!o.current)return;if(typeof c=="number"){n.go(c);return}let m=nt(c,JSON.parse(s),a,d.relative==="path");e==null&&t!=="/"&&(m.pathname=m.pathname==="/"?t:V([t,m.pathname])),(d.replace?n.replace:n.push)(m,d.state,d)},[t,n,s,a,e])}l.createContext(null);function ke(e,{relative:t}={}){let{matches:n}=l.useContext(te),{pathname:r}=ne(),a=JSON.stringify(_t(n));return l.useMemo(()=>nt(e,JSON.parse(a),r,t==="path"),[e,a,r,t])}function Dn(e,t){return Wt(e,t)}function Wt(e,t,n){var f;T(Re(),"useRoutes() may be used only in the context of a <Router> component.");let{navigator:r}=l.useContext(W),{matches:a}=l.useContext(te),s=a[a.length-1],o=s?s.params:{},u=s?s.pathname:"/",c=s?s.pathnameBase:"/",d=s&&s.route;{let y=d&&d.path||"";Kt(u,!d||y.endsWith("*")||y.endsWith("*?"),`You rendered descendant <Routes> (or called \`useRoutes()\`) at "${u}" (under <Route path="${y}">) 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="${y}"> to <Route path="${y==="/"?"*":`${y}/*`}">.`)}let m=ne(),h;if(t){let y=typeof t=="string"?ue(t):t;T(c==="/"||((f=y.pathname)==null?void 0:f.startsWith(c)),`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 "${c}" but pathname "${y.pathname}" was given in the \`location\` prop.`),h=y}else h=m;let p=h.pathname||"/",g=p;if(c!=="/"){let y=c.replace(/^\//,"").split("/");g="/"+p.replace(/^\//,"").split("/").slice(y.length).join("/")}let v=n&&n.state.matches.length?n.state.matches.map(y=>Object.assign(y,{route:n.manifest[y.route.id]||y.route})):At(e,{pathname:g});q(d||v!=null,`No routes matched location "${h.pathname}${h.search}${h.hash}" `),q(v==null||v[v.length-1].route.element!==void 0||v[v.length-1].route.Component!==void 0||v[v.length-1].route.lazy!==void 0,`Matched leaf route at location "${h.pathname}${h.search}${h.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 b=Vn(v&&v.map(y=>Object.assign({},y,{params:Object.assign({},o,y.params),pathname:V([c,r.encodeLocation?r.encodeLocation(y.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:y.pathname]),pathnameBase:y.pathnameBase==="/"?c:V([c,r.encodeLocation?r.encodeLocation(y.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:y.pathnameBase])})),a,n);return t&&b?l.createElement(Ee.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",mask:void 0,...h},navigationType:"POP"}},b):b}function Un(){let e=Yn(),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},s={padding:"2px 4px",backgroundColor:r},o=null;return console.error("Error handled by React Router default ErrorBoundary:",e),o=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:s},"ErrorBoundary")," or"," ",l.createElement("code",{style:s},"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,o)}var Hn=l.createElement(Un,null),Vt=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=Bn(e.digest);n&&(e=n)}let t=e!==void 0?l.createElement(te.Provider,{value:this.props.routeContext},l.createElement(rt.Provider,{value:e,children:this.props.component})):this.props.children;return this.context?l.createElement(zn,{error:e},t):t}};Vt.contextType=Ot;var Je=new WeakMap;function zn({children:e,error:t}){let{basename:n}=l.useContext(W);if(typeof t=="object"&&t&&"digest"in t&&typeof t.digest=="string"){let r=$n(t.digest);if(r){let a=Je.get(t);if(a)throw a;let s=Bt(r.location,n);if($t&&!Je.get(t))if(s.isExternal||r.reloadDocument)window.location.href=s.absoluteURL||s.to;else{const o=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(s.to,{replace:r.replace}));throw Je.set(t,o),o}return l.createElement("meta",{httpEquiv:"refresh",content:`0;url=${s.absoluteURL||s.to}`})}}return e}function Wn({routeContext:e,match:t,children:n}){let r=l.useContext(de);return r&&r.static&&r.staticContext&&(t.route.errorElement||t.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=t.route.id),l.createElement(te.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,s=r==null?void 0:r.errors;if(s!=null){let m=a.findIndex(h=>h.route.id&&(s==null?void 0:s[h.route.id])!==void 0);T(m>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(s).join(",")}`),a=a.slice(0,Math.min(a.length,m+1))}let o=!1,u=-1;if(n&&r){o=r.renderFallback;for(let m=0;m<a.length;m++){let h=a[m];if((h.route.HydrateFallback||h.route.hydrateFallbackElement)&&(u=m),h.route.id){let{loaderData:p,errors:g}=r,v=h.route.loader&&!p.hasOwnProperty(h.route.id)&&(!g||g[h.route.id]===void 0);if(h.route.lazy||v){n.isStatic&&(o=!0),u>=0?a=a.slice(0,u+1):a=[a[0]];break}}}}let c=n==null?void 0:n.onError,d=r&&c?(m,h)=>{var p,g;c(m,{location:r.location,params:((g=(p=r.matches)==null?void 0:p[0])==null?void 0:g.params)??{},pattern:Mn(r.matches),errorInfo:h})}:void 0;return a.reduceRight((m,h,p)=>{let g,v=!1,b=null,f=null;r&&(g=s&&h.route.id?s[h.route.id]:void 0,b=h.route.errorElement||Hn,o&&(u<0&&p===0?(Kt("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),v=!0,f=null):u===p&&(v=!0,f=h.route.hydrateFallbackElement||null)));let y=t.concat(a.slice(0,p+1)),w=()=>{let x;return g?x=b:v?x=f:h.route.Component?x=l.createElement(h.route.Component,null):h.route.element?x=h.route.element:x=m,l.createElement(Wn,{match:h,routeContext:{outlet:m,matches:y,isDataRoute:r!=null},children:x})};return r&&(h.route.ErrorBoundary||h.route.errorElement||p===0)?l.createElement(Vt,{location:r.location,revalidation:r.revalidation,component:b,error:g,children:w(),routeContext:{outlet:null,matches:y,isDataRoute:!0},onError:d}):w()},null)}function at(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function Kn(e){let t=l.useContext(de);return T(t,at(e)),t}function Jn(e){let t=l.useContext(Fe);return T(t,at(e)),t}function qn(e){let t=l.useContext(te);return T(t,at(e)),t}function st(e){let t=qn(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 Gn(){return st("useRouteId")}function Yn(){var r;let e=l.useContext(rt),t=Jn("useRouteError"),n=st("useRouteError");return e!==void 0?e:(r=t.errors)==null?void 0:r[n]}function Xn(){let{router:e}=Kn("useNavigate"),t=st("useNavigate"),n=l.useRef(!1);return zt(()=>{n.current=!0}),l.useCallback(async(a,s={})=>{q(n.current,Ht),n.current&&(typeof a=="number"?await e.navigate(a):await e.navigate(a,{fromRouteId:t,...s}))},[e,t])}var Et={};function Kt(e,t,n){!t&&!Et[e]&&(Et[e]=!0,q(!1,n))}l.memo(Qn);function Qn({routes:e,manifest:t,future:n,state:r,isStatic:a,onError:s}){return Wt(e,void 0,{manifest:t,state:r,isStatic:a,onError:s})}function Pe(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:s=!1,useTransitions:o}){T(!Re(),"You cannot render a <Router> inside another <Router>. You should never have more than one in your app.");let u=e.replace(/^\/*/,"/"),c=l.useMemo(()=>({basename:u,navigator:a,static:s,useTransitions:o,future:{}}),[u,a,s,o]);typeof n=="string"&&(n=ue(n));let{pathname:d="/",search:m="",hash:h="",state:p=null,key:g="default",mask:v}=n,b=l.useMemo(()=>{let f=ee(d,u);return f==null?null:{location:{pathname:f,search:m,hash:h,state:p,key:g,mask:v},navigationType:r}},[u,d,m,h,p,g,r,v]);return q(b!=null,`<Router basename="${u}"> is not able to match the URL "${d}${m}${h}" because it does not start with the basename, so the <Router> won't render anything.`),b==null?null:l.createElement(W.Provider,{value:c},l.createElement(Ee.Provider,{children:t,value:b}))}function er({children:e,location:t}){return Dn(Xe(e),t)}function Xe(e,t=[]){let n=[];return l.Children.forEach(e,(r,a)=>{if(!l.isValidElement(r))return;let s=[...t,a];if(r.type===l.Fragment){n.push.apply(n,Xe(r.props.children,s));return}T(r.type===Pe,`[${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 o={id:r.props.id||s.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&&(o.children=Xe(r.props.children,s)),n.push(o)}),n}var Ie="get",_e="application/x-www-form-urlencoded";function Oe(e){return typeof HTMLElement<"u"&&e instanceof HTMLElement}function tr(e){return Oe(e)&&e.tagName.toLowerCase()==="button"}function nr(e){return Oe(e)&&e.tagName.toLowerCase()==="form"}function rr(e){return Oe(e)&&e.tagName.toLowerCase()==="input"}function ar(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function sr(e,t){return e.button===0&&(!t||t==="_self")&&!ar(e)}var Me=null;function or(){if(Me===null)try{new FormData(document.createElement("form"),0),Me=!1}catch{Me=!0}return Me}var ir=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function qe(e){return e!=null&&!ir.has(e)?(q(!1,`"${e}" is not a valid \`encType\` for \`<Form>\`/\`<fetcher.Form>\` and will default to "${_e}"`),null):e}function lr(e,t){let n,r,a,s,o;if(nr(e)){let u=e.getAttribute("action");r=u?ee(u,t):null,n=e.getAttribute("method")||Ie,a=qe(e.getAttribute("enctype"))||_e,s=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 c=e.getAttribute("formaction")||u.getAttribute("action");if(r=c?ee(c,t):null,n=e.getAttribute("formmethod")||u.getAttribute("method")||Ie,a=qe(e.getAttribute("formenctype"))||qe(u.getAttribute("enctype"))||_e,s=new FormData(u,e),!or()){let{name:d,type:m,value:h}=e;if(m==="image"){let p=d?`${d}.`:"";s.append(`${p}x`,"0"),s.append(`${p}y`,"0")}else d&&s.append(d,h)}}else{if(Oe(e))throw new Error('Cannot submit element that is not <form>, <button>, or <input type="submit|image">');n=Ie,r=null,a=_e,o=e}return s&&a==="text/plain"&&(o=s,s=void 0),{action:r,method:n.toLowerCase(),encType:a,formData:s,body:o}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");function ot(e,t){if(e===!1||e===null||typeof e>"u")throw new Error(t)}function Jt(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&&ee(a.pathname,t)==="/"?a.pathname=`${$e(t)}/_root.${r}`:a.pathname=`${$e(a.pathname)}.${r}`,a}async function cr(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 ur(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 s=t.routes[a.route.id];if(s){let o=await cr(s,n);return o.links?o.links():[]}return[]}));return pr(r.flat(1).filter(ur).filter(a=>a.rel==="stylesheet"||a.rel==="preload").map(a=>a.rel==="stylesheet"?{...a,rel:"prefetch",as:"style"}:{...a,rel:"prefetch"}))}function Rt(e,t,n,r,a,s){let o=(c,d)=>n[d]?c.route.id!==n[d].route.id:!0,u=(c,d)=>{var m;return n[d].pathname!==c.pathname||((m=n[d].route.path)==null?void 0:m.endsWith("*"))&&n[d].params["*"]!==c.params["*"]};return s==="assets"?t.filter((c,d)=>o(c,d)||u(c,d)):s==="data"?t.filter((c,d)=>{var h;let m=r.routes[c.route.id];if(!m||!m.hasLoader)return!1;if(o(c,d)||u(c,d))return!0;if(c.route.shouldRevalidate){let p=c.route.shouldRevalidate({currentUrl:new URL(a.pathname+a.search+a.hash,window.origin),currentParams:((h=n[0])==null?void 0:h.params)||{},nextUrl:new URL(e,window.origin),nextParams:c.params,defaultShouldRevalidate:!0});if(typeof p=="boolean")return p}return!0}):[]}function hr(e,t,{includeHydrateFallback:n}={}){return fr(e.map(r=>{let a=t.routes[r.route.id];if(!a)return[];let s=[a.module];return a.clientActionModule&&(s=s.concat(a.clientActionModule)),a.clientLoaderModule&&(s=s.concat(a.clientLoaderModule)),n&&a.hydrateFallbackModule&&(s=s.concat(a.hydrateFallbackModule)),a.imports&&(s=s.concat(a.imports)),s}).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 s=JSON.stringify(mr(a));return n.has(s)||(n.add(s),r.push({key:s,link:a})),r},[])}function it(){let e=l.useContext(de);return ot(e,"You must render this element inside a <DataRouterContext.Provider> element"),e}function gr(){let e=l.useContext(Fe);return ot(e,"You must render this element inside a <DataRouterStateContext.Provider> element"),e}var lt=l.createContext(void 0);lt.displayName="FrameworkContext";function ct(){let e=l.useContext(lt);return ot(e,"You must render this element inside a <HydratedRouter> element"),e}function yr(e,t){let n=l.useContext(lt),[r,a]=l.useState(!1),[s,o]=l.useState(!1),{onFocus:u,onBlur:c,onMouseEnter:d,onMouseLeave:m,onTouchStart:h}=t,p=l.useRef(null);l.useEffect(()=>{if(e==="render"&&o(!0),e==="viewport"){let b=y=>{y.forEach(w=>{o(w.isIntersecting)})},f=new IntersectionObserver(b,{threshold:.5});return p.current&&f.observe(p.current),()=>{f.disconnect()}}},[e]),l.useEffect(()=>{if(r){let b=setTimeout(()=>{o(!0)},100);return()=>{clearTimeout(b)}}},[r]);let g=()=>{a(!0)},v=()=>{a(!1),o(!1)};return n?e!=="intent"?[s,p,{}]:[s,p,{onFocus:pe(u,g),onBlur:pe(c,v),onMouseEnter:pe(d,g),onMouseLeave:pe(m,v),onTouchStart:pe(h,g)}]:[!1,p,{}]}function pe(e,t){return n=>{e&&e(n),n.defaultPrevented||t(n)}}function vr({page:e,...t}){let n=An(),{router:r}=it(),a=l.useMemo(()=>At(r.routes,e,r.basename),[r.routes,e,r.basename]);return a?n?l.createElement(wr,{page:e,matches:a,...t}):l.createElement(xr,{page:e,matches:a,...t}):null}function br(e){let{manifest:t,routeModules:n}=ct(),[r,a]=l.useState([]);return l.useEffect(()=>{let s=!1;return dr(e,t,n).then(o=>{s||a(o)}),()=>{s=!0}},[e,t,n]),r}function wr({page:e,matches:t,...n}){let r=ne(),{future:a}=ct(),{basename:s}=it(),o=l.useMemo(()=>{if(e===r.pathname+r.search+r.hash)return[];let u=Jt(e,s,a.unstable_trailingSlashAwareDataRequests,"rsc"),c=!1,d=[];for(let m of t)typeof m.route.shouldRevalidate=="function"?c=!0:d.push(m.route.id);return c&&d.length>0&&u.searchParams.set("_routes",d.join(",")),[u.pathname+u.search]},[s,a.unstable_trailingSlashAwareDataRequests,e,r,t]);return l.createElement(l.Fragment,null,o.map(u=>l.createElement("link",{key:u,rel:"prefetch",as:"fetch",href:u,...n})))}function xr({page:e,matches:t,...n}){let r=ne(),{future:a,manifest:s,routeModules:o}=ct(),{basename:u}=it(),{loaderData:c,matches:d}=gr(),m=l.useMemo(()=>Rt(e,t,d,s,r,"data"),[e,t,d,s,r]),h=l.useMemo(()=>Rt(e,t,d,s,r,"assets"),[e,t,d,s,r]),p=l.useMemo(()=>{if(e===r.pathname+r.search+r.hash)return[];let b=new Set,f=!1;if(t.forEach(w=>{var A;let x=s.routes[w.route.id];!x||!x.hasLoader||(!m.some(R=>R.route.id===w.route.id)&&w.route.id in c&&((A=o[w.route.id])!=null&&A.shouldRevalidate)||x.hasClientLoader?f=!0:b.add(w.route.id))}),b.size===0)return[];let y=Jt(e,u,a.unstable_trailingSlashAwareDataRequests,"data");return f&&b.size>0&&y.searchParams.set("_routes",t.filter(w=>b.has(w.route.id)).map(w=>w.route.id).join(",")),[y.pathname+y.search]},[u,a.unstable_trailingSlashAwareDataRequests,c,r,s,m,t,e,o]),g=l.useMemo(()=>hr(h,s),[h,s]),v=br(h);return l.createElement(l.Fragment,null,p.map(b=>l.createElement("link",{key:b,rel:"prefetch",as:"fetch",href:b,...n})),g.map(b=>l.createElement("link",{key:b,rel:"modulepreload",href:b,...n})),v.map(({key:b,link:f})=>l.createElement("link",{key:b,nonce:n.nonce,...f,crossOrigin:f.crossOrigin??n.crossOrigin})))}function Er(...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 s=a.current,[o,u]=l.useState({action:s.action,location:s.location}),c=l.useCallback(d=>{n===!1?u(d):l.startTransition(()=>u(d))},[n]);return l.useLayoutEffect(()=>s.listen(c),[s,c]),l.createElement(Zn,{basename:e,children:t,location:o.location,navigationType:o.action,navigator:s,useTransitions:n})}var qt=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,Gt=l.forwardRef(function({onClick:t,discover:n="render",prefetch:r="none",relative:a,reloadDocument:s,replace:o,mask:u,state:c,target:d,to:m,preventScrollReset:h,viewTransition:p,defaultShouldRevalidate:g,...v},b){let{basename:f,navigator:y,useTransitions:w}=l.useContext(W),x=typeof m=="string"&&qt.test(m),A=Bt(m,f);m=A.to;let R=Fn(m,{relative:a}),D=ne(),K=null;if(u){let F=nt(u,[],D.mask?D.mask.pathname:"/",!0);f!=="/"&&(F.pathname=F.pathname==="/"?f:V([f,F.pathname])),K=y.createHref(F)}let[X,oe,he]=yr(r,v),He=jr(m,{replace:o,mask:u,state:c,target:d,preventScrollReset:h,relative:a,viewTransition:p,defaultShouldRevalidate:g,useTransitions:w});function le(F){t&&t(F),F.defaultPrevented||He(F)}let Ne=!(A.isExternal||s),re=l.createElement("a",{...v,...he,href:(Ne?K:void 0)||A.absoluteURL||R,onClick:Ne?le:t,ref:Er(b,oe),target:d,"data-discover":!x&&n==="render"?"true":void 0});return X&&!x?l.createElement(l.Fragment,null,re,l.createElement(vr,{page:R})):re});Gt.displayName="Link";var kr=l.forwardRef(function({"aria-current":t="page",caseSensitive:n=!1,className:r="",end:a=!1,style:s,to:o,viewTransition:u,children:c,...d},m){let h=ke(o,{relative:d.relative}),p=ne(),g=l.useContext(Fe),{navigator:v,basename:b}=l.useContext(W),f=g!=null&&Ir(h)&&u===!0,y=v.encodeLocation?v.encodeLocation(h).pathname:h.pathname,w=p.pathname,x=g&&g.navigation&&g.navigation.location?g.navigation.location.pathname:null;n||(w=w.toLowerCase(),x=x?x.toLowerCase():null,y=y.toLowerCase()),x&&b&&(x=ee(x,b)||x);const A=y!=="/"&&y.endsWith("/")?y.length-1:y.length;let R=w===y||!a&&w.startsWith(y)&&w.charAt(A)==="/",D=x!=null&&(x===y||!a&&x.startsWith(y)&&x.charAt(y.length)==="/"),K={isActive:R,isPending:D,isTransitioning:f},X=R?t:void 0,oe;typeof r=="function"?oe=r(K):oe=[r,R?"active":null,D?"pending":null,f?"transitioning":null].filter(Boolean).join(" ");let he=typeof s=="function"?s(K):s;return l.createElement(Gt,{...d,"aria-current":X,className:oe,ref:m,style:he,to:o,viewTransition:u},typeof c=="function"?c(K):c)});kr.displayName="NavLink";var Nr=l.forwardRef(({discover:e="render",fetcherKey:t,navigate:n,reloadDocument:r,replace:a,state:s,method:o=Ie,action:u,onSubmit:c,relative:d,preventScrollReset:m,viewTransition:h,defaultShouldRevalidate:p,...g},v)=>{let{useTransitions:b}=l.useContext(W),f=Ar(),y=Pr(u,{relative:d}),w=o.toLowerCase()==="get"?"get":"post",x=typeof u=="string"&&qt.test(u),A=R=>{if(c&&c(R),R.defaultPrevented)return;R.preventDefault();let D=R.nativeEvent.submitter,K=(D==null?void 0:D.getAttribute("formmethod"))||o,X=()=>f(D||R.currentTarget,{fetcherKey:t,method:K,navigate:n,replace:a,state:s,relative:d,preventScrollReset:m,viewTransition:h,defaultShouldRevalidate:p});b&&n!==!1?l.startTransition(()=>X()):X()};return l.createElement("form",{ref:v,method:w,action:y,onSubmit:r?c:A,...g,"data-discover":!x&&e==="render"?"true":void 0})});Nr.displayName="Form";function Cr(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function Yt(e){let t=l.useContext(de);return T(t,Cr(e)),t}function jr(e,{target:t,replace:n,mask:r,state:a,preventScrollReset:s,relative:o,viewTransition:u,defaultShouldRevalidate:c,useTransitions:d}={}){let m=Se(),h=ne(),p=ke(e,{relative:o});return l.useCallback(g=>{if(sr(g,t)){g.preventDefault();let v=n!==void 0?n:we(h)===we(p),b=()=>m(e,{replace:v,mask:r,state:a,preventScrollReset:s,relative:o,viewTransition:u,defaultShouldRevalidate:c});d?l.startTransition(()=>b()):b()}},[h,m,p,n,r,a,t,e,s,o,u,c,d])}var Mr=0,Tr=()=>`__${String(++Mr)}__`;function Ar(){let{router:e}=Yt("useSubmit"),{basename:t}=l.useContext(W),n=Gn(),r=e.fetch,a=e.navigate;return l.useCallback(async(s,o={})=>{let{action:u,method:c,encType:d,formData:m,body:h}=lr(s,t);if(o.navigate===!1){let p=o.fetcherKey||Tr();await r(p,n,o.action||u,{defaultShouldRevalidate:o.defaultShouldRevalidate,preventScrollReset:o.preventScrollReset,formData:m,body:h,formMethod:o.method||c,formEncType:o.encType||d,flushSync:o.flushSync})}else await a(o.action||u,{defaultShouldRevalidate:o.defaultShouldRevalidate,preventScrollReset:o.preventScrollReset,formData:m,body:h,formMethod:o.method||c,formEncType:o.encType||d,replace:o.replace,state:o.state,fromRouteId:n,flushSync:o.flushSync,viewTransition:o.viewTransition})},[r,a,t,n])}function Pr(e,{relative:t}={}){let{basename:n}=l.useContext(W),r=l.useContext(te);T(r,"useFormAction must be used inside a RouteContext");let[a]=r.matches.slice(-1),s={...ke(e||".",{relative:t})},o=ne();if(e==null){s.search=o.search;let u=new URLSearchParams(s.search),c=u.getAll("index");if(c.some(m=>m==="")){u.delete("index"),c.filter(h=>h).forEach(h=>u.append("index",h));let m=u.toString();s.search=m?`?${m}`:""}}return(!e||e===".")&&a.route.index&&(s.search=s.search?s.search.replace(/^\?/,"?index&"):"?index"),n!=="/"&&(s.pathname=s.pathname==="/"?n:V([n,s.pathname])),we(s)}function Ir(e,{relative:t}={}){let n=l.useContext(Dt);T(n!=null,"`useViewTransitionState` must be used within `react-router-dom`'s `RouterProvider`. Did you accidentally import `RouterProvider` from `react-router`?");let{basename:r}=Yt("useViewTransitionState"),a=ke(e,{relative:t});if(!n.isTransitioning)return!1;let s=ee(n.currentLocation.pathname,r)||n.currentLocation.pathname,o=ee(n.nextLocation.pathname,r)||n.nextLocation.pathname;return Le(a.pathname,o)!=null||Le(a.pathname,s)!=null}const _=6,ae=2.6,J=240,Q={LE:[10,13],RE:[29,13],MO:[20,27]};function G(e,t,n){const r=[],a=Math.ceil(n);for(let s=-a;s<=a;s++)for(let o=-a;o<=a;o++)s*s+o*o<=n*n&&r.push([e+s,t+o]);return r}function $(e,t,n,r,a,s=5){const o=[],u=new Set;for(let c=r;c<=a;c+=s){const d=c*Math.PI/180,m=Math.round(e+n*Math.cos(d)),h=Math.round(t+n*Math.sin(d)),p=`${m},${h}`;u.has(p)||(u.add(p),o.push([m,h]))}return o}function Y(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 Qe(e,t,n,r){const a=[],s=new Set,o=Math.round(n);for(let u=-o;u<=o;u++){const c=u/o*Math.PI,d=Math.round(t+r*Math.sin(c)),m=`${e+u},${d}`;s.has(m)||(s.add(m),a.push([e+u,d]))}return a}function _r(e,t,n,r){const a=[],s=Math.round(n);for(let o=-s;o<=s;o++){const u=o+s;a.push([e+o,Math.round(t+(u%4<2?r:-r))])}return a}function St(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 kt(e,t,n,r){const a=[],s=new Set,o=Math.round(r*2*Math.PI*8);for(let u=0;u<=o;u++){const c=u/o*r*2*Math.PI,d=u/o*n,m=Math.round(e+d*Math.cos(c)),h=Math.round(t+d*Math.sin(c)),p=`${m},${h}`;s.has(p)||(s.add(p),a.push([m,h]))}return a}function Ge(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 Nt(e,t){return[...$(e,t-1,1.5,200,360,30),[e,t+1],[e,t+3]]}function Z(e,t){return{iris:G(e,t,3),pupil:G(e,t,1.5),hl:[[e-1,t-1]],lash:Y(e,t-3,3)}}function z(e,t){return{iris:G(e,t,4),pupil:G(e,t,2),hl:[[e-1,t-1],[e-2,t-2]],lash:Y(e,t-4,4)}}function ce(e,t){return{iris:G(e,t,3).filter(([,r])=>r>=t-1&&r<=t+1),pupil:[[e,t]],lash:Y(e,t-1,2)}}function se(e,t){return{iris:G(e,t,3).filter(([,r])=>r>=t),pupil:[[e-1,t],[e,t],[e+1,t]],lash:Y(e,t,3)}}function Te(e,t){return{iris:G(e,t+1,3),pupil:G(e,t+2,1.5),hl:[[e-1,t]],lash:Y(e,t-2,2)}}function Ae(e,t,n=2){return{iris:G(e,t,3),pupil:G(e+n,t,1.5),hl:[[e+n-1,t-1]],lash:Y(e,t-3,3)}}function Lr(e,t){return{wink:$(e,t+1,3,200,340,15)}}function ve(e,t){return $(e,t,5,25,155)}function Ze(e,t){return $(e,t,7,15,165)}function Ct(e,t){return Y(e,t,5)}function $r(e,t){const n=$(e-2,t,4,30,120,10),r=$(e+3,t+2,2.5,270,360,15),a=new Set(n.map(([s,o])=>`${s},${o}`));return[...n,...r.filter(([s,o])=>!a.has(`${s},${o}`))]}function Br(e,t){const n=$(e-2,t,2,200,340,20),r=$(e+2,t,2,200,340,20),a=Y(e,t+2,3),s=new Set(n.map(([o,u])=>`${o},${u}`));return[...n,...r.filter(([o,u])=>!s.has(`${o},${u}`)),...a]}function Fr(e,t,n){const r=Math.abs(Math.sin(n*1.4));if(r<.25)return $(e,t,4,20,160,8);const a=r<.65?1:2,s=$(e,t-a,3.5,190,350,8),o=$(e,t+a,3,10,170,8),u=new Set(s.map(([c,d])=>`${c},${d}`));return[...s,...o.filter(([c,d])=>!u.has(`${c},${d}`))]}const[S,k]=Q.LE,[N,C]=Q.RE,[j,M]=Q.MO,L="#22CCFF",Or=[{id:"idle",label:"😐 待机",color:"#00FFEE",category:"interaction",canBlink:!0,leftEye:Z(S,k),rightEye:Z(N,C),mouth:ve(j,M)},{id:"listening",label:"👂 聆听",color:"#44AAFF",category:"interaction",canBlink:!0,leftEye:z(S,k),rightEye:z(N,C),mouth:$(j,M,3,0,180)},{id:"thinking",label:"🤔 思考",color:"#FFCC00",category:"interaction",canBlink:!0,leftEye:ce(S,k),rightEye:Z(N,C),mouth:Qe(j,M,5,1),extras:[{dots:Nt(S-1,k-6),color:"#FFCC00",alpha:.75}]},{id:"speaking",label:"💬 说话",color:"#FFFFFF",pupilColor:"#002233",category:"interaction",canBlink:!0,leftEye:Z(S,k),rightEye:Z(N,C),speakingMouth:!0},{id:"happy",label:"😊 开心",color:"#FF44AA",category:"interaction",canBlink:!0,leftEye:{heart:St(S,k)},rightEye:{heart:St(N,C)},mouth:Ze(j,M)},{id:"error",label:"😵 错误",color:"#FF4400",category:"interaction",canBlink:!0,leftEye:{spiral:kt(S,k,4,2)},rightEye:{spiral:kt(N,C,4,2)},mouth:_r(j,M,5,1.5)},{id:"confused",label:"😕 困惑",color:"#BB44FF",category:"interaction",canBlink:!0,leftEye:z(S,k),rightEye:ce(N,C),mouth:Qe(j,M,5,1.5),extras:[{dots:Nt(N+1,C-6),color:"#BB44FF",alpha:.75}]},{id:"dreaming",label:"💤 做梦",color:"#5566FF",category:"interaction",canBlink:!0,leftEye:se(S,k),rightEye:se(N,C),mouth:ve(j,M),extras:[{dots:Ge(24,10),color:"#5566FF",alpha:.85,zzzIndex:0},{dots:Ge(28,7),color:"#7788FF",alpha:.75,zzzIndex:1},{dots:Ge(32,4),color:"#99AAFF",alpha:.65,zzzIndex:2}]}],Xt=[{id:"natural_smile",label:"01 自然微笑",color:L,category:"auto",canBlink:!0,leftEye:Z(S,k),rightEye:Z(N,C),mouth:ve(j,M)},{id:"calm_relax",label:"02 平静放松",color:L,category:"auto",canBlink:!0,leftEye:se(S,k),rightEye:se(N,C),mouth:Ct(j,M)},{id:"curious_observe",label:"03 好奇观察",color:L,category:"auto",canBlink:!0,leftEye:z(S,k),rightEye:z(N,C),mouth:$(j,M,4,30,150,8)},{id:"light_joy",label:"04 轻松愉悦",color:L,category:"auto",canBlink:!0,leftEye:ce(S,k),rightEye:ce(N,C),mouth:Ze(j,M)},{id:"side_think",label:"05 侧目思考",color:L,category:"auto",canBlink:!0,leftEye:Ae(S,k,2),rightEye:Ae(N,C,2),mouth:Qe(j,M,4,1)},{id:"warm_friendly",label:"06 温和友善",color:L,category:"auto",canBlink:!0,leftEye:Te(S,k),rightEye:Te(N,C),mouth:ve(j,M)},{id:"quiet_listen",label:"07 静静聆听",color:L,category:"auto",canBlink:!0,leftEye:Z(S,k),rightEye:Z(N,C),mouth:Y(j,M,4)},{id:"focus_gaze",label:"08 专注注视",color:L,category:"auto",canBlink:!0,leftEye:z(S,k),rightEye:z(N,C),mouth:Ct(j,M)},{id:"quiet_wait",label:"09 安静等待",color:L,category:"auto",canBlink:!0,leftEye:se(S,k),rightEye:se(N,C),mouth:$(j,M,4,30,150,8)},{id:"slow_blink",label:"10 慢眨眼",color:L,category:"auto",canBlink:!0,leftEye:ce(S,k),rightEye:ce(N,C),mouth:ve(j,M)},{id:"look_around",label:"11 左右扫视",color:L,category:"auto",canBlink:!0,leftEye:Ae(S,k,-2),rightEye:Ae(N,C,-2),mouth:Y(j,M,4)},{id:"playful",label:"12 小小调皮",color:L,category:"auto",canBlink:!1,leftEye:Lr(S,k),rightEye:z(N,C),mouth:$r(j,M)},{id:"joyful_wait",label:"13 愉悦期待",color:L,category:"auto",canBlink:!0,leftEye:z(S,k),rightEye:z(N,C),mouth:Ze(j,M)},{id:"slight_surprise",label:"14 轻微惊喜",color:L,category:"auto",canBlink:!0,leftEye:z(S,k),rightEye:z(N,C),mouth:$(j,M,3,0,180,10)},{id:"gentle_gaze",label:"15 温柔注视",color:L,category:"auto",canBlink:!0,leftEye:Te(S,k),rightEye:Te(N,C),mouth:$(j,M,4,30,150,8)},{id:"spaceout",label:"16 发呆放空",color:L,category:"auto",canBlink:!0,leftEye:se(S,k),rightEye:se(N,C),mouth:Br(j,M)}],ut=[...Or,...Xt],ge=Xt.map(e=>e.id),et=Object.fromEntries(ut.map(e=>[e.id,e]));function O(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[s,o]of t){const u=s*_+_/2,c=o*_+_/2;e.moveTo(u+ae,c),e.arc(u,c,ae,0,Math.PI*2)}e.fill(),e.shadowBlur=0,e.fillStyle="rgba(255,255,255,0.55)",e.beginPath();for(const[s,o]of t){const u=s*_+_/2,c=o*_+_/2;e.moveTo(u+ae*.38,c),e.arc(u,c,ae*.38,0,Math.PI*2)}e.fill()}else{const s=[],o=[];for(const[c,d]of t){const m=(c*7.3+d*13.1)*.31;(Math.sin(a*1.1+m)>0?s:o).push([c,d])}const u=(c,d,m)=>{if(c.length){e.globalAlpha=Math.max(0,Math.min(1,d)),e.shadowBlur=m,e.shadowColor=n,e.fillStyle=n,e.beginPath();for(const[h,p]of c){const g=h*_+_/2,v=p*_+_/2;e.moveTo(g+ae,v),e.arc(g,v,ae,0,Math.PI*2)}e.fill()}};u(o,r*.68,7),u(s,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[c,d]of t){const m=c*_+_/2,h=d*_+_/2;e.moveTo(m+ae*.38,h),e.arc(m,h,ae*.38,0,Math.PI*2)}e.fill()}e.restore()}}function ye(e,t,n){return n>=1?e:e.map(([r,a])=>[r,t+(a-t)*n])}function Dr(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 jt(e,t,n,r,a,s,o,u,c){if(!t)return;const d=s||"#001020";t.iris?(O(e,ye(t.iris,r,u),a,o,c),O(e,ye(t.pupil,r,u),d,o,null),t.hl&&O(e,ye(t.hl,r,u),"#ffffff",o*.9,null),t.lash&&O(e,ye(t.lash,r,u),a,o,null)):t.closed!==void 0?(O(e,t.closed,a,o,c),t.lash&&O(e,t.lash,a,o,null)):t.wink?O(e,t.wink,a,o,c):t.heart?O(e,t.heart,a,o,c):t.spiral?O(e,t.spiral,a,o,c):t.star?O(e,t.star,a,o,c):t.pts&&O(e,ye(t.pts,r,u),a,o,c)}function Ur({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 s=n.current.getContext("2d"),o=r.current;function u(d,m,h,p){if(!d)return;jt(s,d.leftEye,Q.LE[0],Q.LE[1],d.color,d.pupilColor,m,h,p),jt(s,d.rightEye,Q.RE[0],Q.RE[1],d.color,d.pupilColor,m,h,p);const g=d.speakingMouth?Fr(Q.MO[0],Q.MO[1],o.t):d.mouth;if(g&&O(s,g,d.color,m,p),d.extras)for(const v of d.extras){let b=m*v.alpha;if(v.zzzIndex!==void 0){const f=o.t-v.zzzIndex*1.2;b*=.35+.65*(Math.sin(f)*.5+.5)}O(s,v.dots,v.color,b,null)}}function c(){const d=performance.now();o.t+=.04,s.clearRect(0,0,J,J),s.fillStyle="#000",s.fillRect(0,0,J,J);let m=1,h=0;if(o.transitionStart!==null){const b=d-o.transitionStart;if(b>=380)o.transitionStart=null,o.previousId=null;else{const f=b/380,y=f<.5?2*f*f:1-(-2*f+2)**2/2;m=y,h=1-y}}const p=et[o.currentId];!o.blinkStart&&o.transitionStart===null&&(p!=null&&p.canBlink)&&d>=o.nextBlink&&(o.blinkStart=d,o.nextBlink=d+2500+Math.random()*2500),o.blinkStart!==null&&d-o.blinkStart>=340&&(o.blinkStart=null);const g=Dr(o.blinkStart,d);o.previousId&&u(et[o.previousId],h,1,null);const v=o.transitionStart===null?o.t:null;u(p,m,g,v),s.save(),s.globalAlpha=.04,s.fillStyle="#000";for(let b=0;b<J;b+=2)s.fillRect(0,b+1,J,1);s.restore(),o.raf=requestAnimationFrame(c)}return o.raf=requestAnimationFrame(c),()=>cancelAnimationFrame(o.raf)},[]),i.jsx("canvas",{ref:n,width:J,height:J,style:{width:J*t,height:J*t,imageRendering:"pixelated",borderRadius:14,boxShadow:"0 0 40px rgba(0,255,200,0.2)",display:"block"}})}function Hr({base64:e,mimeType:t="audio/mp3",label:n="🔊"}){const r=e?`data:${t};base64,${e}`:null;return r?i.jsx("audio",{className:"audio-btn",controls:!0,src:r,title:n,preload:"none"}):null}const zr={terminal:"💻",web_search:"🔍",web_extract:"📄",browser:"🌐",read_file:"📂",write_file:"✏️",execute_code:"⚡",delegate_task:"🤖"};function Wr({toolCalls:e}){return!e||e.length===0?null:i.jsxs("details",{className:"tool-calls",children:[i.jsxs("summary",{className:"tool-calls-summary",children:["🔧 Hermes 使用了 ",e.length," 个工具"]}),i.jsx("ul",{className:"tool-calls-list",children:e.map((t,n)=>i.jsxs("li",{className:"tool-calls-item",children:[i.jsx("span",{className:"tool-calls-icon",children:zr[t.tool]||"🔧"}),i.jsx("span",{className:"tool-calls-name",children:t.tool}),t.preview&&i.jsx("code",{className:"tool-calls-preview",children:t.preview})]},n))})]})}function Vr({role:e,text:t,audioBase64:n,audioMime:r,toolCalls:a}){const s=e==="user";return i.jsxs("div",{className:`bubble ${s?"bubble-user":"bubble-bot"}`,children:[i.jsx("div",{className:"bubble-label",children:s?"你":"JBOT"}),!s&&i.jsx(Wr,{toolCalls:a}),i.jsx("div",{className:"bubble-text",children:t}),n&&i.jsx(Hr,{base64:n,mimeType:r||"audio/mp3"})]})}function Kr({messages:e,voiceStatus:t}){const n=l.useRef(null),r=Se();return l.useEffect(()=>{var a;(a=n.current)==null||a.scrollIntoView({behavior:"smooth"})},[e]),i.jsxs("section",{className:"chat-panel",children:[i.jsxs("div",{className:"chat-header",children:[i.jsx("span",{className:"chat-title",children:"对话"}),i.jsx("button",{className:"history-link",onClick:()=>r("/history"),children:"历史记录 →"})]}),t&&i.jsx("div",{className:`voice-status voice-status-${t.type}`,children:t.text}),i.jsxs("div",{className:"chat-messages",children:[e.length===0?i.jsx("p",{className:"chat-empty",children:"按住 Space 开始说话…"}):e.map(a=>i.jsx(Vr,{role:a.role,text:a.text,audioBase64:a.audioBase64,audioMime:a.audioMime,toolCalls:a.toolCalls},a.id)),i.jsx("div",{ref:n})]})]})}const De="jbot_memory",Jr=100;function be(){try{return JSON.parse(localStorage.getItem(De)||"[]")}catch{return[]}}function qr(e){const t=be(),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(De,JSON.stringify([r,...t].slice(0,Jr))),r}function Gr(e){localStorage.setItem(De,JSON.stringify(be().filter(t=>t.id!==e)))}function Yr(){localStorage.removeItem(De)}function Xr({memories:e,onMemoriesChange:t}){const[n,r]=l.useState(!1),a=o=>{Gr(o),t()},s=()=>{window.confirm("清空所有记忆?")&&(Yr(),t())};return i.jsxs("div",{className:"memory-panel",children:[i.jsxs("button",{className:"memory-toggle",onClick:()=>r(o=>!o),children:[i.jsx("span",{children:"🧠 长期记忆"}),i.jsx("span",{className:"memory-badge",children:e.length}),i.jsx("span",{className:"memory-arrow",children:n?"▲":"▼"})]}),n&&i.jsx("div",{className:"memory-body",children:e.length===0?i.jsx("p",{className:"memory-empty",children:"对话后会自动记住关于你的信息"}):i.jsxs(i.Fragment,{children:[i.jsx("ul",{className:"memory-list",children:e.map(o=>i.jsxs("li",{className:"memory-item",children:[i.jsx("span",{className:"memory-text",children:o.text}),i.jsx("button",{className:"memory-del",onClick:()=>a(o.id),title:"删除",children:"×"})]},o.id))}),i.jsx("button",{className:"memory-clear",onClick:s,children:"清空全部"})]})})]})}const ie="/api/jbot";async function Qr(){return(await fetch(`${ie}/config/`)).json()}async function Zr(e,t=[],n={}){const r=await fetch(`${ie}/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 ea(e,t="audio/webm"){const n=await fetch(`${ie}/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 ta(e,t){const n=await fetch(`${ie}/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 na(e,t){try{const n=await fetch(`${ie}/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[]}}async function ra(){try{const e=await fetch(`${ie}/api-config/`);return e.ok?e.json():{}}catch{return{}}}async function aa(e){const t=await fetch(`${ie}/api-config/`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok){const n=await t.json().catch(()=>({}));throw new Error(n.error||`HTTP ${t.status}`)}return t.json()}function sa(){const[e,t]=l.useState(!1),n=l.useRef(null),r=l.useRef(null),a=l.useRef(null),s=l.useRef([]),o=l.useRef(""),u=l.useCallback(async()=>{var p;if(e)return;s.current=[],o.current="",(p=n.current)!=null&&p.active||(n.current=await navigator.mediaDevices.getUserMedia({audio:!0}));const d=MediaRecorder.isTypeSupported("audio/webm;codecs=opus")?"audio/webm;codecs=opus":"audio/webm",m=new MediaRecorder(n.current,{mimeType:d});m.ondataavailable=g=>{g.data.size>0&&s.current.push(g.data)},m.start(100),r.current=m;const h=window.SpeechRecognition||window.webkitSpeechRecognition;if(h){const g=new h;g.lang="zh-CN",g.interimResults=!0,g.continuous=!0,g.onresult=v=>{let b="";for(const f of v.results)f.isFinal&&(b+=f[0].transcript);b&&(o.current=b)},g.onerror=v=>{console.warn("SpeechRecognition error:",v.error)},g.start(),a.current=g}t(!0)},[e]),c=l.useCallback(()=>new Promise(d=>{var p,g;t(!1);const m=o.current;try{(p=a.current)==null||p.stop()}catch{}a.current=null,(g=n.current)==null||g.getTracks().forEach(v=>v.stop()),n.current=null;const h=r.current;if(!h)return d({transcript:m,audioBase64:null,mimeType:null});h.onstop=async()=>{const v=h.mimeType;if(s.current.length===0)return d({transcript:m,audioBase64:null,mimeType:v});const b=new Blob(s.current,{type:v}),f=new FileReader;f.onloadend=()=>{d({transcript:m,audioBase64:f.result.split(",")[1],mimeType:v})},f.readAsDataURL(b)},h.stop(),r.current=null}),[]);return{isRecording:e,start:u,stop:c}}const Ue="jbot_history",oa=200;function Be(){try{return JSON.parse(localStorage.getItem(Ue)||"[]")}catch{return[]}}function ia(e){const t=Be(),n=[{id:crypto.randomUUID(),timestamp:Date.now(),...e},...t];return localStorage.setItem(Ue,JSON.stringify(n.slice(0,oa))),n[0]}function la(){localStorage.removeItem(Ue)}function ca(e){localStorage.setItem(Ue,JSON.stringify(Be().filter(t=>t.id!==e)))}const ua=[{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"}],Qt="zh_female_vv_uranus_bigtts",dt="jbot_settings",tt={robotName:"JBOT",robotPersonality:"你是一个友好、简洁、偶尔幽默的AI机器人助手。回复控制在80字以内。",language:"auto",voiceId:Qt,customVoiceId:"",responseMaxWords:80,switchIntervalMs:1e4};function xe(){try{const e=JSON.parse(localStorage.getItem(dt)||"{}");return{...tt,...e}}catch{return{...tt}}}function da(e){const n={...xe(),...e};return localStorage.setItem(dt,JSON.stringify(n)),n}function ha(){return localStorage.removeItem(dt),{...tt}}function fa(e=null){var n;const t=e||xe();return((n=t.customVoiceId)==null?void 0:n.trim())||t.voiceId||Qt}const ma=ut.filter(e=>e.category==="interaction"),pa=ut.filter(e=>e.category==="auto"),ga={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 ya(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 va(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 ba({phase:e,onStart:t,onEnd:n}){const r=e==="thinking"||e==="speaking";let a="🎙 按住说话",s="";e==="acquiring"?(a="⏳ 准备中…",s=" vbtn--acquiring"):e==="listening"?(a="🔴 松开发送",s=" vbtn--recording"):e==="thinking"?(a="⚙ 思考中…",s=" vbtn--busy"):e==="speaking"&&(a="🔊 播放中…",s=" vbtn--busy");const o=c=>{c.preventDefault(),r||t()},u=c=>{c.preventDefault(),n()};return i.jsx("div",{className:"vbtn-wrap",children:i.jsx("button",{className:`vbtn${s}`,disabled:r,onMouseDown:o,onMouseUp:u,onMouseLeave:u,onTouchStart:o,onTouchEnd:u,onTouchCancel:u,children:a})})}function wa(){var mt;const e=Se(),[t,n]=l.useState(ge[0]),[r,a]=l.useState(!0),[s,o]=l.useState(1),[u]=l.useState(()=>xe().switchIntervalMs??1e4),c=l.useRef(null),d=l.useRef(!0),m=l.useRef(ge[0]),h=l.useRef(null),p=l.useRef(u);l.useEffect(()=>{d.current=r},[r]),l.useEffect(()=>{m.current=t},[t]);const g=l.useCallback(()=>{clearTimeout(c.current),c.current=null},[]);h.current=()=>{if(g(),!d.current)return;const E=1+(Math.random()-.5)*.3;c.current=setTimeout(()=>{var I;const U=ge.filter(H=>H!==m.current),P=U[Math.floor(Math.random()*U.length)];n(P),(I=h.current)==null||I.call(h)},p.current*E)};const v=l.useCallback(()=>{var E;return(E=h.current)==null?void 0:E.call(h)},[]);l.useEffect(()=>(r?v():g(),g),[r,v,g]);const b=l.useCallback(E=>{g(),n(E),d.current&&v()},[g,v]),{start:f,stop:y}=sa(),[w,x]=l.useState("idle"),[A,R]=l.useState(null),[D,K]=l.useState([]),[X,oe]=l.useState([]),[he,He]=l.useState(()=>be()),[le,Ne]=l.useState(!1),re=l.useRef("idle"),F=l.useRef(!1),ht=l.useCallback(()=>He(be()),[]);l.useEffect(()=>{Qr().then(E=>{(E==null?void 0:E.backendMode)==="hermes"&&Ne(!0)}).catch(()=>{})},[]),l.useEffect(()=>{re.current=w},[w]);const ft=(E,U,P,I,H)=>{const fe={id:crypto.randomUUID(),role:E,text:U,audioBase64:P,audioMime:I,toolCalls:H};return K(Ve=>[...Ve.slice(-29),fe]),fe},ze=l.useCallback(async()=>{if(!(F.current||re.current!=="idle")){F.current=!0,g(),x("acquiring"),R({type:"acquiring",text:"⏳ 麦克风准备中…"});try{await f()}catch(E){console.warn("[PTT] Mic acquisition failed:",E.message),F.current=!1,x("idle"),R({type:"error",text:"⚠ 麦克风不可用"}),setTimeout(()=>R(null),2500),v();return}n("listening"),x("listening"),R({type:"listening",text:"🎙 请讲话 · 松开结束"})}},[g,f,v]),We=l.useCallback(async()=>{if(!F.current)return;if(F.current=!1,re.current==="acquiring"){x("idle"),R(null),v();return}if(re.current!=="listening")return;x("thinking"),n("thinking"),R({type:"thinking",text:"⚙ 识别中…"});const{transcript:E,audioBase64:U,mimeType:P}=await y();let I="";if(U)try{R({type:"thinking",text:"⚙ 识别中…"});const{text:B}=await ea(U,P||"audio/webm");I=(B==null?void 0:B.trim())||""}catch(B){console.warn("[ASR] Volcengine failed, using browser transcript:",B.message)}if(I||(I=E.trim()),!I){x("idle"),n("idle"),R(null);return}ft("user",I,U,P),R({type:"thinking",text:"⚙ 思考中…"});let H="",fe=[];try{const B=le?[]:be().map(en=>en.text),Ce=xe(),je=[...X,{role:"user",content:I}],gt=await Zr(je.slice(-10),B,Ce);H=gt.text,fe=gt.toolCalls||[],oe([...je,{role:"assistant",content:H}].slice(-20))}catch(B){H=`对话出错: ${B.message}`}n("speaking"),x("speaking"),R({type:"speaking",text:"🔊 播放中…"});const Ve=fa();let me=null,pt=!1;try{const{audioBase64:B}=await ta(H,Ve);me=B}catch(B){console.warn("[TTS] Volcengine unavailable, using browser TTS:",B.message),pt=!0}pt&&R({type:"speaking",text:"🔊 播放中… (浏览器语音)"}),ft("bot",H,me,"audio/mp3",fe),ia({userText:I,botText:H,userAudioBase64:U,userAudioMime:P,botAudioBase64:me,botAudioMime:"audio/mp3"}),le||na(I,H).then(B=>{let Ce=!1;B.forEach(je=>{qr(je)&&(Ce=!0)}),Ce&&ht()}).catch(()=>{}),me?await ya(me,"audio/mp3"):await va(H),x("idle"),R(null);const Zt=ge[Math.floor(Math.random()*ge.length)];n(Zt),v()},[y,X,v]);return l.useEffect(()=>{function E(P){if(!(P.target.tagName==="INPUT"||P.target.tagName==="TEXTAREA")){if(P.code==="Space"&&!P.repeat){P.preventDefault(),ze();return}if(re.current==="idle"){const I=ga[P.key.toLowerCase()];I&&b(I)}}}function U(P){P.code==="Space"&&(P.preventDefault(),We())}return window.addEventListener("keydown",E),window.addEventListener("keyup",U),()=>{window.removeEventListener("keydown",E),window.removeEventListener("keyup",U)}},[ze,We,b]),i.jsxs("div",{className:"app",children:[i.jsxs("header",{className:"hdr",children:[i.jsx("a",{href:"/",className:"hdr-home",title:"返回主页",children:"🏠"}),i.jsxs("h1",{children:["J",i.jsx("span",{className:"accent",children:"BOT"})]}),i.jsx("p",{className:"subtitle",children:"AI Robot Face · 240×240"}),i.jsxs("nav",{className:"hdr-nav",children:[i.jsx("button",{className:"hdr-link",onClick:()=>e("/history"),children:"历史"}),i.jsx("button",{className:"hdr-link",onClick:()=>e("/settings"),children:"设置"})]})]}),i.jsxs("div",{className:"page-body",children:[i.jsxs("aside",{className:"left-col",children:[i.jsxs("section",{className:"screen-wrap",children:[i.jsxs("div",{className:"scale-controls",children:[i.jsx("button",{className:`scale-btn${s===1?" active":""}`,onClick:()=>o(1),children:"1×"}),i.jsx("button",{className:`scale-btn${s===2?" active":""}`,onClick:()=>o(2),children:"2×"})]}),i.jsx("div",{className:"bezel",children:i.jsx(Ur,{expressionId:t,scale:s})}),i.jsx("div",{className:"expr-label",children:(mt=et[t])==null?void 0:mt.label})]}),i.jsxs("section",{className:"panel",children:[i.jsxs("div",{className:"panel-section",children:[i.jsxs("h3",{children:["交互状态 ",i.jsx("span",{className:"key-hint",children:"1 8"})]}),i.jsx("div",{className:"btn-grid",children:ma.map(E=>i.jsx("button",{className:`ebtn${t===E.id?" active":""}`,style:{"--c":E.color},onClick:()=>b(E.id),children:E.label},E.id))})]}),i.jsxs("div",{className:"panel-section",children:[i.jsxs("h3",{children:["微表情 ",i.jsx("span",{className:"key-hint",children:"QI · 自动"})]}),i.jsx("div",{className:"btn-grid btn-grid-4",children:pa.map(E=>i.jsx("button",{className:`ebtn${t===E.id?" active":""}`,style:{"--c":E.color},onClick:()=>b(E.id),children:E.label},E.id))})]}),i.jsxs("label",{className:"toggle",children:[i.jsx("input",{type:"checkbox",checked:r,onChange:E=>a(E.target.checked)}),i.jsx("span",{children:"自动轮换微表情"})]})]})]}),i.jsxs("div",{className:"right-col",children:[!le&&i.jsx(Xr,{memories:he,onMemoriesChange:ht}),le&&i.jsx("div",{className:"hermes-mode-badge",children:"🧠 Hermes Agent 模式 · 记忆由 Agent 管理"}),i.jsx(Kr,{messages:D,voiceStatus:A}),i.jsx(ba,{phase:w,onStart:ze,onEnd:We})]})]})]})}function Mt({base64:e,mimeType:t="audio/mp3"}){return e?i.jsx("audio",{className:"hist-audio",controls:!0,src:`data:${t};base64,${e}`,preload:"none"}):null}function xa({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 i.jsxs("article",{className:"hist-entry",children:[i.jsxs("div",{className:"hist-meta",children:[i.jsx("span",{className:"hist-time",children:r}),i.jsx("button",{className:"hist-del",onClick:()=>t(e.id),title:"删除",children:"✕"})]}),i.jsxs("div",{className:"hist-row hist-row-user",children:[i.jsx("div",{className:"hist-role",children:"你"}),i.jsxs("div",{className:"hist-body",children:[i.jsx("p",{className:"hist-text",children:e.userText||"(语音消息)"}),i.jsx(Mt,{base64:e.userAudioBase64,mimeType:e.userAudioMime||"audio/webm"})]})]}),i.jsxs("div",{className:"hist-row hist-row-bot",children:[i.jsx("div",{className:"hist-role",children:"JBOT"}),i.jsxs("div",{className:"hist-body",children:[i.jsx("p",{className:"hist-text",children:e.botText||""}),i.jsx(Mt,{base64:e.botAudioBase64,mimeType:"audio/mp3"})]})]})]})}function Ea(){const[e,t]=l.useState(()=>Be()),n=Se(),r=s=>{ca(s),t(Be())},a=()=>{window.confirm("确认清空所有历史记录?")&&(la(),t([]))};return i.jsxs("div",{className:"hist-page",children:[i.jsxs("div",{className:"hist-toolbar",children:[i.jsx("button",{className:"hist-back",onClick:()=>n("/"),children:"← 返回"}),i.jsx("h1",{className:"hist-heading",children:"历史对话"}),i.jsx("button",{className:"hist-clear",onClick:a,disabled:e.length===0,children:"清空"})]}),e.length===0?i.jsx("p",{className:"hist-empty",children:"暂无历史记录"}):i.jsx("div",{className:"hist-list",children:e.map(s=>i.jsx(xa,{entry:s,onDelete:r},s.id))})]})}const Tt={volcAppId:"",volcAccessToken:"",openrouterApiKey:"",llmModel:"deepseek/deepseek-chat",volcTtsVoice:"zh_female_vv_uranus_bigtts",volcAsrResource:"volc.bigasr.sauc.duration",hermesUrl:"http://192.168.1.10:8642",hermesApiKey:"",backendMode:"openrouter"};function Ra(){const e=Se(),[t,n]=l.useState(()=>xe()),[r,a]=l.useState(Tt),[s,o]=l.useState(!0),[u,c]=l.useState(!1),[d,m]=l.useState({});l.useEffect(()=>{ra().then(f=>{f&&!f.error&&a(y=>({...y,...f}))}).finally(()=>o(!1))},[]);const h=(f,y)=>{n(w=>({...w,[f]:y})),c(!1)},p=(f,y)=>{a(w=>({...w,[f]:y})),c(!1)},g=f=>m(y=>({...y,[f]:!y[f]})),v=async()=>{da(t);try{await aa(r),c(!0),setTimeout(()=>c(!1),2e3)}catch(f){alert("API 配置保存失败:"+f.message)}},b=()=>{if(window.confirm("重置所有设置为默认值?")){const f=ha();n(f),a(Tt),c(!1)}};return i.jsxs("div",{className:"settings-page",children:[i.jsxs("div",{className:"settings-toolbar",children:[i.jsx("button",{className:"settings-back",onClick:()=>e("/"),children:"← 返回"}),i.jsx("h1",{className:"settings-heading",children:"全局设置"}),i.jsx("button",{className:"settings-save",onClick:v,children:u?"✓ 已保存":"保存"})]}),i.jsxs("div",{className:"settings-body",children:[i.jsxs("section",{className:"settings-section",children:[i.jsx("h2",{className:"settings-section-title",children:"🔑 API 配置"}),i.jsx("p",{className:"settings-hint-block",children:"配置保存在服务器数据库中。Token 字段显示 *** 表示已配置,留空则保持不变。"}),s?i.jsx("p",{className:"settings-hint-block",children:"加载中…"}):i.jsxs(i.Fragment,{children:[i.jsxs("label",{className:"settings-label",children:["Volcengine App ID",i.jsx("input",{className:"settings-input",value:r.volcAppId,onChange:f=>p("volcAppId",f.target.value),placeholder:"填写火山引擎 App ID"})]}),i.jsxs("label",{className:"settings-label",children:["Volcengine Access Token",i.jsxs("div",{className:"settings-secret-row",children:[i.jsx("input",{className:"settings-input",type:d.volcAccessToken?"text":"password",value:r.volcAccessToken,onChange:f=>p("volcAccessToken",f.target.value),placeholder:"留空则保持不变"}),i.jsx("button",{className:"settings-show-btn",onClick:()=>g("volcAccessToken"),children:d.volcAccessToken?"隐藏":"显示"})]})]}),i.jsxs("label",{className:"settings-label",children:["OpenRouter API Key",i.jsxs("div",{className:"settings-secret-row",children:[i.jsx("input",{className:"settings-input",type:d.openrouterApiKey?"text":"password",value:r.openrouterApiKey,onChange:f=>p("openrouterApiKey",f.target.value),placeholder:"留空则保持不变"}),i.jsx("button",{className:"settings-show-btn",onClick:()=>g("openrouterApiKey"),children:d.openrouterApiKey?"隐藏":"显示"})]})]}),i.jsxs("label",{className:"settings-label",children:["ASR Resource ID",i.jsx("input",{className:"settings-input",value:r.volcAsrResource,onChange:f=>p("volcAsrResource",f.target.value),placeholder:"volc.bigasr.sauc.duration"})]})]})]}),i.jsxs("section",{className:"settings-section",children:[i.jsx("h2",{className:"settings-section-title",children:"🧠 AI 后端模式"}),i.jsx("p",{className:"settings-hint-block",children:"选择对话 AI 后端。Hermes Agent 支持工具调用、长期记忆和推理链。"}),i.jsx("div",{className:"settings-radio-group",children:[{value:"openrouter",label:"OpenRouter(直接调用模型)"},{value:"hermes",label:"Hermes Agent(本地 Agent,支持工具/记忆)"}].map(f=>i.jsxs("label",{className:"settings-radio-label",children:[i.jsx("input",{type:"radio",name:"backendMode",value:f.value,checked:r.backendMode===f.value,onChange:()=>p("backendMode",f.value)}),f.label]},f.value))}),r.backendMode==="openrouter"&&i.jsxs("label",{className:"settings-label settings-label-mt",children:["LLM 模型",i.jsx("input",{className:"settings-input",value:r.llmModel,onChange:f=>p("llmModel",f.target.value),placeholder:"deepseek/deepseek-chat"}),i.jsx("span",{className:"settings-hint",children:"OpenRouter 模型 ID,例如 openai/gpt-4o"})]}),r.backendMode==="hermes"&&i.jsxs(i.Fragment,{children:[i.jsxs("label",{className:"settings-label settings-label-mt",children:["Hermes Agent URL",i.jsx("input",{className:"settings-input",value:r.hermesUrl,onChange:f=>p("hermesUrl",f.target.value),placeholder:"http://192.168.1.10:8642"}),i.jsx("span",{className:"settings-hint",children:"本地 Hermes 实例地址,需开启 API_SERVER_ENABLED=true"})]}),i.jsxs("label",{className:"settings-label",children:["Hermes API Key",i.jsxs("div",{className:"settings-secret-row",children:[i.jsx("input",{className:"settings-input",type:d.hermesApiKey?"text":"password",value:r.hermesApiKey,onChange:f=>p("hermesApiKey",f.target.value),placeholder:"留空则不鉴权(局域网内可不填)"}),i.jsx("button",{className:"settings-show-btn",onClick:()=>g("hermesApiKey"),children:d.hermesApiKey?"隐藏":"显示"})]})]}),i.jsx("p",{className:"settings-hint-block",children:"💡 Hermes 模式下,中间工具调用不会转语音,只有最终回答会朗读。工具调用进度会显示在聊天界面。"})]})]}),i.jsxs("section",{className:"settings-section",children:[i.jsx("h2",{className:"settings-section-title",children:"🤖 机器人身份"}),i.jsxs("label",{className:"settings-label",children:["名字",i.jsx("input",{className:"settings-input",value:t.robotName,onChange:f=>h("robotName",f.target.value),placeholder:"JBOT"})]}),i.jsxs("label",{className:"settings-label",children:["人格描述 ",i.jsx("span",{className:"settings-hint",children:"会注入到每轮对话的系统提示"}),i.jsx("textarea",{className:"settings-textarea",rows:3,value:t.robotPersonality,onChange:f=>h("robotPersonality",f.target.value),placeholder:"你是一个友好、简洁、偶尔幽默的AI机器人助手。回复控制在80字以内。"})]}),i.jsxs("div",{className:"settings-label",children:["微表情切换间隔",i.jsxs("div",{className:"settings-slider-row",children:[i.jsx("input",{type:"range",min:"3",max:"30",step:"1",value:Math.round((t.switchIntervalMs??1e4)/1e3),onChange:f=>h("switchIntervalMs",Number(f.target.value)*1e3),className:"settings-slider"}),i.jsxs("span",{className:"settings-slider-val",children:[Math.round((t.switchIntervalMs??1e4)/1e3)," 秒"]})]})]})]}),i.jsxs("section",{className:"settings-section",children:[i.jsx("h2",{className:"settings-section-title",children:"👤 用户背景"}),i.jsxs("label",{className:"settings-label",children:["关于你 ",i.jsx("span",{className:"settings-hint",children:"机器人会了解你的背景,更好地回答"}),i.jsx("textarea",{className:"settings-textarea",rows:3,value:t.extraContext||"",onChange:f=>h("extraContext",f.target.value),placeholder:"例如:我叫小明,是一名软件工程师,在上海工作,对AI和嵌入式系统感兴趣。"})]})]}),i.jsxs("section",{className:"settings-section",children:[i.jsx("h2",{className:"settings-section-title",children:"🌐 语言"}),i.jsx("div",{className:"settings-radio-group",children:[{value:"auto",label:"自动(跟随用户语言)"},{value:"zh-CN",label:"中文"},{value:"en-US",label:"English"}].map(f=>i.jsxs("label",{className:"settings-radio-label",children:[i.jsx("input",{type:"radio",name:"language",value:f.value,checked:t.language===f.value,onChange:()=>h("language",f.value)}),f.label]},f.value))})]}),i.jsxs("section",{className:"settings-section",children:[i.jsx("h2",{className:"settings-section-title",children:"🔊 语音音色"}),i.jsx("div",{className:"settings-voice-grid",children:ua.map(f=>i.jsxs("button",{className:`settings-voice-btn ${!t.customVoiceId&&t.voiceId===f.id?"active":""}`,onClick:()=>{h("voiceId",f.id),h("customVoiceId","")},children:[i.jsx("span",{className:"voice-btn-label",children:f.label}),i.jsxs("span",{className:"voice-btn-meta",children:[f.lang," · ",f.gender," · ",f.style]})]},f.id))}),i.jsxs("label",{className:"settings-label settings-label-mt",children:["自定义音色 ID ",i.jsx("span",{className:"settings-hint",children:"填写后会覆盖上方选择"}),i.jsx("input",{className:"settings-input",value:t.customVoiceId||"",onChange:f=>h("customVoiceId",f.target.value),placeholder:"例如 zh_female_vv_uranus_bigtts"})]}),i.jsxs("p",{className:"settings-hint-block",children:["完整音色列表见"," ",i.jsx("a",{href:"https://www.volcengine.com/docs/6561/1257544",target:"_blank",rel:"noreferrer",children:"火山引擎 TTS 音色文档"})]})]}),i.jsxs("section",{className:"settings-section settings-section-danger",children:[i.jsx("h2",{className:"settings-section-title",children:"⚠️ 重置"}),i.jsx("button",{className:"settings-reset-btn",onClick:b,children:"重置为默认设置"})]})]})]})}tn.createRoot(document.getElementById("jbot-root")).render(i.jsx(l.StrictMode,{children:i.jsx(Sr,{basename:"/jbot",children:i.jsxs(er,{children:[i.jsx(Pe,{path:"/",element:i.jsx(wa,{})}),i.jsx(Pe,{path:"/history",element:i.jsx(Ea,{})}),i.jsx(Pe,{path:"/settings",element:i.jsx(Ra,{})})]})})}));