@szjy/ai-coms 0.1.16 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/images/sikao.svg +20 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +2418 -1235
- package/dist/index.umd.js +7 -3
- package/dist/packages/common/voice/EqualizerBars.vue.d.ts +17 -0
- package/dist/packages/common/voice/VoiceCaptionBar.vue.d.ts +2 -0
- package/dist/packages/common/voice/VoiceMicButton.vue.d.ts +2 -0
- package/dist/packages/common/voice/VoiceOverlay.vue.d.ts +29 -0
- package/dist/packages/common/voice/aec.d.ts +52 -0
- package/dist/packages/common/voice/aec.test.d.ts +1 -0
- package/dist/packages/common/voice/api.d.ts +31 -0
- package/dist/packages/common/voice/api.test.d.ts +1 -0
- package/dist/packages/common/voice/asr.d.ts +20 -0
- package/dist/packages/common/voice/asr.test.d.ts +1 -0
- package/dist/packages/common/voice/constants.d.ts +37 -0
- package/dist/packages/common/voice/index.d.ts +11 -0
- package/dist/packages/common/voice/playback.d.ts +14 -0
- package/dist/packages/common/voice/types.d.ts +86 -0
- package/dist/packages/common/voice/useVoice.d.ts +29 -0
- package/dist/packages/common/voice/useVoice.test.d.ts +1 -0
- package/dist/packages/components/AiChat/src/index.vue.d.ts +37 -0
- package/dist/packages/components/AiChatPlain/src/index.vue.d.ts +37 -0
- package/dist/style.css +2 -2
- package/package.json +6 -2
package/dist/index.umd.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
(function(
|
|
2
|
-
`),
|
|
3
|
-
`)).getReader();console.log("reader from response:",o),r({error:0,reader:o})}else r({error:1,reader:null})}).catch(()=>{r({error:1,reader:null})})}):{error:1,reader:null}}const ge=new Map,ye=new Map;function ke(t,n){ge.set(t,n)}function Pe(t,n){ye.set(t,n)}function Me(t){return ge.get(t)}function je(t){return ge.has(t)}function Ie(t){return ye.get(t)}function Le(t){return ye.has(t)}const xt={"&":"&","<":"<",">":">",'"':""","'":"'"};function X(t){return String(t??"").replace(/[&<>"']/g,n=>xt[n])}function $e(t){const a=we(t,{block:t});return a?`<div class="szjy-ui" data-szjy-ui="1">${a}</div>`:""}function we(t,n){if(!t||typeof t!="object"||typeof t.type!="string")return"";const a=Me(t.type);return a?a(t,n):""}function Fe(t){const n=t.action;if(!n||typeof n!="string")return"";if(!Le(n))return` disabled title="未知动作:${X(n)}"`;const a=t.actionParams===void 0?"":encodeURIComponent(JSON.stringify(t.actionParams??null));return` data-szjy-ui-action="${X(n)}" data-szjy-ui-params="${a}"`}function Ut(t){return typeof t=="number"&&Number.isFinite(t)&&t>=0?`${t}px`:typeof t=="string"&&/^\d+(\.\d+)?(px|rem|em|%)?$/.test(t.trim())?/^\d+(\.\d+)?$/.test(t.trim())?`${t.trim()}px`:t.trim():"12px"}function Bt(t,n){const a=typeof t.title=="string"&&t.title?`<div class="szjy-ui-list__title">${X(t.title)}</div>`:"",s=(Array.isArray(t.items)?t.items:[]).map(i=>we(i,n)).filter(Boolean).map(i=>`<div class="szjy-ui-list__item">${i}</div>`).join(""),o=X(Ut(t.gap));return'<div class="szjy-ui-list">'+a+`<div class="szjy-ui-list__items" style="gap:${o}">${s}</div></div>`}ke("list",Bt);const _t=["default","primary","success","warning","danger","info","text"],zt=["small","default","large"];function Pt(t,n){const a=t.props,r=a&&typeof a=="object"?a:{},s=_t.includes(r.type)?r.type:"default",o=zt.includes(r.size)?r.size:"default",i=X(r.content??r.text??"按钮"),l=Fe(t);return`<button type="button" class="${["szjy-ui-btn",`szjy-ui-btn--${s}`,`szjy-ui-btn--${o}`].join(" ")}"${l}><span class="szjy-ui-btn__text">${i}</span><span class="szjy-ui-btn__status" aria-live="polite"></span></button>`}ke("button",Pt);const Mt=15e3,Oe=/未就绪|未加载/,jt="BIM_SANDBOX",It={locateComponent:t=>[t==null?void 0:t.wbsCode],openPDFSearch:()=>[]};let Lt=0;function $t(t,n){let a;if(!t||t==="self")a=[window];else if(t==="parent")a=[window.parent];else if(t==="top")a=[window.top];else if(typeof t=="function")try{a=t(n)}catch(o){console.error("[szjy-ui] 解析 postMessage 目标窗口失败:",o),a=[]}else Array.isArray(t)?a=t:a=[t];const r=[],s=o=>{if(o){if(Array.isArray(o)){o.forEach(s);return}typeof o.postMessage=="function"&&!r.includes(o)&&r.push(o)}};return s(a),r}function Q(t){if(t===window)return`self (${location.origin})`;if(t===window.parent)return"parent";if(t===window.top)return"top";try{return`window (${t.location.href.slice(0,60)})`}catch{return"window (cross-origin)"}}function Ft(t){try{const n=t.$bimSandbox;return n&&typeof n=="object"?n:null}catch{return null}}function Ot(t,n,a){if(n.type!==jt)return{handled:!1};const r=It[n.action];if(!r)return{handled:!1};const s=Ft(t);if(!s||typeof s[n.action]!="function")return{handled:!1};const o=r(n.payload);let i;try{i=s[n.action](...o)}catch(l){return console.error("[szjy-ui] $bimSandbox 方法调用异常,回退 postMessage:",l),{handled:!1}}return a&&console.log("[szjy-ui] $bimSandbox 直调",{method:n.action,args:o,result:i,target:Q(t)}),{handled:!0,result:i}}function De(t,n,a,r,s,o,i){return(()=>{const{handled:c,result:u}=Ot(t,n,i);return c?(u&&u.success?o&&F(a,"success",u.message||"执行成功"):u&&Oe.test(String(u.message||""))&&r>0?(i&&console.warn(`[szjy-ui] $bimSandbox 直调失败(${u.message}),${s}ms 后自动重试,剩余 ${r-1} 次`),o&&F(a,"retrying",`${u.message},${Math.round(s/1e3)}s 后自动重试`),setTimeout(()=>{De(t,n,a,r-1,s,o,i)},s)):o&&F(a,"error",u&&u.message||"执行失败"),!0):!1})()}function Dt(t){const n=Ht(t.config),a=!t.config||t.config.debug!==!1,r=n.feedback!==!1,s=n.retry===!1?{retries:0,delay:2e3}:{retries:2,delay:2e3,...n.retry||{}};if(!t.params||typeof t.params!="object"||Array.isArray(t.params)){console.warn("[szjy-ui] postMessage 动作的 actionParams 必须是对象:",t.params),F(t.triggerEl,"error","参数无效");return}const o={...t.params},i=$t(n.target,o);if(!i.length){console.warn("[szjy-ui] postMessage 无可用目标窗口,target 配置:",n.target),F(t.triggerEl,"error","无目标窗口");return}const l=n.targetOrigin||"*",c=n.transport||"auto";if(c!=="postMessage"){let u=!1;for(const S of i)if(De(S,o,t.triggerEl,s.retries,s.delay,r,a)){u=!0;break}if(u)return;if(c==="global"){console.warn("[szjy-ui] transport=global 但 $bimSandbox 全局方法不可用:",{targets:i.map(Q),message:o}),F(t.triggerEl,"error","全局方法不可用");return}a&&console.log("[szjy-ui] $bimSandbox 不可用,回退 postMessage 通道")}o.requestId===void 0&&(o.requestId=`szjy-ui-${Date.now()}-${++Lt}`),He(i,o,l),a&&console.log("[szjy-ui] postMessage 已发送",{message:o,targets:i.map(Q),targetOrigin:l,feedback:r}),r&&(F(t.triggerEl,"loading","已发送"),qt(o,i,t.triggerEl,l,s,a))}function Ht(t){return t&&t.postMessage||{}}function He(t,n,a){t.forEach(r=>{try{r.postMessage(n,a)}catch(s){console.error("[szjy-ui] postMessage 发送失败:",s)}})}function qt(t,n,a,r,s,o){let i=s.retries;const l=s.delay;let c=null;const u=()=>{window.removeEventListener("message",R),c&&(clearTimeout(c),c=null)},S=()=>{c&&clearTimeout(c),c=setTimeout(()=>{u(),o&&console.warn("[szjy-ui] postMessage 超时未收到回执",{message:t,targets:n.map(Q),targetOrigin:r}),F(a,"none","未收到回执")},Mt)},R=v=>{const h=v.data;!h||typeof h!="object"||t.type!==void 0&&h.type!==t.type||h.success!==void 0&&(t.requestId!==void 0&&h.requestId!==void 0&&String(h.requestId)!==String(t.requestId)||v.source&&!n.includes(v.source)||(o&&console.log("[szjy-ui] postMessage 收到回执",{requestId:h.requestId,success:h.success,message:h.message,data:h.data,from:Q(v.source)}),h.success?(u(),F(a,"success",h.message||"执行成功")):Oe.test(String(h.message||""))&&i>0?(i-=1,o&&console.warn(`[szjy-ui] postMessage 回执失败(${h.message}),${l}ms 后自动重试,剩余 ${i} 次`),F(a,"retrying",`${h.message},${Math.round(l/1e3)}s 后自动重试`),c&&clearTimeout(c),setTimeout(()=>{He(n,t,r),o&&console.log("[szjy-ui] postMessage 重试已发送",{message:t,targets:n.map(Q),targetOrigin:r}),F(a,"loading","已发送"),S()},l)):(u(),F(a,"error",h.message||"执行失败"))))};window.addEventListener("message",R),S()}function F(t,n,a){if(!t||!t.isConnected)return;const r=t.querySelector(":scope > .szjy-ui-btn__status");t.classList.remove("is-loading","is-success","is-error","is-retrying"),n&&n!=="none"&&t.classList.add(`is-${n}`),r&&(r.textContent=a||"")}Pe("postMessage",Dt);const qe="szjy-ui";function We(t){if(!t||typeof t!="string")return null;const n=t.trim();if(!n.startsWith("{"))return null;let a;try{a=JSON.parse(n)}catch{return null}return Wt(a)}function Wt(t){return!t||typeof t!="object"||Array.isArray(t)||typeof t.type!="string"||!je(t.type)||t.items!==void 0&&!Array.isArray(t.items)?null:t}function Ge(t,n={}){if(!t)return()=>{};const a=r=>{var v;const s=r.target,o=s&&typeof s.closest=="function"?s.closest("[data-szjy-ui-action]"):null;if(!o||!t.contains(o))return;const i=o.getAttribute("data-szjy-ui-action")||"",l=Ie(i);if(!l){console.warn(`[szjy-ui] 未注册的动作: ${i}`);return}const c=o.getAttribute("data-szjy-ui-params");let u=null;if(c)try{u=JSON.parse(decodeURIComponent(c))}catch(h){console.error("[szjy-ui] actionParams 解析失败:",h);return}const S=n.getConfig?n.getConfig():null;if(!S||S.debug!==!1){const h=(v=o.querySelector(":scope > .szjy-ui-btn__text"))==null?void 0:v.textContent;console.log("[szjy-ui] 动作触发",{action:i,params:u,text:(h||o.textContent||"").trim().slice(0,40),trigger:o})}const R=n.getInterceptor?n.getInterceptor():null;if(!(R&&R(i,u,o)===!1)){if(n.onAction)try{n.onAction({action:i,params:u,triggerEl:o})}catch(h){console.error("[szjy-ui] onAction 回调执行失败:",h)}l({params:u,config:S,triggerEl:o})}};return t.addEventListener("click",a),()=>{t.removeEventListener("click",a)}}let D=null;function Gt(){return D||(window.markdownit?(D=new window.markdownit({html:!0,linkify:!0,typographer:!0}),D.renderer.rules.fence=(t,n)=>{const a=t[n],r=(a.info||"").trim().split(/\s+/)[0];if(r===qe){const o=We(a.content),i=o?$e(o):"";if(i)return i}let s="";if(r&&window.hljs&&window.hljs.getLanguage(r))try{s=window.hljs.highlight(a.content,{language:r}).value}catch{s=""}return s||(s=D.utils.escapeHtml(a.content)),`<pre class="md-code-block"><code class="hljs${r?" language-"+r:""}">${s}</code></pre>`}):console.log("markdownit is not loaded"),D)}const Jt=(t,n)=>{const a=t.__vccOpts||t;for(const[r,s]of n)a[r]=s;return a},Kt=["src","alt"],ue=Jt({__name:"SvgIcon",props:{name:{type:String,required:!0},size:{type:[Number,String],default:16},color:{type:String,default:""},className:{type:String,default:""},basePath:{type:String,default:"/icons/"}},setup(t){const n=t,a=e.computed(()=>{if(n.name.startsWith("http://")||n.name.startsWith("https://")||n.name.startsWith("/"))return n.name;const o=n.name.endsWith(".svg")?n.name:`${n.name}.svg`;return`${n.basePath}${o}`}),r=e.computed(()=>{const o=typeof n.size=="number"?`${n.size}px`:n.size;return{width:o,height:o,display:"inline-flex",justifyContent:"center",alignItems:"center"}}),s=e.computed(()=>{const o={width:"100%",height:"100%"};return n.color&&(o.filter=`drop-shadow(0 0 0 ${n.color})`),o});return(o,i)=>(e.openBlock(),e.createElementBlock("div",{class:"svg-icon-wrapper",style:e.normalizeStyle(r.value)},[e.createElementVNode("img",{src:a.value,alt:t.name,class:e.normalizeClass(["svg-icon",t.className]),style:e.normalizeStyle(s.value)},null,14,Kt)],4))}},[["__scopeId","data-v-490b11c1"]]),Yt=async t=>{if(navigator.clipboard&&navigator.permissions)await navigator.clipboard.writeText(t);else{const n=document.createElement("textArea");n.value=t,n.style.width=0,n.style.position="fixed",n.style.left="-999px",n.style.top="10px",n.setAttribute("readonly","readonly"),document.body.appendChild(n),n.select(),document.execCommand("copy"),document.body.removeChild(n)}},Zt={class:"thinking-title"},Xt={class:"thinking-toggle-hint"},Qt=["innerHTML"],en=["innerHTML"],tn=10,nn={__name:"Previewer",props:{reader:null,model:"szjy",scrollToBottomFn:null,displayText:"",messagePostRender:{type:Function,default:null},customUi:{type:Object,default:null},uiActionHandler:{type:Function,default:null}},emits:["failed","completed","updating","ui-action"],setup(t,{expose:n,emit:a}){const{appContext:r}=e.getCurrentInstance(),{$message:s}=r.config.globalProperties,o=t,i=e.ref(o.displayText||""),l=e.ref(!0),c=e.ref(!1),u=e.ref(!!o.displayText),S=a,R=e.ref(null);let v=null;e.watch(R,B=>{v&&(v(),v=null),B&&(v=Ge(B,{getConfig:()=>o.customUi,getInterceptor:()=>o.uiActionHandler,onAction:T=>S("ui-action",T)}))});let h=null;const M=e.computed(()=>Tt(i.value)),A=e.computed(()=>M.value.thinking.length>0),_=e.ref(o.displayText?M.value.content.length:0),k=e.computed(()=>M.value.isThinkingStreaming&&!u.value),p=e.ref(!1),w=()=>{p.value=!p.value};let f=null,d=null;const C=e.ref(0);e.watch(()=>M.value.thinking,B=>{!B||C.value>0||(d===null&&(d=f??Date.now()),M.value.content&&E())});const E=()=>{if(C.value>0||!A.value)return;const B=d??f;B&&(C.value=Math.max(1,Math.round((Date.now()-B)/1e3)))},z=e.computed(()=>k.value?"正在思考...":C.value>0?`已深度思考(用时 ${C.value} 秒)`:"思考过程"),N=e.computed(()=>A.value?D?D.render(M.value.thinking):M.value.thinking:""),x=e.computed(()=>M.value.content.slice(0,_.value)),b=e.computed(()=>D?D.render(x.value):x.value),P=()=>{o.reader&&o.reader.cancel(),c.value=!0,$.value=!1,K(),u.value=!0,E(),S("completed",i.value),l.value=!1,h&&(cancelAnimationFrame(h),h=null)},H=e.computed(()=>`${b.value}`),q=e.ref(!1),W=()=>{q.value=!0},K=()=>{q.value=!1},$=e.ref(!1),te=async()=>{if(!o.reader)return;const B=new TextDecoder("utf-8");for(l.value=!0;!c.value;)try{if(!o.reader){$.value=!0;break}const{value:T,done:I}=await o.reader.read();if(!o.reader){$.value=!0;break}if(I){$.value=!0;break}const oe=_e[o.model];if(!oe)break;const O=oe.call(_e,T,B);if(O.done){$.value=!0;break}!f&&O.content&&(f=Date.now()),i.value+=O.content,h===null&&ne()}catch(T){$.value=!0,console.log(3333,T),S("failed",T),P();break}finally{K()}},ie=async()=>{o.scrollToBottomFn&&o.scrollToBottomFn()},me=(B=()=>{},T=()=>{})=>{const I=M.value.content.length;_.value>I&&(_.value=I),_.value<I?(_.value=Math.min(I,_.value+tn),B()):T()},ne=()=>{if(c.value&&h){cancelAnimationFrame(h),h=null,l.value=!1;return}$.value?me(()=>{h=requestAnimationFrame(ne),S("updating",null)},()=>{E(),S("completed",i.value),l.value=!1,u.value=!0,e.nextTick(()=>{if($.value=!1,o.messagePostRender&&R.value)try{o.messagePostRender(R.value,M.value.content)}catch(B){console.error("messagePostRender 执行失败:",B)}}),h=null}):(me(),h=requestAnimationFrame(ne)),ie()};e.watch(()=>o.reader,()=>{o.reader&&te()},{immediate:!0,deep:!0}),e.onUnmounted(()=>{v&&(v(),v=null),P()}),n({abortReader:P,initializeStart:W,initializeEnd:K}),e.computed(()=>q.value?!0:(!o.reader||!l||i.value,!1));const ve=async()=>{try{const B=M.value.content||i.value;await Yt(B),s.success("复制成功")}catch(B){console.error("复制失败:",B),s.error("复制失败")}};return(B,T)=>(e.openBlock(),e.createBlock(e.Transition,{name:"fade"},{default:e.withCtx(()=>[H.value||A.value?(e.openBlock(),e.createElementBlock("div",{key:0,ref_key:"refWrapperContent",ref:R,"text-16":"",class:"w-full h-full overflow-y-auto relative","p-24px":""},[A.value?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["ai-thinking-block",{"is-expanded":p.value||k.value,"is-streaming":k.value}])},[e.createElementVNode("div",{class:"thinking-header",onClick:w},[T[0]||(T[0]=e.createElementVNode("svg",{class:"thinking-arrow",viewBox:"0 0 1024 1024",width:"10",height:"10"},[e.createElementVNode("path",{d:"M704 512 320 256v512z",fill:"currentColor"})],-1)),e.createElementVNode("span",Zt,e.toDisplayString(z.value),1),e.createElementVNode("span",Xt,e.toDisplayString(p.value||k.value?"收起":"展开"),1)]),e.withDirectives(e.createElementVNode("div",{class:"thinking-body",innerHTML:N.value},null,8,Qt),[[e.vShow,p.value||k.value]])],2)):e.createCommentVNode("",!0),e.createElementVNode("div",{class:"markdown-wrapper",innerHTML:H.value},null,8,en),u.value?(e.openBlock(),e.createElementBlock("div",{key:1,class:"ai-copy-btn-wrapper",onClick:ve},[e.createVNode(ue,{name:"/images/svg/copy.svg",color:"#666666"}),T[1]||(T[1]=e.createElementVNode("span",{class:"copy-text"},"复制",-1))])):e.createCommentVNode("",!0)],512)):e.createCommentVNode("",!0)]),_:1}))}};class Je{constructor(n,a){V(this,"ratio");V(this,"leftover",new Float32Array(0));V(this,"fracOffset",0);this.ratio=n/a}reset(){this.leftover=new Float32Array(0),this.fracOffset=0}process(n){if(this.ratio===1)return new Float32Array(n);const a=new Float32Array(this.leftover.length+n.length);if(a.set(this.leftover),a.set(n,this.leftover.length),a.length<2)return this.leftover=a,new Float32Array(0);const r=[];let s=this.fracOffset;for(;s<a.length-1;){const i=Math.floor(s),l=s-i,c=a[i],u=a[i+1];r.push(c+l*(u-c)),s+=this.ratio}const o=Math.min(a.length,Math.floor(s));return this.leftover=a.slice(o),this.fracOffset=s-o,Float32Array.from(r)}}class Ke{constructor(n={}){V(this,"targetSampleRate");V(this,"audioContext",null);V(this,"mediaStream",null);V(this,"sourceNode",null);V(this,"processorNode",null);V(this,"muteGain",null);V(this,"resampler",null);V(this,"audioChunks",[]);V(this,"onVolumeChange");V(this,"onAudioChunk");V(this,"_isRecording",!1);this.targetSampleRate=n.sampleRate||16e3,this.onVolumeChange=n.onVolumeChange,this.onAudioChunk=n.onAudioChunk}get isRecording(){return this._isRecording}async start(){if(this._isRecording)return;if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia)throw new Error("当前浏览器环境不支持获取麦克风音频,请使用现代浏览器并确保在 HTTPS/localhost 环境下运行。");try{this.mediaStream=await navigator.mediaDevices.getUserMedia({audio:{channelCount:{ideal:1},sampleRate:{ideal:this.targetSampleRate},echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0}})}catch(r){throw r.name==="NotAllowedError"||r.name==="PermissionDeniedError"?new Error("麦克风权限被拒绝,请在浏览器地址栏允许麦克风访问权限。"):r.name==="NotFoundError"||r.name==="DevicesNotFoundError"?new Error("未检测到可用的麦克风输入设备。"):new Error(`无法启动麦克风: ${r.message||r}`)}const n=window.AudioContext||window.webkitAudioContext;try{this.audioContext=new n({sampleRate:this.targetSampleRate})}catch{this.audioContext=new n}this.audioContext.state==="suspended"&&await this.audioContext.resume(),this.audioChunks=[],this.resampler=this.audioContext.sampleRate===this.targetSampleRate?null:new Je(this.audioContext.sampleRate,this.targetSampleRate),this.sourceNode=this.audioContext.createMediaStreamSource(this.mediaStream);const a=4096;this.processorNode=this.audioContext.createScriptProcessor(a,1,1),this.processorNode.onaudioprocess=r=>{var i;if(!this._isRecording)return;const s=new Float32Array(r.inputBuffer.getChannelData(0));if(this.onVolumeChange){let l=0;for(let S=0;S<s.length;S++)l+=s[S]*s[S];const c=Math.sqrt(l/s.length),u=Math.min(100,Math.round(c*100*5));this.onVolumeChange(u)}const o=this.resampler?this.resampler.process(s):s;o.length&&(this.audioChunks.push(o),(i=this.onAudioChunk)==null||i.call(this,o))},this.muteGain=this.audioContext.createGain(),this.muteGain.gain.value=0,this.sourceNode.connect(this.processorNode),this.processorNode.connect(this.muteGain),this.muteGain.connect(this.audioContext.destination),this._isRecording=!0}async stop(){if(!this._isRecording)return new Float32Array(0);this._isRecording=!1,this.cleanup();const n=this.audioChunks.reduce((s,o)=>s+o.length,0),a=new Float32Array(n);let r=0;for(const s of this.audioChunks)a.set(s,r),r+=s.length;return this.audioChunks=[],a}cancel(){this._isRecording=!1,this.audioChunks=[],this.cleanup()}cleanup(){this.processorNode&&(this.processorNode.disconnect(),this.processorNode.onaudioprocess=null,this.processorNode=null),this.muteGain&&(this.muteGain.disconnect(),this.muteGain=null),this.sourceNode&&(this.sourceNode.disconnect(),this.sourceNode=null),this.resampler=null,this.mediaStream&&(this.mediaStream.getTracks().forEach(n=>n.stop()),this.mediaStream=null),this.audioContext&&this.audioContext.state!=="closed"&&(this.audioContext.close().catch(()=>{}),this.audioContext=null)}}function Ye(t,n,a){if(n===a)return new Float32Array(t);const r=n/a,s=Math.round(t.length/r),o=new Float32Array(s);for(let i=0;i<s;i++){const l=i*r,c=Math.floor(l),u=l-c,S=t[c]??0,R=t[c+1]??S;o[i]=S+u*(R-S)}return o}async function Ze(t,n=16e3){const a=await t.arrayBuffer(),r=window.AudioContext||window.webkitAudioContext,s=new r;try{const o=await s.decodeAudioData(a);let i;if(o.numberOfChannels>1){i=new Float32Array(o.length);for(let l=0;l<o.numberOfChannels;l++){const c=o.getChannelData(l);for(let u=0;u<o.length;u++)i[u]+=c[u]/o.numberOfChannels}}else i=o.getChannelData(0);return Ye(i,o.sampleRate,n)}finally{s.state!=="closed"&&await s.close().catch(()=>{})}}function be(t,n=16e3){const a=new ArrayBuffer(44+t.length*2),r=new DataView(a),s=(i,l)=>{for(let c=0;c<l.length;c++)r.setUint8(i+c,l.charCodeAt(c))};s(0,"RIFF"),r.setUint32(4,36+t.length*2,!0),s(8,"WAVE"),s(12,"fmt "),r.setUint32(16,16,!0),r.setUint16(20,1,!0),r.setUint16(22,1,!0),r.setUint32(24,n,!0),r.setUint32(28,n*2,!0),r.setUint16(32,2,!0),r.setUint16(34,16,!0),s(36,"data"),r.setUint32(40,t.length*2,!0);let o=44;for(let i=0;i<t.length;i++,o+=2){const l=Math.max(-1,Math.min(1,t[i]));r.setInt16(o,l<0?l*32768:l*32767,!0)}return new Blob([r],{type:"audio/wav"})}const Xe=16e3,on=Math.round(Xe*.35),Se="/scripts/ai/whisper.worker.js";function rn(){return new Worker(Ce(Se),{type:"module"})}function Ce(t){return/^https?:\/\//i.test(t)?t:typeof location<"u"?new URL(t,location.origin).href:t}function Qe(t){if(!t.ok)return!1;const n=(t.headers.get("content-type")||"").toLowerCase();return!(n.includes("text/html")||n.includes("application/xhtml+xml"))}async function an(t){try{const n=await fetch(t,{method:"HEAD"});if(Qe(n))return!0}catch{}try{const n=await fetch(t,{headers:{Range:"bytes=0-64"}});if(Qe(n))return!0}catch{}return!1}async function sn(t){const n=[];t&&n.push(Ce(t)),n.push(Ce(Se));const a=[...new Set(n.filter(Boolean))];for(const r of a)if(await an(r))return console.log("[VoiceInputManager] 使用语音 Worker:",r),r;return console.warn("[VoiceInputManager] 未探测到可访问的 Worker 脚本,将回退到 Vite 打包注入地址。已尝试:",a.join(" , ")),null}class et{constructor(n={}){V(this,"recorder",null);V(this,"worker",null);V(this,"status","idle");V(this,"options");V(this,"isReady",!1);V(this,"initPromise",null);V(this,"currentTaskId",0);V(this,"pcmParts",[]);V(this,"pcmLength",0);V(this,"streamChunkIndex",0);V(this,"committedText","");this.options={soundBaseUrl:"/sounds/",remoteHost:"https://hf-mirror.com",modelId:"onnx-community/whisper-base",language:"chinese",...n}}get currentStatus(){return this.status}get ready(){return this.isReady}async init(n){if(!this.isReady)return this.initPromise?this.initPromise:(n&&(this.options.soundBaseUrl=n),this.initPromise=new Promise((a,r)=>{this.setStatus("loading","正在准备语音识别引擎..."),(async()=>{var o,i;try{const l=await sn(this.options.workerUrl);this.worker=l?new Worker(l,{type:"module"}):rn(),this.worker.onmessage=c=>{this.handleWorkerMessage(c,a,r)},this.worker.onerror=c=>{var R,v;const S=`语音后台线程异常: ${c.message||c.filename||l||"未知错误"}`;this.initPromise=null,this.setStatus("error",S),(v=(R=this.options).onError)==null||v.call(R,S),r(c)},this.worker.postMessage({type:"INIT",data:{modelId:this.options.modelId,soundBaseUrl:this.options.soundBaseUrl,remoteHost:this.options.remoteHost}})}catch(l){const c=`创建语音 Worker 失败: ${l.message||l}`;this.initPromise=null,this.setStatus("error",c),(i=(o=this.options).onError)==null||i.call(o,c),r(l)}})()}),this.initPromise)}async startRecording(){var n,a,r,s;if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){const o=window.isSecureContext?"当前浏览器环境不支持获取麦克风音频,请使用现代浏览器。":"当前页面不是安全上下文,浏览器禁止调用麦克风。请使用 https:// 或 http://localhost / http://127.0.0.1 访问(通过局域网 IP 的 http 地址无法录音)。";throw this.setStatus("error",o),(a=(n=this.options).onError)==null||a.call(n,o),new Error(o)}this.isReady||await this.init(),this.recorder||(this.recorder=new Ke({onVolumeChange:o=>{var i,l;(l=(i=this.options).onVolumeChange)==null||l.call(i,o)},onAudioChunk:o=>{this.appendPcm(o)}}));try{this.currentTaskId++,this.resetStreamState(),await this.recorder.start(),this.setStatus("recording","正在录音...")}catch(o){throw this.setStatus("error",o.message||"启动录音失败"),(s=(r=this.options).onError)==null||s.call(r,o.message||"启动录音失败"),o}}async stopAndTranscribe(){var n,a,r,s;if(!(!this.recorder||!this.recorder.isRecording))try{await this.recorder.stop();const o=this.mergePcm();if(o.length===0){this.resetStreamState(),this.setStatus("idle");return}this.setStatus("transcribing","正在识别语音...");try{const i=be(o),l=URL.createObjectURL(i);(a=(n=this.options).onAudioRecorded)==null||a.call(n,l,i)}catch(i){console.warn("生成录音回放音频失败:",i)}await this.transcribeAudioData(o)}catch(o){this.setStatus("error",o.message||"音频处理失败"),(s=(r=this.options).onError)==null||s.call(r,o.message||"音频处理失败")}}async transcribeAudioData(n,a){var r,s,o,i;this.isReady||await this.init(),this.setStatus("transcribing","正在流式识别音频...");try{a&&((s=(r=this.options).onAudioRecorded)==null||s.call(r,a,be(n))),this.currentTaskId++,this.resetStreamState(),this.appendPcm(n),this.dispatchFullAudio()}catch(l){this.setStatus("error",l.message||"音频处理失败"),(i=(o=this.options).onError)==null||i.call(o,l.message||"音频处理失败")}}async transcribeFile(n){var a,r;this.isReady||await this.init(),this.setStatus("loading","正在解析音频文件...");try{const s=await Ze(n);if(s.length===0)throw new Error("未能从该文件中提取出有效音频");const o=URL.createObjectURL(n);await this.transcribeAudioData(s,o)}catch(s){this.setStatus("error",s.message||"音频文件解析失败"),(r=(a=this.options).onError)==null||r.call(a,s.message||"音频文件解析失败")}}cancelRecording(){var a;const n=this.currentTaskId;this.currentTaskId++,(a=this.worker)==null||a.postMessage({type:"CANCEL",taskId:n}),this.resetStreamState(),this.recorder&&this.recorder.cancel(),this.setStatus("idle")}cancelTranscribe(){var a;const n=this.currentTaskId;this.currentTaskId++,(a=this.worker)==null||a.postMessage({type:"CANCEL",taskId:n}),this.resetStreamState(),(this.status==="transcribing"||this.status==="recording")&&this.setStatus("idle")}async clearCache(){this.worker&&(this.worker.postMessage({type:"CLEAR_CACHE"}),this.isReady=!1,this.initPromise=null)}destroy(){var a;const n=this.currentTaskId;this.currentTaskId++,(a=this.worker)==null||a.postMessage({type:"CANCEL",taskId:n}),this.resetStreamState(),this.recorder&&(this.recorder.cancel(),this.recorder=null),this.worker&&(this.worker.terminate(),this.worker=null),this.isReady=!1,this.initPromise=null,this.setStatus("idle")}resetStreamState(){this.pcmParts=[],this.pcmLength=0,this.streamChunkIndex=0,this.committedText=""}appendPcm(n){!n||n.length===0||(this.pcmParts.push(new Float32Array(n)),this.pcmLength+=n.length)}mergePcm(){const n=new Float32Array(this.pcmLength);let a=0;for(const r of this.pcmParts)n.set(r,a),a+=r.length;return n}emitPartial(n){var a,r;(r=(a=this.options).onPartial)==null||r.call(a,(n||"").trim())}finishStream(n){var r,s;const a=(n??this.committedText).trim();this.setStatus("idle"),(s=(r=this.options).onResult)==null||s.call(r,a)}dispatchFullAudio(){if(!this.worker){this.finishStream();return}if(this.pcmLength<on){this.finishStream();return}const n=this.mergePcm(),a=n.length>Xe*30;this.committedText="",this.worker.postMessage({type:"TRANSCRIBE",data:{taskId:this.currentTaskId,audio:n,language:this.options.language,stream:!0,chunkIndex:this.streamChunkIndex++,isFinal:!0,mode:"append",nativeChunking:a}},[n.buffer])}handleWorkerMessage(n,a,r){var u,S,R,v;const{type:s,data:o,taskId:i,text:l,error:c}=n.data;switch(s){case"READY":this.isReady=!0,this.setStatus("ready","语音引擎就绪"),a==null||a();break;case"PROGRESS":if(o){const h=typeof o.progress=="number"?Math.round(o.progress):0;this.setStatus("downloading",`正在下载语音模型... ${h}%`),(S=(u=this.options).onProgress)==null||S.call(u,{status:o.status||"progress",progress:h,file:o.file,loaded:o.loaded,total:o.total})}break;case"TRANSCRIBING":if(i&&i!==this.currentTaskId)return;this.status!=="recording"&&this.setStatus("transcribing","正在流式转写文字...");break;case"PARTIAL":if(i&&i!==this.currentTaskId)return;this.committedText=l||"",this.emitPartial(this.committedText);break;case"RESULT":if(i&&i!==this.currentTaskId)return;this.committedText=(l||"").trim()||this.committedText,this.emitPartial(this.committedText),this.finishStream(this.committedText);break;case"CACHE_CLEARED":this.setStatus("idle","语音模型缓存已清空");break;case"ERROR":if(i&&i!==this.currentTaskId)return;this.setStatus("error",c||"语音服务异常"),(v=(R=this.options).onError)==null||v.call(R,c||"语音服务异常"),r==null||r(new Error(c));break}}setStatus(n,a){var r,s;this.status=n,(s=(r=this.options).onStatusChange)==null||s.call(r,n,a)}}const ln={class:"panel-header"},cn={class:"header-actions"},un={class:"header-title"},dn={class:"action-icons"},fn={class:"body-content"},mn={key:0,class:"welcome-content"},hn={class:"subtitle"},pn={class:"highlight"},gn={class:"quick-questions"},yn=["onClick"],kn={key:1,class:"message-content user-content"},wn={class:"panel-footer"},bn={key:0,src:ht,alt:"加载中",class:"loading-icon"},Sn={key:0,class:"voice-progress-banner"},Cn={class:"progress-info"},En={class:"progress-text"},vn={key:0,class:"progress-percent"},Nn={key:0,class:"progress-track"},An={class:"recording-main"},Tn={class:"recording-status"},Rn={key:0,class:"recording-time"},Vn={class:"recording-hint"},xn={key:1,class:"volume-waves"},Un={class:"recording-actions"},Bn=["title"],_n={key:0,class:"voice-playback-bar"},zn=["title"],Pn={class:"playback-play-icon"},Mn={key:0,viewBox:"0 0 24 24",width:"14",height:"14",fill:"currentColor"},jn={key:1,viewBox:"0 0 24 24",width:"14",height:"14",fill:"currentColor"},In={class:"playback-title"},Ln={key:0,class:"playback-time"},$n={key:1,class:"playback-waves"},Fn={class:"input-box"},On={class:"input-actions-box"},Dn=["src"],tt={__name:"ChatPanel",props:{modelValue:{type:Boolean,default:!1},token:{type:String,default:""},identifier:{type:String,default:""},baseUrl:{type:String,default:""},title:{type:String,default:"数智AI助理"},llmName:{type:String,default:"szjy"},messagePostRender:{type:Function,default:null},extraConfig:{type:Object,default:()=>({})},soundBaseUrl:{type:String,default:"/sounds/"},workerUrl:{type:String,default:""},enableVoiceInput:{type:Boolean,default:!1},enableVoiceUpload:{type:Boolean,default:!1},embedded:{type:Boolean,default:!1},customUi:{type:Object,default:null},uiActionHandler:{type:Function,default:null},mockResponse:{type:String,default:""}},emits:["update:modelValue","submit","ui-action"],setup(t,{emit:n}){const{appContext:a}=e.getCurrentInstance(),{$message:r}=a.config.globalProperties,s=t;let o=null;const i=e.ref("idle"),l=e.ref(""),c=e.ref(0),u=e.ref(0),S=e.ref(0);let R=null;const v=e.ref(""),h=e.ref(!1),M=e.ref(0);let A=null;const _=e.ref(""),k=e.ref(""),p=e.computed(()=>i.value==="downloading"),w=e.computed(()=>i.value==="loading"),f=e.computed(()=>i.value==="recording"),d=e.computed(()=>i.value==="transcribing"),C=e.computed(()=>f.value?"正在录音,点击完成后开始识别":_.value?"正在流式转写...":"正在识别语音中..."),E=e.computed(()=>s.enableVoiceInput?"请输入您的问题或点击麦克风语音输入":s.enableVoiceUpload?"请输入您的问题或上传音频识别":"请输入您的问题"),z=(g,m)=>{const U=(g||"").trim(),j=(m||"").trim();return j?U?/[A-Za-z0-9]$/.test(U)&&/[A-Za-z0-9]/.test(j.charAt(0))?`${U} ${j}`:`${U}${j}`:j:U},N=g=>{const m=Math.floor(g/60),U=g%60;return`${m.toString().padStart(2,"0")}:${U.toString().padStart(2,"0")}`},x=()=>(o||(o=new et({soundBaseUrl:s.soundBaseUrl||"/sounds/",workerUrl:s.workerUrl||void 0,onStatusChange:(g,m)=>{i.value=g,m&&(l.value=m)},onProgress:g=>{typeof g.progress=="number"&&(c.value=g.progress)},onVolumeChange:g=>{u.value=g},onAudioRecorded:g=>{v.value&&URL.revokeObjectURL(v.value),v.value=g,M.value=S.value},onPartial:g=>{_.value=g||"",T.value=z(k.value,g)},onResult:g=>{_.value=g||"",T.value=z(k.value,g),g?r.success("语音识别完成"):r.warning("未能识别出有效语音,请重试"),setTimeout(()=>{_.value="",I.value&&I.value.focus()},100)},onError:g=>{r.error(g||"语音输入服务出错"),P()}})),o),b=()=>{P(),S.value=0,R=setInterval(()=>{S.value+=1},1e3)},P=()=>{R&&(clearInterval(R),R=null)},H=async()=>{if(!s.enableVoiceInput)return;if(f.value){await q();return}h.value&&A&&(A.pause(),h.value=!1);const g=x();try{k.value=T.value,_.value="",b(),await g.startRecording()}catch(m){P(),console.error("启动录音失败:",m)}},q=async()=>{P(),o&&await o.stopAndTranscribe()},W=e.ref(null),K=()=>{s.enableVoiceUpload&&W.value&&(W.value.value="",W.value.click())},$=async g=>{var J;if(!s.enableVoiceUpload)return;const m=g.target,U=(J=m==null?void 0:m.files)==null?void 0:J[0];if(!U)return;h.value&&A&&(A.pause(),h.value=!1);const j=x();try{k.value=T.value,_.value="",r.info(`正在流式识别文件: ${U.name}`),await j.transcribeFile(U)}catch(L){r.error(`文件识别失败: ${L.message||L}`)}},te=()=>{P(),_.value="",T.value=k.value,o&&o.cancelRecording()},ie=()=>{_.value="",T.value=k.value,o&&o.cancelTranscribe(),r.info("已取消本次语音识别")},me=()=>{if(v.value){if(h.value&&A){A.pause(),h.value=!1;return}A&&(A.pause(),A=null),A=new Audio(v.value),A.onloadedmetadata=()=>{A&&!isNaN(A.duration)&&(M.value=Math.round(A.duration))},A.onended=()=>{h.value=!1},A.onerror=()=>{h.value=!1,r.error("音频试听播放失败")},A.play().then(()=>{h.value=!0}).catch(g=>{console.error("音频播放出错:",g),h.value=!1})}},ne=()=>{A&&(A.pause(),A=null),h.value=!1,v.value&&(URL.revokeObjectURL(v.value),v.value="")};e.onBeforeUnmount(()=>{P(),ne(),o&&(o.destroy(),o=null)});const ve=e.computed(()=>Be.find(g=>g.modelName===s.llmName)??Be.find(g=>g.modelName==="szjy")),B=n,T=e.ref(""),I=e.ref(null),oe=e.ref(!1),O=e.ref([]),so=e.ref(["什么是AI助理,能做什么?","当前项目的基本情况?","当前项目的进度情况?","当前项目的参建方有哪些?","数智建管平台有哪些功能?能做什么?"]),re=e.ref([]),le=e.ref(!1),Ne=e.ref(null),Ae=()=>{e.nextTick(()=>{if(Ne.value){const g=Ne.value,m=g.scrollHeight,U=g.scrollTop,j=g.clientHeight;m-U-j<100?g.scrollTop=m:g.scrollTo({top:m})}})},Y=e.ref(!1),io=e.computed(()=>Y.value?"/images/ai-stop.png":"/images/ai-send.png"),dt=(g,m)=>{console.log("onFailedReader",g,m),le.value=!1;const U=ft();U&&U.initializeEnd(),r.error("转换失败,请重试"),Y.value=!1,setTimeout(()=>{I.value&&I.value.focus()})},lo=(g,m)=>{le.value=!1,Y.value=!1,Ae(),m&&O.value[g]&&(O.value[g].displayText=m),setTimeout(()=>{I.value&&I.value.focus()})},co=g=>{Y.value=!0},uo=()=>{Y.value=!1,B("update:modelValue",!1),oe.value=!1,O.value=[]},Te=e.ref(!1),fo=()=>{Te.value=!Te.value},mo=g=>{T.value=g,Re()},ft=()=>{for(let g=re.value.length-1;g>=0;g--)if(re.value[g])return re.value[g];return null},Re=async()=>{if(console.log("stylizingLoading:",le.value),le.value){const J=ft();console.log("lastPreviewer:",J),J&&(console.log("abortReader"),J.abortReader());return}if(!T.value.trim()){console.log("no input, return"),I.value.focus();return}O.value.push({type:"user",content:T.value}),Y.value=!0,oe.value=!0,B("submit",T.value),Ae();const g=T.value;T.value="";const m=O.value.length;re.value[m]&&re.value[m].initializeStart(),le.value=!0,O.value.push({type:"ai"});const{error:U,reader:j}=await Vt(ve.value,{text:g,token:s.token,identifier:s.identifier,baseUrl:s.baseUrl,extraConfig:s.mockResponse?Object.assign({},s.extraConfig,{mockResponse:s.mockResponse}):s.extraConfig});if(U){console.log(45455,U),dt(m,U);return}j&&(O.value[m].reader=j)};return(g,m)=>{const U=e.resolveComponent("el-icon"),j=e.resolveComponent("el-button"),J=e.resolveComponent("el-input");return e.openBlock(),e.createBlock(e.Transition,{name:"slide"},{default:e.withCtx(()=>[t.modelValue?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["ai-panel",{"drawer-mode":Te.value,"embedded-mode":t.embedded}])},[e.createElementVNode("div",ln,[e.createElementVNode("div",cn,[e.createElementVNode("div",un,e.toDisplayString(t.title),1),e.createElementVNode("div",dn,[t.embedded?e.createCommentVNode("",!0):(e.openBlock(),e.createBlock(U,{key:0,class:"action-icon",onClick:fo},{default:e.withCtx(()=>[e.createVNode(ue,{name:"/images/svg/drawer-layout.svg",color:"#999999"})]),_:1})),e.createVNode(U,{class:"action-icon",onClick:uo},{default:e.withCtx(()=>[e.createVNode(ue,{name:"/images/svg/close.svg",color:"#999999"})]),_:1})])])]),e.createElementVNode("div",fn,[oe.value?(e.openBlock(),e.createElementBlock("div",{key:1,class:"chat-messages",ref_key:"messageContainerRef",ref:Ne},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(O.value,(L,ae)=>(e.openBlock(),e.createElementBlock("div",{key:ae,class:e.normalizeClass(["message-item",L.type==="user"?"user-message":"ai-message"])},[L.type==="ai"?(e.openBlock(),e.createBlock(nn,{key:0,ref_for:!0,ref:G=>re.value[ae]=G,reader:L.reader,"onUpdate:reader":G=>L.reader=G,model:s.llmName,displayText:L.displayText,scrollToBottomFn:Ae,messagePostRender:t.messagePostRender,customUi:t.customUi,uiActionHandler:t.uiActionHandler,onFailed:G=>dt(ae,G),onCompleted:G=>lo(ae,G),onUpdating:()=>co(),onUiAction:m[0]||(m[0]=G=>B("ui-action",G))},null,8,["reader","onUpdate:reader","model","displayText","messagePostRender","customUi","uiActionHandler","onFailed","onCompleted","onUpdating"])):(e.openBlock(),e.createElementBlock("div",kn,e.toDisplayString(L.content),1))],2))),128))],512)):(e.openBlock(),e.createElementBlock("div",mn,[m[3]||(m[3]=e.createElementVNode("div",{class:"title"},[e.createElementVNode("img",{src:mt,alt:"AI助手",class:"panel-icon"}),e.createElementVNode("h3",{class:"title-text"},"Hi, 您好")],-1)),e.createElementVNode("div",hn,[m[2]||(m[2]=e.createTextVNode(" 我是",-1)),e.createElementVNode("span",pn,e.toDisplayString(t.title),1)]),e.createElementVNode("div",gn,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(so.value,(L,ae)=>(e.openBlock(),e.createElementBlock("div",{key:ae,class:"question-item",onClick:G=>mo(L)},[e.createElementVNode("span",null,e.toDisplayString(L),1),e.createVNode(U,null,{default:e.withCtx(()=>[e.createVNode(ue,{name:"/images/svg/arrow-right.svg",color:"#999999"})]),_:1})],8,yn))),128))])]))]),e.createElementVNode("div",wn,[Y.value?(e.openBlock(),e.createElementBlock("img",bn)):e.createCommentVNode("",!0),e.createVNode(e.Transition,{name:"fade"},{default:e.withCtx(()=>[p.value||w.value?(e.openBlock(),e.createElementBlock("div",Sn,[e.createElementVNode("div",Cn,[m[4]||(m[4]=e.createElementVNode("span",{class:"progress-icon"},"⏳",-1)),e.createElementVNode("span",En,e.toDisplayString(l.value),1),c.value>0?(e.openBlock(),e.createElementBlock("span",vn,e.toDisplayString(c.value)+"%",1)):e.createCommentVNode("",!0)]),c.value>0?(e.openBlock(),e.createElementBlock("div",Nn,[e.createElementVNode("div",{class:"progress-bar",style:e.normalizeStyle({width:c.value+"%"})},null,4)])):e.createCommentVNode("",!0)])):e.createCommentVNode("",!0)]),_:1}),e.createVNode(e.Transition,{name:"fade"},{default:e.withCtx(()=>[f.value||d.value?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["voice-recording-panel",{"has-transcript":d.value}])},[e.createElementVNode("div",An,[e.createElementVNode("div",Tn,[e.createElementVNode("span",{class:e.normalizeClass(["recording-pulse",{transcribing:d.value}])},null,2),f.value?(e.openBlock(),e.createElementBlock("span",Rn,e.toDisplayString(N(S.value)),1)):e.createCommentVNode("",!0),e.createElementVNode("span",Vn,e.toDisplayString(C.value),1),f.value?(e.openBlock(),e.createElementBlock("div",xn,[e.createElementVNode("span",{class:"wave",style:e.normalizeStyle({height:Math.max(4,Math.min(22,u.value*.3))+"px"})},null,4),e.createElementVNode("span",{class:"wave",style:e.normalizeStyle({height:Math.max(4,Math.min(30,u.value*.5))+"px"})},null,4),e.createElementVNode("span",{class:"wave",style:e.normalizeStyle({height:Math.max(4,Math.min(18,u.value*.25))+"px"})},null,4)])):e.createCommentVNode("",!0)]),e.createElementVNode("div",Un,[f.value?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[e.createVNode(j,{size:"small",circle:"",onClick:te,title:"取消录音",class:"voice-cancel-btn"},{default:e.withCtx(()=>[...m[5]||(m[5]=[e.createElementVNode("svg",{viewBox:"0 0 1024 1024",width:"12",height:"12"},[e.createElementVNode("path",{d:"M512 456.310154L94.247385 38.557538a39.384615 39.384615 0 0 0-55.689847 55.689847L456.310154 512 38.557538 929.752615a39.384615 39.384615 0 0 0 55.689847 55.689847L512 567.689846l417.752615 417.752616c15.163077 15.163077 40.526769 15.163077 55.689847 0s15.163077-40.526769 0-55.689847L567.689846 512l417.752616-417.752615a39.384615 39.384615 0 0 0-55.689847-55.689847L512 456.310154z",fill:"currentColor"})],-1)])]),_:1}),e.createVNode(j,{type:"primary",size:"small",round:"",onClick:q,class:"voice-finish-btn"},{default:e.withCtx(()=>[...m[6]||(m[6]=[e.createTextVNode(" 完成 ",-1)])]),_:1})],64)):d.value?(e.openBlock(),e.createBlock(j,{key:1,size:"small",round:"",onClick:ie,class:"voice-cancel-transcribe-btn"},{default:e.withCtx(()=>[...m[7]||(m[7]=[e.createTextVNode(" 取消识别 ",-1)])]),_:1})):e.createCommentVNode("",!0)])]),d.value?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["live-transcript",{empty:!_.value}]),title:_.value},[_.value?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[e.createTextVNode(e.toDisplayString(_.value),1),m[8]||(m[8]=e.createElementVNode("span",{class:"caret"},"|",-1))],64)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[e.createTextVNode("正在识别,文字将实时显示...")],64))],10,Bn)):e.createCommentVNode("",!0)],2)):e.createCommentVNode("",!0)]),_:1}),e.createVNode(e.Transition,{name:"fade"},{default:e.withCtx(()=>[v.value&&!f.value&&!d.value?(e.openBlock(),e.createElementBlock("div",_n,[e.createElementVNode("div",{class:"playback-main",onClick:me,title:h.value?"点击暂停":"点击播放录音"},[e.createElementVNode("div",Pn,[h.value?(e.openBlock(),e.createElementBlock("svg",jn,[...m[10]||(m[10]=[e.createElementVNode("path",{d:"M6 19h4V5H6v14zm8-14v14h4V5h-4z"},null,-1)])])):(e.openBlock(),e.createElementBlock("svg",Mn,[...m[9]||(m[9]=[e.createElementVNode("path",{d:"M8 5v14l11-7z"},null,-1)])]))]),e.createElementVNode("span",In,e.toDisplayString(h.value?"正在播放录音...":"点击试听本次录音"),1),M.value>0?(e.openBlock(),e.createElementBlock("span",Ln,e.toDisplayString(N(M.value)),1)):e.createCommentVNode("",!0),h.value?(e.openBlock(),e.createElementBlock("div",$n,[...m[11]||(m[11]=[e.createElementVNode("span",{class:"wave-bar"},null,-1),e.createElementVNode("span",{class:"wave-bar"},null,-1),e.createElementVNode("span",{class:"wave-bar"},null,-1),e.createElementVNode("span",{class:"wave-bar"},null,-1)])])):e.createCommentVNode("",!0)],8,zn),e.createElementVNode("div",{class:"playback-close",onClick:ne,title:"清除试听"},[...m[12]||(m[12]=[e.createElementVNode("svg",{viewBox:"0 0 1024 1024",width:"12",height:"12"},[e.createElementVNode("path",{d:"M512 456.310154L94.247385 38.557538a39.384615 39.384615 0 0 0-55.689847 55.689847L456.310154 512 38.557538 929.752615a39.384615 39.384615 0 0 0 55.689847 55.689847L512 567.689846l417.752615 417.752616c15.163077 15.163077 40.526769 15.163077 55.689847 0s15.163077-40.526769 0-55.689847L567.689846 512l417.752616-417.752615a39.384615 39.384615 0 0 0-55.689847-55.689847L512 456.310154z",fill:"currentColor"})],-1)])])])):e.createCommentVNode("",!0)]),_:1}),e.withDirectives(e.createElementVNode("div",Fn,[e.createVNode(J,{modelValue:T.value,"onUpdate:modelValue":m[1]||(m[1]=L=>T.value=L),ref_key:"refInputTextString",ref:I,placeholder:E.value,autofocus:"",onKeyup:e.withKeys(Re,["enter"])},{append:e.withCtx(()=>[e.createElementVNode("div",On,[t.enableVoiceUpload?(e.openBlock(),e.createElementBlock("div",{key:0,class:"voice-upload-btn",onClick:K,title:"上传音频/视频文件识别 (支持 .wav, .mp4, .mp3, .m4a)"},[...m[13]||(m[13]=[e.createElementVNode("svg",{viewBox:"0 0 24 24",width:"17",height:"17",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},[e.createElementVNode("path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"}),e.createElementVNode("polyline",{points:"17 8 12 3 7 8"}),e.createElementVNode("line",{x1:"12",y1:"3",x2:"12",y2:"15"})],-1)])])):e.createCommentVNode("",!0),t.enableVoiceUpload?(e.openBlock(),e.createElementBlock("input",{key:1,type:"file",ref_key:"refAudioFileInput",ref:W,accept:"audio/*,video/mp4,.wav,.mp4,.mp3,.m4a",style:{display:"none"},onChange:$},null,544)):e.createCommentVNode("",!0),t.enableVoiceInput?(e.openBlock(),e.createElementBlock("div",{key:2,class:e.normalizeClass(["voice-mic-btn",{"loading-anim":p.value||w.value}]),onClick:H,title:"语音输入"},[...m[14]||(m[14]=[e.createElementVNode("svg",{viewBox:"0 0 24 24",width:"18",height:"18",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},[e.createElementVNode("path",{d:"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z",fill:"currentColor",opacity:"0.2"}),e.createElementVNode("path",{d:"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"}),e.createElementVNode("path",{d:"M19 10v2a7 7 0 0 1-14 0v-2"}),e.createElementVNode("line",{x1:"12",y1:"19",x2:"12",y2:"22"})],-1)])],2)):e.createCommentVNode("",!0),e.createElementVNode("div",{class:"send-icon-box",onClick:Re},[e.createElementVNode("img",{src:io.value,alt:"发送",class:"send-icon"},null,8,Dn)])])]),_:1},8,["modelValue","placeholder"])],512),[[e.vShow,!f.value&&!d.value]])])],2)):e.createCommentVNode("",!0)]),_:1})}}};var nt={exports:{}};(function(t,n){(function(a,r){t.exports=r()})(window,function(){return function(a){var r={};function s(o){if(r[o])return r[o].exports;var i=r[o]={i:o,l:!1,exports:{}};return a[o].call(i.exports,i,i.exports,s),i.l=!0,i.exports}return s.m=a,s.c=r,s.d=function(o,i,l){s.o(o,i)||Object.defineProperty(o,i,{enumerable:!0,get:l})},s.r=function(o){typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(o,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(o,"__esModule",{value:!0})},s.t=function(o,i){if(1&i&&(o=s(o)),8&i||4&i&&typeof o=="object"&&o&&o.__esModule)return o;var l=Object.create(null);if(s.r(l),Object.defineProperty(l,"default",{enumerable:!0,value:o}),2&i&&typeof o!="string")for(var c in o)s.d(l,c,(function(u){return o[u]}).bind(null,c));return l},s.n=function(o){var i=o&&o.__esModule?function(){return o.default}:function(){return o};return s.d(i,"a",i),i},s.o=function(o,i){return Object.prototype.hasOwnProperty.call(o,i)},s.p="",s(s.s=0)}([function(a,r,s){function o(k,p,w,f){w.push(k),f.push([].concat(p[k]||[]))}function i(k,p){if(!k)throw new Error("[getMaxDepsChain] dep 参数不能为空");var w=[],f=[],d=[];for(o(k,p,f,d);f.length;){var C=d.pop();if(C&&C.length){var E=C.shift();if(d.push(C),~f.indexOf(E))throw new Error("[getMaxDepsChain][loop] 存在循环依赖,请检查依赖关系; nextName: "+E+", mainStack: "+f);o(E,p,f,d)}else w.push([].concat(f)),f.pop()}return w.reduce(function(z,N){return N.length>z.length?N:z},[])}function l(k){if(!k)throw new Error("[depsParser] 入参不能为空");var p={};k.forEach(function(f){p[f.name]=f.deps||[]});var w=[];return k.forEach(function(f){var d=i(f.name,p).length-1;f.priority=d,w[d]=(w[d]||[]).concat(f)}),w}s.r(r),s.d(r,"loadScript",function(){return v}),s.d(r,"loadScripts",function(){return h}),s.d(r,"dynamicLoadScripts",function(){return M}),s.d(r,"createScriptsLoadIterator",function(){return A}),s.d(r,"loadScriptsQueue",function(){return _}),s.d(r,"getMaxDepsChain",function(){return i}),s.d(r,"depsParser",function(){return l});var c=function(){return(c=Object.assign||function(k){for(var p,w=1,f=arguments.length;w<f;w++)for(var d in p=arguments[w])Object.prototype.hasOwnProperty.call(p,d)&&(k[d]=p[d]);return k}).apply(this,arguments)},u=function(k,p,w,f){return new(w||(w=Promise))(function(d,C){function E(x){try{N(f.next(x))}catch(b){C(b)}}function z(x){try{N(f.throw(x))}catch(b){C(b)}}function N(x){var b;x.done?d(x.value):(b=x.value,b instanceof w?b:new w(function(P){P(b)})).then(E,z)}N((f=f.apply(k,[])).next())})},S=function(k,p){var w,f,d,C,E={label:0,sent:function(){if(1&d[0])throw d[1];return d[1]},trys:[],ops:[]};return C={next:z(0),throw:z(1),return:z(2)},typeof Symbol=="function"&&(C[Symbol.iterator]=function(){return this}),C;function z(N){return function(x){return function(b){if(w)throw new TypeError("Generator is already executing.");for(;E;)try{if(w=1,f&&(d=2&b[0]?f.return:b[0]?f.throw||((d=f.return)&&d.call(f),0):f.next)&&!(d=d.call(f,b[1])).done)return d;switch(f=0,d&&(b=[2&b[0],d.value]),b[0]){case 0:case 1:d=b;break;case 4:return E.label++,{value:b[1],done:!1};case 5:E.label++,f=b[1],b=[0];continue;case 7:b=E.ops.pop(),E.trys.pop();continue;default:if(d=E.trys,!((d=d.length>0&&d[d.length-1])||b[0]!==6&&b[0]!==2)){E=0;continue}if(b[0]===3&&(!d||b[1]>d[0]&&b[1]<d[3])){E.label=b[1];break}if(b[0]===6&&E.label<d[1]){E.label=d[1],d=b;break}if(d&&E.label<d[2]){E.label=d[2],E.ops.push(b);break}d[2]&&E.ops.pop(),E.trys.pop();continue}b=p.call(k,E)}catch(P){b=[6,P],f=0}finally{w=d=0}if(5&b[0])throw b[1];return{value:b[0]?b[1]:void 0,done:!0}}([N,x])}}},R=function(k){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var p,w=k[Symbol.asyncIterator];return w?w.call(k):(k=typeof __values=="function"?__values(k):k[Symbol.iterator](),p={},f("next"),f("throw"),f("return"),p[Symbol.asyncIterator]=function(){return this},p);function f(d){p[d]=k[d]&&function(C){return new Promise(function(E,z){(function(N,x,b,P){Promise.resolve(P).then(function(H){N({value:H,done:b})},x)})(E,z,(C=k[d](C)).done,C.value)})}}};function v(k,p){return p===void 0&&(p=!1),new Promise(function(w,f){var d=p?document.head:document.body,C=document.createElement("script");C.type="text/javascript",C.src=k,C.crossOrigin="anonymous",C.onreadystatechange=w,C.onload=w,C.onerror=f,d.appendChild(C)})}var h=function(k,p){return p===void 0&&(p={}),u(void 0,void 0,void 0,function(){var w,f,d,C,E;return S(this,function(z){switch(z.label){case 0:return w=p.baseUrl,f=w===void 0?"":w,d=p.lastLoadResult,C=p.inHead,E=C!==void 0&&C,[4,Promise.all(k.map(function(N){return u(void 0,void 0,void 0,function(){var x,b,P,H,q,W,K,$;return S(this,function(te){switch(te.label){case 0:return x=N.name,b=N.path,P=N.deps,(K={})[x]=!0,H=K,($={})[x]=!1,q=$,window[x]?[2,H]:[3,1];case 1:return W=!0,P&&d&&[].concat(P).forEach(function(ie){d[ie]!==!1&&(W=!0)}),W?[4,v(b.indexOf("http")===0||b.indexOf("//:")===0?b:f+b,E).then(function(){return H}).catch(function(){return q})]:[3,3];case 2:return[2,te.sent()];case 3:return[2,q]}})})}))];case 1:return[2,z.sent()]}})})},M=function(k,p){return p===void 0&&(p={}),function(){var w=[].concat(l(k));return{next:function(){if(w.length){var f=w.shift();return h(f,p).then(function(d){return{value:d,done:!1}})}return Promise.resolve({done:!0})}}}},A=function(k,p){var w;return p===void 0&&(p={}),(w={})[Symbol.asyncIterator]=M(k,p),w},_=function(k,p){return p===void 0&&(p={}),u(void 0,void 0,void 0,function(){var w,f,d,C,E,z;return S(this,function(N){switch(N.label){case 0:N.trys.push([0,5,6,11]),w=R(A(k,p)),N.label=1;case 1:return[4,w.next()];case 2:if((f=N.sent()).done)return[3,4];d=f.value,p.lastLoadResult=p.lastLoadResult||{},console.log("current load: ",d),d.forEach(function(x){p.lastLoadResult=c(c({},p.lastLoadResult),x)}),N.label=3;case 3:return[3,1];case 4:return[3,11];case 5:return C=N.sent(),E={error:C},[3,11];case 6:return N.trys.push([6,,9,10]),f&&!f.done&&(z=w.return)?[4,z.call(w)]:[3,8];case 7:N.sent(),N.label=8;case 8:return[3,10];case 9:if(E)throw E.error;return[7];case 10:return[7];case 11:return[2,p.lastLoadResult]}})})}}])})})(nt);var Hn=nt.exports;function ot(){const t=[{name:"markdownit",path:"markdown-it.min.js"},{name:"hljs",path:"highlight.11.11.1.min.js"}];let n={};Hn.loadScriptsQueue(t,{baseUrl:"/scripts/ai/",lastLoadResult:n,inHead:!1}).then(a=>{if(console.log("load ai deps: ",a),window.markdownit){const r=window.markdownit();console.log("markdownit: ",r),Gt()}})}const qn={key:0,class:"ai-assistant"},Wn={name:"AiChat"},rt=e.defineComponent({...Wn,props:{token:{type:String,default:""},identifier:{type:String,default:""},baseUrl:{type:String,default:""},title:{type:String,default:"数智AI助理"},llmName:{type:String,default:"szjy"},messagePostRender:{type:Function,default:null},extraConfig:{type:Object,default:()=>({})},soundBaseUrl:{type:String,default:"/sounds/"},workerUrl:{type:String,default:""},enableVoiceInput:{type:Boolean,default:!1},enableVoiceUpload:{type:Boolean,default:!1},customUi:{type:Object,default:null},uiActionHandler:{type:Function,default:null},mockResponse:{type:String,default:""}},emits:["ui-action"],setup(t,{emit:n}){const a=e.ref(!1),r=e.ref(!1),s=n,o=()=>{a.value=!a.value},i=()=>{r.value=!0,a.value=!1},l=c=>{console.log("用户输入:",c)};return ot(),(c,u)=>r.value?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("div",qn,[e.createVNode(tt,{modelValue:a.value,"onUpdate:modelValue":u[0]||(u[0]=S=>a.value=S),onSubmit:l,onUiAction:u[1]||(u[1]=S=>s("ui-action",S)),token:t.token,identifier:t.identifier,baseUrl:t.baseUrl,title:t.title,llmName:t.llmName,messagePostRender:t.messagePostRender,extraConfig:t.extraConfig,customUi:t.customUi,uiActionHandler:t.uiActionHandler,mockResponse:t.mockResponse,soundBaseUrl:t.soundBaseUrl,workerUrl:t.workerUrl,enableVoiceInput:t.enableVoiceInput,enableVoiceUpload:t.enableVoiceUpload},null,8,["modelValue","token","identifier","baseUrl","title","llmName","messagePostRender","extraConfig","customUi","uiActionHandler","mockResponse","soundBaseUrl","workerUrl","enableVoiceInput","enableVoiceUpload"]),e.createElementVNode("div",{class:"ai-icon",onClick:o},[e.createElementVNode("div",{class:"close-icon",onClick:e.withModifiers(i,["stop"])},[...u[2]||(u[2]=[e.createElementVNode("svg",{viewBox:"0 0 1024 1024",width:"8",height:"8"},[e.createElementVNode("path",{d:"M512 456.310154L94.247385 38.557538a39.384615 39.384615 0 0 0-55.689847 55.689847L456.310154 512 38.557538 929.752615a39.384615 39.384615 0 0 0 55.689847 55.689847L512 567.689846l417.752615 417.752616c15.163077 15.163077 40.526769 15.163077 55.689847 0s15.163077-40.526769 0-55.689847L567.689846 512l417.752616-417.752615a39.384615 39.384615 0 0 0-55.689847-55.689847L512 456.310154z",fill:"currentColor"})],-1)])]),u[3]||(u[3]=e.createElementVNode("img",{src:Z,alt:"AI助手"},null,-1)),u[4]||(u[4]=e.createElementVNode("span",{class:"ai-icon-text"},"AI助手",-1))])]))}}),Gn={class:"ai-chat-plain"},Jn={name:"AiChatPlain"},at=e.defineComponent({...Jn,props:{token:{type:String,default:""},identifier:{type:String,default:""},baseUrl:{type:String,default:""},title:{type:String,default:"数智AI助理"},llmName:{type:String,default:"szjy"},messagePostRender:{type:Function,default:null},extraConfig:{type:Object,default:()=>({})},soundBaseUrl:{type:String,default:"/sounds/"},workerUrl:{type:String,default:""},enableVoiceInput:{type:Boolean,default:!1},enableVoiceUpload:{type:Boolean,default:!1},customUi:{type:Object,default:null},uiActionHandler:{type:Function,default:null},mockResponse:{type:String,default:""}},emits:["submit","ui-action"],setup(t,{emit:n}){const a=n;return ot(),(r,s)=>(e.openBlock(),e.createElementBlock("div",Gn,[e.createVNode(tt,{"model-value":!0,token:t.token,identifier:t.identifier,baseUrl:t.baseUrl,title:t.title,llmName:t.llmName,messagePostRender:t.messagePostRender,extraConfig:t.extraConfig,customUi:t.customUi,uiActionHandler:t.uiActionHandler,mockResponse:t.mockResponse,soundBaseUrl:t.soundBaseUrl,workerUrl:t.workerUrl,enableVoiceInput:t.enableVoiceInput,enableVoiceUpload:t.enableVoiceUpload,embedded:!0,onSubmit:s[0]||(s[0]=o=>a("submit",o)),onUiAction:s[1]||(s[1]=o=>a("ui-action",o))},null,8,["token","identifier","baseUrl","title","llmName","messagePostRender","extraConfig","customUi","uiActionHandler","mockResponse","soundBaseUrl","workerUrl","enableVoiceInput","enableVoiceUpload"])]))}}),st=Object.freeze(Object.defineProperty({__proto__:null,SzAiChat:rt,SzAiChatPlain:at},Symbol.toStringTag,{value:"Module"})),Ee=function(t){if(!Ee.installed){Ee.installed=!0;for(let n in st){const a=Reflect.get(st,n);t.component(a.name,a)}}},Kn=(t,n)=>{const a=n?`?${new URLSearchParams(n).toString()}`:"";console.log(`点击了路由链接: ${t}${a}`)},it=t=>{const n=t.indexOf("?");if(n===-1)return{routeName:t};const a=t.substring(0,n),r=t.substring(n+1),s={};return new URLSearchParams(r).forEach((i,l)=>{s[l]=i}),{routeName:a,queryParams:Object.keys(s).length>0?s:void 0}},Yn={color:"#536fec",fontWeight:"bold",textDecoration:"underline",cursor:"pointer",padding:"0 3px"},lt=t=>{const n=/#router:([^#]+)#/g,a=[];let r=0,s;for(;(s=n.exec(t))!==null;){s.index>r&&a.push({text:t.substring(r,s.index)});const o=s[1],{routeName:i,queryParams:l}=it(o);a.push({text:i,routeName:i,queryParams:l}),r=n.lastIndex}return r<t.length&&a.push({text:t.substring(r)}),a},ct=(t,n,a={},r)=>{const{onRouteClick:s=Kn,linkStyle:o={}}=a,i=document.createElement("a");i.href="#",i.textContent=t;const l={...Yn,...o};return Object.assign(i.style,l),i.addEventListener("click",c=>{c.preventDefault(),s(n,r)}),i},ut=t=>{const n=/#router:([^#]+)#/g,a=[],r=document.createTreeWalker(t,NodeFilter.SHOW_TEXT,null);let s=r.nextNode();for(;s;){const o=s,i=o.textContent||"";if(n.test(i)){n.lastIndex=0;const l=lt(i);l.length>0&&a.push({node:o,replacements:l})}s=r.nextNode()}return a},Zn=(t,n,a={})=>{const r=ut(t);r.forEach(({node:s,replacements:o})=>{var l;const i=document.createDocumentFragment();o.forEach(({text:c,routeName:u,queryParams:S})=>{if(u){const R=ct(c,u,a,S);i.appendChild(R)}else i.appendChild(document.createTextNode(c))}),(l=s.parentNode)==null||l.replaceChild(i,s)}),a!=null&&a.nodeCallback&&r.forEach(({node:s,replacements:o})=>{var i;(i=a.nodeCallback)==null||i.call(a,s,o)})},se="szjy-voice-models",de="szjy-voice-cache-v1";function ee(){return typeof navigator<"u"&&!!navigator.storage&&typeof navigator.storage.getDirectory=="function"}async function fe(t=se){if(!ee())return null;try{return await(await navigator.storage.getDirectory()).getDirectoryHandle(t,{create:!0})}catch(n){return console.warn("[OPFS] 获取目录失败,将使用降级缓存:",n),null}}async function Xn(t,n,a=se){if(ee())try{const r=await fe(a);if(r){const o=await(await r.getFileHandle(t,{create:!0})).createWritable();return await o.write(n),await o.close(),!0}}catch(r){console.warn(`[OPFS] 写入文件 ${t} 失败:`,r)}if(typeof caches<"u")try{const r=await caches.open(de),s=new Response(n,{headers:{"Content-Type":"application/octet-stream"}});return await r.put(`/${a}/${t}`,s),!0}catch(r){console.warn(`[CacheStorage] 缓存写入 ${t} 失败:`,r)}return!1}async function Qn(t,n=se){if(ee())try{const a=await fe(n);if(a)return await(await(await a.getFileHandle(t,{create:!1})).getFile()).arrayBuffer()}catch{}if(typeof caches<"u")try{const r=await(await caches.open(de)).match(`/${n}/${t}`);if(r)return await r.arrayBuffer()}catch{}return null}async function eo(t,n=se){if(ee())try{const a=await fe(n);if(a)return(await(await a.getFileHandle(t,{create:!1})).getFile()).size>0}catch{}if(typeof caches<"u")try{return!!await(await caches.open(de)).match(`/${n}/${t}`)}catch{}return!1}async function to(t=se){let n=!1;if(ee())try{await(await navigator.storage.getDirectory()).removeEntry(t,{recursive:!0}),n=!0,console.log(`[OPFS] 成功清空语音模型缓存目录: ${t}`)}catch(a){a.name==="NotFoundError"?n=!0:console.warn(`[OPFS] 清理目录 ${t} 异常:`,a)}if(typeof caches<"u")try{const a=await caches.keys();for(const r of a)(r.includes("transformers")||r.includes("szjy-voice")||r===de)&&(await caches.delete(r),n=!0)}catch(a){console.warn("[CacheStorage] 清除缓存异常:",a)}return n}const no="0.1.16",oo="Sz";function ro({componentPrefix:t=oo,components:n=[]}={}){const a=[];function r(o,i,l){o.component(t+i)||o.component(t+i,l)}function s(o){a.includes(o)||(a.push(o),n.forEach(i=>{const{name:l,alias:c}=i;r(o,l,i),c&&c.forEach(u=>{r(o,u,i)})}))}return{version:no,componentPrefix:t,install:s}}const ao={install(t){Ee(t)}};y.AudioRecorder=Ke,y.DEFAULT_MOCK_RESPONSE=xe,y.DEFAULT_WHISPER_WORKER_URL=Se,y.SZJY_UI_FENCE_LANG=qe,y.StreamResampler=Je,y.SzAiChat=rt,y.SzAiChatPlain=at,y.VoiceInputManager=et,y.bindSzjyUiEvents=Ge,y.clearVoiceModelCache=to,y.create=ro,y.createMockStylized=Ue,y.createRouteLink=ct,y.decodeAudioFile=Ze,y.default=ao,y.escapeHtml=X,y.findRouteTextNodes=ut,y.float32ToWav=be,y.getFileFromCache=Qn,y.getOPFSDirectory=fe,y.getSzjyUiAction=Ie,y.getSzjyUiComponent=Me,y.hasFileInCache=eo,y.hasSzjyUiAction=Le,y.hasSzjyUiComponent=je,y.isOPFSSupported=ee,y.parseRouteMarkerContent=it,y.parseRouteMarkers=lt,y.parseSzjyUiFence=We,y.registerSzjyUiAction=Pe,y.registerSzjyUiComponent=ke,y.renderActionAttrs=Fe,y.renderSzjyUiBlock=$e,y.renderSzjyUiNode=we,y.resampleAudioData=Ye,y.routeLinkRender=Zn,y.saveFileToCache=Xn,Object.defineProperties(y,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
|
1
|
+
(function(p,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(p=typeof globalThis<"u"?globalThis:p||self,e(p["szjy-ai-coms"]={},p.Vue))})(this,function(p,e){"use strict";var Br=Object.defineProperty;var Rr=(p,e,he)=>e in p?Br(p,e,{enumerable:!0,configurable:!0,writable:!0,value:he}):p[e]=he;var j=(p,e,he)=>Rr(p,typeof e!="symbol"?e+"":e,he);const he="/images/ai-round.png",sn="/images/ai-sqrt.png",ln="/images/sikao.svg",cn="/images/bars-loading.svg";function Qe(t){return t.startsWith("http://")||t.startsWith("https://")?t:`${location.protocol}//${location.host}${t}`}async function un(t,n,r,o="",s={}){const{projectId:a}=s,i=Qe(o),l=new URL(`${i}/v1/chat/completions`),c=(s==null?void 0:s.authToken)||"app-oLZVFFdYyJX2QK3rdOLWsC2u";s!=null&&s.authToken||console.error("缺少 authToken!现在默认使用内网的 authToken");const u=new Request(l,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${c}`},body:JSON.stringify({model:"dify",stream:!0,inputs:{token:n,projectCode:r,...a?{projectId:a}:{}},messages:[{role:"system",content:"你是一个专业的AI助手,请用中文回答问题。"},{role:"user",content:t}]})});return fetch(u)}async function dn(t,n,r,o="",s={}){const a=new URL("http://localhost:11434/api/chat"),i={};Object.keys(i).forEach(c=>{a.searchParams.append(c,i[c])});const l=new Request(a,{mode:"cors",method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:"llama3",stream:!0,messages:[{role:"system",content:"全程使用中文回答问题。"},{role:"user",content:t}]})});return fetch(l)}async function fn(t,n,r,o="",s={}){const a=new URL(`${location.origin}/spark/v1/chat/completions`),i={};Object.keys(i).forEach(c=>{a.searchParams.append(c,i[c])});const l=new Request(a,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({model:"generalv4.0Ultra",stream:!0,messages:[{role:"user",content:t}]})});return fetch(l)}async function mn(t,n,r,o="",s={}){const a=new URL(`${location.origin}/siliconflow/v1/chat/completions`),i={};Object.keys(i).forEach(c=>{a.searchParams.append(c,i[c])});const l=new Request(a,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({model:"Qwen/Qwen1.5-110B-Chat",stream:!0,messages:[{role:"user",content:t}]})});return fetch(l)}async function hn(t,n,r,o="",s={}){const a=new URL(`${location.origin}/moonshot/v1/chat/completions`),i={};Object.keys(i).forEach(c=>{a.searchParams.append(c,i[c])});const l=new Request(a,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({model:"moonshot-v1-8k",stream:!0,messages:[{role:"system",content:"你是 Kimi,由 Moonshot AI 提供的人工智能助手,你更擅长中文和英文的对话。你会为用户提供安全,有帮助,准确的回答。同时,你会拒绝一切涉及恐怖主义,种族歧视,黄色暴力等问题的回答。Moonshot AI 为专有名词,不可翻译成其他语言。"},{role:"user",content:t}]})});return fetch(l)}async function pn(t,n,r,o="",s={}){const a=new URL(`${location.origin}/dashscope/compatible-mode/v1/chat/completions`),i={};Object.keys(i).forEach(c=>{a.searchParams.append(c,i[c])});const l=new Request(a,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({model:"qwq-32b-preview",stream:!0,messages:[{role:"system",content:"全程使用中文回答问题"},{role:"user",content:t}]})});return fetch(l)}async function gn(t,n,r,o="",s={}){const a=Qe(o),i=new URL(`${a}/support/${r}/a`),l={};Object.keys(l).forEach(u=>{i.searchParams.append(u,l[u])});const c=new Request(i,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({content:t})});return fetch(c)}const et=["根据您的问题,我为您整理了以下构件:","","```szjy-ui",JSON.stringify({title:"构件列表",type:"list",gap:12,items:[{type:"button",props:{type:"primary",content:"查看构件1(CHKS-TJ01-02-01-01-01-01)"},action:"postMessage",actionParams:{type:"BIM_SANDBOX",action:"locateComponent",payload:{wbsCode:"CHKS-TJ01-02-01-01-01-01"}}},{type:"button",props:{type:"primary",content:"查看构件2(CHKS-TJ01-02-01-01-04-02)"},action:"postMessage",actionParams:{type:"BIM_SANDBOX",action:"locateComponent",payload:{wbsCode:"CHKS-TJ01-02-01-01-04-02"}}},{type:"button",props:{type:"default",content:"查看构件3(不存在的编码,演示失败反馈)"},action:"postMessage",actionParams:{type:"BIM_SANDBOX",action:"locateComponent",payload:{wbsCode:"CHKS-NOT-EXIST"}}}]},null,2),"```","","点击上方按钮即可在 BIM 沙盘中定位对应构件。"].join(`
|
|
2
|
+
`),yn=8,kn=80,wn=t=>new Promise(n=>setTimeout(n,t));function Sn(t,n){const r=Math.ceil(t.length/n),o=[];for(let s=0;s<t.length;s+=r)o.push(t.slice(s,s+r));return o.length?o:[""]}async function tt(t,n,r,o="",s={}){const i=(s&&typeof s.mockResponse=="string"?s.mockResponse.trim():"")||et,l=new TextEncoder,c=new ReadableStream({async start(u){for(const f of Sn(i,yn))u.enqueue(l.encode(f)),await wn(kn);u.close()}});return new Response(c,{status:200,headers:{"Content-Type":"text/plain; charset=utf-8"}})}const bn=t=>{if(t.startsWith("data:")){const n=t.substring(5).trim();if(n==="[DONE]")return{done:!0};try{return JSON.parse(n)}catch(r){console.error("JSON parsing error:",r)}}return null},Re="<think>",ve="</think>",_e=(t,n)=>{const r=Math.max(0,t.length-(n.length-1));for(let o=r;o<t.length;o++)if(n.startsWith(t.slice(o)))return t.length-o;return 0},En=t=>{let n="",r="",o=t||"",s=!1;for(;o;){const a=o.indexOf(Re),i=o.indexOf(ve);if(a>=0&&(i<0||a<i))r+=o.slice(0,a),o=o.slice(a+Re.length),s=!0;else if(i>=0&&(a<0||i<a))n+=o.slice(0,i),o=o.slice(i+ve.length),s=!1;else if(s){const l=_e(o,ve);n+=o.slice(0,o.length-l),o=""}else{const l=Math.max(_e(o,Re),_e(o,ve));r+=o.slice(0,o.length-l),o=""}}return{thinking:n.trim(),content:r.trim(),isThinkingStreaming:s}},nt=[{label:"模拟数据模型",modelName:"standard",api:tt},{label:"Spark 星火大模型",modelName:"spark",api:fn},{label:"Ollama 3 大模型",modelName:"ollama3",api:dn},{label:"SiliconFlow 硅基流动大模型",modelName:"siliconflow",api:mn},{label:"Kimi Moonshot 月之暗面大模型",modelName:"moonshot",api:hn},{label:"通义千问大模型",modelName:"dashscope",api:pn},{label:"数智建管大模型",modelName:"szjy",api:gn},{label:"Dify (OpenAI 兼容)",modelName:"dify-openai",api:un}],ot={standard(t,n){let r="";return t instanceof Uint8Array?r=n.decode(t,{stream:!0}):r=t,{content:r}},spark(t){const n=bn(t);if(n.done)return{done:!0};const r=n.choices[0].delta,o=r.reasoning_content||r.reasoning;let s=r.content||"";return o&&(s=`<think>${o}</think>${s}`),{content:s}},siliconflow(t){return this.spark(t)},moonshot(t){return this.spark(t)},dashscope(t){return this.spark(t)},szjy(t){return this.spark(t)},"dify-openai"(t){return this.spark(t)},ollama3(t){return{content:JSON.parse(t).message.content}}},rt=(t,n,r)=>{const o=t.split(r);return o.slice(0,-1).forEach(s=>{s.trim()!==""&&n.enqueue(s)}),o[o.length-1]},Cn=t=>{let n="";return new TransformStream({transform(r,o){if(n+=r,n.trim().startsWith("data:"))n=rt(n,o,t);else try{JSON.parse(n),n=rt(n,o,t)}catch{o.enqueue(r),n=""}},flush(r){n.trim()!==""&&r.enqueue(n)}})};async function vn(t,n){const r=t.api;return r?new Promise(o=>{r(n.text,n.token,n.identifier,n.baseUrl,n.extraConfig).then(s=>{if(s.body){const a=s.body.pipeThrough(new TextDecoderStream).pipeThrough(Cn(`
|
|
3
|
+
`)).getReader();console.log("reader from response:",a),o({error:0,reader:a})}else o({error:1,reader:null})}).catch(()=>{o({error:1,reader:null})})}):{error:1,reader:null}}const Le=new Map,xe=new Map;function Ue(t,n){Le.set(t,n)}function at(t,n){xe.set(t,n)}function st(t){return Le.get(t)}function it(t){return Le.has(t)}function lt(t){return xe.get(t)}function ct(t){return xe.has(t)}const An={"&":"&","<":"<",">":">",'"':""","'":"'"};function pe(t){return String(t??"").replace(/[&<>"']/g,n=>An[n])}function ut(t){const r=Pe(t,{block:t});return r?`<div class="szjy-ui" data-szjy-ui="1">${r}</div>`:""}function Pe(t,n){if(!t||typeof t!="object"||typeof t.type!="string")return"";const r=st(t.type);return r?r(t,n):""}function dt(t){const n=t.action;if(!n||typeof n!="string")return"";if(!ct(n))return` disabled title="未知动作:${pe(n)}"`;const r=t.actionParams===void 0?"":encodeURIComponent(JSON.stringify(t.actionParams??null));return` data-szjy-ui-action="${pe(n)}" data-szjy-ui-params="${r}"`}function Tn(t){return typeof t=="number"&&Number.isFinite(t)&&t>=0?`${t}px`:typeof t=="string"&&/^\d+(\.\d+)?(px|rem|em|%)?$/.test(t.trim())?/^\d+(\.\d+)?$/.test(t.trim())?`${t.trim()}px`:t.trim():"12px"}function Nn(t,n){const r=typeof t.title=="string"&&t.title?`<div class="szjy-ui-list__title">${pe(t.title)}</div>`:"",s=(Array.isArray(t.items)?t.items:[]).map(i=>Pe(i,n)).filter(Boolean).map(i=>`<div class="szjy-ui-list__item">${i}</div>`).join(""),a=pe(Tn(t.gap));return'<div class="szjy-ui-list">'+r+`<div class="szjy-ui-list__items" style="gap:${a}">${s}</div></div>`}Ue("list",Nn);const Vn=["default","primary","success","warning","danger","info","text"],Bn=["small","default","large"];function Rn(t,n){const r=t.props,o=r&&typeof r=="object"?r:{},s=Vn.includes(o.type)?o.type:"default",a=Bn.includes(o.size)?o.size:"default",i=pe(o.content??o.text??"按钮"),l=dt(t);return`<button type="button" class="${["szjy-ui-btn",`szjy-ui-btn--${s}`,`szjy-ui-btn--${a}`].join(" ")}"${l}><span class="szjy-ui-btn__text">${i}</span><span class="szjy-ui-btn__status" aria-live="polite"></span></button>`}Ue("button",Rn);const _n=15e3,ft=/未就绪|未加载/,Ln="BIM_SANDBOX",xn={locateComponent:t=>[t==null?void 0:t.wbsCode],openPDFSearch:()=>[]};let Un=0;function Pn(t,n){let r;if(!t||t==="self")r=[window];else if(t==="parent")r=[window.parent];else if(t==="top")r=[window.top];else if(typeof t=="function")try{r=t(n)}catch(a){console.error("[szjy-ui] 解析 postMessage 目标窗口失败:",a),r=[]}else Array.isArray(t)?r=t:r=[t];const o=[],s=a=>{if(a){if(Array.isArray(a)){a.forEach(s);return}typeof a.postMessage=="function"&&!o.includes(a)&&o.push(a)}};return s(r),o}function ge(t){if(t===window)return`self (${location.origin})`;if(t===window.parent)return"parent";if(t===window.top)return"top";try{return`window (${t.location.href.slice(0,60)})`}catch{return"window (cross-origin)"}}function Mn(t){try{const n=t.$bimSandbox;return n&&typeof n=="object"?n:null}catch{return null}}function zn(t,n,r){if(n.type!==Ln)return{handled:!1};const o=xn[n.action];if(!o)return{handled:!1};const s=Mn(t);if(!s||typeof s[n.action]!="function")return{handled:!1};const a=o(n.payload);let i;try{i=s[n.action](...a)}catch(l){return console.error("[szjy-ui] $bimSandbox 方法调用异常,回退 postMessage:",l),{handled:!1}}return r&&console.log("[szjy-ui] $bimSandbox 直调",{method:n.action,args:a,result:i,target:ge(t)}),{handled:!0,result:i}}function mt(t,n,r,o,s,a,i){return(()=>{const{handled:c,result:u}=zn(t,n,i);return c?(u&&u.success?a&&te(r,"success",u.message||"执行成功"):u&&ft.test(String(u.message||""))&&o>0?(i&&console.warn(`[szjy-ui] $bimSandbox 直调失败(${u.message}),${s}ms 后自动重试,剩余 ${o-1} 次`),a&&te(r,"retrying",`${u.message},${Math.round(s/1e3)}s 后自动重试`),setTimeout(()=>{mt(t,n,r,o-1,s,a,i)},s)):a&&te(r,"error",u&&u.message||"执行失败"),!0):!1})()}function jn(t){const n=In(t.config),r=!t.config||t.config.debug!==!1,o=n.feedback!==!1,s=n.retry===!1?{retries:0,delay:2e3}:{retries:2,delay:2e3,...n.retry||{}};if(!t.params||typeof t.params!="object"||Array.isArray(t.params)){console.warn("[szjy-ui] postMessage 动作的 actionParams 必须是对象:",t.params),te(t.triggerEl,"error","参数无效");return}const a={...t.params},i=Pn(n.target,a);if(!i.length){console.warn("[szjy-ui] postMessage 无可用目标窗口,target 配置:",n.target),te(t.triggerEl,"error","无目标窗口");return}const l=n.targetOrigin||"*",c=n.transport||"auto";if(c!=="postMessage"){let u=!1;for(const f of i)if(mt(f,a,t.triggerEl,s.retries,s.delay,o,r)){u=!0;break}if(u)return;if(c==="global"){console.warn("[szjy-ui] transport=global 但 $bimSandbox 全局方法不可用:",{targets:i.map(ge),message:a}),te(t.triggerEl,"error","全局方法不可用");return}r&&console.log("[szjy-ui] $bimSandbox 不可用,回退 postMessage 通道")}a.requestId===void 0&&(a.requestId=`szjy-ui-${Date.now()}-${++Un}`),ht(i,a,l),r&&console.log("[szjy-ui] postMessage 已发送",{message:a,targets:i.map(ge),targetOrigin:l,feedback:o}),o&&(te(t.triggerEl,"loading","已发送"),On(a,i,t.triggerEl,l,s,r))}function In(t){return t&&t.postMessage||{}}function ht(t,n,r){t.forEach(o=>{try{o.postMessage(n,r)}catch(s){console.error("[szjy-ui] postMessage 发送失败:",s)}})}function On(t,n,r,o,s,a){let i=s.retries;const l=s.delay;let c=null;const u=()=>{window.removeEventListener("message",V),c&&(clearTimeout(c),c=null)},f=()=>{c&&clearTimeout(c),c=setTimeout(()=>{u(),a&&console.warn("[szjy-ui] postMessage 超时未收到回执",{message:t,targets:n.map(ge),targetOrigin:o}),te(r,"none","未收到回执")},_n)},V=A=>{const g=A.data;!g||typeof g!="object"||t.type!==void 0&&g.type!==t.type||g.success!==void 0&&(t.requestId!==void 0&&g.requestId!==void 0&&String(g.requestId)!==String(t.requestId)||A.source&&!n.includes(A.source)||(a&&console.log("[szjy-ui] postMessage 收到回执",{requestId:g.requestId,success:g.success,message:g.message,data:g.data,from:ge(A.source)}),g.success?(u(),te(r,"success",g.message||"执行成功")):ft.test(String(g.message||""))&&i>0?(i-=1,a&&console.warn(`[szjy-ui] postMessage 回执失败(${g.message}),${l}ms 后自动重试,剩余 ${i} 次`),te(r,"retrying",`${g.message},${Math.round(l/1e3)}s 后自动重试`),c&&clearTimeout(c),setTimeout(()=>{ht(n,t,o),a&&console.log("[szjy-ui] postMessage 重试已发送",{message:t,targets:n.map(ge),targetOrigin:o}),te(r,"loading","已发送"),f()},l)):(u(),te(r,"error",g.message||"执行失败"))))};window.addEventListener("message",V),f()}function te(t,n,r){if(!t||!t.isConnected)return;const o=t.querySelector(":scope > .szjy-ui-btn__status");t.classList.remove("is-loading","is-success","is-error","is-retrying"),n&&n!=="none"&&t.classList.add(`is-${n}`),o&&(o.textContent=r||"")}at("postMessage",jn);const pt="szjy-ui";function gt(t){if(!t||typeof t!="string")return null;const n=t.trim();if(!n.startsWith("{"))return null;let r;try{r=JSON.parse(n)}catch{return null}return Dn(r)}function Dn(t){return!t||typeof t!="object"||Array.isArray(t)||typeof t.type!="string"||!it(t.type)||t.items!==void 0&&!Array.isArray(t.items)?null:t}function yt(t,n={}){if(!t)return()=>{};const r=o=>{var A;const s=o.target,a=s&&typeof s.closest=="function"?s.closest("[data-szjy-ui-action]"):null;if(!a||!t.contains(a))return;const i=a.getAttribute("data-szjy-ui-action")||"",l=lt(i);if(!l){console.warn(`[szjy-ui] 未注册的动作: ${i}`);return}const c=a.getAttribute("data-szjy-ui-params");let u=null;if(c)try{u=JSON.parse(decodeURIComponent(c))}catch(g){console.error("[szjy-ui] actionParams 解析失败:",g);return}const f=n.getConfig?n.getConfig():null;if(!f||f.debug!==!1){const g=(A=a.querySelector(":scope > .szjy-ui-btn__text"))==null?void 0:A.textContent;console.log("[szjy-ui] 动作触发",{action:i,params:u,text:(g||a.textContent||"").trim().slice(0,40),trigger:a})}const V=n.getInterceptor?n.getInterceptor():null;if(!(V&&V(i,u,a)===!1)){if(n.onAction)try{n.onAction({action:i,params:u,triggerEl:a})}catch(g){console.error("[szjy-ui] onAction 回调执行失败:",g)}l({params:u,config:f,triggerEl:a})}};return t.addEventListener("click",r),()=>{t.removeEventListener("click",r)}}let ie=null;function $n(){return ie||(window.markdownit?(ie=new window.markdownit({html:!0,linkify:!0,typographer:!0}),ie.renderer.rules.fence=(t,n)=>{const r=t[n],o=(r.info||"").trim().split(/\s+/)[0];if(o===pt){const a=gt(r.content),i=a?ut(a):"";if(i)return i}let s="";if(o&&window.hljs&&window.hljs.getLanguage(o))try{s=window.hljs.highlight(r.content,{language:o}).value}catch{s=""}return s||(s=ie.utils.escapeHtml(r.content)),`<pre class="md-code-block"><code class="hljs${o?" language-"+o:""}">${s}</code></pre>`}):console.log("markdownit is not loaded"),ie)}const Fn=(t,n)=>{const r=t.__vccOpts||t;for(const[o,s]of n)r[o]=s;return r},Hn=["src","alt"],Ae=Fn({__name:"SvgIcon",props:{name:{type:String,required:!0},size:{type:[Number,String],default:16},color:{type:String,default:""},className:{type:String,default:""},basePath:{type:String,default:"/icons/"}},setup(t){const n=t,r=e.computed(()=>{if(n.name.startsWith("http://")||n.name.startsWith("https://")||n.name.startsWith("/"))return n.name;const a=n.name.endsWith(".svg")?n.name:`${n.name}.svg`;return`${n.basePath}${a}`}),o=e.computed(()=>{const a=typeof n.size=="number"?`${n.size}px`:n.size;return{width:a,height:a,display:"inline-flex",justifyContent:"center",alignItems:"center"}}),s=e.computed(()=>{const a={width:"100%",height:"100%"};return n.color&&(a.filter=`drop-shadow(0 0 0 ${n.color})`),a});return(a,i)=>(e.openBlock(),e.createElementBlock("div",{class:"svg-icon-wrapper",style:e.normalizeStyle(o.value)},[e.createElementVNode("img",{src:r.value,alt:t.name,class:e.normalizeClass(["svg-icon",t.className]),style:e.normalizeStyle(s.value)},null,14,Hn)],4))}},[["__scopeId","data-v-490b11c1"]]),qn=async t=>{if(navigator.clipboard&&navigator.permissions)await navigator.clipboard.writeText(t);else{const n=document.createElement("textArea");n.value=t,n.style.width=0,n.style.position="fixed",n.style.left="-999px",n.style.top="10px",n.setAttribute("readonly","readonly"),document.body.appendChild(n),n.select(),document.execCommand("copy"),document.body.removeChild(n)}},Wn={class:"thinking-title"},Gn={class:"thinking-toggle-hint"},Jn=["innerHTML"],Kn=["innerHTML"],Yn=10,Xn={__name:"Previewer",props:{reader:null,model:"szjy",scrollToBottomFn:null,displayText:"",messagePostRender:{type:Function,default:null},customUi:{type:Object,default:null},uiActionHandler:{type:Function,default:null}},emits:["failed","started","completed","updating","ui-action"],setup(t,{expose:n,emit:r}){const{appContext:o}=e.getCurrentInstance(),{$message:s}=o.config.globalProperties,a=t,i=e.ref(a.displayText||""),l=e.ref(!0),c=e.ref(!1),u=e.ref(!!a.displayText),f=r,V=e.ref(null);let A=null;e.watch(V,$=>{A&&(A(),A=null),$&&(A=yt($,{getConfig:()=>a.customUi,getInterceptor:()=>a.uiActionHandler,onAction:h=>f("ui-action",h)}))});let g=null;const C=e.computed(()=>En(i.value)),T=e.computed(()=>C.value.thinking.length>0),_=e.ref(a.displayText?C.value.content.length:0),S=e.computed(()=>C.value.isThinkingStreaming&&!u.value),d=e.ref(!1),E=()=>{d.value=!d.value};let y=null,m=null;const B=e.ref(0);e.watch(()=>C.value.thinking,$=>{!$||B.value>0||(m===null&&(m=y??Date.now()),C.value.content&&R())});const R=()=>{if(B.value>0||!T.value)return;const $=m??y;$&&(B.value=Math.max(1,Math.round((Date.now()-$)/1e3)))},O=e.computed(()=>S.value?"正在思考...":B.value>0?`已深度思考(用时 ${B.value} 秒)`:"思考过程"),x=e.computed(()=>T.value?ie?ie.render(C.value.thinking):C.value.thinking:""),M=e.computed(()=>C.value.content.slice(0,_.value)),N=e.computed(()=>ie?ie.render(M.value):M.value),D=()=>{a.reader&&a.reader.cancel(),c.value=!0,G.value=!1,ee(),u.value=!0,R(),f("completed",i.value),l.value=!1,g&&(cancelAnimationFrame(g),g=null)},X=e.computed(()=>`${N.value}`),q=e.ref(!1),Z=()=>{q.value=!0},ee=()=>{q.value=!1},G=e.ref(!1),ne=async()=>{if(!a.reader)return;const $=new TextDecoder("utf-8");for(l.value=!0;!c.value;)try{if(!a.reader){G.value=!0;break}const{value:h,done:L}=await a.reader.read();if(!a.reader){G.value=!0;break}if(L){G.value=!0;break}const I=ot[a.model];if(!I)break;const z=I.call(ot,h,$);if(z.done){G.value=!0;break}!y&&z.content&&(y=Date.now(),f("started")),i.value+=z.content,g===null&&oe()}catch(h){G.value=!0,console.log(3333,h),f("failed",h),D();break}finally{ee()}},re=async()=>{a.scrollToBottomFn&&a.scrollToBottomFn()},ae=($=()=>{},h=()=>{})=>{const L=C.value.content.length;_.value>L&&(_.value=L),_.value<L?(_.value=Math.min(L,_.value+Yn),$()):h()},oe=()=>{if(c.value&&g){cancelAnimationFrame(g),g=null,l.value=!1;return}G.value?ae(()=>{g=requestAnimationFrame(oe),f("updating",null)},()=>{R(),f("completed",i.value),l.value=!1,u.value=!0,e.nextTick(()=>{if(G.value=!1,a.messagePostRender&&V.value)try{a.messagePostRender(V.value,C.value.content)}catch($){console.error("messagePostRender 执行失败:",$)}}),g=null}):(ae(),g=requestAnimationFrame(oe)),re()};e.watch(()=>a.reader,()=>{a.reader&&ne()},{immediate:!0,deep:!0}),e.onUnmounted(()=>{A&&(A(),A=null),D()}),n({abortReader:D,initializeStart:Z,initializeEnd:ee,getRawText:()=>i.value,isAborted:()=>c.value}),e.computed(()=>q.value?!0:(!a.reader||!l||i.value,!1));const fe=async()=>{try{const $=C.value.content||i.value;await qn($),s.success("复制成功")}catch($){console.error("复制失败:",$),s.error("复制失败")}};return($,h)=>(e.openBlock(),e.createBlock(e.Transition,{name:"fade"},{default:e.withCtx(()=>[X.value||T.value?(e.openBlock(),e.createElementBlock("div",{key:0,ref_key:"refWrapperContent",ref:V,"text-16":"",class:"w-full h-full overflow-y-auto relative","p-24px":""},[T.value?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["ai-thinking-block",{"is-expanded":d.value||S.value,"is-streaming":S.value}])},[e.createElementVNode("div",{class:"thinking-header",onClick:E},[h[0]||(h[0]=e.createElementVNode("svg",{class:"thinking-arrow",viewBox:"0 0 1024 1024",width:"10",height:"10"},[e.createElementVNode("path",{d:"M704 512 320 256v512z",fill:"currentColor"})],-1)),e.createElementVNode("span",Wn,e.toDisplayString(O.value),1),e.createElementVNode("span",Gn,e.toDisplayString(d.value||S.value?"收起":"展开"),1)]),e.withDirectives(e.createElementVNode("div",{class:"thinking-body",innerHTML:x.value},null,8,Jn),[[e.vShow,d.value||S.value]])],2)):e.createCommentVNode("",!0),e.createElementVNode("div",{class:"markdown-wrapper",innerHTML:X.value},null,8,Kn),u.value?(e.openBlock(),e.createElementBlock("div",{key:1,class:"ai-copy-btn-wrapper",onClick:fe},[e.createVNode(Ae,{name:"/images/svg/copy.svg",color:"#666666"}),h[1]||(h[1]=e.createElementVNode("span",{class:"copy-text"},"复制",-1))])):e.createCommentVNode("",!0)],512)):e.createCommentVNode("",!0)]),_:1}))}};class kt{constructor(n,r){j(this,"ratio");j(this,"leftover",new Float32Array(0));j(this,"fracOffset",0);this.ratio=n/r}reset(){this.leftover=new Float32Array(0),this.fracOffset=0}process(n){if(this.ratio===1)return new Float32Array(n);const r=new Float32Array(this.leftover.length+n.length);if(r.set(this.leftover),r.set(n,this.leftover.length),r.length<2)return this.leftover=r,new Float32Array(0);const o=[];let s=this.fracOffset;for(;s<r.length-1;){const i=Math.floor(s),l=s-i,c=r[i],u=r[i+1];o.push(c+l*(u-c)),s+=this.ratio}const a=Math.min(r.length,Math.floor(s));return this.leftover=r.slice(a),this.fracOffset=s-a,Float32Array.from(o)}}class wt{constructor(n={}){j(this,"targetSampleRate");j(this,"audioContext",null);j(this,"mediaStream",null);j(this,"sourceNode",null);j(this,"processorNode",null);j(this,"muteGain",null);j(this,"resampler",null);j(this,"audioChunks",[]);j(this,"onVolumeChange");j(this,"onAudioChunk");j(this,"_isRecording",!1);this.targetSampleRate=n.sampleRate||16e3,this.onVolumeChange=n.onVolumeChange,this.onAudioChunk=n.onAudioChunk}get isRecording(){return this._isRecording}async start(){if(this._isRecording)return;if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia)throw new Error("当前浏览器环境不支持获取麦克风音频,请使用现代浏览器并确保在 HTTPS/localhost 环境下运行。");try{this.mediaStream=await navigator.mediaDevices.getUserMedia({audio:{channelCount:{ideal:1},sampleRate:{ideal:this.targetSampleRate},echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0}})}catch(o){throw o.name==="NotAllowedError"||o.name==="PermissionDeniedError"?new Error("麦克风权限被拒绝,请在浏览器地址栏允许麦克风访问权限。"):o.name==="NotFoundError"||o.name==="DevicesNotFoundError"?new Error("未检测到可用的麦克风输入设备。"):new Error(`无法启动麦克风: ${o.message||o}`)}const n=window.AudioContext||window.webkitAudioContext;try{this.audioContext=new n({sampleRate:this.targetSampleRate})}catch{this.audioContext=new n}this.audioContext.state==="suspended"&&await this.audioContext.resume(),this.audioChunks=[],this.resampler=this.audioContext.sampleRate===this.targetSampleRate?null:new kt(this.audioContext.sampleRate,this.targetSampleRate),this.sourceNode=this.audioContext.createMediaStreamSource(this.mediaStream);const r=4096;this.processorNode=this.audioContext.createScriptProcessor(r,1,1),this.processorNode.onaudioprocess=o=>{var i;if(!this._isRecording)return;const s=new Float32Array(o.inputBuffer.getChannelData(0));if(this.onVolumeChange){let l=0;for(let f=0;f<s.length;f++)l+=s[f]*s[f];const c=Math.sqrt(l/s.length),u=Math.min(100,Math.round(c*100*5));this.onVolumeChange(u)}const a=this.resampler?this.resampler.process(s):s;a.length&&(this.audioChunks.push(a),(i=this.onAudioChunk)==null||i.call(this,a))},this.muteGain=this.audioContext.createGain(),this.muteGain.gain.value=0,this.sourceNode.connect(this.processorNode),this.processorNode.connect(this.muteGain),this.muteGain.connect(this.audioContext.destination),this._isRecording=!0}async stop(){if(!this._isRecording)return new Float32Array(0);this._isRecording=!1,this.cleanup();const n=this.audioChunks.reduce((s,a)=>s+a.length,0),r=new Float32Array(n);let o=0;for(const s of this.audioChunks)r.set(s,o),o+=s.length;return this.audioChunks=[],r}cancel(){this._isRecording=!1,this.audioChunks=[],this.cleanup()}cleanup(){this.processorNode&&(this.processorNode.disconnect(),this.processorNode.onaudioprocess=null,this.processorNode=null),this.muteGain&&(this.muteGain.disconnect(),this.muteGain=null),this.sourceNode&&(this.sourceNode.disconnect(),this.sourceNode=null),this.resampler=null,this.mediaStream&&(this.mediaStream.getTracks().forEach(n=>n.stop()),this.mediaStream=null),this.audioContext&&this.audioContext.state!=="closed"&&(this.audioContext.close().catch(()=>{}),this.audioContext=null)}}function St(t,n,r){if(n===r)return new Float32Array(t);const o=n/r,s=Math.round(t.length/o),a=new Float32Array(s);for(let i=0;i<s;i++){const l=i*o,c=Math.floor(l),u=l-c,f=t[c]??0,V=t[c+1]??f;a[i]=f+u*(V-f)}return a}async function bt(t,n=16e3){const r=await t.arrayBuffer(),o=window.AudioContext||window.webkitAudioContext,s=new o;try{const a=await s.decodeAudioData(r);let i;if(a.numberOfChannels>1){i=new Float32Array(a.length);for(let l=0;l<a.numberOfChannels;l++){const c=a.getChannelData(l);for(let u=0;u<a.length;u++)i[u]+=c[u]/a.numberOfChannels}}else i=a.getChannelData(0);return St(i,a.sampleRate,n)}finally{s.state!=="closed"&&await s.close().catch(()=>{})}}function Me(t,n=16e3){const r=new ArrayBuffer(44+t.length*2),o=new DataView(r),s=(i,l)=>{for(let c=0;c<l.length;c++)o.setUint8(i+c,l.charCodeAt(c))};s(0,"RIFF"),o.setUint32(4,36+t.length*2,!0),s(8,"WAVE"),s(12,"fmt "),o.setUint32(16,16,!0),o.setUint16(20,1,!0),o.setUint16(22,1,!0),o.setUint32(24,n,!0),o.setUint32(28,n*2,!0),o.setUint16(32,2,!0),o.setUint16(34,16,!0),s(36,"data"),o.setUint32(40,t.length*2,!0);let a=44;for(let i=0;i<t.length;i++,a+=2){const l=Math.max(-1,Math.min(1,t[i]));o.setInt16(a,l<0?l*32768:l*32767,!0)}return new Blob([o],{type:"audio/wav"})}const Et=16e3,Zn=Math.round(Et*.35),ze="/scripts/ai/whisper.worker.js";function Qn(){return new Worker(je(ze),{type:"module"})}function je(t){return/^https?:\/\//i.test(t)?t:typeof location<"u"?new URL(t,location.origin).href:t}function Ct(t){if(!t.ok)return!1;const n=(t.headers.get("content-type")||"").toLowerCase();return!(n.includes("text/html")||n.includes("application/xhtml+xml"))}async function eo(t){try{const n=await fetch(t,{method:"HEAD"});if(Ct(n))return!0}catch{}try{const n=await fetch(t,{headers:{Range:"bytes=0-64"}});if(Ct(n))return!0}catch{}return!1}async function to(t){const n=[];t&&n.push(je(t)),n.push(je(ze));const r=[...new Set(n.filter(Boolean))];for(const o of r)if(await eo(o))return console.log("[VoiceInputManager] 使用语音 Worker:",o),o;return console.warn("[VoiceInputManager] 未探测到可访问的 Worker 脚本,将回退到 Vite 打包注入地址。已尝试:",r.join(" , ")),null}class vt{constructor(n={}){j(this,"recorder",null);j(this,"worker",null);j(this,"status","idle");j(this,"options");j(this,"isReady",!1);j(this,"initPromise",null);j(this,"currentTaskId",0);j(this,"pcmParts",[]);j(this,"pcmLength",0);j(this,"streamChunkIndex",0);j(this,"committedText","");this.options={soundBaseUrl:"/sounds/",remoteHost:"https://hf-mirror.com",modelId:"onnx-community/whisper-base",language:"chinese",...n}}get currentStatus(){return this.status}get ready(){return this.isReady}async init(n){if(!this.isReady)return this.initPromise?this.initPromise:(n&&(this.options.soundBaseUrl=n),this.initPromise=new Promise((r,o)=>{this.setStatus("loading","正在准备语音识别引擎..."),(async()=>{var a,i;try{const l=await to(this.options.workerUrl);this.worker=l?new Worker(l,{type:"module"}):Qn(),this.worker.onmessage=c=>{this.handleWorkerMessage(c,r,o)},this.worker.onerror=c=>{var V,A;const f=`语音后台线程异常: ${c.message||c.filename||l||"未知错误"}`;this.initPromise=null,this.setStatus("error",f),(A=(V=this.options).onError)==null||A.call(V,f),o(c)},this.worker.postMessage({type:"INIT",data:{modelId:this.options.modelId,soundBaseUrl:this.options.soundBaseUrl,remoteHost:this.options.remoteHost}})}catch(l){const c=`创建语音 Worker 失败: ${l.message||l}`;this.initPromise=null,this.setStatus("error",c),(i=(a=this.options).onError)==null||i.call(a,c),o(l)}})()}),this.initPromise)}async startRecording(){var n,r,o,s;if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){const a=window.isSecureContext?"当前浏览器环境不支持获取麦克风音频,请使用现代浏览器。":"当前页面不是安全上下文,浏览器禁止调用麦克风。请使用 https:// 或 http://localhost / http://127.0.0.1 访问(通过局域网 IP 的 http 地址无法录音)。";throw this.setStatus("error",a),(r=(n=this.options).onError)==null||r.call(n,a),new Error(a)}this.isReady||await this.init(),this.recorder||(this.recorder=new wt({onVolumeChange:a=>{var i,l;(l=(i=this.options).onVolumeChange)==null||l.call(i,a)},onAudioChunk:a=>{this.appendPcm(a)}}));try{this.currentTaskId++,this.resetStreamState(),await this.recorder.start(),this.setStatus("recording","正在录音...")}catch(a){throw this.setStatus("error",a.message||"启动录音失败"),(s=(o=this.options).onError)==null||s.call(o,a.message||"启动录音失败"),a}}async stopAndTranscribe(){var n,r,o,s;if(!(!this.recorder||!this.recorder.isRecording))try{await this.recorder.stop();const a=this.mergePcm();if(a.length===0){this.resetStreamState(),this.setStatus("idle");return}this.setStatus("transcribing","正在识别语音...");try{const i=Me(a),l=URL.createObjectURL(i);(r=(n=this.options).onAudioRecorded)==null||r.call(n,l,i)}catch(i){console.warn("生成录音回放音频失败:",i)}await this.transcribeAudioData(a)}catch(a){this.setStatus("error",a.message||"音频处理失败"),(s=(o=this.options).onError)==null||s.call(o,a.message||"音频处理失败")}}async transcribeAudioData(n,r){var o,s,a,i;this.isReady||await this.init(),this.setStatus("transcribing","正在流式识别音频...");try{r&&((s=(o=this.options).onAudioRecorded)==null||s.call(o,r,Me(n))),this.currentTaskId++,this.resetStreamState(),this.appendPcm(n),this.dispatchFullAudio()}catch(l){this.setStatus("error",l.message||"音频处理失败"),(i=(a=this.options).onError)==null||i.call(a,l.message||"音频处理失败")}}async transcribeFile(n){var r,o;this.isReady||await this.init(),this.setStatus("loading","正在解析音频文件...");try{const s=await bt(n);if(s.length===0)throw new Error("未能从该文件中提取出有效音频");const a=URL.createObjectURL(n);await this.transcribeAudioData(s,a)}catch(s){this.setStatus("error",s.message||"音频文件解析失败"),(o=(r=this.options).onError)==null||o.call(r,s.message||"音频文件解析失败")}}cancelRecording(){var r;const n=this.currentTaskId;this.currentTaskId++,(r=this.worker)==null||r.postMessage({type:"CANCEL",taskId:n}),this.resetStreamState(),this.recorder&&this.recorder.cancel(),this.setStatus("idle")}cancelTranscribe(){var r;const n=this.currentTaskId;this.currentTaskId++,(r=this.worker)==null||r.postMessage({type:"CANCEL",taskId:n}),this.resetStreamState(),(this.status==="transcribing"||this.status==="recording")&&this.setStatus("idle")}async clearCache(){this.worker&&(this.worker.postMessage({type:"CLEAR_CACHE"}),this.isReady=!1,this.initPromise=null)}destroy(){var r;const n=this.currentTaskId;this.currentTaskId++,(r=this.worker)==null||r.postMessage({type:"CANCEL",taskId:n}),this.resetStreamState(),this.recorder&&(this.recorder.cancel(),this.recorder=null),this.worker&&(this.worker.terminate(),this.worker=null),this.isReady=!1,this.initPromise=null,this.setStatus("idle")}resetStreamState(){this.pcmParts=[],this.pcmLength=0,this.streamChunkIndex=0,this.committedText=""}appendPcm(n){!n||n.length===0||(this.pcmParts.push(new Float32Array(n)),this.pcmLength+=n.length)}mergePcm(){const n=new Float32Array(this.pcmLength);let r=0;for(const o of this.pcmParts)n.set(o,r),r+=o.length;return n}emitPartial(n){var r,o;(o=(r=this.options).onPartial)==null||o.call(r,(n||"").trim())}finishStream(n){var o,s;const r=(n??this.committedText).trim();this.setStatus("idle"),(s=(o=this.options).onResult)==null||s.call(o,r)}dispatchFullAudio(){if(!this.worker){this.finishStream();return}if(this.pcmLength<Zn){this.finishStream();return}const n=this.mergePcm(),r=n.length>Et*30;this.committedText="",this.worker.postMessage({type:"TRANSCRIBE",data:{taskId:this.currentTaskId,audio:n,language:this.options.language,stream:!0,chunkIndex:this.streamChunkIndex++,isFinal:!0,mode:"append",nativeChunking:r}},[n.buffer])}handleWorkerMessage(n,r,o){var u,f,V,A;const{type:s,data:a,taskId:i,text:l,error:c}=n.data;switch(s){case"READY":this.isReady=!0,this.setStatus("ready","语音引擎就绪"),r==null||r();break;case"PROGRESS":if(a){const g=typeof a.progress=="number"?Math.round(a.progress):0;this.setStatus("downloading",`正在下载语音模型... ${g}%`),(f=(u=this.options).onProgress)==null||f.call(u,{status:a.status||"progress",progress:g,file:a.file,loaded:a.loaded,total:a.total})}break;case"TRANSCRIBING":if(i&&i!==this.currentTaskId)return;this.status!=="recording"&&this.setStatus("transcribing","正在流式转写文字...");break;case"PARTIAL":if(i&&i!==this.currentTaskId)return;this.committedText=l||"",this.emitPartial(this.committedText);break;case"RESULT":if(i&&i!==this.currentTaskId)return;this.committedText=(l||"").trim()||this.committedText,this.emitPartial(this.committedText),this.finishStream(this.committedText);break;case"CACHE_CLEARED":this.setStatus("idle","语音模型缓存已清空");break;case"ERROR":if(i&&i!==this.currentTaskId)return;this.setStatus("error",c||"语音服务异常"),(A=(V=this.options).onError)==null||A.call(V,c||"语音服务异常"),o==null||o(new Error(c));break}}setStatus(n,r){var o,s;this.status=n,(s=(o=this.options).onStatusChange)==null||s.call(o,n,r)}}const de=16e3,Ie=.015,At=.25,Tt=2e3,Oe=3e4,Nt=250,De=350,Vt=.25,Bt=900,Rt=.5,_t=12,$e=1024,Lt=260,xt=600,Ut=80,Fe=28,Te="/api/voice",no={filterLength:256,delay:64,step:.1,epsilon:1e-6},oo=256,ro=64,ao=.1,so=1e-6;class Pt{constructor(n={}){j(this,"w");j(this,"xBuf");j(this,"filterLength");j(this,"delay");j(this,"mu");j(this,"eps");j(this,"cursor",0);j(this,"filled",0);this.filterLength=n.filterLength??oo,this.delay=n.delay??ro,this.mu=n.step??ao,this.eps=n.epsilon??so,this.w=new Float32Array(this.filterLength),this.xBuf=new Float32Array(this.delay+this.filterLength)}process(n,r){const o=n.length,s=new Float32Array(o);if(o===0)return s;const a=this.xBuf,i=a.length;let l=this.cursor;for(let c=0;c<o;c++){a[l]=c<r.length?r[c]:0,l=(l+1)%i,this.filled=Math.min(this.filled+1,i);const u=n[c];if(this.filled>=this.delay+this.filterLength){let f=0,V=0,A=(l-this.delay+i)%i;for(let _=0;_<this.filterLength;_++){const S=a[A];f+=this.w[_]*S,V+=S*S,A=(A-1+i)%i}const g=u-f;s[c]=g;const C=V+this.eps,T=this.mu*g/C;A=(l-this.delay+i)%i;for(let _=0;_<this.filterLength;_++)this.w[_]+=T*a[A],A=(A-1+i)%i}else s[c]=u}return this.cursor=l,s}reset(){this.w.fill(0),this.xBuf.fill(0),this.cursor=0,this.filled=0}}const we=(t,n)=>`${t.replace(/\/+$/,"")}${n}`;function Mt(t=Te,n={}){return fetch(we(t,"/ready"),{headers:n}).then(r=>r.json())}function zt(t=Te,n={}){return fetch(we(t,"/config"),{headers:n}).then(r=>r.json())}function io(t,n={},r,o){const s={"content-type":"application/octet-stream",...n};return o!==void 0&&(s["x-voice-session"]=o),fetch(we(t,"/asr"),{method:"POST",headers:s,body:r.slice().buffer}).then(async a=>{if(!a.ok)throw new Error(`asr http ${a.status}`);return await a.json()})}function He(t,n={},r){return fetch(we(t,"/cancel"),{method:"POST",headers:{"content-type":"application/json",...n},body:JSON.stringify({sessionId:r})}).then(async o=>{if(!o.ok)throw new Error(`cancel http ${o.status}`);return await o.json()})}function jt(t,n={},r,o){const s=we(t,"/stream");if(!(Object.keys(n).length>0)){const C=new EventSource(s);return C.onopen=()=>o({connected:!0}),C.onerror=()=>o({connected:!1}),C.addEventListener("audio",T=>{try{r(JSON.parse(T.data))}catch{}}),{close:()=>C.close()}}let i=!1,l=null,c=null,u="";const f=()=>{i||c!==null||(c=setTimeout(()=>{c=null,g()},3e3))},V=(C,T)=>{if(C==="audio")try{r(JSON.parse(T))}catch{}},A=()=>{let C;for(;(C=u.indexOf(`
|
|
4
|
+
|
|
5
|
+
`))!==-1;){const T=u.slice(0,C);u=u.slice(C+2);let _="message";const S=[];for(const d of T.split(`
|
|
6
|
+
`))d.startsWith(":")||(d.startsWith("event:")?_=d.slice(6).trim():d.startsWith("data:")&&S.push(d.slice(5).trimStart()));S.length>0&&V(_,S.join(`
|
|
7
|
+
`))}},g=async()=>{if(!i){l=new AbortController;try{const C=await fetch(s,{headers:n,signal:l.signal});if(!C.ok||!C.body)throw new Error(`stream http ${C.status}`);o({connected:!0});const T=C.body.getReader(),_=new TextDecoder;for(;;){const{done:S,value:d}=await T.read();if(S)break;u+=_.decode(d,{stream:!0}),A()}}catch{}i||(o({connected:!1}),f())}};return g(),{close:()=>{i=!0,c!==null&&clearTimeout(c);try{l==null||l.abort()}catch{}}}}function It(t,n){const{asrUrl:r,getHeaders:o,getEchoReference:s}=n;let a="idle";const i=new Set,l=new Set,c=new Set,u=new Set,f=new Set;let V=!1,A=null,g=null,C=null,T=!1,_=!1,S=!1,d=[],E=[],y=0,m=0,B=!1,R=0,O=!1,x=0,M=null,N=0,D="";const X=()=>typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`p-${Date.now()}-${Math.random().toString(36).slice(2)}`,q=h=>{a=h;for(const L of i)try{L(h)}catch{}},Z=h=>{const L=h.trim();if(L)for(const I of l)try{I(L)}catch{}},ee=()=>{const h=new Float32Array(d.reduce((I,z)=>I+z.length,0));let L=0;for(const I of d)h.set(I,L),L+=I.length;return h},G=async()=>{if(O||f.size===0||d.length===0)return;const h=d.reduce((P,J)=>P+J.length,0)/de;if(h<Rt||h>_t)return;const L=ee();if(L.length<=N)return;const I=L.subarray(N);N=L.length;const z=x;O=!0;const W=new AbortController;M=W;try{const P=await fetch(r,{method:"POST",headers:{"content-type":"application/octet-stream",...(o==null?void 0:o())??{},"x-voice-session":D,"x-dsh-session":D},body:I.slice().buffer,signal:W.signal});if(!P.ok)return;const J=await P.json();if(z!==x)return;const k=(J.text??"").trim();if(!k)return;for(const v of f)try{v(k)}catch{}}catch{}finally{O=!1,M===W&&(M=null)}},ne=async h=>{if(!V){V=!0,q("transcribing");try{const L=h.slice().buffer,I=await fetch(r,{method:"POST",headers:{"content-type":"application/octet-stream",...(o==null?void 0:o())??{}},body:L});if(!I.ok)throw new Error(`asr http ${I.status}`);const z=await I.json();z.text&&Z(z.text)}catch(L){console.warn(`[voice] transcription failed: ${String(L)}`)}finally{V=!1,q(T?S?"speech":"recording":"idle")}}},re=()=>{if(d.length===0)return;const h=ee();d=[],S=!1,y=0,m=0,ne(h)},ae=()=>{const h=Math.floor(De/1e3*de);h>0&&d.push(new Float32Array(h)),re()},oe=h=>{if(!T||B)return;let L=0;for(let P=0;P<h.length;P++)L+=h[P]*h[P];const I=Math.sqrt(L/h.length),z=h.length/de*1e3,W=Math.min(1,I/At);for(const P of u)try{P(W)}catch{}if(_){if(!S&&I>Ie){S=!0,q("speech");for(const P of c)try{P()}catch{}}if(m+=z,d.push(h),m>Oe){ae();return}R+=z,R>=Bt&&(R=0,G());return}if(I>Ie){if(!S){S=!0,q("speech");for(const P of c)try{P()}catch{}for(const P of E)d.push(P);E=[]}m+=z,y=0,d.push(h),m>Oe&&ae()}else if(S)m+=z,y+=z,d.push(h),y>Tt&&ae();else{E.push(h);const P=Nt;let J=0,k=0;for(let v=E.length-1;v>=0;v--)if(J+=E[v].length/de*1e3,J>P){k=v+1;break}k>0&&(E=E.slice(k))}},fe=async()=>{var I;if(T)return;const h=((I=s==null?void 0:s())==null?void 0:I.node)??null;g=await navigator.mediaDevices.getUserMedia({audio:{channelCount:1,echoCancellation:h===null,noiseSuppression:!0,autoGainControl:!0}}),A=new AudioContext({sampleRate:de}),await A.resume().catch(()=>{});const L=A.createMediaStreamSource(g);if(h===null)C=A.createScriptProcessor($e,1,1),C.onaudioprocess=z=>{const W=z.inputBuffer.getChannelData(0);oe(new Float32Array(W))},L.connect(C);else{const z=new Pt({});C=A.createScriptProcessor($e,2,1),C.onaudioprocess=W=>{const P=W.inputBuffer.getChannelData(0),J=W.inputBuffer.getChannelData(1);oe(z.process(P,J))},L.connect(C,0,0),h.connect(C,0,1)}C.connect(A.destination),T=!0},$=async(h=!1)=>{if(!T)return;T=!1,B=!0,x++,R=0;try{M==null||M.abort()}catch{}M=null;const L=_;_=!1;try{if(h?!1:L?d.length>0:S){const z=d.reduce((W,P)=>W+P.length,0)/de;if(!L||z>=Vt){const W=Math.floor(De/1e3*de);d.push(new Float32Array(W)),re()}else d=[]}else d=[];S=!1,y=0,m=0,E=[]}finally{B=!1}try{C==null||C.disconnect()}catch{}C=null,N=0,D="";try{g==null||g.getTracks().forEach(I=>I.stop())}catch{}g=null;try{await(A==null?void 0:A.close())}catch{}A=null};return{get state(){return a},async start(h){if(!T){_=(h==null?void 0:h.hold)===!0,x++,R=0,N=0,D=X(),q("recording");try{await fe()}catch(L){throw _=!1,q("idle"),L}}},async stop(){if(!T){q("idle");return}await $(),V||q("idle")},async cancel(){await $(!0),q("idle")},onSegment(h){return l.add(h),()=>{l.delete(h)}},onState(h){return i.add(h),h(a),()=>{i.delete(h)}},onSpeechStart(h){return c.add(h),()=>{c.delete(h)}},onLevel(h){return u.add(h),()=>{u.delete(h)}},onPartial(h){return f.add(h),()=>{f.delete(h)}}}}function Ot(t){const n=t instanceof DOMException?t.name:"",r=t instanceof Error?t.message:String(t);switch(n){case"NotAllowedError":case"SecurityError":return"麦克风被拒绝:请在浏览器地址栏的权限设置里允许麦克风";case"NotFoundError":case"OverconstrainedError":return"找不到麦克风设备:请检查系统输入设备";case"NotReadableError":return"麦克风被其他程序占用";default:return r?`麦克风不可用:${r}`:"麦克风不可用"}}function lo(t){const n=atob(t),r=new Uint8Array(n.length);for(let s=0;s<n.length;s++)r[s]=n.charCodeAt(s);const o=r[0]===82&&r[1]===73&&r[2]===70&&r[3]===70;return URL.createObjectURL(new Blob([r],{type:o?"audio/wav":"audio/mpeg"}))}function Dt(t){const n=new Set;let r={connected:!1,playing:!1,caption:null};const o=[],s=$t();let a=null;const i=()=>{for(const f of n)f(r)},l=f=>{r={...r,...f},i()},c=()=>{const f=o.shift();if(!f){l({playing:!1,caption:null});return}co();const V=lo(f.audio);s.src=V,s.onended=()=>{URL.revokeObjectURL(V),c()},s.onerror=()=>{URL.revokeObjectURL(V),c()},l({playing:!0,caption:f.text}),s.play().catch(()=>{l({playing:!1})})},u=f=>{f.sessionId===t.getSessionId()&&f.audio&&(o.push(f),s.paused&&c())};return{connect(){var f;a===null&&(a=jt(t.streamUrl,((f=t.getHeaders)==null?void 0:f.call(t))??{},u,V=>l({connected:V.connected})))},skip(){o.length=0,s.pause(),s.onended=null,s.onerror=null,l({playing:!1,caption:null})},subscribe(f){return n.add(f),f(r),()=>{n.delete(f)}},getEchoReference(){return be?{node:be}:null}}}let qe=null;function $t(){return qe===null&&(qe=typeof Audio<"u"?new Audio:{}),qe}let Se=null,be=null;function co(){if(Se===null){Se=new AudioContext;const t=$t();be===null&&(be=Se.createMediaElementSource(t),be.connect(Se.destination))}return Se}const We=Symbol("szjy-voice");function Ge(){const t=e.inject(We);if(!t)throw new Error("useVoiceContext() 必须在 useVoice() 所在组件的子树中调用");return t}function Ft(t){const n=e.ref("idle"),r=e.ref(null),o=e.shallowRef(null),s=e.shallowRef(null),a=e.ref(null),i=()=>{var d;return((d=t.getAuthHeaders)==null?void 0:d.call(t))??{}},l=()=>e.toValue(t.sessionId),c=()=>e.toValue(t.running)===!0;let u=!1;const f=()=>{u=!0},V=()=>{var d;(d=s.value)==null||d.skip(),He(g(),i(),l()).catch(()=>{})};let A=t.apiBase??Te;const g=()=>A;let C=!1;(async()=>{try{const d=await Mt(g(),i());if(C)return;if(d.protocolVersion!==void 0&&d.protocolVersion!==1){r.value="语音协议不兼容";return}if(d.modelReady!==void 0&&d.modelReady===!1){r.value="语音模型未就绪";return}const E=await zt(g(),i());if(C)return;A=t.apiBase??E.basePath??A,a.value=E.asr;const y=Dt({streamUrl:g(),getHeaders:i,getSessionId:l});s.value=y,y.connect();const m=It(E.asr,{asrUrl:`${g()}/asr`,getHeaders:i,getEchoReference:()=>y.getEchoReference()});m.onState(B=>{n.value=B}),m.onSpeechStart(()=>{y.skip(),He(g(),i(),l()).catch(()=>{}),c()&&t.onCancelTurn()}),m.onSegment(B=>{const R=B.trim();if(!R)return;t.onTranscript(R);const O=u||E.asr.autoSend;u=!1,O&&setTimeout(()=>{try{t.onSubmit()}catch{}},60)}),o.value=m}catch(d){C||(r.value=`语音服务不可用:${d instanceof Error?d.message:String(d)}`)}})();const T=()=>{var d,E;C=!0,(d=o.value)==null||d.stop(),o.value=null,(E=s.value)==null||E.skip(),s.value=null};e.onUnmounted(T);const _=(d,E=!1)=>{!d&&!E||fetch(`${g()}/speak`,{method:"POST",headers:{"content-type":"application/json",...i()},body:JSON.stringify({sessionId:l(),text:d,final:E})}).catch(()=>{})},S={engine:o,playback:s,config:a,asrState:n,error:r,requestSubmitOnNextSegment:f,skipPlayback:V,speak:_};return e.provide(We,S),{asrState:n,error:r,dispose:T,speak:_}}const uo={class:"szjyv-ptt-backdrop"},fo={key:0,class:"szjyv-ptt-caret"},mo={class:"szjyv-kbd"},Ht=e.defineComponent({__name:"VoiceOverlay",props:{levels:{},armedCancel:{type:Boolean},pending:{type:Boolean},partial:{},source:{},hotkey:{}},setup(t){const n=t,r=e.computed(()=>n.armedCancel?"#f85149":"#2ea043"),o=e.computed(()=>Array.from({length:Fe},(a,i)=>n.levels[i]??0)),s=e.computed(()=>{const a=n.hotkey,i=typeof navigator<"u"&&/Mac|iP(hone|ad|od)/.test(navigator.platform??"");switch(a){case"Control":return i?"⌃":"Ctrl";case"Alt":return i?"⌥":"Alt";case"Meta":return i?"⌘":"Win";case"Shift":return"Shift";case" ":return"Space";default:return a}});return(a,i)=>(e.openBlock(),e.createElementBlock("div",uo,[e.createElementVNode("div",{class:e.normalizeClass(["szjyv-ptt-card",{cancel:t.armedCancel}])},[e.createElementVNode("div",{class:e.normalizeClass(["szjyv-ptt-wave",{frozen:t.pending}])},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(o.value,(l,c)=>(e.openBlock(),e.createElementBlock("span",{key:c,class:"szjyv-ptt-bar",style:e.normalizeStyle({height:`${3+l*37}px`,background:r.value,opacity:.45+l*.55})},null,4))),128))],2),t.partial&&!t.armedCancel?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["szjyv-ptt-live",{stale:t.pending}])},[e.createTextVNode(e.toDisplayString(t.partial)+" ",1),t.pending?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("span",fo))],2)):e.createCommentVNode("",!0),e.createElementVNode("div",{class:"szjyv-ptt-hint",style:e.normalizeStyle({color:t.armedCancel?"#f85149":"#8b949e"})},[t.pending?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[i[0]||(i[0]=e.createElementVNode("span",{class:"szjyv-spin szjyv-ptt-spinner"},null,-1)),i[1]||(i[1]=e.createTextVNode(" 识别中… ",-1))],64)):t.armedCancel?(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[e.createTextVNode("松开手指 取消发送")],64)):t.source==="key"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:2},[i[2]||(i[2]=e.createTextVNode(" 松开 ",-1)),e.createElementVNode("span",mo,e.toDisplayString(s.value),1),i[3]||(i[3]=e.createTextVNode(" 发送 · ",-1)),i[4]||(i[4]=e.createElementVNode("span",{class:"szjyv-kbd"},"Esc",-1)),i[5]||(i[5]=e.createTextVNode(" 取消 ",-1))],64)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:3},[e.createTextVNode("松开发送 · 上滑取消")],64))],4)],2)]))}}),Je=e.defineComponent({__name:"EqualizerBars",props:{color:{},height:{}},setup(t){return(n,r)=>(e.openBlock(),e.createElementBlock("span",{class:"szjyv-eq",style:e.normalizeStyle({height:`${t.height}px`})},[(e.openBlock(),e.createElementBlock(e.Fragment,null,e.renderList(3,o=>e.createElementVNode("span",{key:o,style:e.normalizeStyle({background:t.color,animationDelay:`${(o-1)*.18}s`})},null,4)),64))],4))}}),ho={key:1,class:"szjyv-toast"},po=["title"],go={key:2,class:"szjyv-mic-icon",viewBox:"0 0 24 24",width:"17",height:"17",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round","aria-hidden":"true"},yo=["stroke"],ko={key:4,class:"szjyv-mic-label"},qt=e.defineComponent({__name:"VoiceMicButton",setup(t){const n=Ge(),r=n.asrState,o=e.ref(null),s={idle:"voice: 待识别(点按说话)",recording:"voice: 录音中…",speech:"voice: 说话中…",transcribing:"voice: 识别中…","loading-model":"voice: 模型加载中…"},a={idle:"#8b949e",recording:"#f85149",speech:"#2ea043",transcribing:"#58a6ff","loading-model":"#bc8cff"},i=e.ref(!1),l=e.ref(!1),c=e.ref([]),u=e.ref(""),f=e.ref(!1),V=e.ref("pointer"),A=e.ref(""),g=e.ref(null),C=e.ref(null),T=e.ref(null),_=e.ref(0),S=e.ref(!1),d=e.ref(!1),E=e.ref(!1);e.watch(()=>n.config.value,k=>{A.value=(k==null?void 0:k.hotkey)??""},{immediate:!0});const y=e.computed(()=>r.value==="transcribing"||r.value==="loading-model"),m=e.computed(()=>{var k;return o.value?"voice error":r.value==="idle"?"mic":((k=s[r.value])==null?void 0:k.replace("voice: ",""))??"mic"}),B=e.computed(()=>{if(o.value)return o.value;const k=A.value?`;也可长按 ${R(A.value)}`:"";return`${s[r.value]??""}(长按说话,松开发送${k})`});function R(k){const v=typeof navigator<"u"&&/Mac|iP(hone|ad|od)/.test(navigator.platform??"");switch(k){case"Control":return v?"⌃":"Ctrl";case"Alt":return v?"⌥":"Alt";case"Meta":return v?"⌘":"Win";case"Shift":return"Shift";case" ":return"Space";default:return k}}e.watch(()=>n.error.value,k=>{k!==null&&o.value===null&&(o.value=k)},{immediate:!0}),e.watch(o,k=>{k!==null&&setTimeout(()=>{o.value===k&&(o.value=null)},4e3)});const O=async()=>{const k=n.engine.value;if(k){if(E.value){E.value=!1;return}o.value=null;try{k.state==="idle"?await k.start():await k.stop()}catch(v){o.value=v instanceof Error?v.message:String(v)}}};e.watch(i,k=>{const v=n.engine.value;if(!k||!v)return;c.value=[];const F=v.onLevel(le=>{c.value=c.value.length<Fe?[...c.value,le]:[...c.value.slice(1),le]});u.value="";const K=v.onPartial(le=>{u.value=le}),Q=v.onSegment(()=>{f.value=!1,u.value=""});x=()=>{F(),K(),Q()}});let x=null;e.watch(i,(k,v)=>{!k&&v&&x&&(x(),x=null)}),e.watch([f,r],([k,v])=>{if(!k||v==="transcribing"||v==="loading-model")return;setTimeout(()=>{f.value=!1,u.value=""},v==="idle"?220:12e3)});const M=k=>{if(T.value&&(clearTimeout(T.value),T.value=null),!d.value){C.value=null;return}d.value=!1,C.value=null,E.value=!0,i.value=!1,l.value=!1,S.value=!1;const v=n.engine.value;if(k){u.value="",f.value=!1,v==null||v.cancel();return}f.value=!0,n.requestSubmitOnNextSegment(),v==null||v.stop()},N=(k,v,F="pointer",K=Lt)=>{n.engine.value!==null&&(T.value&&clearTimeout(T.value),_.value=k,C.value=F,v==null||v(),T.value=setTimeout(()=>{var Q;T.value=null,d.value=!0,V.value=F,i.value=!0,f.value=!1,u.value="",o.value=null,(Q=n.engine.value)==null||Q.start({hold:!0}).catch(le=>{o.value=Ot(le),d.value=!1,C.value=null,i.value=!1})},K))},D=k=>{if(!d.value||C.value==="key")return;const v=_.value-k>Ut;v!==S.value&&(S.value=v,l.value=v)},X=k=>{N(k.clientY,()=>{try{k.currentTarget.setPointerCapture(k.pointerId)}catch{}})},q=k=>D(k.clientY),Z=()=>{C.value!=="key"&&M(S.value)},ee=()=>{C.value!=="key"&&M(!0)},G=()=>{const k=g.value;if(!k)return null;let v=k.parentElement;for(let F=0;v&&F<4;F++){const K=Array.from(v.querySelectorAll("button")).filter(Q=>Q!==k&&!k.contains(Q));if(K.length>0)return K[K.length-1];v=v.parentElement}return null},ne=e.ref(G);ne.value=G;let re=!1;const ae=k=>{const v=ne.value();if(!v)return;const F=v.getBoundingClientRect();k.clientX>=F.left&&k.clientX<=F.right&&k.clientY>=F.top&&k.clientY<=F.bottom&&W.value(k.clientY)},oe=k=>J.value(k.clientY),fe=()=>{C.value!=="key"&&P.value(S.value)},$=()=>{C.value!=="key"&&P.value(!0)},h=k=>{if(!E.value)return;const v=ne.value(),F=k.target;!v||!F||!(v===F||v.contains(F))||(E.value=!1,k.preventDefault(),k.stopImmediatePropagation())},L=k=>{const v=A.value;if(v){if(C.value!==null){if(k.key===v||C.value==="pointer"&&k.key!=="Escape")return;P.value(!0);return}k.key!==v||k.repeat||k.isComposing||W.value(0,void 0,"key",xt)}},I=k=>{C.value==="key"&&k.key===A.value&&P.value(!1)},z=()=>{C.value==="key"&&P.value(!0)},W=e.ref(N);W.value=N;const P=e.ref(M);P.value=M;const J=e.ref(D);return J.value=D,e.onMounted(()=>{re||(window.addEventListener("pointerdown",ae),window.addEventListener("pointermove",oe),window.addEventListener("pointerup",fe),window.addEventListener("pointercancel",$),window.addEventListener("click",h,!0),window.addEventListener("keydown",L),window.addEventListener("keyup",I),window.addEventListener("blur",z))}),e.onUnmounted(()=>{re=!0,window.removeEventListener("pointerdown",ae),window.removeEventListener("pointermove",oe),window.removeEventListener("pointerup",fe),window.removeEventListener("pointercancel",$),window.removeEventListener("click",h,!0),window.removeEventListener("keydown",L),window.removeEventListener("keyup",I),window.removeEventListener("blur",z),T.value&&clearTimeout(T.value),x==null||x()}),(k,v)=>(e.openBlock(),e.createElementBlock(e.Fragment,null,[i.value||f.value?(e.openBlock(),e.createBlock(Ht,{key:0,levels:c.value,"armed-cancel":l.value,pending:f.value,partial:u.value,source:V.value,hotkey:A.value},null,8,["levels","armed-cancel","pending","partial","source","hotkey"])):e.createCommentVNode("",!0),o.value?(e.openBlock(),e.createElementBlock("div",ho,e.toDisplayString(o.value),1)):e.createCommentVNode("",!0),e.createElementVNode("button",{ref_key:"anchorRef",ref:g,class:"szjyv-mic",title:B.value,onClick:O,onPointerdown:X,onPointermove:v[0]||(v[0]=F=>q(F)),onPointerup:Z,onPointercancel:ee},[y.value?(e.openBlock(),e.createElementBlock("span",{key:0,class:"szjyv-spin szjyv-mic-spinner",style:e.normalizeStyle({borderTopColor:a[e.unref(r)]})},null,4)):e.unref(r)==="speech"?(e.openBlock(),e.createBlock(Je,{key:1,color:"#2ea043",height:11})):e.unref(r)==="idle"&&!i.value?(e.openBlock(),e.createElementBlock("svg",go,[e.createElementVNode("path",{d:"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z",stroke:o.value?"#f85149":"#57606a",fill:"currentColor","fill-opacity":"0.15"},null,8,yo),v[1]||(v[1]=e.createElementVNode("path",{d:"M19 10v2a7 7 0 0 1-14 0v-2"},null,-1)),v[2]||(v[2]=e.createElementVNode("line",{x1:"12",y1:"19",x2:"12",y2:"22"},null,-1))])):(e.openBlock(),e.createElementBlock("span",{key:3,class:e.normalizeClass(["szjyv-mic-dot",{pulse:e.unref(r)==="recording"&&!o.value}]),style:e.normalizeStyle({background:o.value?"#f85149":a[e.unref(r)]})},null,6)),i.value||m.value!=="mic"?(e.openBlock(),e.createElementBlock("span",ko,e.toDisplayString(i.value?l.value?"松开取消":"松开发送":m.value),1)):e.createCommentVNode("",!0)],40,po)],64))}}),wo={class:"szjyv-captionbar"},Wt=e.defineComponent({__name:"VoiceCaptionBar",setup(t){const n=Ge(),r=e.reactive({connected:!1,playing:!1,caption:null});let o=null;const s=e.watch(()=>n.playback.value,c=>{!c||o||(o=c.subscribe(u=>Object.assign(r,u)))},{immediate:!0});e.onUnmounted(()=>{s(),o==null||o()});const a=e.computed(()=>r.connected&&r.playing),i=e.computed(()=>a.value?"#2ea043":r.connected?"#8b949e":"#f85149"),l=()=>{n.skipPlayback()};return(c,u)=>(e.openBlock(),e.createElementBlock("div",wo,[a.value?(e.openBlock(),e.createBlock(Je,{key:0,color:"#2ea043",height:13})):(e.openBlock(),e.createElementBlock("span",{key:1,class:e.normalizeClass(["szjyv-caption-dot",{offline:!r.connected}]),style:e.normalizeStyle({background:i.value})},null,6)),(e.openBlock(),e.createElementBlock("span",{key:r.caption??"idle",class:"szjyv-caption-text"},e.toDisplayString(r.caption??(r.connected?"voice ready":"voice offline")),1)),r.playing?(e.openBlock(),e.createElementBlock("button",{key:2,class:"szjyv-skip",onClick:l},"skip")):e.createCommentVNode("",!0)]))}}),So={class:"panel-header"},bo={class:"header-actions"},Eo={class:"header-title"},Co={class:"action-icons"},vo={class:"body-content"},Ao={key:0,class:"welcome-content"},To={class:"subtitle"},No={class:"highlight"},Vo={class:"quick-questions"},Bo=["onClick"],Ro={key:1,class:"message-content user-content"},_o={key:0,class:"ai-thinking-indicator"},Lo={key:1,class:"ai-failed-tip"},xo={class:"panel-footer"},Uo={key:0,class:"voice-progress-banner"},Po={class:"progress-info"},Mo={class:"progress-text"},zo={key:0,class:"progress-percent"},jo={key:0,class:"progress-track"},Io={class:"recording-main"},Oo={class:"recording-status"},Do={key:0,class:"recording-time"},$o={class:"recording-hint"},Fo={key:1,class:"volume-waves"},Ho={class:"recording-actions"},qo=["title"],Wo={key:0,class:"voice-playback-bar"},Go=["title"],Jo={class:"playback-play-icon"},Ko={key:0,viewBox:"0 0 24 24",width:"14",height:"14",fill:"currentColor"},Yo={key:1,viewBox:"0 0 24 24",width:"14",height:"14",fill:"currentColor"},Xo={class:"playback-title"},Zo={key:0,class:"playback-time"},Qo={key:1,class:"playback-waves"},er={class:"input-box"},tr={class:"input-actions-box"},nr=["src"],Gt={__name:"ChatPanel",props:{modelValue:{type:Boolean,default:!1},token:{type:String,default:""},identifier:{type:String,default:""},baseUrl:{type:String,default:""},title:{type:String,default:"数智AI助理"},llmName:{type:String,default:"szjy"},messagePostRender:{type:Function,default:null},extraConfig:{type:Object,default:()=>({})},soundBaseUrl:{type:String,default:"/sounds/"},workerUrl:{type:String,default:""},enableVoiceInput:{type:Boolean,default:!1},enableDuplexVoice:{type:Boolean,default:!1},voiceApiBase:{type:String,default:""},enableVoiceTts:{type:Boolean,default:!1},enableVoiceUpload:{type:Boolean,default:!1},embedded:{type:Boolean,default:!1},customUi:{type:Object,default:null},uiActionHandler:{type:Function,default:null},mockResponse:{type:String,default:""}},emits:["update:modelValue","submit","ui-action"],setup(t,{emit:n}){const{appContext:r}=e.getCurrentInstance(),{$message:o}=r.config.globalProperties,s=t;let a=null;const i=e.ref("idle"),l=e.ref(""),c=e.ref(0),u=e.ref(0),f=e.ref(0);let V=null;const A=e.ref(""),g=e.ref(!1),C=e.ref(0);let T=null;const _=e.ref(""),S=e.ref(""),d=e.computed(()=>i.value==="downloading"),E=e.computed(()=>i.value==="loading"),y=e.computed(()=>i.value==="recording"),m=e.computed(()=>i.value==="transcribing"),B=e.computed(()=>y.value?"正在录音,点击完成后开始识别":_.value?"正在流式转写...":"正在识别语音中..."),R=e.computed(()=>s.enableVoiceInput?"请输入您的问题或点击麦克风语音输入":s.enableVoiceUpload?"请输入您的问题或上传音频识别":"请输入您的问题"),O=(w,b)=>{const U=(w||"").trim(),H=(b||"").trim();return H?U?/[A-Za-z0-9]$/.test(U)&&/[A-Za-z0-9]/.test(H.charAt(0))?`${U} ${H}`:`${U}${H}`:H:U},x=w=>{const b=Math.floor(w/60),U=w%60;return`${b.toString().padStart(2,"0")}:${U.toString().padStart(2,"0")}`},M=()=>(a||(a=new vt({soundBaseUrl:s.soundBaseUrl||"/sounds/",workerUrl:s.workerUrl||void 0,onStatusChange:(w,b)=>{i.value=w,b&&(l.value=b)},onProgress:w=>{typeof w.progress=="number"&&(c.value=w.progress)},onVolumeChange:w=>{u.value=w},onAudioRecorded:w=>{A.value&&URL.revokeObjectURL(A.value),A.value=w,C.value=f.value},onPartial:w=>{_.value=w||"",h.value=O(S.value,w)},onResult:w=>{_.value=w||"",h.value=O(S.value,w),w?o.success("语音识别完成"):o.warning("未能识别出有效语音,请重试"),setTimeout(()=>{_.value="",L.value&&L.value.focus()},100)},onError:w=>{o.error(w||"语音输入服务出错"),D()}})),a),N=()=>{D(),f.value=0,V=setInterval(()=>{f.value+=1},1e3)},D=()=>{V&&(clearInterval(V),V=null)},X=async()=>{if(!s.enableVoiceInput)return;if(y.value){await q();return}g.value&&T&&(T.pause(),g.value=!1);const w=M();try{S.value=h.value,_.value="",N(),await w.startRecording()}catch(b){D(),console.error("启动录音失败:",b)}},q=async()=>{D(),a&&await a.stopAndTranscribe()},Z=e.ref(null),ee=()=>{s.enableVoiceUpload&&Z.value&&(Z.value.value="",Z.value.click())},G=async w=>{var se;if(!s.enableVoiceUpload)return;const b=w.target,U=(se=b==null?void 0:b.files)==null?void 0:se[0];if(!U)return;g.value&&T&&(T.pause(),g.value=!1);const H=M();try{S.value=h.value,_.value="",o.info(`正在流式识别文件: ${U.name}`),await H.transcribeFile(U)}catch(Y){o.error(`文件识别失败: ${Y.message||Y}`)}},ne=()=>{D(),_.value="",h.value=S.value,a&&a.cancelRecording()},re=()=>{_.value="",h.value=S.value,a&&a.cancelTranscribe(),o.info("已取消本次语音识别")},ae=()=>{if(A.value){if(g.value&&T){T.pause(),g.value=!1;return}T&&(T.pause(),T=null),T=new Audio(A.value),T.onloadedmetadata=()=>{T&&!isNaN(T.duration)&&(C.value=Math.round(T.duration))},T.onended=()=>{g.value=!1},T.onerror=()=>{g.value=!1,o.error("音频试听播放失败")},T.play().then(()=>{g.value=!0}).catch(w=>{console.error("音频播放出错:",w),g.value=!1})}},oe=()=>{T&&(T.pause(),T=null),g.value=!1,A.value&&(URL.revokeObjectURL(A.value),A.value="")};e.onBeforeUnmount(()=>{D(),oe(),a&&(a.destroy(),a=null)});const fe=e.computed(()=>nt.find(w=>w.modelName===s.llmName)??nt.find(w=>w.modelName==="szjy")),$=n,h=e.ref(""),L=e.ref(null),I=e.ref(!1),z=e.ref([]),W=e.ref(["什么是AI助理,能做什么?","当前项目的基本情况?","当前项目的进度情况?","当前项目的参建方有哪些?","数智建管平台有哪些功能?能做什么?"]),P=e.ref([]),J=e.ref(!1),k=e.ref(null),v=()=>{e.nextTick(()=>{if(k.value){const w=k.value,b=w.scrollHeight,U=w.scrollTop,H=w.clientHeight;b-U-H<100?w.scrollTop=b:w.scrollTo({top:b})}})},F=e.ref(!1),K=e.ref(!1),Q=e.ref("");let le="";const wr=e.computed(()=>F.value?"/images/ai-stop.png":"/images/ai-send.png"),on=(w,b)=>{var ce;console.log("onFailedReader",w,b),Ce(),J.value=!1,K.value=!1;const U=Xe();U&&U.initializeEnd();const H=z.value[w],se=P.value[w],Y=((ce=se==null?void 0:se.getRawText)==null?void 0:ce.call(se))||"";H&&H.type==="ai"&&!H.displayText&&!Y&&z.value.splice(w,1),Q.value=le,F.value=!1,v(),setTimeout(()=>{L.value&&L.value.focus()})},Sr=w=>{K.value=!1},br=(w,b)=>{J.value=!1,F.value=!1,K.value=!1,v(),Vr(w,b),b&&z.value[w]&&(z.value[w].displayText=b),setTimeout(()=>{L.value&&L.value.focus()})},Er=w=>{F.value=!0,Nr(w)},Cr=()=>{F.value=!1,K.value=!1,Q.value="",$("update:modelValue",!1),I.value=!1,z.value=[]},Ye=e.ref(!1),vr=()=>{Ye.value=!Ye.value},Ar=w=>{h.value=w,Be()},Xe=()=>{for(let w=P.value.length-1;w>=0;w--)if(P.value[w])return P.value[w];return null},Be=async()=>{if(console.log("stylizingLoading:",J.value),J.value){K.value=!1;const b=Xe();console.log("lastPreviewer:",b),b&&(console.log("abortReader"),b.abortReader());return}if(!h.value.trim()){console.log("no input, return"),L.value.focus();return}z.value.push({type:"user",content:h.value}),F.value=!0,I.value=!0,Q.value="",$("submit",h.value),v();const w=h.value;le=w,h.value="",await rn(w)},Tr=async()=>{const w=Q.value;!w||J.value||(Q.value="",le=w,F.value=!0,v(),await rn(w))},rn=async w=>{const b=z.value.length;P.value[b]&&P.value[b].initializeStart(),J.value=!0,K.value=!0,z.value.push({type:"ai"});const{error:U,reader:H}=await vn(fe.value,{text:w,token:s.token,identifier:s.identifier,baseUrl:s.baseUrl,extraConfig:s.mockResponse?Object.assign({},s.extraConfig,{mockResponse:s.mockResponse}):s.extraConfig});if(U){console.log(45455,U),on(b,U);return}H&&(z.value[b].reader=H)};let ke=null,me=0,an=0;const Ze=e.ref(s.enableVoiceTts);e.watch(()=>s.enableVoiceTts,w=>{Ze.value=w,w||Ce()});const Ce=()=>{me=0},Nr=w=>{if(!ke)return;const b=P.value[w];if(!b||!b.getRawText)return;const U=b.getRawText()||"";if(!Ze.value){U.length>me&&(me=U.length);return}const H=Date.now();U.length>me&&H-an>250&&(ke(U.slice(me),!1),me=U.length,an=H)},Vr=(w,b)=>{if(!ke)return;if(!Ze.value){Ce();return}const U=P.value[w];if(U&&U.isAborted&&U.isAborted()){Ce();return}const H=b||(U&&U.getRawText?U.getRawText():"")||"";H.length>me&&ke(H.slice(me),!1),ke("",!0),Ce()};if(s.enableDuplexVoice){const w="chat-voice-"+Date.now().toString(36)+Math.random().toString(36).slice(2,8),{speak:b}=Ft({apiBase:s.voiceApiBase||void 0,sessionId:w,running:e.computed(()=>F.value),onTranscript:U=>{h.value=O(h.value,U)},onSubmit:()=>{Be()},onCancelTurn:()=>{const U=Xe();U&&U.abortReader()}});ke=b}return(w,b)=>{const U=e.resolveComponent("el-icon"),H=e.resolveComponent("el-button"),se=e.resolveComponent("el-input");return e.openBlock(),e.createBlock(e.Transition,{name:"slide"},{default:e.withCtx(()=>[t.modelValue?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["ai-panel",{"drawer-mode":Ye.value,"embedded-mode":t.embedded}])},[e.createElementVNode("div",So,[e.createElementVNode("div",bo,[e.createElementVNode("div",Eo,e.toDisplayString(t.title),1),e.createElementVNode("div",Co,[t.embedded?e.createCommentVNode("",!0):(e.openBlock(),e.createBlock(U,{key:0,class:"action-icon",onClick:vr},{default:e.withCtx(()=>[e.createVNode(Ae,{name:"/images/svg/drawer-layout.svg",color:"#999999"})]),_:1})),e.createVNode(U,{class:"action-icon",onClick:Cr},{default:e.withCtx(()=>[e.createVNode(Ae,{name:"/images/svg/close.svg",color:"#999999"})]),_:1})])])]),e.createElementVNode("div",vo,[I.value?(e.openBlock(),e.createElementBlock("div",{key:1,class:"chat-messages",ref_key:"messageContainerRef",ref:k},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(z.value,(Y,ce)=>(e.openBlock(),e.createElementBlock("div",{key:ce,class:e.normalizeClass(["message-item",Y.type==="user"?"user-message":"ai-message"])},[Y.type==="ai"?(e.openBlock(),e.createBlock(Xn,{key:0,ref_for:!0,ref:ue=>P.value[ce]=ue,reader:Y.reader,"onUpdate:reader":ue=>Y.reader=ue,model:s.llmName,displayText:Y.displayText,scrollToBottomFn:v,messagePostRender:t.messagePostRender,customUi:t.customUi,uiActionHandler:t.uiActionHandler,onFailed:ue=>on(ce,ue),onStarted:()=>Sr(),onCompleted:ue=>br(ce,ue),onUpdating:()=>Er(ce),onUiAction:b[0]||(b[0]=ue=>$("ui-action",ue))},null,8,["reader","onUpdate:reader","model","displayText","messagePostRender","customUi","uiActionHandler","onFailed","onStarted","onCompleted","onUpdating"])):(e.openBlock(),e.createElementBlock("div",Ro,e.toDisplayString(Y.content),1))],2))),128)),e.createVNode(e.Transition,{name:"ai-status-fade"},{default:e.withCtx(()=>[K.value?(e.openBlock(),e.createElementBlock("div",_o,[...b[4]||(b[4]=[e.createElementVNode("img",{src:ln,alt:"AI思考中",class:"thinking-icon"},null,-1),e.createElementVNode("img",{src:cn,alt:"",class:"thinking-loading-icon"},null,-1),e.createElementVNode("span",{class:"thinking-text"},"正在努力思考中~",-1)])])):Q.value?(e.openBlock(),e.createElementBlock("div",Lo,[b[5]||(b[5]=e.createElementVNode("span",{class:"failed-text"},"网络问题请重试",-1)),e.createElementVNode("button",{class:"retry-btn",onClick:Tr},"重试")])):e.createCommentVNode("",!0)]),_:1})],512)):(e.openBlock(),e.createElementBlock("div",Ao,[b[3]||(b[3]=e.createElementVNode("div",{class:"title"},[e.createElementVNode("img",{src:sn,alt:"AI助手",class:"panel-icon"}),e.createElementVNode("h3",{class:"title-text"},"Hi, 您好")],-1)),e.createElementVNode("div",To,[b[2]||(b[2]=e.createTextVNode(" 我是",-1)),e.createElementVNode("span",No,e.toDisplayString(t.title),1)]),e.createElementVNode("div",Vo,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(W.value,(Y,ce)=>(e.openBlock(),e.createElementBlock("div",{key:ce,class:"question-item",onClick:ue=>Ar(Y)},[e.createElementVNode("span",null,e.toDisplayString(Y),1),e.createVNode(U,null,{default:e.withCtx(()=>[e.createVNode(Ae,{name:"/images/svg/arrow-right.svg",color:"#999999"})]),_:1})],8,Bo))),128))])]))]),e.createElementVNode("div",xo,[e.createVNode(e.Transition,{name:"fade"},{default:e.withCtx(()=>[d.value||E.value?(e.openBlock(),e.createElementBlock("div",Uo,[e.createElementVNode("div",Po,[b[6]||(b[6]=e.createElementVNode("span",{class:"progress-icon"},"⏳",-1)),e.createElementVNode("span",Mo,e.toDisplayString(l.value),1),c.value>0?(e.openBlock(),e.createElementBlock("span",zo,e.toDisplayString(c.value)+"%",1)):e.createCommentVNode("",!0)]),c.value>0?(e.openBlock(),e.createElementBlock("div",jo,[e.createElementVNode("div",{class:"progress-bar",style:e.normalizeStyle({width:c.value+"%"})},null,4)])):e.createCommentVNode("",!0)])):e.createCommentVNode("",!0)]),_:1}),e.createVNode(e.Transition,{name:"fade"},{default:e.withCtx(()=>[y.value||m.value?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["voice-recording-panel",{"has-transcript":m.value}])},[e.createElementVNode("div",Io,[e.createElementVNode("div",Oo,[e.createElementVNode("span",{class:e.normalizeClass(["recording-pulse",{transcribing:m.value}])},null,2),y.value?(e.openBlock(),e.createElementBlock("span",Do,e.toDisplayString(x(f.value)),1)):e.createCommentVNode("",!0),e.createElementVNode("span",$o,e.toDisplayString(B.value),1),y.value?(e.openBlock(),e.createElementBlock("div",Fo,[e.createElementVNode("span",{class:"wave",style:e.normalizeStyle({height:Math.max(4,Math.min(22,u.value*.3))+"px"})},null,4),e.createElementVNode("span",{class:"wave",style:e.normalizeStyle({height:Math.max(4,Math.min(30,u.value*.5))+"px"})},null,4),e.createElementVNode("span",{class:"wave",style:e.normalizeStyle({height:Math.max(4,Math.min(18,u.value*.25))+"px"})},null,4)])):e.createCommentVNode("",!0)]),e.createElementVNode("div",Ho,[y.value?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[e.createVNode(H,{size:"small",circle:"",onClick:ne,title:"取消录音",class:"voice-cancel-btn"},{default:e.withCtx(()=>[...b[7]||(b[7]=[e.createElementVNode("svg",{viewBox:"0 0 1024 1024",width:"12",height:"12"},[e.createElementVNode("path",{d:"M512 456.310154L94.247385 38.557538a39.384615 39.384615 0 0 0-55.689847 55.689847L456.310154 512 38.557538 929.752615a39.384615 39.384615 0 0 0 55.689847 55.689847L512 567.689846l417.752615 417.752616c15.163077 15.163077 40.526769 15.163077 55.689847 0s15.163077-40.526769 0-55.689847L567.689846 512l417.752616-417.752615a39.384615 39.384615 0 0 0-55.689847-55.689847L512 456.310154z",fill:"currentColor"})],-1)])]),_:1}),e.createVNode(H,{type:"primary",size:"small",round:"",onClick:q,class:"voice-finish-btn"},{default:e.withCtx(()=>[...b[8]||(b[8]=[e.createTextVNode(" 完成 ",-1)])]),_:1})],64)):m.value?(e.openBlock(),e.createBlock(H,{key:1,size:"small",round:"",onClick:re,class:"voice-cancel-transcribe-btn"},{default:e.withCtx(()=>[...b[9]||(b[9]=[e.createTextVNode(" 取消识别 ",-1)])]),_:1})):e.createCommentVNode("",!0)])]),m.value?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["live-transcript",{empty:!_.value}]),title:_.value},[_.value?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[e.createTextVNode(e.toDisplayString(_.value),1),b[10]||(b[10]=e.createElementVNode("span",{class:"caret"},"|",-1))],64)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[e.createTextVNode("正在识别,文字将实时显示...")],64))],10,qo)):e.createCommentVNode("",!0)],2)):e.createCommentVNode("",!0)]),_:1}),e.createVNode(e.Transition,{name:"fade"},{default:e.withCtx(()=>[A.value&&!y.value&&!m.value?(e.openBlock(),e.createElementBlock("div",Wo,[e.createElementVNode("div",{class:"playback-main",onClick:ae,title:g.value?"点击暂停":"点击播放录音"},[e.createElementVNode("div",Jo,[g.value?(e.openBlock(),e.createElementBlock("svg",Yo,[...b[12]||(b[12]=[e.createElementVNode("path",{d:"M6 19h4V5H6v14zm8-14v14h4V5h-4z"},null,-1)])])):(e.openBlock(),e.createElementBlock("svg",Ko,[...b[11]||(b[11]=[e.createElementVNode("path",{d:"M8 5v14l11-7z"},null,-1)])]))]),e.createElementVNode("span",Xo,e.toDisplayString(g.value?"正在播放录音...":"点击试听本次录音"),1),C.value>0?(e.openBlock(),e.createElementBlock("span",Zo,e.toDisplayString(x(C.value)),1)):e.createCommentVNode("",!0),g.value?(e.openBlock(),e.createElementBlock("div",Qo,[...b[13]||(b[13]=[e.createElementVNode("span",{class:"wave-bar"},null,-1),e.createElementVNode("span",{class:"wave-bar"},null,-1),e.createElementVNode("span",{class:"wave-bar"},null,-1),e.createElementVNode("span",{class:"wave-bar"},null,-1)])])):e.createCommentVNode("",!0)],8,Go),e.createElementVNode("div",{class:"playback-close",onClick:oe,title:"清除试听"},[...b[14]||(b[14]=[e.createElementVNode("svg",{viewBox:"0 0 1024 1024",width:"12",height:"12"},[e.createElementVNode("path",{d:"M512 456.310154L94.247385 38.557538a39.384615 39.384615 0 0 0-55.689847 55.689847L456.310154 512 38.557538 929.752615a39.384615 39.384615 0 0 0 55.689847 55.689847L512 567.689846l417.752615 417.752616c15.163077 15.163077 40.526769 15.163077 55.689847 0s15.163077-40.526769 0-55.689847L567.689846 512l417.752616-417.752615a39.384615 39.384615 0 0 0-55.689847-55.689847L512 456.310154z",fill:"currentColor"})],-1)])])])):e.createCommentVNode("",!0)]),_:1}),e.withDirectives(e.createElementVNode("div",er,[e.createVNode(se,{modelValue:h.value,"onUpdate:modelValue":b[1]||(b[1]=Y=>h.value=Y),ref_key:"refInputTextString",ref:L,placeholder:R.value,autofocus:"",onKeyup:e.withKeys(Be,["enter"])},{append:e.withCtx(()=>[e.createElementVNode("div",tr,[t.enableVoiceUpload?(e.openBlock(),e.createElementBlock("div",{key:0,class:"voice-upload-btn",onClick:ee,title:"上传音频/视频文件识别 (支持 .wav, .mp4, .mp3, .m4a)"},[...b[15]||(b[15]=[e.createElementVNode("svg",{viewBox:"0 0 24 24",width:"17",height:"17",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},[e.createElementVNode("path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"}),e.createElementVNode("polyline",{points:"17 8 12 3 7 8"}),e.createElementVNode("line",{x1:"12",y1:"3",x2:"12",y2:"15"})],-1)])])):e.createCommentVNode("",!0),t.enableVoiceUpload?(e.openBlock(),e.createElementBlock("input",{key:1,type:"file",ref_key:"refAudioFileInput",ref:Z,accept:"audio/*,video/mp4,.wav,.mp4,.mp3,.m4a",style:{display:"none"},onChange:G},null,544)):e.createCommentVNode("",!0),t.enableVoiceInput?(e.openBlock(),e.createElementBlock("div",{key:2,class:e.normalizeClass(["voice-mic-btn",{"loading-anim":d.value||E.value}]),onClick:X,title:"语音输入"},[...b[16]||(b[16]=[e.createElementVNode("svg",{viewBox:"0 0 24 24",width:"18",height:"18",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},[e.createElementVNode("path",{d:"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z",fill:"currentColor",opacity:"0.2"}),e.createElementVNode("path",{d:"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"}),e.createElementVNode("path",{d:"M19 10v2a7 7 0 0 1-14 0v-2"}),e.createElementVNode("line",{x1:"12",y1:"19",x2:"12",y2:"22"})],-1)])],2)):e.createCommentVNode("",!0),t.enableDuplexVoice?(e.openBlock(),e.createBlock(e.unref(qt),{key:3})):e.createCommentVNode("",!0),e.createElementVNode("div",{class:"send-icon-box",onClick:Be},[e.createElementVNode("img",{src:wr.value,alt:"发送",class:"send-icon"},null,8,nr)])])]),_:1},8,["modelValue","placeholder"])],512),[[e.vShow,!y.value&&!m.value]]),t.enableDuplexVoice?(e.openBlock(),e.createBlock(e.unref(Wt),{key:0})):e.createCommentVNode("",!0)])],2)):e.createCommentVNode("",!0)]),_:1})}}};var Jt={exports:{}};(function(t,n){(function(r,o){t.exports=o()})(window,function(){return function(r){var o={};function s(a){if(o[a])return o[a].exports;var i=o[a]={i:a,l:!1,exports:{}};return r[a].call(i.exports,i,i.exports,s),i.l=!0,i.exports}return s.m=r,s.c=o,s.d=function(a,i,l){s.o(a,i)||Object.defineProperty(a,i,{enumerable:!0,get:l})},s.r=function(a){typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(a,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(a,"__esModule",{value:!0})},s.t=function(a,i){if(1&i&&(a=s(a)),8&i||4&i&&typeof a=="object"&&a&&a.__esModule)return a;var l=Object.create(null);if(s.r(l),Object.defineProperty(l,"default",{enumerable:!0,value:a}),2&i&&typeof a!="string")for(var c in a)s.d(l,c,(function(u){return a[u]}).bind(null,c));return l},s.n=function(a){var i=a&&a.__esModule?function(){return a.default}:function(){return a};return s.d(i,"a",i),i},s.o=function(a,i){return Object.prototype.hasOwnProperty.call(a,i)},s.p="",s(s.s=0)}([function(r,o,s){function a(S,d,E,y){E.push(S),y.push([].concat(d[S]||[]))}function i(S,d){if(!S)throw new Error("[getMaxDepsChain] dep 参数不能为空");var E=[],y=[],m=[];for(a(S,d,y,m);y.length;){var B=m.pop();if(B&&B.length){var R=B.shift();if(m.push(B),~y.indexOf(R))throw new Error("[getMaxDepsChain][loop] 存在循环依赖,请检查依赖关系; nextName: "+R+", mainStack: "+y);a(R,d,y,m)}else E.push([].concat(y)),y.pop()}return E.reduce(function(O,x){return x.length>O.length?x:O},[])}function l(S){if(!S)throw new Error("[depsParser] 入参不能为空");var d={};S.forEach(function(y){d[y.name]=y.deps||[]});var E=[];return S.forEach(function(y){var m=i(y.name,d).length-1;y.priority=m,E[m]=(E[m]||[]).concat(y)}),E}s.r(o),s.d(o,"loadScript",function(){return A}),s.d(o,"loadScripts",function(){return g}),s.d(o,"dynamicLoadScripts",function(){return C}),s.d(o,"createScriptsLoadIterator",function(){return T}),s.d(o,"loadScriptsQueue",function(){return _}),s.d(o,"getMaxDepsChain",function(){return i}),s.d(o,"depsParser",function(){return l});var c=function(){return(c=Object.assign||function(S){for(var d,E=1,y=arguments.length;E<y;E++)for(var m in d=arguments[E])Object.prototype.hasOwnProperty.call(d,m)&&(S[m]=d[m]);return S}).apply(this,arguments)},u=function(S,d,E,y){return new(E||(E=Promise))(function(m,B){function R(M){try{x(y.next(M))}catch(N){B(N)}}function O(M){try{x(y.throw(M))}catch(N){B(N)}}function x(M){var N;M.done?m(M.value):(N=M.value,N instanceof E?N:new E(function(D){D(N)})).then(R,O)}x((y=y.apply(S,[])).next())})},f=function(S,d){var E,y,m,B,R={label:0,sent:function(){if(1&m[0])throw m[1];return m[1]},trys:[],ops:[]};return B={next:O(0),throw:O(1),return:O(2)},typeof Symbol=="function"&&(B[Symbol.iterator]=function(){return this}),B;function O(x){return function(M){return function(N){if(E)throw new TypeError("Generator is already executing.");for(;R;)try{if(E=1,y&&(m=2&N[0]?y.return:N[0]?y.throw||((m=y.return)&&m.call(y),0):y.next)&&!(m=m.call(y,N[1])).done)return m;switch(y=0,m&&(N=[2&N[0],m.value]),N[0]){case 0:case 1:m=N;break;case 4:return R.label++,{value:N[1],done:!1};case 5:R.label++,y=N[1],N=[0];continue;case 7:N=R.ops.pop(),R.trys.pop();continue;default:if(m=R.trys,!((m=m.length>0&&m[m.length-1])||N[0]!==6&&N[0]!==2)){R=0;continue}if(N[0]===3&&(!m||N[1]>m[0]&&N[1]<m[3])){R.label=N[1];break}if(N[0]===6&&R.label<m[1]){R.label=m[1],m=N;break}if(m&&R.label<m[2]){R.label=m[2],R.ops.push(N);break}m[2]&&R.ops.pop(),R.trys.pop();continue}N=d.call(S,R)}catch(D){N=[6,D],y=0}finally{E=m=0}if(5&N[0])throw N[1];return{value:N[0]?N[1]:void 0,done:!0}}([x,M])}}},V=function(S){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var d,E=S[Symbol.asyncIterator];return E?E.call(S):(S=typeof __values=="function"?__values(S):S[Symbol.iterator](),d={},y("next"),y("throw"),y("return"),d[Symbol.asyncIterator]=function(){return this},d);function y(m){d[m]=S[m]&&function(B){return new Promise(function(R,O){(function(x,M,N,D){Promise.resolve(D).then(function(X){x({value:X,done:N})},M)})(R,O,(B=S[m](B)).done,B.value)})}}};function A(S,d){return d===void 0&&(d=!1),new Promise(function(E,y){var m=d?document.head:document.body,B=document.createElement("script");B.type="text/javascript",B.src=S,B.crossOrigin="anonymous",B.onreadystatechange=E,B.onload=E,B.onerror=y,m.appendChild(B)})}var g=function(S,d){return d===void 0&&(d={}),u(void 0,void 0,void 0,function(){var E,y,m,B,R;return f(this,function(O){switch(O.label){case 0:return E=d.baseUrl,y=E===void 0?"":E,m=d.lastLoadResult,B=d.inHead,R=B!==void 0&&B,[4,Promise.all(S.map(function(x){return u(void 0,void 0,void 0,function(){var M,N,D,X,q,Z,ee,G;return f(this,function(ne){switch(ne.label){case 0:return M=x.name,N=x.path,D=x.deps,(ee={})[M]=!0,X=ee,(G={})[M]=!1,q=G,window[M]?[2,X]:[3,1];case 1:return Z=!0,D&&m&&[].concat(D).forEach(function(re){m[re]!==!1&&(Z=!0)}),Z?[4,A(N.indexOf("http")===0||N.indexOf("//:")===0?N:y+N,R).then(function(){return X}).catch(function(){return q})]:[3,3];case 2:return[2,ne.sent()];case 3:return[2,q]}})})}))];case 1:return[2,O.sent()]}})})},C=function(S,d){return d===void 0&&(d={}),function(){var E=[].concat(l(S));return{next:function(){if(E.length){var y=E.shift();return g(y,d).then(function(m){return{value:m,done:!1}})}return Promise.resolve({done:!0})}}}},T=function(S,d){var E;return d===void 0&&(d={}),(E={})[Symbol.asyncIterator]=C(S,d),E},_=function(S,d){return d===void 0&&(d={}),u(void 0,void 0,void 0,function(){var E,y,m,B,R,O;return f(this,function(x){switch(x.label){case 0:x.trys.push([0,5,6,11]),E=V(T(S,d)),x.label=1;case 1:return[4,E.next()];case 2:if((y=x.sent()).done)return[3,4];m=y.value,d.lastLoadResult=d.lastLoadResult||{},console.log("current load: ",m),m.forEach(function(M){d.lastLoadResult=c(c({},d.lastLoadResult),M)}),x.label=3;case 3:return[3,1];case 4:return[3,11];case 5:return B=x.sent(),R={error:B},[3,11];case 6:return x.trys.push([6,,9,10]),y&&!y.done&&(O=E.return)?[4,O.call(E)]:[3,8];case 7:x.sent(),x.label=8;case 8:return[3,10];case 9:if(R)throw R.error;return[7];case 10:return[7];case 11:return[2,d.lastLoadResult]}})})}}])})})(Jt);var or=Jt.exports;function Kt(){const t=[{name:"markdownit",path:"markdown-it.min.js"},{name:"hljs",path:"highlight.11.11.1.min.js"}];let n={};or.loadScriptsQueue(t,{baseUrl:"/scripts/ai/",lastLoadResult:n,inHead:!1}).then(r=>{if(console.log("load ai deps: ",r),window.markdownit){const o=window.markdownit();console.log("markdownit: ",o),$n()}})}const rr={key:0,class:"ai-assistant"},ar={name:"AiChat"},Yt=e.defineComponent({...ar,props:{token:{type:String,default:""},identifier:{type:String,default:""},baseUrl:{type:String,default:""},title:{type:String,default:"数智AI助理"},llmName:{type:String,default:"szjy"},messagePostRender:{type:Function,default:null},extraConfig:{type:Object,default:()=>({})},soundBaseUrl:{type:String,default:"/sounds/"},workerUrl:{type:String,default:""},enableVoiceInput:{type:Boolean,default:!1},enableDuplexVoice:{type:Boolean,default:!1},voiceApiBase:{type:String,default:""},enableVoiceTts:{type:Boolean,default:!1},enableVoiceUpload:{type:Boolean,default:!1},customUi:{type:Object,default:null},uiActionHandler:{type:Function,default:null},mockResponse:{type:String,default:""}},emits:["ui-action"],setup(t,{emit:n}){const r=e.ref(!1),o=e.ref(!1),s=n,a=()=>{r.value=!r.value},i=()=>{o.value=!0,r.value=!1},l=c=>{console.log("用户输入:",c)};return Kt(),(c,u)=>o.value?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("div",rr,[e.createVNode(Gt,{modelValue:r.value,"onUpdate:modelValue":u[0]||(u[0]=f=>r.value=f),onSubmit:l,onUiAction:u[1]||(u[1]=f=>s("ui-action",f)),token:t.token,identifier:t.identifier,baseUrl:t.baseUrl,title:t.title,llmName:t.llmName,messagePostRender:t.messagePostRender,extraConfig:t.extraConfig,customUi:t.customUi,uiActionHandler:t.uiActionHandler,mockResponse:t.mockResponse,soundBaseUrl:t.soundBaseUrl,workerUrl:t.workerUrl,enableVoiceInput:t.enableVoiceInput,enableDuplexVoice:t.enableDuplexVoice,voiceApiBase:t.voiceApiBase,enableVoiceTts:t.enableVoiceTts,enableVoiceUpload:t.enableVoiceUpload},null,8,["modelValue","token","identifier","baseUrl","title","llmName","messagePostRender","extraConfig","customUi","uiActionHandler","mockResponse","soundBaseUrl","workerUrl","enableVoiceInput","enableDuplexVoice","voiceApiBase","enableVoiceTts","enableVoiceUpload"]),e.createElementVNode("div",{class:"ai-icon",onClick:a},[e.createElementVNode("div",{class:"close-icon",onClick:e.withModifiers(i,["stop"])},[...u[2]||(u[2]=[e.createElementVNode("svg",{viewBox:"0 0 1024 1024",width:"8",height:"8"},[e.createElementVNode("path",{d:"M512 456.310154L94.247385 38.557538a39.384615 39.384615 0 0 0-55.689847 55.689847L456.310154 512 38.557538 929.752615a39.384615 39.384615 0 0 0 55.689847 55.689847L512 567.689846l417.752615 417.752616c15.163077 15.163077 40.526769 15.163077 55.689847 0s15.163077-40.526769 0-55.689847L567.689846 512l417.752616-417.752615a39.384615 39.384615 0 0 0-55.689847-55.689847L512 456.310154z",fill:"currentColor"})],-1)])]),u[3]||(u[3]=e.createElementVNode("img",{src:he,alt:"AI助手"},null,-1)),u[4]||(u[4]=e.createElementVNode("span",{class:"ai-icon-text"},"AI助手",-1))])]))}}),sr={class:"ai-chat-plain"},ir={name:"AiChatPlain"},Xt=e.defineComponent({...ir,props:{token:{type:String,default:""},identifier:{type:String,default:""},baseUrl:{type:String,default:""},title:{type:String,default:"数智AI助理"},llmName:{type:String,default:"szjy"},messagePostRender:{type:Function,default:null},extraConfig:{type:Object,default:()=>({})},soundBaseUrl:{type:String,default:"/sounds/"},workerUrl:{type:String,default:""},enableVoiceInput:{type:Boolean,default:!1},enableDuplexVoice:{type:Boolean,default:!1},voiceApiBase:{type:String,default:""},enableVoiceTts:{type:Boolean,default:!1},enableVoiceUpload:{type:Boolean,default:!1},customUi:{type:Object,default:null},uiActionHandler:{type:Function,default:null},mockResponse:{type:String,default:""}},emits:["submit","ui-action"],setup(t,{emit:n}){const r=n;return Kt(),(o,s)=>(e.openBlock(),e.createElementBlock("div",sr,[e.createVNode(Gt,{"model-value":!0,token:t.token,identifier:t.identifier,baseUrl:t.baseUrl,title:t.title,llmName:t.llmName,messagePostRender:t.messagePostRender,extraConfig:t.extraConfig,customUi:t.customUi,uiActionHandler:t.uiActionHandler,mockResponse:t.mockResponse,soundBaseUrl:t.soundBaseUrl,workerUrl:t.workerUrl,enableVoiceInput:t.enableVoiceInput,enableDuplexVoice:t.enableDuplexVoice,voiceApiBase:t.voiceApiBase,enableVoiceTts:t.enableVoiceTts,enableVoiceUpload:t.enableVoiceUpload,embedded:!0,onSubmit:s[0]||(s[0]=a=>r("submit",a)),onUiAction:s[1]||(s[1]=a=>r("ui-action",a))},null,8,["token","identifier","baseUrl","title","llmName","messagePostRender","extraConfig","customUi","uiActionHandler","mockResponse","soundBaseUrl","workerUrl","enableVoiceInput","enableDuplexVoice","voiceApiBase","enableVoiceTts","enableVoiceUpload"])]))}}),Zt=Object.freeze(Object.defineProperty({__proto__:null,SzAiChat:Yt,SzAiChatPlain:Xt},Symbol.toStringTag,{value:"Module"})),Ke=function(t){if(!Ke.installed){Ke.installed=!0;for(let n in Zt){const r=Reflect.get(Zt,n);t.component(r.name,r)}}},lr=(t,n)=>{const r=n?`?${new URLSearchParams(n).toString()}`:"";console.log(`点击了路由链接: ${t}${r}`)},Qt=t=>{const n=t.indexOf("?");if(n===-1)return{routeName:t};const r=t.substring(0,n),o=t.substring(n+1),s={};return new URLSearchParams(o).forEach((i,l)=>{s[l]=i}),{routeName:r,queryParams:Object.keys(s).length>0?s:void 0}},cr={color:"#536fec",fontWeight:"bold",textDecoration:"underline",cursor:"pointer",padding:"0 3px"},en=t=>{const n=/#router:([^#]+)#/g,r=[];let o=0,s;for(;(s=n.exec(t))!==null;){s.index>o&&r.push({text:t.substring(o,s.index)});const a=s[1],{routeName:i,queryParams:l}=Qt(a);r.push({text:i,routeName:i,queryParams:l}),o=n.lastIndex}return o<t.length&&r.push({text:t.substring(o)}),r},tn=(t,n,r={},o)=>{const{onRouteClick:s=lr,linkStyle:a={}}=r,i=document.createElement("a");i.href="#",i.textContent=t;const l={...cr,...a};return Object.assign(i.style,l),i.addEventListener("click",c=>{c.preventDefault(),s(n,o)}),i},nn=t=>{const n=/#router:([^#]+)#/g,r=[],o=document.createTreeWalker(t,NodeFilter.SHOW_TEXT,null);let s=o.nextNode();for(;s;){const a=s,i=a.textContent||"";if(n.test(i)){n.lastIndex=0;const l=en(i);l.length>0&&r.push({node:a,replacements:l})}s=o.nextNode()}return r},ur=(t,n,r={})=>{const o=nn(t);o.forEach(({node:s,replacements:a})=>{var l;const i=document.createDocumentFragment();a.forEach(({text:c,routeName:u,queryParams:f})=>{if(u){const V=tn(c,u,r,f);i.appendChild(V)}else i.appendChild(document.createTextNode(c))}),(l=s.parentNode)==null||l.replaceChild(i,s)}),r!=null&&r.nodeCallback&&o.forEach(({node:s,replacements:a})=>{var i;(i=r.nodeCallback)==null||i.call(r,s,a)})},Ee="szjy-voice-models",Ne="szjy-voice-cache-v1";function ye(){return typeof navigator<"u"&&!!navigator.storage&&typeof navigator.storage.getDirectory=="function"}async function Ve(t=Ee){if(!ye())return null;try{return await(await navigator.storage.getDirectory()).getDirectoryHandle(t,{create:!0})}catch(n){return console.warn("[OPFS] 获取目录失败,将使用降级缓存:",n),null}}async function dr(t,n,r=Ee){if(ye())try{const o=await Ve(r);if(o){const a=await(await o.getFileHandle(t,{create:!0})).createWritable();return await a.write(n),await a.close(),!0}}catch(o){console.warn(`[OPFS] 写入文件 ${t} 失败:`,o)}if(typeof caches<"u")try{const o=await caches.open(Ne),s=new Response(n,{headers:{"Content-Type":"application/octet-stream"}});return await o.put(`/${r}/${t}`,s),!0}catch(o){console.warn(`[CacheStorage] 缓存写入 ${t} 失败:`,o)}return!1}async function fr(t,n=Ee){if(ye())try{const r=await Ve(n);if(r)return await(await(await r.getFileHandle(t,{create:!1})).getFile()).arrayBuffer()}catch{}if(typeof caches<"u")try{const o=await(await caches.open(Ne)).match(`/${n}/${t}`);if(o)return await o.arrayBuffer()}catch{}return null}async function mr(t,n=Ee){if(ye())try{const r=await Ve(n);if(r)return(await(await r.getFileHandle(t,{create:!1})).getFile()).size>0}catch{}if(typeof caches<"u")try{return!!await(await caches.open(Ne)).match(`/${n}/${t}`)}catch{}return!1}async function hr(t=Ee){let n=!1;if(ye())try{await(await navigator.storage.getDirectory()).removeEntry(t,{recursive:!0}),n=!0,console.log(`[OPFS] 成功清空语音模型缓存目录: ${t}`)}catch(r){r.name==="NotFoundError"?n=!0:console.warn(`[OPFS] 清理目录 ${t} 异常:`,r)}if(typeof caches<"u")try{const r=await caches.keys();for(const o of r)(o.includes("transformers")||o.includes("szjy-voice")||o===Ne)&&(await caches.delete(o),n=!0)}catch(r){console.warn("[CacheStorage] 清除缓存异常:",r)}return n}const pr="0.1.17",gr="Sz";function yr({componentPrefix:t=gr,components:n=[]}={}){const r=[];function o(a,i,l){a.component(t+i)||a.component(t+i,l)}function s(a){r.includes(a)||(r.push(a),n.forEach(i=>{const{name:l,alias:c}=i;o(a,l,i),c&&c.forEach(u=>{o(a,u,i)})}))}return{version:pr,componentPrefix:t,install:s}}const kr={install(t){Ke(t)}};p.AEC_DEFAULTS=no,p.AudioRecorder=wt,p.BUFFER_SIZE=$e,p.CANCEL_DRAG_PX=Ut,p.DEFAULT_BASE_PATH=Te,p.DEFAULT_MOCK_RESPONSE=et,p.DEFAULT_WHISPER_WORKER_URL=ze,p.ENERGY_THRESHOLD=Ie,p.EqualizerBars=Je,p.HOLD_THRESHOLD_MS=Lt,p.KEY_HOLD_THRESHOLD_MS=xt,p.LEVEL_CEILING=At,p.MAX_SEGMENT_MS=Oe,p.MIN_HOLD_SEGMENT_S=Vt,p.NlmsAec=Pt,p.PARTIAL_INTERVAL_MS=Bt,p.PARTIAL_MAX_S=_t,p.PARTIAL_MIN_S=Rt,p.POST_PAD_MS=De,p.PRE_PAD_MS=Nt,p.SAMPLE_RATE=de,p.SILENCE_TIMEOUT_MS=Tt,p.SZJY_UI_FENCE_LANG=pt,p.StreamResampler=kt,p.SzAiChat=Yt,p.SzAiChatPlain=Xt,p.VOICE_CONTEXT_KEY=We,p.VoiceCaptionBar=Wt,p.VoiceInputManager=vt,p.VoiceMicButton=qt,p.VoiceOverlay=Ht,p.WAVE_BARS=Fe,p.bindSzjyUiEvents=yt,p.clearVoiceModelCache=hr,p.create=yr,p.createAsrEngine=It,p.createMockStylized=tt,p.createPlaybackEngine=Dt,p.createRouteLink=tn,p.decodeAudioFile=bt,p.default=kr,p.escapeHtml=pe,p.findRouteTextNodes=nn,p.float32ToWav=Me,p.getConfig=zt,p.getFileFromCache=fr,p.getOPFSDirectory=Ve,p.getReady=Mt,p.getSzjyUiAction=lt,p.getSzjyUiComponent=st,p.hasFileInCache=mr,p.hasSzjyUiAction=ct,p.hasSzjyUiComponent=it,p.isOPFSSupported=ye,p.micErrorMessage=Ot,p.openAudioStream=jt,p.parseRouteMarkerContent=Qt,p.parseRouteMarkers=en,p.parseSzjyUiFence=gt,p.postAsr=io,p.postCancel=He,p.registerSzjyUiAction=at,p.registerSzjyUiComponent=Ue,p.renderActionAttrs=dt,p.renderSzjyUiBlock=ut,p.renderSzjyUiNode=Pe,p.resampleAudioData=St,p.routeLinkRender=ur,p.saveFileToCache=dr,p.useVoice=Ft,p.useVoiceContext=Ge,Object.defineProperties(p,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<import('vue').ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
|
|
2
|
+
color: string;
|
|
3
|
+
height?: number;
|
|
4
|
+
}>>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
|
|
5
|
+
color: string;
|
|
6
|
+
height?: number;
|
|
7
|
+
}>>> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
8
|
+
export default _default;
|
|
9
|
+
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
|
|
10
|
+
type __VLS_TypePropsToRuntimeProps<T> = {
|
|
11
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
12
|
+
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
|
|
13
|
+
} : {
|
|
14
|
+
type: import('vue').PropType<T[K]>;
|
|
15
|
+
required: true;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<import('vue').ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
|
|
2
|
+
levels: number[];
|
|
3
|
+
armedCancel: boolean;
|
|
4
|
+
/** Released, waiting on the authoritative transcript from the host. */
|
|
5
|
+
pending: boolean;
|
|
6
|
+
/** Interim transcript of the capture so far ('' until the first one lands). */
|
|
7
|
+
partial: string;
|
|
8
|
+
source: "pointer" | "key";
|
|
9
|
+
hotkey: string;
|
|
10
|
+
}>>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
|
|
11
|
+
levels: number[];
|
|
12
|
+
armedCancel: boolean;
|
|
13
|
+
/** Released, waiting on the authoritative transcript from the host. */
|
|
14
|
+
pending: boolean;
|
|
15
|
+
/** Interim transcript of the capture so far ('' until the first one lands). */
|
|
16
|
+
partial: string;
|
|
17
|
+
source: "pointer" | "key";
|
|
18
|
+
hotkey: string;
|
|
19
|
+
}>>> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
20
|
+
export default _default;
|
|
21
|
+
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
|
|
22
|
+
type __VLS_TypePropsToRuntimeProps<T> = {
|
|
23
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? {
|
|
24
|
+
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
|
|
25
|
+
} : {
|
|
26
|
+
type: import('vue').PropType<T[K]>;
|
|
27
|
+
required: true;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NLMS (normalized least-mean-squares) acoustic echo canceller.
|
|
3
|
+
*
|
|
4
|
+
* The browser's `echoCancellation` constraint is a black box: quality varies
|
|
5
|
+
* by OS/browser and it cannot see what *this* page is playing. When the TTS
|
|
6
|
+
* voice is loud, playback bleeds into the mic and falsely trips the barge-in
|
|
7
|
+
* VAD. This module runs a second, explicit echo canceller on the mic signal
|
|
8
|
+
* using the page's own TTS output as the reference — so the canceller is
|
|
9
|
+
* always aligned with exactly what the assistant said, not an OS guess.
|
|
10
|
+
*
|
|
11
|
+
* Algorithm: standard NLMS with a fixed tap delay + adaptive FIR.
|
|
12
|
+
* y[n] = w · x[n - D .. n - D - L] (estimated echo)
|
|
13
|
+
* e[n] = d[n] - y[n] (clean signal)
|
|
14
|
+
* w += μ · e[n] · x / (‖x‖² + ε)
|
|
15
|
+
*
|
|
16
|
+
* 移植自 dsh-voice src/aec.ts(PRD 7.2)。Pure module — no Web Audio types.
|
|
17
|
+
*/
|
|
18
|
+
export interface AecOptions {
|
|
19
|
+
/** FIR filter length (taps). Covers speaker->mic delay + early reflections. */
|
|
20
|
+
filterLength?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Fixed delay applied to the reference before the filter, in samples.
|
|
23
|
+
* The speaker->mic path has a short OS/buffer latency; a fixed lead-in
|
|
24
|
+
* lets a shorter filter still cover the tail.
|
|
25
|
+
*/
|
|
26
|
+
delay?: number;
|
|
27
|
+
/** Normalized step size (0 < μ < 2; ~0.1 is a safe default). */
|
|
28
|
+
step?: number;
|
|
29
|
+
/** Regularizer on the denominator to avoid div-by-zero on silence. */
|
|
30
|
+
epsilon?: number;
|
|
31
|
+
}
|
|
32
|
+
export declare class NlmsAec {
|
|
33
|
+
private readonly w;
|
|
34
|
+
private readonly xBuf;
|
|
35
|
+
private readonly filterLength;
|
|
36
|
+
private readonly delay;
|
|
37
|
+
private readonly mu;
|
|
38
|
+
private readonly eps;
|
|
39
|
+
/** Ring cursor into xBuf (reference history). */
|
|
40
|
+
private cursor;
|
|
41
|
+
/** How many reference samples we have buffered so far (for warm-up). */
|
|
42
|
+
private filled;
|
|
43
|
+
constructor(options?: AecOptions);
|
|
44
|
+
/**
|
|
45
|
+
* Push the next mic/reference block; returns the echo-removed mic samples
|
|
46
|
+
* (same length as the input). Reference may be shorter than the mic block
|
|
47
|
+
* (e.g. silence pad) — it is zero-filled to the block length.
|
|
48
|
+
*/
|
|
49
|
+
process(mic: Float32Array, ref: Float32Array): Float32Array;
|
|
50
|
+
/** Reset adaptation (call on start/stop to avoid stale speaker->mic path). */
|
|
51
|
+
reset(): void;
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ReadyResponse, VoiceConfig, VoiceFrame } from './types';
|
|
2
|
+
|
|
3
|
+
export declare function getReady(base?: string, headers?: Record<string, string>): Promise<ReadyResponse>;
|
|
4
|
+
export declare function getConfig(base?: string, headers?: Record<string, string>): Promise<VoiceConfig>;
|
|
5
|
+
/**
|
|
6
|
+
* POST PCM 识别。
|
|
7
|
+
*
|
|
8
|
+
* - 正式识别:不带 `x-voice-session`。
|
|
9
|
+
* - 预览:带 `x-voice-session`,body 只发相对上次预览的增量。
|
|
10
|
+
* - body 必须 `float32Array.slice().buffer`:subarray().buffer 仍是整段缓冲。
|
|
11
|
+
*/
|
|
12
|
+
export declare function postAsr(base: string, headers: Record<string, string> | undefined, pcm: Float32Array, previewSessionId?: string): Promise<{
|
|
13
|
+
text: string;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function postCancel(base: string, headers: Record<string, string> | undefined, sessionId: string): Promise<{
|
|
16
|
+
ok: boolean;
|
|
17
|
+
}>;
|
|
18
|
+
export interface AudioStreamHandle {
|
|
19
|
+
close(): void;
|
|
20
|
+
}
|
|
21
|
+
export interface AudioStreamStatus {
|
|
22
|
+
connected: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 订阅 TTS SSE 流(`GET {base}/stream`,`event: audio`)。
|
|
26
|
+
*
|
|
27
|
+
* - 有自定义头(如 Authorization):fetch + ReadableStream 手工解析 SSE。
|
|
28
|
+
* - 无自定义头:可用 EventSource。
|
|
29
|
+
* - 心跳行以 `:` 开头,忽略;连接失败 3s 后重试,不打崩页面。
|
|
30
|
+
*/
|
|
31
|
+
export declare function openAudioStream(base: string, headers: Record<string, string> | undefined, onFrame: (frame: VoiceFrame) => void, onStatus: (status: AudioStreamStatus) => void): AudioStreamHandle;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|