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