@szjy/ai-coms 0.1.8 → 0.1.12

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/index.umd.js CHANGED
@@ -1,2 +1,2 @@
1
- (function(E,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(E=typeof globalThis<"u"?globalThis:E||self,e(E["szjy-ai-coms"]={},E.Vue))})(this,function(E,e){"use strict";const Z="/images/ai-round.png",G="/images/ai-sqrt.png",ee="/images/bars-loading.svg";function $(n){return n.startsWith("http://")||n.startsWith("https://")?n:`${location.protocol}//${location.host}${n}`}async function te(n,r,l,i="",o={}){const{projectId:t}=o,a=$(i),u=new URL(`${a}/v1/chat/completions`),f=(o==null?void 0:o.authToken)||"app-oLZVFFdYyJX2QK3rdOLWsC2u";o!=null&&o.authToken||console.error("缺少 authToken!现在默认使用内网的 authToken");const b=new Request(u,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${f}`},body:JSON.stringify({model:"dify",stream:!0,inputs:{token:r,projectCode:l,...t?{projectId:t}:{}},messages:[{role:"system",content:"你是一个专业的AI助手,请用中文回答问题。"},{role:"user",content:n}]})});return fetch(b)}async function ne(n,r,l,i="",o={}){const t=new URL("http://localhost:11434/api/chat"),a={};Object.keys(a).forEach(f=>{t.searchParams.append(f,a[f])});const u=new Request(t,{mode:"cors",method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:"llama3",stream:!0,messages:[{role:"system",content:"全程使用中文回答问题。"},{role:"user",content:n}]})});return fetch(u)}async function re(n,r,l,i="",o={}){const t=new URL(`${location.origin}/spark/v1/chat/completions`),a={};Object.keys(a).forEach(f=>{t.searchParams.append(f,a[f])});const u=new Request(t,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`},body:JSON.stringify({model:"generalv4.0Ultra",stream:!0,messages:[{role:"user",content:n}]})});return fetch(u)}async function oe(n,r,l,i="",o={}){const t=new URL(`${location.origin}/siliconflow/v1/chat/completions`),a={};Object.keys(a).forEach(f=>{t.searchParams.append(f,a[f])});const u=new Request(t,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`},body:JSON.stringify({model:"Qwen/Qwen1.5-110B-Chat",stream:!0,messages:[{role:"user",content:n}]})});return fetch(u)}async function ae(n,r,l,i="",o={}){const t=new URL(`${location.origin}/moonshot/v1/chat/completions`),a={};Object.keys(a).forEach(f=>{t.searchParams.append(f,a[f])});const u=new Request(t,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`},body:JSON.stringify({model:"moonshot-v1-8k",stream:!0,messages:[{role:"system",content:"你是 Kimi,由 Moonshot AI 提供的人工智能助手,你更擅长中文和英文的对话。你会为用户提供安全,有帮助,准确的回答。同时,你会拒绝一切涉及恐怖主义,种族歧视,黄色暴力等问题的回答。Moonshot AI 为专有名词,不可翻译成其他语言。"},{role:"user",content:n}]})});return fetch(u)}async function se(n,r,l,i="",o={}){const t=new URL(`${location.origin}/dashscope/compatible-mode/v1/chat/completions`),a={};Object.keys(a).forEach(f=>{t.searchParams.append(f,a[f])});const u=new Request(t,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`},body:JSON.stringify({model:"qwq-32b-preview",stream:!0,messages:[{role:"system",content:"全程使用中文回答问题"},{role:"user",content:n}]})});return fetch(u)}async function le(n,r,l,i="",o={}){const t=$(i),a=new URL(`${t}/support/${l}/a`),u={};Object.keys(u).forEach(b=>{a.searchParams.append(b,u[b])});const f=new Request(a,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${r}`},body:JSON.stringify({content:n})});return fetch(f)}const ie=n=>{if(n.startsWith("data:")){const r=n.substring(5).trim();if(r==="[DONE]")return{done:!0};try{return JSON.parse(r)}catch(l){console.error("JSON parsing error:",l)}}return null},A=[{label:"模拟数据模型",modelName:"standard",api:null},{label:"Spark 星火大模型",modelName:"spark",api:re},{label:"Ollama 3 大模型",modelName:"ollama3",api:ne},{label:"SiliconFlow 硅基流动大模型",modelName:"siliconflow",api:oe},{label:"Kimi Moonshot 月之暗面大模型",modelName:"moonshot",api:ae},{label:"通义千问大模型",modelName:"dashscope",api:se},{label:"数智建管大模型",modelName:"szjy",api:le},{label:"Dify (OpenAI 兼容)",modelName:"dify-openai",api:te}],q={standard(n,r){let l="";return n instanceof Uint8Array?l=r.decode(n,{stream:!0}):l=n,{content:l}},spark(n){const r=ie(n);return r.done?{done:!0}:{content:r.choices[0].delta.content||""}},siliconflow(n){return this.spark(n)},moonshot(n){return this.spark(n)},dashscope(n){return this.spark(n)},szjy(n){return this.spark(n)},"dify-openai"(n){return this.spark(n)},ollama3(n){return{content:JSON.parse(n).message.content}}},M=(n,r,l)=>{const i=n.split(l);return i.slice(0,-1).forEach(o=>{o.trim()!==""&&r.enqueue(o)}),i[i.length-1]},ce=n=>{let r="";return new TransformStream({transform(l,i){if(r+=l,r.trim().startsWith("data:"))r=M(r,i,n);else try{JSON.parse(r),r=M(r,i,n)}catch{i.enqueue(l),r=""}},flush(l){r.trim()!==""&&l.enqueue(r)}})};async function de(n,r){const l=n.api;return l?new Promise(i=>{l(r.text,r.token,r.identifier,r.baseUrl,r.extraConfig).then(o=>{if(o.body){const t=o.body.pipeThrough(new TextDecoderStream).pipeThrough(ce(`
2
- `)).getReader();console.log("reader from response:",t),i({error:0,reader:t})}else i({error:1,reader:null})}).catch(o=>{i({error:1,reader:null})})}):{error:1,reader:null}}let z=null;function ue(){return z||(window.markdownit?z=new window.markdownit({html:!0,linkify:!0,typographer:!0}):console.log("markdownit is not loaded"),z)}const F=(n,r)=>{const l=n.__vccOpts||n;for(const[i,o]of r)l[i]=o;return l},fe=["src","alt"],U=F({__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(n){const r=n,l=e.computed(()=>{if(r.name.startsWith("http://")||r.name.startsWith("https://")||r.name.startsWith("/"))return r.name;const t=r.name.endsWith(".svg")?r.name:`${r.name}.svg`;return`${r.basePath}${t}`}),i=e.computed(()=>{const t=typeof r.size=="number"?`${r.size}px`:r.size;return{width:t,height:t,display:"inline-flex",justifyContent:"center",alignItems:"center"}}),o=e.computed(()=>{const t={width:"100%",height:"100%"};return r.color&&(t.filter=`drop-shadow(0 0 0 ${r.color})`),t});return(t,a)=>(e.openBlock(),e.createElementBlock("div",{class:"svg-icon-wrapper",style:e.normalizeStyle(i.value)},[e.createElementVNode("img",{src:l.value,alt:n.name,class:e.normalizeClass(["svg-icon",n.className]),style:e.normalizeStyle(o.value)},null,14,fe)],4))}},[["__scopeId","data-v-490b11c1"]]),me=async n=>{if(navigator.clipboard&&navigator.permissions)await navigator.clipboard.writeText(n);else{const r=document.createElement("textArea");r.value=n,r.style.width=0,r.style.position="fixed",r.style.left="-999px",r.style.top="10px",r.setAttribute("readonly","readonly"),document.body.appendChild(r),r.select(),document.execCommand("copy"),document.body.removeChild(r)}},pe=["innerHTML"],he={__name:"Previewer",props:{reader:null,model:"szjy",scrollToBottomFn:null,displayText:"",messagePostRender:{type:Function,default:null}},emits:["failed","completed","updating"],setup(n,{expose:r,emit:l}){const{appContext:i}=e.getCurrentInstance(),{$message:o}=i.config.globalProperties,t=n,a=e.ref(t.displayText||""),u=e.ref(""),f=e.ref(!0),b=e.ref(!1),N=e.ref(!!t.displayText),B=l,T=e.ref(null);let C=null;const j=e.computed(()=>z?z.render(a.value):a.value),O=()=>{t.reader&&t.reader.cancel(),b.value=!0,d.value=!1,p(),N.value=!0,B("completed",a.value),f.value=!1,C&&(cancelAnimationFrame(C),C=null)},P=e.computed(()=>`${j.value}`),h=e.ref(!1),m=()=>{h.value=!0},p=()=>{h.value=!1},d=e.ref(!1),c=async()=>{if(!t.reader)return;const w=new TextDecoder("utf-8");for(f.value=!0;!b.value;)try{if(!t.reader){d.value=!0;break}const{value:s,done:k}=await t.reader.read();if(!t.reader){d.value=!0;break}if(k){d.value=!0;break}const x=q[t.model];if(!x)break;const R=x.call(q,s,w);if(R.done){d.value=!0;break}u.value+=R.content,C===null&&S()}catch(s){d.value=!0,console.log(3333,s),B("failed",s),O();break}finally{p()}},y=async()=>{t.scrollToBottomFn&&t.scrollToBottomFn()},g=(w=()=>{},s=()=>{})=>{if(u.value.length>0){const k=u.value.substring(0,10);a.value+=k,u.value=u.value.substring(10),w()}else s()},S=()=>{if(b.value&&C){cancelAnimationFrame(C),C=null,f.value=!1;return}d.value?g(()=>{C=requestAnimationFrame(S),B("updating",null)},()=>{B("completed",a.value),f.value=!1,N.value=!0,e.nextTick(()=>{if(d.value=!1,t.messagePostRender&&T.value)try{t.messagePostRender(T.value,a.value)}catch(w){console.error("messagePostRender 执行失败:",w)}}),C=null}):(g(),C=requestAnimationFrame(S)),y()};e.watch(()=>t.reader,()=>{t.reader&&c()},{immediate:!0,deep:!0}),e.onUnmounted(()=>{O()}),r({abortReader:O,initializeStart:m,initializeEnd:p}),e.computed(()=>h.value?!0:(!t.reader||!f||a.value,!1));const v=async()=>{try{const w=a.value;await me(w),o.success("复制成功")}catch(w){console.error("复制失败:",w),o.error("复制失败")}};return(w,s)=>(e.openBlock(),e.createBlock(e.Transition,{name:"fade"},{default:e.withCtx(()=>[P.value?(e.openBlock(),e.createElementBlock("div",{key:0,ref_key:"refWrapperContent",ref:T,"text-16":"",class:"w-full h-full overflow-y-auto relative","p-24px":""},[e.createElementVNode("div",{class:"markdown-wrapper",innerHTML:P.value},null,8,pe),N.value?(e.openBlock(),e.createElementBlock("div",{key:0,class:"ai-copy-btn-wrapper",onClick:v},[e.createVNode(U,{name:"/images/svg/copy.svg",color:"#666666"}),s[0]||(s[0]=e.createElementVNode("span",{class:"copy-text"},"复制",-1))])):e.createCommentVNode("",!0)],512)):e.createCommentVNode("",!0)]),_:1}))}},ye={class:"panel-header"},ge={class:"header-actions"},be={class:"header-title"},ke={class:"action-icons"},we={class:"body-content"},ve={key:0,class:"welcome-content"},Se={class:"subtitle"},xe={class:"highlight"},Ne={class:"quick-questions"},Ce=["onClick"],_e={key:1,class:"message-content user-content"},Ee={class:"panel-footer"},Te={key:0,src:ee,alt:"加载中",class:"loading-icon"},Re={class:"input-box"},Pe=["src"],Ve={__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:()=>({})}},emits:["update:modelValue","submit"],setup(n,{emit:r}){const{appContext:l}=e.getCurrentInstance(),{$message:i}=l.config.globalProperties,o=n,t=e.computed(()=>A.find(s=>s.modelName===o.llmName)??A.find(s=>s.modelName==="szjy")),a=r,u=e.ref(""),f=e.ref(null),b=e.ref(!1),N=e.ref([]),B=e.ref(["什么是AI助理,能做什么?","当前项目的基本情况?","当前项目的进度情况?","当前项目的参建方有哪些?","数智建管平台有哪些功能?能做什么?"]),T=e.ref([]),C=e.ref(!1),j=e.ref(null),O=()=>{e.nextTick(()=>{if(j.value){const s=j.value,k=s.scrollHeight,x=s.scrollTop,R=s.clientHeight;k-x-R<100?s.scrollTop=k:s.scrollTo({top:k})}})},P=e.ref(!1),h=e.computed(()=>P.value?"/images/ai-stop.png":"/images/ai-send.png"),m=(s,k)=>{console.log("onFailedReader",s,k),C.value=!1;const x=v();x&&x.initializeEnd(),i.error("转换失败,请重试"),P.value=!1,setTimeout(()=>{f.value&&f.value.focus()})},p=(s,k)=>{C.value=!1,P.value=!1,O(),k&&N.value[s]&&(N.value[s].displayText=k),setTimeout(()=>{f.value&&f.value.focus()})},d=s=>{P.value=!0},c=()=>{P.value=!1,a("update:modelValue",!1),b.value=!1,N.value=[]},y=e.ref(!1),g=()=>{y.value=!y.value},S=s=>{u.value=s,w()},v=()=>{for(let s=T.value.length-1;s>=0;s--)if(T.value[s])return T.value[s];return null},w=async()=>{if(console.log("stylizingLoading:",C.value),C.value){const _=v();console.log("lastPreviewer:",_),_&&(console.log("abortReader"),_.abortReader());return}if(!u.value.trim()){console.log("no input, return"),f.value.focus();return}N.value.push({type:"user",content:u.value}),P.value=!0,b.value=!0,a("submit",u.value),O();const s=u.value;u.value="";const k=N.value.length;T.value[k]&&T.value[k].initializeStart(),C.value=!0,N.value.push({type:"ai"});const{error:x,reader:R}=await de(t.value,{text:s,token:o.token,identifier:o.identifier,baseUrl:o.baseUrl,extraConfig:o.extraConfig});if(x){console.log(45455,x),m(k,x);return}R&&(N.value[k].reader=R)};return(s,k)=>{const x=e.resolveComponent("el-icon"),R=e.resolveComponent("el-input");return e.openBlock(),e.createBlock(e.Transition,{name:"slide"},{default:e.withCtx(()=>[n.modelValue?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["ai-panel",{"drawer-mode":y.value}])},[e.createElementVNode("div",ye,[e.createElementVNode("div",ge,[e.createElementVNode("div",be,e.toDisplayString(n.title),1),e.createElementVNode("div",ke,[e.createVNode(x,{class:"action-icon",onClick:g},{default:e.withCtx(()=>[e.createVNode(U,{name:"/images/svg/drawer-layout.svg",color:"#999999"})]),_:1}),e.createVNode(x,{class:"action-icon",onClick:c},{default:e.withCtx(()=>[e.createVNode(U,{name:"/images/svg/close.svg",color:"#999999"})]),_:1})])])]),e.createElementVNode("div",we,[b.value?(e.openBlock(),e.createElementBlock("div",{key:1,class:"chat-messages",ref_key:"messageContainerRef",ref:j},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(N.value,(_,L)=>(e.openBlock(),e.createElementBlock("div",{key:L,class:e.normalizeClass(["message-item",_.type==="user"?"user-message":"ai-message"])},[_.type==="ai"?(e.openBlock(),e.createBlock(he,{key:0,ref_for:!0,ref:V=>T.value[L]=V,reader:_.reader,"onUpdate:reader":V=>_.reader=V,model:o.llmName,displayText:_.displayText,scrollToBottomFn:O,messagePostRender:n.messagePostRender,onFailed:V=>m(L,V),onCompleted:V=>p(L,V),onUpdating:()=>d()},null,8,["reader","onUpdate:reader","model","displayText","messagePostRender","onFailed","onCompleted","onUpdating"])):(e.openBlock(),e.createElementBlock("div",_e,e.toDisplayString(_.content),1))],2))),128))],512)):(e.openBlock(),e.createElementBlock("div",ve,[k[2]||(k[2]=e.createElementVNode("div",{class:"title"},[e.createElementVNode("img",{src:G,alt:"AI助手",class:"panel-icon"}),e.createElementVNode("h3",{class:"title-text"},"Hi, 您好")],-1)),e.createElementVNode("div",Se,[k[1]||(k[1]=e.createTextVNode(" 我是",-1)),e.createElementVNode("span",xe,e.toDisplayString(n.title),1)]),e.createElementVNode("div",Ne,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(B.value,(_,L)=>(e.openBlock(),e.createElementBlock("div",{key:L,class:"question-item",onClick:V=>S(_)},[e.createElementVNode("span",null,e.toDisplayString(_),1),e.createVNode(x,null,{default:e.withCtx(()=>[e.createVNode(U,{name:"/images/svg/arrow-right.svg",color:"#999999"})]),_:1})],8,Ce))),128))])]))]),e.createElementVNode("div",Ee,[P.value?(e.openBlock(),e.createElementBlock("img",Te)):e.createCommentVNode("",!0),e.createElementVNode("div",Re,[e.createVNode(R,{modelValue:u.value,"onUpdate:modelValue":k[0]||(k[0]=_=>u.value=_),ref_key:"refInputTextString",ref:f,placeholder:"请输入您的问题",autofocus:"",onKeyup:e.withKeys(w,["enter"])},{append:e.withCtx(()=>[e.createElementVNode("div",{class:"send-icon-box",onClick:w},[e.createElementVNode("img",{src:h.value,alt:"发送",class:"send-icon"},null,8,Pe)])]),_:1},8,["modelValue"])])])],2)):e.createCommentVNode("",!0)]),_:1})}}};var D={exports:{}};(function(n,r){(function(l,i){n.exports=i()})(window,function(){return function(l){var i={};function o(t){if(i[t])return i[t].exports;var a=i[t]={i:t,l:!1,exports:{}};return l[t].call(a.exports,a,a.exports,o),a.l=!0,a.exports}return o.m=l,o.c=i,o.d=function(t,a,u){o.o(t,a)||Object.defineProperty(t,a,{enumerable:!0,get:u})},o.r=function(t){typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.t=function(t,a){if(1&a&&(t=o(t)),8&a||4&a&&typeof t=="object"&&t&&t.__esModule)return t;var u=Object.create(null);if(o.r(u),Object.defineProperty(u,"default",{enumerable:!0,value:t}),2&a&&typeof t!="string")for(var f in t)o.d(u,f,(function(b){return t[b]}).bind(null,f));return u},o.n=function(t){var a=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(a,"a",a),a},o.o=function(t,a){return Object.prototype.hasOwnProperty.call(t,a)},o.p="",o(o.s=0)}([function(l,i,o){function t(h,m,p,d){p.push(h),d.push([].concat(m[h]||[]))}function a(h,m){if(!h)throw new Error("[getMaxDepsChain] dep 参数不能为空");var p=[],d=[],c=[];for(t(h,m,d,c);d.length;){var y=c.pop();if(y&&y.length){var g=y.shift();if(c.push(y),~d.indexOf(g))throw new Error("[getMaxDepsChain][loop] 存在循环依赖,请检查依赖关系; nextName: "+g+", mainStack: "+d);t(g,m,d,c)}else p.push([].concat(d)),d.pop()}return p.reduce(function(S,v){return v.length>S.length?v:S},[])}function u(h){if(!h)throw new Error("[depsParser] 入参不能为空");var m={};h.forEach(function(d){m[d.name]=d.deps||[]});var p=[];return h.forEach(function(d){var c=a(d.name,m).length-1;d.priority=c,p[c]=(p[c]||[]).concat(d)}),p}o.r(i),o.d(i,"loadScript",function(){return T}),o.d(i,"loadScripts",function(){return C}),o.d(i,"dynamicLoadScripts",function(){return j}),o.d(i,"createScriptsLoadIterator",function(){return O}),o.d(i,"loadScriptsQueue",function(){return P}),o.d(i,"getMaxDepsChain",function(){return a}),o.d(i,"depsParser",function(){return u});var f=function(){return(f=Object.assign||function(h){for(var m,p=1,d=arguments.length;p<d;p++)for(var c in m=arguments[p])Object.prototype.hasOwnProperty.call(m,c)&&(h[c]=m[c]);return h}).apply(this,arguments)},b=function(h,m,p,d){return new(p||(p=Promise))(function(c,y){function g(w){try{v(d.next(w))}catch(s){y(s)}}function S(w){try{v(d.throw(w))}catch(s){y(s)}}function v(w){var s;w.done?c(w.value):(s=w.value,s instanceof p?s:new p(function(k){k(s)})).then(g,S)}v((d=d.apply(h,[])).next())})},N=function(h,m){var p,d,c,y,g={label:0,sent:function(){if(1&c[0])throw c[1];return c[1]},trys:[],ops:[]};return y={next:S(0),throw:S(1),return:S(2)},typeof Symbol=="function"&&(y[Symbol.iterator]=function(){return this}),y;function S(v){return function(w){return function(s){if(p)throw new TypeError("Generator is already executing.");for(;g;)try{if(p=1,d&&(c=2&s[0]?d.return:s[0]?d.throw||((c=d.return)&&c.call(d),0):d.next)&&!(c=c.call(d,s[1])).done)return c;switch(d=0,c&&(s=[2&s[0],c.value]),s[0]){case 0:case 1:c=s;break;case 4:return g.label++,{value:s[1],done:!1};case 5:g.label++,d=s[1],s=[0];continue;case 7:s=g.ops.pop(),g.trys.pop();continue;default:if(c=g.trys,!((c=c.length>0&&c[c.length-1])||s[0]!==6&&s[0]!==2)){g=0;continue}if(s[0]===3&&(!c||s[1]>c[0]&&s[1]<c[3])){g.label=s[1];break}if(s[0]===6&&g.label<c[1]){g.label=c[1],c=s;break}if(c&&g.label<c[2]){g.label=c[2],g.ops.push(s);break}c[2]&&g.ops.pop(),g.trys.pop();continue}s=m.call(h,g)}catch(k){s=[6,k],d=0}finally{p=c=0}if(5&s[0])throw s[1];return{value:s[0]?s[1]:void 0,done:!0}}([v,w])}}},B=function(h){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var m,p=h[Symbol.asyncIterator];return p?p.call(h):(h=typeof __values=="function"?__values(h):h[Symbol.iterator](),m={},d("next"),d("throw"),d("return"),m[Symbol.asyncIterator]=function(){return this},m);function d(c){m[c]=h[c]&&function(y){return new Promise(function(g,S){(function(v,w,s,k){Promise.resolve(k).then(function(x){v({value:x,done:s})},w)})(g,S,(y=h[c](y)).done,y.value)})}}};function T(h,m){return m===void 0&&(m=!1),new Promise(function(p,d){var c=m?document.head:document.body,y=document.createElement("script");y.type="text/javascript",y.src=h,y.crossOrigin="anonymous",y.onreadystatechange=p,y.onload=p,y.onerror=d,c.appendChild(y)})}var C=function(h,m){return m===void 0&&(m={}),b(void 0,void 0,void 0,function(){var p,d,c,y,g;return N(this,function(S){switch(S.label){case 0:return p=m.baseUrl,d=p===void 0?"":p,c=m.lastLoadResult,y=m.inHead,g=y!==void 0&&y,[4,Promise.all(h.map(function(v){return b(void 0,void 0,void 0,function(){var w,s,k,x,R,_,L,V;return N(this,function(Y){switch(Y.label){case 0:return w=v.name,s=v.path,k=v.deps,(L={})[w]=!0,x=L,(V={})[w]=!1,R=V,window[w]?[2,x]:[3,1];case 1:return _=!0,k&&c&&[].concat(k).forEach(function(Fe){c[Fe]!==!1&&(_=!0)}),_?[4,T(s.indexOf("http")===0||s.indexOf("//:")===0?s:d+s,g).then(function(){return x}).catch(function(){return R})]:[3,3];case 2:return[2,Y.sent()];case 3:return[2,R]}})})}))];case 1:return[2,S.sent()]}})})},j=function(h,m){return m===void 0&&(m={}),function(){var p=[].concat(u(h));return{next:function(){if(p.length){var d=p.shift();return C(d,m).then(function(c){return{value:c,done:!1}})}return Promise.resolve({done:!0})}}}},O=function(h,m){var p;return m===void 0&&(m={}),(p={})[Symbol.asyncIterator]=j(h,m),p},P=function(h,m){return m===void 0&&(m={}),b(void 0,void 0,void 0,function(){var p,d,c,y,g,S;return N(this,function(v){switch(v.label){case 0:v.trys.push([0,5,6,11]),p=B(O(h,m)),v.label=1;case 1:return[4,p.next()];case 2:if((d=v.sent()).done)return[3,4];c=d.value,m.lastLoadResult=m.lastLoadResult||{},console.log("current load: ",c),c.forEach(function(w){m.lastLoadResult=f(f({},m.lastLoadResult),w)}),v.label=3;case 3:return[3,1];case 4:return[3,11];case 5:return y=v.sent(),g={error:y},[3,11];case 6:return v.trys.push([6,,9,10]),d&&!d.done&&(S=p.return)?[4,S.call(p)]:[3,8];case 7:v.sent(),v.label=8;case 8:return[3,10];case 9:if(g)throw g.error;return[7];case 10:return[7];case 11:return[2,m.lastLoadResult]}})})}}])})})(D);var Be=D.exports;const Oe={key:0,class:"ai-assistant"},Le={name:"AiChat"},je=e.defineComponent({...Le,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:()=>({})}},setup(n){const r=e.ref(!1),l=e.ref(!1),i=()=>{r.value=!r.value},o=()=>{l.value=!0,r.value=!1},t=f=>{console.log("用户输入:",f)},a=[{name:"markdownit",path:"markdown-it.min.js"},{name:"hljs",path:"highlight.11.11.1.min.js"}];let u={};return Be.loadScriptsQueue(a,{baseUrl:"/scripts/ai/",lastLoadResult:u,inHead:!1}).then(f=>{if(console.log("load ai deps: ",f),window.markdownit){const b=window.markdownit();console.log("markdownit: ",b),ue()}}),(f,b)=>l.value?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("div",Oe,[e.createVNode(Ve,{modelValue:r.value,"onUpdate:modelValue":b[0]||(b[0]=N=>r.value=N),onSubmit:t,token:n.token,identifier:n.identifier,baseUrl:n.baseUrl,title:n.title,llmName:n.llmName,messagePostRender:n.messagePostRender,extraConfig:n.extraConfig},null,8,["modelValue","token","identifier","baseUrl","title","llmName","messagePostRender","extraConfig"]),e.createElementVNode("div",{class:"ai-icon",onClick:i},[e.createElementVNode("div",{class:"close-icon",onClick:e.withModifiers(o,["stop"])},[...b[1]||(b[1]=[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)])]),b[2]||(b[2]=e.createElementVNode("img",{src:Z,alt:"AI助手"},null,-1)),b[3]||(b[3]=e.createElementVNode("span",{class:"ai-icon-text"},"AI助手",-1))])]))}}),W=F(je,[["__scopeId","data-v-33f89960"]]),J=Object.freeze(Object.defineProperty({__proto__:null,SzAiChat:W},Symbol.toStringTag,{value:"Module"})),I=function(n){if(!I.installed){I.installed=!0;for(let r in J){const l=Reflect.get(J,r);n.component(l.name,l)}}},ze=(n,r)=>{const l=r?`?${new URLSearchParams(r).toString()}`:"";console.log(`点击了路由链接: ${n}${l}`)},H=n=>{const r=n.indexOf("?");if(r===-1)return{routeName:n};const l=n.substring(0,r),i=n.substring(r+1),o={};return new URLSearchParams(i).forEach((a,u)=>{o[u]=a}),{routeName:l,queryParams:Object.keys(o).length>0?o:void 0}},Ue={color:"#536fec",fontWeight:"bold",textDecoration:"underline",cursor:"pointer",padding:"0 3px"},Q=n=>{const r=/#router:([^#]+)#/g,l=[];let i=0,o;for(;(o=r.exec(n))!==null;){o.index>i&&l.push({text:n.substring(i,o.index)});const t=o[1],{routeName:a,queryParams:u}=H(t);l.push({text:a,routeName:a,queryParams:u}),i=r.lastIndex}return i<n.length&&l.push({text:n.substring(i)}),l},K=(n,r,l={},i)=>{const{onRouteClick:o=ze,linkStyle:t={}}=l,a=document.createElement("a");a.href="#",a.textContent=n;const u={...Ue,...t};return Object.assign(a.style,u),a.addEventListener("click",f=>{f.preventDefault(),o(r,i)}),a},X=n=>{const r=/#router:([^#]+)#/g,l=[],i=document.createTreeWalker(n,NodeFilter.SHOW_TEXT,null);let o=i.nextNode();for(;o;){const t=o,a=t.textContent||"";if(r.test(a)){r.lastIndex=0;const u=Q(a);u.length>0&&l.push({node:t,replacements:u})}o=i.nextNode()}return l},Ie=(n,r,l={})=>{const i=X(n);i.forEach(({node:o,replacements:t})=>{var u;const a=document.createDocumentFragment();t.forEach(({text:f,routeName:b,queryParams:N})=>{if(b){const B=K(f,b,l,N);a.appendChild(B)}else a.appendChild(document.createTextNode(f))}),(u=o.parentNode)==null||u.replaceChild(a,o)}),l!=null&&l.nodeCallback&&i.forEach(({node:o,replacements:t})=>{var a;(a=l.nodeCallback)==null||a.call(l,o,t)})},$e="0.1.8",Ae="Sz";function qe({componentPrefix:n=Ae,components:r=[]}={}){const l=[];function i(t,a,u){t.component(n+a)||t.component(n+a,u)}function o(t){l.includes(t)||(l.push(t),r.forEach(a=>{const{name:u,alias:f}=a;i(t,u,a),f&&f.forEach(b=>{i(t,b,a)})}))}return{version:$e,componentPrefix:n,install:o}}const Me={install(n){I(n)}};E.SzAiChat=W,E.create=qe,E.createRouteLink=K,E.default=Me,E.findRouteTextNodes=X,E.parseRouteMarkerContent=H,E.parseRouteMarkers=Q,E.routeLinkRender=Ie,Object.defineProperties(E,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
1
+ (function(C,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(C=typeof globalThis<"u"?globalThis:C||self,e(C["szjy-ai-coms"]={},C.Vue))})(this,function(C,e){"use strict";var vn=Object.defineProperty;var Nn=(C,e,Z)=>e in C?vn(C,e,{enumerable:!0,configurable:!0,writable:!0,value:Z}):C[e]=Z;var x=(C,e,Z)=>Nn(C,typeof e!="symbol"?e+"":e,Z);const Z="/images/ai-round.png",We="/images/ai-sqrt.png",qe="/images/bars-loading.svg";function Se(r){return r.startsWith("http://")||r.startsWith("https://")?r:`${location.protocol}//${location.host}${r}`}async function Ge(r,t,a,n="",s={}){const{projectId:o}=s,i=Se(n),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 k=new Request(l,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${c}`},body:JSON.stringify({model:"dify",stream:!0,inputs:{token:t,projectCode:a,...o?{projectId:o}:{}},messages:[{role:"system",content:"你是一个专业的AI助手,请用中文回答问题。"},{role:"user",content:r}]})});return fetch(k)}async function Je(r,t,a,n="",s={}){const o=new URL("http://localhost:11434/api/chat"),i={};Object.keys(i).forEach(c=>{o.searchParams.append(c,i[c])});const l=new Request(o,{mode:"cors",method:"post",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:"llama3",stream:!0,messages:[{role:"system",content:"全程使用中文回答问题。"},{role:"user",content:r}]})});return fetch(l)}async function Ke(r,t,a,n="",s={}){const o=new URL(`${location.origin}/spark/v1/chat/completions`),i={};Object.keys(i).forEach(c=>{o.searchParams.append(c,i[c])});const l=new Request(o,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({model:"generalv4.0Ultra",stream:!0,messages:[{role:"user",content:r}]})});return fetch(l)}async function Qe(r,t,a,n="",s={}){const o=new URL(`${location.origin}/siliconflow/v1/chat/completions`),i={};Object.keys(i).forEach(c=>{o.searchParams.append(c,i[c])});const l=new Request(o,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({model:"Qwen/Qwen1.5-110B-Chat",stream:!0,messages:[{role:"user",content:r}]})});return fetch(l)}async function Ze(r,t,a,n="",s={}){const o=new URL(`${location.origin}/moonshot/v1/chat/completions`),i={};Object.keys(i).forEach(c=>{o.searchParams.append(c,i[c])});const l=new Request(o,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({model:"moonshot-v1-8k",stream:!0,messages:[{role:"system",content:"你是 Kimi,由 Moonshot AI 提供的人工智能助手,你更擅长中文和英文的对话。你会为用户提供安全,有帮助,准确的回答。同时,你会拒绝一切涉及恐怖主义,种族歧视,黄色暴力等问题的回答。Moonshot AI 为专有名词,不可翻译成其他语言。"},{role:"user",content:r}]})});return fetch(l)}async function Ye(r,t,a,n="",s={}){const o=new URL(`${location.origin}/dashscope/compatible-mode/v1/chat/completions`),i={};Object.keys(i).forEach(c=>{o.searchParams.append(c,i[c])});const l=new Request(o,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({model:"qwq-32b-preview",stream:!0,messages:[{role:"system",content:"全程使用中文回答问题"},{role:"user",content:r}]})});return fetch(l)}async function Xe(r,t,a,n="",s={}){const o=Se(n),i=new URL(`${o}/support/${a}/a`),l={};Object.keys(l).forEach(k=>{i.searchParams.append(k,l[k])});const c=new Request(i,{method:"post",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({content:r})});return fetch(c)}const et=r=>{if(r.startsWith("data:")){const t=r.substring(5).trim();if(t==="[DONE]")return{done:!0};try{return JSON.parse(t)}catch(a){console.error("JSON parsing error:",a)}}return null},he="<think>",ie="</think>",me=(r,t)=>{const a=Math.max(0,r.length-(t.length-1));for(let n=a;n<r.length;n++)if(t.startsWith(r.slice(n)))return r.length-n;return 0},tt=r=>{let t="",a="",n=r||"",s=!1;for(;n;){const o=n.indexOf(he),i=n.indexOf(ie);if(o>=0&&(i<0||o<i))a+=n.slice(0,o),n=n.slice(o+he.length),s=!0;else if(i>=0&&(o<0||i<o))t+=n.slice(0,i),n=n.slice(i+ie.length),s=!1;else if(s){const l=me(n,ie);t+=n.slice(0,n.length-l),n=""}else{const l=Math.max(me(n,he),me(n,ie));a+=n.slice(0,n.length-l),n=""}}return{thinking:t.trim(),content:a.trim(),isThinkingStreaming:s}},Ee=[{label:"模拟数据模型",modelName:"standard",api:null},{label:"Spark 星火大模型",modelName:"spark",api:Ke},{label:"Ollama 3 大模型",modelName:"ollama3",api:Je},{label:"SiliconFlow 硅基流动大模型",modelName:"siliconflow",api:Qe},{label:"Kimi Moonshot 月之暗面大模型",modelName:"moonshot",api:Ze},{label:"通义千问大模型",modelName:"dashscope",api:Ye},{label:"数智建管大模型",modelName:"szjy",api:Xe},{label:"Dify (OpenAI 兼容)",modelName:"dify-openai",api:Ge}],ve={standard(r,t){let a="";return r instanceof Uint8Array?a=t.decode(r,{stream:!0}):a=r,{content:a}},spark(r){const t=et(r);if(t.done)return{done:!0};const a=t.choices[0].delta,n=a.reasoning_content||a.reasoning;let s=a.content||"";return n&&(s=`<think>${n}</think>${s}`),{content:s}},siliconflow(r){return this.spark(r)},moonshot(r){return this.spark(r)},dashscope(r){return this.spark(r)},szjy(r){return this.spark(r)},"dify-openai"(r){return this.spark(r)},ollama3(r){return{content:JSON.parse(r).message.content}}},Ne=(r,t,a)=>{const n=r.split(a);return n.slice(0,-1).forEach(s=>{s.trim()!==""&&t.enqueue(s)}),n[n.length-1]},nt=r=>{let t="";return new TransformStream({transform(a,n){if(t+=a,t.trim().startsWith("data:"))t=Ne(t,n,r);else try{JSON.parse(t),t=Ne(t,n,r)}catch{n.enqueue(a),t=""}},flush(a){t.trim()!==""&&a.enqueue(t)}})};async function ot(r,t){const a=r.api;return a?new Promise(n=>{a(t.text,t.token,t.identifier,t.baseUrl,t.extraConfig).then(s=>{if(s.body){const o=s.body.pipeThrough(new TextDecoderStream).pipeThrough(nt(`
2
+ `)).getReader();console.log("reader from response:",o),n({error:0,reader:o})}else n({error:1,reader:null})}).catch(()=>{n({error:1,reader:null})})}):{error:1,reader:null}}let H=null;function rt(){return H||(window.markdownit?(H=new window.markdownit({html:!0,linkify:!0,typographer:!0}),H.renderer.rules.fence=(r,t)=>{const a=r[t],n=(a.info||"").trim().split(/\s+/)[0];let s="";if(n&&window.hljs&&window.hljs.getLanguage(n))try{s=window.hljs.highlight(a.content,{language:n}).value}catch{s=""}return s||(s=H.utils.escapeHtml(a.content)),`<pre class="md-code-block"><code class="hljs${n?" language-"+n:""}">${s}</code></pre>`}):console.log("markdownit is not loaded"),H)}const at=(r,t)=>{const a=r.__vccOpts||r;for(const[n,s]of t)a[n]=s;return a},st=["src","alt"],le=at({__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(r){const t=r,a=e.computed(()=>{if(t.name.startsWith("http://")||t.name.startsWith("https://")||t.name.startsWith("/"))return t.name;const o=t.name.endsWith(".svg")?t.name:`${t.name}.svg`;return`${t.basePath}${o}`}),n=e.computed(()=>{const o=typeof t.size=="number"?`${t.size}px`:t.size;return{width:o,height:o,display:"inline-flex",justifyContent:"center",alignItems:"center"}}),s=e.computed(()=>{const o={width:"100%",height:"100%"};return t.color&&(o.filter=`drop-shadow(0 0 0 ${t.color})`),o});return(o,i)=>(e.openBlock(),e.createElementBlock("div",{class:"svg-icon-wrapper",style:e.normalizeStyle(n.value)},[e.createElementVNode("img",{src:a.value,alt:r.name,class:e.normalizeClass(["svg-icon",r.className]),style:e.normalizeStyle(s.value)},null,14,st)],4))}},[["__scopeId","data-v-490b11c1"]]),it=async r=>{if(navigator.clipboard&&navigator.permissions)await navigator.clipboard.writeText(r);else{const t=document.createElement("textArea");t.value=r,t.style.width=0,t.style.position="fixed",t.style.left="-999px",t.style.top="10px",t.setAttribute("readonly","readonly"),document.body.appendChild(t),t.select(),document.execCommand("copy"),document.body.removeChild(t)}},lt={class:"thinking-title"},ct={class:"thinking-toggle-hint"},dt=["innerHTML"],ut=["innerHTML"],ht=10,mt={__name:"Previewer",props:{reader:null,model:"szjy",scrollToBottomFn:null,displayText:"",messagePostRender:{type:Function,default:null}},emits:["failed","completed","updating"],setup(r,{expose:t,emit:a}){const{appContext:n}=e.getCurrentInstance(),{$message:s}=n.config.globalProperties,o=r,i=e.ref(o.displayText||""),l=e.ref(!0),c=e.ref(!1),k=e.ref(!!o.displayText),E=a,_=e.ref(null);let V=null;const S=e.computed(()=>tt(i.value)),z=e.computed(()=>S.value.thinking.length>0),v=e.ref(o.displayText?S.value.content.length:0),P=e.computed(()=>S.value.isThinkingStreaming&&!k.value),y=e.ref(!1),f=()=>{y.value=!y.value};let p=null,u=null;const d=e.ref(0);e.watch(()=>S.value.thinking,I=>{!I||d.value>0||(u===null&&(u=p??Date.now()),S.value.content&&w())});const w=()=>{if(d.value>0||!z.value)return;const I=u??p;I&&(d.value=Math.max(1,Math.round((Date.now()-I)/1e3)))},b=e.computed(()=>P.value?"正在思考...":d.value>0?`已深度思考(用时 ${d.value} 秒)`:"思考过程"),B=e.computed(()=>z.value?H?H.render(S.value.thinking):S.value.thinking:""),N=e.computed(()=>S.value.content.slice(0,v.value)),R=e.computed(()=>H?H.render(N.value):N.value),g=()=>{o.reader&&o.reader.cancel(),c.value=!0,O.value=!1,D(),k.value=!0,w(),E("completed",i.value),l.value=!1,V&&(cancelAnimationFrame(V),V=null)},U=e.computed(()=>`${R.value}`),$=e.ref(!1),q=()=>{$.value=!0},D=()=>{$.value=!1},O=e.ref(!1),X=async()=>{if(!o.reader)return;const I=new TextDecoder("utf-8");for(l.value=!0;!c.value;)try{if(!o.reader){O.value=!0;break}const{value:M,done:A}=await o.reader.read();if(!o.reader){O.value=!0;break}if(A){O.value=!0;break}const j=ve[o.model];if(!j)break;const K=j.call(ve,M,I);if(K.done){O.value=!0;break}!p&&K.content&&(p=Date.now()),i.value+=K.content,V===null&&ae()}catch(M){O.value=!0,console.log(3333,M),E("failed",M),g();break}finally{D()}},ee=async()=>{o.scrollToBottomFn&&o.scrollToBottomFn()},te=(I=()=>{},M=()=>{})=>{const A=S.value.content.length;v.value>A&&(v.value=A),v.value<A?(v.value=Math.min(A,v.value+ht),I()):M()},ae=()=>{if(c.value&&V){cancelAnimationFrame(V),V=null,l.value=!1;return}O.value?te(()=>{V=requestAnimationFrame(ae),E("updating",null)},()=>{w(),E("completed",i.value),l.value=!1,k.value=!0,e.nextTick(()=>{if(O.value=!1,o.messagePostRender&&_.value)try{o.messagePostRender(_.value,S.value.content)}catch(I){console.error("messagePostRender 执行失败:",I)}}),V=null}):(te(),V=requestAnimationFrame(ae)),ee()};e.watch(()=>o.reader,()=>{o.reader&&X()},{immediate:!0,deep:!0}),e.onUnmounted(()=>{g()}),t({abortReader:g,initializeStart:q,initializeEnd:D}),e.computed(()=>$.value?!0:(!o.reader||!l||i.value,!1));const ue=async()=>{try{const I=S.value.content||i.value;await it(I),s.success("复制成功")}catch(I){console.error("复制失败:",I),s.error("复制失败")}};return(I,M)=>(e.openBlock(),e.createBlock(e.Transition,{name:"fade"},{default:e.withCtx(()=>[U.value||z.value?(e.openBlock(),e.createElementBlock("div",{key:0,ref_key:"refWrapperContent",ref:_,"text-16":"",class:"w-full h-full overflow-y-auto relative","p-24px":""},[z.value?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["ai-thinking-block",{"is-expanded":y.value||P.value,"is-streaming":P.value}])},[e.createElementVNode("div",{class:"thinking-header",onClick:f},[M[0]||(M[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",lt,e.toDisplayString(b.value),1),e.createElementVNode("span",ct,e.toDisplayString(y.value||P.value?"收起":"展开"),1)]),e.withDirectives(e.createElementVNode("div",{class:"thinking-body",innerHTML:B.value},null,8,dt),[[e.vShow,y.value||P.value]])],2)):e.createCommentVNode("",!0),e.createElementVNode("div",{class:"markdown-wrapper",innerHTML:U.value},null,8,ut),k.value?(e.openBlock(),e.createElementBlock("div",{key:1,class:"ai-copy-btn-wrapper",onClick:ue},[e.createVNode(le,{name:"/images/svg/copy.svg",color:"#666666"}),M[1]||(M[1]=e.createElementVNode("span",{class:"copy-text"},"复制",-1))])):e.createCommentVNode("",!0)],512)):e.createCommentVNode("",!0)]),_:1}))}};class Ve{constructor(t,a){x(this,"ratio");x(this,"leftover",new Float32Array(0));x(this,"fracOffset",0);this.ratio=t/a}reset(){this.leftover=new Float32Array(0),this.fracOffset=0}process(t){if(this.ratio===1)return new Float32Array(t);const a=new Float32Array(this.leftover.length+t.length);if(a.set(this.leftover),a.set(t,this.leftover.length),a.length<2)return this.leftover=a,new Float32Array(0);const n=[];let s=this.fracOffset;for(;s<a.length-1;){const i=Math.floor(s),l=s-i,c=a[i],k=a[i+1];n.push(c+l*(k-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(n)}}class xe{constructor(t={}){x(this,"targetSampleRate");x(this,"audioContext",null);x(this,"mediaStream",null);x(this,"sourceNode",null);x(this,"processorNode",null);x(this,"muteGain",null);x(this,"resampler",null);x(this,"audioChunks",[]);x(this,"onVolumeChange");x(this,"onAudioChunk");x(this,"_isRecording",!1);this.targetSampleRate=t.sampleRate||16e3,this.onVolumeChange=t.onVolumeChange,this.onAudioChunk=t.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(n){throw n.name==="NotAllowedError"||n.name==="PermissionDeniedError"?new Error("麦克风权限被拒绝,请在浏览器地址栏允许麦克风访问权限。"):n.name==="NotFoundError"||n.name==="DevicesNotFoundError"?new Error("未检测到可用的麦克风输入设备。"):new Error(`无法启动麦克风: ${n.message||n}`)}const t=window.AudioContext||window.webkitAudioContext;try{this.audioContext=new t({sampleRate:this.targetSampleRate})}catch{this.audioContext=new t}this.audioContext.state==="suspended"&&await this.audioContext.resume(),this.audioChunks=[],this.resampler=this.audioContext.sampleRate===this.targetSampleRate?null:new Ve(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=n=>{var i;if(!this._isRecording)return;const s=new Float32Array(n.inputBuffer.getChannelData(0));if(this.onVolumeChange){let l=0;for(let E=0;E<s.length;E++)l+=s[E]*s[E];const c=Math.sqrt(l/s.length),k=Math.min(100,Math.round(c*100*5));this.onVolumeChange(k)}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 t=this.audioChunks.reduce((s,o)=>s+o.length,0),a=new Float32Array(t);let n=0;for(const s of this.audioChunks)a.set(s,n),n+=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(t=>t.stop()),this.mediaStream=null),this.audioContext&&this.audioContext.state!=="closed"&&(this.audioContext.close().catch(()=>{}),this.audioContext=null)}}function Te(r,t,a){if(t===a)return new Float32Array(r);const n=t/a,s=Math.round(r.length/n),o=new Float32Array(s);for(let i=0;i<s;i++){const l=i*n,c=Math.floor(l),k=l-c,E=r[c]??0,_=r[c+1]??E;o[i]=E+k*(_-E)}return o}async function Re(r,t=16e3){const a=await r.arrayBuffer(),n=window.AudioContext||window.webkitAudioContext,s=new n;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 k=0;k<o.length;k++)i[k]+=c[k]/o.numberOfChannels}}else i=o.getChannelData(0);return Te(i,o.sampleRate,t)}finally{s.state!=="closed"&&await s.close().catch(()=>{})}}function fe(r,t=16e3){const a=new ArrayBuffer(44+r.length*2),n=new DataView(a),s=(i,l)=>{for(let c=0;c<l.length;c++)n.setUint8(i+c,l.charCodeAt(c))};s(0,"RIFF"),n.setUint32(4,36+r.length*2,!0),s(8,"WAVE"),s(12,"fmt "),n.setUint32(16,16,!0),n.setUint16(20,1,!0),n.setUint16(22,1,!0),n.setUint32(24,t,!0),n.setUint32(28,t*2,!0),n.setUint16(32,2,!0),n.setUint16(34,16,!0),s(36,"data"),n.setUint32(40,r.length*2,!0);let o=44;for(let i=0;i<r.length;i++,o+=2){const l=Math.max(-1,Math.min(1,r[i]));n.setInt16(o,l<0?l*32768:l*32767,!0)}return new Blob([n],{type:"audio/wav"})}const Be=16e3,ft=Math.round(Be*.35),pe="/scripts/ai/whisper.worker.js";function pt(){return new Worker(ge(pe),{type:"module"})}function ge(r){return/^https?:\/\//i.test(r)?r:typeof location<"u"?new URL(r,location.origin).href:r}function Ae(r){if(!r.ok)return!1;const t=(r.headers.get("content-type")||"").toLowerCase();return!(t.includes("text/html")||t.includes("application/xhtml+xml"))}async function gt(r){try{const t=await fetch(r,{method:"HEAD"});if(Ae(t))return!0}catch{}try{const t=await fetch(r,{headers:{Range:"bytes=0-64"}});if(Ae(t))return!0}catch{}return!1}async function yt(r){const t=[];r&&t.push(ge(r)),t.push(ge(pe));const a=[...new Set(t.filter(Boolean))];for(const n of a)if(await gt(n))return console.log("[VoiceInputManager] 使用语音 Worker:",n),n;return console.warn("[VoiceInputManager] 未探测到可访问的 Worker 脚本,将回退到 Vite 打包注入地址。已尝试:",a.join(" , ")),null}class _e{constructor(t={}){x(this,"recorder",null);x(this,"worker",null);x(this,"status","idle");x(this,"options");x(this,"isReady",!1);x(this,"initPromise",null);x(this,"currentTaskId",0);x(this,"pcmParts",[]);x(this,"pcmLength",0);x(this,"streamChunkIndex",0);x(this,"committedText","");this.options={soundBaseUrl:"/sounds/",remoteHost:"https://hf-mirror.com",modelId:"onnx-community/whisper-base",language:"chinese",...t}}get currentStatus(){return this.status}get ready(){return this.isReady}async init(t){if(!this.isReady)return this.initPromise?this.initPromise:(t&&(this.options.soundBaseUrl=t),this.initPromise=new Promise((a,n)=>{this.setStatus("loading","正在准备语音识别引擎..."),(async()=>{var o,i;try{const l=await yt(this.options.workerUrl);this.worker=l?new Worker(l,{type:"module"}):pt(),this.worker.onmessage=c=>{this.handleWorkerMessage(c,a,n)},this.worker.onerror=c=>{var _,V;const E=`语音后台线程异常: ${c.message||c.filename||l||"未知错误"}`;this.initPromise=null,this.setStatus("error",E),(V=(_=this.options).onError)==null||V.call(_,E),n(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),n(l)}})()}),this.initPromise)}async startRecording(){var t,a,n,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=(t=this.options).onError)==null||a.call(t,o),new Error(o)}this.isReady||await this.init(),this.recorder||(this.recorder=new xe({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=(n=this.options).onError)==null||s.call(n,o.message||"启动录音失败"),o}}async stopAndTranscribe(){var t,a,n,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=fe(o),l=URL.createObjectURL(i);(a=(t=this.options).onAudioRecorded)==null||a.call(t,l,i)}catch(i){console.warn("生成录音回放音频失败:",i)}await this.transcribeAudioData(o)}catch(o){this.setStatus("error",o.message||"音频处理失败"),(s=(n=this.options).onError)==null||s.call(n,o.message||"音频处理失败")}}async transcribeAudioData(t,a){var n,s,o,i;this.isReady||await this.init(),this.setStatus("transcribing","正在流式识别音频...");try{a&&((s=(n=this.options).onAudioRecorded)==null||s.call(n,a,fe(t))),this.currentTaskId++,this.resetStreamState(),this.appendPcm(t),this.dispatchFullAudio()}catch(l){this.setStatus("error",l.message||"音频处理失败"),(i=(o=this.options).onError)==null||i.call(o,l.message||"音频处理失败")}}async transcribeFile(t){var a,n;this.isReady||await this.init(),this.setStatus("loading","正在解析音频文件...");try{const s=await Re(t);if(s.length===0)throw new Error("未能从该文件中提取出有效音频");const o=URL.createObjectURL(t);await this.transcribeAudioData(s,o)}catch(s){this.setStatus("error",s.message||"音频文件解析失败"),(n=(a=this.options).onError)==null||n.call(a,s.message||"音频文件解析失败")}}cancelRecording(){var a;const t=this.currentTaskId;this.currentTaskId++,(a=this.worker)==null||a.postMessage({type:"CANCEL",taskId:t}),this.resetStreamState(),this.recorder&&this.recorder.cancel(),this.setStatus("idle")}cancelTranscribe(){var a;const t=this.currentTaskId;this.currentTaskId++,(a=this.worker)==null||a.postMessage({type:"CANCEL",taskId:t}),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 t=this.currentTaskId;this.currentTaskId++,(a=this.worker)==null||a.postMessage({type:"CANCEL",taskId:t}),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(t){!t||t.length===0||(this.pcmParts.push(new Float32Array(t)),this.pcmLength+=t.length)}mergePcm(){const t=new Float32Array(this.pcmLength);let a=0;for(const n of this.pcmParts)t.set(n,a),a+=n.length;return t}emitPartial(t){var a,n;(n=(a=this.options).onPartial)==null||n.call(a,(t||"").trim())}finishStream(t){var n,s;const a=(t??this.committedText).trim();this.setStatus("idle"),(s=(n=this.options).onResult)==null||s.call(n,a)}dispatchFullAudio(){if(!this.worker){this.finishStream();return}if(this.pcmLength<ft){this.finishStream();return}const t=this.mergePcm(),a=t.length>Be*30;this.committedText="",this.worker.postMessage({type:"TRANSCRIBE",data:{taskId:this.currentTaskId,audio:t,language:this.options.language,stream:!0,chunkIndex:this.streamChunkIndex++,isFinal:!0,mode:"append",nativeChunking:a}},[t.buffer])}handleWorkerMessage(t,a,n){var k,E,_,V;const{type:s,data:o,taskId:i,text:l,error:c}=t.data;switch(s){case"READY":this.isReady=!0,this.setStatus("ready","语音引擎就绪"),a==null||a();break;case"PROGRESS":if(o){const S=typeof o.progress=="number"?Math.round(o.progress):0;this.setStatus("downloading",`正在下载语音模型... ${S}%`),(E=(k=this.options).onProgress)==null||E.call(k,{status:o.status||"progress",progress:S,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=(_=this.options).onError)==null||V.call(_,c||"语音服务异常"),n==null||n(new Error(c));break}}setStatus(t,a){var n,s;this.status=t,(s=(n=this.options).onStatusChange)==null||s.call(n,t,a)}}const kt={class:"panel-header"},wt={class:"header-actions"},bt={class:"header-title"},Ct={class:"action-icons"},St={class:"body-content"},Et={key:0,class:"welcome-content"},vt={class:"subtitle"},Nt={class:"highlight"},Vt={class:"quick-questions"},xt=["onClick"],Tt={key:1,class:"message-content user-content"},Rt={class:"panel-footer"},Bt={key:0,src:qe,alt:"加载中",class:"loading-icon"},At={key:0,class:"voice-progress-banner"},_t={class:"progress-info"},Pt={class:"progress-text"},Ut={key:0,class:"progress-percent"},It={key:0,class:"progress-track"},Lt={class:"recording-main"},Mt={class:"recording-status"},Ft={key:0,class:"recording-time"},Ot={class:"recording-hint"},zt={key:1,class:"volume-waves"},Dt={class:"recording-actions"},$t=["title"],jt={key:0,class:"voice-playback-bar"},Ht=["title"],Wt={class:"playback-play-icon"},qt={key:0,viewBox:"0 0 24 24",width:"14",height:"14",fill:"currentColor"},Gt={key:1,viewBox:"0 0 24 24",width:"14",height:"14",fill:"currentColor"},Jt={class:"playback-title"},Kt={key:0,class:"playback-time"},Qt={key:1,class:"playback-waves"},Zt={class:"input-box"},Yt={class:"input-actions-box"},Xt=["src"],Pe={__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}},emits:["update:modelValue","submit"],setup(r,{emit:t}){const{appContext:a}=e.getCurrentInstance(),{$message:n}=a.config.globalProperties,s=r;let o=null;const i=e.ref("idle"),l=e.ref(""),c=e.ref(0),k=e.ref(0),E=e.ref(0);let _=null;const V=e.ref(""),S=e.ref(!1),z=e.ref(0);let v=null;const P=e.ref(""),y=e.ref(""),f=e.computed(()=>i.value==="downloading"),p=e.computed(()=>i.value==="loading"),u=e.computed(()=>i.value==="recording"),d=e.computed(()=>i.value==="transcribing"),w=e.computed(()=>u.value?"正在录音,点击完成后开始识别":P.value?"正在流式转写...":"正在识别语音中..."),b=e.computed(()=>s.enableVoiceInput?"请输入您的问题或点击麦克风语音输入":s.enableVoiceUpload?"请输入您的问题或上传音频识别":"请输入您的问题"),B=(m,h)=>{const T=(m||"").trim(),L=(h||"").trim();return L?T?/[A-Za-z0-9]$/.test(T)&&/[A-Za-z0-9]/.test(L.charAt(0))?`${T} ${L}`:`${T}${L}`:L:T},N=m=>{const h=Math.floor(m/60),T=m%60;return`${h.toString().padStart(2,"0")}:${T.toString().padStart(2,"0")}`},R=()=>(o||(o=new _e({soundBaseUrl:s.soundBaseUrl||"/sounds/",workerUrl:s.workerUrl||void 0,onStatusChange:(m,h)=>{i.value=m,h&&(l.value=h)},onProgress:m=>{typeof m.progress=="number"&&(c.value=m.progress)},onVolumeChange:m=>{k.value=m},onAudioRecorded:m=>{V.value&&URL.revokeObjectURL(V.value),V.value=m,z.value=E.value},onPartial:m=>{P.value=m||"",A.value=B(y.value,m)},onResult:m=>{P.value=m||"",A.value=B(y.value,m),m?n.success("语音识别完成"):n.warning("未能识别出有效语音,请重试"),setTimeout(()=>{P.value="",j.value&&j.value.focus()},100)},onError:m=>{n.error(m||"语音输入服务出错"),U()}})),o),g=()=>{U(),E.value=0,_=setInterval(()=>{E.value+=1},1e3)},U=()=>{_&&(clearInterval(_),_=null)},$=async()=>{if(!s.enableVoiceInput)return;if(u.value){await q();return}S.value&&v&&(v.pause(),S.value=!1);const m=R();try{y.value=A.value,P.value="",g(),await m.startRecording()}catch(h){U(),console.error("启动录音失败:",h)}},q=async()=>{U(),o&&await o.stopAndTranscribe()},D=e.ref(null),O=()=>{s.enableVoiceUpload&&D.value&&(D.value.value="",D.value.click())},X=async m=>{var W;if(!s.enableVoiceUpload)return;const h=m.target,T=(W=h==null?void 0:h.files)==null?void 0:W[0];if(!T)return;S.value&&v&&(v.pause(),S.value=!1);const L=R();try{y.value=A.value,P.value="",n.info(`正在流式识别文件: ${T.name}`),await L.transcribeFile(T)}catch(F){n.error(`文件识别失败: ${F.message||F}`)}},ee=()=>{U(),P.value="",A.value=y.value,o&&o.cancelRecording()},te=()=>{P.value="",A.value=y.value,o&&o.cancelTranscribe(),n.info("已取消本次语音识别")},ae=()=>{if(V.value){if(S.value&&v){v.pause(),S.value=!1;return}v&&(v.pause(),v=null),v=new Audio(V.value),v.onloadedmetadata=()=>{v&&!isNaN(v.duration)&&(z.value=Math.round(v.duration))},v.onended=()=>{S.value=!1},v.onerror=()=>{S.value=!1,n.error("音频试听播放失败")},v.play().then(()=>{S.value=!0}).catch(m=>{console.error("音频播放出错:",m),S.value=!1})}},ue=()=>{v&&(v.pause(),v=null),S.value=!1,V.value&&(URL.revokeObjectURL(V.value),V.value="")};e.onBeforeUnmount(()=>{U(),ue(),o&&(o.destroy(),o=null)});const I=e.computed(()=>Ee.find(m=>m.modelName===s.llmName)??Ee.find(m=>m.modelName==="szjy")),M=t,A=e.ref(""),j=e.ref(null),K=e.ref(!1),G=e.ref([]),yn=e.ref(["什么是AI助理,能做什么?","当前项目的基本情况?","当前项目的进度情况?","当前项目的参建方有哪些?","数智建管平台有哪些功能?能做什么?"]),ne=e.ref([]),se=e.ref(!1),ke=e.ref(null),we=()=>{e.nextTick(()=>{if(ke.value){const m=ke.value,h=m.scrollHeight,T=m.scrollTop,L=m.clientHeight;h-T-L<100?m.scrollTop=h:m.scrollTo({top:h})}})},Q=e.ref(!1),kn=e.computed(()=>Q.value?"/images/ai-stop.png":"/images/ai-send.png"),je=(m,h)=>{console.log("onFailedReader",m,h),se.value=!1;const T=He();T&&T.initializeEnd(),n.error("转换失败,请重试"),Q.value=!1,setTimeout(()=>{j.value&&j.value.focus()})},wn=(m,h)=>{se.value=!1,Q.value=!1,we(),h&&G.value[m]&&(G.value[m].displayText=h),setTimeout(()=>{j.value&&j.value.focus()})},bn=m=>{Q.value=!0},Cn=()=>{Q.value=!1,M("update:modelValue",!1),K.value=!1,G.value=[]},be=e.ref(!1),Sn=()=>{be.value=!be.value},En=m=>{A.value=m,Ce()},He=()=>{for(let m=ne.value.length-1;m>=0;m--)if(ne.value[m])return ne.value[m];return null},Ce=async()=>{if(console.log("stylizingLoading:",se.value),se.value){const W=He();console.log("lastPreviewer:",W),W&&(console.log("abortReader"),W.abortReader());return}if(!A.value.trim()){console.log("no input, return"),j.value.focus();return}G.value.push({type:"user",content:A.value}),Q.value=!0,K.value=!0,M("submit",A.value),we();const m=A.value;A.value="";const h=G.value.length;ne.value[h]&&ne.value[h].initializeStart(),se.value=!0,G.value.push({type:"ai"});const{error:T,reader:L}=await ot(I.value,{text:m,token:s.token,identifier:s.identifier,baseUrl:s.baseUrl,extraConfig:s.extraConfig});if(T){console.log(45455,T),je(h,T);return}L&&(G.value[h].reader=L)};return(m,h)=>{const T=e.resolveComponent("el-icon"),L=e.resolveComponent("el-button"),W=e.resolveComponent("el-input");return e.openBlock(),e.createBlock(e.Transition,{name:"slide"},{default:e.withCtx(()=>[r.modelValue?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["ai-panel",{"drawer-mode":be.value,"embedded-mode":r.embedded}])},[e.createElementVNode("div",kt,[e.createElementVNode("div",wt,[e.createElementVNode("div",bt,e.toDisplayString(r.title),1),e.createElementVNode("div",Ct,[r.embedded?e.createCommentVNode("",!0):(e.openBlock(),e.createBlock(T,{key:0,class:"action-icon",onClick:Sn},{default:e.withCtx(()=>[e.createVNode(le,{name:"/images/svg/drawer-layout.svg",color:"#999999"})]),_:1})),e.createVNode(T,{class:"action-icon",onClick:Cn},{default:e.withCtx(()=>[e.createVNode(le,{name:"/images/svg/close.svg",color:"#999999"})]),_:1})])])]),e.createElementVNode("div",St,[K.value?(e.openBlock(),e.createElementBlock("div",{key:1,class:"chat-messages",ref_key:"messageContainerRef",ref:ke},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(G.value,(F,oe)=>(e.openBlock(),e.createElementBlock("div",{key:oe,class:e.normalizeClass(["message-item",F.type==="user"?"user-message":"ai-message"])},[F.type==="ai"?(e.openBlock(),e.createBlock(mt,{key:0,ref_for:!0,ref:J=>ne.value[oe]=J,reader:F.reader,"onUpdate:reader":J=>F.reader=J,model:s.llmName,displayText:F.displayText,scrollToBottomFn:we,messagePostRender:r.messagePostRender,onFailed:J=>je(oe,J),onCompleted:J=>wn(oe,J),onUpdating:()=>bn()},null,8,["reader","onUpdate:reader","model","displayText","messagePostRender","onFailed","onCompleted","onUpdating"])):(e.openBlock(),e.createElementBlock("div",Tt,e.toDisplayString(F.content),1))],2))),128))],512)):(e.openBlock(),e.createElementBlock("div",Et,[h[2]||(h[2]=e.createElementVNode("div",{class:"title"},[e.createElementVNode("img",{src:We,alt:"AI助手",class:"panel-icon"}),e.createElementVNode("h3",{class:"title-text"},"Hi, 您好")],-1)),e.createElementVNode("div",vt,[h[1]||(h[1]=e.createTextVNode(" 我是",-1)),e.createElementVNode("span",Nt,e.toDisplayString(r.title),1)]),e.createElementVNode("div",Vt,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(yn.value,(F,oe)=>(e.openBlock(),e.createElementBlock("div",{key:oe,class:"question-item",onClick:J=>En(F)},[e.createElementVNode("span",null,e.toDisplayString(F),1),e.createVNode(T,null,{default:e.withCtx(()=>[e.createVNode(le,{name:"/images/svg/arrow-right.svg",color:"#999999"})]),_:1})],8,xt))),128))])]))]),e.createElementVNode("div",Rt,[Q.value?(e.openBlock(),e.createElementBlock("img",Bt)):e.createCommentVNode("",!0),e.createVNode(e.Transition,{name:"fade"},{default:e.withCtx(()=>[f.value||p.value?(e.openBlock(),e.createElementBlock("div",At,[e.createElementVNode("div",_t,[h[3]||(h[3]=e.createElementVNode("span",{class:"progress-icon"},"⏳",-1)),e.createElementVNode("span",Pt,e.toDisplayString(l.value),1),c.value>0?(e.openBlock(),e.createElementBlock("span",Ut,e.toDisplayString(c.value)+"%",1)):e.createCommentVNode("",!0)]),c.value>0?(e.openBlock(),e.createElementBlock("div",It,[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(()=>[u.value||d.value?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["voice-recording-panel",{"has-transcript":d.value}])},[e.createElementVNode("div",Lt,[e.createElementVNode("div",Mt,[e.createElementVNode("span",{class:e.normalizeClass(["recording-pulse",{transcribing:d.value}])},null,2),u.value?(e.openBlock(),e.createElementBlock("span",Ft,e.toDisplayString(N(E.value)),1)):e.createCommentVNode("",!0),e.createElementVNode("span",Ot,e.toDisplayString(w.value),1),u.value?(e.openBlock(),e.createElementBlock("div",zt,[e.createElementVNode("span",{class:"wave",style:e.normalizeStyle({height:Math.max(4,Math.min(22,k.value*.3))+"px"})},null,4),e.createElementVNode("span",{class:"wave",style:e.normalizeStyle({height:Math.max(4,Math.min(30,k.value*.5))+"px"})},null,4),e.createElementVNode("span",{class:"wave",style:e.normalizeStyle({height:Math.max(4,Math.min(18,k.value*.25))+"px"})},null,4)])):e.createCommentVNode("",!0)]),e.createElementVNode("div",Dt,[u.value?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[e.createVNode(L,{size:"small",circle:"",onClick:ee,title:"取消录音",class:"voice-cancel-btn"},{default:e.withCtx(()=>[...h[4]||(h[4]=[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(L,{type:"primary",size:"small",round:"",onClick:q,class:"voice-finish-btn"},{default:e.withCtx(()=>[...h[5]||(h[5]=[e.createTextVNode(" 完成 ",-1)])]),_:1})],64)):d.value?(e.openBlock(),e.createBlock(L,{key:1,size:"small",round:"",onClick:te,class:"voice-cancel-transcribe-btn"},{default:e.withCtx(()=>[...h[6]||(h[6]=[e.createTextVNode(" 取消识别 ",-1)])]),_:1})):e.createCommentVNode("",!0)])]),d.value?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["live-transcript",{empty:!P.value}]),title:P.value},[P.value?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[e.createTextVNode(e.toDisplayString(P.value),1),h[7]||(h[7]=e.createElementVNode("span",{class:"caret"},"|",-1))],64)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[e.createTextVNode("正在识别,文字将实时显示...")],64))],10,$t)):e.createCommentVNode("",!0)],2)):e.createCommentVNode("",!0)]),_:1}),e.createVNode(e.Transition,{name:"fade"},{default:e.withCtx(()=>[V.value&&!u.value&&!d.value?(e.openBlock(),e.createElementBlock("div",jt,[e.createElementVNode("div",{class:"playback-main",onClick:ae,title:S.value?"点击暂停":"点击播放录音"},[e.createElementVNode("div",Wt,[S.value?(e.openBlock(),e.createElementBlock("svg",Gt,[...h[9]||(h[9]=[e.createElementVNode("path",{d:"M6 19h4V5H6v14zm8-14v14h4V5h-4z"},null,-1)])])):(e.openBlock(),e.createElementBlock("svg",qt,[...h[8]||(h[8]=[e.createElementVNode("path",{d:"M8 5v14l11-7z"},null,-1)])]))]),e.createElementVNode("span",Jt,e.toDisplayString(S.value?"正在播放录音...":"点击试听本次录音"),1),z.value>0?(e.openBlock(),e.createElementBlock("span",Kt,e.toDisplayString(N(z.value)),1)):e.createCommentVNode("",!0),S.value?(e.openBlock(),e.createElementBlock("div",Qt,[...h[10]||(h[10]=[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,Ht),e.createElementVNode("div",{class:"playback-close",onClick:ue,title:"清除试听"},[...h[11]||(h[11]=[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",Zt,[e.createVNode(W,{modelValue:A.value,"onUpdate:modelValue":h[0]||(h[0]=F=>A.value=F),ref_key:"refInputTextString",ref:j,placeholder:b.value,autofocus:"",onKeyup:e.withKeys(Ce,["enter"])},{append:e.withCtx(()=>[e.createElementVNode("div",Yt,[r.enableVoiceUpload?(e.openBlock(),e.createElementBlock("div",{key:0,class:"voice-upload-btn",onClick:O,title:"上传音频/视频文件识别 (支持 .wav, .mp4, .mp3, .m4a)"},[...h[12]||(h[12]=[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),r.enableVoiceUpload?(e.openBlock(),e.createElementBlock("input",{key:1,type:"file",ref_key:"refAudioFileInput",ref:D,accept:"audio/*,video/mp4,.wav,.mp4,.mp3,.m4a",style:{display:"none"},onChange:X},null,544)):e.createCommentVNode("",!0),r.enableVoiceInput?(e.openBlock(),e.createElementBlock("div",{key:2,class:e.normalizeClass(["voice-mic-btn",{"loading-anim":f.value||p.value}]),onClick:$,title:"语音输入"},[...h[13]||(h[13]=[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:Ce},[e.createElementVNode("img",{src:kn.value,alt:"发送",class:"send-icon"},null,8,Xt)])])]),_:1},8,["modelValue","placeholder"])],512),[[e.vShow,!u.value&&!d.value]])])],2)):e.createCommentVNode("",!0)]),_:1})}}};var Ue={exports:{}};(function(r,t){(function(a,n){r.exports=n()})(window,function(){return function(a){var n={};function s(o){if(n[o])return n[o].exports;var i=n[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=n,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(k){return o[k]}).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,n,s){function o(y,f,p,u){p.push(y),u.push([].concat(f[y]||[]))}function i(y,f){if(!y)throw new Error("[getMaxDepsChain] dep 参数不能为空");var p=[],u=[],d=[];for(o(y,f,u,d);u.length;){var w=d.pop();if(w&&w.length){var b=w.shift();if(d.push(w),~u.indexOf(b))throw new Error("[getMaxDepsChain][loop] 存在循环依赖,请检查依赖关系; nextName: "+b+", mainStack: "+u);o(b,f,u,d)}else p.push([].concat(u)),u.pop()}return p.reduce(function(B,N){return N.length>B.length?N:B},[])}function l(y){if(!y)throw new Error("[depsParser] 入参不能为空");var f={};y.forEach(function(u){f[u.name]=u.deps||[]});var p=[];return y.forEach(function(u){var d=i(u.name,f).length-1;u.priority=d,p[d]=(p[d]||[]).concat(u)}),p}s.r(n),s.d(n,"loadScript",function(){return V}),s.d(n,"loadScripts",function(){return S}),s.d(n,"dynamicLoadScripts",function(){return z}),s.d(n,"createScriptsLoadIterator",function(){return v}),s.d(n,"loadScriptsQueue",function(){return P}),s.d(n,"getMaxDepsChain",function(){return i}),s.d(n,"depsParser",function(){return l});var c=function(){return(c=Object.assign||function(y){for(var f,p=1,u=arguments.length;p<u;p++)for(var d in f=arguments[p])Object.prototype.hasOwnProperty.call(f,d)&&(y[d]=f[d]);return y}).apply(this,arguments)},k=function(y,f,p,u){return new(p||(p=Promise))(function(d,w){function b(R){try{N(u.next(R))}catch(g){w(g)}}function B(R){try{N(u.throw(R))}catch(g){w(g)}}function N(R){var g;R.done?d(R.value):(g=R.value,g instanceof p?g:new p(function(U){U(g)})).then(b,B)}N((u=u.apply(y,[])).next())})},E=function(y,f){var p,u,d,w,b={label:0,sent:function(){if(1&d[0])throw d[1];return d[1]},trys:[],ops:[]};return w={next:B(0),throw:B(1),return:B(2)},typeof Symbol=="function"&&(w[Symbol.iterator]=function(){return this}),w;function B(N){return function(R){return function(g){if(p)throw new TypeError("Generator is already executing.");for(;b;)try{if(p=1,u&&(d=2&g[0]?u.return:g[0]?u.throw||((d=u.return)&&d.call(u),0):u.next)&&!(d=d.call(u,g[1])).done)return d;switch(u=0,d&&(g=[2&g[0],d.value]),g[0]){case 0:case 1:d=g;break;case 4:return b.label++,{value:g[1],done:!1};case 5:b.label++,u=g[1],g=[0];continue;case 7:g=b.ops.pop(),b.trys.pop();continue;default:if(d=b.trys,!((d=d.length>0&&d[d.length-1])||g[0]!==6&&g[0]!==2)){b=0;continue}if(g[0]===3&&(!d||g[1]>d[0]&&g[1]<d[3])){b.label=g[1];break}if(g[0]===6&&b.label<d[1]){b.label=d[1],d=g;break}if(d&&b.label<d[2]){b.label=d[2],b.ops.push(g);break}d[2]&&b.ops.pop(),b.trys.pop();continue}g=f.call(y,b)}catch(U){g=[6,U],u=0}finally{p=d=0}if(5&g[0])throw g[1];return{value:g[0]?g[1]:void 0,done:!0}}([N,R])}}},_=function(y){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var f,p=y[Symbol.asyncIterator];return p?p.call(y):(y=typeof __values=="function"?__values(y):y[Symbol.iterator](),f={},u("next"),u("throw"),u("return"),f[Symbol.asyncIterator]=function(){return this},f);function u(d){f[d]=y[d]&&function(w){return new Promise(function(b,B){(function(N,R,g,U){Promise.resolve(U).then(function($){N({value:$,done:g})},R)})(b,B,(w=y[d](w)).done,w.value)})}}};function V(y,f){return f===void 0&&(f=!1),new Promise(function(p,u){var d=f?document.head:document.body,w=document.createElement("script");w.type="text/javascript",w.src=y,w.crossOrigin="anonymous",w.onreadystatechange=p,w.onload=p,w.onerror=u,d.appendChild(w)})}var S=function(y,f){return f===void 0&&(f={}),k(void 0,void 0,void 0,function(){var p,u,d,w,b;return E(this,function(B){switch(B.label){case 0:return p=f.baseUrl,u=p===void 0?"":p,d=f.lastLoadResult,w=f.inHead,b=w!==void 0&&w,[4,Promise.all(y.map(function(N){return k(void 0,void 0,void 0,function(){var R,g,U,$,q,D,O,X;return E(this,function(ee){switch(ee.label){case 0:return R=N.name,g=N.path,U=N.deps,(O={})[R]=!0,$=O,(X={})[R]=!1,q=X,window[R]?[2,$]:[3,1];case 1:return D=!0,U&&d&&[].concat(U).forEach(function(te){d[te]!==!1&&(D=!0)}),D?[4,V(g.indexOf("http")===0||g.indexOf("//:")===0?g:u+g,b).then(function(){return $}).catch(function(){return q})]:[3,3];case 2:return[2,ee.sent()];case 3:return[2,q]}})})}))];case 1:return[2,B.sent()]}})})},z=function(y,f){return f===void 0&&(f={}),function(){var p=[].concat(l(y));return{next:function(){if(p.length){var u=p.shift();return S(u,f).then(function(d){return{value:d,done:!1}})}return Promise.resolve({done:!0})}}}},v=function(y,f){var p;return f===void 0&&(f={}),(p={})[Symbol.asyncIterator]=z(y,f),p},P=function(y,f){return f===void 0&&(f={}),k(void 0,void 0,void 0,function(){var p,u,d,w,b,B;return E(this,function(N){switch(N.label){case 0:N.trys.push([0,5,6,11]),p=_(v(y,f)),N.label=1;case 1:return[4,p.next()];case 2:if((u=N.sent()).done)return[3,4];d=u.value,f.lastLoadResult=f.lastLoadResult||{},console.log("current load: ",d),d.forEach(function(R){f.lastLoadResult=c(c({},f.lastLoadResult),R)}),N.label=3;case 3:return[3,1];case 4:return[3,11];case 5:return w=N.sent(),b={error:w},[3,11];case 6:return N.trys.push([6,,9,10]),u&&!u.done&&(B=p.return)?[4,B.call(p)]:[3,8];case 7:N.sent(),N.label=8;case 8:return[3,10];case 9:if(b)throw b.error;return[7];case 10:return[7];case 11:return[2,f.lastLoadResult]}})})}}])})})(Ue);var en=Ue.exports;function Ie(){const r=[{name:"markdownit",path:"markdown-it.min.js"},{name:"hljs",path:"highlight.11.11.1.min.js"}];let t={};en.loadScriptsQueue(r,{baseUrl:"/scripts/ai/",lastLoadResult:t,inHead:!1}).then(a=>{if(console.log("load ai deps: ",a),window.markdownit){const n=window.markdownit();console.log("markdownit: ",n),rt()}})}const tn={key:0,class:"ai-assistant"},nn={name:"AiChat"},Le=e.defineComponent({...nn,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}},setup(r){const t=e.ref(!1),a=e.ref(!1),n=()=>{t.value=!t.value},s=()=>{a.value=!0,t.value=!1},o=i=>{console.log("用户输入:",i)};return Ie(),(i,l)=>a.value?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("div",tn,[e.createVNode(Pe,{modelValue:t.value,"onUpdate:modelValue":l[0]||(l[0]=c=>t.value=c),onSubmit:o,token:r.token,identifier:r.identifier,baseUrl:r.baseUrl,title:r.title,llmName:r.llmName,messagePostRender:r.messagePostRender,extraConfig:r.extraConfig,soundBaseUrl:r.soundBaseUrl,workerUrl:r.workerUrl,enableVoiceInput:r.enableVoiceInput,enableVoiceUpload:r.enableVoiceUpload},null,8,["modelValue","token","identifier","baseUrl","title","llmName","messagePostRender","extraConfig","soundBaseUrl","workerUrl","enableVoiceInput","enableVoiceUpload"]),e.createElementVNode("div",{class:"ai-icon",onClick:n},[e.createElementVNode("div",{class:"close-icon",onClick:e.withModifiers(s,["stop"])},[...l[1]||(l[1]=[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)])]),l[2]||(l[2]=e.createElementVNode("img",{src:Z,alt:"AI助手"},null,-1)),l[3]||(l[3]=e.createElementVNode("span",{class:"ai-icon-text"},"AI助手",-1))])]))}}),on={class:"ai-chat-plain"},rn={name:"AiChatPlain"},Me=e.defineComponent({...rn,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}},emits:["submit"],setup(r,{emit:t}){const a=t;return Ie(),(n,s)=>(e.openBlock(),e.createElementBlock("div",on,[e.createVNode(Pe,{"model-value":!0,token:r.token,identifier:r.identifier,baseUrl:r.baseUrl,title:r.title,llmName:r.llmName,messagePostRender:r.messagePostRender,extraConfig:r.extraConfig,soundBaseUrl:r.soundBaseUrl,workerUrl:r.workerUrl,enableVoiceInput:r.enableVoiceInput,enableVoiceUpload:r.enableVoiceUpload,embedded:!0,onSubmit:s[0]||(s[0]=o=>a("submit",o))},null,8,["token","identifier","baseUrl","title","llmName","messagePostRender","extraConfig","soundBaseUrl","workerUrl","enableVoiceInput","enableVoiceUpload"])]))}}),Fe=Object.freeze(Object.defineProperty({__proto__:null,SzAiChat:Le,SzAiChatPlain:Me},Symbol.toStringTag,{value:"Module"})),ye=function(r){if(!ye.installed){ye.installed=!0;for(let t in Fe){const a=Reflect.get(Fe,t);r.component(a.name,a)}}},an=(r,t)=>{const a=t?`?${new URLSearchParams(t).toString()}`:"";console.log(`点击了路由链接: ${r}${a}`)},Oe=r=>{const t=r.indexOf("?");if(t===-1)return{routeName:r};const a=r.substring(0,t),n=r.substring(t+1),s={};return new URLSearchParams(n).forEach((i,l)=>{s[l]=i}),{routeName:a,queryParams:Object.keys(s).length>0?s:void 0}},sn={color:"#536fec",fontWeight:"bold",textDecoration:"underline",cursor:"pointer",padding:"0 3px"},ze=r=>{const t=/#router:([^#]+)#/g,a=[];let n=0,s;for(;(s=t.exec(r))!==null;){s.index>n&&a.push({text:r.substring(n,s.index)});const o=s[1],{routeName:i,queryParams:l}=Oe(o);a.push({text:i,routeName:i,queryParams:l}),n=t.lastIndex}return n<r.length&&a.push({text:r.substring(n)}),a},De=(r,t,a={},n)=>{const{onRouteClick:s=an,linkStyle:o={}}=a,i=document.createElement("a");i.href="#",i.textContent=r;const l={...sn,...o};return Object.assign(i.style,l),i.addEventListener("click",c=>{c.preventDefault(),s(t,n)}),i},$e=r=>{const t=/#router:([^#]+)#/g,a=[],n=document.createTreeWalker(r,NodeFilter.SHOW_TEXT,null);let s=n.nextNode();for(;s;){const o=s,i=o.textContent||"";if(t.test(i)){t.lastIndex=0;const l=ze(i);l.length>0&&a.push({node:o,replacements:l})}s=n.nextNode()}return a},ln=(r,t,a={})=>{const n=$e(r);n.forEach(({node:s,replacements:o})=>{var l;const i=document.createDocumentFragment();o.forEach(({text:c,routeName:k,queryParams:E})=>{if(k){const _=De(c,k,a,E);i.appendChild(_)}else i.appendChild(document.createTextNode(c))}),(l=s.parentNode)==null||l.replaceChild(i,s)}),a!=null&&a.nodeCallback&&n.forEach(({node:s,replacements:o})=>{var i;(i=a.nodeCallback)==null||i.call(a,s,o)})},re="szjy-voice-models",ce="szjy-voice-cache-v1";function Y(){return typeof navigator<"u"&&!!navigator.storage&&typeof navigator.storage.getDirectory=="function"}async function de(r=re){if(!Y())return null;try{return await(await navigator.storage.getDirectory()).getDirectoryHandle(r,{create:!0})}catch(t){return console.warn("[OPFS] 获取目录失败,将使用降级缓存:",t),null}}async function cn(r,t,a=re){if(Y())try{const n=await de(a);if(n){const o=await(await n.getFileHandle(r,{create:!0})).createWritable();return await o.write(t),await o.close(),!0}}catch(n){console.warn(`[OPFS] 写入文件 ${r} 失败:`,n)}if(typeof caches<"u")try{const n=await caches.open(ce),s=new Response(t,{headers:{"Content-Type":"application/octet-stream"}});return await n.put(`/${a}/${r}`,s),!0}catch(n){console.warn(`[CacheStorage] 缓存写入 ${r} 失败:`,n)}return!1}async function dn(r,t=re){if(Y())try{const a=await de(t);if(a)return await(await(await a.getFileHandle(r,{create:!1})).getFile()).arrayBuffer()}catch{}if(typeof caches<"u")try{const n=await(await caches.open(ce)).match(`/${t}/${r}`);if(n)return await n.arrayBuffer()}catch{}return null}async function un(r,t=re){if(Y())try{const a=await de(t);if(a)return(await(await a.getFileHandle(r,{create:!1})).getFile()).size>0}catch{}if(typeof caches<"u")try{return!!await(await caches.open(ce)).match(`/${t}/${r}`)}catch{}return!1}async function hn(r=re){let t=!1;if(Y())try{await(await navigator.storage.getDirectory()).removeEntry(r,{recursive:!0}),t=!0,console.log(`[OPFS] 成功清空语音模型缓存目录: ${r}`)}catch(a){a.name==="NotFoundError"?t=!0:console.warn(`[OPFS] 清理目录 ${r} 异常:`,a)}if(typeof caches<"u")try{const a=await caches.keys();for(const n of a)(n.includes("transformers")||n.includes("szjy-voice")||n===ce)&&(await caches.delete(n),t=!0)}catch(a){console.warn("[CacheStorage] 清除缓存异常:",a)}return t}const mn="0.1.12",fn="Sz";function pn({componentPrefix:r=fn,components:t=[]}={}){const a=[];function n(o,i,l){o.component(r+i)||o.component(r+i,l)}function s(o){a.includes(o)||(a.push(o),t.forEach(i=>{const{name:l,alias:c}=i;n(o,l,i),c&&c.forEach(k=>{n(o,k,i)})}))}return{version:mn,componentPrefix:r,install:s}}const gn={install(r){ye(r)}};C.AudioRecorder=xe,C.DEFAULT_WHISPER_WORKER_URL=pe,C.StreamResampler=Ve,C.SzAiChat=Le,C.SzAiChatPlain=Me,C.VoiceInputManager=_e,C.clearVoiceModelCache=hn,C.create=pn,C.createRouteLink=De,C.decodeAudioFile=Re,C.default=gn,C.findRouteTextNodes=$e,C.float32ToWav=fe,C.getFileFromCache=dn,C.getOPFSDirectory=de,C.hasFileInCache=un,C.isOPFSSupported=Y,C.parseRouteMarkerContent=Oe,C.parseRouteMarkers=ze,C.resampleAudioData=Te,C.routeLinkRender=ln,C.saveFileToCache=cn,Object.defineProperties(C,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
@@ -1,3 +1,8 @@
1
+ export type AiExtraConfig = {
2
+ projectId?: string | number;
3
+ authToken?: string;
4
+ [key: string]: unknown;
5
+ };
1
6
  /**
2
7
  * Event Stream 调用大模型接口 Dify(兼容 OpenAI 格式)(Fetch 调用)
3
8
  * 请求格式:
@@ -7,28 +12,28 @@
7
12
  * "messages": [ { role, content }, ... ]
8
13
  * }
9
14
  */
10
- export declare function createDifyOpenAIStylized(text: any, token: any, identifier: any, baseUrl?: string, extraConfig?: {}): Promise<Response>;
15
+ export declare function createDifyOpenAIStylized(text: any, token: any, identifier: any, baseUrl?: string, extraConfig?: AiExtraConfig): Promise<Response>;
11
16
  /**
12
17
  * Event Stream 调用大模型接口 Ollama3 (Fetch 调用)
13
18
  */
14
- export declare function createOllama3Stylized(text: any, token: any, identifier: any, baseUrl?: string, extraConfig?: {}): Promise<Response>;
19
+ export declare function createOllama3Stylized(text: any, _token: any, _identifier: any, _baseUrl?: string, _extraConfig?: AiExtraConfig): Promise<Response>;
15
20
  /**
16
21
  * Event Stream 调用大模型接口 Spark 星火认知大模型 (Fetch 调用)
17
22
  */
18
- export declare function createSparkStylized(text: any, token: any, identifier: any, baseUrl?: string, extraConfig?: {}): Promise<Response>;
23
+ export declare function createSparkStylized(text: any, token: any, _identifier: any, _baseUrl?: string, _extraConfig?: AiExtraConfig): Promise<Response>;
19
24
  /**
20
25
  * Event Stream 调用大模型接口 SiliconFlow 硅基流动大模型 (Fetch 调用)
21
26
  */
22
- export declare function createSiliconFlowStylized(text: any, token: any, identifier: any, baseUrl?: string, extraConfig?: {}): Promise<Response>;
27
+ export declare function createSiliconFlowStylized(text: any, token: any, _identifier: any, _baseUrl?: string, _extraConfig?: AiExtraConfig): Promise<Response>;
23
28
  /**
24
29
  * Event Stream 调用大模型接口 Kimi Moonshot 月之暗面大模型 (Fetch 调用)
25
30
  */
26
- export declare function createKimiMoonshotStylized(text: any, token: any, identifier: any, baseUrl?: string, extraConfig?: {}): Promise<Response>;
31
+ export declare function createKimiMoonshotStylized(text: any, token: any, _identifier: any, _baseUrl?: string, _extraConfig?: AiExtraConfig): Promise<Response>;
27
32
  /**
28
33
  * Event Stream 调用大模型接口 Kimi Moonshot 月之暗面大模型 (Fetch 调用)
29
34
  */
30
- export declare function createDashScopeStylized(text: any, token: any, identifier: any, baseUrl?: string, extraConfig?: {}): Promise<Response>;
35
+ export declare function createDashScopeStylized(text: any, token: any, _identifier: any, _baseUrl?: string, _extraConfig?: AiExtraConfig): Promise<Response>;
31
36
  /**
32
37
  * Event Stream 调用大模型接口 数智交院 月之暗面大模型 (Fetch 调用)
33
38
  */
34
- export declare function createSZJYStylized(text: any, token: any, identifier: any, baseUrl?: string, extraConfig?: {}): Promise<Response>;
39
+ export declare function createSZJYStylized(text: any, token: any, identifier: any, baseUrl?: string, _extraConfig?: AiExtraConfig): Promise<Response>;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * OPFS (Origin Private File System) 缓存管理器
3
+ * 提供端侧模型的高性能文件系统持久化存储、读取、校验与清理能力
4
+ * 当环境不支持 OPFS 时,自动降级至 CacheStorage / 内存
5
+ */
6
+ /**
7
+ * 检查当前浏览器环境是否支持 OPFS
8
+ */
9
+ export declare function isOPFSSupported(): boolean;
10
+ /**
11
+ * 获取或创建指定名称的 OPFS 子目录
12
+ */
13
+ export declare function getOPFSDirectory(dirName?: string): Promise<FileSystemDirectoryHandle | null>;
14
+ /**
15
+ * 保存文件到本地缓存(OPFS 优先,降级 CacheStorage)
16
+ */
17
+ export declare function saveFileToCache(fileName: string, data: ArrayBuffer | Uint8Array | Blob, dirName?: string): Promise<boolean>;
18
+ /**
19
+ * 从本地缓存获取文件(OPFS 优先,降级 CacheStorage)
20
+ */
21
+ export declare function getFileFromCache(fileName: string, dirName?: string): Promise<ArrayBuffer | null>;
22
+ /**
23
+ * 检查指定文件是否已存在于本地缓存中且非空
24
+ */
25
+ export declare function hasFileInCache(fileName: string, dirName?: string): Promise<boolean>;
26
+ /**
27
+ * 清除本地语音模型缓存(同时清理 OPFS 与 CacheStorage)
28
+ * 供用户或开发者重置模型、解决下载中断或异常
29
+ */
30
+ export declare function clearVoiceModelCache(dirName?: string): Promise<boolean>;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * 录音采集与 16kHz 单声道重采样模块
3
+ * 专为 Whisper 端侧语音识别设计
4
+ */
5
+ export interface RecorderOptions {
6
+ sampleRate?: number;
7
+ onVolumeChange?: (volume: number) => void;
8
+ /** 每次采集到 16kHz PCM 分片时回调(与内部缓存共享引用,调用方如需 Transferable 请先拷贝) */
9
+ onAudioChunk?: (chunk: Float32Array) => void;
10
+ }
11
+ /**
12
+ * 跨 ScriptProcessor 缓冲的连续线性重采样,避免每片独立插值在边界产生断裂。
13
+ */
14
+ export declare class StreamResampler {
15
+ private ratio;
16
+ private leftover;
17
+ private fracOffset;
18
+ constructor(fromRate: number, toRate: number);
19
+ reset(): void;
20
+ process(chunk: Float32Array): Float32Array;
21
+ }
22
+ export declare class AudioRecorder {
23
+ private targetSampleRate;
24
+ private audioContext;
25
+ private mediaStream;
26
+ private sourceNode;
27
+ private processorNode;
28
+ private muteGain;
29
+ private resampler;
30
+ private audioChunks;
31
+ private onVolumeChange?;
32
+ private onAudioChunk?;
33
+ private _isRecording;
34
+ constructor(options?: RecorderOptions);
35
+ get isRecording(): boolean;
36
+ /**
37
+ * 开始录音
38
+ */
39
+ start(): Promise<void>;
40
+ /**
41
+ * 停止录音并返回完整的 16kHz Float32Array 音频数据
42
+ */
43
+ stop(): Promise<Float32Array>;
44
+ /**
45
+ * 取消录音并丢弃采集的数据
46
+ */
47
+ cancel(): void;
48
+ private cleanup;
49
+ }
50
+ /**
51
+ * 线性插值音频重采样
52
+ */
53
+ export declare function resampleAudioData(audioData: Float32Array, fromSampleRate: number, toSampleRate: number): Float32Array;
54
+ /**
55
+ * 解析并解码音频/视频文件 (WAV, MP4, MP3, M4A 等) 为 16kHz 单声道 Float32Array
56
+ */
57
+ export declare function decodeAudioFile(file: File | Blob, targetSampleRate?: number): Promise<Float32Array>;
58
+ /**
59
+ * 将 16kHz 单声道 Float32Array PCM 数据编码为标准 WAV 格式 Blob
60
+ */
61
+ export declare function float32ToWav(samples: Float32Array, sampleRate?: number): Blob;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Whisper 转写后处理:折叠重复、去掉短音频上的常见幻觉。
3
+ * 实时短分片被右侧补零到 30 秒时,模型常循环输出「三十分」一类时间词。
4
+ */
5
+ /**
6
+ * 折叠连续重复的短语与单字(「三十分三十分三十分」→「三十分」)
7
+ */
8
+ export declare function collapseRepeatedPhrases(text: string): string;
9
+ /**
10
+ * 按音频时长限制字数,挡住没被折叠掉的超长循环输出。
11
+ */
12
+ export declare function clampTranscriptToAudio(text: string, durationSec: number): string;
13
+ /**
14
+ * 清理单次推理结果。短音频上的纯幻觉直接丢弃。
15
+ */
16
+ export declare function sanitizeTranscript(text: string, durationSec?: number): string;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 语音大运行时独立入口。
3
+ * 只导出 Worker 用到的 Transformers API,由 scripts/build-voice-assets.mjs 打成
4
+ * public/scripts/ai/transformers.runtime.js,WASM 保持为同目录外部文件。
5
+ */
6
+ export { pipeline, env, WhisperTextStreamer } from '@huggingface/transformers';
@@ -0,0 +1,99 @@
1
+ /**
2
+ * 语音输入调度中枢 (VoiceInputManager)
3
+ * 统一管理录音、Worker 线程通信、模型加载进度、状态机及结果回调
4
+ */
5
+ export type VoiceStatus = 'idle' | 'downloading' | 'loading' | 'ready' | 'recording' | 'transcribing' | 'error';
6
+ export interface VoiceProgressInfo {
7
+ status: string;
8
+ progress?: number;
9
+ file?: string;
10
+ loaded?: number;
11
+ total?: number;
12
+ text?: string;
13
+ }
14
+ export interface VoiceManagerOptions {
15
+ soundBaseUrl?: string;
16
+ /**
17
+ * Whisper Worker 脚本地址。不传时自动探测:
18
+ * 1) 相对库入口的 dist/assets 产物(npm link / @fs)
19
+ * 2) 宿主 public 目录 /scripts/ai/whisper.worker.js
20
+ * 3) Vite 打包注入的 URL
21
+ */
22
+ workerUrl?: string;
23
+ remoteHost?: string;
24
+ modelId?: string;
25
+ language?: string;
26
+ onStatusChange?: (status: VoiceStatus, message?: string) => void;
27
+ onProgress?: (info: VoiceProgressInfo) => void;
28
+ onVolumeChange?: (volume: number) => void;
29
+ onAudioRecorded?: (audioUrl: string, blob: Blob) => void;
30
+ /** 转写过程中的中间文本(录音结束后 / 上传文件时按 token 回推) */
31
+ onPartial?: (text: string) => void;
32
+ onResult?: (text: string) => void;
33
+ onError?: (error: string) => void;
34
+ }
35
+ /** 宿主项目复制 public 后的稳定 Worker 路径(与 markdown-it 等静态脚本同目录) */
36
+ export declare const DEFAULT_WHISPER_WORKER_URL = "/scripts/ai/whisper.worker.js";
37
+ export declare class VoiceInputManager {
38
+ private recorder;
39
+ private worker;
40
+ private status;
41
+ private options;
42
+ private isReady;
43
+ private initPromise;
44
+ private currentTaskId;
45
+ private pcmParts;
46
+ private pcmLength;
47
+ private streamChunkIndex;
48
+ private committedText;
49
+ constructor(options?: VoiceManagerOptions);
50
+ get currentStatus(): VoiceStatus;
51
+ get ready(): boolean;
52
+ /**
53
+ * 初始化语音引擎(延迟加载,仅在首次使用或调用时触发)
54
+ */
55
+ init(customBaseUrl?: string): Promise<void>;
56
+ /**
57
+ * 开始语音录入(只采集,点「完成」后再转写)
58
+ */
59
+ startRecording(): Promise<void>;
60
+ /**
61
+ * 停止录音并触发模型端侧推理
62
+ */
63
+ stopAndTranscribe(): Promise<void>;
64
+ /**
65
+ * 直接对外部传入的 16kHz Float32Array 音频进行端侧推理(例如文件上传)
66
+ */
67
+ transcribeAudioData(audioBuffer: Float32Array, customAudioUrl?: string): Promise<void>;
68
+ /**
69
+ * 上传音频/视频文件(支持 mp4, wav, mp3, m4a 等)并在浏览器端解析识别
70
+ */
71
+ transcribeFile(file: File | Blob): Promise<void>;
72
+ /**
73
+ * 取消当前录音并丢弃
74
+ */
75
+ cancelRecording(): void;
76
+ /**
77
+ * 取消当前的语音识别推理任务
78
+ */
79
+ cancelTranscribe(): void;
80
+ /**
81
+ * 清除本地模型缓存
82
+ */
83
+ clearCache(): Promise<void>;
84
+ /**
85
+ * 销毁并释放所有资源
86
+ */
87
+ destroy(): void;
88
+ private resetStreamState;
89
+ private appendPcm;
90
+ private mergePcm;
91
+ private emitPartial;
92
+ private finishStream;
93
+ /**
94
+ * 录音结束或上传:整段一次送入 Worker。超过 30s 由 Worker 按重叠窗口切分。
95
+ */
96
+ private dispatchFullAudio;
97
+ private handleWorkerMessage;
98
+ private setStatus;
99
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Whisper Web Worker 语音识别多线程服务
3
+ * 基于 @huggingface/transformers 运行在后台 Worker 线程中
4
+ * 采用 WebGPU 优先,降级 WebAssembly (WASM CPU)
5
+ * 支持进度广播与 OPFS / 本地持久化缓存
6
+ */
7
+ export {};
@@ -1,3 +1,3 @@
1
- declare let MarkdownInstance: null;
2
- export declare function genMarkdownIt(): null;
1
+ declare let MarkdownInstance: MarkdownItInstance | null;
2
+ export declare function genMarkdownIt(): MarkdownItInstance | null;
3
3
  export { MarkdownInstance };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * 聊天运行时依赖加载(markdown-it / highlight.js)
3
+ * 挂件(sz-ai-chat)与嵌入式(sz-ai-chat-plain)两种外壳共用:
4
+ * 从 /scripts/ai/ 加载 markdown-it 与 highlight 脚本,完成后初始化全局 MarkdownIt 实例。
5
+ */
6
+ export declare function useChatDeps(): void;
@@ -42,6 +42,34 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
42
42
  type: ObjectConstructor;
43
43
  default: () => {};
44
44
  };
45
+ /**
46
+ * 语音识别模型静态资源基础路径,默认为 '/sounds/'
47
+ */
48
+ soundBaseUrl: {
49
+ type: StringConstructor;
50
+ default: string;
51
+ };
52
+ /**
53
+ * Whisper Worker 脚本地址。不传则自动探测库产物与 /scripts/ai/whisper.worker.js
54
+ */
55
+ workerUrl: {
56
+ type: StringConstructor;
57
+ default: string;
58
+ };
59
+ /**
60
+ * 是否显示麦克风语音输入入口,默认关闭
61
+ */
62
+ enableVoiceInput: {
63
+ type: BooleanConstructor;
64
+ default: boolean;
65
+ };
66
+ /**
67
+ * 是否显示上传音频/视频识别入口,默认关闭
68
+ */
69
+ enableVoiceUpload: {
70
+ type: BooleanConstructor;
71
+ default: boolean;
72
+ };
45
73
  }>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
46
74
  token: {
47
75
  type: StringConstructor;
@@ -86,13 +114,45 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
86
114
  type: ObjectConstructor;
87
115
  default: () => {};
88
116
  };
117
+ /**
118
+ * 语音识别模型静态资源基础路径,默认为 '/sounds/'
119
+ */
120
+ soundBaseUrl: {
121
+ type: StringConstructor;
122
+ default: string;
123
+ };
124
+ /**
125
+ * Whisper Worker 脚本地址。不传则自动探测库产物与 /scripts/ai/whisper.worker.js
126
+ */
127
+ workerUrl: {
128
+ type: StringConstructor;
129
+ default: string;
130
+ };
131
+ /**
132
+ * 是否显示麦克风语音输入入口,默认关闭
133
+ */
134
+ enableVoiceInput: {
135
+ type: BooleanConstructor;
136
+ default: boolean;
137
+ };
138
+ /**
139
+ * 是否显示上传音频/视频识别入口,默认关闭
140
+ */
141
+ enableVoiceUpload: {
142
+ type: BooleanConstructor;
143
+ default: boolean;
144
+ };
89
145
  }>> & Readonly<{}>, {
146
+ baseUrl: string;
90
147
  token: string;
91
148
  identifier: string;
92
- baseUrl: string;
93
149
  title: string;
94
150
  llmName: string;
95
151
  messagePostRender: Function;
96
152
  extraConfig: Record<string, any>;
153
+ soundBaseUrl: string;
154
+ workerUrl: string;
155
+ enableVoiceInput: boolean;
156
+ enableVoiceUpload: boolean;
97
157
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
98
158
  export default _default;
@@ -5,6 +5,18 @@ import { createSparkStylized } from '../../../../api/ai';
5
5
  * 如: 科大讯飞星火、Kimi Moonshot 等大模型的 response
6
6
  */
7
7
  export declare const parseJsonLikeData: (content: any) => any;
8
+ /**
9
+ * 从大模型原始输出中分离「思考过程」与「正文」,兼容两种格式:
10
+ * 1. 标准 <think>...</think> 包裹(DeepSeek R1 风格)
11
+ * 2. Dify 兼容口:思考内容直接输出在前,仅以 </think> 结尾(无开标签)
12
+ *
13
+ * isThinkingStreaming 表示流式输出尚未闭合(已出现 <think> 但还没等到 </think>)。
14
+ */
15
+ export declare const parseThinking: (raw: string) => {
16
+ thinking: string;
17
+ content: string;
18
+ isThinkingStreaming: boolean;
19
+ };
8
20
  /**
9
21
  * 大模型映射列表
10
22
  */
@@ -0,0 +1,3 @@
1
+ import { default as SzAiChatPlain } from './src/index.vue';
2
+
3
+ export { SzAiChatPlain };