Files
junvandCopilot d99a362a37 jbot: keep avatar thinking during TTS and protect history storage
- Use a thinking/running face while speech audio is being generated
- Switch to speaking only when playback actually begins
- Add quota-safe history persistence that strips audio from older entries
  instead of crashing localStorage writes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-17 20:34:57 +10:00

19 lines
76 KiB
JavaScript
Raw Permalink 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 dn}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 Et="popstate";function Rt(e){return typeof e=="object"&&e!=null&&"pathname"in e&&"search"in e&&"hash"in e&&"state"in e&&"key"in e}function hn(e={}){function t(r,a){var u;let s=(u=a.state)==null?void 0:u.masked,{pathname:o,search:c,hash:d}=s||r.location;return et("",{pathname:o,search:c,hash:d},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:Re(a)}return mn(t,n,null,e)}function M(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 fn(){return Math.random().toString(36).substring(2,10)}function kt(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 et(e,t,n=null,r,a){return{pathname:typeof e=="string"?e:e.pathname,search:"",hash:"",...typeof t=="string"?he(t):t,state:n,key:t&&t.key||r||fn(),mask:a}}function Re({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 he(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 mn(e,t,n,r={}){let{window:a=document.defaultView,v5Compat:s=!1}=r,o=a.history,c="POP",d=null,u=f();u==null&&(u=0,o.replaceState({...o.state,idx:u},""));function f(){return(o.state||{idx:null}).idx}function h(){c="POP";let m=f(),g=m==null?null:m-u;u=m,d&&d({action:c,location:v.location,delta:g})}function p(m,g){c="PUSH";let x=Rt(m)?m:et(v.location,m,g);u=f()+1;let w=kt(x,u),$=v.createHref(x.mask||x);try{o.pushState(w,"",$)}catch(R){if(R instanceof DOMException&&R.name==="DataCloneError")throw R;a.location.assign($)}s&&d&&d({action:c,location:v.location,delta:1})}function b(m,g){c="REPLACE";let x=Rt(m)?m:et(v.location,m,g);u=f();let w=kt(x,u),$=v.createHref(x.mask||x);o.replaceState(w,"",$),s&&d&&d({action:c,location:v.location,delta:0})}function y(m){return pn(m)}let v={get action(){return c},get location(){return e(a,o)},listen(m){if(d)throw new Error("A history only accepts one active listener");return a.addEventListener(Et,h),d=m,()=>{a.removeEventListener(Et,h),d=null}},createHref(m){return t(a,m)},createURL:y,encodeLocation(m){let g=y(m);return{pathname:g.pathname,search:g.search,hash:g.hash}},push:p,replace:b,go(m){return o.go(m)}};return v}function pn(e,t=!1){let n="http://localhost";typeof window<"u"&&(n=window.location.origin!=="null"?window.location.origin:window.location.href),M(n,"No window.location.(origin|href) available to create URL");let r=typeof e=="string"?e:Re(e);return r=r.replace(/ $/,"%20"),!t&&r.startsWith("//")&&(r=n+r),new URL(r,n)}function Bt(e,t,n="/"){return gn(e,t,n,!1)}function gn(e,t,n,r,a){let s=typeof t=="string"?he(t):t,o=te(s.pathname||"/",n);if(o==null)return null;let c=yn(e),d=null,u=Tn(o);for(let f=0;d==null&&f<c.length;++f)d=Nn(c[f],u,r);return d}function yn(e){let t=Ft(e);return bn(t),t}function Ft(e,t=[],n=[],r="",a=!1){let s=(o,c,d=a,u)=>{let f={relativePath:u===void 0?o.path||"":u,caseSensitive:o.caseSensitive===!0,childrenIndex:c,route:o};if(f.relativePath.startsWith("/")){if(!f.relativePath.startsWith(r)&&d)return;M(f.relativePath.startsWith(r),`Absolute route path "${f.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),f.relativePath=f.relativePath.slice(r.length)}let h=W([r,f.relativePath]),p=n.concat(f);o.children&&o.children.length>0&&(M(o.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${h}".`),Ft(o.children,t,p,h,d)),!(o.path==null&&!o.index)&&t.push({path:h,score:Sn(h,o.index),routesMeta:p})};return e.forEach((o,c)=>{var d;if(o.path===""||!((d=o.path)!=null&&d.includes("?")))s(o,c);else for(let u of Ot(o.path))s(o,c,!0,u)}),t}function Ot(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=Ot(r.join("/")),c=[];return c.push(...o.map(d=>d===""?s:[s,d].join("/"))),a&&c.push(...o),c.map(d=>e.startsWith("/")&&d===""?"/":d)}function bn(e){e.sort((t,n)=>t.score!==n.score?n.score-t.score:jn(t.routesMeta.map(r=>r.childrenIndex),n.routesMeta.map(r=>r.childrenIndex)))}var vn=/^:[\w-]+$/,wn=3,xn=2,En=1,Rn=10,kn=-2,St=e=>e==="*";function Sn(e,t){let n=e.split("/"),r=n.length;return n.some(St)&&(r+=kn),t&&(r+=xn),n.filter(a=>!St(a)).reduce((a,s)=>a+(vn.test(s)?wn:s===""?En:Rn),r)}function jn(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 Nn(e,t,n=!1){let{routesMeta:r}=e,a={},s="/",o=[];for(let c=0;c<r.length;++c){let d=r[c],u=c===r.length-1,f=s==="/"?t:t.slice(s.length)||"/",h=De({path:d.relativePath,caseSensitive:d.caseSensitive,end:u},f),p=d.route;if(!h&&u&&n&&!r[r.length-1].route.index&&(h=De({path:d.relativePath,caseSensitive:d.caseSensitive,end:!1},f)),!h)return null;Object.assign(a,h.params),o.push({params:a,pathname:W([s,h.pathname]),pathnameBase:_n(W([s,h.pathnameBase])),route:p}),h.pathnameBase!=="/"&&(s=W([s,h.pathnameBase]))}return o}function De(e,t){typeof e=="string"&&(e={path:e,caseSensitive:!1,end:!0});let[n,r]=Cn(e.path,e.caseSensitive,e.end),a=t.match(n);if(!a)return null;let s=a[0],o=s.replace(/(.)\/+$/,"$1"),c=a.slice(1);return{params:r.reduce((u,{paramName:f,isOptional:h},p)=>{if(f==="*"){let y=c[p]||"";o=s.slice(0,s.length-y.length).replace(/(.)\/+$/,"$1")}const b=c[p];return h&&!b?u[f]=void 0:u[f]=(b||"").replace(/%2F/g,"/"),u},{}),pathname:s,pathnameBase:o,pattern:e}}function Cn(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,c,d,u,f)=>{if(r.push({paramName:c,isOptional:d!=null}),d){let h=f.charAt(u+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 Tn(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 te(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 Mn=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;function An(e,t="/"){let{pathname:n,search:r="",hash:a=""}=typeof e=="string"?he(e):e,s;return n?(n=Ut(n),n.startsWith("/")?s=jt(n.substring(1),"/"):s=jt(n,t)):s=t,{pathname:s,search:In(r),hash:Pn(a)}}function jt(e,t){let n=Ue(t).split("/");return e.split("/").forEach(a=>{a===".."?n.length>1&&n.pop():a!=="."&&n.push(a)}),n.length>1?n.join("/"):"/"}function Ye(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 $n(e){return e.filter((t,n)=>n===0||t.route.path&&t.route.path.length>0)}function Dt(e){let t=$n(e);return t.map((n,r)=>r===t.length-1?n.pathname:n.pathnameBase)}function ot(e,t,n,r=!1){let a;typeof e=="string"?a=he(e):(a={...e},M(!a.pathname||!a.pathname.includes("?"),Ye("?","pathname","search",a)),M(!a.pathname||!a.pathname.includes("#"),Ye("#","pathname","hash",a)),M(!a.search||!a.search.includes("#"),Ye("#","search","hash",a)));let s=e===""||a.pathname==="",o=s?"/":a.pathname,c;if(o==null)c=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("/")}c=h>=0?t[h]:"/"}let d=An(a,c),u=o&&o!=="/"&&o.endsWith("/"),f=(s||o===".")&&n.endsWith("/");return!d.pathname.endsWith("/")&&(u||f)&&(d.pathname+="/"),d}var Ut=e=>e.replace(/\/\/+/g,"/"),W=e=>Ut(e.join("/")),Ue=e=>e.replace(/\/+$/,""),_n=e=>Ue(e).replace(/^\/*/,"/"),In=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,Pn=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e,Ln=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 Bn(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.internal=="boolean"&&"data"in e}function Fn(e){let t=e.map(n=>n.route.path).filter(Boolean);return W(t)||"/"}var Ht=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function zt(e,t){let n=e;if(typeof n!="string"||!Mn.test(n))return{absoluteURL:void 0,isExternal:!1,to:n};let r=n,a=!1;if(Ht)try{let s=new URL(window.location.href),o=n.startsWith("//")?new URL(s.protocol+n):new URL(n),c=te(o.pathname,t);o.origin===s.origin&&c!=null?n=c+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 Wt=["POST","PUT","PATCH","DELETE"];new Set(Wt);var On=["GET",...Wt];new Set(On);var fe=l.createContext(null);fe.displayName="DataRouter";var ze=l.createContext(null);ze.displayName="DataRouterState";var Vt=l.createContext(!1);function Dn(){return l.useContext(Vt)}var Kt=l.createContext({isTransitioning:!1});Kt.displayName="ViewTransition";var Un=l.createContext(new Map);Un.displayName="Fetchers";var Hn=l.createContext(null);Hn.displayName="Await";var z=l.createContext(null);z.displayName="Navigation";var Se=l.createContext(null);Se.displayName="Location";var ne=l.createContext({outlet:null,matches:[],isDataRoute:!1});ne.displayName="Route";var it=l.createContext(null);it.displayName="RouteError";var Jt="REACT_ROUTER_ERROR",zn="REDIRECT",Wn="ROUTE_ERROR_RESPONSE";function Vn(e){if(e.startsWith(`${Jt}:${zn}:{`))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 Kn(e){if(e.startsWith(`${Jt}:${Wn}:{`))try{let t=JSON.parse(e.slice(40));if(typeof t=="object"&&t&&typeof t.status=="number"&&typeof t.statusText=="string")return new Ln(t.status,t.statusText,t.data)}catch{}}function Jn(e,{relative:t}={}){M(je(),"useHref() may be used only in the context of a <Router> component.");let{basename:n,navigator:r}=l.useContext(z),{hash:a,pathname:s,search:o}=Ce(e,{relative:t}),c=s;return n!=="/"&&(c=s==="/"?n:W([n,s])),r.createHref({pathname:c,search:o,hash:a})}function je(){return l.useContext(Se)!=null}function re(){return M(je(),"useLocation() may be used only in the context of a <Router> component."),l.useContext(Se).location}var qt="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function Gt(e){l.useContext(z).static||l.useLayoutEffect(e)}function Ne(){let{isDataRoute:e}=l.useContext(ne);return e?or():qn()}function qn(){M(je(),"useNavigate() may be used only in the context of a <Router> component.");let e=l.useContext(fe),{basename:t,navigator:n}=l.useContext(z),{matches:r}=l.useContext(ne),{pathname:a}=re(),s=JSON.stringify(Dt(r)),o=l.useRef(!1);return Gt(()=>{o.current=!0}),l.useCallback((d,u={})=>{if(q(o.current,qt),!o.current)return;if(typeof d=="number"){n.go(d);return}let f=ot(d,JSON.parse(s),a,u.relative==="path");e==null&&t!=="/"&&(f.pathname=f.pathname==="/"?t:W([t,f.pathname])),(u.replace?n.replace:n.push)(f,u.state,u)},[t,n,s,a,e])}l.createContext(null);function Ce(e,{relative:t}={}){let{matches:n}=l.useContext(ne),{pathname:r}=re(),a=JSON.stringify(Dt(n));return l.useMemo(()=>ot(e,JSON.parse(a),r,t==="path"),[e,a,r,t])}function Gn(e,t){return Yt(e,t)}function Yt(e,t,n){var m;M(je(),"useRoutes() may be used only in the context of a <Router> component.");let{navigator:r}=l.useContext(z),{matches:a}=l.useContext(ne),s=a[a.length-1],o=s?s.params:{},c=s?s.pathname:"/",d=s?s.pathnameBase:"/",u=s&&s.route;{let g=u&&u.path||"";Qt(c,!u||g.endsWith("*")||g.endsWith("*?"),`You rendered descendant <Routes> (or called \`useRoutes()\`) at "${c}" (under <Route path="${g}">) 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="${g}"> to <Route path="${g==="/"?"*":`${g}/*`}">.`)}let f=re(),h;if(t){let g=typeof t=="string"?he(t):t;M(d==="/"||((m=g.pathname)==null?void 0:m.startsWith(d)),`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 "${d}" but pathname "${g.pathname}" was given in the \`location\` prop.`),h=g}else h=f;let p=h.pathname||"/",b=p;if(d!=="/"){let g=d.replace(/^\//,"").split("/");b="/"+p.replace(/^\//,"").split("/").slice(g.length).join("/")}let y=n&&n.state.matches.length?n.state.matches.map(g=>Object.assign(g,{route:n.manifest[g.route.id]||g.route})):Bt(e,{pathname:b});q(u||y!=null,`No routes matched location "${h.pathname}${h.search}${h.hash}" `),q(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 "${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 v=er(y&&y.map(g=>Object.assign({},g,{params:Object.assign({},o,g.params),pathname:W([d,r.encodeLocation?r.encodeLocation(g.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:g.pathname]),pathnameBase:g.pathnameBase==="/"?d:W([d,r.encodeLocation?r.encodeLocation(g.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:g.pathnameBase])})),a,n);return t&&v?l.createElement(Se.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",mask:void 0,...h},navigationType:"POP"}},v):v}function Yn(){let e=sr(),t=Bn(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 Xn=l.createElement(Yn,null),Xt=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=Kn(e.digest);n&&(e=n)}let t=e!==void 0?l.createElement(ne.Provider,{value:this.props.routeContext},l.createElement(it.Provider,{value:e,children:this.props.component})):this.props.children;return this.context?l.createElement(Qn,{error:e},t):t}};Xt.contextType=Vt;var Xe=new WeakMap;function Qn({children:e,error:t}){let{basename:n}=l.useContext(z);if(typeof t=="object"&&t&&"digest"in t&&typeof t.digest=="string"){let r=Vn(t.digest);if(r){let a=Xe.get(t);if(a)throw a;let s=zt(r.location,n);if(Ht&&!Xe.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 Xe.set(t,o),o}return l.createElement("meta",{httpEquiv:"refresh",content:`0;url=${s.absoluteURL||s.to}`})}}return e}function Zn({routeContext:e,match:t,children:n}){let r=l.useContext(fe);return r&&r.static&&r.staticContext&&(t.route.errorElement||t.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=t.route.id),l.createElement(ne.Provider,{value:e},n)}function er(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 f=a.findIndex(h=>h.route.id&&(s==null?void 0:s[h.route.id])!==void 0);M(f>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(s).join(",")}`),a=a.slice(0,Math.min(a.length,f+1))}let o=!1,c=-1;if(n&&r){o=r.renderFallback;for(let f=0;f<a.length;f++){let h=a[f];if((h.route.HydrateFallback||h.route.hydrateFallbackElement)&&(c=f),h.route.id){let{loaderData:p,errors:b}=r,y=h.route.loader&&!p.hasOwnProperty(h.route.id)&&(!b||b[h.route.id]===void 0);if(h.route.lazy||y){n.isStatic&&(o=!0),c>=0?a=a.slice(0,c+1):a=[a[0]];break}}}}let d=n==null?void 0:n.onError,u=r&&d?(f,h)=>{var p,b;d(f,{location:r.location,params:((b=(p=r.matches)==null?void 0:p[0])==null?void 0:b.params)??{},pattern:Fn(r.matches),errorInfo:h})}:void 0;return a.reduceRight((f,h,p)=>{let b,y=!1,v=null,m=null;r&&(b=s&&h.route.id?s[h.route.id]:void 0,v=h.route.errorElement||Xn,o&&(c<0&&p===0?(Qt("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),y=!0,m=null):c===p&&(y=!0,m=h.route.hydrateFallbackElement||null)));let g=t.concat(a.slice(0,p+1)),x=()=>{let w;return b?w=v:y?w=m:h.route.Component?w=l.createElement(h.route.Component,null):h.route.element?w=h.route.element:w=f,l.createElement(Zn,{match:h,routeContext:{outlet:f,matches:g,isDataRoute:r!=null},children:w})};return r&&(h.route.ErrorBoundary||h.route.errorElement||p===0)?l.createElement(Xt,{location:r.location,revalidation:r.revalidation,component:v,error:b,children:x(),routeContext:{outlet:null,matches:g,isDataRoute:!0},onError:u}):x()},null)}function lt(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function tr(e){let t=l.useContext(fe);return M(t,lt(e)),t}function nr(e){let t=l.useContext(ze);return M(t,lt(e)),t}function rr(e){let t=l.useContext(ne);return M(t,lt(e)),t}function ct(e){let t=rr(e),n=t.matches[t.matches.length-1];return M(n.route.id,`${e} can only be used on routes that contain a unique "id"`),n.route.id}function ar(){return ct("useRouteId")}function sr(){var r;let e=l.useContext(it),t=nr("useRouteError"),n=ct("useRouteError");return e!==void 0?e:(r=t.errors)==null?void 0:r[n]}function or(){let{router:e}=tr("useNavigate"),t=ct("useNavigate"),n=l.useRef(!1);return Gt(()=>{n.current=!0}),l.useCallback(async(a,s={})=>{q(n.current,qt),n.current&&(typeof a=="number"?await e.navigate(a):await e.navigate(a,{fromRouteId:t,...s}))},[e,t])}var Nt={};function Qt(e,t,n){!t&&!Nt[e]&&(Nt[e]=!0,q(!1,n))}l.memo(ir);function ir({routes:e,manifest:t,future:n,state:r,isStatic:a,onError:s}){return Yt(e,void 0,{manifest:t,state:r,isStatic:a,onError:s})}function Be(e){M(!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 lr({basename:e="/",children:t=null,location:n,navigationType:r="POP",navigator:a,static:s=!1,useTransitions:o}){M(!je(),"You cannot render a <Router> inside another <Router>. You should never have more than one in your app.");let c=e.replace(/^\/*/,"/"),d=l.useMemo(()=>({basename:c,navigator:a,static:s,useTransitions:o,future:{}}),[c,a,s,o]);typeof n=="string"&&(n=he(n));let{pathname:u="/",search:f="",hash:h="",state:p=null,key:b="default",mask:y}=n,v=l.useMemo(()=>{let m=te(u,c);return m==null?null:{location:{pathname:m,search:f,hash:h,state:p,key:b,mask:y},navigationType:r}},[c,u,f,h,p,b,r,y]);return q(v!=null,`<Router basename="${c}"> is not able to match the URL "${u}${f}${h}" because it does not start with the basename, so the <Router> won't render anything.`),v==null?null:l.createElement(z.Provider,{value:d},l.createElement(Se.Provider,{children:t,value:v}))}function cr({children:e,location:t}){return Gn(tt(e),t)}function tt(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,tt(r.props.children,s));return}M(r.type===Be,`[${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>`),M(!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=tt(r.props.children,s)),n.push(o)}),n}var Fe="get",Oe="application/x-www-form-urlencoded";function We(e){return typeof HTMLElement<"u"&&e instanceof HTMLElement}function ur(e){return We(e)&&e.tagName.toLowerCase()==="button"}function dr(e){return We(e)&&e.tagName.toLowerCase()==="form"}function hr(e){return We(e)&&e.tagName.toLowerCase()==="input"}function fr(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function mr(e,t){return e.button===0&&(!t||t==="_self")&&!fr(e)}var _e=null;function pr(){if(_e===null)try{new FormData(document.createElement("form"),0),_e=!1}catch{_e=!0}return _e}var gr=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function Qe(e){return e!=null&&!gr.has(e)?(q(!1,`"${e}" is not a valid \`encType\` for \`<Form>\`/\`<fetcher.Form>\` and will default to "${Oe}"`),null):e}function yr(e,t){let n,r,a,s,o;if(dr(e)){let c=e.getAttribute("action");r=c?te(c,t):null,n=e.getAttribute("method")||Fe,a=Qe(e.getAttribute("enctype"))||Oe,s=new FormData(e)}else if(ur(e)||hr(e)&&(e.type==="submit"||e.type==="image")){let c=e.form;if(c==null)throw new Error('Cannot submit a <button> or <input type="submit"> without a <form>');let d=e.getAttribute("formaction")||c.getAttribute("action");if(r=d?te(d,t):null,n=e.getAttribute("formmethod")||c.getAttribute("method")||Fe,a=Qe(e.getAttribute("formenctype"))||Qe(c.getAttribute("enctype"))||Oe,s=new FormData(c,e),!pr()){let{name:u,type:f,value:h}=e;if(f==="image"){let p=u?`${u}.`:"";s.append(`${p}x`,"0"),s.append(`${p}y`,"0")}else u&&s.append(u,h)}}else{if(We(e))throw new Error('Cannot submit element that is not <form>, <button>, or <input type="submit|image">');n=Fe,r=null,a=Oe,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 ut(e,t){if(e===!1||e===null||typeof e>"u")throw new Error(t)}function Zt(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&&te(a.pathname,t)==="/"?a.pathname=`${Ue(t)}/_root.${r}`:a.pathname=`${Ue(a.pathname)}.${r}`,a}async function br(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 vr(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 wr(e,t,n){let r=await Promise.all(e.map(async a=>{let s=t.routes[a.route.id];if(s){let o=await br(s,n);return o.links?o.links():[]}return[]}));return kr(r.flat(1).filter(vr).filter(a=>a.rel==="stylesheet"||a.rel==="preload").map(a=>a.rel==="stylesheet"?{...a,rel:"prefetch",as:"style"}:{...a,rel:"prefetch"}))}function Ct(e,t,n,r,a,s){let o=(d,u)=>n[u]?d.route.id!==n[u].route.id:!0,c=(d,u)=>{var f;return n[u].pathname!==d.pathname||((f=n[u].route.path)==null?void 0:f.endsWith("*"))&&n[u].params["*"]!==d.params["*"]};return s==="assets"?t.filter((d,u)=>o(d,u)||c(d,u)):s==="data"?t.filter((d,u)=>{var h;let f=r.routes[d.route.id];if(!f||!f.hasLoader)return!1;if(o(d,u)||c(d,u))return!0;if(d.route.shouldRevalidate){let p=d.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:d.params,defaultShouldRevalidate:!0});if(typeof p=="boolean")return p}return!0}):[]}function xr(e,t,{includeHydrateFallback:n}={}){return Er(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 Er(e){return[...new Set(e)]}function Rr(e){let t={},n=Object.keys(e).sort();for(let r of n)t[r]=e[r];return t}function kr(e,t){let n=new Set;return new Set(t),e.reduce((r,a)=>{let s=JSON.stringify(Rr(a));return n.has(s)||(n.add(s),r.push({key:s,link:a})),r},[])}function dt(){let e=l.useContext(fe);return ut(e,"You must render this element inside a <DataRouterContext.Provider> element"),e}function Sr(){let e=l.useContext(ze);return ut(e,"You must render this element inside a <DataRouterStateContext.Provider> element"),e}var ht=l.createContext(void 0);ht.displayName="FrameworkContext";function ft(){let e=l.useContext(ht);return ut(e,"You must render this element inside a <HydratedRouter> element"),e}function jr(e,t){let n=l.useContext(ht),[r,a]=l.useState(!1),[s,o]=l.useState(!1),{onFocus:c,onBlur:d,onMouseEnter:u,onMouseLeave:f,onTouchStart:h}=t,p=l.useRef(null);l.useEffect(()=>{if(e==="render"&&o(!0),e==="viewport"){let v=g=>{g.forEach(x=>{o(x.isIntersecting)})},m=new IntersectionObserver(v,{threshold:.5});return p.current&&m.observe(p.current),()=>{m.disconnect()}}},[e]),l.useEffect(()=>{if(r){let v=setTimeout(()=>{o(!0)},100);return()=>{clearTimeout(v)}}},[r]);let b=()=>{a(!0)},y=()=>{a(!1),o(!1)};return n?e!=="intent"?[s,p,{}]:[s,p,{onFocus:ye(c,b),onBlur:ye(d,y),onMouseEnter:ye(u,b),onMouseLeave:ye(f,y),onTouchStart:ye(h,b)}]:[!1,p,{}]}function ye(e,t){return n=>{e&&e(n),n.defaultPrevented||t(n)}}function Nr({page:e,...t}){let n=Dn(),{router:r}=dt(),a=l.useMemo(()=>Bt(r.routes,e,r.basename),[r.routes,e,r.basename]);return a?n?l.createElement(Tr,{page:e,matches:a,...t}):l.createElement(Mr,{page:e,matches:a,...t}):null}function Cr(e){let{manifest:t,routeModules:n}=ft(),[r,a]=l.useState([]);return l.useEffect(()=>{let s=!1;return wr(e,t,n).then(o=>{s||a(o)}),()=>{s=!0}},[e,t,n]),r}function Tr({page:e,matches:t,...n}){let r=re(),{future:a}=ft(),{basename:s}=dt(),o=l.useMemo(()=>{if(e===r.pathname+r.search+r.hash)return[];let c=Zt(e,s,a.unstable_trailingSlashAwareDataRequests,"rsc"),d=!1,u=[];for(let f of t)typeof f.route.shouldRevalidate=="function"?d=!0:u.push(f.route.id);return d&&u.length>0&&c.searchParams.set("_routes",u.join(",")),[c.pathname+c.search]},[s,a.unstable_trailingSlashAwareDataRequests,e,r,t]);return l.createElement(l.Fragment,null,o.map(c=>l.createElement("link",{key:c,rel:"prefetch",as:"fetch",href:c,...n})))}function Mr({page:e,matches:t,...n}){let r=re(),{future:a,manifest:s,routeModules:o}=ft(),{basename:c}=dt(),{loaderData:d,matches:u}=Sr(),f=l.useMemo(()=>Ct(e,t,u,s,r,"data"),[e,t,u,s,r]),h=l.useMemo(()=>Ct(e,t,u,s,r,"assets"),[e,t,u,s,r]),p=l.useMemo(()=>{if(e===r.pathname+r.search+r.hash)return[];let v=new Set,m=!1;if(t.forEach(x=>{var $;let w=s.routes[x.route.id];!w||!w.hasLoader||(!f.some(R=>R.route.id===x.route.id)&&x.route.id in d&&(($=o[x.route.id])!=null&&$.shouldRevalidate)||w.hasClientLoader?m=!0:v.add(x.route.id))}),v.size===0)return[];let g=Zt(e,c,a.unstable_trailingSlashAwareDataRequests,"data");return m&&v.size>0&&g.searchParams.set("_routes",t.filter(x=>v.has(x.route.id)).map(x=>x.route.id).join(",")),[g.pathname+g.search]},[c,a.unstable_trailingSlashAwareDataRequests,d,r,s,f,t,e,o]),b=l.useMemo(()=>xr(h,s),[h,s]),y=Cr(h);return l.createElement(l.Fragment,null,p.map(v=>l.createElement("link",{key:v,rel:"prefetch",as:"fetch",href:v,...n})),b.map(v=>l.createElement("link",{key:v,rel:"modulepreload",href:v,...n})),y.map(({key:v,link:m})=>l.createElement("link",{key:v,nonce:n.nonce,...m,crossOrigin:m.crossOrigin??n.crossOrigin})))}function Ar(...e){return t=>{e.forEach(n=>{typeof n=="function"?n(t):n!=null&&(n.current=t)})}}var $r=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";try{$r&&(window.__reactRouterVersion="7.15.1")}catch{}function _r({basename:e,children:t,useTransitions:n,window:r}){let a=l.useRef();a.current==null&&(a.current=hn({window:r,v5Compat:!0}));let s=a.current,[o,c]=l.useState({action:s.action,location:s.location}),d=l.useCallback(u=>{n===!1?c(u):l.startTransition(()=>c(u))},[n]);return l.useLayoutEffect(()=>s.listen(d),[s,d]),l.createElement(lr,{basename:e,children:t,location:o.location,navigationType:o.action,navigator:s,useTransitions:n})}var en=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,tn=l.forwardRef(function({onClick:t,discover:n="render",prefetch:r="none",relative:a,reloadDocument:s,replace:o,mask:c,state:d,target:u,to:f,preventScrollReset:h,viewTransition:p,defaultShouldRevalidate:b,...y},v){let{basename:m,navigator:g,useTransitions:x}=l.useContext(z),w=typeof f=="string"&&en.test(f),$=zt(f,m);f=$.to;let R=Jn(f,{relative:a}),U=re(),V=null;if(c){let I=ot(c,[],U.mask?U.mask.pathname:"/",!0);m!=="/"&&(I.pathname=I.pathname==="/"?m:W([m,I.pathname])),V=g.createHref(I)}let[X,ie,me]=jr(r,y),Ke=Br(f,{replace:o,mask:c,state:d,target:u,preventScrollReset:h,relative:a,viewTransition:p,defaultShouldRevalidate:b,useTransitions:x});function le(I){t&&t(I),I.defaultPrevented||Ke(I)}let Te=!($.isExternal||s),Q=l.createElement("a",{...y,...me,href:(Te?V:void 0)||$.absoluteURL||R,onClick:Te?le:t,ref:Ar(v,ie),target:u,"data-discover":!w&&n==="render"?"true":void 0});return X&&!w?l.createElement(l.Fragment,null,Q,l.createElement(Nr,{page:R})):Q});tn.displayName="Link";var Ir=l.forwardRef(function({"aria-current":t="page",caseSensitive:n=!1,className:r="",end:a=!1,style:s,to:o,viewTransition:c,children:d,...u},f){let h=Ce(o,{relative:u.relative}),p=re(),b=l.useContext(ze),{navigator:y,basename:v}=l.useContext(z),m=b!=null&&Hr(h)&&c===!0,g=y.encodeLocation?y.encodeLocation(h).pathname:h.pathname,x=p.pathname,w=b&&b.navigation&&b.navigation.location?b.navigation.location.pathname:null;n||(x=x.toLowerCase(),w=w?w.toLowerCase():null,g=g.toLowerCase()),w&&v&&(w=te(w,v)||w);const $=g!=="/"&&g.endsWith("/")?g.length-1:g.length;let R=x===g||!a&&x.startsWith(g)&&x.charAt($)==="/",U=w!=null&&(w===g||!a&&w.startsWith(g)&&w.charAt(g.length)==="/"),V={isActive:R,isPending:U,isTransitioning:m},X=R?t:void 0,ie;typeof r=="function"?ie=r(V):ie=[r,R?"active":null,U?"pending":null,m?"transitioning":null].filter(Boolean).join(" ");let me=typeof s=="function"?s(V):s;return l.createElement(tn,{...u,"aria-current":X,className:ie,ref:f,style:me,to:o,viewTransition:c},typeof d=="function"?d(V):d)});Ir.displayName="NavLink";var Pr=l.forwardRef(({discover:e="render",fetcherKey:t,navigate:n,reloadDocument:r,replace:a,state:s,method:o=Fe,action:c,onSubmit:d,relative:u,preventScrollReset:f,viewTransition:h,defaultShouldRevalidate:p,...b},y)=>{let{useTransitions:v}=l.useContext(z),m=Dr(),g=Ur(c,{relative:u}),x=o.toLowerCase()==="get"?"get":"post",w=typeof c=="string"&&en.test(c),$=R=>{if(d&&d(R),R.defaultPrevented)return;R.preventDefault();let U=R.nativeEvent.submitter,V=(U==null?void 0:U.getAttribute("formmethod"))||o,X=()=>m(U||R.currentTarget,{fetcherKey:t,method:V,navigate:n,replace:a,state:s,relative:u,preventScrollReset:f,viewTransition:h,defaultShouldRevalidate:p});v&&n!==!1?l.startTransition(()=>X()):X()};return l.createElement("form",{ref:y,method:x,action:g,onSubmit:r?d:$,...b,"data-discover":!w&&e==="render"?"true":void 0})});Pr.displayName="Form";function Lr(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function nn(e){let t=l.useContext(fe);return M(t,Lr(e)),t}function Br(e,{target:t,replace:n,mask:r,state:a,preventScrollReset:s,relative:o,viewTransition:c,defaultShouldRevalidate:d,useTransitions:u}={}){let f=Ne(),h=re(),p=Ce(e,{relative:o});return l.useCallback(b=>{if(mr(b,t)){b.preventDefault();let y=n!==void 0?n:Re(h)===Re(p),v=()=>f(e,{replace:y,mask:r,state:a,preventScrollReset:s,relative:o,viewTransition:c,defaultShouldRevalidate:d});u?l.startTransition(()=>v()):v()}},[h,f,p,n,r,a,t,e,s,o,c,d,u])}var Fr=0,Or=()=>`__${String(++Fr)}__`;function Dr(){let{router:e}=nn("useSubmit"),{basename:t}=l.useContext(z),n=ar(),r=e.fetch,a=e.navigate;return l.useCallback(async(s,o={})=>{let{action:c,method:d,encType:u,formData:f,body:h}=yr(s,t);if(o.navigate===!1){let p=o.fetcherKey||Or();await r(p,n,o.action||c,{defaultShouldRevalidate:o.defaultShouldRevalidate,preventScrollReset:o.preventScrollReset,formData:f,body:h,formMethod:o.method||d,formEncType:o.encType||u,flushSync:o.flushSync})}else await a(o.action||c,{defaultShouldRevalidate:o.defaultShouldRevalidate,preventScrollReset:o.preventScrollReset,formData:f,body:h,formMethod:o.method||d,formEncType:o.encType||u,replace:o.replace,state:o.state,fromRouteId:n,flushSync:o.flushSync,viewTransition:o.viewTransition})},[r,a,t,n])}function Ur(e,{relative:t}={}){let{basename:n}=l.useContext(z),r=l.useContext(ne);M(r,"useFormAction must be used inside a RouteContext");let[a]=r.matches.slice(-1),s={...Ce(e||".",{relative:t})},o=re();if(e==null){s.search=o.search;let c=new URLSearchParams(s.search),d=c.getAll("index");if(d.some(f=>f==="")){c.delete("index"),d.filter(h=>h).forEach(h=>c.append("index",h));let f=c.toString();s.search=f?`?${f}`:""}}return(!e||e===".")&&a.route.index&&(s.search=s.search?s.search.replace(/^\?/,"?index&"):"?index"),n!=="/"&&(s.pathname=s.pathname==="/"?n:W([n,s.pathname])),Re(s)}function Hr(e,{relative:t}={}){let n=l.useContext(Kt);M(n!=null,"`useViewTransitionState` must be used within `react-router-dom`'s `RouterProvider`. Did you accidentally import `RouterProvider` from `react-router`?");let{basename:r}=nn("useViewTransitionState"),a=Ce(e,{relative:t});if(!n.isTransitioning)return!1;let s=te(n.currentLocation.pathname,r)||n.currentLocation.pathname,o=te(n.nextLocation.pathname,r)||n.nextLocation.pathname;return De(a.pathname,o)!=null||De(a.pathname,s)!=null}const L=6,se=2.6,J=240,Z={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 F(e,t,n,r,a,s=5){const o=[],c=new Set;for(let d=r;d<=a;d+=s){const u=d*Math.PI/180,f=Math.round(e+n*Math.cos(u)),h=Math.round(t+n*Math.sin(u)),p=`${f},${h}`;c.has(p)||(c.add(p),o.push([f,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 nt(e,t,n,r){const a=[],s=new Set,o=Math.round(n);for(let c=-o;c<=o;c++){const d=c/o*Math.PI,u=Math.round(t+r*Math.sin(d)),f=`${e+c},${u}`;s.has(f)||(s.add(f),a.push([e+c,u]))}return a}function zr(e,t,n,r){const a=[],s=Math.round(n);for(let o=-s;o<=s;o++){const c=o+s;a.push([e+o,Math.round(t+(c%4<2?r:-r))])}return a}function Tt(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 Mt(e,t,n,r){const a=[],s=new Set,o=Math.round(r*2*Math.PI*8);for(let c=0;c<=o;c++){const d=c/o*r*2*Math.PI,u=c/o*n,f=Math.round(e+u*Math.cos(d)),h=Math.round(t+u*Math.sin(d)),p=`${f},${h}`;s.has(p)||(s.add(p),a.push([f,h]))}return a}function Ze(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 At(e,t){return[...F(e,t-1,1.5,200,360,30),[e,t+1],[e,t+3]]}function ee(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 H(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 de(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 oe(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 Ie(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 Pe(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 Wr(e,t){return{wink:F(e,t+1,3,200,340,15)}}function we(e,t){return F(e,t,5,25,155)}function rt(e,t){return F(e,t,7,15,165)}function $t(e,t){return Y(e,t,5)}function Vr(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(([s,o])=>`${s},${o}`));return[...n,...r.filter(([s,o])=>!a.has(`${s},${o}`))]}function Kr(e,t){const n=F(e-2,t,2,200,340,20),r=F(e+2,t,2,200,340,20),a=Y(e,t+2,3),s=new Set(n.map(([o,c])=>`${o},${c}`));return[...n,...r.filter(([o,c])=>!s.has(`${o},${c}`)),...a]}function Jr(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,s=F(e,t-a,3.5,190,350,8),o=F(e,t+a,3,10,170,8),c=new Set(s.map(([d,u])=>`${d},${u}`));return[...s,...o.filter(([d,u])=>!c.has(`${d},${u}`))]}const[k,S]=Z.LE,[j,N]=Z.RE,[C,T]=Z.MO,B="#22CCFF",qr=[{id:"idle",label:"😐 待机",color:"#00FFEE",category:"interaction",canBlink:!0,leftEye:ee(k,S),rightEye:ee(j,N),mouth:we(C,T)},{id:"listening",label:"👂 聆听",color:"#44AAFF",category:"interaction",canBlink:!0,leftEye:H(k,S),rightEye:H(j,N),mouth:F(C,T,3,0,180)},{id:"thinking",label:"🤔 思考",color:"#FFCC00",category:"interaction",canBlink:!0,leftEye:de(k,S),rightEye:ee(j,N),mouth:nt(C,T,5,1),extras:[{dots:At(k-1,S-6),color:"#FFCC00",alpha:.75}]},{id:"speaking",label:"💬 说话",color:"#FFFFFF",pupilColor:"#002233",category:"interaction",canBlink:!0,leftEye:ee(k,S),rightEye:ee(j,N),speakingMouth:!0},{id:"happy",label:"😊 开心",color:"#FF44AA",category:"interaction",canBlink:!0,leftEye:{heart:Tt(k,S)},rightEye:{heart:Tt(j,N)},mouth:rt(C,T)},{id:"error",label:"😵 错误",color:"#FF4400",category:"interaction",canBlink:!0,leftEye:{spiral:Mt(k,S,4,2)},rightEye:{spiral:Mt(j,N,4,2)},mouth:zr(C,T,5,1.5)},{id:"confused",label:"😕 困惑",color:"#BB44FF",category:"interaction",canBlink:!0,leftEye:H(k,S),rightEye:de(j,N),mouth:nt(C,T,5,1.5),extras:[{dots:At(j+1,N-6),color:"#BB44FF",alpha:.75}]},{id:"dreaming",label:"💤 做梦",color:"#5566FF",category:"interaction",canBlink:!0,leftEye:oe(k,S),rightEye:oe(j,N),mouth:we(C,T),extras:[{dots:Ze(24,10),color:"#5566FF",alpha:.85,zzzIndex:0},{dots:Ze(28,7),color:"#7788FF",alpha:.75,zzzIndex:1},{dots:Ze(32,4),color:"#99AAFF",alpha:.65,zzzIndex:2}]}],rn=[{id:"natural_smile",label:"01 自然微笑",color:B,category:"auto",canBlink:!0,leftEye:ee(k,S),rightEye:ee(j,N),mouth:we(C,T)},{id:"calm_relax",label:"02 平静放松",color:B,category:"auto",canBlink:!0,leftEye:oe(k,S),rightEye:oe(j,N),mouth:$t(C,T)},{id:"curious_observe",label:"03 好奇观察",color:B,category:"auto",canBlink:!0,leftEye:H(k,S),rightEye:H(j,N),mouth:F(C,T,4,30,150,8)},{id:"light_joy",label:"04 轻松愉悦",color:B,category:"auto",canBlink:!0,leftEye:de(k,S),rightEye:de(j,N),mouth:rt(C,T)},{id:"side_think",label:"05 侧目思考",color:B,category:"auto",canBlink:!0,leftEye:Pe(k,S,2),rightEye:Pe(j,N,2),mouth:nt(C,T,4,1)},{id:"warm_friendly",label:"06 温和友善",color:B,category:"auto",canBlink:!0,leftEye:Ie(k,S),rightEye:Ie(j,N),mouth:we(C,T)},{id:"quiet_listen",label:"07 静静聆听",color:B,category:"auto",canBlink:!0,leftEye:ee(k,S),rightEye:ee(j,N),mouth:Y(C,T,4)},{id:"focus_gaze",label:"08 专注注视",color:B,category:"auto",canBlink:!0,leftEye:H(k,S),rightEye:H(j,N),mouth:$t(C,T)},{id:"quiet_wait",label:"09 安静等待",color:B,category:"auto",canBlink:!0,leftEye:oe(k,S),rightEye:oe(j,N),mouth:F(C,T,4,30,150,8)},{id:"slow_blink",label:"10 慢眨眼",color:B,category:"auto",canBlink:!0,leftEye:de(k,S),rightEye:de(j,N),mouth:we(C,T)},{id:"look_around",label:"11 左右扫视",color:B,category:"auto",canBlink:!0,leftEye:Pe(k,S,-2),rightEye:Pe(j,N,-2),mouth:Y(C,T,4)},{id:"playful",label:"12 小小调皮",color:B,category:"auto",canBlink:!1,leftEye:Wr(k,S),rightEye:H(j,N),mouth:Vr(C,T)},{id:"joyful_wait",label:"13 愉悦期待",color:B,category:"auto",canBlink:!0,leftEye:H(k,S),rightEye:H(j,N),mouth:rt(C,T)},{id:"slight_surprise",label:"14 轻微惊喜",color:B,category:"auto",canBlink:!0,leftEye:H(k,S),rightEye:H(j,N),mouth:F(C,T,3,0,180,10)},{id:"gentle_gaze",label:"15 温柔注视",color:B,category:"auto",canBlink:!0,leftEye:Ie(k,S),rightEye:Ie(j,N),mouth:F(C,T,4,30,150,8)},{id:"spaceout",label:"16 发呆放空",color:B,category:"auto",canBlink:!0,leftEye:oe(k,S),rightEye:oe(j,N),mouth:Kr(C,T)}],mt=[...qr,...rn],be=rn.map(e=>e.id),at=Object.fromEntries(mt.map(e=>[e.id,e]));function D(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 c=s*L+L/2,d=o*L+L/2;e.moveTo(c+se,d),e.arc(c,d,se,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 c=s*L+L/2,d=o*L+L/2;e.moveTo(c+se*.38,d),e.arc(c,d,se*.38,0,Math.PI*2)}e.fill()}else{const s=[],o=[];for(const[d,u]of t){const f=(d*7.3+u*13.1)*.31;(Math.sin(a*1.1+f)>0?s:o).push([d,u])}const c=(d,u,f)=>{if(d.length){e.globalAlpha=Math.max(0,Math.min(1,u)),e.shadowBlur=f,e.shadowColor=n,e.fillStyle=n,e.beginPath();for(const[h,p]of d){const b=h*L+L/2,y=p*L+L/2;e.moveTo(b+se,y),e.arc(b,y,se,0,Math.PI*2)}e.fill()}};c(o,r*.68,7),c(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[d,u]of t){const f=d*L+L/2,h=u*L+L/2;e.moveTo(f+se*.38,h),e.arc(f,h,se*.38,0,Math.PI*2)}e.fill()}e.restore()}}function ve(e,t,n){return n>=1?e:e.map(([r,a])=>[r,t+(a-t)*n])}function Gr(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 _t(e,t,n,r,a,s,o,c,d){if(!t)return;const u=s||"#001020";t.iris?(D(e,ve(t.iris,r,c),a,o,d),D(e,ve(t.pupil,r,c),u,o,null),t.hl&&D(e,ve(t.hl,r,c),"#ffffff",o*.9,null),t.lash&&D(e,ve(t.lash,r,c),a,o,null)):t.closed!==void 0?(D(e,t.closed,a,o,d),t.lash&&D(e,t.lash,a,o,null)):t.wink?D(e,t.wink,a,o,d):t.heart?D(e,t.heart,a,o,d):t.spiral?D(e,t.spiral,a,o,d):t.star?D(e,t.star,a,o,d):t.pts&&D(e,ve(t.pts,r,c),a,o,d)}function Yr({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 c(u,f,h,p){if(!u)return;_t(s,u.leftEye,Z.LE[0],Z.LE[1],u.color,u.pupilColor,f,h,p),_t(s,u.rightEye,Z.RE[0],Z.RE[1],u.color,u.pupilColor,f,h,p);const b=u.speakingMouth?Jr(Z.MO[0],Z.MO[1],o.t):u.mouth;if(b&&D(s,b,u.color,f,p),u.extras)for(const y of u.extras){let v=f*y.alpha;if(y.zzzIndex!==void 0){const m=o.t-y.zzzIndex*1.2;v*=.35+.65*(Math.sin(m)*.5+.5)}D(s,y.dots,y.color,v,null)}}function d(){const u=performance.now();o.t+=.04,s.clearRect(0,0,J,J),s.fillStyle="#000",s.fillRect(0,0,J,J);let f=1,h=0;if(o.transitionStart!==null){const v=u-o.transitionStart;if(v>=380)o.transitionStart=null,o.previousId=null;else{const m=v/380,g=m<.5?2*m*m:1-(-2*m+2)**2/2;f=g,h=1-g}}const p=at[o.currentId];!o.blinkStart&&o.transitionStart===null&&(p!=null&&p.canBlink)&&u>=o.nextBlink&&(o.blinkStart=u,o.nextBlink=u+2500+Math.random()*2500),o.blinkStart!==null&&u-o.blinkStart>=340&&(o.blinkStart=null);const b=Gr(o.blinkStart,u);o.previousId&&c(at[o.previousId],h,1,null);const y=o.transitionStart===null?o.t:null;c(p,f,b,y),s.save(),s.globalAlpha=.04,s.fillStyle="#000";for(let v=0;v<J;v+=2)s.fillRect(0,v+1,J,1);s.restore(),o.raf=requestAnimationFrame(d)}return o.raf=requestAnimationFrame(d),()=>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 Le(e,t){const n=[],r=/(\*\*[^*]+?\*\*|__[^_]+?__|`[^`]+?`|\[[^\]]+?\]\([^)]+?\))/g;let a=0,s,o=0;for(;(s=r.exec(e))!==null;){s.index>a&&n.push(e.slice(a,s.index));const c=s[0];if(c.startsWith("**")||c.startsWith("__"))n.push(i.jsx("strong",{children:c.slice(2,-2)},`${t}-b-${o++}`));else if(c.startsWith("`"))n.push(i.jsx("code",{children:c.slice(1,-1)},`${t}-c-${o++}`));else{const d=c.indexOf("]"),u=c.slice(1,d),f=c.slice(d+2,-1);n.push(i.jsx("a",{href:f,target:"_blank",rel:"noreferrer",children:u},`${t}-a-${o++}`))}a=s.index+c.length}return a<e.length&&n.push(e.slice(a)),n}function Xr({text:e}){const n=(e||"").replace(/\r\n/g,`
`).split(`
`),r=[];let a=0,s=0;for(;a<n.length;){const o=n[a];if(!o.trim()){a+=1;continue}if(o.startsWith("```")){const u=[];for(a+=1;a<n.length&&!n[a].startsWith("```");)u.push(n[a]),a+=1;a<n.length&&(a+=1),r.push(i.jsx("pre",{className:"bubble-code",children:i.jsx("code",{children:u.join(`
`)})},`md-${s++}`));continue}const c=o.match(/^(#{1,6})\s+(.*)$/);if(c){const u=Math.min(c[1].length,3),f=`h${u}`;r.push(i.jsx(f,{className:`bubble-heading bubble-heading-${u}`,children:Le(c[2],`h-${s}`)},`md-${s++}`)),a+=1;continue}if(/^\s*[-*+]\s+/.test(o)){const u=[];for(;a<n.length&&/^\s*[-*+]\s+/.test(n[a]);)u.push(n[a].replace(/^\s*[-*+]\s+/,"")),a+=1;r.push(i.jsx("ul",{className:"bubble-list",children:u.map((f,h)=>i.jsx("li",{children:Le(f,`ul-${s}-${h}`)},`md-${s}-${h}`))},`md-${s++}`));continue}if(/^\s*\d+\.\s+/.test(o)){const u=[];for(;a<n.length&&/^\s*\d+\.\s+/.test(n[a]);)u.push(n[a].replace(/^\s*\d+\.\s+/,"")),a+=1;r.push(i.jsx("ol",{className:"bubble-list bubble-list-ordered",children:u.map((f,h)=>i.jsx("li",{children:Le(f,`ol-${s}-${h}`)},`md-${s}-${h}`))},`md-${s++}`));continue}const d=[];for(;a<n.length&&n[a].trim()&&!n[a].startsWith("```")&&!/^(#{1,6})\s+/.test(n[a])&&!/^\s*[-*+]\s+/.test(n[a])&&!/^\s*\d+\.\s+/.test(n[a]);)d.push(n[a]),a+=1;r.push(i.jsx("p",{className:"bubble-paragraph",children:Le(d.join(" "),`p-${s}`)},`md-${s++}`))}return i.jsx("div",{className:"bubble-markdown",children:r})}function Qr({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 ea({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 ta({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(ea,{toolCalls:a}),i.jsx("div",{className:"bubble-text",children:i.jsx(Xr,{text:t})}),n&&i.jsx(Qr,{base64:n,mimeType:r||"audio/mp3"})]})}function na({messages:e,voiceStatus:t}){const n=l.useRef(null),r=Ne();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(ta,{role:a.role,text:a.text,audioBase64:a.audioBase64,audioMime:a.audioMime,toolCalls:a.toolCalls},a.id)),i.jsx("div",{ref:n})]})]})}const Ve="jbot_memory",ra=100;function xe(){try{return JSON.parse(localStorage.getItem(Ve)||"[]")}catch{return[]}}function aa(e){const t=xe(),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(Ve,JSON.stringify([r,...t].slice(0,ra))),r}function sa(e){localStorage.setItem(Ve,JSON.stringify(xe().filter(t=>t.id!==e)))}function oa(){localStorage.removeItem(Ve)}function ia({memories:e,onMemoriesChange:t}){const[n,r]=l.useState(!1),a=o=>{sa(o),t()},s=()=>{window.confirm("清空所有记忆?")&&(oa(),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 ue="/api/jbot";async function la(){return(await fetch(`${ue}/config/`)).json()}async function ca(e,t=[],n={},r){const a=await fetch(`${ue}/chat/`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({messages:e,memories:t,settings:n}),signal:r});if(!a.ok){const s=await a.json().catch(()=>({}));throw new Error(s.error||`HTTP ${a.status}`)}return a.json()}async function ua(e,t="audio/webm"){const n=await fetch(`${ue}/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 da(e,t){const n=await fetch(`${ue}/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 ha(e,t){try{const n=await fetch(`${ue}/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 fa(){try{const e=await fetch(`${ue}/api-config/`);return e.ok?e.json():{}}catch{return{}}}async function ma(e){const t=await fetch(`${ue}/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 pa(){const[e,t]=l.useState(!1),n=l.useRef(null),r=l.useRef(null),a=l.useRef(null),s=l.useRef([]),o=l.useRef(""),c=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 u=MediaRecorder.isTypeSupported("audio/webm;codecs=opus")?"audio/webm;codecs=opus":"audio/webm",f=new MediaRecorder(n.current,{mimeType:u});f.ondataavailable=b=>{b.data.size>0&&s.current.push(b.data)},f.start(100),r.current=f;const h=window.SpeechRecognition||window.webkitSpeechRecognition;if(h){const b=new h;b.lang="zh-CN",b.interimResults=!0,b.continuous=!0,b.onresult=y=>{let v="";for(const m of y.results)m.isFinal&&(v+=m[0].transcript);v&&(o.current=v)},b.onerror=y=>{console.warn("SpeechRecognition error:",y.error)},b.start(),a.current=b}t(!0)},[e]),d=l.useCallback(()=>new Promise(u=>{var p,b;t(!1);const f=o.current;try{(p=a.current)==null||p.stop()}catch{}a.current=null,(b=n.current)==null||b.getTracks().forEach(y=>y.stop()),n.current=null;const h=r.current;if(!h)return u({transcript:f,audioBase64:null,mimeType:null});h.onstop=async()=>{const y=h.mimeType;if(s.current.length===0)return u({transcript:f,audioBase64:null,mimeType:y});const v=new Blob(s.current,{type:y}),m=new FileReader;m.onloadend=()=>{u({transcript:f,audioBase64:m.result.split(",")[1],mimeType:y})},m.readAsDataURL(v)},h.stop(),r.current=null}),[]);return{isRecording:e,start:c,stop:d}}const Ee="jbot_history",ga=60,ya=12;function It(e){return{...e,userAudioBase64:null,userAudioMime:null,botAudioBase64:null,botAudioMime:null}}function an(e){const t=e.slice(0,ga);for(let n=Math.min(ya,t.length);n>=0;n-=1){const r=t.map((a,s)=>s<n?a:It(a));try{return localStorage.setItem(Ee,JSON.stringify(r)),r}catch(a){if((a==null?void 0:a.name)!=="QuotaExceededError"&&(a==null?void 0:a.code)!==22)throw a}}for(let n=Math.min(t.length,20);n>=1;n-=1){const r=t.slice(0,n).map(It);try{return localStorage.setItem(Ee,JSON.stringify(r)),r}catch(a){if((a==null?void 0:a.name)!=="QuotaExceededError"&&(a==null?void 0:a.code)!==22)throw a}}return localStorage.removeItem(Ee),[]}function He(){try{return JSON.parse(localStorage.getItem(Ee)||"[]")}catch{return[]}}function ba(e){const t=He(),n=[{id:crypto.randomUUID(),timestamp:Date.now(),...e},...t];return an(n)[0]||n[0]}function va(){localStorage.removeItem(Ee)}function wa(e){an(He().filter(t=>t.id!==e))}const xa=[{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"}],sn="zh_female_vv_uranus_bigtts",pt="jbot_settings",st={robotName:"JBOT",robotPersonality:"你是一个友好、简洁、偶尔幽默的AI机器人助手。回复控制在80字以内。",language:"auto",voiceId:sn,customVoiceId:"",responseMaxWords:80,switchIntervalMs:1e4};function ke(){try{const e=JSON.parse(localStorage.getItem(pt)||"{}");return{...st,...e}}catch{return{...st}}}function Ea(e){const n={...ke(),...e};return localStorage.setItem(pt,JSON.stringify(n)),n}function Ra(){return localStorage.removeItem(pt),{...st}}function ka(e=null){var n;const t=e||ke();return((n=t.customVoiceId)==null?void 0:n.trim())||t.voiceId||sn}const Sa=mt.filter(e=>e.category==="interaction"),ja=mt.filter(e=>e.category==="auto"),Na={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 Ca(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 Ta(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 Ma(e){return e?e.replace(/```(?:[a-zA-Z0-9_-]+)?\n([\s\S]*?)```/g,(t,n)=>n).replace(/`([^`]+)`/g,"$1").replace(/!\[([^\]]*)\]\([^)]+\)/g,"$1").replace(/\[([^\]]+)\]\(([^)]+)\)/g,"$1").replace(/^\s{0,3}#{1,6}\s+/gm,"").replace(/^\s{0,3}>\s?/gm,"").replace(/^\s*[-*+]\s+/gm,"• ").replace(/^\s*\d+\.\s+/gm,"").replace(/(\*\*|__)(.*?)\1/g,"$2").replace(/(\*|_)(.*?)\1/g,"$2").replace(/\|/g," ").replace(/\r/g,"").replace(/[ \t]+\n/g,`
`).replace(/\n{3,}/g,`
`).trim():""}function Aa({phase:e,onStart:t,onEnd:n,onCancel:r}){const a=e==="thinking"||e==="speaking",s=e!=="idle";let o="🎙 按住说话",c="";e==="acquiring"?(o="⏳ 准备中…",c=" vbtn--acquiring"):e==="listening"?(o="🔴 松开发送",c=" vbtn--recording"):e==="thinking"?(o="⚙ 思考中…",c=" vbtn--busy"):e==="speaking"&&(o="🔊 播放中…",c=" vbtn--busy");const d=f=>{f.preventDefault(),a||t()},u=f=>{f.preventDefault(),n()};return i.jsxs("div",{className:"vbtn-wrap",children:[i.jsx("button",{className:`vbtn${c}`,disabled:a,onMouseDown:d,onMouseUp:u,onMouseLeave:u,onTouchStart:d,onTouchEnd:u,onTouchCancel:u,children:o}),s&&i.jsx("button",{className:"vbtn-cancel",onClick:r,title:"取消",children:"✕"})]})}function $a(){var yt;const e=Ne(),[t,n]=l.useState(be[0]),[r,a]=l.useState(!0),[s,o]=l.useState(1),[c]=l.useState(()=>ke().switchIntervalMs??1e4),d=l.useRef(null),u=l.useRef(!0),f=l.useRef(be[0]),h=l.useRef(null),p=l.useRef(c);l.useEffect(()=>{u.current=r},[r]),l.useEffect(()=>{f.current=t},[t]);const b=l.useCallback(()=>{clearTimeout(d.current),d.current=null},[]);h.current=()=>{if(b(),!u.current)return;const E=1+(Math.random()-.5)*.3;d.current=setTimeout(()=>{var P;const O=be.filter(ae=>ae!==f.current),_=O[Math.floor(Math.random()*O.length)];n(_),(P=h.current)==null||P.call(h)},p.current*E)};const y=l.useCallback(()=>{var E;return(E=h.current)==null?void 0:E.call(h)},[]);l.useEffect(()=>(r?y():b(),b),[r,y,b]);const v=l.useCallback(E=>{b(),n(E),u.current&&y()},[b,y]),{start:m,stop:g}=pa(),[x,w]=l.useState("idle"),[$,R]=l.useState(null),[U,V]=l.useState([]),[X,ie]=l.useState([]),[me,Ke]=l.useState(()=>xe()),[le,Te]=l.useState(!1),Q=l.useRef("idle"),I=l.useRef(!1),Je=l.useCallback(()=>Ke(xe()),[]),Me=l.useRef(null),on=l.useCallback(()=>{var O;I.current=!1;const E=Q.current;(E==="listening"||E==="acquiring")&&g().catch(()=>{}),(O=Me.current)==null||O.abort(),Me.current=null,w("idle"),R(null),n("idle"),y()},[y,g]);l.useEffect(()=>{la().then(E=>{(E==null?void 0:E.backendMode)==="hermes"&&Te(!0)}).catch(()=>{})},[]),l.useEffect(()=>{Q.current=x},[x]);const gt=(E,O,_,P,ae)=>{const K={id:crypto.randomUUID(),role:E,text:O,audioBase64:_,audioMime:P,toolCalls:ae};return V(Ae=>[...Ae.slice(-29),K]),K},qe=l.useCallback(async()=>{if(!(I.current||Q.current!=="idle")){I.current=!0,b(),w("acquiring"),R({type:"acquiring",text:"⏳ 麦克风准备中…"});try{await m()}catch(E){console.warn("[PTT] Mic acquisition failed:",E.message),I.current=!1,w("idle"),R({type:"error",text:"⚠ 麦克风不可用"}),setTimeout(()=>R(null),2500),y();return}if(!I.current){g().catch(()=>{}),w("idle"),R(null),y();return}n("listening"),w("listening"),R({type:"listening",text:"🎙 请讲话 · 松开结束"})}},[b,m,g,y]),ce=l.useCallback(async()=>{var wt;if(!I.current)return;if(I.current=!1,Q.current==="acquiring"){w("idle"),R(null),y();return}if(Q.current!=="listening")return;w("thinking"),n("thinking"),R({type:"thinking",text:"⚙ 识别中…"});const{transcript:E,audioBase64:O,mimeType:_}=await g();let P="";if(O)try{R({type:"thinking",text:"⚙ 识别中…"});const{text:A}=await ua(O,_||"audio/webm");P=(A==null?void 0:A.trim())||""}catch(A){console.warn("[ASR] Volcengine failed, using browser transcript:",A.message)}if(P||(P=E.trim()),!P){w("idle"),n("idle"),R(null);return}gt("user",P,O,_),R({type:"thinking",text:"⚙ 思考中…"});const ae=new AbortController;Me.current=ae;let K="",Ae=[];try{const A=le?[]:xe().map(un=>un.text),ge=ke(),$e=[...X,{role:"user",content:P}],xt=await ca($e.slice(-10),A,ge,ae.signal);K=xt.text,Ae=xt.toolCalls||[],ie([...$e,{role:"assistant",content:K}].slice(-20))}catch(A){if(A.name==="AbortError"){w("idle"),n("idle"),R(null),y();return}K=A.message.includes("Cannot connect to Hermes")?`⚠ Hermes Agent 无法连接,请检查 ${((wt=A.message.match(/at (.+?) —/))==null?void 0:wt[1])??"地址"} 是否在线`:`对话出错: ${A.message}`}if(ae.signal.aborted){w("idle"),n("idle"),R(null),y();return}n("thinking"),w("speaking"),R({type:"tts",text:"🔊 生成语音中…"});const ln=ka(),bt=Ma(K);let pe=null,vt=!1;try{const{audioBase64:A}=await da(bt,ln);pe=A}catch(A){console.warn("[TTS] Volcengine unavailable, using browser TTS:",A.message),vt=!0}R({type:"speaking",text:vt?"🔊 播放中… (浏览器语音)":"🔊 播放中…"}),gt("bot",K,pe,"audio/mp3",Ae),ba({userText:P,botText:K,userAudioBase64:O,userAudioMime:_,botAudioBase64:pe,botAudioMime:"audio/mp3"}),le||ha(P,K).then(A=>{let ge=!1;A.forEach($e=>{aa($e)&&(ge=!0)}),ge&&Je()}).catch(()=>{}),ae.signal.aborted||(n("speaking"),pe?(R({type:"speaking",text:"🔊 播放中…"}),await Ca(pe,"audio/mp3")):(R({type:"speaking",text:"🔊 播放中… (浏览器语音)"}),await Ta(bt))),Me.current=null,w("idle"),R(null);const cn=be[Math.floor(Math.random()*be.length)];n(cn),y()},[g,X,y,le,Je]);l.useEffect(()=>{function E(_){if(!(_.target.tagName==="INPUT"||_.target.tagName==="TEXTAREA")){if(_.code==="Space"&&!_.repeat){_.preventDefault(),qe();return}if(Q.current==="idle"){const P=Na[_.key.toLowerCase()];P&&v(P)}}}function O(_){_.code==="Space"&&(_.preventDefault(),ce())}return window.addEventListener("keydown",E),window.addEventListener("keyup",O),()=>{window.removeEventListener("keydown",E),window.removeEventListener("keyup",O)}},[qe,ce,v]),l.useEffect(()=>{const E=()=>ce();return window.addEventListener("mouseup",E),window.addEventListener("touchend",E,{passive:!0}),window.addEventListener("touchcancel",E,{passive:!0}),()=>{window.removeEventListener("mouseup",E),window.removeEventListener("touchend",E),window.removeEventListener("touchcancel",E)}},[ce]);const Ge=l.useRef(null);return l.useEffect(()=>(x==="listening"?Ge.current=setTimeout(()=>{console.warn("[PTT] Auto-stop: max recording time reached"),ce()},6e4):clearTimeout(Ge.current),()=>clearTimeout(Ge.current)),[x,ce]),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(Yr,{expressionId:t,scale:s})}),i.jsx("div",{className:"expr-label",children:(yt=at[t])==null?void 0:yt.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:Sa.map(E=>i.jsx("button",{className:`ebtn${t===E.id?" active":""}`,style:{"--c":E.color},onClick:()=>v(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:ja.map(E=>i.jsx("button",{className:`ebtn${t===E.id?" active":""}`,style:{"--c":E.color},onClick:()=>v(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(ia,{memories:me,onMemoriesChange:Je}),le&&i.jsx("div",{className:"hermes-mode-badge",children:"🧠 Hermes Agent 模式 · 记忆由 Agent 管理"}),i.jsx(na,{messages:U,voiceStatus:$}),i.jsx(Aa,{phase:x,onStart:qe,onEnd:ce,onCancel:on})]})]})]})}function Pt({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 _a({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(Pt,{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(Pt,{base64:e.botAudioBase64,mimeType:"audio/mp3"})]})]})]})}function Ia(){const[e,t]=l.useState(()=>He()),n=Ne(),r=s=>{wa(s),t(He())},a=()=>{window.confirm("确认清空所有历史记录?")&&(va(),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(_a,{entry:s,onDelete:r},s.id))})]})}const Lt={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 Pa(){const e=Ne(),[t,n]=l.useState(()=>ke()),[r,a]=l.useState(Lt),[s,o]=l.useState(!0),[c,d]=l.useState(!1),[u,f]=l.useState({});l.useEffect(()=>{fa().then(m=>{m&&!m.error&&a(g=>({...g,...m}))}).finally(()=>o(!1))},[]);const h=(m,g)=>{n(x=>({...x,[m]:g})),d(!1)},p=(m,g)=>{a(x=>({...x,[m]:g})),d(!1)},b=m=>f(g=>({...g,[m]:!g[m]})),y=async()=>{Ea(t);try{await ma(r),d(!0),setTimeout(()=>d(!1),2e3)}catch(m){alert("API 配置保存失败:"+m.message)}},v=()=>{if(window.confirm("重置所有设置为默认值?")){const m=Ra();n(m),a(Lt),d(!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:y,children:c?"✓ 已保存":"保存"})]}),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:m=>p("volcAppId",m.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:u.volcAccessToken?"text":"password",value:r.volcAccessToken,onChange:m=>p("volcAccessToken",m.target.value),placeholder:"留空则保持不变"}),i.jsx("button",{className:"settings-show-btn",onClick:()=>b("volcAccessToken"),children:u.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:u.openrouterApiKey?"text":"password",value:r.openrouterApiKey,onChange:m=>p("openrouterApiKey",m.target.value),placeholder:"留空则保持不变"}),i.jsx("button",{className:"settings-show-btn",onClick:()=>b("openrouterApiKey"),children:u.openrouterApiKey?"隐藏":"显示"})]})]}),i.jsxs("label",{className:"settings-label",children:["ASR Resource ID",i.jsx("input",{className:"settings-input",value:r.volcAsrResource,onChange:m=>p("volcAsrResource",m.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(m=>i.jsxs("label",{className:"settings-radio-label",children:[i.jsx("input",{type:"radio",name:"backendMode",value:m.value,checked:r.backendMode===m.value,onChange:()=>p("backendMode",m.value)}),m.label]},m.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:m=>p("llmModel",m.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:m=>p("hermesUrl",m.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:u.hermesApiKey?"text":"password",value:r.hermesApiKey,onChange:m=>p("hermesApiKey",m.target.value),placeholder:"留空则不鉴权(局域网内可不填)"}),i.jsx("button",{className:"settings-show-btn",onClick:()=>b("hermesApiKey"),children:u.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:m=>h("robotName",m.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:m=>h("robotPersonality",m.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:m=>h("switchIntervalMs",Number(m.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:m=>h("extraContext",m.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(m=>i.jsxs("label",{className:"settings-radio-label",children:[i.jsx("input",{type:"radio",name:"language",value:m.value,checked:t.language===m.value,onChange:()=>h("language",m.value)}),m.label]},m.value))})]}),i.jsxs("section",{className:"settings-section",children:[i.jsx("h2",{className:"settings-section-title",children:"🔊 语音音色"}),i.jsx("div",{className:"settings-voice-grid",children:xa.map(m=>i.jsxs("button",{className:`settings-voice-btn ${!t.customVoiceId&&t.voiceId===m.id?"active":""}`,onClick:()=>{h("voiceId",m.id),h("customVoiceId","")},children:[i.jsx("span",{className:"voice-btn-label",children:m.label}),i.jsxs("span",{className:"voice-btn-meta",children:[m.lang," · ",m.gender," · ",m.style]})]},m.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:m=>h("customVoiceId",m.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:v,children:"重置为默认设置"})]})]})]})}dn.createRoot(document.getElementById("jbot-root")).render(i.jsx(l.StrictMode,{children:i.jsx(_r,{basename:"/jbot",children:i.jsxs(cr,{children:[i.jsx(Be,{path:"/",element:i.jsx($a,{})}),i.jsx(Be,{path:"/history",element:i.jsx(Ia,{})}),i.jsx(Be,{path:"/settings",element:i.jsx(Pa,{})})]})})}));