fmode-ng 0.0.32 → 0.0.34

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.
Files changed (24) hide show
  1. package/esm2022/lib/aigc/avatar/modal-chat-voice-input/modal-chat-voice-input.component.mjs +1 -1
  2. package/esm2022/lib/aigc/chat/chat-message-area/comp-message-area.component.mjs +1 -1
  3. package/esm2022/lib/aigc/chat/chat-message-card/comp-message-card.component.mjs +1 -1
  4. package/esm2022/lib/aigc/chat/chat-modal-input/modal-audio-message/modal-audio-message.component.mjs +1 -1
  5. package/esm2022/lib/aigc/chat/chat-modal-input/modal-input.component.mjs +1 -1
  6. package/esm2022/lib/aigc/chat/comp-role-prompt/comp-role-prompt.component.mjs +1 -1
  7. package/esm2022/lib/aigc/service-fmai/service-chat/chat-class.mjs +1 -1
  8. package/esm2022/lib/aigc/service-fmai/service-chat/chat.service.mjs +1 -1
  9. package/esm2022/lib/aigc/service-fmai/service-chat/pipes/chat-content.pipe.mjs +1 -1
  10. package/esm2022/lib/aigc/voice/fmode-voice.service.mjs +1 -1
  11. package/esm2022/lib/aigc/voice/lib/pcm2wav.mjs +1 -1
  12. package/esm2022/lib/aigc/voice/tts/fmode-tts-class.mjs +1 -1
  13. package/esm2022/lib/storage/service-upload/nova-upload.service.mjs +1 -1
  14. package/fesm2022/fmode-ng.mjs +1 -1
  15. package/fesm2022/fmode-ng.mjs.map +1 -1
  16. package/lib/aigc/chat/chat-message-card/comp-message-card.component.d.ts +3 -0
  17. package/lib/aigc/chat/chat-modal-input/modal-audio-message/modal-audio-message.component.d.ts +6 -1
  18. package/lib/aigc/service-fmai/service-chat/chat-class.d.ts +7 -3
  19. package/lib/aigc/service-fmai/service-chat/chat.service.d.ts +3 -1
  20. package/lib/aigc/voice/fmode-voice.service.d.ts +6 -2
  21. package/lib/aigc/voice/lib/pcm2wav.d.ts +1 -1
  22. package/lib/aigc/voice/tts/fmode-tts-class.d.ts +15 -3
  23. package/lib/storage/service-upload/nova-upload.service.d.ts +1 -0
  24. package/package.json +1 -1
@@ -5,6 +5,6 @@
5
5
  * 保留所有权利 All Rights Reserved.
6
6
  * /home/ryan/workspace/nova/nova-admin/dist/fmode-ng/fesm2022/fmode-ng.mjs
7
7
  */
8
- import*as i0 from"@angular/core";import{Injectable,Pipe,Component,Input,ViewChild,NgModule,EventEmitter,Output}from"@angular/core";import*as i1$1 from"@angular/router";import{RouterModule}from"@angular/router";import{finalize,Observable,bufferTime,concatMap,delay,combineLatest}from"rxjs";import*as Parse from"parse";import Parse__default from"parse";import{PromptTemplate}from"@langchain/core/prompts";import{SpeechSynthesizer}from"microsoft-cognitiveservices-speech-sdk/distrib/lib/src/sdk/SpeechSynthesizer";import{SpeechConfig}from"microsoft-cognitiveservices-speech-sdk/distrib/lib/src/sdk/SpeechConfig";import{ResultReason}from"microsoft-cognitiveservices-speech-sdk/distrib/lib/src/sdk/ResultReason";import*as i1 from"@angular/common/http";import{HttpHeaders,HttpClientModule}from"@angular/common/http";import*as i2 from"@ionic/angular";import{IonicModule,ModalController,IonModal as IonModal$1}from"@ionic/angular";import*as i2$2 from"@angular/common";import{DatePipe,CommonModule}from"@angular/common";import{Camera,CameraSource,CameraResultType}from"@capacitor/camera";import{Capacitor}from"@capacitor/core";import{Filesystem}from"@capacitor/filesystem";import{FilesystemWeb}from"@capacitor/filesystem/dist/esm/web.js";import*as qiniu from"qiniu-js";import*as i2$1 from"@awesome-cordova-plugins/diagnostic/ngx";import{Diagnostic}from"@awesome-cordova-plugins/diagnostic/ngx";import{MediaCapture}from"@awesome-cordova-plugins/media-capture";import SparkMD5 from"spark-md5";import{mathjax}from"mathjax-full/js/mathjax";import{TeX}from"mathjax-full/js/input/tex";import{SVG}from"mathjax-full/js/output/svg";import{CHTML}from"mathjax-full/js/output/chtml";import{AllPackages}from"mathjax-full/js/input/tex/AllPackages";import{liteAdaptor}from"mathjax-full/js/adaptors/liteAdaptor";import{RegisterHTMLHandler}from"mathjax-full/js/handlers/html";import hljs from"highlight.js";import MarkdownIt from"markdown-it";import $ from"jquery";import abbr from"markdown-it-abbr";import footnote from"markdown-it-footnote";import deflist from"markdown-it-deflist";import mark from"markdown-it-mark";import ins from"markdown-it-ins";import sub from"markdown-it-sub";import sup from"markdown-it-sup";import ruby from"markdown-it-ruby";import plantumlEncoder from"plantuml-encoder";import*as i1$2 from"@angular/platform-browser";import{Clipboard}from"@capacitor/clipboard";import Recorder from"recorder-core";import"recorder-core/src/engine/pcm";import"recorder-core/src/engine/wav";import"recorder-core/src/extensions/waveview";import CryptoJS from"crypto-js";import*as i7 from"@angular/forms";import{FormsModule,ReactiveFormsModule}from"@angular/forms";import*as BABYLON from"@babylonjs/core";import"@babylonjs/loaders";import*as i2$3 from"@ionic/angular/standalone";import{IonIcon,IonList,IonLabel,IonNote,IonAvatar,IonItem,IonText,IonButton,IonToolbar,IonButtons,IonModal,IonTitle,IonHeader,IonCard,ModalController as ModalController$1,IonSegment,IonSpinner,IonTextarea,IonPopover,IonContent,IonInput}from"@ionic/angular/standalone";import*as i3 from"ng-zorro-antd/avatar";import{NzAvatarModule}from"ng-zorro-antd/avatar";import{catchError}from"rxjs/operators";import*as i4 from"ng-zorro-antd/icon";import{NzIconModule}from"ng-zorro-antd/icon";import*as i5 from"ng-zorro-antd/message";import*as i8 from"ng-zorro-antd/modal";import{NzModalModule}from"ng-zorro-antd/modal";import*as AMapLoader from"@amap/amap-jsapi-loader";import ObsClient from"esdk-obs-browserjs";class AgentPrompt{constructor(){}jsonCompletion(e,t){let n,o=new FmodeChatCompletion([{role:"user",content:e}]);return o.model=t||"fmode-4.5-128k",o.sendCompletion({isDirect:!0}).pipe(finalize((()=>{let e;console.log(n),n.json=this.extractAndParseJson(e),n.complete=!0})))}extractAndParseJson(e){let t=e.indexOf("{");if(-1===t)return{};let n=0,o=t;for(let i=t;i<e.length;i++)if("{"===e[i]?n++:"}"===e[i]&&n--,0===n){o=i;break}if(0!==n)return{};const i=e.slice(t,o+1);try{return JSON.parse(i)}catch(e){return console.error("Failed to parse JSON:",e),{}}}extractMarkdownToMultiArray(e){let t=e.split("\n"),n=[],o=n,i=[n];for(let e of t){if(!e.trim())continue;if(e.startsWith("#")){let t=e.replace(/^#+\s*/,"");o.push([t]);continue}let t=e.search(/\S/)/2,n=e.trim().replace(/^-+\s*/,"");for(;t<i.length-1;)i.pop();for(;t>i.length-1;){let e=[];i[i.length-1].push(e),i.push(e)}o=i[i.length-1],o.push(n)}return n}async getFormatTpl(e,t){let n=await this.getPromptTpl(e);return await n.format(t)}async getPromptTpl(e){let t=new Parse__default.Query("PromptTemplate");t.equalTo("code",e);let n=await t.first();return PromptTemplate.fromTemplate(n?.get("template"),{templateFormat:"mustache"})}getTokens(e){return e=e||"",2*e?.length}}class FmodeTTS{constructor(e){this.subscriptionKey=e?.subscriptionKey,this.authorizationToken=e?.token,this.region=e?.region,this.subscriptionKey&&(this.speechConfig=SpeechConfig.fromSubscription(this.subscriptionKey,this.region)),this.authorizationToken&&(this.speechConfig=SpeechConfig.fromAuthorizationToken(this.authorizationToken,this.region)),this.synthesizer=new SpeechSynthesizer(this.speechConfig)}extractSSMLContent(e){var t=e.match(/<speak.*?<\/speak>/s);return t?t[0]:e}async speakAsync(e){return e=this.extractSSMLContent(e),console.log(e),new Promise(((t,n)=>{const o=Date.now();let i="speakTextAsync";e?.indexOf("<")>-1&&(i="speakSsmlAsync"),this.synthesizer[i](e,(e=>{if(e.reason===ResultReason.SynthesizingAudioCompleted){const n=Date.now();let i=e?.audioData;this.playAudioData(i),console.log(`Audio synthesis finished. Duration: ${n-o} ms`),t()}else n(`Speech synthesis failed. Reason: ${e.errorDetails}`)}),(e=>{n(`Error occurred during synthesis: ${e}`)}))}))}onBreak(e){}playAudioData(e){let t=new Blob([e],{type:"audio/wav"}),n=URL.createObjectURL(t);new Audio(n).play()}}const API_BASE="https://server.fmode.cn/api/apig/aigc/gpt",agentPrompt=new AgentPrompt,PromptTplTalkSSMLOutputCode="talk-ssml-output-tpl",PromptTplTalkTextSSMLCode="talk-text-ssml-tpl";function getMessageContentText(e){let t="";return"string"==typeof e&&(t=e),"object"==typeof e&&(t=e?.find((e=>e?.text))?.text||""),t}function getMessageImageUrl(e){return"object"==typeof e?e?.find((e=>e?.image_url))?.image_url?.url||"":null}class FmodeChat{showAvatar(){this.avatarConfig=this.role?.get("avatarConfig"),this.avatarConfig&&(this.isAvatarShow=!0,this.avatarConfig?.image&&(this.avatarConfig.image.waiting=this.avatarConfig.image.waiting||this.role?.get("thumb")||this.role?.get("avatar"),this.avatarMode="image"),this.avatarConfig?.video&&(this.avatarConfig.video.waiting=this.avatarConfig.video.waiting,this.avatarMode="video"))}constructor(e,t,n,o,i,a){this.ChatSession=Parse__default.Object.extend("ChatSession"),this.messageList=[{role:"system",content:"系统提示:AI仅供参考"}],this.latestAIResponse="",this.userInput="",this.userImage="",this.isAvatarShow=!1,this.avatarMode="",this.isPromptModalOpen=!1,this.promptList=[],this.leftButtons=[{title:"灵感",icon:"color-wand-outline",onClick:()=>{this.isPromptModalOpen=!0},show:()=>this?.promptList?.length},{title:"角色",icon:"people-outline",onClick:()=>{this.navCtrl?.navigateRoot("/chat/pro/mask")},show:()=>!0},{title:"呼叫",icon:"call-outline",onClick:()=>{this.chatServ?.callRole(this.role)},show:()=>this?.role?.get("voiceConfig")}],this.isVoiceInputMode=!1,this.isTexting=!1,this.isTalkMode=!1,this.SSMLRoleVoice="zh-CN-XiaoxiaoNeural",this.playAnimation=e=>{console.log(e)},this.chatServ=o,this.role=t,this.sessionId=e,this.navCtrl=i,this.ncloud=a,n?.id&&(this.chatSession=n,this.messageList=this.chatSession.get("messageList"),this.sessionId=n?.id)}async loadTalkSystemPrompt(e){if(!this.isTalkMode)return;if(!e)return;"男"==e?.get("gender")?this.SSMLRoleVoice="zh-CN-YunyeNeural":this.SSMLRoleVoice="zh-CN-XiaoxiaoNeural",this.SSMLRoleVoice=e?.get("voiceConfig")?.voice||this.SSMLRoleVoice;let t=await agentPrompt.getFormatTpl("talk-ssml-output-tpl",{SSMLRoleVoice:this.SSMLRoleVoice}),n=e.get("prompt")||"请你扮演飞码AI的人工智能专家。";n+=t;let o={role:"user",content:n,hidden:!0},i=this.messageList?.map((e=>e?.content)).join();if(i.indexOf(n)>-1)return;let a=this.messageList?.findIndex((e=>"system"==e?.role)),r=a+1;this.messageList.splice(r,0,o)}loadRolePrompt(){let e=this.role?.get("prompt"),t={role:"user",content:e,hidden:!0};if(!e)return;let n=this.messageList?.map((e=>e?.content)).join();if(n.indexOf(e)>-1)return;let o=this.messageList?.findIndex((e=>"system"==e?.role)),i=o+1;this.messageList.splice(i,0,t)}async sendMessage(e="FmodeAiTest测试问题",t,n,o){this.loadRolePrompt(),t?this.messageList.push({role:"user",content:[{type:"image_url",image_url:{url:t}},{type:"text",text:e}],complete:!0,createdAt:new Date}):this.messageList.push({role:"user",content:e,complete:!0,createdAt:new Date});let i=new FmodeChatCompletion(this.fixMessageList(this.messageList),{model:this.chatServ?.currentModel?.get("code")||"fmode-4.5-128k"}),a=!1;this.isTalkMode&&(a=!0);let r=i.sendCompletion({isDirect:a,onComplete:n||null}).pipe(finalize((async()=>{if(this.isTalkMode){let e=this.messageList[i.indexOfList]?.content,t=await this.getVoiceByContentText(e,o);o?.onSSMLComplete&&o?.onSSMLComplete(t),this.messageList[i.indexOfList].voice=t}this.messageList[i.indexOfList].complete=!0}))).subscribe((e=>{this.messageList[i.indexOfList]=e,this.latestAIResponse=this.getContentText(e?.content);let t=this.chatSession?.get("messageList")?.length;this.messageList?.length>t&&this.saveChatSession(),e?.complete&&(this.saveChatSession(),r.unsubscribe())}))}getVoiceByContentText(e,t,n=!1){let o=this.getContentText(e),i=new(Parse__default.Object.extend("ChatVoice")),a="";return this.SSMLRoleVoice=this.role?.get("voiceConfig")?.voice||this.SSMLRoleVoice,new Promise((async(e,t)=>{let resolveChatVoice=async()=>{i.set("content",o),i.set("ssml",a),i=await i.save(),e({id:i?.id,ssml:a})};if(0==n&&(a=`<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="zh-CN"><voice name="${this.SSMLRoleVoice}">${o}</voice></speak>`,resolveChatVoice()),1==n){let e=await agentPrompt.getFormatTpl("talk-text-ssml-tpl",{content:o,SSMLRoleVoice:this.SSMLRoleVoice});new FmodeChatCompletion(this.fixMessageList([{role:"user",content:e}]),{model:this.chatServ?.currentModel?.get("code")||"fmode-4.5-128k"}).sendCompletion({isDirect:!0}).subscribe((async e=>{e?.complete&&(a=this.getContentText(e?.content),resolveChatVoice())}))}}))}getContentText(e){return"string"==typeof e?e:e?.[0]?.text||""}async initTTS(){let e=await this.ncloud.apig("voice/tts/token",{company:localStorage.getItem("company")});if(console.log(e),e?.token){let t=new FmodeTTS(e);this.tts=t}}async playTTS(e){if(await this.initTTS(),this.tts)try{await this.tts.speakAsync(e?.ssml)}catch(e){console.error(e)}}async saveChatSession(){if("new"==this.sessionId&&(this.chatSession=new this.ChatSession),this.chatSession.set("title",this.genTitle()),this.chatSession.set("role",this.role?.toPointer()),this.chatSession.set("messageList",this.messageList),this.chatSession.set("user",Parse__default.User.current()?.toPointer()),this.chatSession=await this.chatSession.save(),this.sessionId=this.chatSession?.id,this.sessionId){let e=`${window.location.origin}/chat/pro/chat/${this.sessionId}`;if(window.location?.pathname?.indexOf("chat/session")>-1){window.location.origin,this.sessionId}e=this.getInviteUrl(e),window.history.replaceState(null,null,e);let t={sid:this.chatSession?.id,rid:this.role?.id,name:this.role?.get("name"),message:this.chatSession?.get("messageList")?.[this.chatSession?.get("messageList")?.length-1]?.content?.slice(0,20),latest:this.chatSession?.createdAt};this.chatServ?.chatList?.length||(this.chatServ.chatList=[]);let n=this.chatServ?.chatList?.find((e=>e?.sid==t?.sid));n>-1?this.chatServ.chatList[n]=t:this.chatServ?.chatList.unshift(t)}}getInviteUrl(e){let t="?";t=e?.indexOf("?")>-1?"&":"?";let n=Parse__default.User?.current()?.id;if(-1==e?.indexOf("invite="+n)){if(!n)return e;e+=t+"invite="+n}return e}genTitle(){if(this.title)return this.title;let e=this.messageList.find((e=>"user"==e.role))?.content;return"string"==typeof e&&(this.title=e?.slice(0,15)||""),"object"==typeof e&&(this.title=e?.find((e=>e?.text))?.text||""),this.title}fixMessageList(e){return e.map((e=>({role:e.role,content:e.content})))}nowStr(){let e=new Date;return`${e.getFullYear()}/${e.getMonth()+1}/${e.getDate()} ${e.getHours()}:${e.getMinutes()}:${e.getSeconds()}`}}class FmodeChatCompletion{constructor(e,t){this.content="",this.contentBuffer=[],this.isCompleted=!1,this.indexOfList=Number(e.length),this.messages=e,this.model=t?.model||"fmode-4.5-128k"}sendCompletion(e={}){e.intTime=e?.intTime||50,e.isDirect=e?.isDirect||!1,e?.isDirect&&(e.intTime=1);let t={messages:this.messages,stream:!0,model:this.model,temperature:.5,presence_penalty:0,frequency_penalty:0};return new Observable((n=>{let o=RequestFmodeChatApi("/v1/chat/completions",t).subscribe((t=>{let i=String(t);if("data: [DONE]"==i&&(this.isCompleted=!0,e?.isDirect&&this.isCompleted&&(n.next({role:"assistant",content:this.content,complete:!0,createdAt:new Date}),o.unsubscribe(),e?.onComplete&&e.onComplete({role:"assistant",content:this.content,complete:!0,createdAt:new Date}),n.complete())),i.indexOf("data: {")>-1){let t=chunkToJson(i),a=t?.choices?.[0]?.delta?.content||"";this.contentBuffer.push(a),e?.isDirect&&(this.content+=a||"",this.isCompleted||n.next({role:"assistant",cid:t?.id,content:this.content,createdAt:new Date})),e?.isDirect||this.contentPusher||(this.contentPusher=setInterval((()=>{this.isCompleted&&0==this.contentBuffer?.length&&(n.next({role:"assistant",cid:t?.id,content:this.content,complete:!0,createdAt:new Date}),o.unsubscribe(),clearInterval(this.contentPusher),n.complete()),this.contentBuffer?.length>=0&&(this.contentBuffer?.length>0&&(this.content+=this.contentBuffer.shift()),n.next({role:"assistant",cid:t?.id,content:this.content,createdAt:new Date}))}),e?.intTime))}}))})).pipe(bufferTime(100),concatMap((e=>e)),delay(200))}}function chunkToJson(e){let t;try{t=JSON.parse(e.replaceAll("data: ",""))}catch(e){console.error(e)}return t||{}}function RequestFmodeChatApi(e,t,n="POST"){return new Observable((o=>{let i=API_BASE+e,a=`Bearer ${Parse__default.User.current()?.getSessionToken()||localStorage.getItem("FMODE_AI_TOKEN")}`;return t.token=a,t&&(t=JSON.stringify(t)),fetch(i,{headers:{"Content-Type":"text/plain","Cache-Control":"no-cache"},body:t||null,method:n,credentials:"omit",mode:"cors"}).then((e=>{let t="";{let n=e.body?.getReader();const i=new TextDecoder;let a=new ReadableStream({start(e){!function read(){n.read().then((({done:t,value:n})=>{if(t)return e.close(),void o.complete();e.enqueue(n),read()}))}()}}).getReader();a.read().then((function processStream({done:e,value:n}){if(e)return;!function processData(e){let n=(t+e).split("\n");if(n?.length>1){for(let e=0;e<n.length-1;e++){let t=n[e];o.next(t)}t=n[n.length-1]}}(i.decode(n)),a.read().then(processStream)}))}})).catch((e=>o.error(e))),()=>{}}))}function JsonToFormData(e){const t=new FormData;return function appendFormData(e,n=""){Array.isArray(e)?e.forEach(((e,t)=>{appendFormData(e,`${n}[${t}]`)})):"object"==typeof e&&null!==e?Object.keys(e).forEach((t=>{const o=n?`${n}.${t}`:t;appendFormData(e[t],o)})):t.append(n,e)}(e),t}class NovaCloudService{constructor(e){this.http=e,this.serverURL="https://server.fmode.cn/api",localStorage.setItem("NOVA_APIG_SERVER","aHR0cHMlM0ElMkYlMkZzZXJ2ZXIuZm1vZGUuY24lMkZhcGklMkZhcGlnJTJG")}novaql(e,t){let n=this.serverURL+"/novaql/select",o={sql:e};return o&&t?.length>0&&(o.params=JSON.stringify(t)),new Promise(((e,t)=>{this.http.post(n,o,{headers:new HttpHeaders({"Content-Type":"application/json"}),withCredentials:!1}).subscribe((t=>{if(t&&200==t.code){let n=t.data;e(n)}}),(e=>{t(e)}))}))}apig(e,t,n="post"){localStorage.setItem("NOVA_APIG_SERVER","aHR0cHMlM0ElMkYlMkZzZXJ2ZXIuZm1vZGUuY24lMkZhcGklMkZhcGlnJTJG");let o=localStorage.getItem("NOVA_APIG_SERVER");o=decodeURIComponent(atob(o)),e=o+e,console.log(e);let i=Parse__default.User.current();return new Promise(((o,a)=>{try{this.http.request(n,e,{body:t||null,headers:new HttpHeaders({"Content-Type":"application/json",Authorization:`Bearer ${i?.getSessionToken()}`}),withCredentials:!1}).subscribe((e=>{if(e&&200==e.code||e&&1==e.code||e&&0==e.code){let t=e?.data;o(t)}else o(null)}),(e=>{console.error(e.mess),a(e)}))}catch(e){return console.error("请求出错")}}))}apigTest(e,t,n="post"){e="https://test.fmode.cn/api/apig/"+e,console.log(e);let o=Parse__default.User.current();return t.token=`Bearer ${o?.getSessionToken()}`,new Promise(((o,i)=>{try{this.http.request(n,e,{body:t||null,headers:new HttpHeaders({"Content-Type":"application/json"}),withCredentials:!1}).subscribe((e=>{if(e&&200==e.code||e&&1==e.code||e&&0==e.code){let t=e?.data;o(t)}else o(null)}),(e=>{console.error(e.mess),i(e)}))}catch(e){return console.error("请求出错")}}))}api(e,t){return e=this.serverURL+e,new Promise(((n,o)=>{this.http.post(e,t,{headers:new HttpHeaders({"Content-Type":"application/json"}),withCredentials:!1}).subscribe((e=>{if(e&&200==e.code||e&&1==e.code){let t=e.data;n(t)}else n(null)}),(e=>{o(e)}))}))}searchParse(e){let t={};if((e=e||location.search)&&e.length>1){let n=(e=e.substring(1)).split("&");for(let e=0;e<n.length;e++){if(!n[e])continue;let o=n[e].split("=");t[o[0]]=void 0===o[1]?"":o[1]}}return t}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:NovaCloudService,deps:[{token:i1.HttpClient}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:NovaCloudService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:NovaCloudService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i1.HttpClient}]});class CrossService{getMenuType(){return this.clientWidth=document.body.clientWidth,this.onResizeScreen(),this.navMenuType}constructor(e,t,n){this.platform=e,this.modalCtrl=t,this.navCtrl=n,this.mobileWidth=915,this.clientWidth=document.body.clientWidth,this.clientWidth=document.body.clientWidth,this.updateWidth(),this.onResizeScreen()}async dismisModalTop(e){let t=await this.modalCtrl.getTop();t&&(e?.preventDefault&&e?.preventDefault(),t.dismiss(),t.isOpen=!1)}updateWidth(){this.fixInterval=setInterval((()=>{if(this.clientWidth)return clearInterval(this.fixInterval),void delete this.fixInterval;console.log(document.body.clientWidth),this.clientWidth=document.body.clientWidth}),200)}onResizeScreen(e){this.clientWidth=document.body.clientWidth,this.clientWidth>=this.mobileWidth?(this.leftMenuMode="horizontal",this.navMenuType="pc"):(this.leftMenuMode="inline",this.navMenuType="mobile")}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CrossService,deps:[{token:i2.Platform},{token:i2.ModalController},{token:i2.NavController}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CrossService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CrossService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i2.Platform},{type:i2.ModalController},{type:i2.NavController}]});class ChatService{constructor(e,t,n,o,i,a){this.router=e,this.ncloud=t,this.platform=n,this.alertCtrl=o,this.navCtrl=i,this.cross=a,this.chatMap={},this.isCapacitor=!1,this.platformMap={pc:"电脑端",mobile:"移动端"},this.isCapacitor=this.platform.is("capacitor")}async loadModelList(e){if(this.modelList?.length)return;let t=new Parse__default.Query("ChatModel");t.notEqualTo("isDeleted",!0),t.equalTo("isEnabled",!0),t.addAscending("index"),this.modelList=await t.find(),this.currentModel=e||this.modelList?.find((e=>"fmode-4.5-128k"==e.get("code")))}async doButtonAction(e){let t=this.cross.navMenuType,n=e?.platform?.map((e=>this.platformMap[e])).join("、");if(e?.platform?.length>0&&-1==e?.platform?.indexOf(t)){(await this.alertCtrl.create({header:"注意",subHeader:"终端不符",message:`请您使用${n}开启本功能。`,buttons:[{role:"ok",text:"知道了"}]})).present()}else e?.path&&this.navCtrl.navigateRoot(e?.path)}async initChatMap(e){if(this.chatMap[e])return this.chatMap[e];let t=new Parse__default.Query("ChatSession");t.include("role","role.model");let n=await t.get(e),o=new FmodeChat(n?.id,n?.get("role"),n,this,this.navCtrl,this.ncloud);return this.chatMap[e]=o,this.chatMap[e]}async getChatSession(){if(!Parse__default?.User?.current()?.id)return;let e=new Parse__default.Query("ChatSession");e.include("role","role.model"),e.addDescending("updatedAt"),e.equalTo("user",Parse__default.User.current().toPointer()),e.notEqualTo("isDeleted",!0),e.limit(30);let t=await e.find();this.chatList=t.map((e=>(this.chatMap[e?.id]=new FmodeChat(e?.id,e?.get("role"),e,this,this.navCtrl,this.ncloud),{session:e,sid:e?.id,isHidden:!1,rid:e?.get("role")?.id,name:e?.get("role")?.get("name"),thumb:e?.get("role")?.get("thumb"),title:e?.get("title")||e?.get("role")?.get("name"),message:e?.get("messageList")?.[e?.get("messageList")?.length-1]?.content?.slice(0,20),latest:e?.createdAt})))}async getChatSessionDistinct(){let e=await this.ncloud.novaql('SELECT t1."objectId" as sid , "AvatarRole"."objectId" as rid, * FROM (\n SELECT *,ROW_NUMBER() OVER (PARTITION BY "user", "role" ORDER BY "createdAt" DESC) AS rn\n FROM "ChatSession" WHERE "user"=$1\n ) as t1\n LEFT JOIN "AvatarRole" ON "AvatarRole"."objectId" = t1."role"\n WHERE t1.rn=1\n LIMIT $2\n ;',[Parse__default.User.current()?.id,10]),t=e?.map((e=>({sid:e?.sid,rid:e?.rid,name:e?.name,message:e?.messageList?.[e?.messageList?.length-1]?.content?.slice(0,20),latest:e?.createdAt})));return this.chatList=t,this.chatList}createChatPanel(e,t){let n=t?.id||"new";t=new FmodeChat(n,e,t,this,this.navCtrl,this.ncloud),this.chatMap[n]=t,this.router.navigate(["/chat/pro/chat/"+n])}async createNewRoleChat(e){let t=new Parse__default.Query("AvatarRole");t.include("model");let n=await t.get(e);return new FmodeChat("new",n,null,this,this.navCtrl,this.ncloud)}async restoreChatPanel(e){let t=new Parse__default.Query("AvatarRole"),n=new Parse__default.Query("ChatSession"),o=await t.get(e?.rid),i=await n.get(e?.sid),a=new FmodeChat(e?.sid,o,i,this,this.navCtrl,this.ncloud);this.chatMap[e?.sid]=a,this.router.navigate(["/chat/pro/chat/"+e?.sid])}async callRole(e){document.body.classList.add("dark"),this.router.navigate([`/avatar/role/${e.id}`,{type:"phone"}])}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatService,deps:[{token:i1$1.Router},{token:NovaCloudService},{token:i2.Platform},{token:i2.AlertController},{token:i2.NavController},{token:CrossService}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatService,providedIn:"root"})}}function calcFileMd5(e){return new Promise(((t,n)=>{const o=new FileReader;o.onload=e=>{try{const o=e.target?.result;if(o){const e=new SparkMD5.ArrayBuffer;e.append(o);const n=e.end();t(n)}else n(new Error("Failed to load file"))}catch(e){n(e)}},o.onerror=e=>{n(e)},o.readAsArrayBuffer(e)}))}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i1$1.Router},{type:NovaCloudService},{type:i2.Platform},{type:i2.AlertController},{type:i2.NavController},{type:CrossService}]});class NovaUploadService{constructor(e,t){this.platform=e,this.diagnostic=t,this.maxSize=5242880,this.getUptoken(!0),this.requestPermission(),this.queryDomain()}async upload(e,t){let n,o=e.type,i=e.name?.split("."),a=i[i.length-1];try{n=await calcFileMd5(e)}catch(e){}let r,s,l=this.fileToBlob(e);return r=o.indexOf("image")>-1?await this.saveQiniuImageFile(l,a,null,t):await this.saveQiniuMediaFile(e,l,null,t),r.md5=n,r?.url?.indexOf("undefined")>-1&&(r.url=(this.qiniuDomain||"https://file-cloud.fmode.cn/")+r.url.replace("undefined/","")),r?.url&&(s=await this.saveAttachment(r,this.qiniuDomain,null,this.getCompanyId())),s?.id&&(r.id=s?.id),r}isCapacitor(){return this.platform.is("capacitor")||this.platform.is("cordova")}async requestPermission(){this.isCapacitor()&&(await this.requestStoagePermission(),await this.requestCameraPermission())}async requestStoagePermission(){let e=await this.diagnostic.isExternalStorageAuthorized();if(console.log("permisson_STORAGE:",e),!e){await this.diagnostic.requestExternalStorageAuthorization()}}async requestCameraPermission(){let e=await this.diagnostic.isCameraAuthorized();if(console.log("permisson_Camera:",e),!e){await this.diagnostic.requestCameraAuthorization()}}async getUptoken(e=!1){if(console.log("getUptoken"),this.qiniuConf||e)try{console.log(this.getCompanyId());let e=await Parse__default.Cloud.run("qiniu_uptoken",{company:this.getCompanyId()});console.log(e),this.qiniuConf=e}catch(e){console.error(e)}}genFileKey(e,t){let n=new Date,o=new DatePipe("en");return t||(t=this.getCompanyId()),t+"/"+o.transform(n,"yMMdd")+"/"+String(e.id).substr(20,6)+o.transform(n,"hhmmssSSS")+/\.[^\.]+/.exec(e.name)}getCompanyId(){if(this.company)return this.company;return localStorage.getItem("company")}async queryDomain(){let e=new Parse__default.Query("Company"),t=await e.get(this.getCompanyId());t.get("configQiniu")&&t.get("configQiniu").domain?(console.log(t.get("configQiniu").domain),this.qiniuDomain=t.get("configQiniu").domain):this.qiniuDomain="https://file-cloud.fmode.cn"}async saveAttachment(e,t,n,o){let i=e.url;i.startsWith("http")||(i=t+i),i=i.replace(/undefined\//,""),o||(o=localStorage.getItem("company"));let a=Parse__default.User.current(),r=new Parse__default.Query("Attachment");r.equalTo("url",i);let s=await r.first();if(s&&s.id)return console.error("该文件已存在,无需重复上传"),s;return s=new(Parse__default.Object.extend("Attachment")),s.set("size",e.size),s.set("url",i),s.set("name",e.name),s.set("mime",e.type),s.set("md5",e?.md5),a?.id&&s.set("user",a.toPointer()),o&&s.set("company",{__type:"Pointer",className:"Company",objectId:localStorage.getItem("company")}),n&&s.set("category",{__type:"Pointer",className:"Category",objectId:n}),await s.save()}async captureVideo(e){if(this.qiniuConf=e,!this.isCapacitor())return;let t=await this.cameraCaptureVideoFile(),n=await this.getMediaFileDataString(t);return await this.saveQiniuMediaFile(t,n)}async cameraCaptureVideoFile(){let e=MediaCapture,t=await e.captureVideo({limit:1});return t?.length>0?t[0]:null}async getMediaFileDataString(e){new FilesystemWeb,e.fullPath.replaceAll("///","//");let t=await Filesystem.stat({path:e.fullPath}),n=Capacitor.convertFileSrc(t.uri),o=await fetch(n),i=await o.blob();if(console.log(i.size),console.log(JSON.stringify(t)),console.log(JSON.stringify(o)),console.log(JSON.stringify(Object.keys(o))),i)return i;throw"读取文件失败"}async takePicture(e){if(this.qiniuConf=e,!this.isCapacitor())return;await this.getUptoken();let t=await this.cameraTakePictureDataUrl();if(!t?.dataUrl)return;let n=await this.base64ToBlob(t?.dataUrl),o=await this.saveQiniuImageFile(n,t?.format);return console.log(JSON.stringify(o)),o}async cameraTakePictureDataUrl(){if(!this.isCapacitor())return;return await Camera.getPhoto({quality:90,allowEditing:!1,source:CameraSource.Camera,resultType:CameraResultType.DataUrl})}async saveQiniuImageFile(e,t,n,o){let i=this.maxSize;if(e.size>i)throw await console.log("照片过大,超出限制5MB"),"超出文件大小";let a=new DatePipe("en").transform(new Date,"yyyyMMddHHmmss"),r=`${a}.${t}`,s=`image/${t}`,l={fname:r,params:{},mimeType:"image/*"},c={useCdnDomain:!0,forceDirect:!0};console.log(this.qiniuConf);let d=this.genFileKey({id:a,name:r});return console.log("图片上传前"),new Promise(((t,n)=>{console.log("进入了上传"),qiniu.upload(e,d,this.qiniuConf?.uptoken,l,c).subscribe({next:e=>{console.log(e),o&&o(e)},error:async e=>{console.log(e)},complete:n=>{console.log("上传完成"),console.log(`${this.qiniuConf?.domain}${n.key}`),n.url=`${this.qiniuConf?.domain}${n.key}`,n.name=r,n.type=s,n.size=e.size,t(n)}})}))}async saveQiniuMediaFile(e,t,n,o){let i=e.name,a=e.type;if(e.size>104857600)throw console.log("视频过大,超出限制100MB"),"超出文件大小";let r=new DatePipe("en").transform(new Date,"yyyyMMddHHmmss"),s={fname:i,params:{},mimeType:a},l={useCdnDomain:!0,forceDirect:!0},c=this.genFileKey({id:r,name:i});return console.log("图片上传前"),console.log(e.name,t.size),console.log(t.size),console.log(t.size/1024/1024),new Promise(((n,i)=>{console.log("进入了上传"),qiniu.upload(t,c,this.qiniuConf?.uptoken,s,l).subscribe({next:e=>{console.log("主要用来展示进度"),o&&o(e),console.log(JSON.stringify(e))},error:async e=>{console.log("上传失败"),console.log(JSON.stringify(e))},complete:t=>{console.log("上传完成"),console.log(JSON.stringify(t)),e.key=t.key,console.log(e.type),e.url=`${this.qiniuConf?.domain}${t.key}`,console.log(e.url),n(e)}})}))}async base64ToBlobType(e,t){let n=await fetch(`data:${t};base64,${e}`);return await n.blob()}async base64ToBlob(e){let t=await fetch(e);return await t.blob()}fileToBlob(e){const t=e.slice(0,e.size,e.type);return new Blob([t],{type:e.type})}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:NovaUploadService,deps:[{token:i2.Platform},{token:i2$1.Diagnostic}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:NovaUploadService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:NovaUploadService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i2.Platform},{type:i2$1.Diagnostic}]});class ImagineService{constructor(e,t,n){this.http=e,this.ncloud=t,this.uploadServ=n,this.taskDetailMap={},this.newWorkList=[],this.myWorkList=[]}async drawDalle(e){e.size=e?.size||"1024x1024",e.style=e?.style||"natural",e.quality=e?.quality||null;let t={model:"dall-e-3",prompt:e.prompt,n:1,quality:e.quality,response_format:"url",size:e.size,style:e.style};if(e.prompt?.length>3e3)throw"prompt maximum < 4000 characters";let n=await this.ncloud.apigTest("aigc/gpt/v1/images/generations",t);if(console.log(n),n?.id){let e=new Parse__default.Query("ImagineWork");e.get(n?.id);let t=await e.first();console.log(t),t?.id&&this.newWorkList.unshift(t)}return n}priceDalle(e){let t=[{model:"dall-e-3",quality:null,size:"1024x1024",credit:6.4},{model:"dall-e-3",quality:null,size:"1024x1792",credit:12.8},{model:"dall-e-3",quality:null,size:"1792x1024",credit:12.8},{model:"dall-e-3",quality:"hd",size:"1024x1024",credit:12.8},{model:"dall-e-3",quality:"hd",size:"1024x1792",credit:19.2},{model:"dall-e-3",quality:"hd",size:"1792x1024",credit:19.2},{model:"dall-e-2",quality:null,size:"1024x1024",credit:3.2},{model:"dall-e-2",quality:null,size:"512x512",credit:2.88},{model:"dall-e-2",quality:null,size:"256x256",credit:2.56}].find((t=>t.model==e.model&&t.quality==e.quality&&t.size==e.size));return t?.credit||19.2}priceStableDiffusion(e){let t=e.width*e.height,n=763e-9*t*e.steps+2278e-8*t*(e?.upscale||0)+(e?.hrSteps||0)*t*(e?.hrScale||0)*(e?.hrScale||0)*763e-9+(e?.faceFix?2:0)+(e?.imgOptions?.removeBackground?2:0)+(e?.imgOptions?.redrawBackground?2:0)+(e?.imgOptions?.facePreservation?2:0)+(e?.imgOptions?.genderDetect?1:0)+2*(e?.controlnet?.units?.length||0);return n=.3*n*e.batchSize,n}b64DataToBase64Image(e){let t=atob(e),n=new Blob([t],{type:"image/webp"});new Promise((e=>{let t=new FileReader;t.onloadend=function(){let n=t.result;console.log(n),e(n)},t.readAsDataURL(n)}))}async draw(e){let t=await this.ncloud.apig("aigc/sdapi/v1/draw",e),n=t?.paintingSign;return n&&setTimeout((async()=>{let e=new Parse__default.Query("ImagineWork");e.equalTo("taskId",n);let t=await e.first();console.log(t),t?.id&&this.newWorkList.unshift(t)}),1e3),t}async taskDetail(e){let t=await this.ncloud.apig("aigc/sdapi/v1/task/detail",{taskId:e});return console.log(t),this.taskDetailMap[e]=t,t}getMyWorkQuery(){let e=Parse__default.User.current();if(!e?.id)return;let t=this.getWorkQuery();return t.include("model","module","user"),t.equalTo("user",e.toPointer()),t}getWorkQuery(){let e=new Date((new Date).getTime()-6e4),t=Parse__default.Query.fromJSON("ImagineWork",{where:{$or:[{createdAt:{$lte:e},progress:{$ne:0}},{createdAt:{$gt:e}}]}});return t.include("model","module","user"),t.notEqualTo("isDeleted",!0),t.notEqualTo("isFailed",!0),t.doesNotExist("respData.error"),t.doesNotExist("respData.data.taskLimitCount"),t.addDescending("createdAt"),t}getimg(){return new Promise(((e,t)=>{let n=document.createElement("input");n.type="file",n.click();let handleChange=async()=>{if(n.removeEventListener("change",handleChange),n.files&&n.files.length>0){let t=n.files[0],o=await this.uploadServ.upload(t,(e=>{console.log(e),e.total.percent.toFixed(2)}));e(o.url)}else t("未选择文件")};n.addEventListener("change",handleChange)}))}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ImagineService,deps:[{token:i1.HttpClient},{token:NovaCloudService},{token:NovaUploadService}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ImagineService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ImagineService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i1.HttpClient},{type:NovaCloudService},{type:NovaUploadService}]});class FmaiService{constructor(e,t){this.imagine=e,this.chat=t}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmaiService,deps:[{token:ImagineService},{token:ChatService}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmaiService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmaiService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:ImagineService},{type:ChatService}]});let colorMap=["primary","secondary","tertiary","success","warning","danger","light","medium","dark"];const MASK_LIST=[{name:"执行李",type:"employee",title:"首席执行官",desc:"一位富有远见和领导才能的创业新秀。她具备战略思维和决策能力,能够为公司设定长期目标并领导团队实现这些目标。",color:colorMap[0],cover:"https://imgsource.huashi6.com/images/ai/2023/9/29/15_48766.jpg?e=1695974629&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:oPkQSsyQLLD08R_J4SMeO1f1RdM="},{name:"技术刘",type:"employee",title:"首席技术官",desc:"一位技术专家,拥有广泛的技术知识和经验。他善于解决复杂的技术问题,并能够领导开发团队实施创新的技术解决方案。",color:colorMap[1],cover:["https://imgsource.huashi6.com/images/ai/2023/9/29/9_619877.jpg?e=1695952672&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:LDuSg8_n5g4Rj_8F5PKrGzV4T54=","https://imgsource.huashi6.com/images/ai/2023/9/27/20_17767.jpg?e=1695819037&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:a9uOeeJMN2oopK-3WQZzldPXfH0="]},{name:"点子王",type:"employee",title:"首席运营官",desc:"一位富有创意和市场洞察力的市场营销专家。她擅长制定营销策略,了解目标受众,并能够利用各种渠道和工具推广公司的产品或服务。",color:colorMap[2],cover:"https://imgsource.huashi6.com/images/ai/2023/9/29/9_186291.jpg?e=1695952125&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:EhEUtwnC9hpu-SXXsBrp2Q-rcJk="},{title:"设计总监",name:"李欣",type:"employee",desc:"一位富有创造力和用户导向思维的设计师。她能够理解用户需求,并通过设计直观、易用且吸引人的用户界面来提供出色的用户体验。",color:colorMap[3],cover:"https://imgsource.huashi6.com/images/ai/2023/9/29/9_18099.jpg?e=1695952201&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:G_a60v52iTTqvJgeTSa_8zJUY2w="},{title:"运营经理",name:"刘洁",type:"employee",desc:"一位组织能力强、注重细节并擅长解决问题的运营专家。她能够协调各个部门的工作,并确保公司的运营流程高效运行。",color:colorMap[4],cover:"https://imgsource.huashi6.com/images/ai/2023/9/29/9_842519.jpg?e=1695952125&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:FM_kKZDzkcLQ1EX4266dXU46cRc="},{title:"销售经理",name:"张伟",type:"employee",desc:"一位富有销售天赋和人际交往能力的销售专家。他善于与客户建立良好的关系,并能够推动销售团队实现业绩目标。",color:colorMap[5],cover:"https://imgsource.huashi6.com/images/ai/2023/9/29/15_739110.jpg?e=1695974920&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:vg_sn-qn67MJS-7j2o7mWzOCUSk="},{title:"数据分析师",name:"杨晨",type:"employee",desc:"一位善于解读数据和提供商业洞察的数据分析专家。她能够收集、分析和解释数据,为公司的决策制定提供有力的支持。",color:colorMap[6],cover:"https://imgsource.huashi6.com/images/ai/2023/9/29/15_204321.jpg?e=1695974779&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:dC2sGmJekSPBTCycPF76BkQPBoo="},{title:"财务经理",name:"赵晓",type:"employee",desc:"一位精通财务管理和分析的专业人士。她能够制定财务战略、管理公司的财务流程,并提供准确的财务报告和预测。",color:colorMap[7],cover:"https://imgsource.huashi6.com/images/ai/2023/9/29/15_947878.jpg?e=1695974779&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:TFGn0_l2PqhUTe9G4A3it769hcU="},{title:"品牌专员",name:"王雅",type:"employee",desc:"一位富有创意和品牌意识的专业人士。她能够塑造和管理公司的品牌形象,制定品牌营销策略,并与内部和外部利益相关者建立良好的合作关系。",color:colorMap[8],cover:["https://imgsource.huashi6.com/images/ai/2023/9/29/15_129581.jpg?e=1695975151&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:YQrpiv1hBKRPIdaEbDDDkLFuPG8=","https://imgsource.huashi6.com/images/ai/2023/9/29/15_912136.jpg?e=1695975151&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:8SVMU1rdKD8eaJ1gH_qGQzcrMhM="]},{title:"全科",name:"孔博",type:"teacher",desc:"擅长全科教学的金牌教师,知识面广泛,博古通今,因材施教,耐心稳重。",color:colorMap[0],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/12_40958.jpg?e=1697604189&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:U7r1Td30lXdf9mE1TMVAnDhBP6c="]},{title:"语文",name:"王明",type:"teacher",desc:"激发学生对文学的热爱,引导他们成为优秀的作家和沟通者。",color:colorMap[1],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/11_698893.jpg?e=1697602689&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:hK_AuY7BA1pp33QVeUue5QjIg4o="]},{title:"数学",name:"万红",type:"teacher",desc:"以清晰的逻辑和耐心的指导,帮助学生掌握数学的基础知识和解题技巧。",color:colorMap[2],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/11_256253.jpg?e=1697603314&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:K2iqp_ZzHYzXNu_0VJlywyANHp8="]},{title:"英语",name:"张瑞",type:"teacher",desc:"激发学生对英语学习的兴趣,培养他们的听、说、读、写能力,让他们自信地运用英语。",color:colorMap[3],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/12_266171.jpg?e=1697603707&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:uhpxBbT-jlSt_KjAnj0SFsFAjWU="]},{title:"物理",name:"金晓",type:"teacher",desc:"通过实验和案例,帮助学生理解物理原理,培养他们的科学思维和实验技能。",color:colorMap[4],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/11_694925.jpg?e=1697603071&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:FznZxhkYUrZ-BzX05dvNt8acTUw="]},{title:"化学",name:"陈华",type:"teacher",desc:"激发学生对化学的好奇心,教授他们化学知识和实验技巧,培养他们的实验和分析能力。",color:colorMap[5],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/11_942234.jpg?e=1697603169&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:__2T8cxLl4J0AwMR9MJdDiooDF0="]},{title:"生物",name:"杨婷",type:"teacher",desc:"引导学生探索生命的奥秘,培养他们的科学观察和实验能力,让他们热爱生物科学。",color:colorMap[6],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/12_330738.jpg?e=1697603491&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:2K5-DHPnUQ-R9GGxtWKiEG68QlE="]},{title:"历史",name:"赵亮",type:"teacher",desc:"帮助学生了解历史事件和文化背景,培养他们的历史意识和批判思维。",color:colorMap[7],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/11_256302.jpg?e=1697602689&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:YP7ffC1YKO-Pb0C3ks4caT0QqZk="]},{title:"地理",name:"林丽",type:"teacher",desc:"引导学生探索地球的奥秘,培养他们的地理观察和分析能力,让他们热爱地理科学。",color:colorMap[8],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/12_555804.jpg?e=1697604054&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:xLN4QW0x9jx9lEB4EFHWvI_gEsI="]}];class UtilnowPipe{constructor(){this.enLocale={"秒钟前":" seconds ago","分钟前":" minutes ago","小时前":" hours ago","天前":" days ago"}}transform(e,t){let n=((new Date).getTime()-e.getTime())/1e3;if(n<=60)return this.handleArgs(n.toFixed(0),"秒钟前",t);let o=n/60;if(o<60)return this.handleArgs(o.toFixed(0),"分钟前",t);let i=o/60;if(i<24)return this.handleArgs(i.toFixed(0),"小时前",t);let a=i/24;return a<7?this.handleArgs(a.toFixed(0),"天前",t):`${e?.getFullYear()}-${e?.getMonth()+1}-${e?.getDate()}`}handleArgs(e,t,n){return"en"==n&&(t=this.enLocale[t]),"TranslateService"==n?.constructor?.name&&(console.log(t),"en"==n?.getDefaultLang()&&(t=this.enLocale[t])),"json"==n?{unit:t,value:e}:e+t}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:UtilnowPipe,deps:[],target:i0.ɵɵFactoryTarget.Pipe})}static{this.ɵpipe=i0.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:UtilnowPipe,isStandalone:!0,name:"utilnow"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:UtilnowPipe,decorators:[{type:Pipe,args:[{name:"utilnow",standalone:!0}]}]});class ChatContentPipe{transform(e,...t){console.log(t);let n=t?.[0]||"text";return"text"==n?getMessageContentText(e):"image_url"==n?getMessageImageUrl(e):e}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatContentPipe,deps:[],target:i0.ɵɵFactoryTarget.Pipe})}static{this.ɵpipe=i0.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:ChatContentPipe,isStandalone:!0,name:"chatContent"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatContentPipe,decorators:[{type:Pipe,args:[{name:"chatContent",pure:!0,standalone:!0}]}]});class HidexmlPipe{transform(e,...t){return e?this.hideXmlTags(e):""}hideXmlTags(e){return e.replace(/<[^>]*>/g,"")}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:HidexmlPipe,deps:[],target:i0.ɵɵFactoryTarget.Pipe})}static{this.ɵpipe=i0.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:HidexmlPipe,isStandalone:!0,name:"hidexml"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:HidexmlPipe,decorators:[{type:Pipe,args:[{name:"hidexml",standalone:!0}]}]});class MarkdownMathJax{constructor(e){this.options=e,this.adaptor=liteAdaptor(),RegisterHTMLHandler(this.adaptor)}text_to_mathjax(e,t){if(!e?.length)return"";if(!e?.replace)return"";t=t||this.options;let n=new SVG({fontCache:"local"});"chtml"==t?.output&&(n=new CHTML);const o=mathjax.document("",{skipHtmlTags:["script","noscript","style","textarea","pre","code","annotation","annotation-xml"],InputJax:new TeX({processEscapes:!0,packages:AllPackages}),OutputJax:n}),i={em:16,ex:8,containerWidth:1280};return[/\$\$\ (.+?)\ \$\$/g,/\$\$(.+?)\$\$/g,/\$\$\n(.+?)\n\$\$/g,/\$(.+?)\$/g,/\\\((.+?)\\\)/g,/\\\[(.+?)\\\]/g].forEach((t=>{e=e.replace(t,((e,t)=>{let n=o.convert(`${t}`,i);return`<span class="mathjax raw" style="margin-left:10px;margin-right:10px;">${this.adaptor.innerHTML(n)}</span>`}))})),e}}let md=new MarkdownIt({html:!0,xhtmlOut:!0,breaks:!1,linkify:!1,typographer:!1,quotes:"“”‘’",highlight:function(e,t){if(t&&hljs.getLanguage(t))try{return`<pre style="position:relative;padding:10px;" class="hljs lang-${t}"><code>${hljs.highlight(e,{language:t}).value}</code><small class="hljs-lang"><span class="sr-only">Language:</span>${t}</small></pre>`}catch(e){}return""}});md.use(abbr),md.use(footnote),md.use(deflist),md.use(mark),md.use(ins),md.use(sub),md.use(sup),md.use(ruby);const mditConfig={plantumlServer:"https://www.plantuml.com/plantuml"};function makePlantumlURL(e){const t=plantumlEncoder.encode(e);return`${mditConfig.plantumlServer}/svg/${t}`}md.renderer.rules.plantuml=(e,t,n,o,i)=>{const a=e[t];if("plantuml"!==a.type)return e[t].content;return`\n <img src="${makePlantumlURL(a.content)}" />\n <pre style="position:relative;padding:10px;" class="hljs lang-plantuml"><code>${a.content}</code><small class="hljs-lang"><span class="sr-only">Language:</span>plantuml</small></pre>\n `},md.core.ruler.push("plantuml",(e=>{const t=e.tokens;for(const e of t)"fence"===e.type&&"plantuml"===e.info&&(e.type="plantuml")}));const spaceregex=/\s*/,notinhtmltagregex=/(?![^<]*>|[^<>]*<\/)/;let coloregex=/\[color=([#|(|)|\s|,|\w]*?)\]/;coloregex=new RegExp(coloregex.source+notinhtmltagregex.source,"g");let nameregex=/\[name=(.*?)\]/,timeregex=/\[time=([:|,|+|-|(|)|\s|\w]*?)\]/;const nameandtimeregex=new RegExp(nameregex.source+spaceregex.source+timeregex.source+notinhtmltagregex.source,"g");function replaceExtraTags(e){return console.log("replaceExtraTags",e),e=(e=(e=(e=e.replace(coloregex,'<span class="color" data-color="$1"></span>')).replace(nameandtimeregex,'<small><i class="fa fa-user"></i> $1 <i class="fa fa-clock-o"></i> $2</small>')).replace(nameregex,'<small><i class="fa fa-user"></i> $1</small>')).replace(timeregex,'<small><i class="fa fa-clock-o"></i> $1</small>'),console.log("replaceExtraTags",e),e}function finishView(e){let t=$.parseHTML(`<html><body><div id="topmd">${e}</div></body></html>`)[0],n=$(t),o=n.find("blockquote.raw").removeClass("raw");o=n.find("blockquote");let i=$(o).find("p");i.each(((e,t)=>{let n=$(t).html();n=replaceExtraTags(n),t.innerHTML=n,$(t).html(n),i[e].innerHTML=n,$(i[e]).html(n)})),o.find(".color").each(((e,t)=>{let n=$(t).attr("data-color");$(t).closest("blockquote").css("border-left-color",n)}));let a="<style>\n .markdown-section {\n color: black;\n text-align: left;\n }\n .markdown-section pre .hljs-lang{\n text-transform: uppercase;\n font-weight: 700;\n font-size: .75rem;\n line-height: 1rem;\n padding-top: .25rem;\n padding-bottom: .25rem;\n padding-left: .5rem;\n padding-right: .5rem;\n background-color: rgba(0,0,0,.3);\n border-bottom-left-radius: .375rem;\n top:0;\n right:0;\n position:absolute;\n}\n\n }\n .markdown-section pre .hljs {\n position:relative!important;\n background: #272822!important;\n padding:10px!important;\n color: #ddd;\n text-shadow: none!important;\n }\n\n .markdown-section blockquote {\n margin: 0;\n margin-bottom: 0px;\n margin-bottom: .85em;\n padding: 0 15px;\n color: #858585;\n border-left: 4px solid #e5e5e5;\n border-left-color: rgb(229, 229, 229);\n }\n .markdown-section img {\n max-width:100%;\n }\n </style>"+(n.html()||e);return a=a.replaceAll('src="/uploads/','src="https://md.fmode.cn/uploads/'),a}nameregex=new RegExp(nameregex.source+notinhtmltagregex.source,"g"),timeregex=new RegExp(timeregex.source+notinhtmltagregex.source,"g");class MarkdownParse{constructor(){}parseToHTML(e){this.info("markdown",e),e=(new MarkdownMathJax).text_to_mathjax(e,{output:"svg"});let t=md.render(e);return t=finishView(t),t}info(...e){}}class MarkdownPreviewComponent{constructor(e,t){this.domSan=e,this.renderer=t,this.content="",this.render=!0}ngAfterViewInit(){this.renderMdToHTML()}renderMdToHTML(){if(!this.render)return;let e=(new MarkdownParse).parseToHTML(this.content);this.safeHTML=this.domSan.bypassSecurityTrustHtml(e);let t=this.renderer.createElement("div");t.innerHTML=e,this.renderer.appendChild(this.mdContent.nativeElement,t)}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:MarkdownPreviewComponent,deps:[{token:i1$2.DomSanitizer},{token:i0.Renderer2}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:MarkdownPreviewComponent,selector:"fm-markdown-preview",inputs:{content:"content",render:"render"},viewQueries:[{propertyName:"mdContent",first:!0,predicate:["mdContent"],descendants:!0}],ngImport:i0,template:'<div class="message-body">\n <div *ngIf="render" #mdContent class="markdown-section">\n </div>\n <div *ngIf="!render" class="pre-section">\n {{content}}\n </div>\n</div>',styles:[":host{overflow-x:auto}.message-body div{text-align:left;overflow-x:auto}.message-body .pre-section{white-space:pre-wrap}.markdown-section blockquote{margin:0 0 .85em;padding:0 15px;color:#858585;border-left:4px solid #e5e5e5;border-left-color:#e5e5e5}\n"],dependencies:[{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:MarkdownPreviewComponent,decorators:[{type:Component,args:[{selector:"fm-markdown-preview",template:'<div class="message-body">\n <div *ngIf="render" #mdContent class="markdown-section">\n </div>\n <div *ngIf="!render" class="pre-section">\n {{content}}\n </div>\n</div>',styles:[":host{overflow-x:auto}.message-body div{text-align:left;overflow-x:auto}.message-body .pre-section{white-space:pre-wrap}.markdown-section blockquote{margin:0 0 .85em;padding:0 15px;color:#858585;border-left:4px solid #e5e5e5;border-left-color:#e5e5e5}\n"]}]}],ctorParameters:()=>[{type:i1$2.DomSanitizer},{type:i0.Renderer2}],propDecorators:{content:[{type:Input}],mdContent:[{type:ViewChild,args:["mdContent"]}],render:[{type:Input}]}});class MarkdownPreviewModule{static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:MarkdownPreviewModule,deps:[],target:i0.ɵɵFactoryTarget.NgModule})}static{this.ɵmod=i0.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:MarkdownPreviewModule,declarations:[MarkdownPreviewComponent],imports:[CommonModule],exports:[MarkdownPreviewComponent]})}static{this.ɵinj=i0.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:MarkdownPreviewModule,imports:[CommonModule]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:MarkdownPreviewModule,decorators:[{type:NgModule,args:[{declarations:[MarkdownPreviewComponent],imports:[CommonModule],exports:[MarkdownPreviewComponent]}]}]});class ClipboardService{constructor(e){this.toastCtrl=e}async copyToClipboard(e){try{return await Clipboard.write({string:e}),void this.copySuccess()}catch(t){try{if(navigator.clipboard&&window.isSecureContext)return await(navigator?.clipboard?.writeText(e)),void this.copySuccess();throw!1}catch(t){let n=document.createElement("textarea");n.value=e,n.style.position="fixed",n.style.left="-9999px",n.style.top="-9999px",document.body.appendChild(n),n.focus(),n.select();try{let e=document?.execCommand("copy");e?this.copySuccess():console.error("无法复制文本")}catch(e){console.error("无法复制文本: ",e)}document.body.removeChild(n)}}}async copySuccess(){(await this.toastCtrl.create({duration:1e3,message:"复制成功",color:"primary",icon:"information-circle",position:"top"})).present()}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ClipboardService,deps:[{token:i2.ToastController}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ClipboardService,providedIn:"root"})}}function pcmtoWav(e,t,n,o){let i={chunkId:[82,73,70,70],chunkSize:0,format:[87,65,86,69],subChunk1Id:[102,109,116,32],subChunk1Size:16,audioFormat:1,numChannels:n||1,sampleRate:t||16e3,byteRate:0,blockAlign:0,bitsPerSample:o||16,subChunk2Id:[100,97,116,97],subChunk2Size:0};function u32ToArray(e){return[255&e,e>>8&255,e>>16&255,e>>24&255]}function u16ToArray(e){return[255&e,e>>8&255]}let a=new Uint8Array(e);i.blockAlign=i.numChannels*i.bitsPerSample>>3,i.byteRate=i.blockAlign*i.sampleRate,i.subChunk2Size=a.length*(i.bitsPerSample>>3),i.chunkSize=36+i.subChunk2Size;let r=i.chunkId.concat(u32ToArray(i.chunkSize),i.format,i.subChunk1Id,u32ToArray(i.subChunk1Size),u16ToArray(i.audioFormat),u16ToArray(i.numChannels),u32ToArray(i.sampleRate),u32ToArray(i.byteRate),u16ToArray(i.blockAlign),u16ToArray(i.bitsPerSample),i.subChunk2Id,u32ToArray(i.subChunk2Size)),s=new Uint8Array(r),l=new Uint8Array(s.length+a.length);l.set(s),l.set(a,s.length);let c=new Blob([l],{type:"audio/wav"});return window.URL.createObjectURL(c)}function resampleAudio(e,t,n){let o=e.length,i=Math.floor(o/t*n),a=[];for(let o=0;o<i;o++){let i=Math.floor(o*(t/n));a[o]=e[i]}return a}function convertFrameBufferToBase64(e){const t=new Uint8Array(2*e.length);for(let n=0;n<e.length;n++){const o=e[n];t[2*n]=255&o,t[2*n+1]=o>>8&255}return btoa(String.fromCharCode.apply(null,t))}function resampleBuffer(e,t,n){const o=t/n,i=Math.round(e.length/o),a=new Int16Array(i);for(let t=0;t<i;t++){const n=Math.floor(t*o);a[t]=e[n]}return a}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ClipboardService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i2.ToastController}]});const SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition,SpeechGrammarList=window.SpeechGrammarList||window.webkitSpeechGrammarList;class WebSpeech{constructor(e){this.platform=e}startRecognition(e="Nihao | Hello"){if(!SpeechRecognition)return;if(this.recognition&&this.recognition.stop(),console.log("startRecognition"),this.recognition=new SpeechRecognition,!this.recognition)return;this.recognition.continuous=!0;let t=`#JSGF V1.0; grammar words; public <word> = ${e} ;`;this.recognition=new SpeechRecognition;let n=new SpeechGrammarList;n.addFromString(t,1),this.recognition.grammars=n,this.recognition.start(),this.recognition.onresult=e=>{let t=e.results||[];console.log(t),console.log(t[0]?.[0]),t[0]?.[0]?.transcript?.indexOf("Nihao")>-1&&console.log("Nihao成功唤醒"),t[0]?.[0]?.transcript?.indexOf("Hello")>-1&&console.log("Hello成功唤醒"),this.startRecognition()},this.recognition.onend=e=>{console.log(e)},this.recognition.onerror=e=>{console.error(e)}}speak(e,t=1,n=1.2,o=.8){this.platform.is("capacitor")||this.speakWithEdge(e,1,1.2,.8)}speakWithEdge(e,t=1,n=1.2,o=.8){let i=new SpeechSynthesisUtterance(e),a=this.getVoiceByName("Yaoyao");console.log(a),a&&(i.voice=a),i.rate=n,i.pitch=t,i.volume=10,window.speechSynthesis.speak(i)}getVoiceByName(e){return window.speechSynthesis.getVoices().find((t=>t.name.indexOf(e)>-1))}}class FmodeVoiceService{constructor(e,t){this.platform=e,this.diagnostic=t,this.webSpeech=WebSpeech,this.recordPcmBlob=null,this.recordType="pcm",this.encodingType="raw",this.connStatus="",this.btnStatus="UNDEFINED",this.resultText="",this.resultTextTemp="",this.APPID="50f4a46c",this.API_SECRET="NzFlNmFhZDJjMDNkZGM3NzI0Mzg2OGNm",this.API_KEY="106ddc40dfd4b9ca6d7b47c70fada749",this.requestPermission()}toggleRecord(){console.log(this.btnStatus),"UNDEFINED"===this.btnStatus||"CLOSED"===this.btnStatus?this.startTalk():"CONNECTING"!==this.btnStatus&&"OPEN"!==this.btnStatus||this.finishTalk()}finishTalk(){this.onBeforeFinishTalk&&this.onBeforeFinishTalk(),this.recordStop(),setTimeout((()=>{this.onAfterFinishTalk&&this.onAfterFinishTalk()}),1e3)}async startTalk(e){this.onBeforeStartTalk&&this.onBeforeStartTalk(),event?.preventDefault(),await this.openWithPriviledge(),setTimeout((()=>{this.connectWebSocket()}),100),this.onAfterStartTalk&&this.onAfterStartTalk()}cancelTalk(){this.onBeforeCancelTalk&&this.onBeforeCancelTalk(),this.recordStop(),this.iatWS?.close(),this.resultText=null,this.onAfterCancelTalk&&this.onAfterCancelTalk()}async recordStart(){this.createRecorder(),await this.openWithPriviledge(),this.recorder.start(),this.changeBtnStatus("OPEN"),this.onAfterRecordStart&&this.onAfterRecordStart()}recordStop(){this.recorder?.stop(((e,t)=>{this.iatWS.send(JSON.stringify({data:{status:2,format:"audio/L16;rate=16000",encoding:this.encodingType,audio:""}}));let n=(window.URL||webkitURL).createObjectURL(e);console.log(e,n,"时长:"+t+"ms"),this.recordPcmBlob=e,this.recorder.close(),this.recorder=null,console.log("localUrl",n)}),(e=>{console.log("录音失败:"+e),this.recorder.close(),this.recorder=null})),clearInterval(this.countdownInterval),this.changeBtnStatus("CLOSED")}playRecord(){this.playPCM(this.recordPcmBlob,44100)}playPCM(e,t){let n=new FileReader;n.onload=function(e){let n=pcmtoWav(e.target.result,t,1,16),o=new Audio;o.src=n,o.play()},n.readAsArrayBuffer(e)}async playBuffers(){let e=await this.BuffersToBlob(this.buffers);this.playPCM(e,44100)}BuffersToBlob(e){let t=[];return e.forEach((e=>{e.forEach((e=>{t.push(e)}))})),new Blob([t],{type:"audio/pcm"})}splitAudioData(e){const t=1280,n=Math.ceil(e.length/t),o=[];for(let i=0;i<n;i++){const n=i*t,a=n+t,r=e.slice(n,a);o.push(r)}return o}BufferToBlob(e){return new Blob([e],{type:"audio/pcm"})}createRecorder(){this.recorder||(this.recorder=Recorder({type:this.recordType,sampleRate:44100,bitRate:16,onProcess:(e,t,n,o,i,a)=>{let r=e.length&&e[e.length-1];if(this.buffers=e,r=resampleBuffer(r,44100,16e3),this.iatWS.readyState===this.iatWS.OPEN){if(this.disableASR)return;this.iatWS.send(JSON.stringify({data:{status:1,format:"audio/L16;rate=16000",encoding:this.encodingType,audio:convertFrameBufferToBase64(r)}}))}this.waveClient?.input(e[e.length-1],t,o)}}))}async openWithPriviledge(){return console.log(this.btnStatus),await this.requestPermission(),this.createRecorder(),!!Recorder.IsOpen()||new Promise((e=>{this.recorder.open((()=>{let t=document.querySelector(".record-wave");t&&(console.log(t),Recorder.WaveView&&(this.waveClient=Recorder.WaveView({elem:".record-wave"}))),e(!0)}),((e,t)=>{console.log((t?"UserNotAllow,":"")+"无法录音:"+e)}))}))}getWebSocketUrl(){let e="wss://iat-api.xfyun.cn/v2/iat",t="iat-api.xfyun.cn",n=this.API_KEY,o=this.API_SECRET,i=(new Date).toUTCString(),a=`host: ${t}\ndate: ${i}\nGET /v2/iat HTTP/1.1`,r=CryptoJS.HmacSHA256(a,o),s=CryptoJS.enc.Base64.stringify(r);return e=`${e}?authorization=${btoa(`api_key="${n}", algorithm="hmac-sha256", headers="host date request-line", signature="${s}"`)}&date=${i}&host=${t}`,e}toBase64(e){for(var t="",n=new Uint8Array(e),o=n.byteLength,i=0;i<o;i++)t+=String.fromCharCode(n[i]);return window.btoa(t)}countdown(){let e=60;this.connStatus=`录音中(${e}s)`,this.countdownInterval=setInterval((()=>{e-=1,console.log(e),e<=0?(clearInterval(this.countdownInterval),this.recordStop()):this.connStatus=`录音中(${e}s)`}),1e3)}changeBtnStatus(e){this.btnStatus=e,"CONNECTING"===e?(this.connStatus="建立连接中",this.resultText="",this.resultTextTemp=""):"OPEN"===e?this.countdown():"CLOSING"===e?this.connStatus="关闭连接中":"CLOSED"===e&&(this.connStatus="开始录音")}renderResult(e){let t=JSON.parse(e);if(t.data&&t.data.result){let e=t.data.result,n="",o=e.ws;for(let e=0;e<o.length;e++)n+=o[e].cw[0].w,console.log(n);e.pgs?("apd"===e.pgs&&(this.resultText=this.resultTextTemp),this.resultTextTemp=this.resultText+n):this.resultText=this.resultText+n,this.resultTextTemp||this.resultText,console.log("diff",this.resultTextTemp,this.resultText)}0===t.code&&2===t.data.status&&this.iatWS.close(),0!==t.code&&(this.iatWS.close(),console.error(t))}connectWebSocket(){console.log("connectWebSocket");const e=this.getWebSocketUrl();if("WebSocket"in window)this.iatWS=new WebSocket(e);else if(!("MozWebSocket"in window))return void alert("浏览器不支持WebSocket");console.log("connectWebSocket",this.btnStatus),this.changeBtnStatus("CONNECTING"),this.iatWS.onopen=e=>{this.recordStart();var t={common:{app_id:this.APPID},business:{language:"zh_cn",domain:"iat",accent:"mandarin",vad_eos:5e3,dwa:"wpgs"},data:{status:0,format:"audio/L16;rate=16000",encoding:this.encodingType}};this.iatWS.send(JSON.stringify(t))},this.iatWS.onmessage=e=>{this.renderResult(e.data)},this.iatWS.onerror=e=>{console.error("error",e),this.recordStop(),this.changeBtnStatus("CLOSED")},this.iatWS.onclose=e=>{console.error("close",e),this.recordStop(),this.changeBtnStatus("CLOSED")}}isCapacitor(){return this.platform.is("capacitor")||this.platform.is("cordova")}async requestPermission(){if(this.isCapacitor())try{await this.requestStoagePermission(),await this.requestCameraPermission(),await this.requestMicPermission(),await this.requestRecordAudioPermission()}catch(e){console.error(e)}}async requestRecordAudioPermission(){let e=await this.diagnostic.requestRuntimePermissions([this.diagnostic.permission.RECORD_AUDIO]);console.log("record permission request:",e)}async requestMicPermission(){let e=await this.diagnostic.isMicrophoneAuthorized();if(console.log("permisson_MIC:",e),!e){await this.diagnostic.requestMicrophoneAuthorization()}}async requestStoagePermission(){let e=await this.diagnostic.isExternalStorageAuthorized();if(console.log("permisson_STORAGE:",e),!e){await this.diagnostic.requestExternalStorageAuthorization()}}async requestCameraPermission(){let e=await this.diagnostic.isCameraAuthorized();if(console.log("permisson_Camera:",e),!e){await this.diagnostic.requestCameraAuthorization()}}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeVoiceService,deps:[{token:i2.Platform},{token:i2$1.Diagnostic}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeVoiceService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeVoiceService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i2.Platform},{type:i2$1.Diagnostic}]});class RolePointsCloud{constructor(e,t,n){this.offsetPosition=new BABYLON.Vector3(0,1.25,0),this.animationGroup=new BABYLON.AnimationGroup("RoleAnimGroup"),this.AnimMap={idle:null},this.scene=e,this.engine=this.engine}async init(){this.Mesh=this.loadMesh(),this.loadIdleAnim()}playAnim(e){this.scene.beginDirectAnimation(this.Mesh,[this.AnimMap[e]],0,120,!0)}loadMesh(){let e=BABYLON.MeshBuilder.CreateSphere("sphere",{diameter:2},this.scene);return e.position.addInPlace(this.offsetPosition),e.visibility=1,e.material=new BABYLON.StandardMaterial("mat",this.scene),e.material.wireframe=!0,e.scaling=new BABYLON.Vector3(1,1,1),e}loadIdleAnim(){let e=new BABYLON.Animation("idle","scaling",30,BABYLON.Animation.ANIMATIONTYPE_VECTOR3,BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE),t=[];t.push({frame:0,value:new BABYLON.Vector3(1,1,1)}),t.push({frame:60,value:new BABYLON.Vector3(1.5,1.5,1.5)}),t.push({frame:120,value:new BABYLON.Vector3(1,1,1)}),e.setKeys(t),this.Mesh.animations.push(this.AnimMap.idle),this.AnimMap.idle=e,this.animationGroup.addTargetedAnimation(this.AnimMap.idle,this.Mesh)}}class CompAvatarParticleComponent{constructor(e){this.elementRef=e,this.isWebVR=!1,this.animMap={}}ngAfterViewInit(){if(this.canvas=this.renderCanvas.nativeElement,console.log(this.canvas),this.canvas){let e={};this.engine=new BABYLON.Engine(this.canvas,!0,e),console.log(this.engine),this.createScene(),this.engine.runRenderLoop((()=>{this.scene?.render(),this.engine?.resize()})),window.addEventListener("resize",(()=>{this.engine?.resize()}))}}async createScene(){this.scene=new BABYLON.Scene(this.engine),this.scene.clearColor=new BABYLON.Color4(0,0,0,1),this.mainCamera=this.createCamera(),console.log(this.mainCamera),this.currentRole=new RolePointsCloud(this.scene,this.engine,this.mainCamera),await this.currentRole.init(),this.currentRole.playAnim("idle"),this.currentRole.Mesh.visibility=0,await this.createCloudPoints();new BABYLON.HemisphericLight("light1",new BABYLON.Vector3(0,1,0),this.scene);this.engine?.resize()}createCamera(){let e=new(this.isWebVR?BABYLON.VRDeviceOrientationArcRotateCamera:BABYLON.ArcRotateCamera)("Camera",0,0,30,new BABYLON.Vector3(0,.5,0),this.scene);return e.setPosition(new BABYLON.Vector3(0,0,5)),e.beta=Math.PI/3,e.alpha=Math.PI/1.2,e.radius=15,e}async createCloudPoints(){this.pointsMesh=this.currentRole.Mesh,this.pointsCloud=new BABYLON.PointsCloudSystem("pcs",1,this.scene);let e=new BABYLON.Color3(.7,.8,1),t=new BABYLON.Color4(.7,.8,1),n=(new BABYLON.Color4(.2,.5,1),new BABYLON.Color4(0,0,.2,0),new BABYLON.Texture("/assets/avatar/particle/textures/flare.png",this.scene)),o=new BABYLON.PBRMaterial("material",this.scene);o.emissiveTexture=n,o.emissiveColor=e,this.pointsCloud.addVolumePoints(this.currentRole.Mesh,5e3,BABYLON.PointColor.Color,t),this.pointsCloud.buildMeshAsync().then((()=>{this.playAnimation("waiting")})),this.scene.registerAfterRender((()=>{this.pointsCloud.setParticles()})),this.engine.runRenderLoop((()=>{this.scene.render()}))}playAnimation(e){switch(e){case"waiting":this.cloudAnim();break;case"listening":this.cloudAnim({rotateSpeed:.01,breathing:!1});break;case"thinking":this.cloudAnim({rotateSpeed:.2,breathing:!1});break;case"talking":this.animMap.idle&&this.scene.beginDirectAnimation(this.pointsMesh,[this.animMap.talking],0,20,!0)}}cloudAnim(e={breathing:!0,rotateSpeed:.002}){this.animMap.idle&&this.scene.beginDirectAnimation(this.pointsMesh,[this.animMap.idle],0,120,!0);let t=new BABYLON.Color4(1,1,1,1),n=(new BABYLON.Texture("/assets/avatar/particle/textures/flare.png",this.scene),0);this.pointsCloud.updateParticle=o=>{let i=this.currentRole.Mesh.getBoundingInfo()?.boundingSphere?.radiusWorld,a=this.currentRole.Mesh.getBoundingInfo()?.boundingSphere?.centerWorld;o.idx;if(o.color=t,o.rotation.y+=e.rotateSpeed,o&&n<3&&(console.log(this.currentRole.Mesh.getBoundingInfo()),console.log(o),n++),o.initpos||(o.initpos=o.position),e.breathing){let e=o.initpos.subtract(a);o.position=new BABYLON.Vector3(e.x*i,e.y*i,e.z*i).add(this.currentRole.offsetPosition)}return o}}createSphere(){let e=BABYLON.MeshBuilder.CreateSphere("sphere",{diameter:2},this.scene);e.visibility=1,e.material=new BABYLON.StandardMaterial("mat",this.scene),e.material.wireframe=!0,e.scaling=new BABYLON.Vector3(1,1,1),this.pointsMesh=e;let t=new BABYLON.Animation("breathingAnimation","scaling",30,BABYLON.Animation.ANIMATIONTYPE_VECTOR3,BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE),n=[];n.push({frame:0,value:new BABYLON.Vector3(.3,.3,.3)}),n.push({frame:60,value:new BABYLON.Vector3(.5,.5,.5)}),n.push({frame:120,value:new BABYLON.Vector3(.3,.3,.3)}),t.setKeys(n),this.animMap.idle=t;let o=[{frame:0,value:BABYLON.Vector3.One()},{frame:10,value:new BABYLON.Vector3(1.2,.8,1.2)},{frame:20,value:BABYLON.Vector3.One()}],i=new BABYLON.Animation("talkAnimation","scaling",30,BABYLON.Animation.ANIMATIONTYPE_VECTOR3,BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);return i.setKeys(o),this.animMap.talk=i,this.scene.beginDirectAnimation(e,[this.animMap.idle],0,120,!0),e}async createParticle(){let e=this.createSphere(),t=new BABYLON.ParticleSystem("particles",2e3,this.scene);t.particleTexture=new BABYLON.Texture("/assets/avatar/particle/textures/flare.png",this.scene),t.emitter=e,t.minEmitBox=new BABYLON.Vector3(0,0,0),t.maxEmitBox=new BABYLON.Vector3(0,0,0),t.color1=new BABYLON.Color4(.7,.8,1,1),t.color2=new BABYLON.Color4(.2,.5,1,1),t.colorDead=new BABYLON.Color4(0,0,.2,0),t.minSize=.5,t.maxSize=.5,t.minLifeTime=.1,t.maxLifeTime=.1,t.minAngularSpeed=0,t.maxAngularSpeed=Math.PI,t.minInitialRotation=0,t.maxInitialRotation=Math.PI,t.minEmitPower=0,t.maxEmitPower=0,t.emitRate=1500,t.updateSpeed=.01,t.blendMode=BABYLON.ParticleSystem.BLENDMODE_ONEONE,t.direction1=new BABYLON.Vector3(0,0,0),t.direction2=new BABYLON.Vector3(0,0,0),t.start();let n=t.createSphereEmitter();n.radius=2,n.radiusRange=0,n.directionRandomizer=0,t.gravity=new BABYLON.Vector3(0,0,0),t.disposeOnStop=!0,t.updateFunction=n=>{for(let o=0;o<n.length;o++){let i=n[o],a=e.getBoundingInfo()?.boundingSphere?.radiusWorld;i.position=i.position.normalize().scale(a),i.age+=this.scene.getEngine().getDeltaTime()/1e3,i.age>=i.lifeTime&&(t.recycleParticle(i),o--)}},this.engine.runRenderLoop((()=>{this.scene.render(),t.worldOffset=e.position}))}setCameraToMeshCenter(e,t){t.computeWorldMatrix(!0);let n=t.getBoundingInfo(),o=n.minimum,i=n.maximum,a=i.x-o.x,r=i.y-o.y,s=i.z-o.z,l=n.boundingBox.center;console.log("宽度:"+a),console.log("高度:"+r),console.log("深度:"+s),console.log("中心点:"+l)}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarParticleComponent,deps:[{token:i0.ElementRef}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:CompAvatarParticleComponent,isStandalone:!0,selector:"fm-avatar-role-particle",viewQueries:[{propertyName:"renderCanvas",first:!0,predicate:["renderCanvas"],descendants:!0}],ngImport:i0,template:'<canvas #renderCanvas class="render-canvas"></canvas>',styles:[".render-canvas{display:block;width:100%;height:100%;touch-action:none}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"ngmodule",type:FormsModule}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarParticleComponent,decorators:[{type:Component,args:[{selector:"fm-avatar-role-particle",standalone:!0,imports:[CommonModule,FormsModule],template:'<canvas #renderCanvas class="render-canvas"></canvas>',styles:[".render-canvas{display:block;width:100%;height:100%;touch-action:none}\n"]}]}],ctorParameters:()=>[{type:i0.ElementRef}],propDecorators:{renderCanvas:[{type:ViewChild,args:["renderCanvas"]}]}});class CompAvatarRoleImageComponent{constructor(){this.animClass="waiting",this.imageMap={}}playWave(){!this.wave&&Recorder.WaveView&&(this.wave=Recorder.WaveView({elem:".record-wave-avatar",keep:!1}));let e=function generatePowerLevel(){return 100*Math.random()}();this.waveInterval=setInterval((()=>{let t=function generateSampleRate(){const e=[44100,48e3,88200,96e3];return e[Math.floor(Math.random()*e.length)]}(),n=function generatePcmData(e){const t=[];for(let n=0;n<e;n++)t.push(Math.floor(65536*Math.random())-32768);return t}(1e3);this.wave.input(n,e,t)}),40)}stopWave(){clearInterval(this.waveInterval)}ngAfterViewInit(){}ngOnInit(){setTimeout((()=>{this.imageMap=this.fmodeChat.avatarConfig?.image,this.avatarImage.nativeElement.src=this.imageMap?.waiting,this.fmodeChat.playAnimation=this.playAnimation}),1500)}playAnimation(){let e=this;return t=>{let n=e.avatarImage.nativeElement;switch(e.animClass=t,e.stopWave(),t){case"thinking":case"waiting":n.style.animationPlayState="running";break;case"talking":n.style.animationPlayState="running",e.playWave();break;case"listening":n.style.animationPlayState="pause";break;default:n.style.animationPlayState="paused"}}}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarRoleImageComponent,deps:[],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:CompAvatarRoleImageComponent,isStandalone:!0,selector:"fm-avatar-role-image",inputs:{fmodeChat:"fmodeChat",role:"role"},viewQueries:[{propertyName:"avatarImage",first:!0,predicate:["avatarImage"],descendants:!0}],ngImport:i0,template:'<div class="page">\n <div class="avatar" [class]="animClass">\n <div class="avatar-photo">\n <img #avatarImage alt="">\n \x3c!-- 音频波动 --\x3e\n <div class="record-wave-avatar">\n </div>\n </div>\n </div>\n</div>',styles:[".page{position:relative;width:100vw;height:100%;top:0;left:0;display:flex;justify-content:center;align-items:center;background-color:#000}.avatar{width:100%;display:flex;justify-content:center;align-items:center}.avatar .avatar-photo{position:relative;margin-top:-10vh;width:80%}.avatar .avatar-photo img{border-radius:10px}.avatar .record-wave-avatar{height:50px;width:100%;position:absolute;float:left;left:0;bottom:0}.thinking,.listening,.waiting,.talking{animation-duration:2s;animation-play-state:running;animation-iteration-count:infinite;animation-timing-function:ease-in-out}@keyframes waitingAnimation{0%{transform:scale(1)}50%{transform:scale(1.05)}to{transform:scale(1)}}@keyframes thinkingAnimation{0%{transform:rotate(0)}30%{transform:rotate(10deg)}60%{transform:rotate(-10deg)}to{transform:rotate(0)}}.thinking{animation-name:thinkingAnimation}.waiting{animation-name:waitingAnimation}.listening{animation-name:listeningAnimation}.talking{animation-name:talkingAnimation}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"ngmodule",type:FormsModule}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarRoleImageComponent,decorators:[{type:Component,args:[{selector:"fm-avatar-role-image",standalone:!0,imports:[CommonModule,FormsModule],template:'<div class="page">\n <div class="avatar" [class]="animClass">\n <div class="avatar-photo">\n <img #avatarImage alt="">\n \x3c!-- 音频波动 --\x3e\n <div class="record-wave-avatar">\n </div>\n </div>\n </div>\n</div>',styles:[".page{position:relative;width:100vw;height:100%;top:0;left:0;display:flex;justify-content:center;align-items:center;background-color:#000}.avatar{width:100%;display:flex;justify-content:center;align-items:center}.avatar .avatar-photo{position:relative;margin-top:-10vh;width:80%}.avatar .avatar-photo img{border-radius:10px}.avatar .record-wave-avatar{height:50px;width:100%;position:absolute;float:left;left:0;bottom:0}.thinking,.listening,.waiting,.talking{animation-duration:2s;animation-play-state:running;animation-iteration-count:infinite;animation-timing-function:ease-in-out}@keyframes waitingAnimation{0%{transform:scale(1)}50%{transform:scale(1.05)}to{transform:scale(1)}}@keyframes thinkingAnimation{0%{transform:rotate(0)}30%{transform:rotate(10deg)}60%{transform:rotate(-10deg)}to{transform:rotate(0)}}.thinking{animation-name:thinkingAnimation}.waiting{animation-name:waitingAnimation}.listening{animation-name:listeningAnimation}.talking{animation-name:talkingAnimation}\n"]}]}],propDecorators:{avatarImage:[{type:ViewChild,args:["avatarImage"]}],fmodeChat:[{type:Input}],role:[{type:Input}]}});class ModalChatVoiceInputComponent{constructor(e,t,n,o,i,a){this.platform=e,this.router=t,this.voiceServ=n,this.toastCtrl=o,this.ncloud=i,this.chatServ=a,this.talkMode="click",this.talkTips="点击话筒开始讲话",this.errorText="",this.player=new Audio}ngOnInit(){"press"==this.talkMode&&(this.talkTips="轻触底部开始讲话"),setTimeout((()=>{this.initVoiceSevice(),this.initVoiceASR()}),500)}async initVoiceASR(){this.voiceServ.requestPermission().then((()=>{this.voiceServ.openWithPriviledge(),this.startASRAwake()}))}async startASRAwake(){await this.voiceServ.openWithPriviledge(),new this.voiceServ.webSpeech(this.platform).startRecognition("Nihao | Hello")}playMusic(e){this.player.src=`/assets/avatar/voice/${e}.mp3`,this.player.play()}initVoiceSevice(){this.fmodeChat.userInput=this.voiceServ.resultText,this.voiceServ.requestPermission().then((()=>{this.voiceServ.openWithPriviledge()})),this.voiceServ.onBeforeStartTalk=()=>{this.fmodeChat.playAnimation("listening"),this.playMusic("start-talk")},this.voiceServ.onBeforeCancelTalk=()=>{this.playMusic("interupt-talk"),this.fmodeChat.playAnimation("waiting")},this.voiceServ.onAfterCancelTalk=()=>{this.startASRAwake()},this.voiceServ.onBeforeFinishTalk=()=>{this.fmodeChat.playAnimation("thinking"),this.playMusic("stop-talk")},this.voiceServ.onAfterFinishTalk=()=>{console.log("onAfterFinishTalk"),this.fmodeChat.userInput=this.voiceServ?.resultText,this.sendMessage(),this.startASRAwake()}}async sendMessage(){if(!this.fmodeChat.userInput){return this.errorText="内容不能为空",void(await this.toastCtrl.create({message:this.errorText,position:"top",icon:"alert",color:"warning-circle",duration:1e3})).present()}this.fmodeChat?.sendMessage(this.voiceServ.resultText,null,(e=>{}),{onSSMLComplete:e=>{console.log(e);e.ssml;this.fmodeChat.playTTS(e),this.fmodeChat.playAnimation("talking"),setTimeout((()=>{this.fmodeChat.playAnimation("waiting")}),6e3)}}),this.fmodeChat.userInput="",this.fmodeChat.userImage=""}testTTS(e){console.log(e),e=e||"你好呀,我是飞马小智!很高兴为您介绍脑控科技的发展历程。我们成立于2019年",new this.voiceServ.webSpeech(this.platform).speak(e)}testXunfeiTTS(){}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ModalChatVoiceInputComponent,deps:[{token:i2.Platform},{token:i1$1.Router},{token:FmodeVoiceService},{token:i2.ToastController},{token:NovaCloudService},{token:ChatService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:ModalChatVoiceInputComponent,isStandalone:!0,selector:"fm-modal-chat-voice-input",inputs:{fmodeChat:"fmodeChat",talkMode:"talkMode"},providers:[FmodeVoiceService],ngImport:i0,template:' \n <ng-container *ngIf="fmodeChat">\n\n \x3c!-- 用户输入 提示区域 --\x3e\n <div class="user-asr-input" style="text-align: center;" *ngIf="!fmodeChat?.userInput && voiceServ.btnStatus!=\'OPEN\'">{{talkTips}}</div>\n <div class="user-asr-input">{{fmodeChat?.userInput}}</div>\n \n \x3c!-- 测试按钮 --\x3e\n <div class="test-button-group" *ngIf="false">\n <button class="button-record" (click)="voiceServ.toggleRecord()">开始录制 {{voiceServ.connStatus}} {{voiceServ.btnStatus}}</button>\n <br>\n <button class="button-record" (click)="voiceServ.playRecord()">播放录制结果</button>\n <br>\n <button class="button-record" (click)="voiceServ.playBuffers()">播放Buffers结果</button>\n <button (click)="testTTS()">测试TTS纯WEB</button>\n <button (click)="startASR()">测试ASR</button> \n <button (click)="testXunfeiTTS()">测试合成</button> \n </div>\n\n \n \n \x3c!-- 交互按钮 --\x3e\n <ion-fab slot="fixed" horizontal="center" vertical="bottom">\n <ng-container *ngIf="talkMode==\'click\'">\n \x3c!-- 默认按钮:开始讲话 --\x3e\n <ion-fab-button color="primary" closeIcon="checkmark" (click)="voiceServ.toggleRecord()">\n <ion-icon name="mic-outline"></ion-icon>\n </ion-fab-button>\n\n \x3c!-- 讲话中:取消发送 --\x3e\n <ion-fab-list side="end">\n <ion-fab-button [class]="\'loading\'" (click)="voiceServ.cancelTalk()">\n <ion-icon name="pause-outline"></ion-icon>\n </ion-fab-button>\n </ion-fab-list>\n </ng-container>\n \n <ng-container *ngIf="talkMode==\'press\'">\n <ion-fab-button color="primary" closeIcon="mic-outline" (touchstart)="voiceServ.toggleRecord()" (touchend)="voiceServ.cancelTalk()">\n <ion-icon name="mic-outline"></ion-icon>\n </ion-fab-button>\n </ng-container>\n </ion-fab>\n\n\n \x3c!-- 音频波动 --\x3e\n <div class="record-wave">\n </div>\n</ng-container>\n',styles:['ion-fab{margin-bottom:10vh}.fab-button-close-active:before{content:"";position:absolute;top:-5px;left:-5px;width:66px;height:66px;border-radius:50%;border:5px solid #fff;border-top-color:transparent;animation:spin 2s ease-in-out infinite;animation-fill-mode:both;animation-play-state:running}.record-wave{position:fixed;bottom:0;width:100vw;height:6vh}\n'],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"ngmodule",type:IonicModule},{kind:"component",type:i2.IonFab,selector:"ion-fab",inputs:["activated","edge","horizontal","vertical"]},{kind:"component",type:i2.IonFabButton,selector:"ion-fab-button",inputs:["activated","closeIcon","color","disabled","download","href","mode","rel","routerAnimation","routerDirection","show","size","target","translucent","type"]},{kind:"component",type:i2.IonFabList,selector:"ion-fab-list",inputs:["activated","side"]},{kind:"component",type:i2.IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"ngmodule",type:RouterModule}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ModalChatVoiceInputComponent,decorators:[{type:Component,args:[{selector:"fm-modal-chat-voice-input",standalone:!0,imports:[CommonModule,IonicModule,RouterModule],providers:[FmodeVoiceService],template:' \n <ng-container *ngIf="fmodeChat">\n\n \x3c!-- 用户输入 提示区域 --\x3e\n <div class="user-asr-input" style="text-align: center;" *ngIf="!fmodeChat?.userInput && voiceServ.btnStatus!=\'OPEN\'">{{talkTips}}</div>\n <div class="user-asr-input">{{fmodeChat?.userInput}}</div>\n \n \x3c!-- 测试按钮 --\x3e\n <div class="test-button-group" *ngIf="false">\n <button class="button-record" (click)="voiceServ.toggleRecord()">开始录制 {{voiceServ.connStatus}} {{voiceServ.btnStatus}}</button>\n <br>\n <button class="button-record" (click)="voiceServ.playRecord()">播放录制结果</button>\n <br>\n <button class="button-record" (click)="voiceServ.playBuffers()">播放Buffers结果</button>\n <button (click)="testTTS()">测试TTS纯WEB</button>\n <button (click)="startASR()">测试ASR</button> \n <button (click)="testXunfeiTTS()">测试合成</button> \n </div>\n\n \n \n \x3c!-- 交互按钮 --\x3e\n <ion-fab slot="fixed" horizontal="center" vertical="bottom">\n <ng-container *ngIf="talkMode==\'click\'">\n \x3c!-- 默认按钮:开始讲话 --\x3e\n <ion-fab-button color="primary" closeIcon="checkmark" (click)="voiceServ.toggleRecord()">\n <ion-icon name="mic-outline"></ion-icon>\n </ion-fab-button>\n\n \x3c!-- 讲话中:取消发送 --\x3e\n <ion-fab-list side="end">\n <ion-fab-button [class]="\'loading\'" (click)="voiceServ.cancelTalk()">\n <ion-icon name="pause-outline"></ion-icon>\n </ion-fab-button>\n </ion-fab-list>\n </ng-container>\n \n <ng-container *ngIf="talkMode==\'press\'">\n <ion-fab-button color="primary" closeIcon="mic-outline" (touchstart)="voiceServ.toggleRecord()" (touchend)="voiceServ.cancelTalk()">\n <ion-icon name="mic-outline"></ion-icon>\n </ion-fab-button>\n </ng-container>\n </ion-fab>\n\n\n \x3c!-- 音频波动 --\x3e\n <div class="record-wave">\n </div>\n</ng-container>\n',styles:['ion-fab{margin-bottom:10vh}.fab-button-close-active:before{content:"";position:absolute;top:-5px;left:-5px;width:66px;height:66px;border-radius:50%;border:5px solid #fff;border-top-color:transparent;animation:spin 2s ease-in-out infinite;animation-fill-mode:both;animation-play-state:running}.record-wave{position:fixed;bottom:0;width:100vw;height:6vh}\n']}]}],ctorParameters:()=>[{type:i2.Platform},{type:i1$1.Router},{type:FmodeVoiceService},{type:i2.ToastController},{type:NovaCloudService},{type:ChatService}],propDecorators:{fmodeChat:[{type:Input}],talkMode:[{type:Input}]}});class CompAvatarTalkComponent{constructor(e,t,n,o,i,a,r){this.voiceServ=e,this.platform=t,this.router=n,this.navCtrl=o,this.route=i,this.chatServ=a,this.ncloud=r,this.route.paramMap.subscribe((e=>{this.roleId=e.get("roleId"),this.loadAvatarRole(this.roleId)})),document.body.classList.add("dark")}ngOnInit(){}ngOnDestroy(){document.body.classList.remove("dark"),this.voiceServ.resultText=null,this.fmodeChat&&(this.fmodeChat.latestAIResponse=null)}goBack(){document.body.classList.remove("dark");let e=this.avatarRole?.get("backUrl");try{if(e)return void this.navCtrl.navigateRoot(e);this.navCtrl.navigateRoot("/chat/pro/role/"+this.roleId)}catch(e){this.navCtrl.navigateRoot("/chat/pro/role/"+this.roleId)}}async loadAvatarRole(e){let t=new Parse.Query("AvatarRole");this.avatarRole=await t.get(e);let n=await this.chatServ.createNewRoleChat(this.roleId);n.isTalkMode=!0,this.fmodeChat=n,this.fmodeChat.showAvatar()}ngAfterViewInit(){this.listenDivChange()}listenDivChange(){new MutationObserver((()=>{this.scrollToBottom(this.aiRespComp)})).observe(this.aiRespComp.nativeElement,{childList:!0,subtree:!0,attributes:!0})}scrollToBottom(e){e?.nativeElement?.scrollHeight&&(e.nativeElement.scrollTop=e.nativeElement.scrollHeight)}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarTalkComponent,deps:[{token:FmodeVoiceService},{token:i2.Platform},{token:i1$1.Router},{token:i2.NavController},{token:i1$1.ActivatedRoute},{token:ChatService},{token:NovaCloudService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:CompAvatarTalkComponent,isStandalone:!0,selector:"app-comp-avatar-talk",providers:[FmodeVoiceService,NovaCloudService,ChatService,Diagnostic,ModalController],viewQueries:[{propertyName:"avatarComp",first:!0,predicate:["avatar"],descendants:!0},{propertyName:"aiRespComp",first:!0,predicate:["aiRespComp"],descendants:!0}],ngImport:i0,template:'<ion-menu #menu contentId="main-content" side="end">\n <ion-header>\n <ion-toolbar>\n <ion-title>资料</ion-title>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n\n <ion-card style="margin: 0px;">\n <img [src]="avatarRole?.get(\'thumb\')" alt="">\n <ion-card-header>\n <ion-card-subtitle>{{avatarRole?.get(\'tags\')}}</ion-card-subtitle>\n <ion-card-title>{{avatarRole?.get("name")}}</ion-card-title>\n </ion-card-header>\n \n <ion-card-content>\n {{avatarRole?.get("desc")}}\n\n <ion-list [inset]="true" style="margin:0px;">\n \x3c!-- <ion-item>\n <ion-avatar *ngIf="avatarRole?.get(\'thumb\')" aria-hidden="true" slot="start">\n <img [src]="avatarRole?.get(\'thumb\')" />\n </ion-avatar>\n <ion-label>{{avatarRole?.get("name")}}</ion-label>\n </ion-item> --\x3e\n <ion-item lines="none" *ngIf="avatarRole?.get(\'age\')">\n <ion-note slot="start">年龄</ion-note>\n <ion-label>{{avatarRole?.get("age")}}</ion-label>\n </ion-item>\n <ion-item lines="none" *ngIf="avatarRole?.get(\'gender\')">\n <ion-note slot="start">性别</ion-note>\n <ion-label>{{avatarRole?.get("gender")}}</ion-label>\n </ion-item>\n <ion-item lines="none">\n <ion-note slot="start">称号</ion-note>\n <ion-label>{{avatarRole?.get("title")}}</ion-label>\n </ion-item>\n \n <ion-item lines="none">\n <ion-note slot="start">擅长</ion-note>\n <ion-label>{{avatarRole?.get("tags")?.join(\',\')}}</ion-label>\n </ion-item>\n\n </ion-list>\n </ion-card-content>\n </ion-card>\n \n \n \n </ion-content>\n</ion-menu>\n\n<div class="ion-page" id="main-content">\n <ion-header class="ion-no-border">\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="goBack()"> <ion-icon name="chevron-back-outline"></ion-icon> </ion-button>\n </ion-buttons>\n <ion-title>\n <ion-chip *ngIf="avatarRole?.get(\'title\')">{{avatarRole?.get("title")}}</ion-chip>\n </ion-title>\n <ion-buttons slot="end">\n \x3c!-- <ion-button (click)="playTTSTeting()">TTS测试</ion-button> --\x3e\n {{avatarRole?.get("name")}}\n <ion-button (click)="menu.toggle()"> <ion-icon name="ellipsis-horizontal-outline"></ion-icon> </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n\n \x3c!-- <ion-segment value="voice">\n <ion-segment-button (click)="chatServ.createChatPanel(avatarRole)" value="chat">\n <ion-label>聊天</ion-label>\n </ion-segment-button>\n <ion-segment-button routerLink="{{\'/avatar/role/\'+avatarRole?.id}}" value="voice">\n <ion-label>语音</ion-label>\n </ion-segment-button>\n </ion-segment> --\x3e\n\n \x3c!-- 数字形象:动画效果 --\x3e\n <fm-avatar-role-image *ngIf="avatarRole&&fmodeChat" [fmodeChat]="fmodeChat" [role]="avatarRole" #avatar class="avatar"></fm-avatar-role-image>\n \x3c!-- <fm-avatar-role-particle #avatar class="avatar"></fm-avatar-role-particle> --\x3e\n\n \x3c!-- AI回复的最新消息 --\x3e\n <div class="ai-resp-input" #aiRespComp>{{fmodeChat?.latestAIResponse | hidexml}}</div>\n\n <fm-modal-chat-voice-input *ngIf="fmodeChat" [fmodeChat]="fmodeChat"></fm-modal-chat-voice-input>\n\n</div>\n\n',styles:["ion-menu ion-note{color:#ccc;font-weight:700}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.avatar{display:block;width:100%;height:100%}.ai-resp-input{font-size:1rem;color:#fff;position:fixed;top:60px;max-height:15vh;overflow-y:scroll;padding:0 10px}.user-asr-input{font-size:1rem;color:#fff;position:fixed;bottom:6vh;padding:0 10px}.test-button-group{color:#00f;position:fixed;bottom:20vh}.test-button-group button{padding:10px;margin:10px}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"ngmodule",type:RouterModule},{kind:"ngmodule",type:FormsModule},{kind:"ngmodule",type:IonicModule},{kind:"component",type:i2.IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:i2.IonButtons,selector:"ion-buttons",inputs:["collapse"]},{kind:"component",type:i2.IonCard,selector:"ion-card",inputs:["button","color","disabled","download","href","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:i2.IonCardContent,selector:"ion-card-content",inputs:["mode"]},{kind:"component",type:i2.IonCardHeader,selector:"ion-card-header",inputs:["color","mode","translucent"]},{kind:"component",type:i2.IonCardSubtitle,selector:"ion-card-subtitle",inputs:["color","mode"]},{kind:"component",type:i2.IonCardTitle,selector:"ion-card-title",inputs:["color","mode"]},{kind:"component",type:i2.IonChip,selector:"ion-chip",inputs:["color","disabled","mode","outline"]},{kind:"component",type:i2.IonContent,selector:"ion-content",inputs:["color","fixedSlotPlacement","forceOverscroll","fullscreen","scrollEvents","scrollX","scrollY"]},{kind:"component",type:i2.IonHeader,selector:"ion-header",inputs:["collapse","mode","translucent"]},{kind:"component",type:i2.IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:i2.IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:i2.IonLabel,selector:"ion-label",inputs:["color","mode","position"]},{kind:"component",type:i2.IonList,selector:"ion-list",inputs:["inset","lines","mode"]},{kind:"component",type:i2.IonMenu,selector:"ion-menu",inputs:["contentId","disabled","maxEdgeStart","menuId","side","swipeGesture","type"]},{kind:"component",type:i2.IonNote,selector:"ion-note",inputs:["color","mode"]},{kind:"component",type:i2.IonTitle,selector:"ion-title",inputs:["color","size"]},{kind:"component",type:i2.IonToolbar,selector:"ion-toolbar",inputs:["color","mode"]},{kind:"component",type:CompAvatarRoleImageComponent,selector:"fm-avatar-role-image",inputs:["fmodeChat","role"]},{kind:"component",type:ModalChatVoiceInputComponent,selector:"fm-modal-chat-voice-input",inputs:["fmodeChat","talkMode"]},{kind:"pipe",type:HidexmlPipe,name:"hidexml"}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarTalkComponent,decorators:[{type:Component,args:[{selector:"app-comp-avatar-talk",standalone:!0,imports:[CommonModule,RouterModule,FormsModule,IonicModule,CompAvatarParticleComponent,CompAvatarRoleImageComponent,ModalChatVoiceInputComponent,HidexmlPipe],providers:[FmodeVoiceService,NovaCloudService,ChatService,Diagnostic,ModalController],template:'<ion-menu #menu contentId="main-content" side="end">\n <ion-header>\n <ion-toolbar>\n <ion-title>资料</ion-title>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n\n <ion-card style="margin: 0px;">\n <img [src]="avatarRole?.get(\'thumb\')" alt="">\n <ion-card-header>\n <ion-card-subtitle>{{avatarRole?.get(\'tags\')}}</ion-card-subtitle>\n <ion-card-title>{{avatarRole?.get("name")}}</ion-card-title>\n </ion-card-header>\n \n <ion-card-content>\n {{avatarRole?.get("desc")}}\n\n <ion-list [inset]="true" style="margin:0px;">\n \x3c!-- <ion-item>\n <ion-avatar *ngIf="avatarRole?.get(\'thumb\')" aria-hidden="true" slot="start">\n <img [src]="avatarRole?.get(\'thumb\')" />\n </ion-avatar>\n <ion-label>{{avatarRole?.get("name")}}</ion-label>\n </ion-item> --\x3e\n <ion-item lines="none" *ngIf="avatarRole?.get(\'age\')">\n <ion-note slot="start">年龄</ion-note>\n <ion-label>{{avatarRole?.get("age")}}</ion-label>\n </ion-item>\n <ion-item lines="none" *ngIf="avatarRole?.get(\'gender\')">\n <ion-note slot="start">性别</ion-note>\n <ion-label>{{avatarRole?.get("gender")}}</ion-label>\n </ion-item>\n <ion-item lines="none">\n <ion-note slot="start">称号</ion-note>\n <ion-label>{{avatarRole?.get("title")}}</ion-label>\n </ion-item>\n \n <ion-item lines="none">\n <ion-note slot="start">擅长</ion-note>\n <ion-label>{{avatarRole?.get("tags")?.join(\',\')}}</ion-label>\n </ion-item>\n\n </ion-list>\n </ion-card-content>\n </ion-card>\n \n \n \n </ion-content>\n</ion-menu>\n\n<div class="ion-page" id="main-content">\n <ion-header class="ion-no-border">\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="goBack()"> <ion-icon name="chevron-back-outline"></ion-icon> </ion-button>\n </ion-buttons>\n <ion-title>\n <ion-chip *ngIf="avatarRole?.get(\'title\')">{{avatarRole?.get("title")}}</ion-chip>\n </ion-title>\n <ion-buttons slot="end">\n \x3c!-- <ion-button (click)="playTTSTeting()">TTS测试</ion-button> --\x3e\n {{avatarRole?.get("name")}}\n <ion-button (click)="menu.toggle()"> <ion-icon name="ellipsis-horizontal-outline"></ion-icon> </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n\n \x3c!-- <ion-segment value="voice">\n <ion-segment-button (click)="chatServ.createChatPanel(avatarRole)" value="chat">\n <ion-label>聊天</ion-label>\n </ion-segment-button>\n <ion-segment-button routerLink="{{\'/avatar/role/\'+avatarRole?.id}}" value="voice">\n <ion-label>语音</ion-label>\n </ion-segment-button>\n </ion-segment> --\x3e\n\n \x3c!-- 数字形象:动画效果 --\x3e\n <fm-avatar-role-image *ngIf="avatarRole&&fmodeChat" [fmodeChat]="fmodeChat" [role]="avatarRole" #avatar class="avatar"></fm-avatar-role-image>\n \x3c!-- <fm-avatar-role-particle #avatar class="avatar"></fm-avatar-role-particle> --\x3e\n\n \x3c!-- AI回复的最新消息 --\x3e\n <div class="ai-resp-input" #aiRespComp>{{fmodeChat?.latestAIResponse | hidexml}}</div>\n\n <fm-modal-chat-voice-input *ngIf="fmodeChat" [fmodeChat]="fmodeChat"></fm-modal-chat-voice-input>\n\n</div>\n\n',styles:["ion-menu ion-note{color:#ccc;font-weight:700}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.avatar{display:block;width:100%;height:100%}.ai-resp-input{font-size:1rem;color:#fff;position:fixed;top:60px;max-height:15vh;overflow-y:scroll;padding:0 10px}.user-asr-input{font-size:1rem;color:#fff;position:fixed;bottom:6vh;padding:0 10px}.test-button-group{color:#00f;position:fixed;bottom:20vh}.test-button-group button{padding:10px;margin:10px}\n"]}]}],ctorParameters:()=>[{type:FmodeVoiceService},{type:i2.Platform},{type:i1$1.Router},{type:i2.NavController},{type:i1$1.ActivatedRoute},{type:ChatService},{type:NovaCloudService}],propDecorators:{avatarComp:[{type:ViewChild,args:["avatar"]}],aiRespComp:[{type:ViewChild,args:["aiRespComp"]}]}});const AvatarRoutes=[{path:"role/:roleId",component:CompAvatarTalkComponent,runGuardsAndResolvers:"always"}];class AvatarModule{static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AvatarModule,deps:[],target:i0.ɵɵFactoryTarget.NgModule})}static{this.ɵmod=i0.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:AvatarModule,imports:[CommonModule,FormsModule,HttpClientModule,ReactiveFormsModule,i1$1.RouterModule,CompAvatarTalkComponent],exports:[CompAvatarTalkComponent]})}static{this.ɵinj=i0.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AvatarModule,imports:[CommonModule,FormsModule,HttpClientModule,ReactiveFormsModule,RouterModule.forChild(AvatarRoutes),CompAvatarTalkComponent]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AvatarModule,decorators:[{type:NgModule,args:[{declarations:[],imports:[CommonModule,FormsModule,HttpClientModule,ReactiveFormsModule,RouterModule.forChild(AvatarRoutes),CompAvatarTalkComponent],exports:[CompAvatarTalkComponent]}]}]});class CompAvatarRoleVideoComponent{constructor(){this.animClass="waiting",this.videoMap={}}playWave(){!this.wave&&Recorder.WaveView&&(this.wave=Recorder.WaveView({elem:".record-wave-avatar",keep:!1}));let e=function generatePowerLevel(){return 100*Math.random()}();this.waveInterval=setInterval((()=>{let t=function generateSampleRate(){const e=[44100,48e3,88200,96e3];return e[Math.floor(Math.random()*e.length)]}(),n=function generatePcmData(e){const t=[];for(let n=0;n<e;n++)t.push(Math.floor(65536*Math.random())-32768);return t}(1e3);this.wave.input(n,e,t)}),40)}stopWave(){clearInterval(this.waveInterval)}ngAfterViewInit(){}ngOnInit(){setTimeout((()=>{this.videoMap=this.fmodeChat.avatarConfig?.video,this.playVideo(this.videoMap?.waiting),this.fmodeChat.playAnimation=this.playAnimation}),1500)}playAnimation(){let e=this;return t=>{let n=e.avatarVideo.nativeElement;switch(e.animClass=t,e.stopWave(),e.playVideo(e.videoMap[t]),t){case"thinking":case"waiting":n.style.animationPlayState="running";break;case"talking":n.style.animationPlayState="running",e.playWave();break;case"listening":n.style.animationPlayState="pause";break;default:n.style.animationPlayState="paused"}}}playVideo(e){this.avatarVideo.nativeElement.autoplay=!0,this.avatarVideo.nativeElement.loop=!0,this.avatarVideo.nativeElement.controls=!1,this.avatarVideo.nativeElement.src=e,this.avatarVideo.nativeElement.play()}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarRoleVideoComponent,deps:[],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:CompAvatarRoleVideoComponent,isStandalone:!0,selector:"fm-avatar-role-video",inputs:{fmodeChat:"fmodeChat",role:"role"},viewQueries:[{propertyName:"avatarVideo",first:!0,predicate:["avatarVideo"],descendants:!0}],ngImport:i0,template:'<div class="page">\n <div class="avatar" [class]="animClass">\n <div class="avatar-photo">\n <video #avatarVideo alt=""></video>\n \x3c!-- 音频波动 --\x3e\n <div class="record-wave-avatar">\n </div>\n </div>\n </div>\n</div>',styles:[".page{position:relative;width:100vw;height:100%;top:0;left:0;display:flex;justify-content:center;align-items:center;background-color:#000}.avatar{height:100%;width:100%;display:flex;justify-content:center;align-items:center}.avatar .avatar-photo{position:relative;display:flex;justify-content:center;width:80%;max-height:100%}.avatar .avatar-photo video{border-radius:50%;max-height:100%;max-width:100%}.avatar .record-wave-avatar{height:50px;width:100%;position:absolute;float:left;left:0;bottom:0}.thinking,.listening,.waiting,.talking{animation-duration:2s;animation-play-state:running;animation-iteration-count:infinite;animation-timing-function:ease-in-out}@keyframes waitingAnimation{0%{transform:scale(1)}50%{transform:scale(1.05)}to{transform:scale(1)}}@keyframes thinkingAnimation{0%{transform:rotate(0)}30%{transform:rotate(10deg)}60%{transform:rotate(-10deg)}to{transform:rotate(0)}}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"ngmodule",type:FormsModule}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarRoleVideoComponent,decorators:[{type:Component,args:[{selector:"fm-avatar-role-video",standalone:!0,imports:[CommonModule,FormsModule],template:'<div class="page">\n <div class="avatar" [class]="animClass">\n <div class="avatar-photo">\n <video #avatarVideo alt=""></video>\n \x3c!-- 音频波动 --\x3e\n <div class="record-wave-avatar">\n </div>\n </div>\n </div>\n</div>',styles:[".page{position:relative;width:100vw;height:100%;top:0;left:0;display:flex;justify-content:center;align-items:center;background-color:#000}.avatar{height:100%;width:100%;display:flex;justify-content:center;align-items:center}.avatar .avatar-photo{position:relative;display:flex;justify-content:center;width:80%;max-height:100%}.avatar .avatar-photo video{border-radius:50%;max-height:100%;max-width:100%}.avatar .record-wave-avatar{height:50px;width:100%;position:absolute;float:left;left:0;bottom:0}.thinking,.listening,.waiting,.talking{animation-duration:2s;animation-play-state:running;animation-iteration-count:infinite;animation-timing-function:ease-in-out}@keyframes waitingAnimation{0%{transform:scale(1)}50%{transform:scale(1.05)}to{transform:scale(1)}}@keyframes thinkingAnimation{0%{transform:rotate(0)}30%{transform:rotate(10deg)}60%{transform:rotate(-10deg)}to{transform:rotate(0)}}\n"]}]}],propDecorators:{avatarVideo:[{type:ViewChild,args:["avatarVideo"]}],fmodeChat:[{type:Input}],role:[{type:Input}]}});class ChatListComponent{constructor(e,t,n){this.chatServ=e,this.alertCtrl=t,this.navCtrl=n,this.chatList=[],this.onItemClick=e=>{this.goSession(e)},this.avatar="https://ionicframework.com/docs/img/demos/avatar.svg",this.isPreventGo=!1,this.chatServ.getChatSession().then((()=>{}))}async goSession(e){if(!this.isPreventGo)if(e?.rid||e?.sid)this.chatServ.restoreChatPanel(e);else{(await this.alertCtrl.create({header:"注意",subHeader:"请您选择右侧角色",message:"开始对话",buttons:[{role:"ok",text:"知道了",handler:()=>{}}]})).present(),this.navCtrl.navigateRoot("/chat/pro/mask")}}async presentEditTitle(e,t,n){this.isPreventGo=!0,setTimeout((()=>{this.isPreventGo=!1}),500),n.preventDefault();const o=await this.alertCtrl.create({header:"修改会话标题",subHeader:"",message:"",buttons:[{text:"取消",role:"cancel",handler:()=>{}},{text:"确定",role:"confirm",handler:n=>{t.title=n.title,e?.set("title",n.title),e?.save()}}],inputs:[{placeholder:"会话标题",name:"title",value:t?.title||""}]});await o.present()}async presentDeleteTItle(e,t,n){this.isPreventGo=!0,setTimeout((()=>{this.isPreventGo=!1}),500),n.preventDefault();const o=await this.alertCtrl.create({header:"确认删除?",subHeader:"",message:"",buttons:[{text:"取消",role:"cancel",handler:()=>{}},{text:"确定",role:"confirm",handler:()=>{t.isHidden=!0,e?.set("isDeleted",!0),e?.save()}}]});await o.present()}truncateString(e){return e&&e.length>10?e.slice(0,10)+"...":e}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatListComponent,deps:[{token:ChatService},{token:i2$3.AlertController},{token:i2$3.NavController}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:ChatListComponent,isStandalone:!0,selector:"app-chat-list",inputs:{onItemClick:"onItemClick"},ngImport:i0,template:'<ion-list>\n <ng-container *ngFor="let chat of (chatServ?.chatList || chatList)">\n <ion-item [button]="true" detail="false" *ngIf="!chat?.isHidden" (click)="onItemClick(chat)">\n <div class="unread-indicator-wrapper" slot="start">\n <div class="unread-indicator"></div>\n </div>\n <ion-label>\n <div style="display: flex;justify-content: space-between; align-items: center;">\n <div style="display: flex; flex-direction: row;align-items: center;">\n <strong style="display: flex;align-items: center;">\n <ion-avatar style="margin-right: 10px;">\n <img [src]="chat?.thumb||avatar" />\n </ion-avatar>\n <p style="max-width: 7rem;white-space: nowrap;">{{truncateString(chat?.title)}}</p>\n </strong>\n\n <ion-icon (click)="presentEditTitle(chat?.session,chat,$event)" name="brush-sharp" style="margin-left: 1rem;"></ion-icon>\n <ion-icon (click)="presentDeleteTItle(chat?.session,chat,$event)" name="trash-sharp" style="margin-left: 0.5rem;"></ion-icon>\n \n </div>\n <div class="metadata-end-wrapper" slot="end">\n <ion-note color="medium">{{chat?.latest | date:"HH:mm"}}</ion-note>\n <ion-icon color="medium" name="chevron-forward"></ion-icon>\n </div>\n </div>\n <ion-text></ion-text><br />\n <ion-note color="medium" class="ion-text-wrap">\n {{chat?.message}}\n </ion-note>\n </ion-label>\n </ion-item>\n </ng-container>\n </ion-list>',styles:["ion-icon{color:#fff}ion-list{margin:3px}ion-list ion-item{--inner-padding-bottom:0px;--inner-padding-end:0px;--inner-padding-start:0px;--inner-padding-to:0px;--padding-bottom:0px;--padding-end:0px;--padding-start:0px;--padding-to:0px}ion-list ul{width:100%;list-style-type:none;padding:0;margin:0 0 10px;display:flex;flex-wrap:wrap;background-color:#fff;border-radius:10px}ion-list ul .active__{position:relative;padding:5px 15px;font-size:18px;font-weight:700;color:#535353;transition:.3s}ion-list ul .active{color:#2d8af7;background-color:#f2f4ff;border-radius:10px}ion-list ul li{flex:1 1 auto}ion-list ul li div{cursor:pointer;text-align:center}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"pipe",type:i2$2.DatePipe,name:"date"},{kind:"component",type:IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:IonList,selector:"ion-list",inputs:["inset","lines","mode"]},{kind:"component",type:IonLabel,selector:"ion-label",inputs:["color","mode","position"]},{kind:"component",type:IonNote,selector:"ion-note",inputs:["color","mode"]},{kind:"component",type:IonAvatar,selector:"ion-avatar"},{kind:"component",type:IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:IonText,selector:"ion-text",inputs:["color","mode"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatListComponent,decorators:[{type:Component,args:[{selector:"app-chat-list",imports:[CommonModule,IonIcon,IonList,IonLabel,IonNote,IonButton,IonAvatar,IonItem,IonText],standalone:!0,template:'<ion-list>\n <ng-container *ngFor="let chat of (chatServ?.chatList || chatList)">\n <ion-item [button]="true" detail="false" *ngIf="!chat?.isHidden" (click)="onItemClick(chat)">\n <div class="unread-indicator-wrapper" slot="start">\n <div class="unread-indicator"></div>\n </div>\n <ion-label>\n <div style="display: flex;justify-content: space-between; align-items: center;">\n <div style="display: flex; flex-direction: row;align-items: center;">\n <strong style="display: flex;align-items: center;">\n <ion-avatar style="margin-right: 10px;">\n <img [src]="chat?.thumb||avatar" />\n </ion-avatar>\n <p style="max-width: 7rem;white-space: nowrap;">{{truncateString(chat?.title)}}</p>\n </strong>\n\n <ion-icon (click)="presentEditTitle(chat?.session,chat,$event)" name="brush-sharp" style="margin-left: 1rem;"></ion-icon>\n <ion-icon (click)="presentDeleteTItle(chat?.session,chat,$event)" name="trash-sharp" style="margin-left: 0.5rem;"></ion-icon>\n \n </div>\n <div class="metadata-end-wrapper" slot="end">\n <ion-note color="medium">{{chat?.latest | date:"HH:mm"}}</ion-note>\n <ion-icon color="medium" name="chevron-forward"></ion-icon>\n </div>\n </div>\n <ion-text></ion-text><br />\n <ion-note color="medium" class="ion-text-wrap">\n {{chat?.message}}\n </ion-note>\n </ion-label>\n </ion-item>\n </ng-container>\n </ion-list>',styles:["ion-icon{color:#fff}ion-list{margin:3px}ion-list ion-item{--inner-padding-bottom:0px;--inner-padding-end:0px;--inner-padding-start:0px;--inner-padding-to:0px;--padding-bottom:0px;--padding-end:0px;--padding-start:0px;--padding-to:0px}ion-list ul{width:100%;list-style-type:none;padding:0;margin:0 0 10px;display:flex;flex-wrap:wrap;background-color:#fff;border-radius:10px}ion-list ul .active__{position:relative;padding:5px 15px;font-size:18px;font-weight:700;color:#535353;transition:.3s}ion-list ul .active{color:#2d8af7;background-color:#f2f4ff;border-radius:10px}ion-list ul li{flex:1 1 auto}ion-list ul li div{cursor:pointer;text-align:center}\n"]}]}],ctorParameters:()=>[{type:ChatService},{type:i2$3.AlertController},{type:i2$3.NavController}],propDecorators:{onItemClick:[{type:Input}]}});class FmChatHeaderArea{constructor(e){this.navCtrl=e,this.isModalOpen=!1}goBack(){this.navCtrl.back()}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatHeaderArea,deps:[{token:i2$3.NavController}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:FmChatHeaderArea,isStandalone:!0,selector:"fm-chat-header-area",inputs:{chat:"chat"},ngImport:i0,template:'<ion-toolbar *ngIf="chat?.isAvatarShow==false">\n <ion-buttons slot="start">\n <ion-button (click)="goBack()">\n <ion-icon name="chevron-back-outline"></ion-icon>\n </ion-button>\n </ion-buttons>\n <ion-title>\n <div class="title-avatar-area">\n <div class="avatar-img" (click)="chat.showAvatar()">\n <img *ngIf="chat?.role?.get(\'avatar\')||chat?.role?.get(\'thumb\')" [src]="chat?.role?.get(\'avatar\')||chat?.role?.get(\'thumb\')" />\n <ion-icon *ngIf="chat?.role?.get(\'avatarConfig\')" name="resize-outline"></ion-icon>\n </div>\n <span (click)="chat.showAvatar()">\n {{chat?.role?.get("name")}}\n </span>\n </div>\n </ion-title>\n\n <ion-buttons slot="end">\n <ion-button (click)="isModalOpen=true"> <ion-icon name="ellipsis-horizontal-outline"></ion-icon> </ion-button>\n </ion-buttons>\n</ion-toolbar>\n\n<div class="avatar-area" *ngIf="chat?.isAvatarShow==true">\n <fm-avatar-role-image *ngIf="chat?.avatarMode==\'image\'" [fmodeChat]="chat" [role]="avatarRole"></fm-avatar-role-image>\n <fm-avatar-role-video *ngIf="chat?.avatarMode==\'video\'" [fmodeChat]="chat" [role]="avatarRole"></fm-avatar-role-video>\n</div>\n\n\n<ion-modal [isOpen]="isModalOpen" (willDismiss)="isModalOpen=false">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="isModalOpen=false">返回</ion-button>\n </ion-buttons>\n <ion-title>简介</ion-title>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n\n <ion-card style="margin: 0px;">\n <img [src]="chat?.role?.get(\'thumb\')" alt="">\n <ion-card-header>\n <ion-card-subtitle>{{chat?.role?.get(\'tags\')}}</ion-card-subtitle>\n <ion-card-title>{{chat?.role?.get("name")}}</ion-card-title>\n </ion-card-header>\n \n <ion-card-content>\n {{chat?.role?.get("desc")}}\n \n <ion-list [inset]="true" style="margin:0px;">\n \x3c!-- <ion-item>\n <ion-avatar *ngIf="chat?.role?.get(\'thumb\')" aria-hidden="true" slot="start">\n <img [src]="chat?.role?.get(\'thumb\')" />\n </ion-avatar>\n <ion-label>{{chat?.role?.get("name")}}</ion-label>\n </ion-item> --\x3e\n <ion-item lines="none" *ngIf="chat?.role?.get(\'age\')">\n <ion-note slot="start">年龄</ion-note>\n <ion-label>{{chat?.role?.get("age")}}</ion-label>\n </ion-item>\n <ion-item lines="none" *ngIf="chat?.role?.get(\'gender\')">\n <ion-note slot="start">性别</ion-note>\n <ion-label>{{chat?.role?.get("gender")}}</ion-label>\n </ion-item>\n <ion-item lines="none">\n <ion-note slot="start">称号</ion-note>\n <ion-label>{{chat?.role?.get("title")}}</ion-label>\n </ion-item>\n \n <ion-item lines="none">\n <ion-note slot="start">擅长</ion-note>\n <ion-label>{{chat?.role?.get("tags")?.join(\',\')}}</ion-label>\n </ion-item>\n \n </ion-list>\n </ion-card-content>\n </ion-card>\n </ion-content>\n </ng-template>\n </ion-modal>',styles:[".title-avatar-area{width:100%;height:100%;display:flex;justify-content:center;align-items:center}.title-avatar-area .avatar-img img{width:32px;height:32px;border-radius:50%;margin-right:5px}.title-avatar-area .avatar-img ion-icon{background:#df76dfcc;border-radius:50%;padding:3px;position:absolute;color:#000;margin-left:-20px;font-size:10px;margin-top:18px}.avatar-area{height:100%}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:IonToolbar,selector:"ion-toolbar",inputs:["color","mode"]},{kind:"component",type:IonButtons,selector:"ion-buttons",inputs:["collapse"]},{kind:"component",type:IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:IonModal,selector:"ion-modal"},{kind:"component",type:IonTitle,selector:"ion-title",inputs:["color","size"]},{kind:"component",type:IonHeader,selector:"ion-header",inputs:["collapse","mode","translucent"]},{kind:"component",type:IonList,selector:"ion-list",inputs:["inset","lines","mode"]},{kind:"component",type:IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:IonCard,selector:"ion-card",inputs:["button","color","disabled","download","href","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:IonLabel,selector:"ion-label",inputs:["color","mode","position"]},{kind:"component",type:IonNote,selector:"ion-note",inputs:["color","mode"]},{kind:"component",type:CompAvatarRoleImageComponent,selector:"fm-avatar-role-image",inputs:["fmodeChat","role"]},{kind:"component",type:CompAvatarRoleVideoComponent,selector:"fm-avatar-role-video",inputs:["fmodeChat","role"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatHeaderArea,decorators:[{type:Component,args:[{selector:"fm-chat-header-area",standalone:!0,imports:[CommonModule,IonToolbar,IonButtons,IonButton,IonIcon,IonModal,IonAvatar,IonTitle,IonHeader,IonList,IonItem,IonCard,IonLabel,IonNote,CompAvatarRoleImageComponent,CompAvatarRoleVideoComponent],template:'<ion-toolbar *ngIf="chat?.isAvatarShow==false">\n <ion-buttons slot="start">\n <ion-button (click)="goBack()">\n <ion-icon name="chevron-back-outline"></ion-icon>\n </ion-button>\n </ion-buttons>\n <ion-title>\n <div class="title-avatar-area">\n <div class="avatar-img" (click)="chat.showAvatar()">\n <img *ngIf="chat?.role?.get(\'avatar\')||chat?.role?.get(\'thumb\')" [src]="chat?.role?.get(\'avatar\')||chat?.role?.get(\'thumb\')" />\n <ion-icon *ngIf="chat?.role?.get(\'avatarConfig\')" name="resize-outline"></ion-icon>\n </div>\n <span (click)="chat.showAvatar()">\n {{chat?.role?.get("name")}}\n </span>\n </div>\n </ion-title>\n\n <ion-buttons slot="end">\n <ion-button (click)="isModalOpen=true"> <ion-icon name="ellipsis-horizontal-outline"></ion-icon> </ion-button>\n </ion-buttons>\n</ion-toolbar>\n\n<div class="avatar-area" *ngIf="chat?.isAvatarShow==true">\n <fm-avatar-role-image *ngIf="chat?.avatarMode==\'image\'" [fmodeChat]="chat" [role]="avatarRole"></fm-avatar-role-image>\n <fm-avatar-role-video *ngIf="chat?.avatarMode==\'video\'" [fmodeChat]="chat" [role]="avatarRole"></fm-avatar-role-video>\n</div>\n\n\n<ion-modal [isOpen]="isModalOpen" (willDismiss)="isModalOpen=false">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="isModalOpen=false">返回</ion-button>\n </ion-buttons>\n <ion-title>简介</ion-title>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n\n <ion-card style="margin: 0px;">\n <img [src]="chat?.role?.get(\'thumb\')" alt="">\n <ion-card-header>\n <ion-card-subtitle>{{chat?.role?.get(\'tags\')}}</ion-card-subtitle>\n <ion-card-title>{{chat?.role?.get("name")}}</ion-card-title>\n </ion-card-header>\n \n <ion-card-content>\n {{chat?.role?.get("desc")}}\n \n <ion-list [inset]="true" style="margin:0px;">\n \x3c!-- <ion-item>\n <ion-avatar *ngIf="chat?.role?.get(\'thumb\')" aria-hidden="true" slot="start">\n <img [src]="chat?.role?.get(\'thumb\')" />\n </ion-avatar>\n <ion-label>{{chat?.role?.get("name")}}</ion-label>\n </ion-item> --\x3e\n <ion-item lines="none" *ngIf="chat?.role?.get(\'age\')">\n <ion-note slot="start">年龄</ion-note>\n <ion-label>{{chat?.role?.get("age")}}</ion-label>\n </ion-item>\n <ion-item lines="none" *ngIf="chat?.role?.get(\'gender\')">\n <ion-note slot="start">性别</ion-note>\n <ion-label>{{chat?.role?.get("gender")}}</ion-label>\n </ion-item>\n <ion-item lines="none">\n <ion-note slot="start">称号</ion-note>\n <ion-label>{{chat?.role?.get("title")}}</ion-label>\n </ion-item>\n \n <ion-item lines="none">\n <ion-note slot="start">擅长</ion-note>\n <ion-label>{{chat?.role?.get("tags")?.join(\',\')}}</ion-label>\n </ion-item>\n \n </ion-list>\n </ion-card-content>\n </ion-card>\n </ion-content>\n </ng-template>\n </ion-modal>',styles:[".title-avatar-area{width:100%;height:100%;display:flex;justify-content:center;align-items:center}.title-avatar-area .avatar-img img{width:32px;height:32px;border-radius:50%;margin-right:5px}.title-avatar-area .avatar-img ion-icon{background:#df76dfcc;border-radius:50%;padding:3px;position:absolute;color:#000;margin-left:-20px;font-size:10px;margin-top:18px}.avatar-area{height:100%}\n"]}]}],ctorParameters:()=>[{type:i2$3.NavController}],propDecorators:{chat:[{type:Input}]}}),Parse__default.applicationId||(Parse__default.initialize("ncloudmaster"),Parse__default.serverURL=(Parse__default.serverURL?.split("parse")?.[0]||"https://server.fmode.cn/")+"parse");class AuthService{isGuardLock(e){let t=!0,n=Parse__default.User.current();return t=!n?.id&&this.guardMap[e],t}get logoUrl(){return localStorage.getItem("LOGO_URL")||this._logoUrl||"https://file-cloud.fmode.cn/E4KpGvTEto/20230822/3mkf41033623275.png"}set logoUrl(e){localStorage.setItem("LOGO_URL",e),this._logoUrl=this._logoUrl}getCompanyId(){let e=localStorage.getItem("company");return e=this.company||e,e}constructor(e,t,n){this.router=e,this.novaCloud=t,this.http=n,this.guardMap={},this.isModalShow=!1,this._logoUrl="https://file-cloud.fmode.cn/E4KpGvTEto/20230822/3mkf41033623275.png",this.isLoggedIn=!1,this.LoginPage="/pcuser/login",this.mobileUserMap={}}init(e){this.company=e.company,this.guardType=e.guardType,this.saveParamsInvite()}checkLoginLock(){let e=Parse__default.User.current();return!!e?.id||(this.isModalShow=!0,this.isLoggedIn=!1,!1)}checkLogin(e){this.guardMap[e]=!0;let t=Parse__default.User.current();return console.log("currentUser",t),t&&t.id?(this.setAccount(t),this.isLoggedIn=!0,!0):this.guardType&&"page"!=this.guardType?"modal"==this.guardType?(this.isModalShow=!0,this.isLoggedIn=!1,!0):void 0:(this.redirectUrl=e,this.router.navigate([this.LoginPage]),!1)}async setAccount(e){if(this.account?.id)return;let t=Parse__default.Object.extend("Account"),n=e?.get("company")||{__type:"Pointer",className:"Company",objectId:this.getCompanyId()}||null,o=new Parse__default.Query("Account");o.equalTo("user",e.toPointer());let i=await o.first();return i?.id||(i=new t,i.set({user:e.toPointer(),company:n}),i=await i.save()),this.account=i,i}login(e,t){return new Promise(((n,o)=>{Parse__default.User.logIn(e,t).then((async e=>{if(this.bindInvite(e),this.setCurrentUserLocalStorage(e),"modal"==this.guardType)return await this.refreshPage(),void n(!0);let t=new Parse__default.Query("Company");t.select("rootPage"),t.equalTo("objectId",e?.get("company")?.id);let o=await t.first(),i=o?.get("rootPage");this.redirectUrl=this.redirectUrl||i||"/project/dashboard";let a=this.redirectUrl;a=decodeURIComponent(a),this.router.navigate([a])})).catch((e=>{console.error(e),o({message:"无此用户信息,请先在小程序登录"})}))}))}refreshPage(){return new Promise((e=>{let t=this.router.url;Parse__default.User.current()?.id&&(this.isModalShow=!1),this.router.navigateByUrl("/",{skipLocationChange:!0}).then((()=>{this.router.navigateByUrl(t).then((()=>{e(!0)}))}))}))}setCurrentUserLocalStorage(e){e.get("company")?.id&&localStorage.setItem("company",e.get("company")?.id)}logout(e,t){let n=localStorage.getItem("company");localStorage.clear(),localStorage.setItem("company",n),Parse__default.User.logOut().then((e=>{this.router.navigate([t||"/pcuser/login"])}))}async loginMobilePassword(e,t,n){let o=await this.getMobileUser(e);o?this.login(o,t).then((async e=>{this.isModalShow=!1})).catch((e=>{console.log(e),n.create("error","错误的用户名或密码")})):n.create("error","用户不存在,请尝试其他登录方式")}signMobilePassword(e,t){return new Promise(((n,o)=>{Parse__default.User.signUp(this.getCompanyId()+"-"+e,t,"").then((async t=>{t.id&&(console.log(t),t.set("company",{__type:"Pointer",className:"Company",objectId:this.getCompanyId()}),t.set("mobile",e),t.set("type","user"),this.bindInvite(t),t=await t.save(),n(t))})).catch((e=>{o(e)}))}))}async getMobileUser(e){let t=this.getCompanyId(),n=t+e;if(this.mobileUserMap[n])return this.mobileUserMap[n];let o=await this.novaCloud.api("/auth/getusername",{company:t,mobile:e});return o?.username&&(this.mobileUserMap[n]=o?.username),this.mobileUserMap[n]}async loginCode(e,t,n){return new Promise(((o,i)=>{if(!t)return n?.create("error","请填写有效验证码"),void i();let a=Parse__default.serverURL?.split("parse")?.[0]||"https://server.fmode.cn/";this.http.get(a+`api/auth/mobile?company=${this.company}&mobile=${e}&code=${t}`,{}).pipe(catchError((async e=>{console.log(e),n?.create("error","登录失败:"+e.error.mess),i()}))).subscribe((e=>{200==e.code?Parse__default.User.become(e.data.token).then((async e=>{if(console.log(e),e.id)return this.bindInvite(e),void o(!0);n?.create("error","登录失败"),i()})):(n?.create("error","登录失败"),i())}))}))}saveParamsInvite(){let e=this.novaCloud.searchParse();console.log("saveParamsInvite",e);let t=e?.invite;console.log(t),t&&localStorage.setItem("invite",e?.invite)}bindInvite(e){if(!(e=e||Parse__default.User.current()))return;if(e?.get("invite")?.id)return;let t=localStorage.getItem("invite");t&&this.novaCloud.api("/auth/invite",{current:e?.id,invite:t,type:"code"})}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AuthService,deps:[{token:i1$1.Router},{token:NovaCloudService},{token:i1.HttpClient}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AuthService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AuthService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i1$1.Router},{type:NovaCloudService},{type:i1.HttpClient}]});class AccountService{constructor(e,t,n){this.ncloud=e,this.authServ=t,this.http=n,this.company="",this.billing={credit:{usedDetail:{}}},this.wxAppId="",this.wxpayEnabled=!1,this.company=this.authServ.company||localStorage.getItem("company"),this.getBilling(),this.getProfile(),this.getUserOpenid()}async getProfile(){let e=Parse__default.User.current()?.id;if(!e)return;let t=new Parse__default.Query("Profile");t.equalTo("user",e),t.equalTo("company",this.company),t.notEqualTo("isDeleted",!0);let n=await t.first();n?.id&&(this.profile=n)}async getBilling(){let e;try{e=await this.ncloud.apig("aigc/account",null,"get")}catch(e){}return e?.credit&&(this.billing=e),e}async getUserOpenid(){let e=-1!=navigator.userAgent.toLowerCase().indexOf("micromessenger"),t=this.getQueryStringByName("code"),n=localStorage.getItem("openid");if(!n){if(!Parse__default.User.current())return;let o=Parse__default.User.current().get("wechat");n=o?.wxb4193c93ae9aa696?.openid,e&&(t?await this.getwechat(t):this.authWechat())}}authWechat(e="/account/billing"){if(!localStorage.getItem("openid")){let t="https://ai.fmode.cn"+e;return t=encodeURIComponent(t),void(window.location.href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxb4193c93ae9aa696&redirect_uri="+t+"&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect")}}getQueryStringByName(e){let t=location.search.match(new RegExp("[?&]"+e+"=([^&]+)","i"));return null==t||t.length<1?"":t[1]}async getwechat(e,t="/account/billing"){return new Promise((async(n,o)=>{this.http.post("https://server.fmode.cn/api/wechat/get_wx",{company:this.company,code:e}).subscribe((async e=>{if(console.log(e),e&&200==e.code&&e.data.openid){let t=e.data.openid;localStorage.setItem("openid",t),localStorage.removeItem("code"),Parse__default.User.current().set("wechat",{wxb4193c93ae9aa696:{openid:t}}),await Parse__default.User.current().save(),n(!0)}}),(async e=>{console.log("Error updating items",e),this.authWechat(t),o(!1)}))}))}getWXSignPackageInWechat(){let e={company:this.company,href:encodeURIComponent(location.href.split("?")[0])};this.http.post("https://server.fmode.cn/api/wechat/getconfig",e).subscribe((e=>{const t=e.data;this.wxAppId=t.appid,this.wxpayEnabled=!0,wx.config({debug:!1,appId:t.appid,timestamp:t.timestamp,nonceStr:t.nonceStr,signature:t.signature,jsApiList:["chooseWXPay","onMenuShareTimeline","onMenuShareAppMessage","onMenuShareQQ","onMenuShareQZone","updateAppMessageShareData","updateTimelineShareData"]});let n="https://ai.fmode.cn";location.pathname;Parse__default.User.current()?.id;let o={title:"飞码AI",desc:"解放创意引领未来|国际前沿的AIGC平台",link:n,type:"link",imgUrl:"https://file-cloud.fmode.cn/E4KpGvTEto/20230822/3mkf41033623275.png",success:function(){console.log("分享成功")},error:function(){console.log("分享失败")},cancel:function(){console.log("取消分享")}};wx.ready((()=>{wx.updateAppMessageShareData(o),wx.updateTimelineShareData(o)})),wx.error((()=>{}))}))}async saveAccountLog(e,t,n,o){return new Promise(((i,a)=>{this.http.post("https://test.fmode.cn/api/apig/saveAccountLog",{company:n,uid:Parse__default.User.current().id,orderid:t,info:e}).subscribe((e=>{console.log(e),i(!0)}),(e=>{console.warn(e),o&&o.error("请求超时,请稍后再试"),a()}))}))}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AccountService,deps:[{token:NovaCloudService},{token:AuthService},{token:i1.HttpClient}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AccountService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AccountService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:NovaCloudService},{type:AuthService},{type:i1.HttpClient}]});class CompUserAvatarComponent{constructor(e){this.novaAccount=e,this.type="icon",this.text="U"}ngOnInit(){this.type=this.getType()}ngOnChanges(){this.refresh()}async refresh(){await this.novaAccount.getProfile();let e=this.novaAccount.profile;e?.get("type")&&("student"==e?.get("type")?this.identity="https://file-cloud.fmode.cn/khgbeQmvYZ/20231123/k1k4iq103416124.png":this.identity="https://file-cloud.fmode.cn/E4KpGvTEto/20231116/q12c16094638625.png")}getType(){return this.user?.id?this.user?.get("avatar")?"avatar":this.user?.get("nickname")?(this.text=this.user?.get("nickname")?.slice(0,1),"text"):"icon":"icon"}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompUserAvatarComponent,deps:[{token:AccountService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:CompUserAvatarComponent,isStandalone:!0,selector:"app-comp-user-avatar",inputs:{user:"user"},usesOnChanges:!0,ngImport:i0,template:'<ng-container *ngIf="user?.id || type == \'icon\'">\n <div class="avatar-com">\n \x3c!-- 默认ICON --\x3e\n <nz-avatar\n *ngIf="type == \'icon\'"\n [style]="{ backgroundColor: \'#0199f9\' }"\n nzIcon="user"\n ></nz-avatar>\n \x3c!-- <div *ngIf="type==\'icon\'" class="iconfont icon-yonghu-yuan"></div> --\x3e\n \x3c!-- 头像照片 --\x3e\n <div class="avatar-com">\n <nz-avatar class="comp-avatar"\n *ngIf="type == \'avatar\'"\n [nzSrc]="user?.get(\'avatar\')"\n ></nz-avatar>\n <img\n class="auth-icon"\n *ngIf="identity && type == \'avatar\'"\n [src]="identity"\n alt="已认证"\n />\n </div>\n \x3c!-- 昵称首字符 --\x3e\n <nz-avatar\n *ngIf="type == \'text\'"\n style="background-color: #0199f9"\n [nzText]="text"\n ></nz-avatar>\n </div>\n</ng-container>\n',styles:[".avatar-com{position:relative;width:32px;height:32px}.avatar-com .auth-icon{width:20px;height:20px;border-radius:50%;position:absolute;right:-6px;bottom:-2px}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"ngmodule",type:NzAvatarModule},{kind:"component",type:i3.NzAvatarComponent,selector:"nz-avatar",inputs:["nzShape","nzSize","nzGap","nzText","nzSrc","nzSrcSet","nzAlt","nzIcon"],outputs:["nzError"],exportAs:["nzAvatar"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompUserAvatarComponent,decorators:[{type:Component,args:[{selector:"app-comp-user-avatar",standalone:!0,imports:[CommonModule,NzAvatarModule],template:'<ng-container *ngIf="user?.id || type == \'icon\'">\n <div class="avatar-com">\n \x3c!-- 默认ICON --\x3e\n <nz-avatar\n *ngIf="type == \'icon\'"\n [style]="{ backgroundColor: \'#0199f9\' }"\n nzIcon="user"\n ></nz-avatar>\n \x3c!-- <div *ngIf="type==\'icon\'" class="iconfont icon-yonghu-yuan"></div> --\x3e\n \x3c!-- 头像照片 --\x3e\n <div class="avatar-com">\n <nz-avatar class="comp-avatar"\n *ngIf="type == \'avatar\'"\n [nzSrc]="user?.get(\'avatar\')"\n ></nz-avatar>\n <img\n class="auth-icon"\n *ngIf="identity && type == \'avatar\'"\n [src]="identity"\n alt="已认证"\n />\n </div>\n \x3c!-- 昵称首字符 --\x3e\n <nz-avatar\n *ngIf="type == \'text\'"\n style="background-color: #0199f9"\n [nzText]="text"\n ></nz-avatar>\n </div>\n</ng-container>\n',styles:[".avatar-com{position:relative;width:32px;height:32px}.avatar-com .auth-icon{width:20px;height:20px;border-radius:50%;position:absolute;right:-6px;bottom:-2px}\n"]}]}],ctorParameters:()=>[{type:AccountService}],propDecorators:{user:[{type:Input}]}});class FmChatMessageCard{constructor(e){this.copyServ=e,this.user=Parse__default.User.current()}async copy(){this.copyServ.copyToClipboard(getMessageContentText(this.message?.content))}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatMessageCard,deps:[{token:ClipboardService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:FmChatMessageCard,isStandalone:!0,selector:"fm-chat-message-card",inputs:{message:"message",role:"role",chat:"chat"},ngImport:i0,template:'<div class="message-card" [class.right]="message?.role==\'user\'" [class.center]="message?.role==\'system\'">\n \x3c!-- 用户及操作区 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'"> \x3c!-- 系统消息不显示头像 --\x3e\n <div class="avatar-row">\n <div class="actions">\n \x3c!-- 刷新 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="refresh-outline"></ion-icon> \n </ion-button> --\x3e\n \x3c!-- 复制 --\x3e\n <ion-button size="small" fill="outline" slot="start" (click)="copy()">\n <ion-icon name="copy-outline"></ion-icon>\n </ion-button>\n \x3c!-- 编辑 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="create-outline"></ion-icon>\n </ion-button> --\x3e\n </div>\n \x3c!-- 头像区域 --\x3e\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'" ></nz-avatar>\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 附件:图片 --\x3e\n <div class="item-row images" *ngIf="message?.content | chatContent:\'image_url\'">\n <img [src]="message?.content | chatContent:\'image_url\'" alt="">\n </div>\n \x3c!-- 聊天气泡 --\x3e\n <div class="item-row bubble">\n <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content | chatContent" [render]="false"></fm-markdown-preview>\n <fm-markdown-preview *ngIf="message?.complete" [content]="message?.content | chatContent"></fm-markdown-preview>\n </div>\n \x3c!-- 时间显示 --\x3e\n <div class="item-row loading" *ngIf="message?.role!=\'system\' && !message?.complete">\n 正在输入<ion-spinner name="dots"></ion-spinner>\n </div>\n\n <div class="item-row created" *ngIf="message?.createdAt">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n</div>',styles:[":host-context(body.dark) .message-card .actions .item-native{background:none!important}:host-context(body.dark) .message-card .bubble{color:#0e101d}:host-context(body.dark) .message-card .bubble .content-style{filter:invert(1)!important}:host-context(body.dark) .message-card .bubble fm-markdown-preview{filter:invert(1)!important}:host-context(body.dark) .message-card .right .bubble{color:#921f8a!important;background:#921f8a!important}:host-context(body.dark) .message-card .created span{color:#fff}@media screen and (max-width: 800px){.message-card:focus .actions{opacity:1!important}}.message-card:hover .actions{opacity:1;transition:opacity .3s ease-in-out}.message-card{display:flex;flex-wrap:wrap;justify-content:start;align-items:flex-start}.message-card .avatar-row{width:300px;height:32px;display:flex;flex-direction:row-reverse;justify-content:start;align-items:center}.message-card .actions{display:flex;opacity:0;padding-left:10px;padding-right:10px}.message-card .item-row{display:flex;flex:100%;justify-content:start;margin-bottom:5px}.message-card .images img{max-width:300px}.message-card .bubble{max-width:100%;padding-top:1rem;padding:.5rem;color:#333;flex:none;border-radius:0 3em 3em/0em 3em 3em;color:#fff;background-color:currentColor}.message-card .bubble .content-style{filter:grayscale(1) contrast(999) invert(1)}.message-card .loading{text-align:right;color:#101010}.message-card .created{display:flex}.message-card .created span{font-size:12px;opacity:.4;white-space:nowrap;transition:all .6s ease;color:var(--black);text-align:center;width:100%;box-sizing:border-box;padding-right:10px;pointer-events:none;z-index:1}.right{justify-content:end;align-items:flex-end}.right .avatar-row{flex-direction:row;justify-content:end;width:auto}.right .actions{position:relative;margin-left:0}.right .item-row{justify-content:end}.right .bubble{color:#bbdefb;border-top-left-radius:3em;border-top-right-radius:0}.center{justify-content:center;align-items:center}.center .item-row{justify-content:center}.center .bubble{color:var(--gray-secondary);border-top-left-radius:3em;border-top-right-radius:3em}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"pipe",type:i2$2.DatePipe,name:"date"},{kind:"component",type:CompUserAvatarComponent,selector:"app-comp-user-avatar",inputs:["user"]},{kind:"ngmodule",type:MarkdownPreviewModule},{kind:"component",type:MarkdownPreviewComponent,selector:"fm-markdown-preview",inputs:["content","render"]},{kind:"ngmodule",type:NzAvatarModule},{kind:"component",type:i3.NzAvatarComponent,selector:"nz-avatar",inputs:["nzShape","nzSize","nzGap","nzText","nzSrc","nzSrcSet","nzAlt","nzIcon"],outputs:["nzError"],exportAs:["nzAvatar"]},{kind:"pipe",type:ChatContentPipe,name:"chatContent"}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatMessageCard,decorators:[{type:Component,args:[{selector:"fm-chat-message-card",standalone:!0,imports:[CommonModule,IonItem,CompUserAvatarComponent,MarkdownPreviewModule,NzAvatarModule,IonAvatar,ChatContentPipe],template:'<div class="message-card" [class.right]="message?.role==\'user\'" [class.center]="message?.role==\'system\'">\n \x3c!-- 用户及操作区 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'"> \x3c!-- 系统消息不显示头像 --\x3e\n <div class="avatar-row">\n <div class="actions">\n \x3c!-- 刷新 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="refresh-outline"></ion-icon> \n </ion-button> --\x3e\n \x3c!-- 复制 --\x3e\n <ion-button size="small" fill="outline" slot="start" (click)="copy()">\n <ion-icon name="copy-outline"></ion-icon>\n </ion-button>\n \x3c!-- 编辑 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="create-outline"></ion-icon>\n </ion-button> --\x3e\n </div>\n \x3c!-- 头像区域 --\x3e\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'" ></nz-avatar>\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 附件:图片 --\x3e\n <div class="item-row images" *ngIf="message?.content | chatContent:\'image_url\'">\n <img [src]="message?.content | chatContent:\'image_url\'" alt="">\n </div>\n \x3c!-- 聊天气泡 --\x3e\n <div class="item-row bubble">\n <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content | chatContent" [render]="false"></fm-markdown-preview>\n <fm-markdown-preview *ngIf="message?.complete" [content]="message?.content | chatContent"></fm-markdown-preview>\n </div>\n \x3c!-- 时间显示 --\x3e\n <div class="item-row loading" *ngIf="message?.role!=\'system\' && !message?.complete">\n 正在输入<ion-spinner name="dots"></ion-spinner>\n </div>\n\n <div class="item-row created" *ngIf="message?.createdAt">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n</div>',styles:[":host-context(body.dark) .message-card .actions .item-native{background:none!important}:host-context(body.dark) .message-card .bubble{color:#0e101d}:host-context(body.dark) .message-card .bubble .content-style{filter:invert(1)!important}:host-context(body.dark) .message-card .bubble fm-markdown-preview{filter:invert(1)!important}:host-context(body.dark) .message-card .right .bubble{color:#921f8a!important;background:#921f8a!important}:host-context(body.dark) .message-card .created span{color:#fff}@media screen and (max-width: 800px){.message-card:focus .actions{opacity:1!important}}.message-card:hover .actions{opacity:1;transition:opacity .3s ease-in-out}.message-card{display:flex;flex-wrap:wrap;justify-content:start;align-items:flex-start}.message-card .avatar-row{width:300px;height:32px;display:flex;flex-direction:row-reverse;justify-content:start;align-items:center}.message-card .actions{display:flex;opacity:0;padding-left:10px;padding-right:10px}.message-card .item-row{display:flex;flex:100%;justify-content:start;margin-bottom:5px}.message-card .images img{max-width:300px}.message-card .bubble{max-width:100%;padding-top:1rem;padding:.5rem;color:#333;flex:none;border-radius:0 3em 3em/0em 3em 3em;color:#fff;background-color:currentColor}.message-card .bubble .content-style{filter:grayscale(1) contrast(999) invert(1)}.message-card .loading{text-align:right;color:#101010}.message-card .created{display:flex}.message-card .created span{font-size:12px;opacity:.4;white-space:nowrap;transition:all .6s ease;color:var(--black);text-align:center;width:100%;box-sizing:border-box;padding-right:10px;pointer-events:none;z-index:1}.right{justify-content:end;align-items:flex-end}.right .avatar-row{flex-direction:row;justify-content:end;width:auto}.right .actions{position:relative;margin-left:0}.right .item-row{justify-content:end}.right .bubble{color:#bbdefb;border-top-left-radius:3em;border-top-right-radius:0}.center{justify-content:center;align-items:center}.center .item-row{justify-content:center}.center .bubble{color:var(--gray-secondary);border-top-left-radius:3em;border-top-right-radius:3em}\n"]}]}],ctorParameters:()=>[{type:ClipboardService}],propDecorators:{message:[{type:Input}],role:[{type:Input}],chat:[{type:Input}]}});class CompRolePromptComponent{constructor(e,t){this.cross=e,this.modalController=t,this.role="",this.showModal=!1,this.cateIndex=0,this.company="E4KpGvTEto"}ngOnInit(){this.getChatPrompt()}applyPrompt(e){this.chat.userInput=e,"mobile"==this.cross?.navMenuType&&this.modalController.dismiss()}async getChatPrompt(){let e=new Parse.Query("ChatPrompt");e.notEqualTo("isDeleted",!0),e.equalTo("company",this.company),e.equalTo("role",this.role),e.include("role");let t=await e.find();this.chat.promptList=t,this.chat.promptList.forEach((e=>{let t=e.get("role").get("promptCates").filter((t=>t.name==e.get("cate")));e.img=t[0].img})),console.log(this.chat.promptList)}checkCate(e){this.cateIndex=e}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompRolePromptComponent,deps:[{token:CrossService},{token:i2$3.ModalController}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:CompRolePromptComponent,isStandalone:!0,selector:"app-comp-role-prompt",inputs:{chat:"chat",role:"role"},providers:[ModalController$1],ngImport:i0,template:'<div class="prompt" *ngIf="cross?.navMenuType!=\'mobile\'">\n <ng-container *ngFor="let content of chat?.promptList">\n <div class="prompt_cate">\n <div class="cate_info">\n <div>\n <img [src]="content.img" alt="">\n </div>\n <div class="cate_name">\n {{content.get(\'cate\')}}\n </div>\n </div>\n <ng-container *ngFor="let message of content.get(\'messageList\')">\n <div class="message" (click)="applyPrompt(message)" nz-tooltip [nzTooltipTitle]="message"\n nzTooltipColor="#108ee9">\n {{message}}\n </div>\n </ng-container>\n </div>\n </ng-container>\n</div>\n<ng-container *ngIf="cross?.navMenuType==\'mobile\'">\n <div class="prompt_mobile">\n <ng-container *ngFor="let content of chat?.promptList">\n <div class="prompt_cate">\n <div class="cate_info">\n <div>\n <img [src]="content.img" alt="">\n </div>\n <div class="cate_name">\n {{content.get(\'cate\')}}\n </div>\n </div>\n <ng-container *ngFor="let message of content.get(\'messageList\');let idx = index">\n <div *ngIf="idx<3" class="message" (click)="applyPrompt(message)" nz-tooltip [nzTooltipTitle]="message"\n nzTooltipColor="#108ee9">\n {{message}}\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n <div class="view_more" *ngIf="chat?.promptList?.length">\n <button (click)="chat.isPromptModalOpen=true" expand="block">查看更多<span nz-icon nzType="right" nzTheme="outline"></span></button>\n </div>\n <ion-modal [isOpen]="chat.isPromptModalOpen" (willDismiss)="chat.isPromptModalOpen=false" [initialBreakpoint]="1" [breakpoints]="[0, 1]">\n <ng-template>\n <div class="block">\n <ion-label>话题灵感</ion-label>\n <div class="block_cate">\n \x3c!-- <ion-segment [(ngModel)]="cateIndex">\n <ng-container *ngFor="let prompt of chat?.promptList;let i = index">\n <ion-segment-button value="i">\n <ion-label>{{prompt?.get("cate")}}</ion-label>\n </ion-segment-button>\n </ng-container>\n </ion-segment> --\x3e\n <ng-container *ngFor="let prompt of chat?.promptList;let i = index">\n <ion-button [color]="i==cateIndex?\'secondary\':\'light\'" (click)="checkCate(i)">{{prompt?.get("cate")}}</ion-button>\n \x3c!-- <div [class]="i==cateIndex?\'active_cate\':\'\'" (click)="checkCate(i)">{{prompt?.get("cate")}}</div> --\x3e\n </ng-container>\n </div>\n <div class="message_mobile">\n <ng-container *ngFor="let message of chat?.promptList[cateIndex]?.get(\'messageList\')">\n <div (click)="applyPrompt(message)">{{message}}</div>\n </ng-container>\n </div>\n </div>\n </ng-template>\n </ion-modal>\n</ng-container>',styles:[":host-context(body.dark) .cate_info{color:#fff}:host-context(body.dark) ion-modal .block h4{color:#fff!important}.prompt{color:#000;display:flex;justify-content:space-between;align-items:flex-start}.prompt .prompt_cate{flex:1;height:inherit;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:flex;justify-content:center}.prompt .prompt_cate .cate_info{font-size:1.5em;font-weight:700}.prompt .prompt_cate .cate_info div img{width:58px;height:58px}.prompt .prompt_cate .cate_info .cate_name{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.prompt .prompt_cate .message{padding:1em;margin:1em;background:#fff;border:1px solid #eef2f2;border-radius:12px;box-shadow:0 2px 8px #f5f6f8;cursor:pointer;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}@media screen and (max-width: 390.4px){.prompt .prompt_cate .message{width:100px;height:64px;padding:unset;margin:.8em;background:#fff;border:1px solid #eef2f2;border-radius:12px;box-shadow:0 2px 8px #f5f6f8;cursor:pointer;overflow:hidden;white-space:pre-wrap;text-overflow:ellipsis}}.prompt_mobile{color:#000;display:flex;justify-content:space-between;align-items:flex-start}.prompt_mobile .prompt_cate{flex:1;height:inherit}.prompt_mobile .prompt_cate .cate_info{display:flex;justify-content:center;align-items:center;font-size:1.2em}.prompt_mobile .prompt_cate .cate_info div img{width:48px;height:48px}.prompt_mobile .prompt_cate .cate_info .cate_name{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;overflow:hidden;text-overflow:ellipsis;margin-top:2vw}.prompt_mobile .prompt_cate .message{min-height:48px;padding:0 2vw;margin:4vw 1vw;background:#fff;border:1px solid #eef2f2;border-radius:12px;box-shadow:0 2px 8px #f5f6f8;cursor:pointer;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;text-overflow:ellipsis}.view_more{text-align:center;color:#999;margin:4vw 0}.view_more>button{background-color:transparent}.block{width:100%;height:80vh;padding:2vw}.block .block_cate{display:flex;justify-content:space-between}.block .message_mobile{overflow-y:auto;height:65vh;color:#000}.block .message_mobile>div{background-color:#fff;text-align:center;padding:3vw 0;margin:3vw 0;border-radius:4px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}ion-modal{--height: auto}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"ngmodule",type:FormsModule},{kind:"ngmodule",type:ReactiveFormsModule},{kind:"component",type:IonModal,selector:"ion-modal"},{kind:"component",type:IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:IonLabel,selector:"ion-label",inputs:["color","mode","position"]},{kind:"ngmodule",type:NzIconModule},{kind:"directive",type:i4.NzIconDirective,selector:"[nz-icon]",inputs:["nzSpin","nzRotate","nzType","nzTheme","nzTwotoneColor","nzIconfont"],exportAs:["nzIcon"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompRolePromptComponent,decorators:[{type:Component,args:[{selector:"app-comp-role-prompt",standalone:!0,imports:[CommonModule,FormsModule,ReactiveFormsModule,IonModal,IonButton,IonSegment,IonLabel,NzIconModule],providers:[ModalController$1],template:'<div class="prompt" *ngIf="cross?.navMenuType!=\'mobile\'">\n <ng-container *ngFor="let content of chat?.promptList">\n <div class="prompt_cate">\n <div class="cate_info">\n <div>\n <img [src]="content.img" alt="">\n </div>\n <div class="cate_name">\n {{content.get(\'cate\')}}\n </div>\n </div>\n <ng-container *ngFor="let message of content.get(\'messageList\')">\n <div class="message" (click)="applyPrompt(message)" nz-tooltip [nzTooltipTitle]="message"\n nzTooltipColor="#108ee9">\n {{message}}\n </div>\n </ng-container>\n </div>\n </ng-container>\n</div>\n<ng-container *ngIf="cross?.navMenuType==\'mobile\'">\n <div class="prompt_mobile">\n <ng-container *ngFor="let content of chat?.promptList">\n <div class="prompt_cate">\n <div class="cate_info">\n <div>\n <img [src]="content.img" alt="">\n </div>\n <div class="cate_name">\n {{content.get(\'cate\')}}\n </div>\n </div>\n <ng-container *ngFor="let message of content.get(\'messageList\');let idx = index">\n <div *ngIf="idx<3" class="message" (click)="applyPrompt(message)" nz-tooltip [nzTooltipTitle]="message"\n nzTooltipColor="#108ee9">\n {{message}}\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n <div class="view_more" *ngIf="chat?.promptList?.length">\n <button (click)="chat.isPromptModalOpen=true" expand="block">查看更多<span nz-icon nzType="right" nzTheme="outline"></span></button>\n </div>\n <ion-modal [isOpen]="chat.isPromptModalOpen" (willDismiss)="chat.isPromptModalOpen=false" [initialBreakpoint]="1" [breakpoints]="[0, 1]">\n <ng-template>\n <div class="block">\n <ion-label>话题灵感</ion-label>\n <div class="block_cate">\n \x3c!-- <ion-segment [(ngModel)]="cateIndex">\n <ng-container *ngFor="let prompt of chat?.promptList;let i = index">\n <ion-segment-button value="i">\n <ion-label>{{prompt?.get("cate")}}</ion-label>\n </ion-segment-button>\n </ng-container>\n </ion-segment> --\x3e\n <ng-container *ngFor="let prompt of chat?.promptList;let i = index">\n <ion-button [color]="i==cateIndex?\'secondary\':\'light\'" (click)="checkCate(i)">{{prompt?.get("cate")}}</ion-button>\n \x3c!-- <div [class]="i==cateIndex?\'active_cate\':\'\'" (click)="checkCate(i)">{{prompt?.get("cate")}}</div> --\x3e\n </ng-container>\n </div>\n <div class="message_mobile">\n <ng-container *ngFor="let message of chat?.promptList[cateIndex]?.get(\'messageList\')">\n <div (click)="applyPrompt(message)">{{message}}</div>\n </ng-container>\n </div>\n </div>\n </ng-template>\n </ion-modal>\n</ng-container>',styles:[":host-context(body.dark) .cate_info{color:#fff}:host-context(body.dark) ion-modal .block h4{color:#fff!important}.prompt{color:#000;display:flex;justify-content:space-between;align-items:flex-start}.prompt .prompt_cate{flex:1;height:inherit;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:flex;justify-content:center}.prompt .prompt_cate .cate_info{font-size:1.5em;font-weight:700}.prompt .prompt_cate .cate_info div img{width:58px;height:58px}.prompt .prompt_cate .cate_info .cate_name{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.prompt .prompt_cate .message{padding:1em;margin:1em;background:#fff;border:1px solid #eef2f2;border-radius:12px;box-shadow:0 2px 8px #f5f6f8;cursor:pointer;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}@media screen and (max-width: 390.4px){.prompt .prompt_cate .message{width:100px;height:64px;padding:unset;margin:.8em;background:#fff;border:1px solid #eef2f2;border-radius:12px;box-shadow:0 2px 8px #f5f6f8;cursor:pointer;overflow:hidden;white-space:pre-wrap;text-overflow:ellipsis}}.prompt_mobile{color:#000;display:flex;justify-content:space-between;align-items:flex-start}.prompt_mobile .prompt_cate{flex:1;height:inherit}.prompt_mobile .prompt_cate .cate_info{display:flex;justify-content:center;align-items:center;font-size:1.2em}.prompt_mobile .prompt_cate .cate_info div img{width:48px;height:48px}.prompt_mobile .prompt_cate .cate_info .cate_name{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;overflow:hidden;text-overflow:ellipsis;margin-top:2vw}.prompt_mobile .prompt_cate .message{min-height:48px;padding:0 2vw;margin:4vw 1vw;background:#fff;border:1px solid #eef2f2;border-radius:12px;box-shadow:0 2px 8px #f5f6f8;cursor:pointer;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;text-overflow:ellipsis}.view_more{text-align:center;color:#999;margin:4vw 0}.view_more>button{background-color:transparent}.block{width:100%;height:80vh;padding:2vw}.block .block_cate{display:flex;justify-content:space-between}.block .message_mobile{overflow-y:auto;height:65vh;color:#000}.block .message_mobile>div{background-color:#fff;text-align:center;padding:3vw 0;margin:3vw 0;border-radius:4px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}ion-modal{--height: auto}\n"]}]}],ctorParameters:()=>[{type:CrossService},{type:i2$3.ModalController}],propDecorators:{chat:[{type:Input}],role:[{type:Input}]}});class FmChatMesssageArea{get messageList(){return this.chatServ.chatMap[this.chatId]?.messageList}constructor(e){this.chatServ=e}ngDoCheck(){}ngAfterViewInit(){console.log("ng gogogo1"),console.log("ng gogogo2"),console.log(this.chat)}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatMesssageArea,deps:[{token:ChatService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:FmChatMesssageArea,isStandalone:!0,selector:"fm-chat-message-area",inputs:{chatId:"chatId",chat:"chat"},ngImport:i0,template:'\n<div class="message-list">\n <app-comp-role-prompt *ngIf="chat?.messageList?.length<=1 && !chat?.userInput" [chat]="chat" [role]="chat?.role?.id"></app-comp-role-prompt>\n <ng-container *ngFor="let message of chat?.messageList">\n \x3c!-- 内容格式化区域 --\x3e\n <fm-chat-message-card [chat]="chat" *ngIf="!message?.hidden" [message]="message" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n \x3c!-- 预览无图消息 --\x3e\n <ng-container *ngIf="chat?.userInput&&!chat?.userImage">\n <fm-chat-message-card [chat]="chat" [message]="{role:\'user\',content:chat?.userInput}" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n \x3c!-- 预览有图消息 --\x3e\n <ng-container *ngIf="chat?.userImage">\n <fm-chat-message-card [chat]="chat" [message]="{role:\'user\',content:[{type:\'text\',text:chat?.userInput},{type:\'image_url\',image_url:{url:chat?.userImage}}]}" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n</div>',styles:[".message-list{padding:5px 10px}:host-context(body.dark) .message-list{background-color:#000!important}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:FmChatMessageCard,selector:"fm-chat-message-card",inputs:["message","role","chat"]},{kind:"component",type:CompRolePromptComponent,selector:"app-comp-role-prompt",inputs:["chat","role"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatMesssageArea,decorators:[{type:Component,args:[{selector:"fm-chat-message-area",standalone:!0,imports:[CommonModule,FmChatMessageCard,CompRolePromptComponent],template:'\n<div class="message-list">\n <app-comp-role-prompt *ngIf="chat?.messageList?.length<=1 && !chat?.userInput" [chat]="chat" [role]="chat?.role?.id"></app-comp-role-prompt>\n <ng-container *ngFor="let message of chat?.messageList">\n \x3c!-- 内容格式化区域 --\x3e\n <fm-chat-message-card [chat]="chat" *ngIf="!message?.hidden" [message]="message" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n \x3c!-- 预览无图消息 --\x3e\n <ng-container *ngIf="chat?.userInput&&!chat?.userImage">\n <fm-chat-message-card [chat]="chat" [message]="{role:\'user\',content:chat?.userInput}" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n \x3c!-- 预览有图消息 --\x3e\n <ng-container *ngIf="chat?.userImage">\n <fm-chat-message-card [chat]="chat" [message]="{role:\'user\',content:[{type:\'text\',text:chat?.userInput},{type:\'image_url\',image_url:{url:chat?.userImage}}]}" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n</div>',styles:[".message-list{padding:5px 10px}:host-context(body.dark) .message-list{background-color:#000!important}\n"]}]}],ctorParameters:()=>[{type:ChatService}],propDecorators:{chatId:[{type:Input}],chat:[{type:Input}]}});class ModalAudioMessageComponent{constructor(e,t){this.voiceServ=e,this.toastCtrl=t,this.isRecording=!1,this.player=new Audio,this.clockStr="0:00"}ngOnInit(){this.chat.userInput="",this.initVoiceSevice(),this.voiceServ.startTalk()}playMusic(e){this.player.src=`/assets/avatar/voice/${e}.mp3`,this.player.play()}initVoiceSevice(){this.chat.userInput=this.voiceServ.resultText,this.voiceServ.requestPermission().then((()=>{this.voiceServ.openWithPriviledge()})),this.voiceServ.onBeforeStartTalk=()=>{this.chat.playAnimation("listening"),this.playMusic("start-talk")},this.voiceServ.onAfterRecordStart=()=>{this.isRecording=!0,this.timerInt=setInterval((()=>{this.countTimer()}),1e3)},this.voiceServ.onBeforeCancelTalk=()=>{this.playMusic("interupt-talk"),this.chat.playAnimation("waiting")},this.voiceServ.onAfterCancelTalk=()=>{},this.voiceServ.onBeforeFinishTalk=()=>{this.chat.playAnimation("thinking"),this.playMusic("stop-talk")},this.voiceServ.onAfterFinishTalk=()=>{console.log("onAfterFinishTalk"),this.chat.userInput=this.voiceServ?.resultText,this.sendMessage()}}async sendMessage(){if(this.chat.userInput)this.chat?.sendMessage(this.voiceServ.resultText,this.chat?.userImage,(e=>{}),{onSSMLComplete:e=>{console.log(e);e.ssml;this.chat.playTTS(e),this.chat.playAnimation("talking"),setTimeout((()=>{this.chat.playAnimation("waiting")}),6e3)}}),this.chat.userInput="",this.chat.userImage="";else{(await this.toastCtrl.create({message:"内容不能为空",position:"top",icon:"alert",color:"warning-circle",duration:1e3})).present()}}countTimer(){this.now||(this.now=new Date);let e=(new Date).getTime()-this.now.getTime();e/=1e3,e/1e3>59&&this.send(),this.clockStr=(e/60).toFixed(0)+":"+String((e%60).toFixed(0)).padStart(2,"0")}cancel(){this.clear(),this.voiceServ.cancelTalk(),this.modal?.dismiss(null,"cancel")}send(){this.clear(),this.voiceServ.finishTalk(),this.modal?.dismiss(null,"send")}clear(){this.timerInt&&clearInterval(this.timerInt),this.now=void 0,this.isRecording=!1}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ModalAudioMessageComponent,deps:[{token:FmodeVoiceService},{token:i2$3.ToastController}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:ModalAudioMessageComponent,isStandalone:!0,selector:"fm-modal-audio-message",inputs:{chat:"chat",modal:"modal"},providers:[ModalController$1],ngImport:i0,template:'\x3c!-- <div style="background:#FFFFFF;color:#000000;width:100%">\n {{this.chat.userInput}}\n</div> --\x3e\n<div class="modal-area">\n\n \x3c!-- 加载WebSockets动画 --\x3e\n <ng-container *ngIf="!isRecording">\n <div class="row">\n <ion-spinner name="crescent" color="success" style="width:80px;height:80px;"></ion-spinner>\n </div>\n </ng-container>\n \x3c!-- 录音中动画 --\x3e\n <ng-container *ngIf="isRecording">\n <div class="tips row">\n 请您讲话,AI会识别!\n </div>\n <div class="timer row">\n {{clockStr || "0:00"}}\n </div>\n <div class="audio-wave row">\n <div class="audio">\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n </div>\n </div>\n <div class="actions row">\n <ion-button (click)="cancel()" size="large" shape="round" color="light">\n <ion-icon name="close-outline"></ion-icon>\n </ion-button>\n <ion-button (click)="send()" size="large" shape="round" color="success">\n <ion-icon name="send-outline"></ion-icon>\n </ion-button>\n </div>\n </ng-container>\n</div>',styles:[":host-context(body.dark) .modal-area{color:#fff}.modal-area{display:flex;flex-direction:column;justify-content:center;align-items:center;width:100%;height:100%}.modal-area .row{margin:10px}.modal-area .timer{font-size:1.5rem;font-weight:700}.modal-area .actions{display:flex;justify-content:space-around;width:100%;height:86px}.audio{display:flex;justify-content:space-between;align-items:center;gap:8px;width:60px;height:40px}.audio .wave{height:40px;display:block;width:10px;height:6px;border-radius:8px;background:orange}.audio .wave{animation:audio-wave 2s ease-in-out infinite}.audio .wave:nth-child(1){animation-delay:.1s}.audio .wave:nth-child(2){animation-delay:.2s}.audio .wave:nth-child(3){animation-delay:.3s}.audio .wave:nth-child(4){animation-delay:.4s}.audio .wave:nth-child(5){animation-delay:.5s}@keyframes audio-wave{0%{height:6px;transform:translateY(0);background:#ff8e3a}25%{height:6px;transform:translateY(0);background:#9c73f8}50%{height:30px;transform:translateY(-5px) scaleY(1.5);background:#ed509e}75%{height:6px;transform:translateY(0);background:#9c73f8}to{height:6px;transform:translateY(0);background:#0fccce}}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:IonSpinner,selector:"ion-spinner",inputs:["color","duration","name","paused"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ModalAudioMessageComponent,decorators:[{type:Component,args:[{selector:"fm-modal-audio-message",standalone:!0,imports:[CommonModule,IonButton,IonIcon,IonSpinner],providers:[ModalController$1],template:'\x3c!-- <div style="background:#FFFFFF;color:#000000;width:100%">\n {{this.chat.userInput}}\n</div> --\x3e\n<div class="modal-area">\n\n \x3c!-- 加载WebSockets动画 --\x3e\n <ng-container *ngIf="!isRecording">\n <div class="row">\n <ion-spinner name="crescent" color="success" style="width:80px;height:80px;"></ion-spinner>\n </div>\n </ng-container>\n \x3c!-- 录音中动画 --\x3e\n <ng-container *ngIf="isRecording">\n <div class="tips row">\n 请您讲话,AI会识别!\n </div>\n <div class="timer row">\n {{clockStr || "0:00"}}\n </div>\n <div class="audio-wave row">\n <div class="audio">\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n </div>\n </div>\n <div class="actions row">\n <ion-button (click)="cancel()" size="large" shape="round" color="light">\n <ion-icon name="close-outline"></ion-icon>\n </ion-button>\n <ion-button (click)="send()" size="large" shape="round" color="success">\n <ion-icon name="send-outline"></ion-icon>\n </ion-button>\n </div>\n </ng-container>\n</div>',styles:[":host-context(body.dark) .modal-area{color:#fff}.modal-area{display:flex;flex-direction:column;justify-content:center;align-items:center;width:100%;height:100%}.modal-area .row{margin:10px}.modal-area .timer{font-size:1.5rem;font-weight:700}.modal-area .actions{display:flex;justify-content:space-around;width:100%;height:86px}.audio{display:flex;justify-content:space-between;align-items:center;gap:8px;width:60px;height:40px}.audio .wave{height:40px;display:block;width:10px;height:6px;border-radius:8px;background:orange}.audio .wave{animation:audio-wave 2s ease-in-out infinite}.audio .wave:nth-child(1){animation-delay:.1s}.audio .wave:nth-child(2){animation-delay:.2s}.audio .wave:nth-child(3){animation-delay:.3s}.audio .wave:nth-child(4){animation-delay:.4s}.audio .wave:nth-child(5){animation-delay:.5s}@keyframes audio-wave{0%{height:6px;transform:translateY(0);background:#ff8e3a}25%{height:6px;transform:translateY(0);background:#9c73f8}50%{height:30px;transform:translateY(-5px) scaleY(1.5);background:#ed509e}75%{height:6px;transform:translateY(0);background:#9c73f8}to{height:6px;transform:translateY(0);background:#0fccce}}\n"]}]}],ctorParameters:()=>[{type:FmodeVoiceService},{type:i2$3.ToastController}],propDecorators:{chat:[{type:Input}],modal:[{type:Input}]}});class FmChatModalInput{closeAudio(){this.audioComp?.cancel(),this.isAudioModal=!1}constructor(e,t,n,o,i,a,r,s){this.toastCtrl=e,this.alertCtrl=t,this.navCtrl=n,this.router=o,this.imagineServ=i,this.chatServ=a,this.route=r,this.messages=s,this.errorText="",this.isAudioModal=!1,this.isShare=!1,this.user=Parse__default.User.current()}ngOnInit(){this.loadModel()}async loadModel(){let e=this.chat?.role?.get("model");await this.chatServ.loadModelList(e)}async setMessageImage(){let e=await this.imagineServ.getimg();this.chat.userImage=e,console.log(this.chat?.userImage)}onKeyDown(e){e.ctrlKey&&"Enter"===e.key&&(console.log("Ctrl+Enter 被按下"),this.sendMessage())}async sendMessage(){if(!this.chat.userInput){return this.errorText="内容不能为空",void(await this.toastCtrl.create({message:this.errorText,position:"top",icon:"alert",color:"warning-circle",duration:1e3})).present()}this.chat.isTalkMode=!0,this.chat?.sendMessage(this.chat?.userInput,this.chat?.userImage,(e=>{}),{onSSMLComplete:e=>{console.log(e);e.ssml;this.chat.playTTS(e),this.chat.playAnimation("talking"),setTimeout((()=>{this.chat.playAnimation("waiting")}),6e3)}}),this.chat.userInput="",this.chat.userImage=""}async checkBalance(){if(!this.chatServ?.currentModel?.get("payLimit"))return!0;let e=await this.account.getBilling();if(e?.credit?.balance<10){return(await this.alertCtrl.create({header:"注意",subHeader:"您的余额不足,请充值后解锁高级模型",buttons:[{role:"cancel",text:"取消"},{role:"destructive",text:"充值",handler:()=>{this.router.navigateByUrl("/account/billing")}}]})).present(),!1}return!0}async getChatShare(){this.user=Parse__default.User.current();let e=new Parse__default.Query("ChatShare");e.equalTo("user",Parse__default.User.current().id),e.equalTo("session",this.chat?.sessionId);await e.first()}async toggleChatShare(){let e=new Parse__default.Query("ChatShare");e.equalTo("user",Parse__default.User.current().id),e.equalTo("role",this.chat?.role.id),e.equalTo("session",this.chat?.sessionId),e.select("objectId");let t=await e.first();if(t?.id)t.set("messageList",this.chat?.messageList);else{t=new(Parse__default.Object.extend("ChatShare")),t.set("user",{__type:"Pointer",className:"_User",objectId:Parse__default.User.current()?.id}),t.set("session",{__type:"Pointer",className:"ChatSession",objectId:this.chat?.sessionId}),t.set("role",{__type:"Pointer",className:"AvatarRole",objectId:this.chat?.role.id}),t.set("company",{__type:"Pointer",className:"Company",objectId:"E4KpGvTEto"}),t.set("messageList",this.chat?.messageList)}await t.save(),this.getChatShare()}chatShareSuccessMessage(){this.messages.success("分享成功")}showShare(){this.isShare=!0}handleOkShare(){this.toggleChatShare(),this.chatShareSuccessMessage(),this.isShare=!1}handleCancelShare(){this.isShare=!1}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatModalInput,deps:[{token:i2.ToastController},{token:i2.AlertController},{token:i2.NavController},{token:i1$1.Router},{token:ImagineService},{token:ChatService},{token:i1$1.ActivatedRoute},{token:i5.NzMessageService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:FmChatModalInput,isStandalone:!0,selector:"fm-chat-modal-input",inputs:{chat:"chat",message:"message",role:"role"},viewQueries:[{propertyName:"audioComp",first:!0,predicate:ModalAudioMessageComponent,descendants:!0}],ngImport:i0,template:'<ion-toolbar>\n <ion-item class="button-item" lines="none">\n \x3c!-- 设置 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="settings-outline"></ion-icon> \n </ion-button> --\x3e\n <ng-container *ngFor="let button of chat?.leftButtons">\n <ion-button shape="round" *ngIf="button.show()" fill="outline" [title]="button?.title" slot="start" (click)="button.onClick()">\n <ion-icon [name]="button?.icon"></ion-icon>\n </ion-button>\n </ng-container>\n\n <ng-container *ngFor="let button of chat?.role?.get(\'buttons\')">\n <ion-button shape="round" (click)="chatServ.doButtonAction(button)" fill="outline" slot="start">\n {{button?.name}}\n </ion-button>\n </ng-container>\n\n \x3c!--分享按钮--\x3e\n <ion-button shape="round" *ngIf="chat?.messageList?.length>1" (click)="showShare()" fill="outline" title="分享" slot="start" routerLink="/chat/pro/mask">\n <ion-icon name="share-social-outline"></ion-icon>\n </ion-button>\n \x3c!-- <button nz-button *ngIf="chat?.messageList?.length>1"\n nzType="primary" title="分享" (click)="showShare()" style="width: 31.188px;height: 22px;box-shadow: none;background: #fff;border: 1px solid #4588ff;border-radius: 5px;"> <span class="iconfont icon-fenxiang" style="color: #4588ff;"></span></button>\n --\x3e\n <ion-modal [isOpen]="isShare">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="handleCancelShare()">取消</ion-button>\n </ion-buttons>\n <ion-title>对话分享</ion-title>\n <ion-buttons slot="end">\n <ion-button (click)="handleOkShare()">分享</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ion-content>\n </ng-template>\n </ion-modal>\n\n <nz-modal *ngIf="false"\n [(nzVisible)]="isShare"\n nzTitle="问答分享"\n nzCentered\n nzOkText="分享"\n nzCancelText="取消"\n (nzOnCancel)="handleCancelShare()"\n (nzOnOk)="handleOkShare()"\n >\n <ng-container *nzModalContent>\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ng-container>\n </nz-modal>\n\n \x3c!-- 图片 --\x3e\n <ion-button shape="round" *ngIf="chatServ?.currentModel?.get(\'config\')?.imageEnabled" fill="outline" slot="end" (click)="setMessageImage()">\n <ion-icon name="image-outline"></ion-icon>\n </ion-button>\n \x3c!-- 模型 --\x3e\n <ion-button shape="round" fill="outline" slot="end" id="model-button">\n <ion-icon name="chevron-down-outline"></ion-icon>\n {{chatServ?.currentModel?.get&&chatServ?.currentModel?.get("name")||"飞码4.0"}}\n </ion-button>\n <ion-popover trigger="model-button" [dismissOnSelect]="true">\n <ng-template>\n <ion-content>\n <ion-list>\n <ng-container *ngFor="let model of chatServ.modelList">\n <ion-item (click)="chatServ.currentModel = model" [button]="true" [detail]="false">\n {{model?.get("name")}}\n <ion-note slot="end">{{model?.get("credit")}}/k</ion-note>\n </ion-item>\n </ng-container>\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n\n </ion-item>\n\n <ion-item class="input-item" lines="none">\n \x3c!-- 语音消息输入 --\x3e\n <ng-container *ngIf="chat?.isVoiceInputMode">\n \x3c!-- 切换文本输入 --\x3e\n <ion-button class="btn-input-change" color="primary" (click)="chat.isVoiceInputMode=false" shape="round" size="large">\n <ion-icon name="chatbox-ellipses-outline" slot="icon-only"></ion-icon>\n </ion-button>\n \n <div class="btn-voice-start" (click)="isAudioModal=true">\n <span>\n 点击讲话\n </span> \n </div>\n </ng-container>\n\n \x3c!-- 文本消息输入 --\x3e\n <ng-container *ngIf="!chat?.isVoiceInputMode">\n \x3c!-- 切换语音输入 --\x3e\n <ion-button [style.display]="chat.isTexting?\'none\':\'flex\'" class="btn-input-change" color="primary" *ngIf="chat?.role?.get(\'voiceConfig\')" (click)="chat.isVoiceInputMode=true" shape="round" size="large">\n <ion-icon name="mic-outline" slot="icon-only"></ion-icon>\n </ion-button>\n\n \x3c!-- 文本输入区域 --\x3e\n <ion-textarea *ngIf="chat" (keydown)="onKeyDown($event)"\n [errorText]="errorText"\n [(ngModel)]="chat.userInput"\n (ionFocus)="chat.isTexting=true"\n (ionBlur)="chat.isTexting=false"\n [autoGrow]="true" shape="round" fill="outline"\n label="Ctrl + Enter 发送消息" placeholder="请输入您的提示词"\n labelPlacement="floating"></ion-textarea>\n \n \x3c!-- 文本发送按钮 --\x3e\n <ion-button color="primary" shape="round" size="large" (click)="sendMessage()">\n <ion-icon name="paper-plane-outline" slot="icon-only"></ion-icon>\n </ion-button>\n </ng-container>\n </ion-item>\n</ion-toolbar>\n\n\n\x3c!-- 语音消息输入:弹出区域 --\x3e\n<ion-modal #audioModal [isOpen]="isAudioModal" (willDismiss)="closeAudio()" [initialBreakpoint]="0.35" [breakpoints]="[0, 0.35, 0.5]">\n <ng-template>\n <fm-modal-audio-message #audioComp *ngIf="isAudioModal" [chat]="chat" [modal]="audioModal"></fm-modal-audio-message>\n </ng-template>\n</ion-modal>',styles:['@charset "UTF-8";:host-context(body.dark) .btn-voice-start{background-color:#222428;color:#fff}:host-context(body.dark) ion-textarea{background-color:#222428;color:#fff}ion-toolbar{--background:none}ion-toolbar .button-item{--inner-padding-start:5px;--inner-padding-end:0px;--padding-start:5px;--padding-end:0px}ion-toolbar ion-item{--background:transparent}ion-textarea.custom{--background: #373737;--color: #fff;--padding-end: 10px;--padding-start: 10px;--placeholder-color: #ddd;--placeholder-opacity: .8}ion-textarea.custom textarea{width:calc(100% - 95px)}ion-textarea.custom ion-button{position:absolute;right:0}.input-item{display:flex;min-height:77px;align-items:center;border:none;--inner-padding-start:0px;--inner-padding-end:0px;--padding-start:0px;--padding-end:0px}.input-item ion-textarea{background-color:#fff;max-height:400px;padding:0 5px;margin:0 5px;border-radius:20px;overflow-y:auto}.input-item .btn-voice-start{display:flex;flex:1;justify-content:center;align-items:center;font-weight:700;background:#fff;border-radius:20px;min-height:50px}ion-textarea{transition:width .5s ease}ion-textarea:hover .btn-input-change,ion-textarea:focus-within .btn-input-change{display:none}.input-item:hover ion-textarea,.input-item:focus-within ion-textarea{border-color:var(--logo-color-primary)}::ng-deep .ant-modal-body{max-height:600px;overflow-y:auto}::ng-deep .ant-modal-footer{display:flex;justify-content:space-around}::ng-deep .ant-btn{width:40%}.popup-content{position:relative}.popup-content .message-content-user{display:flex;justify-content:flex-end}.popup-content .message-content-role{display:flex;justify-content:flex-start}.popup-content .message-content-system{display:flex;justify-content:center}.popup-content .user-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#e7f8ff}.popup-content .role-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#f6f6f6}.popup-content .user-question{margin-bottom:5px;display:flex;justify-content:flex-end}.popup-content .chat-time{margin-bottom:10px;display:flex;justify-content:flex-end;font-size:14px;color:#a3a3a3}.popup-content .role-time{justify-content:flex-start}\n'],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:i2$2.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"pipe",type:i2$2.DatePipe,name:"date"},{kind:"ngmodule",type:FormsModule},{kind:"directive",type:i7.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:i7.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"ngmodule",type:ReactiveFormsModule},{kind:"ngmodule",type:RouterModule},{kind:"directive",type:i1$1.RouterLink,selector:"[routerLink]",inputs:["target","queryParams","fragment","queryParamsHandling","state","info","relativeTo","preserveFragment","skipLocationChange","replaceUrl","routerLink"]},{kind:"component",type:IonToolbar,selector:"ion-toolbar",inputs:["color","mode"]},{kind:"component",type:IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:IonList,selector:"ion-list",inputs:["inset","lines","mode"]},{kind:"component",type:IonModal,selector:"ion-modal"},{kind:"component",type:IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:IonTextarea,selector:"ion-textarea",inputs:["autoGrow","autocapitalize","autofocus","clearOnEdit","color","cols","counter","counterFormatter","debounce","disabled","enterkeyhint","errorText","fill","helperText","inputmode","label","labelPlacement","maxlength","minlength","mode","name","placeholder","readonly","required","rows","shape","spellcheck","value","wrap"]},{kind:"component",type:IonPopover,selector:"ion-popover"},{kind:"component",type:IonContent,selector:"ion-content",inputs:["color","fixedSlotPlacement","forceOverscroll","fullscreen","scrollEvents","scrollX","scrollY"]},{kind:"ngmodule",type:NzModalModule},{kind:"component",type:i8.NzModalComponent,selector:"nz-modal",inputs:["nzMask","nzMaskClosable","nzCloseOnNavigation","nzVisible","nzClosable","nzOkLoading","nzOkDisabled","nzCancelDisabled","nzCancelLoading","nzKeyboard","nzNoAnimation","nzCentered","nzDraggable","nzContent","nzFooter","nzZIndex","nzWidth","nzWrapClassName","nzClassName","nzStyle","nzTitle","nzCloseIcon","nzMaskStyle","nzBodyStyle","nzOkText","nzCancelText","nzOkType","nzOkDanger","nzIconType","nzModalType","nzAutofocus","nzOnOk","nzOnCancel"],outputs:["nzOnOk","nzOnCancel","nzAfterOpen","nzAfterClose","nzVisibleChange"],exportAs:["nzModal"]},{kind:"directive",type:i8.NzModalContentDirective,selector:"[nzModalContent]",exportAs:["nzModalContent"]},{kind:"component",type:ModalAudioMessageComponent,selector:"fm-modal-audio-message",inputs:["chat","modal"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatModalInput,decorators:[{type:Component,args:[{selector:"fm-chat-modal-input",standalone:!0,imports:[CommonModule,FormsModule,ReactiveFormsModule,RouterModule,IonToolbar,IonItem,IonButton,IonList,IonModal,IonInput,IonIcon,IonTextarea,IonPopover,IonContent,NzModalModule,ModalAudioMessageComponent],template:'<ion-toolbar>\n <ion-item class="button-item" lines="none">\n \x3c!-- 设置 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="settings-outline"></ion-icon> \n </ion-button> --\x3e\n <ng-container *ngFor="let button of chat?.leftButtons">\n <ion-button shape="round" *ngIf="button.show()" fill="outline" [title]="button?.title" slot="start" (click)="button.onClick()">\n <ion-icon [name]="button?.icon"></ion-icon>\n </ion-button>\n </ng-container>\n\n <ng-container *ngFor="let button of chat?.role?.get(\'buttons\')">\n <ion-button shape="round" (click)="chatServ.doButtonAction(button)" fill="outline" slot="start">\n {{button?.name}}\n </ion-button>\n </ng-container>\n\n \x3c!--分享按钮--\x3e\n <ion-button shape="round" *ngIf="chat?.messageList?.length>1" (click)="showShare()" fill="outline" title="分享" slot="start" routerLink="/chat/pro/mask">\n <ion-icon name="share-social-outline"></ion-icon>\n </ion-button>\n \x3c!-- <button nz-button *ngIf="chat?.messageList?.length>1"\n nzType="primary" title="分享" (click)="showShare()" style="width: 31.188px;height: 22px;box-shadow: none;background: #fff;border: 1px solid #4588ff;border-radius: 5px;"> <span class="iconfont icon-fenxiang" style="color: #4588ff;"></span></button>\n --\x3e\n <ion-modal [isOpen]="isShare">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="handleCancelShare()">取消</ion-button>\n </ion-buttons>\n <ion-title>对话分享</ion-title>\n <ion-buttons slot="end">\n <ion-button (click)="handleOkShare()">分享</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ion-content>\n </ng-template>\n </ion-modal>\n\n <nz-modal *ngIf="false"\n [(nzVisible)]="isShare"\n nzTitle="问答分享"\n nzCentered\n nzOkText="分享"\n nzCancelText="取消"\n (nzOnCancel)="handleCancelShare()"\n (nzOnOk)="handleOkShare()"\n >\n <ng-container *nzModalContent>\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ng-container>\n </nz-modal>\n\n \x3c!-- 图片 --\x3e\n <ion-button shape="round" *ngIf="chatServ?.currentModel?.get(\'config\')?.imageEnabled" fill="outline" slot="end" (click)="setMessageImage()">\n <ion-icon name="image-outline"></ion-icon>\n </ion-button>\n \x3c!-- 模型 --\x3e\n <ion-button shape="round" fill="outline" slot="end" id="model-button">\n <ion-icon name="chevron-down-outline"></ion-icon>\n {{chatServ?.currentModel?.get&&chatServ?.currentModel?.get("name")||"飞码4.0"}}\n </ion-button>\n <ion-popover trigger="model-button" [dismissOnSelect]="true">\n <ng-template>\n <ion-content>\n <ion-list>\n <ng-container *ngFor="let model of chatServ.modelList">\n <ion-item (click)="chatServ.currentModel = model" [button]="true" [detail]="false">\n {{model?.get("name")}}\n <ion-note slot="end">{{model?.get("credit")}}/k</ion-note>\n </ion-item>\n </ng-container>\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n\n </ion-item>\n\n <ion-item class="input-item" lines="none">\n \x3c!-- 语音消息输入 --\x3e\n <ng-container *ngIf="chat?.isVoiceInputMode">\n \x3c!-- 切换文本输入 --\x3e\n <ion-button class="btn-input-change" color="primary" (click)="chat.isVoiceInputMode=false" shape="round" size="large">\n <ion-icon name="chatbox-ellipses-outline" slot="icon-only"></ion-icon>\n </ion-button>\n \n <div class="btn-voice-start" (click)="isAudioModal=true">\n <span>\n 点击讲话\n </span> \n </div>\n </ng-container>\n\n \x3c!-- 文本消息输入 --\x3e\n <ng-container *ngIf="!chat?.isVoiceInputMode">\n \x3c!-- 切换语音输入 --\x3e\n <ion-button [style.display]="chat.isTexting?\'none\':\'flex\'" class="btn-input-change" color="primary" *ngIf="chat?.role?.get(\'voiceConfig\')" (click)="chat.isVoiceInputMode=true" shape="round" size="large">\n <ion-icon name="mic-outline" slot="icon-only"></ion-icon>\n </ion-button>\n\n \x3c!-- 文本输入区域 --\x3e\n <ion-textarea *ngIf="chat" (keydown)="onKeyDown($event)"\n [errorText]="errorText"\n [(ngModel)]="chat.userInput"\n (ionFocus)="chat.isTexting=true"\n (ionBlur)="chat.isTexting=false"\n [autoGrow]="true" shape="round" fill="outline"\n label="Ctrl + Enter 发送消息" placeholder="请输入您的提示词"\n labelPlacement="floating"></ion-textarea>\n \n \x3c!-- 文本发送按钮 --\x3e\n <ion-button color="primary" shape="round" size="large" (click)="sendMessage()">\n <ion-icon name="paper-plane-outline" slot="icon-only"></ion-icon>\n </ion-button>\n </ng-container>\n </ion-item>\n</ion-toolbar>\n\n\n\x3c!-- 语音消息输入:弹出区域 --\x3e\n<ion-modal #audioModal [isOpen]="isAudioModal" (willDismiss)="closeAudio()" [initialBreakpoint]="0.35" [breakpoints]="[0, 0.35, 0.5]">\n <ng-template>\n <fm-modal-audio-message #audioComp *ngIf="isAudioModal" [chat]="chat" [modal]="audioModal"></fm-modal-audio-message>\n </ng-template>\n</ion-modal>',styles:['@charset "UTF-8";:host-context(body.dark) .btn-voice-start{background-color:#222428;color:#fff}:host-context(body.dark) ion-textarea{background-color:#222428;color:#fff}ion-toolbar{--background:none}ion-toolbar .button-item{--inner-padding-start:5px;--inner-padding-end:0px;--padding-start:5px;--padding-end:0px}ion-toolbar ion-item{--background:transparent}ion-textarea.custom{--background: #373737;--color: #fff;--padding-end: 10px;--padding-start: 10px;--placeholder-color: #ddd;--placeholder-opacity: .8}ion-textarea.custom textarea{width:calc(100% - 95px)}ion-textarea.custom ion-button{position:absolute;right:0}.input-item{display:flex;min-height:77px;align-items:center;border:none;--inner-padding-start:0px;--inner-padding-end:0px;--padding-start:0px;--padding-end:0px}.input-item ion-textarea{background-color:#fff;max-height:400px;padding:0 5px;margin:0 5px;border-radius:20px;overflow-y:auto}.input-item .btn-voice-start{display:flex;flex:1;justify-content:center;align-items:center;font-weight:700;background:#fff;border-radius:20px;min-height:50px}ion-textarea{transition:width .5s ease}ion-textarea:hover .btn-input-change,ion-textarea:focus-within .btn-input-change{display:none}.input-item:hover ion-textarea,.input-item:focus-within ion-textarea{border-color:var(--logo-color-primary)}::ng-deep .ant-modal-body{max-height:600px;overflow-y:auto}::ng-deep .ant-modal-footer{display:flex;justify-content:space-around}::ng-deep .ant-btn{width:40%}.popup-content{position:relative}.popup-content .message-content-user{display:flex;justify-content:flex-end}.popup-content .message-content-role{display:flex;justify-content:flex-start}.popup-content .message-content-system{display:flex;justify-content:center}.popup-content .user-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#e7f8ff}.popup-content .role-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#f6f6f6}.popup-content .user-question{margin-bottom:5px;display:flex;justify-content:flex-end}.popup-content .chat-time{margin-bottom:10px;display:flex;justify-content:flex-end;font-size:14px;color:#a3a3a3}.popup-content .role-time{justify-content:flex-start}\n']}]}],ctorParameters:()=>[{type:i2.ToastController},{type:i2.AlertController},{type:i2.NavController},{type:i1$1.Router},{type:ImagineService},{type:ChatService},{type:i1$1.ActivatedRoute},{type:i5.NzMessageService}],propDecorators:{audioComp:[{type:ViewChild,args:[ModalAudioMessageComponent]}],chat:[{type:Input}],message:[{type:Input}],role:[{type:Input}]}});class ChatPanelComponent{constructor(e,t,n){this.route=e,this.router=t,this.chatServ=n,window.location.pathname?.indexOf("chat/session")>-1&&document.body.classList.add("dark")}listenDivChange(){let e=new MutationObserver((()=>{this.scrollToBottom(this.contentComp)})),t={childList:!0,subtree:!0,attributes:!0};this.contentComp?.nativeElement&&e.observe(this.contentComp?.nativeElement,t)}scrollToBottom(e){e?.nativeElement?.scrollHeight&&(e.nativeElement.scrollTop=e.nativeElement.scrollHeight)}ngAfterViewInit(){}ngOnInit(){combineLatest([this.route.params,this.route.queryParams]).subscribe((async e=>{let t=e[0];e[1];if(console.log("params",e),this.chatId=t?.chatId||this.chatId||null,this.chatId&&await this.chatServ.initChatMap(this.chatId),this.roleId=t?.roleId||this.roleId||null,this.roleId){let e=await this.chatServ.createNewRoleChat(this.roleId);this.fmodeChat=e}this.chatId&&(this.fmodeChat=this.chatServ.chatMap[this.chatId],this.fmodeChat||this.router.navigate(["/chat/pro/mask"],{queryParams:{type:"employee"}}),this.fmodeChat=this.chatServ.chatMap[this.chatId]),this.leftButtons&&(this.fmodeChat.leftButtons=this.leftButtons),window.location.pathname?.indexOf("chat/session")>-1?this.fmodeChat.isVoiceInputMode=!0:this.fmodeChat.isVoiceInputMode=!1,this.modelList&&(this.chatServ.modelList=this.modelList,this.chatServ.currentModel=this.modelList[0]),setTimeout((()=>{this.listenDivChange()}),1e3)}))}loadMask(){}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatPanelComponent,deps:[{token:i1$1.ActivatedRoute},{token:i1$1.Router},{token:ChatService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:ChatPanelComponent,isStandalone:!0,selector:"app-chat-panel",inputs:{chatId:"chatId",maskId:"maskId",roleId:"roleId",leftButtons:"leftButtons",modelList:"modelList"},viewQueries:[{propertyName:"contentComp",first:!0,predicate:["contentComp"],descendants:!0}],ngImport:i0,template:'\n\x3c!-- <ion-header></ion-header> --\x3e\n\x3c!-- <ion-content class="ion-padding"> --\x3e\n <div class="chat-page" *ngIf="fmodeChat">\n <div class="header" [class.avatarHeader]="fmodeChat?.isAvatarShow">\n <fm-chat-header-area [chat]="fmodeChat"></fm-chat-header-area>\n </div>\n \n <div class="content" #contentComp>\n <fm-chat-message-area [chat]="fmodeChat"></fm-chat-message-area>\n </div>\n \n <div class="footer">\n <fm-chat-modal-input [chat]="fmodeChat"></fm-chat-modal-input>\n </div>\n </div>\n\n\x3c!-- </ion-content> --\x3e',styles:[".chat-page{display:flex;flex-direction:column;height:100%;background:#f3f3f3}.chat-page .content,.chat-page .header,.chat-page .footer{justify-content:center;align-items:center}.chat-page .content{flex-grow:1;flex:1;overflow-y:auto}.chat-page .avatarHeader{height:35vh!important;overflow:hidden}.chat-page .header{height:44px;margin-bottom:-1px}.chat-page .footer{height:auto;min-height:130px}:host-context(body.dark) .chat-page{background:#000}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:FmChatHeaderArea,selector:"fm-chat-header-area",inputs:["chat"]},{kind:"component",type:FmChatMesssageArea,selector:"fm-chat-message-area",inputs:["chatId","chat"]},{kind:"component",type:FmChatModalInput,selector:"fm-chat-modal-input",inputs:["chat","message","role"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatPanelComponent,decorators:[{type:Component,args:[{selector:"app-chat-panel",standalone:!0,imports:[CommonModule,FmChatHeaderArea,FmChatMesssageArea,FmChatModalInput],template:'\n\x3c!-- <ion-header></ion-header> --\x3e\n\x3c!-- <ion-content class="ion-padding"> --\x3e\n <div class="chat-page" *ngIf="fmodeChat">\n <div class="header" [class.avatarHeader]="fmodeChat?.isAvatarShow">\n <fm-chat-header-area [chat]="fmodeChat"></fm-chat-header-area>\n </div>\n \n <div class="content" #contentComp>\n <fm-chat-message-area [chat]="fmodeChat"></fm-chat-message-area>\n </div>\n \n <div class="footer">\n <fm-chat-modal-input [chat]="fmodeChat"></fm-chat-modal-input>\n </div>\n </div>\n\n\x3c!-- </ion-content> --\x3e',styles:[".chat-page{display:flex;flex-direction:column;height:100%;background:#f3f3f3}.chat-page .content,.chat-page .header,.chat-page .footer{justify-content:center;align-items:center}.chat-page .content{flex-grow:1;flex:1;overflow-y:auto}.chat-page .avatarHeader{height:35vh!important;overflow:hidden}.chat-page .header{height:44px;margin-bottom:-1px}.chat-page .footer{height:auto;min-height:130px}:host-context(body.dark) .chat-page{background:#000}\n"]}]}],ctorParameters:()=>[{type:i1$1.ActivatedRoute},{type:i1$1.Router},{type:ChatService}],propDecorators:{chatId:[{type:Input}],maskId:[{type:Input}],roleId:[{type:Input}],leftButtons:[{type:Input}],modelList:[{type:Input}],contentComp:[{type:ViewChild,args:["contentComp"]}]}}),window._AMapSecurityConfig={securityJsCode:"32aa3f4ab0fa0061de03edd4eafdd50a"};class PageMapStartComponent{constructor(){this.placeList=[{name:"江财蛟桥校区",location:[115.855125,28.744335]},{name:"江财枫林校区",location:[115.835639,28.734119]},{name:"江财麦庐校区",location:[115.816717,28.728899]}]}ngAfterViewInit(){this.initMap()}async initMap(){await this.createMap(),this.goAndMarkPlace(this.placeList[1])}async createMap(){this.AMap=await AMapLoader.load({key:"473b52010df7d3a32db0a2f5db245c8e",version:"2.0"}),this.map=new this.AMap.Map("container")}async addMarks(){let e=new this.AMap.Marker({position:[115.835639,28.734119]});this.map.add(e)}goAndMarkPlace(e){this.map.setCenter(e.location),this.map.setZoom(18),console.log(this.placeList),e.marker||(e.marker=new this.AMap.Marker({position:e.location}),this.map.add(e.marker))}clearMark(e){e?.marker?.remove()}planRoute(e,t){let n;this.map.plugin(["AMap.Transfer"],(()=>{let o={map:this.map,city:"南昌市",panel:"panel",policy:this.AMap.TransferPolicy.LEAST_TIME};console.log(this.AMap),console.log(this.AMap.TransferPolicy),n=new this.AMap.Transfer(o),n.search(new this.AMap.LngLat(e.location[0],e.location[1]),new this.AMap.LngLat(t.location[0],t.location[1]),((e,t)=>{"complete"===e?(console.log("绘制公交路线完成:"),console.log(t)):console.error("公交路线数据查询失败"+t)}))}))}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:PageMapStartComponent,deps:[],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:PageMapStartComponent,selector:"app-page-map.start",ngImport:i0,template:'\x3c!-- 全屏地图 --\x3e\n<div id="container"></div>\n\n\x3c!-- 右侧地点 --\x3e\n<div class="place-list">\n <ng-container *ngFor="let place of placeList">\n <div class="place-item" (click)="goAndMarkPlace(place)">\n {{place.name}}\n <button (click)="clearMark(place)">清除标记</button>\n </div>\n </ng-container>\n\n <button (click)="planRoute(placeList[0],placeList[1])">从蛟桥到枫林</button>\n \n</div>',styles:["#container{width:100%;height:100%;position:fixed}.place-list{display:flex;flex-direction:column;position:fixed;justify-content:center;align-items:center;height:80%;width:200px}.place-list .place-item{background-color:#ffffff4d;height:100px;width:90%}\n"],dependencies:[{kind:"directive",type:i2$2.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:PageMapStartComponent,decorators:[{type:Component,args:[{selector:"app-page-map.start",template:'\x3c!-- 全屏地图 --\x3e\n<div id="container"></div>\n\n\x3c!-- 右侧地点 --\x3e\n<div class="place-list">\n <ng-container *ngFor="let place of placeList">\n <div class="place-item" (click)="goAndMarkPlace(place)">\n {{place.name}}\n <button (click)="clearMark(place)">清除标记</button>\n </div>\n </ng-container>\n\n <button (click)="planRoute(placeList[0],placeList[1])">从蛟桥到枫林</button>\n \n</div>',styles:["#container{width:100%;height:100%;position:fixed}.place-list{display:flex;flex-direction:column;position:fixed;justify-content:center;align-items:center;height:80%;width:200px}.place-list .place-item{background-color:#ffffff4d;height:100px;width:90%}\n"]}]}]}),window._AMapSecurityConfig={securityJsCode:"32aa3f4ab0fa0061de03edd4eafdd50a"};class CompPoiPickerComponent{get name(){return this._name}set name(e){this._name=e,this.nameChange.emit(e)}get address(){return this._address}set address(e){this._address=e,this.addressChange.emit(e)}get location(){return this._location}set location(e){this._location=e,this.locationChange.emit(e)}constructor(){this.nameChange=new EventEmitter,this.addressChange=new EventEmitter,this.locationChange=new EventEmitter,this.isModalOpen=!1}cancel(){this.isModalOpen=!1,this.modal.dismiss(null,"cancel")}confirm(){this.isModalOpen=!1,this.modal.dismiss(this.address,"confirm")}onWillDismiss(e){"confirm"===e.detail.role&&console.log("确认")}openModal(){this.isModalOpen=!0,setTimeout((()=>{this.initMap()}),800)}ngAfterViewInit(){}initMap(){this.createMap()}async createMap(){this.AMap=await AMapLoader.load({key:"473b52010df7d3a32db0a2f5db245c8e",version:"2.0"});let e=this.container.nativeElement;this.map=new this.AMap.Map(e),this.goCurrentCenter()}goCurrentCenter(){this.AMap.plugin(["AMap.Geolocation"],(()=>{let e=new this.AMap.Geolocation({enableHighAccuracy:!0,timeout:1e4,maximumAge:0,convert:!0,showButton:!0,buttonPosition:"RB",buttonOffset:new this.AMap.Pixel(10,10),showMarker:!1,showCircle:!1,panToLocation:!0,zoomToAccuracy:!1});this.map.addControl(e),e.getCurrentPosition((function(e,t){"complete"===e?(console.log("当前位置经度:"+t.position.getLng()),console.log("当前位置纬度:"+t.position.getLat())):console.log("定位失败:"+t.message)}))}))}searchByAddress(){let e=this.panel.nativeElement;this.AMap.plugin(["AMap.PlaceSearch"],(()=>{let t=new this.AMap.PlaceSearch({pageSize:3,pageIndex:1,map:this.map,panel:e,autoFitView:!0});t.on("selectChanged",(e=>{this.name=e.selected.data.name,this.address=e.selected.data.address,this.location=new Parse__default.GeoPoint({latitude:e.selected.data.location.lat,longitude:e.selected.data.location.lng}),this.createCenterMarker()})),t.search(this.address)}))}createCenterMarker(){this.centerMarker||(this.centerMarker=new this.AMap.Marker({position:this.map.getCenter(),offset:new this.AMap.Pixel(-15,-15)}),this.map.add(this.centerMarker),this.map.on("dragging",(()=>{this.centerMarker.setPosition(this.map.getCenter())})),this.map.on("dragend",(()=>{let e=this.centerMarker.getPosition();this.location=new Parse__default.GeoPoint({latitude:e.lat,longitude:e.lng})})))}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompPoiPickerComponent,deps:[],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:CompPoiPickerComponent,selector:"fm-map-poi-picker",inputs:{_name:["name","_name"],_address:["address","_address"],_location:["location","_location"]},outputs:{nameChange:"nameChange",addressChange:"addressChange",locationChange:"locationChange"},viewQueries:[{propertyName:"container",first:!0,predicate:["container"],descendants:!0},{propertyName:"panel",first:!0,predicate:["panel"],descendants:!0},{propertyName:"modal",first:!0,predicate:IonModal$1,descendants:!0}],ngImport:i0,template:'\x3c!-- 未选点 --\x3e\n<ion-button (click)="openModal()" expand="block">开始选点</ion-button>\n\n\x3c!-- 已选点 --\x3e\n\n<ion-modal [isOpen]="isModalOpen" (willDismiss)="onWillDismiss($event)">\n<ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="cancel()">Cancel</ion-button>\n </ion-buttons>\n <ion-title>地图选点<ng-container *ngIf="location">({{location.latitude}},{{location.longitude}})</ng-container></ion-title>\n <ion-buttons slot="end">\n <ion-button (click)="confirm()" [strong]="true">Confirm</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding" style="height:100%">\n \x3c!-- 详细地址 --\x3e\n <ion-item>\n <ion-input\n label="请输入详细地址"\n labelPlacement="stacked"\n type="text"\n placeholder="精确到门牌号"\n [(ngModel)]="address"\n ></ion-input>\n <ion-button slot="end" (click)="searchByAddress()">搜索</ion-button>\n </ion-item>\n \n \x3c!-- 地图选点 --\x3e\n <div #container class="container"></div>\n <div #panel class="panel"></div>\n\n </ion-content>\n</ng-template>\n</ion-modal>\n\n',styles:[".container{width:100%;height:100%}.panel{position:absolute;background-color:#fff;max-height:50%;overflow-y:auto;top:12%;right:10px;width:45%}\n"],dependencies:[{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:i7.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:i7.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"component",type:i2.IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:i2.IonButtons,selector:"ion-buttons",inputs:["collapse"]},{kind:"component",type:i2.IonContent,selector:"ion-content",inputs:["color","fixedSlotPlacement","forceOverscroll","fullscreen","scrollEvents","scrollX","scrollY"]},{kind:"component",type:i2.IonHeader,selector:"ion-header",inputs:["collapse","mode","translucent"]},{kind:"component",type:i2.IonInput,selector:"ion-input",inputs:["autocapitalize","autocomplete","autocorrect","autofocus","clearInput","clearInputIcon","clearOnEdit","color","counter","counterFormatter","debounce","disabled","enterkeyhint","errorText","fill","helperText","inputmode","label","labelPlacement","max","maxlength","min","minlength","mode","multiple","name","pattern","placeholder","readonly","required","shape","spellcheck","step","type","value"]},{kind:"component",type:i2.IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:i2.IonTitle,selector:"ion-title",inputs:["color","size"]},{kind:"component",type:i2.IonToolbar,selector:"ion-toolbar",inputs:["color","mode"]},{kind:"component",type:i2.IonModal,selector:"ion-modal"},{kind:"directive",type:i2.TextValueAccessor,selector:"ion-input:not([type=number]),ion-textarea,ion-searchbar"}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompPoiPickerComponent,decorators:[{type:Component,args:[{selector:"fm-map-poi-picker",template:'\x3c!-- 未选点 --\x3e\n<ion-button (click)="openModal()" expand="block">开始选点</ion-button>\n\n\x3c!-- 已选点 --\x3e\n\n<ion-modal [isOpen]="isModalOpen" (willDismiss)="onWillDismiss($event)">\n<ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="cancel()">Cancel</ion-button>\n </ion-buttons>\n <ion-title>地图选点<ng-container *ngIf="location">({{location.latitude}},{{location.longitude}})</ng-container></ion-title>\n <ion-buttons slot="end">\n <ion-button (click)="confirm()" [strong]="true">Confirm</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding" style="height:100%">\n \x3c!-- 详细地址 --\x3e\n <ion-item>\n <ion-input\n label="请输入详细地址"\n labelPlacement="stacked"\n type="text"\n placeholder="精确到门牌号"\n [(ngModel)]="address"\n ></ion-input>\n <ion-button slot="end" (click)="searchByAddress()">搜索</ion-button>\n </ion-item>\n \n \x3c!-- 地图选点 --\x3e\n <div #container class="container"></div>\n <div #panel class="panel"></div>\n\n </ion-content>\n</ng-template>\n</ion-modal>\n\n',styles:[".container{width:100%;height:100%}.panel{position:absolute;background-color:#fff;max-height:50%;overflow-y:auto;top:12%;right:10px;width:45%}\n"]}]}],ctorParameters:()=>[],propDecorators:{container:[{type:ViewChild,args:["container"]}],panel:[{type:ViewChild,args:["panel"]}],_name:[{type:Input,args:["name"]}],nameChange:[{type:Output}],_address:[{type:Input,args:["address"]}],addressChange:[{type:Output}],_location:[{type:Input,args:["location"]}],locationChange:[{type:Output}],modal:[{type:ViewChild,args:[IonModal$1]}]}});class CompPoiPickerModule{static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompPoiPickerModule,deps:[],target:i0.ɵɵFactoryTarget.NgModule})}static{this.ɵmod=i0.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:CompPoiPickerModule,declarations:[CompPoiPickerComponent],imports:[CommonModule,FormsModule,ReactiveFormsModule,i2.IonicModule],exports:[CompPoiPickerComponent]})}static{this.ɵinj=i0.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompPoiPickerModule,imports:[CommonModule,FormsModule,ReactiveFormsModule,IonicModule.forRoot({mode:"ios"})]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompPoiPickerModule,decorators:[{type:NgModule,args:[{declarations:[CompPoiPickerComponent],imports:[CommonModule,FormsModule,ReactiveFormsModule,IonicModule.forRoot({mode:"ios"})],exports:[CompPoiPickerComponent]}]}]}),window._AMapSecurityConfig={securityJsCode:"32aa3f4ab0fa0061de03edd4eafdd50a"};class PagePlanRouteComponent{constructor(){this.placeList=[],this.currentTab="place",this.addNewPlace(),this.addNewPlace(),this.currentTab="plan"}addNewPlace(){this.placeList?.length>=1?this.placeList.push({name:"秋水广场",address:"南昌市秋水广场",location:new Parse__default.GeoPoint({latitude:28.682634,longitude:115.86273})}):this.placeList.push({name:"八一广场",address:"南昌市八一广场",location:new Parse__default.GeoPoint({latitude:28.673856,longitude:115.904477})})}ngAfterViewInit(){}async initMap(){await this.createMap(),this.goAndMarkPlace(this.placeList[0])}async createMap(){this.AMap=await AMapLoader.load({key:"473b52010df7d3a32db0a2f5db245c8e",version:"2.0"}),this.map=new this.AMap.Map("container-plan")}goAndMarkPlace(e){this.map.setCenter([e.location.latitude,e.location.longitude]),this.map.setZoom(18),e.marker||(e.marker=new this.AMap.Marker({position:[e.location.latitude,e.location.longitude]}),this.map.add(e.marker))}clearMark(e){e?.marker?.remove()}planRoute(e,t){let n;this.map.plugin(["AMap.Transfer"],(()=>{let o={map:this.map,city:"南昌市",panel:"panel",policy:this.AMap.TransferPolicy.LEAST_TIME};n=new this.AMap.Transfer(o);let i=new this.AMap.LngLat(e.location.longitude,e.location.latitude),a=new this.AMap.LngLat(t.location.longitude,t.location.latitude);n.search(i,a,((e,t)=>{"complete"===e?(console.log("绘制公交路线完成:"),console.log(t)):console.error("公交路线数据查询失败"+t)}))}))}async createPlan(){await this.initMap(),this.planRoute(this.placeList[0],this.placeList[1])}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:PagePlanRouteComponent,deps:[],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:PagePlanRouteComponent,selector:"app-page-plan-route",ngImport:i0,template:'<ion-segment value="place">\n <ion-segment-button (click)="currentTab=\'place\'" value="place">\n <ion-label>景点选择</ion-label>\n </ion-segment-button>\n <ion-segment-button (click)="currentTab=\'plan\'" value="plan">\n <ion-label>路线规划</ion-label>\n </ion-segment-button>\n </ion-segment>\n \n\n<ng-container *ngIf="currentTab==\'place\'">\n <h1>选择旅游计划景点</h1>\n\n <ng-container *ngFor="let place of placeList">\n <ion-card>\n <h2>{{place?.name}}</h2>\n <span *ngIf="place.address">详细地址:{{place.address}}</span>\n <span *ngIf="place.location">地图坐标:{{place.location.latitude}},{{place.location.longitude}}</span>\n <fm-map-poi-picker [(name)]="place.name" [(address)]="place.address" [(location)]="place.location"></fm-map-poi-picker>\n </ion-card>\n </ng-container>\n <ion-button (click)="addNewPlace()" expand="block">添加新景点</ion-button>\n</ng-container>\n\n<ng-container *ngIf="currentTab==\'plan\'">\n <ion-button (click)="createPlan()" expand="block">创建规划路线</ion-button>\n\n <div id="container-plan"></div>\n <div id="panel"></div>\n</ng-container>\n\n',styles:["#container-plan{width:100%;height:40%}#panel{width:100%;height:50%}\n"],dependencies:[{kind:"directive",type:i2$2.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:i2.IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:i2.IonCard,selector:"ion-card",inputs:["button","color","disabled","download","href","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:i2.IonLabel,selector:"ion-label",inputs:["color","mode","position"]},{kind:"component",type:i2.IonSegment,selector:"ion-segment",inputs:["color","disabled","mode","scrollable","selectOnFocus","swipeGesture","value"]},{kind:"component",type:i2.IonSegmentButton,selector:"ion-segment-button",inputs:["disabled","layout","mode","type","value"]},{kind:"directive",type:i2.SelectValueAccessor,selector:"ion-select, ion-radio-group, ion-segment, ion-datetime"},{kind:"component",type:CompPoiPickerComponent,selector:"fm-map-poi-picker",inputs:["name","address","location"],outputs:["nameChange","addressChange","locationChange"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:PagePlanRouteComponent,decorators:[{type:Component,args:[{selector:"app-page-plan-route",template:'<ion-segment value="place">\n <ion-segment-button (click)="currentTab=\'place\'" value="place">\n <ion-label>景点选择</ion-label>\n </ion-segment-button>\n <ion-segment-button (click)="currentTab=\'plan\'" value="plan">\n <ion-label>路线规划</ion-label>\n </ion-segment-button>\n </ion-segment>\n \n\n<ng-container *ngIf="currentTab==\'place\'">\n <h1>选择旅游计划景点</h1>\n\n <ng-container *ngFor="let place of placeList">\n <ion-card>\n <h2>{{place?.name}}</h2>\n <span *ngIf="place.address">详细地址:{{place.address}}</span>\n <span *ngIf="place.location">地图坐标:{{place.location.latitude}},{{place.location.longitude}}</span>\n <fm-map-poi-picker [(name)]="place.name" [(address)]="place.address" [(location)]="place.location"></fm-map-poi-picker>\n </ion-card>\n </ng-container>\n <ion-button (click)="addNewPlace()" expand="block">添加新景点</ion-button>\n</ng-container>\n\n<ng-container *ngIf="currentTab==\'plan\'">\n <ion-button (click)="createPlan()" expand="block">创建规划路线</ion-button>\n\n <div id="container-plan"></div>\n <div id="panel"></div>\n</ng-container>\n\n',styles:["#container-plan{width:100%;height:40%}#panel{width:100%;height:50%}\n"]}]}],ctorParameters:()=>[]}),window._AMapSecurityConfig={securityJsCode:"32aa3f4ab0fa0061de03edd4eafdd50a"};class PageLocaScatterComponent{ngAfterViewInit(){this.initMap()}async initMap(){await this.createMap(),await this.createLoca()}async createLoca(){let e=window.loca=new Loca.Container({map:this.map}),t=new Loca.GeoJSONSource({url:"https://a.amap.com/Loca/static/loca-v2/demos/mock_data/sz_road.json"}),n=new Loca.ScatterLayer({zIndex:111,opacity:1,visible:!0,zooms:[2,22]});n.setSource(t),n.setStyle({color:"rgba(43,156,75,1)",unit:"meter",size:[150,150],borderWidth:0}),e.add(n);let o=new Loca.GeoJSONSource({url:"https://a.amap.com/Loca/static/loca-v2/demos/mock_data/sz_road_F.json"}),i=new Loca.ScatterLayer({loca:e,zIndex:113,opacity:1,visible:!0,zooms:[2,22]});i.setSource(o),i.setStyle({unit:"meter",size:[2600,2600],borderWidth:0,texture:"https://a.amap.com/Loca/static/loca-v2/demos/images/breath_red.png",duration:500,animate:!0});let a=new Loca.GeoJSONSource({url:"https://a.amap.com/Loca/static/loca-v2/demos/mock_data/sz_road_E.json"}),r=new Loca.ScatterLayer({loca:e,zIndex:112,opacity:1,visible:!0,zooms:[2,22]});r.setSource(a),r.setStyle({unit:"meter",size:[1e3,1e3],borderWidth:0,texture:"https://a.amap.com/Loca/static/loca-v2/demos/images/breath_yellow.png",duration:1e3,animate:!0}),e.animate.start();let s=new Loca.Dat;s.addLayer(n," 贴地"),s.addLayer(i,"红色"),s.addLayer(r,"黄色")}async createMap(){this.AMap=await AMapLoader.load({key:"473b52010df7d3a32db0a2f5db245c8e",version:"2.0",Loca:{version:"2.0.0"}}),this.map=new this.AMap.Map("container",{zoom:11.7,center:[113.97199630737305,22.5807295363949],pitch:40,showLabel:!1,mapStyle:"amap://styles/dark",viewMode:"3D"})}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:PageLocaScatterComponent,deps:[],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:PageLocaScatterComponent,selector:"app-page-loca-scatter",ngImport:i0,template:'<div id="container"></div>',styles:["#container{width:100%;height:100%;position:fixed}\n"]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:PageLocaScatterComponent,decorators:[{type:Component,args:[{selector:"app-page-loca-scatter",template:'<div id="container"></div>',styles:["#container{width:100%;height:100%;position:fixed}\n"]}]}]});const routes=[{path:"start",component:PageMapStartComponent},{path:"plan/route",component:PagePlanRouteComponent},{path:"loca/scatter",component:PageLocaScatterComponent}];class FmodeMapModule{static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeMapModule,deps:[],target:i0.ɵɵFactoryTarget.NgModule})}static{this.ɵmod=i0.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:FmodeMapModule,declarations:[PageMapStartComponent,PagePlanRouteComponent,PageLocaScatterComponent],imports:[CommonModule,i1$1.RouterModule,i2.IonicModule,CompPoiPickerModule],exports:[CompPoiPickerModule]})}static{this.ɵinj=i0.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeMapModule,imports:[CommonModule,RouterModule.forChild(routes),IonicModule.forRoot({mode:"ios"}),CompPoiPickerModule,CompPoiPickerModule]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeMapModule,decorators:[{type:NgModule,args:[{declarations:[PageMapStartComponent,PagePlanRouteComponent,PageLocaScatterComponent],imports:[CommonModule,RouterModule.forChild(routes),IonicModule.forRoot({mode:"ios"}),CompPoiPickerModule],exports:[CompPoiPickerModule]}]}]});class HwobsService{constructor(){this.Attachment=Parse__default.Object.extend("Attachment"),this.host="https://web3-test.obs.cn-south-1.myhuaweicloud.com/",this.bucketName="web3-test",this.obsClient=new ObsClient({access_key_id:"6UIET20WHUI5TLXWOVNA",secret_access_key:"YaoY8Kj3TeGZHEcBzplTMZiPGNL13Y3frEavC1kF",server:"https://obs.cn-south-1.myhuaweicloud.com"})}listDir(e){return new Promise(((t,n)=>{this.obsClient.listObjects({Bucket:this.bucketName,Prefix:e,Delimiter:"/"},((e,o)=>{if(e)console.error("Error--\x3e"+e),n(e);else{if(console.log("Status--\x3e"+o.CommonMsg.Status),console.log(o),o.CommonMsg.Status<300&&o.InterfaceResult)for(var i in o.InterfaceResult.Contents)console.log("Contents["+i+"]:"),console.log("Key--\x3e"+o.InterfaceResult.Contents[i].Key),console.log("Owner[ID]--\x3e"+o.InterfaceResult.Contents[i].Owner.ID);let e=o.InterfaceResult.CommonPrefixes,n=o.InterfaceResult.Contents;t({dirs:e,files:n})}}))}))}async uploadFile(e,t){let n=await this.checkFileExists(e);return n?.id?n:new Promise(((n,o)=>{this.obsClient.putObject({Bucket:this.bucketName,Key:t,SourceFile:e},(async(i,a)=>{if(i)console.error("Error--\x3e"+i),o(i);else{console.log("Status--\x3e"+a.CommonMsg.Status);let o=await this.saveAttachment(e,t);n(o)}}))}))}async checkFileExists(e){let t,n=await this.getFileHash(e),o=new Parse__default.Query("Attachment");o.equalTo("hash",n),o.equalTo("size",e.size);let i=await o.first();return i?.id||(i=new this.Attachment),t=i,t}async saveAttachment(e,t){let n=await this.getFileHash(e),o=await this.checkFileExists(e);return o.set("name",e.name),o.set("size",e.size),o.set("mime",e.type),o.set("url",this.host+t),o.set("hash",n),o=await o.save(),o}async getFileHash(e){return new Promise(((t,n)=>{const o=new FileReader;o.onload=async e=>{const n=e.target.result,o=await crypto.subtle.digest("SHA-256",n),i=Array.from(new Uint8Array(o)).map((e=>e.toString(16).padStart(2,"0"))).join("");t(i)},o.onerror=e=>{n(e.target.error)},o.readAsArrayBuffer(e)}))}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:HwobsService,deps:[],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:HwobsService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:HwobsService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[]});class HwobsManagerComponent{openFile(e){console.log("Opening file:",e)}openDir(e,t="pre"){if(e)this.prefix=e.Prefix,this.listDir(e.Prefix);else if("pre"==t){let e=this.prefix.split("/");if(e.length>1){let t=e.splice(0,e.length-1).join("/");console.log(t),this.prefix=t,this.listDir(t)}}}showName(e){return e.replaceAll(this.prefix,"")}constructor(e){this.hwobs=e,this.dirs=[],this.files=[],this.prefix="storage/",this.listDir(this.prefix)}async listDir(e){let{dirs:t,files:n}=await this.hwobs.listDir(e);this.dirs=t,this.files=n}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:HwobsManagerComponent,deps:[{token:HwobsService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:HwobsManagerComponent,isStandalone:!0,selector:"fm-storage-hwobs-manager",ngImport:i0,template:'<ion-header>\n <ion-toolbar>\n <ion-title>\n File Manager\n </ion-title>\n </ion-toolbar>\n </ion-header>\n \n <ion-content>\n <ion-list>\n <ion-item (click)="openDir(null,\'pre\')">\n <ion-icon [name]="\'folder\'" slot="start"></ion-icon>\n <ion-label>../</ion-label>\n </ion-item>\n <ion-item *ngFor="let item of dirs" (click)="openDir(item)">\n <ion-icon [name]="\'folder\'" slot="start"></ion-icon>\n <ion-label>{{ showName(item.Prefix) }}</ion-label>\n </ion-item>\n <ion-item *ngFor="let item of files" (click)="openFile(item)">\n <ion-icon [name]="\'document\'" slot="start"></ion-icon>\n <ion-label>{{ showName(item.Key) }}</ion-label>\n </ion-item>\n </ion-list>\n </ion-content>',styles:["ion-list ion-item ion-icon{font-size:24px;margin-right:8px}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"ngmodule",type:FormsModule},{kind:"ngmodule",type:ReactiveFormsModule},{kind:"ngmodule",type:IonicModule},{kind:"component",type:i2.IonContent,selector:"ion-content",inputs:["color","fixedSlotPlacement","forceOverscroll","fullscreen","scrollEvents","scrollX","scrollY"]},{kind:"component",type:i2.IonHeader,selector:"ion-header",inputs:["collapse","mode","translucent"]},{kind:"component",type:i2.IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:i2.IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:i2.IonLabel,selector:"ion-label",inputs:["color","mode","position"]},{kind:"component",type:i2.IonList,selector:"ion-list",inputs:["inset","lines","mode"]},{kind:"component",type:i2.IonTitle,selector:"ion-title",inputs:["color","size"]},{kind:"component",type:i2.IonToolbar,selector:"ion-toolbar",inputs:["color","mode"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:HwobsManagerComponent,decorators:[{type:Component,args:[{standalone:!0,imports:[CommonModule,FormsModule,ReactiveFormsModule,IonicModule],selector:"fm-storage-hwobs-manager",template:'<ion-header>\n <ion-toolbar>\n <ion-title>\n File Manager\n </ion-title>\n </ion-toolbar>\n </ion-header>\n \n <ion-content>\n <ion-list>\n <ion-item (click)="openDir(null,\'pre\')">\n <ion-icon [name]="\'folder\'" slot="start"></ion-icon>\n <ion-label>../</ion-label>\n </ion-item>\n <ion-item *ngFor="let item of dirs" (click)="openDir(item)">\n <ion-icon [name]="\'folder\'" slot="start"></ion-icon>\n <ion-label>{{ showName(item.Prefix) }}</ion-label>\n </ion-item>\n <ion-item *ngFor="let item of files" (click)="openFile(item)">\n <ion-icon [name]="\'document\'" slot="start"></ion-icon>\n <ion-label>{{ showName(item.Key) }}</ion-label>\n </ion-item>\n </ion-list>\n </ion-content>',styles:["ion-list ion-item ion-icon{font-size:24px;margin-right:8px}\n"]}]}],ctorParameters:()=>[{type:HwobsService}]});class FmodeStorgeModule{static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeStorgeModule,deps:[],target:i0.ɵɵFactoryTarget.NgModule})}static{this.ɵmod=i0.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:FmodeStorgeModule,imports:[CommonModule,i2.IonicModule,HwobsManagerComponent],exports:[HwobsManagerComponent]})}static{this.ɵinj=i0.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeStorgeModule,providers:[Diagnostic,NovaUploadService],imports:[CommonModule,IonicModule.forRoot({mode:"ios"}),HwobsManagerComponent]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeStorgeModule,decorators:[{type:NgModule,args:[{declarations:[],imports:[CommonModule,IonicModule.forRoot({mode:"ios"}),HwobsManagerComponent],exports:[HwobsManagerComponent],providers:[Diagnostic,NovaUploadService]}]}]});export{AccountService,AgentPrompt,AuthService,AvatarModule,AvatarRoutes,ChatContentPipe,ChatListComponent,ChatPanelComponent,ChatService,ClipboardService,CompAvatarParticleComponent,CompAvatarRoleImageComponent,CompAvatarRoleVideoComponent,CompAvatarTalkComponent,CompPoiPickerComponent,CompPoiPickerModule,CompRolePromptComponent,CompUserAvatarComponent,CrossService,FmChatHeaderArea,FmChatMessageCard,FmChatMesssageArea,FmChatModalInput,FmaiService,FmodeChat,FmodeChatCompletion,FmodeMapModule,FmodeStorgeModule,FmodeVoiceService,HidexmlPipe,HwobsManagerComponent,HwobsService,ImagineService,MASK_LIST,MarkdownMathJax,MarkdownParse,MarkdownPreviewComponent,MarkdownPreviewModule,ModalChatVoiceInputComponent,NovaCloudService,NovaUploadService,UtilnowPipe,getMessageContentText,getMessageImageUrl};
8
+ import*as i0 from"@angular/core";import{Injectable,Pipe,Component,Input,ViewChild,NgModule,EventEmitter,Output}from"@angular/core";import*as i1$1 from"@angular/router";import{RouterModule}from"@angular/router";import{finalize,Observable,bufferTime,concatMap,delay,combineLatest}from"rxjs";import*as Parse from"parse";import Parse__default from"parse";import{PromptTemplate}from"@langchain/core/prompts";import{SpeechSynthesizer}from"microsoft-cognitiveservices-speech-sdk/distrib/lib/src/sdk/SpeechSynthesizer";import{SpeechConfig}from"microsoft-cognitiveservices-speech-sdk/distrib/lib/src/sdk/SpeechConfig";import{ResultReason}from"microsoft-cognitiveservices-speech-sdk/distrib/lib/src/sdk/ResultReason";import*as i1 from"@angular/common/http";import{HttpHeaders,HttpClientModule}from"@angular/common/http";import*as i2 from"@ionic/angular";import{IonicModule,ModalController,IonModal as IonModal$1}from"@ionic/angular";import*as i2$2 from"@angular/common";import{DatePipe,CommonModule}from"@angular/common";import{Camera,CameraSource,CameraResultType}from"@capacitor/camera";import{Capacitor}from"@capacitor/core";import{Filesystem}from"@capacitor/filesystem";import{FilesystemWeb}from"@capacitor/filesystem/dist/esm/web.js";import*as qiniu from"qiniu-js";import*as i2$1 from"@awesome-cordova-plugins/diagnostic/ngx";import{Diagnostic}from"@awesome-cordova-plugins/diagnostic/ngx";import CryptoJS from"crypto-js";import{MediaCapture}from"@awesome-cordova-plugins/media-capture";import SparkMD5 from"spark-md5";import{mathjax}from"mathjax-full/js/mathjax";import{TeX}from"mathjax-full/js/input/tex";import{SVG}from"mathjax-full/js/output/svg";import{CHTML}from"mathjax-full/js/output/chtml";import{AllPackages}from"mathjax-full/js/input/tex/AllPackages";import{liteAdaptor}from"mathjax-full/js/adaptors/liteAdaptor";import{RegisterHTMLHandler}from"mathjax-full/js/handlers/html";import hljs from"highlight.js";import MarkdownIt from"markdown-it";import $ from"jquery";import abbr from"markdown-it-abbr";import footnote from"markdown-it-footnote";import deflist from"markdown-it-deflist";import mark from"markdown-it-mark";import ins from"markdown-it-ins";import sub from"markdown-it-sub";import sup from"markdown-it-sup";import ruby from"markdown-it-ruby";import plantumlEncoder from"plantuml-encoder";import*as i1$2 from"@angular/platform-browser";import{Clipboard}from"@capacitor/clipboard";import Recorder from"recorder-core";import"recorder-core/src/engine/pcm";import"recorder-core/src/engine/wav";import"recorder-core/src/extensions/waveview";import*as i7 from"@angular/forms";import{FormsModule,ReactiveFormsModule}from"@angular/forms";import*as BABYLON from"@babylonjs/core";import"@babylonjs/loaders";import*as i2$3 from"@ionic/angular/standalone";import{IonIcon,IonList,IonLabel,IonNote,IonAvatar,IonItem,IonText,IonButton,IonToolbar,IonButtons,IonModal,IonTitle,IonHeader,IonCard,ModalController as ModalController$1,IonSegment,IonSpinner,IonTextarea,IonPopover,IonContent,IonInput}from"@ionic/angular/standalone";import*as i3 from"ng-zorro-antd/avatar";import{NzAvatarModule}from"ng-zorro-antd/avatar";import{catchError}from"rxjs/operators";import{NzSanitizerPipe}from"ng-zorro-antd/pipes";import*as i5 from"ng-zorro-antd/icon";import{NzIconModule}from"ng-zorro-antd/icon";import*as i5$1 from"ng-zorro-antd/message";import*as i8 from"ng-zorro-antd/modal";import{NzModalModule}from"ng-zorro-antd/modal";import*as AMapLoader from"@amap/amap-jsapi-loader";import ObsClient from"esdk-obs-browserjs";class AgentPrompt{constructor(){}jsonCompletion(e,t){let n,o=new FmodeChatCompletion([{role:"user",content:e}]);return o.model=t||"fmode-4.5-128k",o.sendCompletion({isDirect:!0}).pipe(finalize((()=>{let e;console.log(n),n.json=this.extractAndParseJson(e),n.complete=!0})))}extractAndParseJson(e){let t=e.indexOf("{");if(-1===t)return{};let n=0,o=t;for(let i=t;i<e.length;i++)if("{"===e[i]?n++:"}"===e[i]&&n--,0===n){o=i;break}if(0!==n)return{};const i=e.slice(t,o+1);try{return JSON.parse(i)}catch(e){return console.error("Failed to parse JSON:",e),{}}}extractMarkdownToMultiArray(e){let t=e.split("\n"),n=[],o=n,i=[n];for(let e of t){if(!e.trim())continue;if(e.startsWith("#")){let t=e.replace(/^#+\s*/,"");o.push([t]);continue}let t=e.search(/\S/)/2,n=e.trim().replace(/^-+\s*/,"");for(;t<i.length-1;)i.pop();for(;t>i.length-1;){let e=[];i[i.length-1].push(e),i.push(e)}o=i[i.length-1],o.push(n)}return n}async getFormatTpl(e,t){let n=await this.getPromptTpl(e);return await n.format(t)}async getPromptTpl(e){let t=new Parse__default.Query("PromptTemplate");t.equalTo("code",e);let n=await t.first();return PromptTemplate.fromTemplate(n?.get("template"),{templateFormat:"mustache"})}getTokens(e){return e=e||"",2*e?.length}}class FmodeTTS{constructor(e,t){this.uploadServ=t,this.subscriptionKey=e?.subscriptionKey,this.authorizationToken=e?.token,this.region=e?.region,this.subscriptionKey&&(this.speechConfig=SpeechConfig.fromSubscription(this.subscriptionKey,this.region)),this.authorizationToken&&(this.speechConfig=SpeechConfig.fromAuthorizationToken(this.authorizationToken,this.region)),this.synthesizer=new SpeechSynthesizer(this.speechConfig)}extractTextFromXML(e){const t=/>([^<]+)</g;let n,o=[];for(;null!==(n=t.exec(e));){const e=n[1].trim();e&&o.push(e)}return o.join(" ")}extractSSMLContent(e){var t=e.match(/<speak.*?<\/speak>/s);return t?t[0]:e}async speakAsync(e,t,n){if(!t){let n=Parse__default.Object.extend("ChatVoice");(t=new n).set("ssml",e),t.set("content",this.extractTextFromXML(e));let o=localStorage.getItem("company");o&&t.set("company",{__type:"Pointer",className:"Company",objectId:o}),Parse__default.User.current()?.id&&t.set("user",Parse__default.User.current().toPointer())}if(!t?.get("voiceFile")){let n=[];t?.get("content")&&n.push({content:t?.get("content")}),e&&n.push({ssml:e});let o=Parse__default.Query.fromJSON("ChatVoice",{include:"voiceFile",where:{$or:n}}),i=await o.first();t.set("voiceFile",i?.get("voiceFile")?.toPointer())}return t?.get("voiceFile")?(this.playAudioData(t?.get("voiceFile")?.get("url"),t,n),t):(e=this.extractSSMLContent(e),new Promise(((o,i)=>{const a=Date.now();let r="speakTextAsync";e?.indexOf("<")>-1&&(r="speakSsmlAsync"),this.eventMap?.onSpeakBefore&&this.eventMap?.onSpeakBefore(),this.synthesizer[r](e,(e=>{if(console.log(e),e.reason===ResultReason.SynthesizingAudioCompleted){this.eventMap?.onAudioCompleted&&this.eventMap?.onAudioCompleted();const i=Date.now();let r=e?.audioData;t.set("duration",Number(e?.audioDuration)/1e4),this.playAudioData(r,t,n),console.log(`Audio synthesis finished. Duration: ${i-a} ms`),o(t)}else i(`Speech synthesis failed. Reason: ${e.errorDetails}`)}),(e=>{i(`Error occurred during synthesis: ${e}`)}))})))}onBreak(e){}playAudioData(e,t,n){let o;if(console.log("audioData",e),!(e?.indexOf&&e?.indexOf("http")>=-1)){let n=new Blob([e],{type:"audio/wav"});return o=URL.createObjectURL(n),void this.uploadAndSaveVoice(n,t)}o=e;let i=new Audio(o);i.onloadeddata=()=>{let e=1e3*i.duration;console.log("duration",e),t?.get("duration")||(t?.set("duration",e),t?.save()),n?.onLoaded&&n?.onLoaded(i)},i.onpause=()=>{n?.onStop&&n?.onStop()},i.onended=()=>{n?.onStop&&n?.onStop()},i.onclose=()=>{n?.onStop&&n?.onStop()},i.play()}async uploadAndSaveVoice(e,t){if(this.uploadServ){let n=t?.id||this.uploadServ?.genMd5(t?.get("content")||t?.get("ssml")),o=new Date,i=n+o.getFullYear()+(o.getMonth()+1)+o.getDate()+o.getHours()+o.getMinutes()+o.getSeconds()+".wav",a=new File([e],i,{type:"audio/wav"}),r=await this.uploadServ.upload(a,(e=>{console.log(e)})),s={__type:"Pointer",className:"Attachment",objectId:r?.id};s?.objectId&&(t.set("voiceFile",s),t=await t.save())}}}const API_BASE="https://server.fmode.cn/api/apig/aigc/gpt",agentPrompt=new AgentPrompt,PromptTplTalkSSMLOutputCode="talk-ssml-output-tpl",PromptTplTalkTextSSMLCode="talk-text-ssml-tpl";function getMessageContentText(e){let t="";return"string"==typeof e&&(t=e),"object"==typeof e&&(t=e?.find((e=>e?.text))?.text||""),t}function getMessageImageUrl(e){return"object"==typeof e?e?.find((e=>e?.image_url))?.image_url?.url||"":null}class FmodeChat{showAvatar(){this.avatarConfig=this.role?.get("avatarConfig"),this.avatarConfig&&(this.isAvatarShow=!0,this.avatarConfig?.image&&(this.avatarConfig.image.waiting=this.avatarConfig.image.waiting||this.role?.get("thumb")||this.role?.get("avatar"),this.avatarMode="image"),this.avatarConfig?.video&&(this.avatarConfig.video.waiting=this.avatarConfig.video.waiting,this.avatarMode="video"))}constructor(e,t,n,o,i,a,r){this.ChatSession=Parse__default.Object.extend("ChatSession"),this.messageList=[{role:"system",content:"系统提示:AI仅供参考"}],this.latestAIResponse="",this.userInput="",this.userImage="",this.isAvatarShow=!1,this.avatarMode="",this.isPromptModalOpen=!1,this.promptList=[],this.leftButtons=[{title:"灵感",icon:"color-wand-outline",onClick:()=>{this.isPromptModalOpen=!0},show:()=>this?.promptList?.length},{title:"角色",icon:"people-outline",onClick:()=>{this.navCtrl?.navigateRoot("/chat/pro/mask")},show:()=>!0},{title:"呼叫",icon:"call-outline",onClick:()=>{this.chatServ?.callRole(this.role)},show:()=>this?.role?.get("voiceConfig")}],this.isVoiceInputMode=!1,this.isTexting=!1,this.isTalkMode=!1,this.SSMLRoleVoice="zh-CN-XiaoxiaoNeural",this.playAnimation=e=>{console.log(e)},this.voiceMap={},this.chatServ=o,this.role=t,this.sessionId=e,this.navCtrl=i,this.ncloud=a,this.uploadServ=r,n?.id&&(this.chatSession=n,this.messageList=this.chatSession.get("messageList"),this.sessionId=n?.id)}async loadTalkSystemPrompt(e){if(!this.isTalkMode)return;if(!e)return;"男"==e?.get("gender")?this.SSMLRoleVoice="zh-CN-YunyeNeural":this.SSMLRoleVoice="zh-CN-XiaoxiaoNeural",this.SSMLRoleVoice=e?.get("voiceConfig")?.voice||this.SSMLRoleVoice;let t=await agentPrompt.getFormatTpl("talk-ssml-output-tpl",{SSMLRoleVoice:this.SSMLRoleVoice}),n=e.get("prompt")||"请你扮演飞码AI的人工智能专家。";n+=t;let o={role:"user",content:n,hidden:!0},i=this.messageList?.map((e=>e?.content)).join();if(i.indexOf(n)>-1)return;let a=this.messageList?.findIndex((e=>"system"==e?.role)),r=a+1;this.messageList.splice(r,0,o)}loadRolePrompt(){let e=this.role?.get("prompt"),t={role:"user",content:e,hidden:!0};if(!e)return;let n=this.messageList?.map((e=>e?.content)).join();if(n.indexOf(e)>-1)return;let o=this.messageList?.findIndex((e=>"system"==e?.role)),i=o+1;this.messageList.splice(i,0,t)}async sendMessage(e="FmodeAiTest测试问题",t,n,o,i){if(this.loadRolePrompt(),t){let n={role:"user",content:[{type:"image_url",image_url:{url:t}},{type:"text",text:e}],complete:!0,createdAt:new Date};i&&(n.voice={id:i?.id}),this.messageList.push({role:"user",content:[{type:"image_url",image_url:{url:t}},{type:"text",text:e}],complete:!0,createdAt:new Date})}else{let t={role:"user",content:e,complete:!0,createdAt:new Date};i&&(t.voice={id:i?.id,duration:i?.duration}),this.messageList.push(t)}let a=new FmodeChatCompletion(this.fixMessageList(this.messageList),{model:this.chatServ?.currentModel?.get("code")||"fmode-4.5-128k"});this.userInput="",this.userImage="";let r=!1;this.isTalkMode&&(r=!0);let s=a.sendCompletion({isDirect:r,onComplete:n||null}).pipe(finalize((async()=>{if(this.isTalkMode){let e=this.messageList[a.indexOfList]?.content,t=await this.getVoiceByContentText(e,o);o?.onSSMLComplete&&o?.onSSMLComplete(t),this.messageList[a.indexOfList].voice=t,this.playChatVoice(this.voiceMap[t?.id])}this.messageList[a.indexOfList].complete=!0}))).subscribe((e=>{this.messageList[a.indexOfList]=e,this.latestAIResponse=this.getContentText(e?.content);let t=this.chatSession?.get("messageList")?.length;this.messageList?.length>t&&this.saveChatSession(),e?.complete&&(this.saveChatSession(),s.unsubscribe())}))}getVoiceByContentText(e,t,n=!1){let o=this.getContentText(e),i=new(Parse__default.Object.extend("ChatVoice")),a="";return this.SSMLRoleVoice=this.role?.get("voiceConfig")?.voice||this.SSMLRoleVoice,new Promise((async(e,t)=>{let resolveChatVoice=async()=>{i.set("content",o),i.set("ssml",a),i.set("role","assistant");let t=localStorage.getItem("company");t&&i.set("company",{__type:"Pointer",className:"Company",objectId:t}),Parse__default.User.current()?.id&&i.set("user",Parse__default.User.current().toPointer()),this.chatSession?.id&&i.set("session",this.chatSession?.toPointer()),i=await i.save(),this.voiceMap[i?.id]=i,e({id:i?.id})};if(0==n&&(a=`<speak xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xmlns:emo="http://www.w3.org/2009/10/emotionml" version="1.0" xml:lang="zh-CN"><voice name="${this.SSMLRoleVoice}">${o}</voice></speak>`,resolveChatVoice()),1==n){let e=await agentPrompt.getFormatTpl("talk-text-ssml-tpl",{content:o,SSMLRoleVoice:this.SSMLRoleVoice});new FmodeChatCompletion(this.fixMessageList([{role:"user",content:e}]),{model:this.chatServ?.currentModel?.get("code")||"fmode-4.5-128k"}).sendCompletion({isDirect:!0}).subscribe((async e=>{e?.complete&&(a=this.getContentText(e?.content),resolveChatVoice())}))}}))}getContentText(e){return"string"==typeof e?e:e?.[0]?.text||""}async initTTS(){let e=await this.ncloud.apig("voice/tts/token",{company:localStorage.getItem("company")});if(console.log(e),e?.token){let t=new FmodeTTS(e,this.uploadServ);this.tts=t}}async playChatVoice(e,t){if(await this.initTTS(),this.tts)try{this.playAnimation("talking"),await this.tts.speakAsync(e?.get("ssml"),e,{onLoaded:e=>{t.onLoaded&&t.onLoaded(e)},onStop:()=>{t.onStop&&t.onStop(),this.playAnimation("waiting")}})}catch(e){console.error(e)}}async saveChatSession(){if("new"==this.sessionId&&(this.chatSession=new this.ChatSession),this.chatSession.set("title",this.genTitle()),this.chatSession.set("role",this.role?.toPointer()),this.chatSession.set("messageList",this.messageList),this.chatSession.set("user",Parse__default.User.current()?.toPointer()),this.chatSession=await this.chatSession.save(),this.sessionId=this.chatSession?.id,this.sessionId){let e=`${window.location.origin}/chat/pro/chat/${this.sessionId}`;if(window.location?.pathname?.indexOf("chat/session")>-1){window.location.origin,this.sessionId}e=this.getInviteUrl(e),window.history.replaceState(null,null,e);let t={sid:this.chatSession?.id,rid:this.role?.id,name:this.role?.get("name"),message:this.chatSession?.get("messageList")?.[this.chatSession?.get("messageList")?.length-1]?.content?.slice(0,20),latest:this.chatSession?.createdAt};this.chatServ?.chatList?.length||(this.chatServ.chatList=[]);let n=this.chatServ?.chatList?.find((e=>e?.sid==t?.sid));n>-1?this.chatServ.chatList[n]=t:this.chatServ?.chatList.unshift(t)}}getInviteUrl(e){let t="?";t=e?.indexOf("?")>-1?"&":"?";let n=Parse__default.User?.current()?.id;if(-1==e?.indexOf("invite="+n)){if(!n)return e;e+=t+"invite="+n}return e}genTitle(){if(this.title)return this.title;let e=this.messageList.find((e=>"user"==e.role))?.content;return"string"==typeof e&&(this.title=e?.slice(0,15)||""),"object"==typeof e&&(this.title=e?.find((e=>e?.text))?.text||""),this.title}fixMessageList(e){return e.map((e=>({role:e.role,content:e.content})))}nowStr(){let e=new Date;return`${e.getFullYear()}/${e.getMonth()+1}/${e.getDate()} ${e.getHours()}:${e.getMinutes()}:${e.getSeconds()}`}}class FmodeChatCompletion{constructor(e,t){this.content="",this.contentBuffer=[],this.isCompleted=!1,this.indexOfList=Number(e.length),this.messages=e,this.model=t?.model||"fmode-4.5-128k"}sendCompletion(e={}){e.intTime=e?.intTime||50,e.isDirect=e?.isDirect||!1,e?.isDirect&&(e.intTime=1);let t={messages:this.messages,stream:!0,model:this.model,temperature:.5,presence_penalty:0,frequency_penalty:0};return new Observable((n=>{let o=RequestFmodeChatApi("/v1/chat/completions",t).subscribe((t=>{let i=String(t);if("data: [DONE]"==i&&(this.isCompleted=!0,e?.isDirect&&this.isCompleted&&(n.next({role:"assistant",content:this.content,complete:!0,createdAt:new Date}),o.unsubscribe(),e?.onComplete&&e.onComplete({role:"assistant",content:this.content,complete:!0,createdAt:new Date}),n.complete())),i.indexOf("data: {")>-1){let t=chunkToJson(i),a=t?.choices?.[0]?.delta?.content||"";this.contentBuffer.push(a),e?.isDirect&&(this.content+=a||"",this.isCompleted||n.next({role:"assistant",cid:t?.id,content:this.content,createdAt:new Date})),e?.isDirect||this.contentPusher||(this.contentPusher=setInterval((()=>{this.isCompleted&&0==this.contentBuffer?.length&&(n.next({role:"assistant",cid:t?.id,content:this.content,complete:!0,createdAt:new Date}),o.unsubscribe(),clearInterval(this.contentPusher),n.complete()),this.contentBuffer?.length>=0&&(this.contentBuffer?.length>0&&(this.content+=this.contentBuffer.shift()),n.next({role:"assistant",cid:t?.id,content:this.content,createdAt:new Date}))}),e?.intTime))}}))})).pipe(bufferTime(100),concatMap((e=>e)),delay(200))}}function chunkToJson(e){let t;try{t=JSON.parse(e.replaceAll("data: ",""))}catch(e){console.error(e)}return t||{}}function RequestFmodeChatApi(e,t,n="POST"){return new Observable((o=>{let i=API_BASE+e,a=`Bearer ${Parse__default.User.current()?.getSessionToken()||localStorage.getItem("FMODE_AI_TOKEN")}`;return t.token=a,t&&(t=JSON.stringify(t)),fetch(i,{headers:{"Content-Type":"text/plain","Cache-Control":"no-cache"},body:t||null,method:n,credentials:"omit",mode:"cors"}).then((e=>{let t="";{let n=e.body?.getReader();const i=new TextDecoder;let a=new ReadableStream({start(e){!function read(){n.read().then((({done:t,value:n})=>{if(t)return e.close(),void o.complete();e.enqueue(n),read()}))}()}}).getReader();a.read().then((function processStream({done:e,value:n}){if(e)return;!function processData(e){let n=(t+e).split("\n");if(n?.length>1){for(let e=0;e<n.length-1;e++){let t=n[e];o.next(t)}t=n[n.length-1]}}(i.decode(n)),a.read().then(processStream)}))}})).catch((e=>o.error(e))),()=>{}}))}function JsonToFormData(e){const t=new FormData;return function appendFormData(e,n=""){Array.isArray(e)?e.forEach(((e,t)=>{appendFormData(e,`${n}[${t}]`)})):"object"==typeof e&&null!==e?Object.keys(e).forEach((t=>{const o=n?`${n}.${t}`:t;appendFormData(e[t],o)})):t.append(n,e)}(e),t}class NovaCloudService{constructor(e){this.http=e,this.serverURL="https://server.fmode.cn/api",localStorage.setItem("NOVA_APIG_SERVER","aHR0cHMlM0ElMkYlMkZzZXJ2ZXIuZm1vZGUuY24lMkZhcGklMkZhcGlnJTJG")}novaql(e,t){let n=this.serverURL+"/novaql/select",o={sql:e};return o&&t?.length>0&&(o.params=JSON.stringify(t)),new Promise(((e,t)=>{this.http.post(n,o,{headers:new HttpHeaders({"Content-Type":"application/json"}),withCredentials:!1}).subscribe((t=>{if(t&&200==t.code){let n=t.data;e(n)}}),(e=>{t(e)}))}))}apig(e,t,n="post"){localStorage.setItem("NOVA_APIG_SERVER","aHR0cHMlM0ElMkYlMkZzZXJ2ZXIuZm1vZGUuY24lMkZhcGklMkZhcGlnJTJG");let o=localStorage.getItem("NOVA_APIG_SERVER");o=decodeURIComponent(atob(o)),e=o+e,console.log(e);let i=Parse__default.User.current();return new Promise(((o,a)=>{try{this.http.request(n,e,{body:t||null,headers:new HttpHeaders({"Content-Type":"application/json",Authorization:`Bearer ${i?.getSessionToken()}`}),withCredentials:!1}).subscribe((e=>{if(e&&200==e.code||e&&1==e.code||e&&0==e.code){let t=e?.data;o(t)}else o(null)}),(e=>{console.error(e.mess),a(e)}))}catch(e){return console.error("请求出错")}}))}apigTest(e,t,n="post"){e="https://test.fmode.cn/api/apig/"+e,console.log(e);let o=Parse__default.User.current();return t.token=`Bearer ${o?.getSessionToken()}`,new Promise(((o,i)=>{try{this.http.request(n,e,{body:t||null,headers:new HttpHeaders({"Content-Type":"application/json"}),withCredentials:!1}).subscribe((e=>{if(e&&200==e.code||e&&1==e.code||e&&0==e.code){let t=e?.data;o(t)}else o(null)}),(e=>{console.error(e.mess),i(e)}))}catch(e){return console.error("请求出错")}}))}api(e,t){return e=this.serverURL+e,new Promise(((n,o)=>{this.http.post(e,t,{headers:new HttpHeaders({"Content-Type":"application/json"}),withCredentials:!1}).subscribe((e=>{if(e&&200==e.code||e&&1==e.code){let t=e.data;n(t)}else n(null)}),(e=>{o(e)}))}))}searchParse(e){let t={};if((e=e||location.search)&&e.length>1){let n=(e=e.substring(1)).split("&");for(let e=0;e<n.length;e++){if(!n[e])continue;let o=n[e].split("=");t[o[0]]=void 0===o[1]?"":o[1]}}return t}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:NovaCloudService,deps:[{token:i1.HttpClient}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:NovaCloudService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:NovaCloudService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i1.HttpClient}]});class CrossService{getMenuType(){return this.clientWidth=document.body.clientWidth,this.onResizeScreen(),this.navMenuType}constructor(e,t,n){this.platform=e,this.modalCtrl=t,this.navCtrl=n,this.mobileWidth=915,this.clientWidth=document.body.clientWidth,this.clientWidth=document.body.clientWidth,this.updateWidth(),this.onResizeScreen()}async dismisModalTop(e){let t=await this.modalCtrl.getTop();t&&(e?.preventDefault&&e?.preventDefault(),t.dismiss(),t.isOpen=!1)}updateWidth(){this.fixInterval=setInterval((()=>{if(this.clientWidth)return clearInterval(this.fixInterval),void delete this.fixInterval;console.log(document.body.clientWidth),this.clientWidth=document.body.clientWidth}),200)}onResizeScreen(e){this.clientWidth=document.body.clientWidth,this.clientWidth>=this.mobileWidth?(this.leftMenuMode="horizontal",this.navMenuType="pc"):(this.leftMenuMode="inline",this.navMenuType="mobile")}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CrossService,deps:[{token:i2.Platform},{token:i2.ModalController},{token:i2.NavController}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CrossService,providedIn:"root"})}}function calcFileMd5(e){return new Promise(((t,n)=>{const o=new FileReader;o.onload=e=>{try{const o=e.target?.result;if(o){const e=new SparkMD5.ArrayBuffer;e.append(o);const n=e.end();t(n)}else n(new Error("Failed to load file"))}catch(e){n(e)}},o.onerror=e=>{n(e)},o.readAsArrayBuffer(e)}))}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CrossService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i2.Platform},{type:i2.ModalController},{type:i2.NavController}]});class NovaUploadService{constructor(e,t){this.platform=e,this.diagnostic=t,this.maxSize=5242880,this.getUptoken(!0),this.requestPermission(),this.queryDomain()}async upload(e,t){let n,o=e.type,i=e.name?.split("."),a=i[i.length-1];try{n=await calcFileMd5(e)}catch(e){}let r,s,l=this.fileToBlob(e);return r=o.indexOf("image")>-1?await this.saveQiniuImageFile(l,a,null,t):await this.saveQiniuMediaFile(e,l,null,t),r.md5=n,r?.url?.indexOf("undefined")>-1&&(r.url=(this.qiniuDomain||"https://file-cloud.fmode.cn/")+r.url.replace("undefined/","")),r?.url&&(s=await this.saveAttachment(r,this.qiniuDomain,null,this.getCompanyId())),s?.id&&(r.id=s?.id),r}isCapacitor(){return this.platform.is("capacitor")||this.platform.is("cordova")}async requestPermission(){this.isCapacitor()&&(await this.requestStoagePermission(),await this.requestCameraPermission())}async requestStoagePermission(){let e=await this.diagnostic.isExternalStorageAuthorized();if(console.log("permisson_STORAGE:",e),!e){await this.diagnostic.requestExternalStorageAuthorization()}}async requestCameraPermission(){let e=await this.diagnostic.isCameraAuthorized();if(console.log("permisson_Camera:",e),!e){await this.diagnostic.requestCameraAuthorization()}}async getUptoken(e=!1){if(console.log("getUptoken"),this.qiniuConf||e)try{console.log(this.getCompanyId());let e=await Parse__default.Cloud.run("qiniu_uptoken",{company:this.getCompanyId()});console.log(e),this.qiniuConf=e}catch(e){console.error(e)}}genFileKey(e,t){let n=new Date,o=new DatePipe("en");return t||(t=this.getCompanyId()),t+"/"+o.transform(n,"yMMdd")+"/"+String(e.id).substr(20,6)+o.transform(n,"hhmmssSSS")+/\.[^\.]+/.exec(e.name)}getCompanyId(){if(this.company)return this.company;return localStorage.getItem("company")}async queryDomain(){let e=new Parse__default.Query("Company"),t=await e.get(this.getCompanyId());t.get("configQiniu")&&t.get("configQiniu").domain?(console.log(t.get("configQiniu").domain),this.qiniuDomain=t.get("configQiniu").domain):this.qiniuDomain="https://file-cloud.fmode.cn"}async saveAttachment(e,t,n,o){let i=e.url;i.startsWith("http")||(i=t+i),i=i.replace(/undefined\//,""),o||(o=localStorage.getItem("company"));let a=Parse__default.User.current(),r=new Parse__default.Query("Attachment");r.equalTo("url",i);let s=await r.first();if(s&&s.id)return console.error("该文件已存在,无需重复上传"),s;return s=new(Parse__default.Object.extend("Attachment")),s.set("size",e.size),s.set("url",i),s.set("name",e.name),s.set("mime",e.type),s.set("md5",e?.md5),a?.id&&s.set("user",a.toPointer()),o&&s.set("company",{__type:"Pointer",className:"Company",objectId:localStorage.getItem("company")}),n&&s.set("category",{__type:"Pointer",className:"Category",objectId:n}),await s.save()}async captureVideo(e){if(this.qiniuConf=e,!this.isCapacitor())return;let t=await this.cameraCaptureVideoFile(),n=await this.getMediaFileDataString(t);return await this.saveQiniuMediaFile(t,n)}async cameraCaptureVideoFile(){let e=MediaCapture,t=await e.captureVideo({limit:1});return t?.length>0?t[0]:null}async getMediaFileDataString(e){new FilesystemWeb,e.fullPath.replaceAll("///","//");let t=await Filesystem.stat({path:e.fullPath}),n=Capacitor.convertFileSrc(t.uri),o=await fetch(n),i=await o.blob();if(console.log(i.size),console.log(JSON.stringify(t)),console.log(JSON.stringify(o)),console.log(JSON.stringify(Object.keys(o))),i)return i;throw"读取文件失败"}async takePicture(e){if(this.qiniuConf=e,!this.isCapacitor())return;await this.getUptoken();let t=await this.cameraTakePictureDataUrl();if(!t?.dataUrl)return;let n=await this.base64ToBlob(t?.dataUrl),o=await this.saveQiniuImageFile(n,t?.format);return console.log(JSON.stringify(o)),o}async cameraTakePictureDataUrl(){if(!this.isCapacitor())return;return await Camera.getPhoto({quality:90,allowEditing:!1,source:CameraSource.Camera,resultType:CameraResultType.DataUrl})}async saveQiniuImageFile(e,t,n,o){let i=this.maxSize;if(e.size>i)throw await console.log("照片过大,超出限制5MB"),"超出文件大小";let a=new DatePipe("en").transform(new Date,"yyyyMMddHHmmss"),r=`${a}.${t}`,s=`image/${t}`,l={fname:r,params:{},mimeType:"image/*"},c={useCdnDomain:!0,forceDirect:!0};console.log(this.qiniuConf);let d=this.genFileKey({id:a,name:r});return console.log("图片上传前"),new Promise(((t,n)=>{console.log("进入了上传"),qiniu.upload(e,d,this.qiniuConf?.uptoken,l,c).subscribe({next:e=>{console.log(e),o&&o(e)},error:async e=>{console.log(e)},complete:n=>{console.log("上传完成"),console.log(`${this.qiniuConf?.domain}${n.key}`),n.url=`${this.qiniuConf?.domain}${n.key}`,n.name=r,n.type=s,n.size=e.size,t(n)}})}))}async saveQiniuMediaFile(e,t,n,o){let i=e.name,a=e.type;if(e.size>104857600)throw console.log("视频过大,超出限制100MB"),"超出文件大小";let r=new DatePipe("en").transform(new Date,"yyyyMMddHHmmss"),s={fname:i,params:{},mimeType:a},l={useCdnDomain:!0,forceDirect:!0},c=this.genFileKey({id:r,name:i});return console.log("图片上传前"),console.log(e.name,t.size),console.log(t.size),console.log(t.size/1024/1024),new Promise(((n,i)=>{console.log("进入了上传"),qiniu.upload(t,c,this.qiniuConf?.uptoken,s,l).subscribe({next:e=>{console.log("主要用来展示进度"),o&&o(e),console.log(JSON.stringify(e))},error:async e=>{console.log("上传失败"),console.log(JSON.stringify(e))},complete:t=>{console.log("上传完成"),console.log(JSON.stringify(t)),e.key=t.key,console.log(e.type),e.url=`${this.qiniuConf?.domain}${t.key}`,console.log(e.url),n(e)}})}))}async base64ToBlobType(e,t){let n=await fetch(`data:${t};base64,${e}`);return await n.blob()}async base64ToBlob(e){let t=await fetch(e);return await t.blob()}fileToBlob(e){const t=e.slice(0,e.size,e.type);return new Blob([t],{type:e.type})}genMd5(e){return CryptoJS.MD5(e).toString()}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:NovaUploadService,deps:[{token:i2.Platform},{token:i2$1.Diagnostic}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:NovaUploadService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:NovaUploadService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i2.Platform},{type:i2$1.Diagnostic}]});class ChatService{constructor(e,t,n,o,i,a,r){this.router=e,this.ncloud=t,this.platform=n,this.alertCtrl=o,this.navCtrl=i,this.cross=a,this.uploadServ=r,this.chatMap={},this.isCapacitor=!1,this.platformMap={pc:"电脑端",mobile:"移动端"},this.isCapacitor=this.platform.is("capacitor")}async loadModelList(e){if(this.modelList?.length)return;let t=new Parse__default.Query("ChatModel");t.notEqualTo("isDeleted",!0),t.equalTo("isEnabled",!0),t.addAscending("index"),this.modelList=await t.find(),this.currentModel=e||this.modelList?.find((e=>"fmode-4.5-128k"==e.get("code")))}async doButtonAction(e){let t=this.cross.navMenuType,n=e?.platform?.map((e=>this.platformMap[e])).join("、");if(e?.platform?.length>0&&-1==e?.platform?.indexOf(t)){(await this.alertCtrl.create({header:"注意",subHeader:"终端不符",message:`请您使用${n}开启本功能。`,buttons:[{role:"ok",text:"知道了"}]})).present()}else e?.path&&this.navCtrl.navigateRoot(e?.path)}async initChatMap(e){if(this.chatMap[e])return this.chatMap[e];let t=new Parse__default.Query("ChatSession");t.include("role","role.model");let n=await t.get(e),o=new FmodeChat(n?.id,n?.get("role"),n,this,this.navCtrl,this.ncloud,this.uploadServ);return this.chatMap[e]=o,this.chatMap[e]}async getChatSession(){if(!Parse__default?.User?.current()?.id)return;let e=new Parse__default.Query("ChatSession");e.include("role","role.model"),e.addDescending("updatedAt"),e.equalTo("user",Parse__default.User.current().toPointer()),e.notEqualTo("isDeleted",!0),e.limit(30);let t=await e.find();this.chatList=t.map((e=>(this.chatMap[e?.id]=new FmodeChat(e?.id,e?.get("role"),e,this,this.navCtrl,this.ncloud,this.uploadServ),{session:e,sid:e?.id,isHidden:!1,rid:e?.get("role")?.id,name:e?.get("role")?.get("name"),thumb:e?.get("role")?.get("thumb"),title:e?.get("title")||e?.get("role")?.get("name"),message:e?.get("messageList")?.[e?.get("messageList")?.length-1]?.content?.slice(0,20),latest:e?.createdAt})))}async getChatSessionDistinct(){let e=await this.ncloud.novaql('SELECT t1."objectId" as sid , "AvatarRole"."objectId" as rid, * FROM (\n SELECT *,ROW_NUMBER() OVER (PARTITION BY "user", "role" ORDER BY "createdAt" DESC) AS rn\n FROM "ChatSession" WHERE "user"=$1\n ) as t1\n LEFT JOIN "AvatarRole" ON "AvatarRole"."objectId" = t1."role"\n WHERE t1.rn=1\n LIMIT $2\n ;',[Parse__default.User.current()?.id,10]),t=e?.map((e=>({sid:e?.sid,rid:e?.rid,name:e?.name,message:e?.messageList?.[e?.messageList?.length-1]?.content?.slice(0,20),latest:e?.createdAt})));return this.chatList=t,this.chatList}createChatPanel(e,t){let n=t?.id||"new";t=new FmodeChat(n,e,t,this,this.navCtrl,this.ncloud,this.uploadServ),this.chatMap[n]=t,this.router.navigate(["/chat/pro/chat/"+n])}async createNewRoleChat(e){let t=new Parse__default.Query("AvatarRole");t.include("model");let n=await t.get(e);return new FmodeChat("new",n,null,this,this.navCtrl,this.ncloud,this.uploadServ)}async restoreChatPanel(e){let t=new Parse__default.Query("AvatarRole"),n=new Parse__default.Query("ChatSession"),o=await t.get(e?.rid),i=await n.get(e?.sid),a=new FmodeChat(e?.sid,o,i,this,this.navCtrl,this.ncloud,this.uploadServ);this.chatMap[e?.sid]=a,this.router.navigate(["/chat/pro/chat/"+e?.sid])}async callRole(e){document.body.classList.add("dark"),this.router.navigate([`/avatar/role/${e.id}`,{type:"phone"}])}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatService,deps:[{token:i1$1.Router},{token:NovaCloudService},{token:i2.Platform},{token:i2.AlertController},{token:i2.NavController},{token:CrossService},{token:NovaUploadService}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i1$1.Router},{type:NovaCloudService},{type:i2.Platform},{type:i2.AlertController},{type:i2.NavController},{type:CrossService},{type:NovaUploadService}]});class ImagineService{constructor(e,t,n){this.http=e,this.ncloud=t,this.uploadServ=n,this.taskDetailMap={},this.newWorkList=[],this.myWorkList=[]}async drawDalle(e){e.size=e?.size||"1024x1024",e.style=e?.style||"natural",e.quality=e?.quality||null;let t={model:"dall-e-3",prompt:e.prompt,n:1,quality:e.quality,response_format:"url",size:e.size,style:e.style};if(e.prompt?.length>3e3)throw"prompt maximum < 4000 characters";let n=await this.ncloud.apigTest("aigc/gpt/v1/images/generations",t);if(console.log(n),n?.id){let e=new Parse__default.Query("ImagineWork");e.get(n?.id);let t=await e.first();console.log(t),t?.id&&this.newWorkList.unshift(t)}return n}priceDalle(e){let t=[{model:"dall-e-3",quality:null,size:"1024x1024",credit:6.4},{model:"dall-e-3",quality:null,size:"1024x1792",credit:12.8},{model:"dall-e-3",quality:null,size:"1792x1024",credit:12.8},{model:"dall-e-3",quality:"hd",size:"1024x1024",credit:12.8},{model:"dall-e-3",quality:"hd",size:"1024x1792",credit:19.2},{model:"dall-e-3",quality:"hd",size:"1792x1024",credit:19.2},{model:"dall-e-2",quality:null,size:"1024x1024",credit:3.2},{model:"dall-e-2",quality:null,size:"512x512",credit:2.88},{model:"dall-e-2",quality:null,size:"256x256",credit:2.56}].find((t=>t.model==e.model&&t.quality==e.quality&&t.size==e.size));return t?.credit||19.2}priceStableDiffusion(e){let t=e.width*e.height,n=763e-9*t*e.steps+2278e-8*t*(e?.upscale||0)+(e?.hrSteps||0)*t*(e?.hrScale||0)*(e?.hrScale||0)*763e-9+(e?.faceFix?2:0)+(e?.imgOptions?.removeBackground?2:0)+(e?.imgOptions?.redrawBackground?2:0)+(e?.imgOptions?.facePreservation?2:0)+(e?.imgOptions?.genderDetect?1:0)+2*(e?.controlnet?.units?.length||0);return n=.3*n*e.batchSize,n}b64DataToBase64Image(e){let t=atob(e),n=new Blob([t],{type:"image/webp"});new Promise((e=>{let t=new FileReader;t.onloadend=function(){let n=t.result;console.log(n),e(n)},t.readAsDataURL(n)}))}async draw(e){let t=await this.ncloud.apig("aigc/sdapi/v1/draw",e),n=t?.paintingSign;return n&&setTimeout((async()=>{let e=new Parse__default.Query("ImagineWork");e.equalTo("taskId",n);let t=await e.first();console.log(t),t?.id&&this.newWorkList.unshift(t)}),1e3),t}async taskDetail(e){let t=await this.ncloud.apig("aigc/sdapi/v1/task/detail",{taskId:e});return console.log(t),this.taskDetailMap[e]=t,t}getMyWorkQuery(){let e=Parse__default.User.current();if(!e?.id)return;let t=this.getWorkQuery();return t.include("model","module","user"),t.equalTo("user",e.toPointer()),t}getWorkQuery(){let e=new Date((new Date).getTime()-6e4),t=Parse__default.Query.fromJSON("ImagineWork",{where:{$or:[{createdAt:{$lte:e},progress:{$ne:0}},{createdAt:{$gt:e}}]}});return t.include("model","module","user"),t.notEqualTo("isDeleted",!0),t.notEqualTo("isFailed",!0),t.doesNotExist("respData.error"),t.doesNotExist("respData.data.taskLimitCount"),t.addDescending("createdAt"),t}getimg(){return new Promise(((e,t)=>{let n=document.createElement("input");n.type="file",n.click();let handleChange=async()=>{if(n.removeEventListener("change",handleChange),n.files&&n.files.length>0){let t=n.files[0],o=await this.uploadServ.upload(t,(e=>{console.log(e),e.total.percent.toFixed(2)}));e(o.url)}else t("未选择文件")};n.addEventListener("change",handleChange)}))}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ImagineService,deps:[{token:i1.HttpClient},{token:NovaCloudService},{token:NovaUploadService}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ImagineService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ImagineService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i1.HttpClient},{type:NovaCloudService},{type:NovaUploadService}]});class FmaiService{constructor(e,t){this.imagine=e,this.chat=t}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmaiService,deps:[{token:ImagineService},{token:ChatService}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmaiService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmaiService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:ImagineService},{type:ChatService}]});let colorMap=["primary","secondary","tertiary","success","warning","danger","light","medium","dark"];const MASK_LIST=[{name:"执行李",type:"employee",title:"首席执行官",desc:"一位富有远见和领导才能的创业新秀。她具备战略思维和决策能力,能够为公司设定长期目标并领导团队实现这些目标。",color:colorMap[0],cover:"https://imgsource.huashi6.com/images/ai/2023/9/29/15_48766.jpg?e=1695974629&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:oPkQSsyQLLD08R_J4SMeO1f1RdM="},{name:"技术刘",type:"employee",title:"首席技术官",desc:"一位技术专家,拥有广泛的技术知识和经验。他善于解决复杂的技术问题,并能够领导开发团队实施创新的技术解决方案。",color:colorMap[1],cover:["https://imgsource.huashi6.com/images/ai/2023/9/29/9_619877.jpg?e=1695952672&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:LDuSg8_n5g4Rj_8F5PKrGzV4T54=","https://imgsource.huashi6.com/images/ai/2023/9/27/20_17767.jpg?e=1695819037&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:a9uOeeJMN2oopK-3WQZzldPXfH0="]},{name:"点子王",type:"employee",title:"首席运营官",desc:"一位富有创意和市场洞察力的市场营销专家。她擅长制定营销策略,了解目标受众,并能够利用各种渠道和工具推广公司的产品或服务。",color:colorMap[2],cover:"https://imgsource.huashi6.com/images/ai/2023/9/29/9_186291.jpg?e=1695952125&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:EhEUtwnC9hpu-SXXsBrp2Q-rcJk="},{title:"设计总监",name:"李欣",type:"employee",desc:"一位富有创造力和用户导向思维的设计师。她能够理解用户需求,并通过设计直观、易用且吸引人的用户界面来提供出色的用户体验。",color:colorMap[3],cover:"https://imgsource.huashi6.com/images/ai/2023/9/29/9_18099.jpg?e=1695952201&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:G_a60v52iTTqvJgeTSa_8zJUY2w="},{title:"运营经理",name:"刘洁",type:"employee",desc:"一位组织能力强、注重细节并擅长解决问题的运营专家。她能够协调各个部门的工作,并确保公司的运营流程高效运行。",color:colorMap[4],cover:"https://imgsource.huashi6.com/images/ai/2023/9/29/9_842519.jpg?e=1695952125&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:FM_kKZDzkcLQ1EX4266dXU46cRc="},{title:"销售经理",name:"张伟",type:"employee",desc:"一位富有销售天赋和人际交往能力的销售专家。他善于与客户建立良好的关系,并能够推动销售团队实现业绩目标。",color:colorMap[5],cover:"https://imgsource.huashi6.com/images/ai/2023/9/29/15_739110.jpg?e=1695974920&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:vg_sn-qn67MJS-7j2o7mWzOCUSk="},{title:"数据分析师",name:"杨晨",type:"employee",desc:"一位善于解读数据和提供商业洞察的数据分析专家。她能够收集、分析和解释数据,为公司的决策制定提供有力的支持。",color:colorMap[6],cover:"https://imgsource.huashi6.com/images/ai/2023/9/29/15_204321.jpg?e=1695974779&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:dC2sGmJekSPBTCycPF76BkQPBoo="},{title:"财务经理",name:"赵晓",type:"employee",desc:"一位精通财务管理和分析的专业人士。她能够制定财务战略、管理公司的财务流程,并提供准确的财务报告和预测。",color:colorMap[7],cover:"https://imgsource.huashi6.com/images/ai/2023/9/29/15_947878.jpg?e=1695974779&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:TFGn0_l2PqhUTe9G4A3it769hcU="},{title:"品牌专员",name:"王雅",type:"employee",desc:"一位富有创意和品牌意识的专业人士。她能够塑造和管理公司的品牌形象,制定品牌营销策略,并与内部和外部利益相关者建立良好的合作关系。",color:colorMap[8],cover:["https://imgsource.huashi6.com/images/ai/2023/9/29/15_129581.jpg?e=1695975151&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:YQrpiv1hBKRPIdaEbDDDkLFuPG8=","https://imgsource.huashi6.com/images/ai/2023/9/29/15_912136.jpg?e=1695975151&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:8SVMU1rdKD8eaJ1gH_qGQzcrMhM="]},{title:"全科",name:"孔博",type:"teacher",desc:"擅长全科教学的金牌教师,知识面广泛,博古通今,因材施教,耐心稳重。",color:colorMap[0],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/12_40958.jpg?e=1697604189&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:U7r1Td30lXdf9mE1TMVAnDhBP6c="]},{title:"语文",name:"王明",type:"teacher",desc:"激发学生对文学的热爱,引导他们成为优秀的作家和沟通者。",color:colorMap[1],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/11_698893.jpg?e=1697602689&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:hK_AuY7BA1pp33QVeUue5QjIg4o="]},{title:"数学",name:"万红",type:"teacher",desc:"以清晰的逻辑和耐心的指导,帮助学生掌握数学的基础知识和解题技巧。",color:colorMap[2],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/11_256253.jpg?e=1697603314&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:K2iqp_ZzHYzXNu_0VJlywyANHp8="]},{title:"英语",name:"张瑞",type:"teacher",desc:"激发学生对英语学习的兴趣,培养他们的听、说、读、写能力,让他们自信地运用英语。",color:colorMap[3],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/12_266171.jpg?e=1697603707&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:uhpxBbT-jlSt_KjAnj0SFsFAjWU="]},{title:"物理",name:"金晓",type:"teacher",desc:"通过实验和案例,帮助学生理解物理原理,培养他们的科学思维和实验技能。",color:colorMap[4],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/11_694925.jpg?e=1697603071&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:FznZxhkYUrZ-BzX05dvNt8acTUw="]},{title:"化学",name:"陈华",type:"teacher",desc:"激发学生对化学的好奇心,教授他们化学知识和实验技巧,培养他们的实验和分析能力。",color:colorMap[5],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/11_942234.jpg?e=1697603169&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:__2T8cxLl4J0AwMR9MJdDiooDF0="]},{title:"生物",name:"杨婷",type:"teacher",desc:"引导学生探索生命的奥秘,培养他们的科学观察和实验能力,让他们热爱生物科学。",color:colorMap[6],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/12_330738.jpg?e=1697603491&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:2K5-DHPnUQ-R9GGxtWKiEG68QlE="]},{title:"历史",name:"赵亮",type:"teacher",desc:"帮助学生了解历史事件和文化背景,培养他们的历史意识和批判思维。",color:colorMap[7],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/11_256302.jpg?e=1697602689&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:YP7ffC1YKO-Pb0C3ks4caT0QqZk="]},{title:"地理",name:"林丽",type:"teacher",desc:"引导学生探索地球的奥秘,培养他们的地理观察和分析能力,让他们热爱地理科学。",color:colorMap[8],cover:["https://imgsource.huashi6.com/images/ai/2023/10/18/12_555804.jpg?e=1697604054&token=qFZErZx7WS1v5B4rgQE2KLMHlYHVNaCuXeaA9OLD:xLN4QW0x9jx9lEB4EFHWvI_gEsI="]}];class UtilnowPipe{constructor(){this.enLocale={"秒钟前":" seconds ago","分钟前":" minutes ago","小时前":" hours ago","天前":" days ago"}}transform(e,t){let n=((new Date).getTime()-e.getTime())/1e3;if(n<=60)return this.handleArgs(n.toFixed(0),"秒钟前",t);let o=n/60;if(o<60)return this.handleArgs(o.toFixed(0),"分钟前",t);let i=o/60;if(i<24)return this.handleArgs(i.toFixed(0),"小时前",t);let a=i/24;return a<7?this.handleArgs(a.toFixed(0),"天前",t):`${e?.getFullYear()}-${e?.getMonth()+1}-${e?.getDate()}`}handleArgs(e,t,n){return"en"==n&&(t=this.enLocale[t]),"TranslateService"==n?.constructor?.name&&(console.log(t),"en"==n?.getDefaultLang()&&(t=this.enLocale[t])),"json"==n?{unit:t,value:e}:e+t}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:UtilnowPipe,deps:[],target:i0.ɵɵFactoryTarget.Pipe})}static{this.ɵpipe=i0.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:UtilnowPipe,isStandalone:!0,name:"utilnow"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:UtilnowPipe,decorators:[{type:Pipe,args:[{name:"utilnow",standalone:!0}]}]});class ChatContentPipe{transform(e,...t){let n=t?.[0]||"text";return"text"==n?getMessageContentText(e):"image_url"==n?getMessageImageUrl(e):e}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatContentPipe,deps:[],target:i0.ɵɵFactoryTarget.Pipe})}static{this.ɵpipe=i0.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:ChatContentPipe,isStandalone:!0,name:"chatContent"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatContentPipe,decorators:[{type:Pipe,args:[{name:"chatContent",pure:!0,standalone:!0}]}]});class HidexmlPipe{transform(e,...t){return e?this.hideXmlTags(e):""}hideXmlTags(e){return e.replace(/<[^>]*>/g,"")}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:HidexmlPipe,deps:[],target:i0.ɵɵFactoryTarget.Pipe})}static{this.ɵpipe=i0.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:HidexmlPipe,isStandalone:!0,name:"hidexml"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:HidexmlPipe,decorators:[{type:Pipe,args:[{name:"hidexml",standalone:!0}]}]});class MarkdownMathJax{constructor(e){this.options=e,this.adaptor=liteAdaptor(),RegisterHTMLHandler(this.adaptor)}text_to_mathjax(e,t){if(!e?.length)return"";if(!e?.replace)return"";t=t||this.options;let n=new SVG({fontCache:"local"});"chtml"==t?.output&&(n=new CHTML);const o=mathjax.document("",{skipHtmlTags:["script","noscript","style","textarea","pre","code","annotation","annotation-xml"],InputJax:new TeX({processEscapes:!0,packages:AllPackages}),OutputJax:n}),i={em:16,ex:8,containerWidth:1280};return[/\$\$\ (.+?)\ \$\$/g,/\$\$(.+?)\$\$/g,/\$\$\n(.+?)\n\$\$/g,/\$(.+?)\$/g,/\\\((.+?)\\\)/g,/\\\[(.+?)\\\]/g].forEach((t=>{e=e.replace(t,((e,t)=>{let n=o.convert(`${t}`,i);return`<span class="mathjax raw" style="margin-left:10px;margin-right:10px;">${this.adaptor.innerHTML(n)}</span>`}))})),e}}let md=new MarkdownIt({html:!0,xhtmlOut:!0,breaks:!1,linkify:!1,typographer:!1,quotes:"“”‘’",highlight:function(e,t){if(t&&hljs.getLanguage(t))try{return`<pre style="position:relative;padding:10px;" class="hljs lang-${t}"><code>${hljs.highlight(e,{language:t}).value}</code><small class="hljs-lang"><span class="sr-only">Language:</span>${t}</small></pre>`}catch(e){}return""}});md.use(abbr),md.use(footnote),md.use(deflist),md.use(mark),md.use(ins),md.use(sub),md.use(sup),md.use(ruby);const mditConfig={plantumlServer:"https://www.plantuml.com/plantuml"};function makePlantumlURL(e){const t=plantumlEncoder.encode(e);return`${mditConfig.plantumlServer}/svg/${t}`}md.renderer.rules.plantuml=(e,t,n,o,i)=>{const a=e[t];if("plantuml"!==a.type)return e[t].content;return`\n <img src="${makePlantumlURL(a.content)}" />\n <pre style="position:relative;padding:10px;" class="hljs lang-plantuml"><code>${a.content}</code><small class="hljs-lang"><span class="sr-only">Language:</span>plantuml</small></pre>\n `},md.core.ruler.push("plantuml",(e=>{const t=e.tokens;for(const e of t)"fence"===e.type&&"plantuml"===e.info&&(e.type="plantuml")}));const spaceregex=/\s*/,notinhtmltagregex=/(?![^<]*>|[^<>]*<\/)/;let coloregex=/\[color=([#|(|)|\s|,|\w]*?)\]/;coloregex=new RegExp(coloregex.source+notinhtmltagregex.source,"g");let nameregex=/\[name=(.*?)\]/,timeregex=/\[time=([:|,|+|-|(|)|\s|\w]*?)\]/;const nameandtimeregex=new RegExp(nameregex.source+spaceregex.source+timeregex.source+notinhtmltagregex.source,"g");function replaceExtraTags(e){return console.log("replaceExtraTags",e),e=(e=(e=(e=e.replace(coloregex,'<span class="color" data-color="$1"></span>')).replace(nameandtimeregex,'<small><i class="fa fa-user"></i> $1 <i class="fa fa-clock-o"></i> $2</small>')).replace(nameregex,'<small><i class="fa fa-user"></i> $1</small>')).replace(timeregex,'<small><i class="fa fa-clock-o"></i> $1</small>'),console.log("replaceExtraTags",e),e}function finishView(e){let t=$.parseHTML(`<html><body><div id="topmd">${e}</div></body></html>`)[0],n=$(t),o=n.find("blockquote.raw").removeClass("raw");o=n.find("blockquote");let i=$(o).find("p");i.each(((e,t)=>{let n=$(t).html();n=replaceExtraTags(n),t.innerHTML=n,$(t).html(n),i[e].innerHTML=n,$(i[e]).html(n)})),o.find(".color").each(((e,t)=>{let n=$(t).attr("data-color");$(t).closest("blockquote").css("border-left-color",n)}));let a="<style>\n .markdown-section {\n color: black;\n text-align: left;\n }\n .markdown-section pre .hljs-lang{\n text-transform: uppercase;\n font-weight: 700;\n font-size: .75rem;\n line-height: 1rem;\n padding-top: .25rem;\n padding-bottom: .25rem;\n padding-left: .5rem;\n padding-right: .5rem;\n background-color: rgba(0,0,0,.3);\n border-bottom-left-radius: .375rem;\n top:0;\n right:0;\n position:absolute;\n}\n\n }\n .markdown-section pre .hljs {\n position:relative!important;\n background: #272822!important;\n padding:10px!important;\n color: #ddd;\n text-shadow: none!important;\n }\n\n .markdown-section blockquote {\n margin: 0;\n margin-bottom: 0px;\n margin-bottom: .85em;\n padding: 0 15px;\n color: #858585;\n border-left: 4px solid #e5e5e5;\n border-left-color: rgb(229, 229, 229);\n }\n .markdown-section img {\n max-width:100%;\n }\n </style>"+(n.html()||e);return a=a.replaceAll('src="/uploads/','src="https://md.fmode.cn/uploads/'),a}nameregex=new RegExp(nameregex.source+notinhtmltagregex.source,"g"),timeregex=new RegExp(timeregex.source+notinhtmltagregex.source,"g");class MarkdownParse{constructor(){}parseToHTML(e){this.info("markdown",e),e=(new MarkdownMathJax).text_to_mathjax(e,{output:"svg"});let t=md.render(e);return t=finishView(t),t}info(...e){}}class MarkdownPreviewComponent{constructor(e,t){this.domSan=e,this.renderer=t,this.content="",this.render=!0}ngAfterViewInit(){this.renderMdToHTML()}renderMdToHTML(){if(!this.render)return;let e=(new MarkdownParse).parseToHTML(this.content);this.safeHTML=this.domSan.bypassSecurityTrustHtml(e);let t=this.renderer.createElement("div");t.innerHTML=e,this.renderer.appendChild(this.mdContent.nativeElement,t)}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:MarkdownPreviewComponent,deps:[{token:i1$2.DomSanitizer},{token:i0.Renderer2}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:MarkdownPreviewComponent,selector:"fm-markdown-preview",inputs:{content:"content",render:"render"},viewQueries:[{propertyName:"mdContent",first:!0,predicate:["mdContent"],descendants:!0}],ngImport:i0,template:'<div class="message-body">\n <div *ngIf="render" #mdContent class="markdown-section">\n </div>\n <div *ngIf="!render" class="pre-section">\n {{content}}\n </div>\n</div>',styles:[":host{overflow-x:auto}.message-body div{text-align:left;overflow-x:auto}.message-body .pre-section{white-space:pre-wrap}.markdown-section blockquote{margin:0 0 .85em;padding:0 15px;color:#858585;border-left:4px solid #e5e5e5;border-left-color:#e5e5e5}\n"],dependencies:[{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:MarkdownPreviewComponent,decorators:[{type:Component,args:[{selector:"fm-markdown-preview",template:'<div class="message-body">\n <div *ngIf="render" #mdContent class="markdown-section">\n </div>\n <div *ngIf="!render" class="pre-section">\n {{content}}\n </div>\n</div>',styles:[":host{overflow-x:auto}.message-body div{text-align:left;overflow-x:auto}.message-body .pre-section{white-space:pre-wrap}.markdown-section blockquote{margin:0 0 .85em;padding:0 15px;color:#858585;border-left:4px solid #e5e5e5;border-left-color:#e5e5e5}\n"]}]}],ctorParameters:()=>[{type:i1$2.DomSanitizer},{type:i0.Renderer2}],propDecorators:{content:[{type:Input}],mdContent:[{type:ViewChild,args:["mdContent"]}],render:[{type:Input}]}});class MarkdownPreviewModule{static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:MarkdownPreviewModule,deps:[],target:i0.ɵɵFactoryTarget.NgModule})}static{this.ɵmod=i0.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:MarkdownPreviewModule,declarations:[MarkdownPreviewComponent],imports:[CommonModule],exports:[MarkdownPreviewComponent]})}static{this.ɵinj=i0.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:MarkdownPreviewModule,imports:[CommonModule]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:MarkdownPreviewModule,decorators:[{type:NgModule,args:[{declarations:[MarkdownPreviewComponent],imports:[CommonModule],exports:[MarkdownPreviewComponent]}]}]});class ClipboardService{constructor(e){this.toastCtrl=e}async copyToClipboard(e){try{return await Clipboard.write({string:e}),void this.copySuccess()}catch(t){try{if(navigator.clipboard&&window.isSecureContext)return await(navigator?.clipboard?.writeText(e)),void this.copySuccess();throw!1}catch(t){let n=document.createElement("textarea");n.value=e,n.style.position="fixed",n.style.left="-9999px",n.style.top="-9999px",document.body.appendChild(n),n.focus(),n.select();try{let e=document?.execCommand("copy");e?this.copySuccess():console.error("无法复制文本")}catch(e){console.error("无法复制文本: ",e)}document.body.removeChild(n)}}}async copySuccess(){(await this.toastCtrl.create({duration:1e3,message:"复制成功",color:"primary",icon:"information-circle",position:"top"})).present()}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ClipboardService,deps:[{token:i2.ToastController}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ClipboardService,providedIn:"root"})}}function pcmtoWav(e,t,n,o){let i={chunkId:[82,73,70,70],chunkSize:0,format:[87,65,86,69],subChunk1Id:[102,109,116,32],subChunk1Size:16,audioFormat:1,numChannels:n||1,sampleRate:t||16e3,byteRate:0,blockAlign:0,bitsPerSample:o||16,subChunk2Id:[100,97,116,97],subChunk2Size:0};function u32ToArray(e){return[255&e,e>>8&255,e>>16&255,e>>24&255]}function u16ToArray(e){return[255&e,e>>8&255]}let a=new Uint8Array(e);i.blockAlign=i.numChannels*i.bitsPerSample>>3,i.byteRate=i.blockAlign*i.sampleRate,i.subChunk2Size=a.length*(i.bitsPerSample>>3),i.chunkSize=36+i.subChunk2Size;let r=i.chunkId.concat(u32ToArray(i.chunkSize),i.format,i.subChunk1Id,u32ToArray(i.subChunk1Size),u16ToArray(i.audioFormat),u16ToArray(i.numChannels),u32ToArray(i.sampleRate),u32ToArray(i.byteRate),u16ToArray(i.blockAlign),u16ToArray(i.bitsPerSample),i.subChunk2Id,u32ToArray(i.subChunk2Size)),s=new Uint8Array(r),l=new Uint8Array(s.length+a.length);return l.set(s),l.set(a,s.length),new Blob([l],{type:"audio/wav"})}function resampleAudio(e,t,n){let o=e.length,i=Math.floor(o/t*n),a=[];for(let o=0;o<i;o++){let i=Math.floor(o*(t/n));a[o]=e[i]}return a}function convertFrameBufferToBase64(e){const t=new Uint8Array(2*e.length);for(let n=0;n<e.length;n++){const o=e[n];t[2*n]=255&o,t[2*n+1]=o>>8&255}return btoa(String.fromCharCode.apply(null,t))}function resampleBuffer(e,t,n){const o=t/n,i=Math.round(e.length/o),a=new Int16Array(i);for(let t=0;t<i;t++){const n=Math.floor(t*o);a[t]=e[n]}return a}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ClipboardService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i2.ToastController}]});const SpeechRecognition=window.SpeechRecognition||window.webkitSpeechRecognition,SpeechGrammarList=window.SpeechGrammarList||window.webkitSpeechGrammarList;class WebSpeech{constructor(e){this.platform=e}startRecognition(e="Nihao | Hello"){if(!SpeechRecognition)return;if(this.recognition&&this.recognition.stop(),console.log("startRecognition"),this.recognition=new SpeechRecognition,!this.recognition)return;this.recognition.continuous=!0;let t=`#JSGF V1.0; grammar words; public <word> = ${e} ;`;this.recognition=new SpeechRecognition;let n=new SpeechGrammarList;n.addFromString(t,1),this.recognition.grammars=n,this.recognition.start(),this.recognition.onresult=e=>{let t=e.results||[];console.log(t),console.log(t[0]?.[0]),t[0]?.[0]?.transcript?.indexOf("Nihao")>-1&&console.log("Nihao成功唤醒"),t[0]?.[0]?.transcript?.indexOf("Hello")>-1&&console.log("Hello成功唤醒"),this.startRecognition()},this.recognition.onend=e=>{console.log(e)},this.recognition.onerror=e=>{console.error(e)}}speak(e,t=1,n=1.2,o=.8){this.platform.is("capacitor")||this.speakWithEdge(e,1,1.2,.8)}speakWithEdge(e,t=1,n=1.2,o=.8){let i=new SpeechSynthesisUtterance(e),a=this.getVoiceByName("Yaoyao");console.log(a),a&&(i.voice=a),i.rate=n,i.pitch=t,i.volume=10,window.speechSynthesis.speak(i)}getVoiceByName(e){return window.speechSynthesis.getVoices().find((t=>t.name.indexOf(e)>-1))}}class FmodeVoiceService{constructor(e,t){this.platform=e,this.diagnostic=t,this.webSpeech=WebSpeech,this.isUserFinish=!1,this.recordWavBlob=null,this.recordPcmBlob=null,this.recordDuration=0,this.recordType="pcm",this.encodingType="raw",this.connStatus="",this.btnStatus="UNDEFINED",this.resultText="",this.resultTextTemp="",this.APPID="50f4a46c",this.API_SECRET="NzFlNmFhZDJjMDNkZGM3NzI0Mzg2OGNm",this.API_KEY="106ddc40dfd4b9ca6d7b47c70fada749",this.requestPermission()}toggleRecord(){console.log(this.btnStatus),"UNDEFINED"===this.btnStatus||"CLOSED"===this.btnStatus?this.startTalk():"CONNECTING"!==this.btnStatus&&"OPEN"!==this.btnStatus||this.finishTalk()}finishTalk(){this.isUserFinish=!0,this.onBeforeFinishTalk&&this.onBeforeFinishTalk(),this.recordStop()}async startTalk(e){this.resultText="",this.resultTextTemp="",this.onBeforeStartTalk&&this.onBeforeStartTalk(),event?.preventDefault(),await this.openWithPriviledge(),setTimeout((()=>{this.connectWebSocket()}),100),this.onAfterStartTalk&&this.onAfterStartTalk()}cancelTalk(){this.onBeforeCancelTalk&&this.onBeforeCancelTalk(),this.recordStop(),this.iatWS?.close(),this.resultText=null,this.onAfterCancelTalk&&this.onAfterCancelTalk()}async recordStart(){this.createRecorder(),await this.openWithPriviledge(),this.recorder.start(),this.changeBtnStatus("OPEN"),this.onAfterRecordStart&&this.onAfterRecordStart()}recordStop(){return new Promise((e=>{clearInterval(this.countdownInterval),this.changeBtnStatus("CLOSED"),this.recorder?.stop((async(t,n)=>{try{this.iatWS.send(JSON.stringify({data:{status:2,format:"audio/L16;rate=16000",encoding:this.encodingType,audio:""}}))}catch(e){}let o=(window.URL||webkitURL).createObjectURL(t);console.log(t,o,"时长:"+n+"ms"),this.recordPcmBlob=t,this.recordWavBlob=await this.pcmBlobToWavBlob(t,44100),this.recordDuration=n,console.log("this.recordWavBlob",this.recordWavBlob),setTimeout((()=>{this.isUserFinish&&(this.onAfterFinishTalk&&this.onAfterFinishTalk(),this.isUserFinish=!1)}),2e3),this.recorder?.close(),this.recorder=null,console.log("localUrl",o),e(!0)}),(t=>{console.log("录音失败:"+t),this.recorder.close(),this.recorder=null,e(null)}))}))}playRecord(){this.playPCM(this.recordPcmBlob,44100)}async pcmBlobToWavBlob(e,t){return new Promise((n=>{let o=new FileReader;o.onload=function(e){let o=pcmtoWav(e.target.result,t,1,16);n(o)},o.readAsArrayBuffer(e)}))}async playPCM(e,t){let n=await this.pcmBlobToWavBlob(e,t),o=window.URL.createObjectURL(n),i=new Audio;i.src=o,i.play()}async playBuffers(){let e=await this.BuffersToBlob(this.buffers);this.playPCM(e,44100)}BuffersToBlob(e){let t=[];return e.forEach((e=>{e.forEach((e=>{t.push(e)}))})),new Blob([t],{type:"audio/pcm"})}splitAudioData(e){const t=1280,n=Math.ceil(e.length/t),o=[];for(let i=0;i<n;i++){const n=i*t,a=n+t,r=e.slice(n,a);o.push(r)}return o}BufferToBlob(e){return new Blob([e],{type:"audio/pcm"})}createRecorder(){this.recorder||(this.recorder=Recorder({type:this.recordType,sampleRate:44100,bitRate:16,onProcess:(e,t,n,o,i,a)=>{let r=e.length&&e[e.length-1];if(this.buffers=e,r=resampleBuffer(r,44100,16e3),this.iatWS.readyState===this.iatWS.OPEN){if(this.disableASR)return;this.iatWS.send(JSON.stringify({data:{status:1,format:"audio/L16;rate=16000",encoding:this.encodingType,audio:convertFrameBufferToBase64(r)}}))}this.waveClient?.input(e[e.length-1],t,o)}}))}async openWithPriviledge(){return console.log(this.btnStatus),await this.requestPermission(),this.createRecorder(),!!Recorder.IsOpen()||new Promise((e=>{this.recorder.open((()=>{let t=document.querySelector(".record-wave");t&&(console.log(t),Recorder.WaveView&&(this.waveClient=Recorder.WaveView({elem:".record-wave"}))),e(!0)}),((e,t)=>{console.log((t?"UserNotAllow,":"")+"无法录音:"+e)}))}))}getWebSocketUrl(){let e="wss://iat-api.xfyun.cn/v2/iat",t="iat-api.xfyun.cn",n=this.API_KEY,o=this.API_SECRET,i=(new Date).toUTCString(),a=`host: ${t}\ndate: ${i}\nGET /v2/iat HTTP/1.1`,r=CryptoJS.HmacSHA256(a,o),s=CryptoJS.enc.Base64.stringify(r);return e=`${e}?authorization=${btoa(`api_key="${n}", algorithm="hmac-sha256", headers="host date request-line", signature="${s}"`)}&date=${i}&host=${t}`,e}toBase64(e){for(var t="",n=new Uint8Array(e),o=n.byteLength,i=0;i<o;i++)t+=String.fromCharCode(n[i]);return window.btoa(t)}countdown(){let e=60;this.connStatus=`录音中(${e}s)`,this.countdownInterval=setInterval((()=>{e-=1,console.log(e),e<=0?(clearInterval(this.countdownInterval),this.recordStop()):this.connStatus=`录音中(${e}s)`}),1e3)}changeBtnStatus(e){this.btnStatus=e,"CONNECTING"===e?this.connStatus="建立连接中":"OPEN"===e?this.countdown():"CLOSING"===e?this.connStatus="关闭连接中":"CLOSED"===e&&(this.connStatus="开始录音")}renderResult(e){let t=JSON.parse(e);if(t.data&&t.data.result){let e=t.data.result,n="",o=e.ws;for(let e=0;e<o.length;e++)n+=o[e].cw[0].w,console.log(n);e.pgs?("apd"===e.pgs&&(this.resultText=this.resultTextTemp),this.resultTextTemp=this.resultText+n):this.resultText=this.resultText+n,this.resultTextTemp||this.resultText,console.log("diff temp",this.resultTextTemp),console.log("diff result",this.resultText)}0===t.code&&2===t.data.status&&this.iatWS.close(),0!==t.code&&(this.iatWS.close(),console.error(t))}connectWebSocket(){console.log("connectWebSocket");const e=this.getWebSocketUrl();if("WebSocket"in window)this.iatWS=new WebSocket(e);else if(!("MozWebSocket"in window))return void alert("浏览器不支持WebSocket");console.log("connectWebSocket",this.btnStatus),this.changeBtnStatus("CONNECTING"),this.iatWS.onopen=e=>{this.recordStart();var t={common:{app_id:this.APPID},business:{language:"zh_cn",domain:"iat",accent:"mandarin",vad_eos:5e3,dwa:"wpgs"},data:{status:0,format:"audio/L16;rate=16000",encoding:this.encodingType}};this.iatWS.send(JSON.stringify(t))},this.iatWS.onmessage=e=>{console.log("onmessage"+this.resultText),this.renderResult(e.data)},this.iatWS.onerror=e=>{console.error("error",e),this.recordStop(),this.changeBtnStatus("CLOSED")},this.iatWS.onclose=async e=>{console.log("onclose"+this.resultText),console.error("close",e),await this.recordStop(),this.changeBtnStatus("CLOSED")}}isCapacitor(){return this.platform.is("capacitor")||this.platform.is("cordova")}async requestPermission(){if(this.isCapacitor())try{await this.requestStoagePermission(),await this.requestCameraPermission(),await this.requestMicPermission(),await this.requestRecordAudioPermission()}catch(e){console.error(e)}}async requestRecordAudioPermission(){let e=await this.diagnostic.requestRuntimePermissions([this.diagnostic.permission.RECORD_AUDIO]);console.log("record permission request:",e)}async requestMicPermission(){let e=await this.diagnostic.isMicrophoneAuthorized();if(console.log("permisson_MIC:",e),!e){await this.diagnostic.requestMicrophoneAuthorization()}}async requestStoagePermission(){let e=await this.diagnostic.isExternalStorageAuthorized();if(console.log("permisson_STORAGE:",e),!e){await this.diagnostic.requestExternalStorageAuthorization()}}async requestCameraPermission(){let e=await this.diagnostic.isCameraAuthorized();if(console.log("permisson_Camera:",e),!e){await this.diagnostic.requestCameraAuthorization()}}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeVoiceService,deps:[{token:i2.Platform},{token:i2$1.Diagnostic}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeVoiceService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeVoiceService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i2.Platform},{type:i2$1.Diagnostic}]});class RolePointsCloud{constructor(e,t,n){this.offsetPosition=new BABYLON.Vector3(0,1.25,0),this.animationGroup=new BABYLON.AnimationGroup("RoleAnimGroup"),this.AnimMap={idle:null},this.scene=e,this.engine=this.engine}async init(){this.Mesh=this.loadMesh(),this.loadIdleAnim()}playAnim(e){this.scene.beginDirectAnimation(this.Mesh,[this.AnimMap[e]],0,120,!0)}loadMesh(){let e=BABYLON.MeshBuilder.CreateSphere("sphere",{diameter:2},this.scene);return e.position.addInPlace(this.offsetPosition),e.visibility=1,e.material=new BABYLON.StandardMaterial("mat",this.scene),e.material.wireframe=!0,e.scaling=new BABYLON.Vector3(1,1,1),e}loadIdleAnim(){let e=new BABYLON.Animation("idle","scaling",30,BABYLON.Animation.ANIMATIONTYPE_VECTOR3,BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE),t=[];t.push({frame:0,value:new BABYLON.Vector3(1,1,1)}),t.push({frame:60,value:new BABYLON.Vector3(1.5,1.5,1.5)}),t.push({frame:120,value:new BABYLON.Vector3(1,1,1)}),e.setKeys(t),this.Mesh.animations.push(this.AnimMap.idle),this.AnimMap.idle=e,this.animationGroup.addTargetedAnimation(this.AnimMap.idle,this.Mesh)}}class CompAvatarParticleComponent{constructor(e){this.elementRef=e,this.isWebVR=!1,this.animMap={}}ngAfterViewInit(){if(this.canvas=this.renderCanvas.nativeElement,console.log(this.canvas),this.canvas){let e={};this.engine=new BABYLON.Engine(this.canvas,!0,e),console.log(this.engine),this.createScene(),this.engine.runRenderLoop((()=>{this.scene?.render(),this.engine?.resize()})),window.addEventListener("resize",(()=>{this.engine?.resize()}))}}async createScene(){this.scene=new BABYLON.Scene(this.engine),this.scene.clearColor=new BABYLON.Color4(0,0,0,1),this.mainCamera=this.createCamera(),console.log(this.mainCamera),this.currentRole=new RolePointsCloud(this.scene,this.engine,this.mainCamera),await this.currentRole.init(),this.currentRole.playAnim("idle"),this.currentRole.Mesh.visibility=0,await this.createCloudPoints();new BABYLON.HemisphericLight("light1",new BABYLON.Vector3(0,1,0),this.scene);this.engine?.resize()}createCamera(){let e=new(this.isWebVR?BABYLON.VRDeviceOrientationArcRotateCamera:BABYLON.ArcRotateCamera)("Camera",0,0,30,new BABYLON.Vector3(0,.5,0),this.scene);return e.setPosition(new BABYLON.Vector3(0,0,5)),e.beta=Math.PI/3,e.alpha=Math.PI/1.2,e.radius=15,e}async createCloudPoints(){this.pointsMesh=this.currentRole.Mesh,this.pointsCloud=new BABYLON.PointsCloudSystem("pcs",1,this.scene);let e=new BABYLON.Color3(.7,.8,1),t=new BABYLON.Color4(.7,.8,1),n=(new BABYLON.Color4(.2,.5,1),new BABYLON.Color4(0,0,.2,0),new BABYLON.Texture("/assets/avatar/particle/textures/flare.png",this.scene)),o=new BABYLON.PBRMaterial("material",this.scene);o.emissiveTexture=n,o.emissiveColor=e,this.pointsCloud.addVolumePoints(this.currentRole.Mesh,5e3,BABYLON.PointColor.Color,t),this.pointsCloud.buildMeshAsync().then((()=>{this.playAnimation("waiting")})),this.scene.registerAfterRender((()=>{this.pointsCloud.setParticles()})),this.engine.runRenderLoop((()=>{this.scene.render()}))}playAnimation(e){switch(e){case"waiting":this.cloudAnim();break;case"listening":this.cloudAnim({rotateSpeed:.01,breathing:!1});break;case"thinking":this.cloudAnim({rotateSpeed:.2,breathing:!1});break;case"talking":this.animMap.idle&&this.scene.beginDirectAnimation(this.pointsMesh,[this.animMap.talking],0,20,!0)}}cloudAnim(e={breathing:!0,rotateSpeed:.002}){this.animMap.idle&&this.scene.beginDirectAnimation(this.pointsMesh,[this.animMap.idle],0,120,!0);let t=new BABYLON.Color4(1,1,1,1),n=(new BABYLON.Texture("/assets/avatar/particle/textures/flare.png",this.scene),0);this.pointsCloud.updateParticle=o=>{let i=this.currentRole.Mesh.getBoundingInfo()?.boundingSphere?.radiusWorld,a=this.currentRole.Mesh.getBoundingInfo()?.boundingSphere?.centerWorld;o.idx;if(o.color=t,o.rotation.y+=e.rotateSpeed,o&&n<3&&(console.log(this.currentRole.Mesh.getBoundingInfo()),console.log(o),n++),o.initpos||(o.initpos=o.position),e.breathing){let e=o.initpos.subtract(a);o.position=new BABYLON.Vector3(e.x*i,e.y*i,e.z*i).add(this.currentRole.offsetPosition)}return o}}createSphere(){let e=BABYLON.MeshBuilder.CreateSphere("sphere",{diameter:2},this.scene);e.visibility=1,e.material=new BABYLON.StandardMaterial("mat",this.scene),e.material.wireframe=!0,e.scaling=new BABYLON.Vector3(1,1,1),this.pointsMesh=e;let t=new BABYLON.Animation("breathingAnimation","scaling",30,BABYLON.Animation.ANIMATIONTYPE_VECTOR3,BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE),n=[];n.push({frame:0,value:new BABYLON.Vector3(.3,.3,.3)}),n.push({frame:60,value:new BABYLON.Vector3(.5,.5,.5)}),n.push({frame:120,value:new BABYLON.Vector3(.3,.3,.3)}),t.setKeys(n),this.animMap.idle=t;let o=[{frame:0,value:BABYLON.Vector3.One()},{frame:10,value:new BABYLON.Vector3(1.2,.8,1.2)},{frame:20,value:BABYLON.Vector3.One()}],i=new BABYLON.Animation("talkAnimation","scaling",30,BABYLON.Animation.ANIMATIONTYPE_VECTOR3,BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);return i.setKeys(o),this.animMap.talk=i,this.scene.beginDirectAnimation(e,[this.animMap.idle],0,120,!0),e}async createParticle(){let e=this.createSphere(),t=new BABYLON.ParticleSystem("particles",2e3,this.scene);t.particleTexture=new BABYLON.Texture("/assets/avatar/particle/textures/flare.png",this.scene),t.emitter=e,t.minEmitBox=new BABYLON.Vector3(0,0,0),t.maxEmitBox=new BABYLON.Vector3(0,0,0),t.color1=new BABYLON.Color4(.7,.8,1,1),t.color2=new BABYLON.Color4(.2,.5,1,1),t.colorDead=new BABYLON.Color4(0,0,.2,0),t.minSize=.5,t.maxSize=.5,t.minLifeTime=.1,t.maxLifeTime=.1,t.minAngularSpeed=0,t.maxAngularSpeed=Math.PI,t.minInitialRotation=0,t.maxInitialRotation=Math.PI,t.minEmitPower=0,t.maxEmitPower=0,t.emitRate=1500,t.updateSpeed=.01,t.blendMode=BABYLON.ParticleSystem.BLENDMODE_ONEONE,t.direction1=new BABYLON.Vector3(0,0,0),t.direction2=new BABYLON.Vector3(0,0,0),t.start();let n=t.createSphereEmitter();n.radius=2,n.radiusRange=0,n.directionRandomizer=0,t.gravity=new BABYLON.Vector3(0,0,0),t.disposeOnStop=!0,t.updateFunction=n=>{for(let o=0;o<n.length;o++){let i=n[o],a=e.getBoundingInfo()?.boundingSphere?.radiusWorld;i.position=i.position.normalize().scale(a),i.age+=this.scene.getEngine().getDeltaTime()/1e3,i.age>=i.lifeTime&&(t.recycleParticle(i),o--)}},this.engine.runRenderLoop((()=>{this.scene.render(),t.worldOffset=e.position}))}setCameraToMeshCenter(e,t){t.computeWorldMatrix(!0);let n=t.getBoundingInfo(),o=n.minimum,i=n.maximum,a=i.x-o.x,r=i.y-o.y,s=i.z-o.z,l=n.boundingBox.center;console.log("宽度:"+a),console.log("高度:"+r),console.log("深度:"+s),console.log("中心点:"+l)}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarParticleComponent,deps:[{token:i0.ElementRef}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:CompAvatarParticleComponent,isStandalone:!0,selector:"fm-avatar-role-particle",viewQueries:[{propertyName:"renderCanvas",first:!0,predicate:["renderCanvas"],descendants:!0}],ngImport:i0,template:'<canvas #renderCanvas class="render-canvas"></canvas>',styles:[".render-canvas{display:block;width:100%;height:100%;touch-action:none}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"ngmodule",type:FormsModule}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarParticleComponent,decorators:[{type:Component,args:[{selector:"fm-avatar-role-particle",standalone:!0,imports:[CommonModule,FormsModule],template:'<canvas #renderCanvas class="render-canvas"></canvas>',styles:[".render-canvas{display:block;width:100%;height:100%;touch-action:none}\n"]}]}],ctorParameters:()=>[{type:i0.ElementRef}],propDecorators:{renderCanvas:[{type:ViewChild,args:["renderCanvas"]}]}});class CompAvatarRoleImageComponent{constructor(){this.animClass="waiting",this.imageMap={}}playWave(){!this.wave&&Recorder.WaveView&&(this.wave=Recorder.WaveView({elem:".record-wave-avatar",keep:!1}));let e=function generatePowerLevel(){return 100*Math.random()}();this.waveInterval=setInterval((()=>{let t=function generateSampleRate(){const e=[44100,48e3,88200,96e3];return e[Math.floor(Math.random()*e.length)]}(),n=function generatePcmData(e){const t=[];for(let n=0;n<e;n++)t.push(Math.floor(65536*Math.random())-32768);return t}(1e3);this.wave.input(n,e,t)}),40)}stopWave(){clearInterval(this.waveInterval)}ngAfterViewInit(){}ngOnInit(){setTimeout((()=>{this.imageMap=this.fmodeChat.avatarConfig?.image,this.avatarImage.nativeElement.src=this.imageMap?.waiting,this.fmodeChat.playAnimation=this.playAnimation}),1500)}playAnimation(){let e=this;return t=>{let n=e.avatarImage.nativeElement;switch(e.animClass=t,e.stopWave(),t){case"thinking":case"waiting":n.style.animationPlayState="running";break;case"talking":n.style.animationPlayState="running",e.playWave();break;case"listening":n.style.animationPlayState="pause";break;default:n.style.animationPlayState="paused"}}}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarRoleImageComponent,deps:[],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:CompAvatarRoleImageComponent,isStandalone:!0,selector:"fm-avatar-role-image",inputs:{fmodeChat:"fmodeChat",role:"role"},viewQueries:[{propertyName:"avatarImage",first:!0,predicate:["avatarImage"],descendants:!0}],ngImport:i0,template:'<div class="page">\n <div class="avatar" [class]="animClass">\n <div class="avatar-photo">\n <img #avatarImage alt="">\n \x3c!-- 音频波动 --\x3e\n <div class="record-wave-avatar">\n </div>\n </div>\n </div>\n</div>',styles:[".page{position:relative;width:100vw;height:100%;top:0;left:0;display:flex;justify-content:center;align-items:center;background-color:#000}.avatar{width:100%;display:flex;justify-content:center;align-items:center}.avatar .avatar-photo{position:relative;margin-top:-10vh;width:80%}.avatar .avatar-photo img{border-radius:10px}.avatar .record-wave-avatar{height:50px;width:100%;position:absolute;float:left;left:0;bottom:0}.thinking,.listening,.waiting,.talking{animation-duration:2s;animation-play-state:running;animation-iteration-count:infinite;animation-timing-function:ease-in-out}@keyframes waitingAnimation{0%{transform:scale(1)}50%{transform:scale(1.05)}to{transform:scale(1)}}@keyframes thinkingAnimation{0%{transform:rotate(0)}30%{transform:rotate(10deg)}60%{transform:rotate(-10deg)}to{transform:rotate(0)}}.thinking{animation-name:thinkingAnimation}.waiting{animation-name:waitingAnimation}.listening{animation-name:listeningAnimation}.talking{animation-name:talkingAnimation}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"ngmodule",type:FormsModule}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarRoleImageComponent,decorators:[{type:Component,args:[{selector:"fm-avatar-role-image",standalone:!0,imports:[CommonModule,FormsModule],template:'<div class="page">\n <div class="avatar" [class]="animClass">\n <div class="avatar-photo">\n <img #avatarImage alt="">\n \x3c!-- 音频波动 --\x3e\n <div class="record-wave-avatar">\n </div>\n </div>\n </div>\n</div>',styles:[".page{position:relative;width:100vw;height:100%;top:0;left:0;display:flex;justify-content:center;align-items:center;background-color:#000}.avatar{width:100%;display:flex;justify-content:center;align-items:center}.avatar .avatar-photo{position:relative;margin-top:-10vh;width:80%}.avatar .avatar-photo img{border-radius:10px}.avatar .record-wave-avatar{height:50px;width:100%;position:absolute;float:left;left:0;bottom:0}.thinking,.listening,.waiting,.talking{animation-duration:2s;animation-play-state:running;animation-iteration-count:infinite;animation-timing-function:ease-in-out}@keyframes waitingAnimation{0%{transform:scale(1)}50%{transform:scale(1.05)}to{transform:scale(1)}}@keyframes thinkingAnimation{0%{transform:rotate(0)}30%{transform:rotate(10deg)}60%{transform:rotate(-10deg)}to{transform:rotate(0)}}.thinking{animation-name:thinkingAnimation}.waiting{animation-name:waitingAnimation}.listening{animation-name:listeningAnimation}.talking{animation-name:talkingAnimation}\n"]}]}],propDecorators:{avatarImage:[{type:ViewChild,args:["avatarImage"]}],fmodeChat:[{type:Input}],role:[{type:Input}]}});class ModalChatVoiceInputComponent{constructor(e,t,n,o,i,a){this.platform=e,this.router=t,this.voiceServ=n,this.toastCtrl=o,this.ncloud=i,this.chatServ=a,this.talkMode="click",this.talkTips="点击话筒开始讲话",this.errorText="",this.player=new Audio}ngOnInit(){"press"==this.talkMode&&(this.talkTips="轻触底部开始讲话"),setTimeout((()=>{this.initVoiceSevice(),this.initVoiceASR()}),500)}async initVoiceASR(){this.voiceServ.requestPermission().then((()=>{this.voiceServ.openWithPriviledge(),this.startASRAwake()}))}async startASRAwake(){await this.voiceServ.openWithPriviledge(),new this.voiceServ.webSpeech(this.platform).startRecognition("Nihao | Hello")}playMusic(e){this.player.src=`/assets/avatar/voice/${e}.mp3`,this.player.play()}initVoiceSevice(){this.fmodeChat.userInput=this.voiceServ.resultText,this.voiceServ.requestPermission().then((()=>{this.voiceServ.openWithPriviledge()})),this.voiceServ.onBeforeStartTalk=()=>{this.fmodeChat.playAnimation("listening"),this.playMusic("start-talk")},this.voiceServ.onBeforeCancelTalk=()=>{this.playMusic("interupt-talk"),this.fmodeChat.playAnimation("waiting")},this.voiceServ.onAfterCancelTalk=()=>{this.startASRAwake()},this.voiceServ.onBeforeFinishTalk=()=>{this.fmodeChat.playAnimation("thinking"),this.playMusic("stop-talk")},this.voiceServ.onAfterFinishTalk=()=>{console.log("onAfterFinishTalk"),this.fmodeChat.userInput=this.voiceServ?.resultText,this.sendMessage(),this.startASRAwake()}}async sendMessage(){if(!this.fmodeChat.userInput){return this.errorText="内容不能为空",void(await this.toastCtrl.create({message:this.errorText,position:"top",icon:"alert",color:"warning-circle",duration:1e3})).present()}this.fmodeChat?.sendMessage(this.voiceServ.resultText,null,(e=>{}),{onSSMLComplete:e=>{console.log(e)}}),this.fmodeChat.userInput="",this.fmodeChat.userImage=""}testTTS(e){console.log(e),e=e||"你好呀,我是飞马小智!很高兴为您介绍脑控科技的发展历程。我们成立于2019年",new this.voiceServ.webSpeech(this.platform).speak(e)}testXunfeiTTS(){}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ModalChatVoiceInputComponent,deps:[{token:i2.Platform},{token:i1$1.Router},{token:FmodeVoiceService},{token:i2.ToastController},{token:NovaCloudService},{token:ChatService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:ModalChatVoiceInputComponent,isStandalone:!0,selector:"fm-modal-chat-voice-input",inputs:{fmodeChat:"fmodeChat",talkMode:"talkMode"},providers:[FmodeVoiceService],ngImport:i0,template:' \n <ng-container *ngIf="fmodeChat">\n\n \x3c!-- 用户输入 提示区域 --\x3e\n <div class="user-asr-input" style="text-align: center;" *ngIf="!fmodeChat?.userInput && voiceServ.btnStatus!=\'OPEN\'">{{talkTips}}</div>\n <div class="user-asr-input">{{fmodeChat?.userInput}}</div>\n \n \x3c!-- 测试按钮 --\x3e\n <div class="test-button-group" *ngIf="false">\n <button class="button-record" (click)="voiceServ.toggleRecord()">开始录制 {{voiceServ.connStatus}} {{voiceServ.btnStatus}}</button>\n <br>\n <button class="button-record" (click)="voiceServ.playRecord()">播放录制结果</button>\n <br>\n <button class="button-record" (click)="voiceServ.playBuffers()">播放Buffers结果</button>\n <button (click)="testTTS()">测试TTS纯WEB</button>\n <button (click)="startASR()">测试ASR</button> \n <button (click)="testXunfeiTTS()">测试合成</button> \n </div>\n\n \n \n \x3c!-- 交互按钮 --\x3e\n <ion-fab slot="fixed" horizontal="center" vertical="bottom">\n <ng-container *ngIf="talkMode==\'click\'">\n \x3c!-- 默认按钮:开始讲话 --\x3e\n <ion-fab-button color="primary" closeIcon="checkmark" (click)="voiceServ.toggleRecord()">\n <ion-icon name="mic-outline"></ion-icon>\n </ion-fab-button>\n\n \x3c!-- 讲话中:取消发送 --\x3e\n <ion-fab-list side="end">\n <ion-fab-button [class]="\'loading\'" (click)="voiceServ.cancelTalk()">\n <ion-icon name="pause-outline"></ion-icon>\n </ion-fab-button>\n </ion-fab-list>\n </ng-container>\n \n <ng-container *ngIf="talkMode==\'press\'">\n <ion-fab-button color="primary" closeIcon="mic-outline" (touchstart)="voiceServ.toggleRecord()" (touchend)="voiceServ.cancelTalk()">\n <ion-icon name="mic-outline"></ion-icon>\n </ion-fab-button>\n </ng-container>\n </ion-fab>\n\n\n \x3c!-- 音频波动 --\x3e\n <div class="record-wave">\n </div>\n</ng-container>\n',styles:['ion-fab{margin-bottom:10vh}.fab-button-close-active:before{content:"";position:absolute;top:-5px;left:-5px;width:66px;height:66px;border-radius:50%;border:5px solid #fff;border-top-color:transparent;animation:spin 2s ease-in-out infinite;animation-fill-mode:both;animation-play-state:running}.record-wave{position:fixed;bottom:0;width:100vw;height:6vh}\n'],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"ngmodule",type:IonicModule},{kind:"component",type:i2.IonFab,selector:"ion-fab",inputs:["activated","edge","horizontal","vertical"]},{kind:"component",type:i2.IonFabButton,selector:"ion-fab-button",inputs:["activated","closeIcon","color","disabled","download","href","mode","rel","routerAnimation","routerDirection","show","size","target","translucent","type"]},{kind:"component",type:i2.IonFabList,selector:"ion-fab-list",inputs:["activated","side"]},{kind:"component",type:i2.IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"ngmodule",type:RouterModule}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ModalChatVoiceInputComponent,decorators:[{type:Component,args:[{selector:"fm-modal-chat-voice-input",standalone:!0,imports:[CommonModule,IonicModule,RouterModule],providers:[FmodeVoiceService],template:' \n <ng-container *ngIf="fmodeChat">\n\n \x3c!-- 用户输入 提示区域 --\x3e\n <div class="user-asr-input" style="text-align: center;" *ngIf="!fmodeChat?.userInput && voiceServ.btnStatus!=\'OPEN\'">{{talkTips}}</div>\n <div class="user-asr-input">{{fmodeChat?.userInput}}</div>\n \n \x3c!-- 测试按钮 --\x3e\n <div class="test-button-group" *ngIf="false">\n <button class="button-record" (click)="voiceServ.toggleRecord()">开始录制 {{voiceServ.connStatus}} {{voiceServ.btnStatus}}</button>\n <br>\n <button class="button-record" (click)="voiceServ.playRecord()">播放录制结果</button>\n <br>\n <button class="button-record" (click)="voiceServ.playBuffers()">播放Buffers结果</button>\n <button (click)="testTTS()">测试TTS纯WEB</button>\n <button (click)="startASR()">测试ASR</button> \n <button (click)="testXunfeiTTS()">测试合成</button> \n </div>\n\n \n \n \x3c!-- 交互按钮 --\x3e\n <ion-fab slot="fixed" horizontal="center" vertical="bottom">\n <ng-container *ngIf="talkMode==\'click\'">\n \x3c!-- 默认按钮:开始讲话 --\x3e\n <ion-fab-button color="primary" closeIcon="checkmark" (click)="voiceServ.toggleRecord()">\n <ion-icon name="mic-outline"></ion-icon>\n </ion-fab-button>\n\n \x3c!-- 讲话中:取消发送 --\x3e\n <ion-fab-list side="end">\n <ion-fab-button [class]="\'loading\'" (click)="voiceServ.cancelTalk()">\n <ion-icon name="pause-outline"></ion-icon>\n </ion-fab-button>\n </ion-fab-list>\n </ng-container>\n \n <ng-container *ngIf="talkMode==\'press\'">\n <ion-fab-button color="primary" closeIcon="mic-outline" (touchstart)="voiceServ.toggleRecord()" (touchend)="voiceServ.cancelTalk()">\n <ion-icon name="mic-outline"></ion-icon>\n </ion-fab-button>\n </ng-container>\n </ion-fab>\n\n\n \x3c!-- 音频波动 --\x3e\n <div class="record-wave">\n </div>\n</ng-container>\n',styles:['ion-fab{margin-bottom:10vh}.fab-button-close-active:before{content:"";position:absolute;top:-5px;left:-5px;width:66px;height:66px;border-radius:50%;border:5px solid #fff;border-top-color:transparent;animation:spin 2s ease-in-out infinite;animation-fill-mode:both;animation-play-state:running}.record-wave{position:fixed;bottom:0;width:100vw;height:6vh}\n']}]}],ctorParameters:()=>[{type:i2.Platform},{type:i1$1.Router},{type:FmodeVoiceService},{type:i2.ToastController},{type:NovaCloudService},{type:ChatService}],propDecorators:{fmodeChat:[{type:Input}],talkMode:[{type:Input}]}});class CompAvatarTalkComponent{constructor(e,t,n,o,i,a,r){this.voiceServ=e,this.platform=t,this.router=n,this.navCtrl=o,this.route=i,this.chatServ=a,this.ncloud=r,this.route.paramMap.subscribe((e=>{this.roleId=e.get("roleId"),this.loadAvatarRole(this.roleId)})),document.body.classList.add("dark")}ngOnInit(){}ngOnDestroy(){document.body.classList.remove("dark"),this.voiceServ.resultText=null,this.fmodeChat&&(this.fmodeChat.latestAIResponse=null)}goBack(){document.body.classList.remove("dark");let e=this.avatarRole?.get("backUrl");try{if(e)return void this.navCtrl.navigateRoot(e);this.navCtrl.navigateRoot("/chat/pro/role/"+this.roleId)}catch(e){this.navCtrl.navigateRoot("/chat/pro/role/"+this.roleId)}}async loadAvatarRole(e){let t=new Parse.Query("AvatarRole");this.avatarRole=await t.get(e);let n=await this.chatServ.createNewRoleChat(this.roleId);n.isTalkMode=!0,this.fmodeChat=n,this.fmodeChat.showAvatar()}ngAfterViewInit(){this.listenDivChange()}listenDivChange(){new MutationObserver((()=>{this.scrollToBottom(this.aiRespComp)})).observe(this.aiRespComp.nativeElement,{childList:!0,subtree:!0,attributes:!0})}scrollToBottom(e){e?.nativeElement?.scrollHeight&&(e.nativeElement.scrollTop=e.nativeElement.scrollHeight)}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarTalkComponent,deps:[{token:FmodeVoiceService},{token:i2.Platform},{token:i1$1.Router},{token:i2.NavController},{token:i1$1.ActivatedRoute},{token:ChatService},{token:NovaCloudService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:CompAvatarTalkComponent,isStandalone:!0,selector:"app-comp-avatar-talk",providers:[FmodeVoiceService,NovaCloudService,ChatService,Diagnostic,ModalController],viewQueries:[{propertyName:"avatarComp",first:!0,predicate:["avatar"],descendants:!0},{propertyName:"aiRespComp",first:!0,predicate:["aiRespComp"],descendants:!0}],ngImport:i0,template:'<ion-menu #menu contentId="main-content" side="end">\n <ion-header>\n <ion-toolbar>\n <ion-title>资料</ion-title>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n\n <ion-card style="margin: 0px;">\n <img [src]="avatarRole?.get(\'thumb\')" alt="">\n <ion-card-header>\n <ion-card-subtitle>{{avatarRole?.get(\'tags\')}}</ion-card-subtitle>\n <ion-card-title>{{avatarRole?.get("name")}}</ion-card-title>\n </ion-card-header>\n \n <ion-card-content>\n {{avatarRole?.get("desc")}}\n\n <ion-list [inset]="true" style="margin:0px;">\n \x3c!-- <ion-item>\n <ion-avatar *ngIf="avatarRole?.get(\'thumb\')" aria-hidden="true" slot="start">\n <img [src]="avatarRole?.get(\'thumb\')" />\n </ion-avatar>\n <ion-label>{{avatarRole?.get("name")}}</ion-label>\n </ion-item> --\x3e\n <ion-item lines="none" *ngIf="avatarRole?.get(\'age\')">\n <ion-note slot="start">年龄</ion-note>\n <ion-label>{{avatarRole?.get("age")}}</ion-label>\n </ion-item>\n <ion-item lines="none" *ngIf="avatarRole?.get(\'gender\')">\n <ion-note slot="start">性别</ion-note>\n <ion-label>{{avatarRole?.get("gender")}}</ion-label>\n </ion-item>\n <ion-item lines="none">\n <ion-note slot="start">称号</ion-note>\n <ion-label>{{avatarRole?.get("title")}}</ion-label>\n </ion-item>\n \n <ion-item lines="none">\n <ion-note slot="start">擅长</ion-note>\n <ion-label>{{avatarRole?.get("tags")?.join(\',\')}}</ion-label>\n </ion-item>\n\n </ion-list>\n </ion-card-content>\n </ion-card>\n \n \n \n </ion-content>\n</ion-menu>\n\n<div class="ion-page" id="main-content">\n <ion-header class="ion-no-border">\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="goBack()"> <ion-icon name="chevron-back-outline"></ion-icon> </ion-button>\n </ion-buttons>\n <ion-title>\n <ion-chip *ngIf="avatarRole?.get(\'title\')">{{avatarRole?.get("title")}}</ion-chip>\n </ion-title>\n <ion-buttons slot="end">\n \x3c!-- <ion-button (click)="playTTSTeting()">TTS测试</ion-button> --\x3e\n {{avatarRole?.get("name")}}\n <ion-button (click)="menu.toggle()"> <ion-icon name="ellipsis-horizontal-outline"></ion-icon> </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n\n \x3c!-- <ion-segment value="voice">\n <ion-segment-button (click)="chatServ.createChatPanel(avatarRole)" value="chat">\n <ion-label>聊天</ion-label>\n </ion-segment-button>\n <ion-segment-button routerLink="{{\'/avatar/role/\'+avatarRole?.id}}" value="voice">\n <ion-label>语音</ion-label>\n </ion-segment-button>\n </ion-segment> --\x3e\n\n \x3c!-- 数字形象:动画效果 --\x3e\n <fm-avatar-role-image *ngIf="avatarRole&&fmodeChat" [fmodeChat]="fmodeChat" [role]="avatarRole" #avatar class="avatar"></fm-avatar-role-image>\n \x3c!-- <fm-avatar-role-particle #avatar class="avatar"></fm-avatar-role-particle> --\x3e\n\n \x3c!-- AI回复的最新消息 --\x3e\n <div class="ai-resp-input" #aiRespComp>{{fmodeChat?.latestAIResponse | hidexml}}</div>\n\n <fm-modal-chat-voice-input *ngIf="fmodeChat" [fmodeChat]="fmodeChat"></fm-modal-chat-voice-input>\n\n</div>\n\n',styles:["ion-menu ion-note{color:#ccc;font-weight:700}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.avatar{display:block;width:100%;height:100%}.ai-resp-input{font-size:1rem;color:#fff;position:fixed;top:60px;max-height:15vh;overflow-y:scroll;padding:0 10px}.user-asr-input{font-size:1rem;color:#fff;position:fixed;bottom:6vh;padding:0 10px}.test-button-group{color:#00f;position:fixed;bottom:20vh}.test-button-group button{padding:10px;margin:10px}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"ngmodule",type:RouterModule},{kind:"ngmodule",type:FormsModule},{kind:"ngmodule",type:IonicModule},{kind:"component",type:i2.IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:i2.IonButtons,selector:"ion-buttons",inputs:["collapse"]},{kind:"component",type:i2.IonCard,selector:"ion-card",inputs:["button","color","disabled","download","href","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:i2.IonCardContent,selector:"ion-card-content",inputs:["mode"]},{kind:"component",type:i2.IonCardHeader,selector:"ion-card-header",inputs:["color","mode","translucent"]},{kind:"component",type:i2.IonCardSubtitle,selector:"ion-card-subtitle",inputs:["color","mode"]},{kind:"component",type:i2.IonCardTitle,selector:"ion-card-title",inputs:["color","mode"]},{kind:"component",type:i2.IonChip,selector:"ion-chip",inputs:["color","disabled","mode","outline"]},{kind:"component",type:i2.IonContent,selector:"ion-content",inputs:["color","fixedSlotPlacement","forceOverscroll","fullscreen","scrollEvents","scrollX","scrollY"]},{kind:"component",type:i2.IonHeader,selector:"ion-header",inputs:["collapse","mode","translucent"]},{kind:"component",type:i2.IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:i2.IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:i2.IonLabel,selector:"ion-label",inputs:["color","mode","position"]},{kind:"component",type:i2.IonList,selector:"ion-list",inputs:["inset","lines","mode"]},{kind:"component",type:i2.IonMenu,selector:"ion-menu",inputs:["contentId","disabled","maxEdgeStart","menuId","side","swipeGesture","type"]},{kind:"component",type:i2.IonNote,selector:"ion-note",inputs:["color","mode"]},{kind:"component",type:i2.IonTitle,selector:"ion-title",inputs:["color","size"]},{kind:"component",type:i2.IonToolbar,selector:"ion-toolbar",inputs:["color","mode"]},{kind:"component",type:CompAvatarRoleImageComponent,selector:"fm-avatar-role-image",inputs:["fmodeChat","role"]},{kind:"component",type:ModalChatVoiceInputComponent,selector:"fm-modal-chat-voice-input",inputs:["fmodeChat","talkMode"]},{kind:"pipe",type:HidexmlPipe,name:"hidexml"}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarTalkComponent,decorators:[{type:Component,args:[{selector:"app-comp-avatar-talk",standalone:!0,imports:[CommonModule,RouterModule,FormsModule,IonicModule,CompAvatarParticleComponent,CompAvatarRoleImageComponent,ModalChatVoiceInputComponent,HidexmlPipe],providers:[FmodeVoiceService,NovaCloudService,ChatService,Diagnostic,ModalController],template:'<ion-menu #menu contentId="main-content" side="end">\n <ion-header>\n <ion-toolbar>\n <ion-title>资料</ion-title>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n\n <ion-card style="margin: 0px;">\n <img [src]="avatarRole?.get(\'thumb\')" alt="">\n <ion-card-header>\n <ion-card-subtitle>{{avatarRole?.get(\'tags\')}}</ion-card-subtitle>\n <ion-card-title>{{avatarRole?.get("name")}}</ion-card-title>\n </ion-card-header>\n \n <ion-card-content>\n {{avatarRole?.get("desc")}}\n\n <ion-list [inset]="true" style="margin:0px;">\n \x3c!-- <ion-item>\n <ion-avatar *ngIf="avatarRole?.get(\'thumb\')" aria-hidden="true" slot="start">\n <img [src]="avatarRole?.get(\'thumb\')" />\n </ion-avatar>\n <ion-label>{{avatarRole?.get("name")}}</ion-label>\n </ion-item> --\x3e\n <ion-item lines="none" *ngIf="avatarRole?.get(\'age\')">\n <ion-note slot="start">年龄</ion-note>\n <ion-label>{{avatarRole?.get("age")}}</ion-label>\n </ion-item>\n <ion-item lines="none" *ngIf="avatarRole?.get(\'gender\')">\n <ion-note slot="start">性别</ion-note>\n <ion-label>{{avatarRole?.get("gender")}}</ion-label>\n </ion-item>\n <ion-item lines="none">\n <ion-note slot="start">称号</ion-note>\n <ion-label>{{avatarRole?.get("title")}}</ion-label>\n </ion-item>\n \n <ion-item lines="none">\n <ion-note slot="start">擅长</ion-note>\n <ion-label>{{avatarRole?.get("tags")?.join(\',\')}}</ion-label>\n </ion-item>\n\n </ion-list>\n </ion-card-content>\n </ion-card>\n \n \n \n </ion-content>\n</ion-menu>\n\n<div class="ion-page" id="main-content">\n <ion-header class="ion-no-border">\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="goBack()"> <ion-icon name="chevron-back-outline"></ion-icon> </ion-button>\n </ion-buttons>\n <ion-title>\n <ion-chip *ngIf="avatarRole?.get(\'title\')">{{avatarRole?.get("title")}}</ion-chip>\n </ion-title>\n <ion-buttons slot="end">\n \x3c!-- <ion-button (click)="playTTSTeting()">TTS测试</ion-button> --\x3e\n {{avatarRole?.get("name")}}\n <ion-button (click)="menu.toggle()"> <ion-icon name="ellipsis-horizontal-outline"></ion-icon> </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n\n \x3c!-- <ion-segment value="voice">\n <ion-segment-button (click)="chatServ.createChatPanel(avatarRole)" value="chat">\n <ion-label>聊天</ion-label>\n </ion-segment-button>\n <ion-segment-button routerLink="{{\'/avatar/role/\'+avatarRole?.id}}" value="voice">\n <ion-label>语音</ion-label>\n </ion-segment-button>\n </ion-segment> --\x3e\n\n \x3c!-- 数字形象:动画效果 --\x3e\n <fm-avatar-role-image *ngIf="avatarRole&&fmodeChat" [fmodeChat]="fmodeChat" [role]="avatarRole" #avatar class="avatar"></fm-avatar-role-image>\n \x3c!-- <fm-avatar-role-particle #avatar class="avatar"></fm-avatar-role-particle> --\x3e\n\n \x3c!-- AI回复的最新消息 --\x3e\n <div class="ai-resp-input" #aiRespComp>{{fmodeChat?.latestAIResponse | hidexml}}</div>\n\n <fm-modal-chat-voice-input *ngIf="fmodeChat" [fmodeChat]="fmodeChat"></fm-modal-chat-voice-input>\n\n</div>\n\n',styles:["ion-menu ion-note{color:#ccc;font-weight:700}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.avatar{display:block;width:100%;height:100%}.ai-resp-input{font-size:1rem;color:#fff;position:fixed;top:60px;max-height:15vh;overflow-y:scroll;padding:0 10px}.user-asr-input{font-size:1rem;color:#fff;position:fixed;bottom:6vh;padding:0 10px}.test-button-group{color:#00f;position:fixed;bottom:20vh}.test-button-group button{padding:10px;margin:10px}\n"]}]}],ctorParameters:()=>[{type:FmodeVoiceService},{type:i2.Platform},{type:i1$1.Router},{type:i2.NavController},{type:i1$1.ActivatedRoute},{type:ChatService},{type:NovaCloudService}],propDecorators:{avatarComp:[{type:ViewChild,args:["avatar"]}],aiRespComp:[{type:ViewChild,args:["aiRespComp"]}]}});const AvatarRoutes=[{path:"role/:roleId",component:CompAvatarTalkComponent,runGuardsAndResolvers:"always"}];class AvatarModule{static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AvatarModule,deps:[],target:i0.ɵɵFactoryTarget.NgModule})}static{this.ɵmod=i0.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:AvatarModule,imports:[CommonModule,FormsModule,HttpClientModule,ReactiveFormsModule,i1$1.RouterModule,CompAvatarTalkComponent],exports:[CompAvatarTalkComponent]})}static{this.ɵinj=i0.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AvatarModule,imports:[CommonModule,FormsModule,HttpClientModule,ReactiveFormsModule,RouterModule.forChild(AvatarRoutes),CompAvatarTalkComponent]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AvatarModule,decorators:[{type:NgModule,args:[{declarations:[],imports:[CommonModule,FormsModule,HttpClientModule,ReactiveFormsModule,RouterModule.forChild(AvatarRoutes),CompAvatarTalkComponent],exports:[CompAvatarTalkComponent]}]}]});class CompAvatarRoleVideoComponent{constructor(){this.animClass="waiting",this.videoMap={}}playWave(){!this.wave&&Recorder.WaveView&&(this.wave=Recorder.WaveView({elem:".record-wave-avatar",keep:!1}));let e=function generatePowerLevel(){return 100*Math.random()}();this.waveInterval=setInterval((()=>{let t=function generateSampleRate(){const e=[44100,48e3,88200,96e3];return e[Math.floor(Math.random()*e.length)]}(),n=function generatePcmData(e){const t=[];for(let n=0;n<e;n++)t.push(Math.floor(65536*Math.random())-32768);return t}(1e3);this.wave.input(n,e,t)}),40)}stopWave(){clearInterval(this.waveInterval)}ngAfterViewInit(){}ngOnInit(){setTimeout((()=>{this.videoMap=this.fmodeChat.avatarConfig?.video,this.playVideo(this.videoMap?.waiting),this.fmodeChat.playAnimation=this.playAnimation}),1500)}playAnimation(){let e=this;return t=>{let n=e.avatarVideo.nativeElement;switch(e.animClass=t,e.stopWave(),e.playVideo(e.videoMap[t]),t){case"thinking":case"waiting":n.style.animationPlayState="running";break;case"talking":n.style.animationPlayState="running",e.playWave();break;case"listening":n.style.animationPlayState="pause";break;default:n.style.animationPlayState="paused"}}}playVideo(e){this.avatarVideo.nativeElement.autoplay=!0,this.avatarVideo.nativeElement.loop=!0,this.avatarVideo.nativeElement.controls=!1,this.avatarVideo.nativeElement.src=e,this.avatarVideo.nativeElement.play()}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarRoleVideoComponent,deps:[],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:CompAvatarRoleVideoComponent,isStandalone:!0,selector:"fm-avatar-role-video",inputs:{fmodeChat:"fmodeChat",role:"role"},viewQueries:[{propertyName:"avatarVideo",first:!0,predicate:["avatarVideo"],descendants:!0}],ngImport:i0,template:'<div class="page">\n <div class="avatar" [class]="animClass">\n <div class="avatar-photo">\n <video #avatarVideo alt=""></video>\n \x3c!-- 音频波动 --\x3e\n <div class="record-wave-avatar">\n </div>\n </div>\n </div>\n</div>',styles:[".page{position:relative;width:100vw;height:100%;top:0;left:0;display:flex;justify-content:center;align-items:center;background-color:#000}.avatar{height:100%;width:100%;display:flex;justify-content:center;align-items:center}.avatar .avatar-photo{position:relative;display:flex;justify-content:center;width:80%;max-height:100%}.avatar .avatar-photo video{border-radius:50%;max-height:100%;max-width:100%}.avatar .record-wave-avatar{height:50px;width:100%;position:absolute;float:left;left:0;bottom:0}.thinking,.listening,.waiting,.talking{animation-duration:2s;animation-play-state:running;animation-iteration-count:infinite;animation-timing-function:ease-in-out}@keyframes waitingAnimation{0%{transform:scale(1)}50%{transform:scale(1.05)}to{transform:scale(1)}}@keyframes thinkingAnimation{0%{transform:rotate(0)}30%{transform:rotate(10deg)}60%{transform:rotate(-10deg)}to{transform:rotate(0)}}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"ngmodule",type:FormsModule}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompAvatarRoleVideoComponent,decorators:[{type:Component,args:[{selector:"fm-avatar-role-video",standalone:!0,imports:[CommonModule,FormsModule],template:'<div class="page">\n <div class="avatar" [class]="animClass">\n <div class="avatar-photo">\n <video #avatarVideo alt=""></video>\n \x3c!-- 音频波动 --\x3e\n <div class="record-wave-avatar">\n </div>\n </div>\n </div>\n</div>',styles:[".page{position:relative;width:100vw;height:100%;top:0;left:0;display:flex;justify-content:center;align-items:center;background-color:#000}.avatar{height:100%;width:100%;display:flex;justify-content:center;align-items:center}.avatar .avatar-photo{position:relative;display:flex;justify-content:center;width:80%;max-height:100%}.avatar .avatar-photo video{border-radius:50%;max-height:100%;max-width:100%}.avatar .record-wave-avatar{height:50px;width:100%;position:absolute;float:left;left:0;bottom:0}.thinking,.listening,.waiting,.talking{animation-duration:2s;animation-play-state:running;animation-iteration-count:infinite;animation-timing-function:ease-in-out}@keyframes waitingAnimation{0%{transform:scale(1)}50%{transform:scale(1.05)}to{transform:scale(1)}}@keyframes thinkingAnimation{0%{transform:rotate(0)}30%{transform:rotate(10deg)}60%{transform:rotate(-10deg)}to{transform:rotate(0)}}\n"]}]}],propDecorators:{avatarVideo:[{type:ViewChild,args:["avatarVideo"]}],fmodeChat:[{type:Input}],role:[{type:Input}]}});class ChatListComponent{constructor(e,t,n){this.chatServ=e,this.alertCtrl=t,this.navCtrl=n,this.chatList=[],this.onItemClick=e=>{this.goSession(e)},this.avatar="https://ionicframework.com/docs/img/demos/avatar.svg",this.isPreventGo=!1,this.chatServ.getChatSession().then((()=>{}))}async goSession(e){if(!this.isPreventGo)if(e?.rid||e?.sid)this.chatServ.restoreChatPanel(e);else{(await this.alertCtrl.create({header:"注意",subHeader:"请您选择右侧角色",message:"开始对话",buttons:[{role:"ok",text:"知道了",handler:()=>{}}]})).present(),this.navCtrl.navigateRoot("/chat/pro/mask")}}async presentEditTitle(e,t,n){this.isPreventGo=!0,setTimeout((()=>{this.isPreventGo=!1}),500),n.preventDefault();const o=await this.alertCtrl.create({header:"修改会话标题",subHeader:"",message:"",buttons:[{text:"取消",role:"cancel",handler:()=>{}},{text:"确定",role:"confirm",handler:n=>{t.title=n.title,e?.set("title",n.title),e?.save()}}],inputs:[{placeholder:"会话标题",name:"title",value:t?.title||""}]});await o.present()}async presentDeleteTItle(e,t,n){this.isPreventGo=!0,setTimeout((()=>{this.isPreventGo=!1}),500),n.preventDefault();const o=await this.alertCtrl.create({header:"确认删除?",subHeader:"",message:"",buttons:[{text:"取消",role:"cancel",handler:()=>{}},{text:"确定",role:"confirm",handler:()=>{t.isHidden=!0,e?.set("isDeleted",!0),e?.save()}}]});await o.present()}truncateString(e){return e&&e.length>10?e.slice(0,10)+"...":e}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatListComponent,deps:[{token:ChatService},{token:i2$3.AlertController},{token:i2$3.NavController}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:ChatListComponent,isStandalone:!0,selector:"app-chat-list",inputs:{onItemClick:"onItemClick"},ngImport:i0,template:'<ion-list>\n <ng-container *ngFor="let chat of (chatServ?.chatList || chatList)">\n <ion-item [button]="true" detail="false" *ngIf="!chat?.isHidden" (click)="onItemClick(chat)">\n <div class="unread-indicator-wrapper" slot="start">\n <div class="unread-indicator"></div>\n </div>\n <ion-label>\n <div style="display: flex;justify-content: space-between; align-items: center;">\n <div style="display: flex; flex-direction: row;align-items: center;">\n <strong style="display: flex;align-items: center;">\n <ion-avatar style="margin-right: 10px;">\n <img [src]="chat?.thumb||avatar" />\n </ion-avatar>\n <p style="max-width: 7rem;white-space: nowrap;">{{truncateString(chat?.title)}}</p>\n </strong>\n\n <ion-icon (click)="presentEditTitle(chat?.session,chat,$event)" name="brush-sharp" style="margin-left: 1rem;"></ion-icon>\n <ion-icon (click)="presentDeleteTItle(chat?.session,chat,$event)" name="trash-sharp" style="margin-left: 0.5rem;"></ion-icon>\n \n </div>\n <div class="metadata-end-wrapper" slot="end">\n <ion-note color="medium">{{chat?.latest | date:"HH:mm"}}</ion-note>\n <ion-icon color="medium" name="chevron-forward"></ion-icon>\n </div>\n </div>\n <ion-text></ion-text><br />\n <ion-note color="medium" class="ion-text-wrap">\n {{chat?.message}}\n </ion-note>\n </ion-label>\n </ion-item>\n </ng-container>\n </ion-list>',styles:["ion-icon{color:#fff}ion-list{margin:3px}ion-list ion-item{--inner-padding-bottom:0px;--inner-padding-end:0px;--inner-padding-start:0px;--inner-padding-to:0px;--padding-bottom:0px;--padding-end:0px;--padding-start:0px;--padding-to:0px}ion-list ul{width:100%;list-style-type:none;padding:0;margin:0 0 10px;display:flex;flex-wrap:wrap;background-color:#fff;border-radius:10px}ion-list ul .active__{position:relative;padding:5px 15px;font-size:18px;font-weight:700;color:#535353;transition:.3s}ion-list ul .active{color:#2d8af7;background-color:#f2f4ff;border-radius:10px}ion-list ul li{flex:1 1 auto}ion-list ul li div{cursor:pointer;text-align:center}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"pipe",type:i2$2.DatePipe,name:"date"},{kind:"component",type:IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:IonList,selector:"ion-list",inputs:["inset","lines","mode"]},{kind:"component",type:IonLabel,selector:"ion-label",inputs:["color","mode","position"]},{kind:"component",type:IonNote,selector:"ion-note",inputs:["color","mode"]},{kind:"component",type:IonAvatar,selector:"ion-avatar"},{kind:"component",type:IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:IonText,selector:"ion-text",inputs:["color","mode"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatListComponent,decorators:[{type:Component,args:[{selector:"app-chat-list",imports:[CommonModule,IonIcon,IonList,IonLabel,IonNote,IonButton,IonAvatar,IonItem,IonText],standalone:!0,template:'<ion-list>\n <ng-container *ngFor="let chat of (chatServ?.chatList || chatList)">\n <ion-item [button]="true" detail="false" *ngIf="!chat?.isHidden" (click)="onItemClick(chat)">\n <div class="unread-indicator-wrapper" slot="start">\n <div class="unread-indicator"></div>\n </div>\n <ion-label>\n <div style="display: flex;justify-content: space-between; align-items: center;">\n <div style="display: flex; flex-direction: row;align-items: center;">\n <strong style="display: flex;align-items: center;">\n <ion-avatar style="margin-right: 10px;">\n <img [src]="chat?.thumb||avatar" />\n </ion-avatar>\n <p style="max-width: 7rem;white-space: nowrap;">{{truncateString(chat?.title)}}</p>\n </strong>\n\n <ion-icon (click)="presentEditTitle(chat?.session,chat,$event)" name="brush-sharp" style="margin-left: 1rem;"></ion-icon>\n <ion-icon (click)="presentDeleteTItle(chat?.session,chat,$event)" name="trash-sharp" style="margin-left: 0.5rem;"></ion-icon>\n \n </div>\n <div class="metadata-end-wrapper" slot="end">\n <ion-note color="medium">{{chat?.latest | date:"HH:mm"}}</ion-note>\n <ion-icon color="medium" name="chevron-forward"></ion-icon>\n </div>\n </div>\n <ion-text></ion-text><br />\n <ion-note color="medium" class="ion-text-wrap">\n {{chat?.message}}\n </ion-note>\n </ion-label>\n </ion-item>\n </ng-container>\n </ion-list>',styles:["ion-icon{color:#fff}ion-list{margin:3px}ion-list ion-item{--inner-padding-bottom:0px;--inner-padding-end:0px;--inner-padding-start:0px;--inner-padding-to:0px;--padding-bottom:0px;--padding-end:0px;--padding-start:0px;--padding-to:0px}ion-list ul{width:100%;list-style-type:none;padding:0;margin:0 0 10px;display:flex;flex-wrap:wrap;background-color:#fff;border-radius:10px}ion-list ul .active__{position:relative;padding:5px 15px;font-size:18px;font-weight:700;color:#535353;transition:.3s}ion-list ul .active{color:#2d8af7;background-color:#f2f4ff;border-radius:10px}ion-list ul li{flex:1 1 auto}ion-list ul li div{cursor:pointer;text-align:center}\n"]}]}],ctorParameters:()=>[{type:ChatService},{type:i2$3.AlertController},{type:i2$3.NavController}],propDecorators:{onItemClick:[{type:Input}]}});class FmChatHeaderArea{constructor(e){this.navCtrl=e,this.isModalOpen=!1}goBack(){this.navCtrl.back()}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatHeaderArea,deps:[{token:i2$3.NavController}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:FmChatHeaderArea,isStandalone:!0,selector:"fm-chat-header-area",inputs:{chat:"chat"},ngImport:i0,template:'<ion-toolbar *ngIf="chat?.isAvatarShow==false">\n <ion-buttons slot="start">\n <ion-button (click)="goBack()">\n <ion-icon name="chevron-back-outline"></ion-icon>\n </ion-button>\n </ion-buttons>\n <ion-title>\n <div class="title-avatar-area">\n <div class="avatar-img" (click)="chat.showAvatar()">\n <img *ngIf="chat?.role?.get(\'avatar\')||chat?.role?.get(\'thumb\')" [src]="chat?.role?.get(\'avatar\')||chat?.role?.get(\'thumb\')" />\n <ion-icon *ngIf="chat?.role?.get(\'avatarConfig\')" name="resize-outline"></ion-icon>\n </div>\n <span (click)="chat.showAvatar()">\n {{chat?.role?.get("name")}}\n </span>\n </div>\n </ion-title>\n\n <ion-buttons slot="end">\n <ion-button (click)="isModalOpen=true"> <ion-icon name="ellipsis-horizontal-outline"></ion-icon> </ion-button>\n </ion-buttons>\n</ion-toolbar>\n\n<div class="avatar-area" *ngIf="chat?.isAvatarShow==true">\n <fm-avatar-role-image *ngIf="chat?.avatarMode==\'image\'" [fmodeChat]="chat" [role]="avatarRole"></fm-avatar-role-image>\n <fm-avatar-role-video *ngIf="chat?.avatarMode==\'video\'" [fmodeChat]="chat" [role]="avatarRole"></fm-avatar-role-video>\n</div>\n\n\n<ion-modal [isOpen]="isModalOpen" (willDismiss)="isModalOpen=false">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="isModalOpen=false">返回</ion-button>\n </ion-buttons>\n <ion-title>简介</ion-title>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n\n <ion-card style="margin: 0px;">\n <img [src]="chat?.role?.get(\'thumb\')" alt="">\n <ion-card-header>\n <ion-card-subtitle>{{chat?.role?.get(\'tags\')}}</ion-card-subtitle>\n <ion-card-title>{{chat?.role?.get("name")}}</ion-card-title>\n </ion-card-header>\n \n <ion-card-content>\n {{chat?.role?.get("desc")}}\n \n <ion-list [inset]="true" style="margin:0px;">\n \x3c!-- <ion-item>\n <ion-avatar *ngIf="chat?.role?.get(\'thumb\')" aria-hidden="true" slot="start">\n <img [src]="chat?.role?.get(\'thumb\')" />\n </ion-avatar>\n <ion-label>{{chat?.role?.get("name")}}</ion-label>\n </ion-item> --\x3e\n <ion-item lines="none" *ngIf="chat?.role?.get(\'age\')">\n <ion-note slot="start">年龄</ion-note>\n <ion-label>{{chat?.role?.get("age")}}</ion-label>\n </ion-item>\n <ion-item lines="none" *ngIf="chat?.role?.get(\'gender\')">\n <ion-note slot="start">性别</ion-note>\n <ion-label>{{chat?.role?.get("gender")}}</ion-label>\n </ion-item>\n <ion-item lines="none">\n <ion-note slot="start">称号</ion-note>\n <ion-label>{{chat?.role?.get("title")}}</ion-label>\n </ion-item>\n \n <ion-item lines="none">\n <ion-note slot="start">擅长</ion-note>\n <ion-label>{{chat?.role?.get("tags")?.join(\',\')}}</ion-label>\n </ion-item>\n \n </ion-list>\n </ion-card-content>\n </ion-card>\n </ion-content>\n </ng-template>\n </ion-modal>',styles:[".title-avatar-area{width:100%;height:100%;display:flex;justify-content:center;align-items:center}.title-avatar-area .avatar-img img{width:32px;height:32px;border-radius:50%;margin-right:5px}.title-avatar-area .avatar-img ion-icon{background:#df76dfcc;border-radius:50%;padding:3px;position:absolute;color:#000;margin-left:-20px;font-size:10px;margin-top:18px}.avatar-area{height:100%}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:IonToolbar,selector:"ion-toolbar",inputs:["color","mode"]},{kind:"component",type:IonButtons,selector:"ion-buttons",inputs:["collapse"]},{kind:"component",type:IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:IonModal,selector:"ion-modal"},{kind:"component",type:IonTitle,selector:"ion-title",inputs:["color","size"]},{kind:"component",type:IonHeader,selector:"ion-header",inputs:["collapse","mode","translucent"]},{kind:"component",type:IonList,selector:"ion-list",inputs:["inset","lines","mode"]},{kind:"component",type:IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:IonCard,selector:"ion-card",inputs:["button","color","disabled","download","href","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:IonLabel,selector:"ion-label",inputs:["color","mode","position"]},{kind:"component",type:IonNote,selector:"ion-note",inputs:["color","mode"]},{kind:"component",type:CompAvatarRoleImageComponent,selector:"fm-avatar-role-image",inputs:["fmodeChat","role"]},{kind:"component",type:CompAvatarRoleVideoComponent,selector:"fm-avatar-role-video",inputs:["fmodeChat","role"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatHeaderArea,decorators:[{type:Component,args:[{selector:"fm-chat-header-area",standalone:!0,imports:[CommonModule,IonToolbar,IonButtons,IonButton,IonIcon,IonModal,IonAvatar,IonTitle,IonHeader,IonList,IonItem,IonCard,IonLabel,IonNote,CompAvatarRoleImageComponent,CompAvatarRoleVideoComponent],template:'<ion-toolbar *ngIf="chat?.isAvatarShow==false">\n <ion-buttons slot="start">\n <ion-button (click)="goBack()">\n <ion-icon name="chevron-back-outline"></ion-icon>\n </ion-button>\n </ion-buttons>\n <ion-title>\n <div class="title-avatar-area">\n <div class="avatar-img" (click)="chat.showAvatar()">\n <img *ngIf="chat?.role?.get(\'avatar\')||chat?.role?.get(\'thumb\')" [src]="chat?.role?.get(\'avatar\')||chat?.role?.get(\'thumb\')" />\n <ion-icon *ngIf="chat?.role?.get(\'avatarConfig\')" name="resize-outline"></ion-icon>\n </div>\n <span (click)="chat.showAvatar()">\n {{chat?.role?.get("name")}}\n </span>\n </div>\n </ion-title>\n\n <ion-buttons slot="end">\n <ion-button (click)="isModalOpen=true"> <ion-icon name="ellipsis-horizontal-outline"></ion-icon> </ion-button>\n </ion-buttons>\n</ion-toolbar>\n\n<div class="avatar-area" *ngIf="chat?.isAvatarShow==true">\n <fm-avatar-role-image *ngIf="chat?.avatarMode==\'image\'" [fmodeChat]="chat" [role]="avatarRole"></fm-avatar-role-image>\n <fm-avatar-role-video *ngIf="chat?.avatarMode==\'video\'" [fmodeChat]="chat" [role]="avatarRole"></fm-avatar-role-video>\n</div>\n\n\n<ion-modal [isOpen]="isModalOpen" (willDismiss)="isModalOpen=false">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="isModalOpen=false">返回</ion-button>\n </ion-buttons>\n <ion-title>简介</ion-title>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n\n <ion-card style="margin: 0px;">\n <img [src]="chat?.role?.get(\'thumb\')" alt="">\n <ion-card-header>\n <ion-card-subtitle>{{chat?.role?.get(\'tags\')}}</ion-card-subtitle>\n <ion-card-title>{{chat?.role?.get("name")}}</ion-card-title>\n </ion-card-header>\n \n <ion-card-content>\n {{chat?.role?.get("desc")}}\n \n <ion-list [inset]="true" style="margin:0px;">\n \x3c!-- <ion-item>\n <ion-avatar *ngIf="chat?.role?.get(\'thumb\')" aria-hidden="true" slot="start">\n <img [src]="chat?.role?.get(\'thumb\')" />\n </ion-avatar>\n <ion-label>{{chat?.role?.get("name")}}</ion-label>\n </ion-item> --\x3e\n <ion-item lines="none" *ngIf="chat?.role?.get(\'age\')">\n <ion-note slot="start">年龄</ion-note>\n <ion-label>{{chat?.role?.get("age")}}</ion-label>\n </ion-item>\n <ion-item lines="none" *ngIf="chat?.role?.get(\'gender\')">\n <ion-note slot="start">性别</ion-note>\n <ion-label>{{chat?.role?.get("gender")}}</ion-label>\n </ion-item>\n <ion-item lines="none">\n <ion-note slot="start">称号</ion-note>\n <ion-label>{{chat?.role?.get("title")}}</ion-label>\n </ion-item>\n \n <ion-item lines="none">\n <ion-note slot="start">擅长</ion-note>\n <ion-label>{{chat?.role?.get("tags")?.join(\',\')}}</ion-label>\n </ion-item>\n \n </ion-list>\n </ion-card-content>\n </ion-card>\n </ion-content>\n </ng-template>\n </ion-modal>',styles:[".title-avatar-area{width:100%;height:100%;display:flex;justify-content:center;align-items:center}.title-avatar-area .avatar-img img{width:32px;height:32px;border-radius:50%;margin-right:5px}.title-avatar-area .avatar-img ion-icon{background:#df76dfcc;border-radius:50%;padding:3px;position:absolute;color:#000;margin-left:-20px;font-size:10px;margin-top:18px}.avatar-area{height:100%}\n"]}]}],ctorParameters:()=>[{type:i2$3.NavController}],propDecorators:{chat:[{type:Input}]}}),Parse__default.applicationId||(Parse__default.initialize("ncloudmaster"),Parse__default.serverURL=(Parse__default.serverURL?.split("parse")?.[0]||"https://server.fmode.cn/")+"parse");class AuthService{isGuardLock(e){let t=!0,n=Parse__default.User.current();return t=!n?.id&&this.guardMap[e],t}get logoUrl(){return localStorage.getItem("LOGO_URL")||this._logoUrl||"https://file-cloud.fmode.cn/E4KpGvTEto/20230822/3mkf41033623275.png"}set logoUrl(e){localStorage.setItem("LOGO_URL",e),this._logoUrl=this._logoUrl}getCompanyId(){let e=localStorage.getItem("company");return e=this.company||e,e}constructor(e,t,n){this.router=e,this.novaCloud=t,this.http=n,this.guardMap={},this.isModalShow=!1,this._logoUrl="https://file-cloud.fmode.cn/E4KpGvTEto/20230822/3mkf41033623275.png",this.isLoggedIn=!1,this.LoginPage="/pcuser/login",this.mobileUserMap={}}init(e){this.company=e.company,this.guardType=e.guardType,this.saveParamsInvite()}checkLoginLock(){let e=Parse__default.User.current();return!!e?.id||(this.isModalShow=!0,this.isLoggedIn=!1,!1)}checkLogin(e){this.guardMap[e]=!0;let t=Parse__default.User.current();return console.log("currentUser",t),t&&t.id?(this.setAccount(t),this.isLoggedIn=!0,!0):this.guardType&&"page"!=this.guardType?"modal"==this.guardType?(this.isModalShow=!0,this.isLoggedIn=!1,!0):void 0:(this.redirectUrl=e,this.router.navigate([this.LoginPage]),!1)}async setAccount(e){if(this.account?.id)return;let t=Parse__default.Object.extend("Account"),n=e?.get("company")||{__type:"Pointer",className:"Company",objectId:this.getCompanyId()}||null,o=new Parse__default.Query("Account");o.equalTo("user",e.toPointer());let i=await o.first();return i?.id||(i=new t,i.set({user:e.toPointer(),company:n}),i=await i.save()),this.account=i,i}login(e,t){return new Promise(((n,o)=>{Parse__default.User.logIn(e,t).then((async e=>{if(this.bindInvite(e),this.setCurrentUserLocalStorage(e),"modal"==this.guardType)return await this.refreshPage(),void n(!0);let t=new Parse__default.Query("Company");t.select("rootPage"),t.equalTo("objectId",e?.get("company")?.id);let o=await t.first(),i=o?.get("rootPage");this.redirectUrl=this.redirectUrl||i||"/project/dashboard";let a=this.redirectUrl;a=decodeURIComponent(a),this.router.navigate([a])})).catch((e=>{console.error(e),o({message:"无此用户信息,请先在小程序登录"})}))}))}refreshPage(){return new Promise((e=>{let t=this.router.url;Parse__default.User.current()?.id&&(this.isModalShow=!1),this.router.navigateByUrl("/",{skipLocationChange:!0}).then((()=>{this.router.navigateByUrl(t).then((()=>{e(!0)}))}))}))}setCurrentUserLocalStorage(e){e.get("company")?.id&&localStorage.setItem("company",e.get("company")?.id)}logout(e,t){let n=localStorage.getItem("company");localStorage.clear(),localStorage.setItem("company",n),Parse__default.User.logOut().then((e=>{this.router.navigate([t||"/pcuser/login"])}))}async loginMobilePassword(e,t,n){let o=await this.getMobileUser(e);o?this.login(o,t).then((async e=>{this.isModalShow=!1})).catch((e=>{console.log(e),n.create("error","错误的用户名或密码")})):n.create("error","用户不存在,请尝试其他登录方式")}signMobilePassword(e,t){return new Promise(((n,o)=>{Parse__default.User.signUp(this.getCompanyId()+"-"+e,t,"").then((async t=>{t.id&&(console.log(t),t.set("company",{__type:"Pointer",className:"Company",objectId:this.getCompanyId()}),t.set("mobile",e),t.set("type","user"),this.bindInvite(t),t=await t.save(),n(t))})).catch((e=>{o(e)}))}))}async getMobileUser(e){let t=this.getCompanyId(),n=t+e;if(this.mobileUserMap[n])return this.mobileUserMap[n];let o=await this.novaCloud.api("/auth/getusername",{company:t,mobile:e});return o?.username&&(this.mobileUserMap[n]=o?.username),this.mobileUserMap[n]}async loginCode(e,t,n){return new Promise(((o,i)=>{if(!t)return n?.create("error","请填写有效验证码"),void i();let a=Parse__default.serverURL?.split("parse")?.[0]||"https://server.fmode.cn/";this.http.get(a+`api/auth/mobile?company=${this.company}&mobile=${e}&code=${t}`,{}).pipe(catchError((async e=>{console.log(e),n?.create("error","登录失败:"+e.error.mess),i()}))).subscribe((e=>{200==e.code?Parse__default.User.become(e.data.token).then((async e=>{if(console.log(e),e.id)return this.bindInvite(e),void o(!0);n?.create("error","登录失败"),i()})):(n?.create("error","登录失败"),i())}))}))}saveParamsInvite(){let e=this.novaCloud.searchParse();console.log("saveParamsInvite",e);let t=e?.invite;console.log(t),t&&localStorage.setItem("invite",e?.invite)}bindInvite(e){if(!(e=e||Parse__default.User.current()))return;if(e?.get("invite")?.id)return;let t=localStorage.getItem("invite");t&&this.novaCloud.api("/auth/invite",{current:e?.id,invite:t,type:"code"})}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AuthService,deps:[{token:i1$1.Router},{token:NovaCloudService},{token:i1.HttpClient}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AuthService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AuthService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:i1$1.Router},{type:NovaCloudService},{type:i1.HttpClient}]});class AccountService{constructor(e,t,n){this.ncloud=e,this.authServ=t,this.http=n,this.company="",this.billing={credit:{usedDetail:{}}},this.wxAppId="",this.wxpayEnabled=!1,this.company=this.authServ.company||localStorage.getItem("company"),this.getBilling(),this.getProfile(),this.getUserOpenid()}async getProfile(){let e=Parse__default.User.current()?.id;if(!e)return;let t=new Parse__default.Query("Profile");t.equalTo("user",e),t.equalTo("company",this.company),t.notEqualTo("isDeleted",!0);let n=await t.first();n?.id&&(this.profile=n)}async getBilling(){let e;try{e=await this.ncloud.apig("aigc/account",null,"get")}catch(e){}return e?.credit&&(this.billing=e),e}async getUserOpenid(){let e=-1!=navigator.userAgent.toLowerCase().indexOf("micromessenger"),t=this.getQueryStringByName("code"),n=localStorage.getItem("openid");if(!n){if(!Parse__default.User.current())return;let o=Parse__default.User.current().get("wechat");n=o?.wxb4193c93ae9aa696?.openid,e&&(t?await this.getwechat(t):this.authWechat())}}authWechat(e="/account/billing"){if(!localStorage.getItem("openid")){let t="https://ai.fmode.cn"+e;return t=encodeURIComponent(t),void(window.location.href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxb4193c93ae9aa696&redirect_uri="+t+"&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect")}}getQueryStringByName(e){let t=location.search.match(new RegExp("[?&]"+e+"=([^&]+)","i"));return null==t||t.length<1?"":t[1]}async getwechat(e,t="/account/billing"){return new Promise((async(n,o)=>{this.http.post("https://server.fmode.cn/api/wechat/get_wx",{company:this.company,code:e}).subscribe((async e=>{if(console.log(e),e&&200==e.code&&e.data.openid){let t=e.data.openid;localStorage.setItem("openid",t),localStorage.removeItem("code"),Parse__default.User.current().set("wechat",{wxb4193c93ae9aa696:{openid:t}}),await Parse__default.User.current().save(),n(!0)}}),(async e=>{console.log("Error updating items",e),this.authWechat(t),o(!1)}))}))}getWXSignPackageInWechat(){let e={company:this.company,href:encodeURIComponent(location.href.split("?")[0])};this.http.post("https://server.fmode.cn/api/wechat/getconfig",e).subscribe((e=>{const t=e.data;this.wxAppId=t.appid,this.wxpayEnabled=!0,wx.config({debug:!1,appId:t.appid,timestamp:t.timestamp,nonceStr:t.nonceStr,signature:t.signature,jsApiList:["chooseWXPay","onMenuShareTimeline","onMenuShareAppMessage","onMenuShareQQ","onMenuShareQZone","updateAppMessageShareData","updateTimelineShareData"]});let n="https://ai.fmode.cn";location.pathname;Parse__default.User.current()?.id;let o={title:"飞码AI",desc:"解放创意引领未来|国际前沿的AIGC平台",link:n,type:"link",imgUrl:"https://file-cloud.fmode.cn/E4KpGvTEto/20230822/3mkf41033623275.png",success:function(){console.log("分享成功")},error:function(){console.log("分享失败")},cancel:function(){console.log("取消分享")}};wx.ready((()=>{wx.updateAppMessageShareData(o),wx.updateTimelineShareData(o)})),wx.error((()=>{}))}))}async saveAccountLog(e,t,n,o){return new Promise(((i,a)=>{this.http.post("https://test.fmode.cn/api/apig/saveAccountLog",{company:n,uid:Parse__default.User.current().id,orderid:t,info:e}).subscribe((e=>{console.log(e),i(!0)}),(e=>{console.warn(e),o&&o.error("请求超时,请稍后再试"),a()}))}))}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AccountService,deps:[{token:NovaCloudService},{token:AuthService},{token:i1.HttpClient}],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AccountService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:AccountService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[{type:NovaCloudService},{type:AuthService},{type:i1.HttpClient}]});class CompUserAvatarComponent{constructor(e){this.novaAccount=e,this.type="icon",this.text="U"}ngOnInit(){this.type=this.getType()}ngOnChanges(){this.refresh()}async refresh(){await this.novaAccount.getProfile();let e=this.novaAccount.profile;e?.get("type")&&("student"==e?.get("type")?this.identity="https://file-cloud.fmode.cn/khgbeQmvYZ/20231123/k1k4iq103416124.png":this.identity="https://file-cloud.fmode.cn/E4KpGvTEto/20231116/q12c16094638625.png")}getType(){return this.user?.id?this.user?.get("avatar")?"avatar":this.user?.get("nickname")?(this.text=this.user?.get("nickname")?.slice(0,1),"text"):"icon":"icon"}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompUserAvatarComponent,deps:[{token:AccountService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:CompUserAvatarComponent,isStandalone:!0,selector:"app-comp-user-avatar",inputs:{user:"user"},usesOnChanges:!0,ngImport:i0,template:'<ng-container *ngIf="user?.id || type == \'icon\'">\n <div class="avatar-com">\n \x3c!-- 默认ICON --\x3e\n <nz-avatar\n *ngIf="type == \'icon\'"\n [style]="{ backgroundColor: \'#0199f9\' }"\n nzIcon="user"\n ></nz-avatar>\n \x3c!-- <div *ngIf="type==\'icon\'" class="iconfont icon-yonghu-yuan"></div> --\x3e\n \x3c!-- 头像照片 --\x3e\n <div class="avatar-com">\n <nz-avatar class="comp-avatar"\n *ngIf="type == \'avatar\'"\n [nzSrc]="user?.get(\'avatar\')"\n ></nz-avatar>\n <img\n class="auth-icon"\n *ngIf="identity && type == \'avatar\'"\n [src]="identity"\n alt="已认证"\n />\n </div>\n \x3c!-- 昵称首字符 --\x3e\n <nz-avatar\n *ngIf="type == \'text\'"\n style="background-color: #0199f9"\n [nzText]="text"\n ></nz-avatar>\n </div>\n</ng-container>\n',styles:[".avatar-com{position:relative;width:32px;height:32px}.avatar-com .auth-icon{width:20px;height:20px;border-radius:50%;position:absolute;right:-6px;bottom:-2px}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"ngmodule",type:NzAvatarModule},{kind:"component",type:i3.NzAvatarComponent,selector:"nz-avatar",inputs:["nzShape","nzSize","nzGap","nzText","nzSrc","nzSrcSet","nzAlt","nzIcon"],outputs:["nzError"],exportAs:["nzAvatar"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompUserAvatarComponent,decorators:[{type:Component,args:[{selector:"app-comp-user-avatar",standalone:!0,imports:[CommonModule,NzAvatarModule],template:'<ng-container *ngIf="user?.id || type == \'icon\'">\n <div class="avatar-com">\n \x3c!-- 默认ICON --\x3e\n <nz-avatar\n *ngIf="type == \'icon\'"\n [style]="{ backgroundColor: \'#0199f9\' }"\n nzIcon="user"\n ></nz-avatar>\n \x3c!-- <div *ngIf="type==\'icon\'" class="iconfont icon-yonghu-yuan"></div> --\x3e\n \x3c!-- 头像照片 --\x3e\n <div class="avatar-com">\n <nz-avatar class="comp-avatar"\n *ngIf="type == \'avatar\'"\n [nzSrc]="user?.get(\'avatar\')"\n ></nz-avatar>\n <img\n class="auth-icon"\n *ngIf="identity && type == \'avatar\'"\n [src]="identity"\n alt="已认证"\n />\n </div>\n \x3c!-- 昵称首字符 --\x3e\n <nz-avatar\n *ngIf="type == \'text\'"\n style="background-color: #0199f9"\n [nzText]="text"\n ></nz-avatar>\n </div>\n</ng-container>\n',styles:[".avatar-com{position:relative;width:32px;height:32px}.avatar-com .auth-icon{width:20px;height:20px;border-radius:50%;position:absolute;right:-6px;bottom:-2px}\n"]}]}],ctorParameters:()=>[{type:AccountService}],propDecorators:{user:[{type:Input}]}});class FmChatMessageCard{constructor(e){this.copyServ=e,this.isVoicePlaying=!1,this.user=Parse__default.User.current()}async playVoice(){let e,t=!1;if(this.isVoicePlaying=!0,this.message?.voice?.id){let t=new Parse__default.Query("ChatVoice");t.include("voiceFile"),e=await t.get(this.message?.voice?.id)}if(console.log(e),!e?.id){let n=await this.chat.getVoiceByContentText(this.message?.content);e=this.chat.voiceMap[n?.id],this.message.voice={id:e?.id,duration:e?.get("duration")},t=!0}this.message?.voice?.duration||(this.message.voice.duration=e?.get("duration"),t=!0),t&&this.chat?.saveChatSession(),this.chat.playChatVoice(e,{onLoaded:e=>{this.message.voice.duration=1e3*e.duration,this.updateVoiceDuration(1e3*e.duration)},onStop:()=>{this.isVoicePlaying=!1}})}updateVoiceDuration(e){this.message?.voice?.duration||(this.message.voice.duration=e,this.chat?.saveChatSession())}async copy(){this.copyServ.copyToClipboard(getMessageContentText(this.message?.content))}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatMessageCard,deps:[{token:ClipboardService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:FmChatMessageCard,isStandalone:!0,selector:"fm-chat-message-card",inputs:{message:"message",role:"role",chat:"chat"},ngImport:i0,template:'<div class="message-card" [class.right]="message?.role==\'user\'" [class.center]="message?.role==\'system\'">\n \x3c!-- 用户及操作区 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'"> \x3c!-- 系统消息不显示头像 --\x3e\n <div class="avatar-row">\n <div class="actions">\n \x3c!-- 刷新 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="refresh-outline"></ion-icon> \n </ion-button> --\x3e\n \x3c!-- 复制 --\x3e\n <ion-button size="small" fill="outline" slot="start" (click)="copy()">\n <ion-icon name="copy-outline"></ion-icon>\n </ion-button>\n \x3c!-- 编辑 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="create-outline"></ion-icon>\n </ion-button> --\x3e\n </div>\n \x3c!-- 音频消息区域 --\x3e\n <div *ngIf="message?.role==\'assistant\'||(message?.role==\'user\'&&message?.voice)" class="play-voice" (click)="playVoice()">\n <div class="voice-button">\n <span nz-icon [nzRotate]="message?.role==\'user\'?-90:90" nzType="wifi" nzTheme="outline" [class.play-voice-playing]="isVoicePlaying"></span>\n </div>\n <div class="voice-info">\n <span *ngIf="message?.voice?.duration">\n {{((message?.voice?.duration||0)/1000)|number:\'1.0-0\'}}"\n </span>\n <span *ngIf="!message?.voice?.duration">\n \x3c!-- --\x3e\n </span>\n </div>\n </div>\n \x3c!-- 头像区域 --\x3e\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'" ></nz-avatar>\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 附件:图片 --\x3e\n <div class="item-row images" *ngIf="message?.content | chatContent:\'image_url\'">\n <img [src]="message?.content | chatContent:\'image_url\'" alt="">\n </div>\n \x3c!-- 聊天气泡 --\x3e\n <div class="item-row bubble">\n <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content | chatContent" [render]="false"></fm-markdown-preview>\n <fm-markdown-preview *ngIf="message?.complete" [content]="message?.content | chatContent"></fm-markdown-preview>\n </div>\n \x3c!-- 时间显示 --\x3e\n <div class="item-row loading" *ngIf="message?.role!=\'system\' && !message?.complete">\n 正在输入<ion-spinner name="dots"></ion-spinner>\n </div>\n\n <div class="item-row created" *ngIf="message?.createdAt">\n <span>{{message?.createdAt | date:"dd/MM/yy HH:mm"}}</span>\n </div>\n</div>',styles:['@charset "UTF-8";:host-context(body.dark) .message-card .actions .item-native{background:none!important}:host-context(body.dark) .message-card .bubble{color:#0e101d}:host-context(body.dark) .message-card .bubble .content-style{filter:invert(1)!important}:host-context(body.dark) .message-card .bubble fm-markdown-preview{filter:invert(1)!important}:host-context(body.dark) .message-card .play-voice{background-color:#0e101d}:host-context(body.dark) .message-card .play-voice .voice-info{color:#fff}:host-context(body.dark) .message-card .right .bubble{color:#921f8a!important;background:#921f8a!important}:host-context(body.dark) .message-card .right .play-voice{background:#921f8a!important}:host-context(body.dark) .message-card .created span{color:#fff}@media screen and (max-width: 800px){.message-card:focus .actions{opacity:1!important}}.message-card:hover .actions{opacity:1;transition:opacity .3s ease-in-out}.message-card{display:flex;flex-wrap:wrap;justify-content:start;align-items:flex-start}.message-card .avatar-row{width:300px;height:32px;display:flex;flex-direction:row-reverse;justify-content:start;align-items:center}.message-card .actions{display:flex;opacity:0;padding-left:10px;padding-right:10px}.message-card .item-row{display:flex;flex:100%;justify-content:start;margin-bottom:5px}.message-card .images img{max-width:300px}.message-card .bubble{display:flex;justify-content:center;max-width:100%;padding-top:1rem;padding:.5rem;color:#333;flex:none;border-radius:0 1.5em 1.5em/0em 1.5em 1.5em;color:#fff;background-color:currentColor}.message-card .bubble .content-style{filter:grayscale(1) contrast(999) invert(1)}.message-card .loading{text-align:right;color:#101010}.message-card .created{display:flex}.message-card .created span{font-size:12px;opacity:.4;white-space:nowrap;transition:all .6s ease;color:var(--black);text-align:center;width:100%;box-sizing:border-box;padding-right:10px;pointer-events:none;z-index:1}.right{justify-content:end;align-items:flex-end}.right .avatar-row{flex-direction:row;justify-content:end;width:auto}.right .actions{position:relative;margin-left:0}.right .item-row{justify-content:end}.right .bubble{color:#bbdefb;border-top-left-radius:1.5em;border-top-right-radius:0}.right .play-voice{flex-direction:row-reverse;background-color:#bbdefb}.center{justify-content:center;align-items:center}.center .item-row{justify-content:center}.center .bubble{color:var(--gray-secondary);border-top-left-radius:1.5em;border-top-right-radius:1.5em}.play-voice{min-width:100px;height:32px;display:flex;justify-content:space-around;align-items:center;background-color:#fff;border-radius:7px}.play-voice .voice-button{width:32px;height:32px;display:flex;justify-content:center;align-items:center}.play-voice .voice-button span{overflow:hidden;font-size:18px;color:#ff69b4}.play-voice .voice-info{height:32px;display:flex;padding:0 10px;justify-content:end;align-items:center;color:#333}.play-voice-playing{animation:play-voice-animation 1s infinite}@keyframes play-voice-animation{0%{width:0}to{width:32px}}\n'],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"pipe",type:i2$2.DecimalPipe,name:"number"},{kind:"pipe",type:i2$2.DatePipe,name:"date"},{kind:"component",type:CompUserAvatarComponent,selector:"app-comp-user-avatar",inputs:["user"]},{kind:"ngmodule",type:MarkdownPreviewModule},{kind:"component",type:MarkdownPreviewComponent,selector:"fm-markdown-preview",inputs:["content","render"]},{kind:"ngmodule",type:NzAvatarModule},{kind:"component",type:i3.NzAvatarComponent,selector:"nz-avatar",inputs:["nzShape","nzSize","nzGap","nzText","nzSrc","nzSrcSet","nzAlt","nzIcon"],outputs:["nzError"],exportAs:["nzAvatar"]},{kind:"ngmodule",type:NzIconModule},{kind:"directive",type:i5.NzIconDirective,selector:"[nz-icon]",inputs:["nzSpin","nzRotate","nzType","nzTheme","nzTwotoneColor","nzIconfont"],exportAs:["nzIcon"]},{kind:"pipe",type:ChatContentPipe,name:"chatContent"}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatMessageCard,decorators:[{type:Component,args:[{selector:"fm-chat-message-card",standalone:!0,imports:[CommonModule,IonItem,CompUserAvatarComponent,MarkdownPreviewModule,NzAvatarModule,IonAvatar,NzIconModule,ChatContentPipe,NzSanitizerPipe],template:'<div class="message-card" [class.right]="message?.role==\'user\'" [class.center]="message?.role==\'system\'">\n \x3c!-- 用户及操作区 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'"> \x3c!-- 系统消息不显示头像 --\x3e\n <div class="avatar-row">\n <div class="actions">\n \x3c!-- 刷新 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="refresh-outline"></ion-icon> \n </ion-button> --\x3e\n \x3c!-- 复制 --\x3e\n <ion-button size="small" fill="outline" slot="start" (click)="copy()">\n <ion-icon name="copy-outline"></ion-icon>\n </ion-button>\n \x3c!-- 编辑 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="create-outline"></ion-icon>\n </ion-button> --\x3e\n </div>\n \x3c!-- 音频消息区域 --\x3e\n <div *ngIf="message?.role==\'assistant\'||(message?.role==\'user\'&&message?.voice)" class="play-voice" (click)="playVoice()">\n <div class="voice-button">\n <span nz-icon [nzRotate]="message?.role==\'user\'?-90:90" nzType="wifi" nzTheme="outline" [class.play-voice-playing]="isVoicePlaying"></span>\n </div>\n <div class="voice-info">\n <span *ngIf="message?.voice?.duration">\n {{((message?.voice?.duration||0)/1000)|number:\'1.0-0\'}}"\n </span>\n <span *ngIf="!message?.voice?.duration">\n \x3c!-- --\x3e\n </span>\n </div>\n </div>\n \x3c!-- 头像区域 --\x3e\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'" ></nz-avatar>\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 附件:图片 --\x3e\n <div class="item-row images" *ngIf="message?.content | chatContent:\'image_url\'">\n <img [src]="message?.content | chatContent:\'image_url\'" alt="">\n </div>\n \x3c!-- 聊天气泡 --\x3e\n <div class="item-row bubble">\n <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content | chatContent" [render]="false"></fm-markdown-preview>\n <fm-markdown-preview *ngIf="message?.complete" [content]="message?.content | chatContent"></fm-markdown-preview>\n </div>\n \x3c!-- 时间显示 --\x3e\n <div class="item-row loading" *ngIf="message?.role!=\'system\' && !message?.complete">\n 正在输入<ion-spinner name="dots"></ion-spinner>\n </div>\n\n <div class="item-row created" *ngIf="message?.createdAt">\n <span>{{message?.createdAt | date:"dd/MM/yy HH:mm"}}</span>\n </div>\n</div>',styles:['@charset "UTF-8";:host-context(body.dark) .message-card .actions .item-native{background:none!important}:host-context(body.dark) .message-card .bubble{color:#0e101d}:host-context(body.dark) .message-card .bubble .content-style{filter:invert(1)!important}:host-context(body.dark) .message-card .bubble fm-markdown-preview{filter:invert(1)!important}:host-context(body.dark) .message-card .play-voice{background-color:#0e101d}:host-context(body.dark) .message-card .play-voice .voice-info{color:#fff}:host-context(body.dark) .message-card .right .bubble{color:#921f8a!important;background:#921f8a!important}:host-context(body.dark) .message-card .right .play-voice{background:#921f8a!important}:host-context(body.dark) .message-card .created span{color:#fff}@media screen and (max-width: 800px){.message-card:focus .actions{opacity:1!important}}.message-card:hover .actions{opacity:1;transition:opacity .3s ease-in-out}.message-card{display:flex;flex-wrap:wrap;justify-content:start;align-items:flex-start}.message-card .avatar-row{width:300px;height:32px;display:flex;flex-direction:row-reverse;justify-content:start;align-items:center}.message-card .actions{display:flex;opacity:0;padding-left:10px;padding-right:10px}.message-card .item-row{display:flex;flex:100%;justify-content:start;margin-bottom:5px}.message-card .images img{max-width:300px}.message-card .bubble{display:flex;justify-content:center;max-width:100%;padding-top:1rem;padding:.5rem;color:#333;flex:none;border-radius:0 1.5em 1.5em/0em 1.5em 1.5em;color:#fff;background-color:currentColor}.message-card .bubble .content-style{filter:grayscale(1) contrast(999) invert(1)}.message-card .loading{text-align:right;color:#101010}.message-card .created{display:flex}.message-card .created span{font-size:12px;opacity:.4;white-space:nowrap;transition:all .6s ease;color:var(--black);text-align:center;width:100%;box-sizing:border-box;padding-right:10px;pointer-events:none;z-index:1}.right{justify-content:end;align-items:flex-end}.right .avatar-row{flex-direction:row;justify-content:end;width:auto}.right .actions{position:relative;margin-left:0}.right .item-row{justify-content:end}.right .bubble{color:#bbdefb;border-top-left-radius:1.5em;border-top-right-radius:0}.right .play-voice{flex-direction:row-reverse;background-color:#bbdefb}.center{justify-content:center;align-items:center}.center .item-row{justify-content:center}.center .bubble{color:var(--gray-secondary);border-top-left-radius:1.5em;border-top-right-radius:1.5em}.play-voice{min-width:100px;height:32px;display:flex;justify-content:space-around;align-items:center;background-color:#fff;border-radius:7px}.play-voice .voice-button{width:32px;height:32px;display:flex;justify-content:center;align-items:center}.play-voice .voice-button span{overflow:hidden;font-size:18px;color:#ff69b4}.play-voice .voice-info{height:32px;display:flex;padding:0 10px;justify-content:end;align-items:center;color:#333}.play-voice-playing{animation:play-voice-animation 1s infinite}@keyframes play-voice-animation{0%{width:0}to{width:32px}}\n']}]}],ctorParameters:()=>[{type:ClipboardService}],propDecorators:{message:[{type:Input}],role:[{type:Input}],chat:[{type:Input}]}});class CompRolePromptComponent{constructor(e,t){this.cross=e,this.modalController=t,this.role="",this.showModal=!1,this.cateIndex=0,this.company="E4KpGvTEto"}ngOnInit(){this.getChatPrompt()}applyPrompt(e){this.chat.userInput=e,"mobile"==this.cross?.navMenuType&&this.modalController.dismiss()}async getChatPrompt(){let e=new Parse.Query("ChatPrompt");e.notEqualTo("isDeleted",!0),e.equalTo("company",this.company),e.equalTo("role",this.role),e.include("role");let t=await e.find();this.chat.promptList=t,this.chat.promptList.forEach((e=>{let t=e.get("role").get("promptCates").filter((t=>t.name==e.get("cate")));e.img=t[0].img})),console.log(this.chat.promptList)}checkCate(e){this.cateIndex=e}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompRolePromptComponent,deps:[{token:CrossService},{token:i2$3.ModalController}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:CompRolePromptComponent,isStandalone:!0,selector:"app-comp-role-prompt",inputs:{chat:"chat",role:"role"},providers:[ModalController$1],ngImport:i0,template:'<ng-container *ngIf="chat?.messageList?.length<=1 && !chat?.userInput">\n <div class="prompt" *ngIf="cross?.navMenuType!=\'mobile\'">\n <ng-container *ngFor="let content of chat?.promptList">\n <div class="prompt_cate">\n <div class="cate_info">\n <div>\n <img [src]="content.img" alt="">\n </div>\n <div class="cate_name">\n {{content.get(\'cate\')}}\n </div>\n </div>\n <ng-container *ngFor="let message of content.get(\'messageList\')">\n <div class="message" (click)="applyPrompt(message)" nz-tooltip [nzTooltipTitle]="message"\n nzTooltipColor="#108ee9">\n {{message}}\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n <ng-container *ngIf="cross?.navMenuType==\'mobile\'">\n <div class="prompt_mobile">\n <ng-container *ngFor="let content of chat?.promptList">\n <div class="prompt_cate">\n <div class="cate_info">\n <div>\n <img [src]="content.img" alt="">\n </div>\n <div class="cate_name">\n {{content.get(\'cate\')}}\n </div>\n </div>\n <ng-container *ngFor="let message of content.get(\'messageList\');let idx = index">\n <div *ngIf="idx<3" class="message" (click)="applyPrompt(message)" nz-tooltip [nzTooltipTitle]="message"\n nzTooltipColor="#108ee9">\n {{message}}\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n <div class="view_more" *ngIf="chat?.promptList?.length">\n <button (click)="chat.isPromptModalOpen=true" expand="block">查看更多<span nz-icon nzType="right" nzTheme="outline"></span></button>\n </div>\n</ng-container>\n\n\n <ion-modal [isOpen]="chat.isPromptModalOpen" (willDismiss)="chat.isPromptModalOpen=false" [initialBreakpoint]="1" [breakpoints]="[0, 1]">\n <ng-template>\n <div class="block">\n <ion-label>话题灵感</ion-label>\n <div class="block_cate">\n \x3c!-- <ion-segment [(ngModel)]="cateIndex">\n <ng-container *ngFor="let prompt of chat?.promptList;let i = index">\n <ion-segment-button value="i">\n <ion-label>{{prompt?.get("cate")}}</ion-label>\n </ion-segment-button>\n </ng-container>\n </ion-segment> --\x3e\n <ng-container *ngFor="let prompt of chat?.promptList;let i = index">\n <ion-button [color]="i==cateIndex?\'secondary\':\'light\'" (click)="checkCate(i)">{{prompt?.get("cate")}}</ion-button>\n \x3c!-- <div [class]="i==cateIndex?\'active_cate\':\'\'" (click)="checkCate(i)">{{prompt?.get("cate")}}</div> --\x3e\n </ng-container>\n </div>\n <div class="message_mobile">\n <ng-container *ngFor="let message of chat?.promptList[cateIndex]?.get(\'messageList\')">\n <div (click)="applyPrompt(message)">{{message}}</div>\n </ng-container>\n </div>\n </div>\n </ng-template>\n </ion-modal>\n</ng-container>',styles:[":host-context(body.dark) .cate_info{color:#fff}:host-context(body.dark) ion-modal .block h4{color:#fff!important}.prompt{color:#000;display:flex;justify-content:space-between;align-items:flex-start}.prompt .prompt_cate{flex:1;height:inherit;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:flex;justify-content:center}.prompt .prompt_cate .cate_info{font-size:1.5em;font-weight:700}.prompt .prompt_cate .cate_info div img{width:58px;height:58px}.prompt .prompt_cate .cate_info .cate_name{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.prompt .prompt_cate .message{padding:1em;margin:1em;background:#fff;border:1px solid #eef2f2;border-radius:12px;box-shadow:0 2px 8px #f5f6f8;cursor:pointer;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}@media screen and (max-width: 390.4px){.prompt .prompt_cate .message{width:100px;height:64px;padding:unset;margin:.8em;background:#fff;border:1px solid #eef2f2;border-radius:12px;box-shadow:0 2px 8px #f5f6f8;cursor:pointer;overflow:hidden;white-space:pre-wrap;text-overflow:ellipsis}}.prompt_mobile{color:#000;display:flex;justify-content:space-between;align-items:flex-start}.prompt_mobile .prompt_cate{flex:1;height:inherit}.prompt_mobile .prompt_cate .cate_info{display:flex;justify-content:center;align-items:center;font-size:1.2em}.prompt_mobile .prompt_cate .cate_info div img{width:48px;height:48px}.prompt_mobile .prompt_cate .cate_info .cate_name{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;overflow:hidden;text-overflow:ellipsis;margin-top:2vw}.prompt_mobile .prompt_cate .message{min-height:48px;padding:0 2vw;margin:4vw 1vw;background:#fff;border:1px solid #eef2f2;border-radius:12px;box-shadow:0 2px 8px #f5f6f8;cursor:pointer;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;text-overflow:ellipsis}.view_more{text-align:center;color:#999;margin:4vw 0}.view_more>button{background-color:transparent}.block{width:100%;height:80vh;padding:2vw}.block .block_cate{display:flex;justify-content:space-between}.block .message_mobile{overflow-y:auto;height:65vh;color:#000}.block .message_mobile>div{background-color:#fff;text-align:center;padding:3vw 0;margin:3vw 0;border-radius:4px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}ion-modal{--height: auto}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"ngmodule",type:FormsModule},{kind:"ngmodule",type:ReactiveFormsModule},{kind:"component",type:IonModal,selector:"ion-modal"},{kind:"component",type:IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:IonLabel,selector:"ion-label",inputs:["color","mode","position"]},{kind:"ngmodule",type:NzIconModule},{kind:"directive",type:i5.NzIconDirective,selector:"[nz-icon]",inputs:["nzSpin","nzRotate","nzType","nzTheme","nzTwotoneColor","nzIconfont"],exportAs:["nzIcon"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompRolePromptComponent,decorators:[{type:Component,args:[{selector:"app-comp-role-prompt",standalone:!0,imports:[CommonModule,FormsModule,ReactiveFormsModule,IonModal,IonButton,IonSegment,IonLabel,NzIconModule],providers:[ModalController$1],template:'<ng-container *ngIf="chat?.messageList?.length<=1 && !chat?.userInput">\n <div class="prompt" *ngIf="cross?.navMenuType!=\'mobile\'">\n <ng-container *ngFor="let content of chat?.promptList">\n <div class="prompt_cate">\n <div class="cate_info">\n <div>\n <img [src]="content.img" alt="">\n </div>\n <div class="cate_name">\n {{content.get(\'cate\')}}\n </div>\n </div>\n <ng-container *ngFor="let message of content.get(\'messageList\')">\n <div class="message" (click)="applyPrompt(message)" nz-tooltip [nzTooltipTitle]="message"\n nzTooltipColor="#108ee9">\n {{message}}\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n <ng-container *ngIf="cross?.navMenuType==\'mobile\'">\n <div class="prompt_mobile">\n <ng-container *ngFor="let content of chat?.promptList">\n <div class="prompt_cate">\n <div class="cate_info">\n <div>\n <img [src]="content.img" alt="">\n </div>\n <div class="cate_name">\n {{content.get(\'cate\')}}\n </div>\n </div>\n <ng-container *ngFor="let message of content.get(\'messageList\');let idx = index">\n <div *ngIf="idx<3" class="message" (click)="applyPrompt(message)" nz-tooltip [nzTooltipTitle]="message"\n nzTooltipColor="#108ee9">\n {{message}}\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n <div class="view_more" *ngIf="chat?.promptList?.length">\n <button (click)="chat.isPromptModalOpen=true" expand="block">查看更多<span nz-icon nzType="right" nzTheme="outline"></span></button>\n </div>\n</ng-container>\n\n\n <ion-modal [isOpen]="chat.isPromptModalOpen" (willDismiss)="chat.isPromptModalOpen=false" [initialBreakpoint]="1" [breakpoints]="[0, 1]">\n <ng-template>\n <div class="block">\n <ion-label>话题灵感</ion-label>\n <div class="block_cate">\n \x3c!-- <ion-segment [(ngModel)]="cateIndex">\n <ng-container *ngFor="let prompt of chat?.promptList;let i = index">\n <ion-segment-button value="i">\n <ion-label>{{prompt?.get("cate")}}</ion-label>\n </ion-segment-button>\n </ng-container>\n </ion-segment> --\x3e\n <ng-container *ngFor="let prompt of chat?.promptList;let i = index">\n <ion-button [color]="i==cateIndex?\'secondary\':\'light\'" (click)="checkCate(i)">{{prompt?.get("cate")}}</ion-button>\n \x3c!-- <div [class]="i==cateIndex?\'active_cate\':\'\'" (click)="checkCate(i)">{{prompt?.get("cate")}}</div> --\x3e\n </ng-container>\n </div>\n <div class="message_mobile">\n <ng-container *ngFor="let message of chat?.promptList[cateIndex]?.get(\'messageList\')">\n <div (click)="applyPrompt(message)">{{message}}</div>\n </ng-container>\n </div>\n </div>\n </ng-template>\n </ion-modal>\n</ng-container>',styles:[":host-context(body.dark) .cate_info{color:#fff}:host-context(body.dark) ion-modal .block h4{color:#fff!important}.prompt{color:#000;display:flex;justify-content:space-between;align-items:flex-start}.prompt .prompt_cate{flex:1;height:inherit;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:flex;justify-content:center}.prompt .prompt_cate .cate_info{font-size:1.5em;font-weight:700}.prompt .prompt_cate .cate_info div img{width:58px;height:58px}.prompt .prompt_cate .cate_info .cate_name{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.prompt .prompt_cate .message{padding:1em;margin:1em;background:#fff;border:1px solid #eef2f2;border-radius:12px;box-shadow:0 2px 8px #f5f6f8;cursor:pointer;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}@media screen and (max-width: 390.4px){.prompt .prompt_cate .message{width:100px;height:64px;padding:unset;margin:.8em;background:#fff;border:1px solid #eef2f2;border-radius:12px;box-shadow:0 2px 8px #f5f6f8;cursor:pointer;overflow:hidden;white-space:pre-wrap;text-overflow:ellipsis}}.prompt_mobile{color:#000;display:flex;justify-content:space-between;align-items:flex-start}.prompt_mobile .prompt_cate{flex:1;height:inherit}.prompt_mobile .prompt_cate .cate_info{display:flex;justify-content:center;align-items:center;font-size:1.2em}.prompt_mobile .prompt_cate .cate_info div img{width:48px;height:48px}.prompt_mobile .prompt_cate .cate_info .cate_name{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;overflow:hidden;text-overflow:ellipsis;margin-top:2vw}.prompt_mobile .prompt_cate .message{min-height:48px;padding:0 2vw;margin:4vw 1vw;background:#fff;border:1px solid #eef2f2;border-radius:12px;box-shadow:0 2px 8px #f5f6f8;cursor:pointer;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;text-overflow:ellipsis}.view_more{text-align:center;color:#999;margin:4vw 0}.view_more>button{background-color:transparent}.block{width:100%;height:80vh;padding:2vw}.block .block_cate{display:flex;justify-content:space-between}.block .message_mobile{overflow-y:auto;height:65vh;color:#000}.block .message_mobile>div{background-color:#fff;text-align:center;padding:3vw 0;margin:3vw 0;border-radius:4px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}ion-modal{--height: auto}\n"]}]}],ctorParameters:()=>[{type:CrossService},{type:i2$3.ModalController}],propDecorators:{chat:[{type:Input}],role:[{type:Input}]}});class FmChatMesssageArea{get messageList(){return this.chatServ.chatMap[this.chatId]?.messageList}constructor(e){this.chatServ=e}ngDoCheck(){}ngAfterViewInit(){console.log("ng gogogo1"),console.log("ng gogogo2"),console.log(this.chat)}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatMesssageArea,deps:[{token:ChatService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:FmChatMesssageArea,isStandalone:!0,selector:"fm-chat-message-area",inputs:{chatId:"chatId",chat:"chat"},ngImport:i0,template:'\n<div class="message-list">\n <app-comp-role-prompt [chat]="chat" [role]="chat?.role?.id"></app-comp-role-prompt>\n <ng-container *ngFor="let message of chat?.messageList">\n \x3c!-- 内容格式化区域 --\x3e\n <fm-chat-message-card [chat]="chat" *ngIf="!message?.hidden" [message]="message" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n \x3c!-- 预览无图消息 --\x3e\n <ng-container *ngIf="chat?.userInput&&!chat?.userImage">\n <fm-chat-message-card [chat]="chat" [message]="{role:\'user\',content:chat?.userInput}" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n \x3c!-- 预览有图消息 --\x3e\n <ng-container *ngIf="chat?.userImage">\n <fm-chat-message-card [chat]="chat" [message]="{role:\'user\',content:[{type:\'text\',text:chat?.userInput},{type:\'image_url\',image_url:{url:chat?.userImage}}]}" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n</div>',styles:[".message-list{padding:5px 20px}:host-context(body.dark) .message-list{background-color:#000!important}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:FmChatMessageCard,selector:"fm-chat-message-card",inputs:["message","role","chat"]},{kind:"component",type:CompRolePromptComponent,selector:"app-comp-role-prompt",inputs:["chat","role"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatMesssageArea,decorators:[{type:Component,args:[{selector:"fm-chat-message-area",standalone:!0,imports:[CommonModule,FmChatMessageCard,CompRolePromptComponent],template:'\n<div class="message-list">\n <app-comp-role-prompt [chat]="chat" [role]="chat?.role?.id"></app-comp-role-prompt>\n <ng-container *ngFor="let message of chat?.messageList">\n \x3c!-- 内容格式化区域 --\x3e\n <fm-chat-message-card [chat]="chat" *ngIf="!message?.hidden" [message]="message" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n \x3c!-- 预览无图消息 --\x3e\n <ng-container *ngIf="chat?.userInput&&!chat?.userImage">\n <fm-chat-message-card [chat]="chat" [message]="{role:\'user\',content:chat?.userInput}" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n \x3c!-- 预览有图消息 --\x3e\n <ng-container *ngIf="chat?.userImage">\n <fm-chat-message-card [chat]="chat" [message]="{role:\'user\',content:[{type:\'text\',text:chat?.userInput},{type:\'image_url\',image_url:{url:chat?.userImage}}]}" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n</div>',styles:[".message-list{padding:5px 20px}:host-context(body.dark) .message-list{background-color:#000!important}\n"]}]}],ctorParameters:()=>[{type:ChatService}],propDecorators:{chatId:[{type:Input}],chat:[{type:Input}]}});class ModalAudioMessageComponent{constructor(e,t,n){this.voiceServ=e,this.toastCtrl=t,this.uploadServ=n,this.isRecording=!1,this.player=new Audio,this.clockStr="0:00"}ngOnInit(){this.chat.userInput="",this.initVoiceSevice(),this.voiceServ.startTalk()}playMusic(e){this.player||(this.player=new Audio),this.player.src=`/assets/avatar/voice/${e}.mp3`;try{this.player?.play()}catch(e){}}initVoiceSevice(){this.chat.userInput=this.voiceServ.resultText,this.voiceServ.requestPermission().then((()=>{this.voiceServ.openWithPriviledge()})),this.voiceServ.onBeforeStartTalk=()=>{this.chat.playAnimation("listening"),this.playMusic("start-talk")},this.voiceServ.onAfterRecordStart=()=>{this.isRecording=!0,this.timerInt=setInterval((()=>{this.countTimer()}),1e3)},this.voiceServ.onBeforeCancelTalk=()=>{this.playMusic("interupt-talk"),this.chat.playAnimation("waiting")},this.voiceServ.onAfterCancelTalk=()=>{},this.voiceServ.onBeforeFinishTalk=()=>{this.chat.playAnimation("thinking"),this.playMusic("stop-talk")},this.voiceServ.onAfterFinishTalk=async()=>{console.log("onAfterFinishTalk1",this.voiceServ?.resultText),console.log("onAfterFinishTalk2",this.voiceServ?.resultTextTemp),this.chat.userInput=""+(this.voiceServ?.resultTextTemp||this.voiceServ?.resultText),this.chat?.userInput&&await this.saveChatVoice(),this.sendMessage()}}async saveChatVoice(){let e=this.voiceServ.recordWavBlob,t=this.voiceServ.recordDuration;if(e){let n=Parse__default.Object.extend("ChatVoice");this.chatVoice=new n,this.chatVoice.set("content",this.chat.userInput),this.chatVoice.set("role","user"),this.chatVoice.set("duration",t);let o=localStorage.getItem("company");o&&this.chatVoice.set("company",{__type:"Pointer",className:"Company",objectId:o}),Parse__default.User.current()?.id&&this.chatVoice.set("user",Parse__default.User.current().toPointer());let i=this.chatVoice?.id||this.uploadServ?.genMd5(this.chatVoice?.get("content")||this.chatVoice?.get("ssml")),a=new Date,r=i+a.getFullYear()+(a.getMonth()+1)+a.getDate()+a.getHours()+a.getMinutes()+a.getSeconds()+".wav",s=new File([e],r,{type:"audio/wav"}),l=await this.uploadServ.upload(s,(e=>{console.log(e)})),c={__type:"Pointer",className:"Attachment",objectId:l?.id};c?.objectId&&(this.chatVoice.set("voiceFile",c),this.chatVoice=await this.chatVoice.save())}}async sendMessage(){if(this.chat.userInput)this.chat?.sendMessage(""+this.chat?.userInput,this.chat?.userImage,(e=>{}),{onSSMLComplete:e=>{console.log(e)}},{id:this.chatVoice?.id,duration:this.chatVoice?.get("duration")});else{(await this.toastCtrl.create({message:"内容不能为空",position:"top",icon:"alert",color:"warning-circle",duration:1e3})).present()}}countTimer(){this.now||(this.now=new Date);let e=(new Date).getTime()-this.now.getTime();e/=1e3,e/1e3>59&&this.send(),this.clockStr=(e/60).toFixed(0)+":"+String((e%60).toFixed(0)).padStart(2,"0")}cancel(){this.clear(),this.voiceServ.cancelTalk(),this.modal?.dismiss(null,"cancel")}send(){this.clear(),this.voiceServ.finishTalk(),this.modal?.dismiss(null,"send")}clear(){this.timerInt&&clearInterval(this.timerInt),this.now=void 0,this.isRecording=!1}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ModalAudioMessageComponent,deps:[{token:FmodeVoiceService},{token:i2$3.ToastController},{token:NovaUploadService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:ModalAudioMessageComponent,isStandalone:!0,selector:"fm-modal-audio-message",inputs:{chat:"chat",modal:"modal"},providers:[ModalController$1],ngImport:i0,template:'\x3c!-- <div style="background:#FFFFFF;color:#000000;width:100%">\n {{this.chat.userInput}}\n</div> --\x3e\n<div class="modal-area">\n\n \x3c!-- 加载WebSockets动画 --\x3e\n <ng-container *ngIf="!isRecording">\n <div class="row">\n <ion-spinner name="crescent" color="success" style="width:80px;height:80px;"></ion-spinner>\n </div>\n </ng-container>\n \x3c!-- 录音中动画 --\x3e\n <ng-container *ngIf="isRecording">\n <div class="tips row">\n 请您讲话,AI会识别!\n </div>\n <div class="timer row">\n {{clockStr || "0:00"}}\n </div>\n <div class="audio-wave row">\n <div class="audio">\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n </div>\n </div>\n <div class="actions row">\n <ion-button (click)="cancel()" size="large" shape="round" color="light">\n <ion-icon name="close-outline"></ion-icon>\n </ion-button>\n <ion-button (click)="send()" size="large" shape="round" color="success">\n <ion-icon name="send-outline"></ion-icon>\n </ion-button>\n </div>\n </ng-container>\n</div>',styles:[":host-context(body.dark) .modal-area{color:#fff}.modal-area{display:flex;flex-direction:column;justify-content:center;align-items:center;width:100%;height:100%}.modal-area .row{margin:10px}.modal-area .timer{font-size:1.5rem;font-weight:700}.modal-area .actions{display:flex;justify-content:space-around;width:100%;height:86px}.audio{display:flex;justify-content:space-between;align-items:center;gap:8px;width:60px;height:40px}.audio .wave{height:40px;display:block;width:10px;height:6px;border-radius:8px;background:orange}.audio .wave{animation:audio-wave 2s ease-in-out infinite}.audio .wave:nth-child(1){animation-delay:.1s}.audio .wave:nth-child(2){animation-delay:.2s}.audio .wave:nth-child(3){animation-delay:.3s}.audio .wave:nth-child(4){animation-delay:.4s}.audio .wave:nth-child(5){animation-delay:.5s}@keyframes audio-wave{0%{height:6px;transform:translateY(0);background:#ff8e3a}25%{height:6px;transform:translateY(0);background:#9c73f8}50%{height:30px;transform:translateY(-5px) scaleY(1.5);background:#ed509e}75%{height:6px;transform:translateY(0);background:#9c73f8}to{height:6px;transform:translateY(0);background:#0fccce}}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:IonSpinner,selector:"ion-spinner",inputs:["color","duration","name","paused"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ModalAudioMessageComponent,decorators:[{type:Component,args:[{selector:"fm-modal-audio-message",standalone:!0,imports:[CommonModule,IonButton,IonIcon,IonSpinner],providers:[ModalController$1],template:'\x3c!-- <div style="background:#FFFFFF;color:#000000;width:100%">\n {{this.chat.userInput}}\n</div> --\x3e\n<div class="modal-area">\n\n \x3c!-- 加载WebSockets动画 --\x3e\n <ng-container *ngIf="!isRecording">\n <div class="row">\n <ion-spinner name="crescent" color="success" style="width:80px;height:80px;"></ion-spinner>\n </div>\n </ng-container>\n \x3c!-- 录音中动画 --\x3e\n <ng-container *ngIf="isRecording">\n <div class="tips row">\n 请您讲话,AI会识别!\n </div>\n <div class="timer row">\n {{clockStr || "0:00"}}\n </div>\n <div class="audio-wave row">\n <div class="audio">\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n </div>\n </div>\n <div class="actions row">\n <ion-button (click)="cancel()" size="large" shape="round" color="light">\n <ion-icon name="close-outline"></ion-icon>\n </ion-button>\n <ion-button (click)="send()" size="large" shape="round" color="success">\n <ion-icon name="send-outline"></ion-icon>\n </ion-button>\n </div>\n </ng-container>\n</div>',styles:[":host-context(body.dark) .modal-area{color:#fff}.modal-area{display:flex;flex-direction:column;justify-content:center;align-items:center;width:100%;height:100%}.modal-area .row{margin:10px}.modal-area .timer{font-size:1.5rem;font-weight:700}.modal-area .actions{display:flex;justify-content:space-around;width:100%;height:86px}.audio{display:flex;justify-content:space-between;align-items:center;gap:8px;width:60px;height:40px}.audio .wave{height:40px;display:block;width:10px;height:6px;border-radius:8px;background:orange}.audio .wave{animation:audio-wave 2s ease-in-out infinite}.audio .wave:nth-child(1){animation-delay:.1s}.audio .wave:nth-child(2){animation-delay:.2s}.audio .wave:nth-child(3){animation-delay:.3s}.audio .wave:nth-child(4){animation-delay:.4s}.audio .wave:nth-child(5){animation-delay:.5s}@keyframes audio-wave{0%{height:6px;transform:translateY(0);background:#ff8e3a}25%{height:6px;transform:translateY(0);background:#9c73f8}50%{height:30px;transform:translateY(-5px) scaleY(1.5);background:#ed509e}75%{height:6px;transform:translateY(0);background:#9c73f8}to{height:6px;transform:translateY(0);background:#0fccce}}\n"]}]}],ctorParameters:()=>[{type:FmodeVoiceService},{type:i2$3.ToastController},{type:NovaUploadService}],propDecorators:{chat:[{type:Input}],modal:[{type:Input}]}});class FmChatModalInput{closeAudio(){this.audioComp?.cancel(),this.isAudioModal=!1}constructor(e,t,n,o,i,a,r,s){this.toastCtrl=e,this.alertCtrl=t,this.navCtrl=n,this.router=o,this.imagineServ=i,this.chatServ=a,this.route=r,this.messages=s,this.errorText="",this.isAudioModal=!1,this.isShare=!1,this.user=Parse__default.User.current()}ngOnInit(){this.loadModel()}async loadModel(){let e=this.chat?.role?.get("model");await this.chatServ.loadModelList(e)}async setMessageImage(){let e=await this.imagineServ.getimg();this.chat.userImage=e,console.log(this.chat?.userImage)}onKeyDown(e){e.ctrlKey&&"Enter"===e.key&&(console.log("Ctrl+Enter 被按下"),this.sendMessage())}async sendMessage(){if(!this.chat.userInput){return this.errorText="内容不能为空",void(await this.toastCtrl.create({message:this.errorText,position:"top",icon:"alert",color:"warning-circle",duration:1e3})).present()}this.chat?.sendMessage(this.chat?.userInput,this.chat?.userImage,(e=>{}),{onSSMLComplete:e=>{console.log(e)}}),this.chat.userInput="",this.chat.userImage=""}async checkBalance(){if(!this.chatServ?.currentModel?.get("payLimit"))return!0;let e=await this.account.getBilling();if(e?.credit?.balance<10){return(await this.alertCtrl.create({header:"注意",subHeader:"您的余额不足,请充值后解锁高级模型",buttons:[{role:"cancel",text:"取消"},{role:"destructive",text:"充值",handler:()=>{this.router.navigateByUrl("/account/billing")}}]})).present(),!1}return!0}async getChatShare(){this.user=Parse__default.User.current();let e=new Parse__default.Query("ChatShare");e.equalTo("user",Parse__default.User.current().id),e.equalTo("session",this.chat?.sessionId);await e.first()}async toggleChatShare(){let e=new Parse__default.Query("ChatShare");e.equalTo("user",Parse__default.User.current().id),e.equalTo("role",this.chat?.role.id),e.equalTo("session",this.chat?.sessionId),e.select("objectId");let t=await e.first();if(t?.id)t.set("messageList",this.chat?.messageList);else{t=new(Parse__default.Object.extend("ChatShare")),t.set("user",{__type:"Pointer",className:"_User",objectId:Parse__default.User.current()?.id}),t.set("session",{__type:"Pointer",className:"ChatSession",objectId:this.chat?.sessionId}),t.set("role",{__type:"Pointer",className:"AvatarRole",objectId:this.chat?.role.id}),t.set("company",{__type:"Pointer",className:"Company",objectId:"E4KpGvTEto"}),t.set("messageList",this.chat?.messageList)}await t.save(),this.getChatShare()}chatShareSuccessMessage(){this.messages.success("分享成功")}showShare(){this.isShare=!0}handleOkShare(){this.toggleChatShare(),this.chatShareSuccessMessage(),this.isShare=!1}handleCancelShare(){this.isShare=!1}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatModalInput,deps:[{token:i2.ToastController},{token:i2.AlertController},{token:i2.NavController},{token:i1$1.Router},{token:ImagineService},{token:ChatService},{token:i1$1.ActivatedRoute},{token:i5$1.NzMessageService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:FmChatModalInput,isStandalone:!0,selector:"fm-chat-modal-input",inputs:{chat:"chat",message:"message",role:"role"},viewQueries:[{propertyName:"audioComp",first:!0,predicate:ModalAudioMessageComponent,descendants:!0}],ngImport:i0,template:'<ion-toolbar>\n <ion-item class="button-item" lines="none">\n \x3c!-- 设置 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="settings-outline"></ion-icon> \n </ion-button> --\x3e\n <ng-container *ngFor="let button of chat?.leftButtons">\n <ion-button shape="round" *ngIf="button.show()" fill="outline" [title]="button?.title" slot="start" (click)="button.onClick()">\n <ion-icon [name]="button?.icon"></ion-icon>\n </ion-button>\n </ng-container>\n\n <ng-container *ngFor="let button of chat?.role?.get(\'buttons\')">\n <ion-button shape="round" (click)="chatServ.doButtonAction(button)" fill="outline" slot="start">\n {{button?.name}}\n </ion-button>\n </ng-container>\n\n \x3c!--分享按钮--\x3e\n <ion-button shape="round" *ngIf="chat?.messageList?.length>1" (click)="showShare()" fill="outline" title="分享" slot="start" routerLink="/chat/pro/mask">\n <ion-icon name="share-social-outline"></ion-icon>\n </ion-button>\n \x3c!-- <button nz-button *ngIf="chat?.messageList?.length>1"\n nzType="primary" title="分享" (click)="showShare()" style="width: 31.188px;height: 22px;box-shadow: none;background: #fff;border: 1px solid #4588ff;border-radius: 5px;"> <span class="iconfont icon-fenxiang" style="color: #4588ff;"></span></button>\n --\x3e\n <ion-modal [isOpen]="isShare">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="handleCancelShare()">取消</ion-button>\n </ion-buttons>\n <ion-title>对话分享</ion-title>\n <ion-buttons slot="end">\n <ion-button (click)="handleOkShare()">分享</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ion-content>\n </ng-template>\n </ion-modal>\n\n <nz-modal *ngIf="false"\n [(nzVisible)]="isShare"\n nzTitle="问答分享"\n nzCentered\n nzOkText="分享"\n nzCancelText="取消"\n (nzOnCancel)="handleCancelShare()"\n (nzOnOk)="handleOkShare()"\n >\n <ng-container *nzModalContent>\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ng-container>\n </nz-modal>\n\n \x3c!-- 图片 --\x3e\n <ion-button shape="round" *ngIf="chatServ?.currentModel?.get(\'config\')?.imageEnabled" fill="outline" slot="end" (click)="setMessageImage()">\n <ion-icon name="image-outline"></ion-icon>\n </ion-button>\n \x3c!-- 模型 --\x3e\n <ion-button shape="round" fill="outline" slot="end" id="model-button">\n <ion-icon name="chevron-down-outline"></ion-icon>\n {{chatServ?.currentModel?.get&&chatServ?.currentModel?.get("name")||"飞码4.0"}}\n </ion-button>\n <ion-popover trigger="model-button" [dismissOnSelect]="true">\n <ng-template>\n <ion-content>\n <ion-list>\n <ng-container *ngFor="let model of chatServ.modelList">\n <ion-item (click)="chatServ.currentModel = model" [button]="true" [detail]="false">\n {{model?.get("name")}}\n <ion-note slot="end">{{model?.get("credit")}}/k</ion-note>\n </ion-item>\n </ng-container>\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n\n </ion-item>\n\n <ion-item class="input-item" lines="none">\n \x3c!-- 语音消息输入 --\x3e\n <ng-container *ngIf="chat?.isVoiceInputMode">\n \x3c!-- 切换文本输入 --\x3e\n <ion-button class="btn-input-change" color="primary" (click)="chat.isVoiceInputMode=false" shape="round" size="large">\n <ion-icon name="chatbox-ellipses-outline" slot="icon-only"></ion-icon>\n </ion-button>\n \n <div class="btn-voice-start" (click)="isAudioModal=true">\n <span>\n 点击讲话\n </span> \n </div>\n </ng-container>\n\n \x3c!-- 文本消息输入 --\x3e\n <ng-container *ngIf="!chat?.isVoiceInputMode">\n \x3c!-- 切换语音输入 --\x3e\n <ion-button [style.display]="chat.isTexting?\'none\':\'flex\'" class="btn-input-change" color="primary" *ngIf="chat?.role?.get(\'voiceConfig\')" (click)="chat.isVoiceInputMode=true" shape="round" size="large">\n <ion-icon name="mic-outline" slot="icon-only"></ion-icon>\n </ion-button>\n\n \x3c!-- 文本输入区域 --\x3e\n <ion-textarea *ngIf="chat" (keydown)="onKeyDown($event)"\n [errorText]="errorText"\n [(ngModel)]="chat.userInput"\n (ionFocus)="chat.isTexting=true"\n (ionBlur)="chat.isTexting=false"\n [autoGrow]="true" shape="round" fill="outline"\n label="Ctrl + Enter 发送消息" placeholder="请输入您的提示词"\n labelPlacement="floating"></ion-textarea>\n \n \x3c!-- 文本发送按钮 --\x3e\n <ion-button color="primary" shape="round" size="large" (click)="sendMessage()">\n <ion-icon name="paper-plane-outline" slot="icon-only"></ion-icon>\n </ion-button>\n </ng-container>\n </ion-item>\n</ion-toolbar>\n\n\n\x3c!-- 语音消息输入:弹出区域 --\x3e\n<ion-modal #audioModal [isOpen]="isAudioModal" (willDismiss)="closeAudio()" [initialBreakpoint]="0.35" [breakpoints]="[0, 0.35, 0.5]">\n <ng-template>\n <fm-modal-audio-message #audioComp *ngIf="isAudioModal" [chat]="chat" [modal]="audioModal"></fm-modal-audio-message>\n </ng-template>\n</ion-modal>',styles:['@charset "UTF-8";:host-context(body.dark) .btn-voice-start{background-color:#222428;color:#fff}:host-context(body.dark) ion-textarea{background-color:#222428;color:#fff}ion-toolbar{--background:none}ion-toolbar .button-item{--inner-padding-start:5px;--inner-padding-end:0px;--padding-start:5px;--padding-end:0px}ion-toolbar ion-item{--background:transparent}ion-textarea.custom{--background: #373737;--color: #fff;--padding-end: 10px;--padding-start: 10px;--placeholder-color: #ddd;--placeholder-opacity: .8}ion-textarea.custom textarea{width:calc(100% - 95px)}ion-textarea.custom ion-button{position:absolute;right:0}.input-item{display:flex;min-height:77px;align-items:center;border:none;--inner-padding-start:0px;--inner-padding-end:0px;--padding-start:0px;--padding-end:0px}.input-item ion-textarea{background-color:#fff;max-height:400px;padding:0 5px;margin:0 5px;border-radius:20px;overflow-y:auto}.input-item .btn-voice-start{display:flex;flex:1;justify-content:center;align-items:center;font-weight:700;background:#fff;border-radius:20px;min-height:50px}ion-textarea{transition:width .5s ease}ion-textarea:hover .btn-input-change,ion-textarea:focus-within .btn-input-change{display:none}.input-item:hover ion-textarea,.input-item:focus-within ion-textarea{border-color:var(--logo-color-primary)}::ng-deep .ant-modal-body{max-height:600px;overflow-y:auto}::ng-deep .ant-modal-footer{display:flex;justify-content:space-around}::ng-deep .ant-btn{width:40%}.popup-content{position:relative}.popup-content .message-content-user{display:flex;justify-content:flex-end}.popup-content .message-content-role{display:flex;justify-content:flex-start}.popup-content .message-content-system{display:flex;justify-content:center}.popup-content .user-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#e7f8ff}.popup-content .role-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#f6f6f6}.popup-content .user-question{margin-bottom:5px;display:flex;justify-content:flex-end}.popup-content .chat-time{margin-bottom:10px;display:flex;justify-content:flex-end;font-size:14px;color:#a3a3a3}.popup-content .role-time{justify-content:flex-start}\n'],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:i2$2.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"pipe",type:i2$2.DatePipe,name:"date"},{kind:"ngmodule",type:FormsModule},{kind:"directive",type:i7.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:i7.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"ngmodule",type:ReactiveFormsModule},{kind:"ngmodule",type:RouterModule},{kind:"directive",type:i1$1.RouterLink,selector:"[routerLink]",inputs:["target","queryParams","fragment","queryParamsHandling","state","info","relativeTo","preserveFragment","skipLocationChange","replaceUrl","routerLink"]},{kind:"component",type:IonToolbar,selector:"ion-toolbar",inputs:["color","mode"]},{kind:"component",type:IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:IonList,selector:"ion-list",inputs:["inset","lines","mode"]},{kind:"component",type:IonModal,selector:"ion-modal"},{kind:"component",type:IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:IonTextarea,selector:"ion-textarea",inputs:["autoGrow","autocapitalize","autofocus","clearOnEdit","color","cols","counter","counterFormatter","debounce","disabled","enterkeyhint","errorText","fill","helperText","inputmode","label","labelPlacement","maxlength","minlength","mode","name","placeholder","readonly","required","rows","shape","spellcheck","value","wrap"]},{kind:"component",type:IonPopover,selector:"ion-popover"},{kind:"component",type:IonContent,selector:"ion-content",inputs:["color","fixedSlotPlacement","forceOverscroll","fullscreen","scrollEvents","scrollX","scrollY"]},{kind:"ngmodule",type:NzModalModule},{kind:"component",type:i8.NzModalComponent,selector:"nz-modal",inputs:["nzMask","nzMaskClosable","nzCloseOnNavigation","nzVisible","nzClosable","nzOkLoading","nzOkDisabled","nzCancelDisabled","nzCancelLoading","nzKeyboard","nzNoAnimation","nzCentered","nzDraggable","nzContent","nzFooter","nzZIndex","nzWidth","nzWrapClassName","nzClassName","nzStyle","nzTitle","nzCloseIcon","nzMaskStyle","nzBodyStyle","nzOkText","nzCancelText","nzOkType","nzOkDanger","nzIconType","nzModalType","nzAutofocus","nzOnOk","nzOnCancel"],outputs:["nzOnOk","nzOnCancel","nzAfterOpen","nzAfterClose","nzVisibleChange"],exportAs:["nzModal"]},{kind:"directive",type:i8.NzModalContentDirective,selector:"[nzModalContent]",exportAs:["nzModalContent"]},{kind:"component",type:ModalAudioMessageComponent,selector:"fm-modal-audio-message",inputs:["chat","modal"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatModalInput,decorators:[{type:Component,args:[{selector:"fm-chat-modal-input",standalone:!0,imports:[CommonModule,FormsModule,ReactiveFormsModule,RouterModule,IonToolbar,IonItem,IonButton,IonList,IonModal,IonInput,IonIcon,IonTextarea,IonPopover,IonContent,NzModalModule,ModalAudioMessageComponent],template:'<ion-toolbar>\n <ion-item class="button-item" lines="none">\n \x3c!-- 设置 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="settings-outline"></ion-icon> \n </ion-button> --\x3e\n <ng-container *ngFor="let button of chat?.leftButtons">\n <ion-button shape="round" *ngIf="button.show()" fill="outline" [title]="button?.title" slot="start" (click)="button.onClick()">\n <ion-icon [name]="button?.icon"></ion-icon>\n </ion-button>\n </ng-container>\n\n <ng-container *ngFor="let button of chat?.role?.get(\'buttons\')">\n <ion-button shape="round" (click)="chatServ.doButtonAction(button)" fill="outline" slot="start">\n {{button?.name}}\n </ion-button>\n </ng-container>\n\n \x3c!--分享按钮--\x3e\n <ion-button shape="round" *ngIf="chat?.messageList?.length>1" (click)="showShare()" fill="outline" title="分享" slot="start" routerLink="/chat/pro/mask">\n <ion-icon name="share-social-outline"></ion-icon>\n </ion-button>\n \x3c!-- <button nz-button *ngIf="chat?.messageList?.length>1"\n nzType="primary" title="分享" (click)="showShare()" style="width: 31.188px;height: 22px;box-shadow: none;background: #fff;border: 1px solid #4588ff;border-radius: 5px;"> <span class="iconfont icon-fenxiang" style="color: #4588ff;"></span></button>\n --\x3e\n <ion-modal [isOpen]="isShare">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="handleCancelShare()">取消</ion-button>\n </ion-buttons>\n <ion-title>对话分享</ion-title>\n <ion-buttons slot="end">\n <ion-button (click)="handleOkShare()">分享</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ion-content>\n </ng-template>\n </ion-modal>\n\n <nz-modal *ngIf="false"\n [(nzVisible)]="isShare"\n nzTitle="问答分享"\n nzCentered\n nzOkText="分享"\n nzCancelText="取消"\n (nzOnCancel)="handleCancelShare()"\n (nzOnOk)="handleOkShare()"\n >\n <ng-container *nzModalContent>\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ng-container>\n </nz-modal>\n\n \x3c!-- 图片 --\x3e\n <ion-button shape="round" *ngIf="chatServ?.currentModel?.get(\'config\')?.imageEnabled" fill="outline" slot="end" (click)="setMessageImage()">\n <ion-icon name="image-outline"></ion-icon>\n </ion-button>\n \x3c!-- 模型 --\x3e\n <ion-button shape="round" fill="outline" slot="end" id="model-button">\n <ion-icon name="chevron-down-outline"></ion-icon>\n {{chatServ?.currentModel?.get&&chatServ?.currentModel?.get("name")||"飞码4.0"}}\n </ion-button>\n <ion-popover trigger="model-button" [dismissOnSelect]="true">\n <ng-template>\n <ion-content>\n <ion-list>\n <ng-container *ngFor="let model of chatServ.modelList">\n <ion-item (click)="chatServ.currentModel = model" [button]="true" [detail]="false">\n {{model?.get("name")}}\n <ion-note slot="end">{{model?.get("credit")}}/k</ion-note>\n </ion-item>\n </ng-container>\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n\n </ion-item>\n\n <ion-item class="input-item" lines="none">\n \x3c!-- 语音消息输入 --\x3e\n <ng-container *ngIf="chat?.isVoiceInputMode">\n \x3c!-- 切换文本输入 --\x3e\n <ion-button class="btn-input-change" color="primary" (click)="chat.isVoiceInputMode=false" shape="round" size="large">\n <ion-icon name="chatbox-ellipses-outline" slot="icon-only"></ion-icon>\n </ion-button>\n \n <div class="btn-voice-start" (click)="isAudioModal=true">\n <span>\n 点击讲话\n </span> \n </div>\n </ng-container>\n\n \x3c!-- 文本消息输入 --\x3e\n <ng-container *ngIf="!chat?.isVoiceInputMode">\n \x3c!-- 切换语音输入 --\x3e\n <ion-button [style.display]="chat.isTexting?\'none\':\'flex\'" class="btn-input-change" color="primary" *ngIf="chat?.role?.get(\'voiceConfig\')" (click)="chat.isVoiceInputMode=true" shape="round" size="large">\n <ion-icon name="mic-outline" slot="icon-only"></ion-icon>\n </ion-button>\n\n \x3c!-- 文本输入区域 --\x3e\n <ion-textarea *ngIf="chat" (keydown)="onKeyDown($event)"\n [errorText]="errorText"\n [(ngModel)]="chat.userInput"\n (ionFocus)="chat.isTexting=true"\n (ionBlur)="chat.isTexting=false"\n [autoGrow]="true" shape="round" fill="outline"\n label="Ctrl + Enter 发送消息" placeholder="请输入您的提示词"\n labelPlacement="floating"></ion-textarea>\n \n \x3c!-- 文本发送按钮 --\x3e\n <ion-button color="primary" shape="round" size="large" (click)="sendMessage()">\n <ion-icon name="paper-plane-outline" slot="icon-only"></ion-icon>\n </ion-button>\n </ng-container>\n </ion-item>\n</ion-toolbar>\n\n\n\x3c!-- 语音消息输入:弹出区域 --\x3e\n<ion-modal #audioModal [isOpen]="isAudioModal" (willDismiss)="closeAudio()" [initialBreakpoint]="0.35" [breakpoints]="[0, 0.35, 0.5]">\n <ng-template>\n <fm-modal-audio-message #audioComp *ngIf="isAudioModal" [chat]="chat" [modal]="audioModal"></fm-modal-audio-message>\n </ng-template>\n</ion-modal>',styles:['@charset "UTF-8";:host-context(body.dark) .btn-voice-start{background-color:#222428;color:#fff}:host-context(body.dark) ion-textarea{background-color:#222428;color:#fff}ion-toolbar{--background:none}ion-toolbar .button-item{--inner-padding-start:5px;--inner-padding-end:0px;--padding-start:5px;--padding-end:0px}ion-toolbar ion-item{--background:transparent}ion-textarea.custom{--background: #373737;--color: #fff;--padding-end: 10px;--padding-start: 10px;--placeholder-color: #ddd;--placeholder-opacity: .8}ion-textarea.custom textarea{width:calc(100% - 95px)}ion-textarea.custom ion-button{position:absolute;right:0}.input-item{display:flex;min-height:77px;align-items:center;border:none;--inner-padding-start:0px;--inner-padding-end:0px;--padding-start:0px;--padding-end:0px}.input-item ion-textarea{background-color:#fff;max-height:400px;padding:0 5px;margin:0 5px;border-radius:20px;overflow-y:auto}.input-item .btn-voice-start{display:flex;flex:1;justify-content:center;align-items:center;font-weight:700;background:#fff;border-radius:20px;min-height:50px}ion-textarea{transition:width .5s ease}ion-textarea:hover .btn-input-change,ion-textarea:focus-within .btn-input-change{display:none}.input-item:hover ion-textarea,.input-item:focus-within ion-textarea{border-color:var(--logo-color-primary)}::ng-deep .ant-modal-body{max-height:600px;overflow-y:auto}::ng-deep .ant-modal-footer{display:flex;justify-content:space-around}::ng-deep .ant-btn{width:40%}.popup-content{position:relative}.popup-content .message-content-user{display:flex;justify-content:flex-end}.popup-content .message-content-role{display:flex;justify-content:flex-start}.popup-content .message-content-system{display:flex;justify-content:center}.popup-content .user-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#e7f8ff}.popup-content .role-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#f6f6f6}.popup-content .user-question{margin-bottom:5px;display:flex;justify-content:flex-end}.popup-content .chat-time{margin-bottom:10px;display:flex;justify-content:flex-end;font-size:14px;color:#a3a3a3}.popup-content .role-time{justify-content:flex-start}\n']}]}],ctorParameters:()=>[{type:i2.ToastController},{type:i2.AlertController},{type:i2.NavController},{type:i1$1.Router},{type:ImagineService},{type:ChatService},{type:i1$1.ActivatedRoute},{type:i5$1.NzMessageService}],propDecorators:{audioComp:[{type:ViewChild,args:[ModalAudioMessageComponent]}],chat:[{type:Input}],message:[{type:Input}],role:[{type:Input}]}});class ChatPanelComponent{constructor(e,t,n){this.route=e,this.router=t,this.chatServ=n,window.location.pathname?.indexOf("chat/session")>-1&&document.body.classList.add("dark")}listenDivChange(){let e=new MutationObserver((()=>{this.scrollToBottom(this.contentComp)})),t={childList:!0,subtree:!0,attributes:!0};this.contentComp?.nativeElement&&e.observe(this.contentComp?.nativeElement,t)}scrollToBottom(e){e?.nativeElement?.scrollHeight&&(e.nativeElement.scrollTop=e.nativeElement.scrollHeight)}ngAfterViewInit(){}ngOnInit(){combineLatest([this.route.params,this.route.queryParams]).subscribe((async e=>{let t=e[0];e[1];if(console.log("params",e),this.chatId=t?.chatId||this.chatId||null,this.chatId&&await this.chatServ.initChatMap(this.chatId),this.roleId=t?.roleId||this.roleId||null,this.roleId){let e=await this.chatServ.createNewRoleChat(this.roleId);this.fmodeChat=e}this.chatId&&(this.fmodeChat=this.chatServ.chatMap[this.chatId],this.fmodeChat||this.router.navigate(["/chat/pro/mask"],{queryParams:{type:"employee"}}),this.fmodeChat=this.chatServ.chatMap[this.chatId]),this.leftButtons&&(this.fmodeChat.leftButtons=this.leftButtons),window.location.pathname?.indexOf("chat/session")>-1?this.fmodeChat.isVoiceInputMode=!0:this.fmodeChat.isVoiceInputMode=!1,this.modelList&&(this.chatServ.modelList=this.modelList,this.chatServ.currentModel=this.modelList[0]),setTimeout((()=>{this.listenDivChange()}),1e3)}))}loadMask(){}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatPanelComponent,deps:[{token:i1$1.ActivatedRoute},{token:i1$1.Router},{token:ChatService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:ChatPanelComponent,isStandalone:!0,selector:"app-chat-panel",inputs:{chatId:"chatId",maskId:"maskId",roleId:"roleId",leftButtons:"leftButtons",modelList:"modelList"},viewQueries:[{propertyName:"contentComp",first:!0,predicate:["contentComp"],descendants:!0}],ngImport:i0,template:'\n\x3c!-- <ion-header></ion-header> --\x3e\n\x3c!-- <ion-content class="ion-padding"> --\x3e\n <div class="chat-page" *ngIf="fmodeChat">\n <div class="header" [class.avatarHeader]="fmodeChat?.isAvatarShow">\n <fm-chat-header-area [chat]="fmodeChat"></fm-chat-header-area>\n </div>\n \n <div class="content" #contentComp>\n <fm-chat-message-area [chat]="fmodeChat"></fm-chat-message-area>\n </div>\n \n <div class="footer">\n <fm-chat-modal-input [chat]="fmodeChat"></fm-chat-modal-input>\n </div>\n </div>\n\n\x3c!-- </ion-content> --\x3e',styles:[".chat-page{display:flex;flex-direction:column;height:100%;background:#f3f3f3}.chat-page .content,.chat-page .header,.chat-page .footer{justify-content:center;align-items:center}.chat-page .content{flex-grow:1;flex:1;overflow-y:auto}.chat-page .avatarHeader{height:35vh!important;overflow:hidden}.chat-page .header{height:44px;margin-bottom:-1px}.chat-page .footer{height:auto;min-height:130px}:host-context(body.dark) .chat-page{background:#000}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:FmChatHeaderArea,selector:"fm-chat-header-area",inputs:["chat"]},{kind:"component",type:FmChatMesssageArea,selector:"fm-chat-message-area",inputs:["chatId","chat"]},{kind:"component",type:FmChatModalInput,selector:"fm-chat-modal-input",inputs:["chat","message","role"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatPanelComponent,decorators:[{type:Component,args:[{selector:"app-chat-panel",standalone:!0,imports:[CommonModule,FmChatHeaderArea,FmChatMesssageArea,FmChatModalInput],template:'\n\x3c!-- <ion-header></ion-header> --\x3e\n\x3c!-- <ion-content class="ion-padding"> --\x3e\n <div class="chat-page" *ngIf="fmodeChat">\n <div class="header" [class.avatarHeader]="fmodeChat?.isAvatarShow">\n <fm-chat-header-area [chat]="fmodeChat"></fm-chat-header-area>\n </div>\n \n <div class="content" #contentComp>\n <fm-chat-message-area [chat]="fmodeChat"></fm-chat-message-area>\n </div>\n \n <div class="footer">\n <fm-chat-modal-input [chat]="fmodeChat"></fm-chat-modal-input>\n </div>\n </div>\n\n\x3c!-- </ion-content> --\x3e',styles:[".chat-page{display:flex;flex-direction:column;height:100%;background:#f3f3f3}.chat-page .content,.chat-page .header,.chat-page .footer{justify-content:center;align-items:center}.chat-page .content{flex-grow:1;flex:1;overflow-y:auto}.chat-page .avatarHeader{height:35vh!important;overflow:hidden}.chat-page .header{height:44px;margin-bottom:-1px}.chat-page .footer{height:auto;min-height:130px}:host-context(body.dark) .chat-page{background:#000}\n"]}]}],ctorParameters:()=>[{type:i1$1.ActivatedRoute},{type:i1$1.Router},{type:ChatService}],propDecorators:{chatId:[{type:Input}],maskId:[{type:Input}],roleId:[{type:Input}],leftButtons:[{type:Input}],modelList:[{type:Input}],contentComp:[{type:ViewChild,args:["contentComp"]}]}}),window._AMapSecurityConfig={securityJsCode:"32aa3f4ab0fa0061de03edd4eafdd50a"};class PageMapStartComponent{constructor(){this.placeList=[{name:"江财蛟桥校区",location:[115.855125,28.744335]},{name:"江财枫林校区",location:[115.835639,28.734119]},{name:"江财麦庐校区",location:[115.816717,28.728899]}]}ngAfterViewInit(){this.initMap()}async initMap(){await this.createMap(),this.goAndMarkPlace(this.placeList[1])}async createMap(){this.AMap=await AMapLoader.load({key:"473b52010df7d3a32db0a2f5db245c8e",version:"2.0"}),this.map=new this.AMap.Map("container")}async addMarks(){let e=new this.AMap.Marker({position:[115.835639,28.734119]});this.map.add(e)}goAndMarkPlace(e){this.map.setCenter(e.location),this.map.setZoom(18),console.log(this.placeList),e.marker||(e.marker=new this.AMap.Marker({position:e.location}),this.map.add(e.marker))}clearMark(e){e?.marker?.remove()}planRoute(e,t){let n;this.map.plugin(["AMap.Transfer"],(()=>{let o={map:this.map,city:"南昌市",panel:"panel",policy:this.AMap.TransferPolicy.LEAST_TIME};console.log(this.AMap),console.log(this.AMap.TransferPolicy),n=new this.AMap.Transfer(o),n.search(new this.AMap.LngLat(e.location[0],e.location[1]),new this.AMap.LngLat(t.location[0],t.location[1]),((e,t)=>{"complete"===e?(console.log("绘制公交路线完成:"),console.log(t)):console.error("公交路线数据查询失败"+t)}))}))}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:PageMapStartComponent,deps:[],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:PageMapStartComponent,selector:"app-page-map.start",ngImport:i0,template:'\x3c!-- 全屏地图 --\x3e\n<div id="container"></div>\n\n\x3c!-- 右侧地点 --\x3e\n<div class="place-list">\n <ng-container *ngFor="let place of placeList">\n <div class="place-item" (click)="goAndMarkPlace(place)">\n {{place.name}}\n <button (click)="clearMark(place)">清除标记</button>\n </div>\n </ng-container>\n\n <button (click)="planRoute(placeList[0],placeList[1])">从蛟桥到枫林</button>\n \n</div>',styles:["#container{width:100%;height:100%;position:fixed}.place-list{display:flex;flex-direction:column;position:fixed;justify-content:center;align-items:center;height:80%;width:200px}.place-list .place-item{background-color:#ffffff4d;height:100px;width:90%}\n"],dependencies:[{kind:"directive",type:i2$2.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:PageMapStartComponent,decorators:[{type:Component,args:[{selector:"app-page-map.start",template:'\x3c!-- 全屏地图 --\x3e\n<div id="container"></div>\n\n\x3c!-- 右侧地点 --\x3e\n<div class="place-list">\n <ng-container *ngFor="let place of placeList">\n <div class="place-item" (click)="goAndMarkPlace(place)">\n {{place.name}}\n <button (click)="clearMark(place)">清除标记</button>\n </div>\n </ng-container>\n\n <button (click)="planRoute(placeList[0],placeList[1])">从蛟桥到枫林</button>\n \n</div>',styles:["#container{width:100%;height:100%;position:fixed}.place-list{display:flex;flex-direction:column;position:fixed;justify-content:center;align-items:center;height:80%;width:200px}.place-list .place-item{background-color:#ffffff4d;height:100px;width:90%}\n"]}]}]}),window._AMapSecurityConfig={securityJsCode:"32aa3f4ab0fa0061de03edd4eafdd50a"};class CompPoiPickerComponent{get name(){return this._name}set name(e){this._name=e,this.nameChange.emit(e)}get address(){return this._address}set address(e){this._address=e,this.addressChange.emit(e)}get location(){return this._location}set location(e){this._location=e,this.locationChange.emit(e)}constructor(){this.nameChange=new EventEmitter,this.addressChange=new EventEmitter,this.locationChange=new EventEmitter,this.isModalOpen=!1}cancel(){this.isModalOpen=!1,this.modal.dismiss(null,"cancel")}confirm(){this.isModalOpen=!1,this.modal.dismiss(this.address,"confirm")}onWillDismiss(e){"confirm"===e.detail.role&&console.log("确认")}openModal(){this.isModalOpen=!0,setTimeout((()=>{this.initMap()}),800)}ngAfterViewInit(){}initMap(){this.createMap()}async createMap(){this.AMap=await AMapLoader.load({key:"473b52010df7d3a32db0a2f5db245c8e",version:"2.0"});let e=this.container.nativeElement;this.map=new this.AMap.Map(e),this.goCurrentCenter()}goCurrentCenter(){this.AMap.plugin(["AMap.Geolocation"],(()=>{let e=new this.AMap.Geolocation({enableHighAccuracy:!0,timeout:1e4,maximumAge:0,convert:!0,showButton:!0,buttonPosition:"RB",buttonOffset:new this.AMap.Pixel(10,10),showMarker:!1,showCircle:!1,panToLocation:!0,zoomToAccuracy:!1});this.map.addControl(e),e.getCurrentPosition((function(e,t){"complete"===e?(console.log("当前位置经度:"+t.position.getLng()),console.log("当前位置纬度:"+t.position.getLat())):console.log("定位失败:"+t.message)}))}))}searchByAddress(){let e=this.panel.nativeElement;this.AMap.plugin(["AMap.PlaceSearch"],(()=>{let t=new this.AMap.PlaceSearch({pageSize:3,pageIndex:1,map:this.map,panel:e,autoFitView:!0});t.on("selectChanged",(e=>{this.name=e.selected.data.name,this.address=e.selected.data.address,this.location=new Parse__default.GeoPoint({latitude:e.selected.data.location.lat,longitude:e.selected.data.location.lng}),this.createCenterMarker()})),t.search(this.address)}))}createCenterMarker(){this.centerMarker||(this.centerMarker=new this.AMap.Marker({position:this.map.getCenter(),offset:new this.AMap.Pixel(-15,-15)}),this.map.add(this.centerMarker),this.map.on("dragging",(()=>{this.centerMarker.setPosition(this.map.getCenter())})),this.map.on("dragend",(()=>{let e=this.centerMarker.getPosition();this.location=new Parse__default.GeoPoint({latitude:e.lat,longitude:e.lng})})))}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompPoiPickerComponent,deps:[],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:CompPoiPickerComponent,selector:"fm-map-poi-picker",inputs:{_name:["name","_name"],_address:["address","_address"],_location:["location","_location"]},outputs:{nameChange:"nameChange",addressChange:"addressChange",locationChange:"locationChange"},viewQueries:[{propertyName:"container",first:!0,predicate:["container"],descendants:!0},{propertyName:"panel",first:!0,predicate:["panel"],descendants:!0},{propertyName:"modal",first:!0,predicate:IonModal$1,descendants:!0}],ngImport:i0,template:'\x3c!-- 未选点 --\x3e\n<ion-button (click)="openModal()" expand="block">开始选点</ion-button>\n\n\x3c!-- 已选点 --\x3e\n\n<ion-modal [isOpen]="isModalOpen" (willDismiss)="onWillDismiss($event)">\n<ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="cancel()">Cancel</ion-button>\n </ion-buttons>\n <ion-title>地图选点<ng-container *ngIf="location">({{location.latitude}},{{location.longitude}})</ng-container></ion-title>\n <ion-buttons slot="end">\n <ion-button (click)="confirm()" [strong]="true">Confirm</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding" style="height:100%">\n \x3c!-- 详细地址 --\x3e\n <ion-item>\n <ion-input\n label="请输入详细地址"\n labelPlacement="stacked"\n type="text"\n placeholder="精确到门牌号"\n [(ngModel)]="address"\n ></ion-input>\n <ion-button slot="end" (click)="searchByAddress()">搜索</ion-button>\n </ion-item>\n \n \x3c!-- 地图选点 --\x3e\n <div #container class="container"></div>\n <div #panel class="panel"></div>\n\n </ion-content>\n</ng-template>\n</ion-modal>\n\n',styles:[".container{width:100%;height:100%}.panel{position:absolute;background-color:#fff;max-height:50%;overflow-y:auto;top:12%;right:10px;width:45%}\n"],dependencies:[{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:i7.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:i7.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"component",type:i2.IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:i2.IonButtons,selector:"ion-buttons",inputs:["collapse"]},{kind:"component",type:i2.IonContent,selector:"ion-content",inputs:["color","fixedSlotPlacement","forceOverscroll","fullscreen","scrollEvents","scrollX","scrollY"]},{kind:"component",type:i2.IonHeader,selector:"ion-header",inputs:["collapse","mode","translucent"]},{kind:"component",type:i2.IonInput,selector:"ion-input",inputs:["autocapitalize","autocomplete","autocorrect","autofocus","clearInput","clearInputIcon","clearOnEdit","color","counter","counterFormatter","debounce","disabled","enterkeyhint","errorText","fill","helperText","inputmode","label","labelPlacement","max","maxlength","min","minlength","mode","multiple","name","pattern","placeholder","readonly","required","shape","spellcheck","step","type","value"]},{kind:"component",type:i2.IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:i2.IonTitle,selector:"ion-title",inputs:["color","size"]},{kind:"component",type:i2.IonToolbar,selector:"ion-toolbar",inputs:["color","mode"]},{kind:"component",type:i2.IonModal,selector:"ion-modal"},{kind:"directive",type:i2.TextValueAccessor,selector:"ion-input:not([type=number]),ion-textarea,ion-searchbar"}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompPoiPickerComponent,decorators:[{type:Component,args:[{selector:"fm-map-poi-picker",template:'\x3c!-- 未选点 --\x3e\n<ion-button (click)="openModal()" expand="block">开始选点</ion-button>\n\n\x3c!-- 已选点 --\x3e\n\n<ion-modal [isOpen]="isModalOpen" (willDismiss)="onWillDismiss($event)">\n<ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="cancel()">Cancel</ion-button>\n </ion-buttons>\n <ion-title>地图选点<ng-container *ngIf="location">({{location.latitude}},{{location.longitude}})</ng-container></ion-title>\n <ion-buttons slot="end">\n <ion-button (click)="confirm()" [strong]="true">Confirm</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding" style="height:100%">\n \x3c!-- 详细地址 --\x3e\n <ion-item>\n <ion-input\n label="请输入详细地址"\n labelPlacement="stacked"\n type="text"\n placeholder="精确到门牌号"\n [(ngModel)]="address"\n ></ion-input>\n <ion-button slot="end" (click)="searchByAddress()">搜索</ion-button>\n </ion-item>\n \n \x3c!-- 地图选点 --\x3e\n <div #container class="container"></div>\n <div #panel class="panel"></div>\n\n </ion-content>\n</ng-template>\n</ion-modal>\n\n',styles:[".container{width:100%;height:100%}.panel{position:absolute;background-color:#fff;max-height:50%;overflow-y:auto;top:12%;right:10px;width:45%}\n"]}]}],ctorParameters:()=>[],propDecorators:{container:[{type:ViewChild,args:["container"]}],panel:[{type:ViewChild,args:["panel"]}],_name:[{type:Input,args:["name"]}],nameChange:[{type:Output}],_address:[{type:Input,args:["address"]}],addressChange:[{type:Output}],_location:[{type:Input,args:["location"]}],locationChange:[{type:Output}],modal:[{type:ViewChild,args:[IonModal$1]}]}});class CompPoiPickerModule{static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompPoiPickerModule,deps:[],target:i0.ɵɵFactoryTarget.NgModule})}static{this.ɵmod=i0.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:CompPoiPickerModule,declarations:[CompPoiPickerComponent],imports:[CommonModule,FormsModule,ReactiveFormsModule,i2.IonicModule],exports:[CompPoiPickerComponent]})}static{this.ɵinj=i0.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompPoiPickerModule,imports:[CommonModule,FormsModule,ReactiveFormsModule,IonicModule.forRoot({mode:"ios"})]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:CompPoiPickerModule,decorators:[{type:NgModule,args:[{declarations:[CompPoiPickerComponent],imports:[CommonModule,FormsModule,ReactiveFormsModule,IonicModule.forRoot({mode:"ios"})],exports:[CompPoiPickerComponent]}]}]}),window._AMapSecurityConfig={securityJsCode:"32aa3f4ab0fa0061de03edd4eafdd50a"};class PagePlanRouteComponent{constructor(){this.placeList=[],this.currentTab="place",this.addNewPlace(),this.addNewPlace(),this.currentTab="plan"}addNewPlace(){this.placeList?.length>=1?this.placeList.push({name:"秋水广场",address:"南昌市秋水广场",location:new Parse__default.GeoPoint({latitude:28.682634,longitude:115.86273})}):this.placeList.push({name:"八一广场",address:"南昌市八一广场",location:new Parse__default.GeoPoint({latitude:28.673856,longitude:115.904477})})}ngAfterViewInit(){}async initMap(){await this.createMap(),this.goAndMarkPlace(this.placeList[0])}async createMap(){this.AMap=await AMapLoader.load({key:"473b52010df7d3a32db0a2f5db245c8e",version:"2.0"}),this.map=new this.AMap.Map("container-plan")}goAndMarkPlace(e){this.map.setCenter([e.location.latitude,e.location.longitude]),this.map.setZoom(18),e.marker||(e.marker=new this.AMap.Marker({position:[e.location.latitude,e.location.longitude]}),this.map.add(e.marker))}clearMark(e){e?.marker?.remove()}planRoute(e,t){let n;this.map.plugin(["AMap.Transfer"],(()=>{let o={map:this.map,city:"南昌市",panel:"panel",policy:this.AMap.TransferPolicy.LEAST_TIME};n=new this.AMap.Transfer(o);let i=new this.AMap.LngLat(e.location.longitude,e.location.latitude),a=new this.AMap.LngLat(t.location.longitude,t.location.latitude);n.search(i,a,((e,t)=>{"complete"===e?(console.log("绘制公交路线完成:"),console.log(t)):console.error("公交路线数据查询失败"+t)}))}))}async createPlan(){await this.initMap(),this.planRoute(this.placeList[0],this.placeList[1])}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:PagePlanRouteComponent,deps:[],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:PagePlanRouteComponent,selector:"app-page-plan-route",ngImport:i0,template:'<ion-segment value="place">\n <ion-segment-button (click)="currentTab=\'place\'" value="place">\n <ion-label>景点选择</ion-label>\n </ion-segment-button>\n <ion-segment-button (click)="currentTab=\'plan\'" value="plan">\n <ion-label>路线规划</ion-label>\n </ion-segment-button>\n </ion-segment>\n \n\n<ng-container *ngIf="currentTab==\'place\'">\n <h1>选择旅游计划景点</h1>\n\n <ng-container *ngFor="let place of placeList">\n <ion-card>\n <h2>{{place?.name}}</h2>\n <span *ngIf="place.address">详细地址:{{place.address}}</span>\n <span *ngIf="place.location">地图坐标:{{place.location.latitude}},{{place.location.longitude}}</span>\n <fm-map-poi-picker [(name)]="place.name" [(address)]="place.address" [(location)]="place.location"></fm-map-poi-picker>\n </ion-card>\n </ng-container>\n <ion-button (click)="addNewPlace()" expand="block">添加新景点</ion-button>\n</ng-container>\n\n<ng-container *ngIf="currentTab==\'plan\'">\n <ion-button (click)="createPlan()" expand="block">创建规划路线</ion-button>\n\n <div id="container-plan"></div>\n <div id="panel"></div>\n</ng-container>\n\n',styles:["#container-plan{width:100%;height:40%}#panel{width:100%;height:50%}\n"],dependencies:[{kind:"directive",type:i2$2.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i2$2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:i2.IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:i2.IonCard,selector:"ion-card",inputs:["button","color","disabled","download","href","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:i2.IonLabel,selector:"ion-label",inputs:["color","mode","position"]},{kind:"component",type:i2.IonSegment,selector:"ion-segment",inputs:["color","disabled","mode","scrollable","selectOnFocus","swipeGesture","value"]},{kind:"component",type:i2.IonSegmentButton,selector:"ion-segment-button",inputs:["disabled","layout","mode","type","value"]},{kind:"directive",type:i2.SelectValueAccessor,selector:"ion-select, ion-radio-group, ion-segment, ion-datetime"},{kind:"component",type:CompPoiPickerComponent,selector:"fm-map-poi-picker",inputs:["name","address","location"],outputs:["nameChange","addressChange","locationChange"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:PagePlanRouteComponent,decorators:[{type:Component,args:[{selector:"app-page-plan-route",template:'<ion-segment value="place">\n <ion-segment-button (click)="currentTab=\'place\'" value="place">\n <ion-label>景点选择</ion-label>\n </ion-segment-button>\n <ion-segment-button (click)="currentTab=\'plan\'" value="plan">\n <ion-label>路线规划</ion-label>\n </ion-segment-button>\n </ion-segment>\n \n\n<ng-container *ngIf="currentTab==\'place\'">\n <h1>选择旅游计划景点</h1>\n\n <ng-container *ngFor="let place of placeList">\n <ion-card>\n <h2>{{place?.name}}</h2>\n <span *ngIf="place.address">详细地址:{{place.address}}</span>\n <span *ngIf="place.location">地图坐标:{{place.location.latitude}},{{place.location.longitude}}</span>\n <fm-map-poi-picker [(name)]="place.name" [(address)]="place.address" [(location)]="place.location"></fm-map-poi-picker>\n </ion-card>\n </ng-container>\n <ion-button (click)="addNewPlace()" expand="block">添加新景点</ion-button>\n</ng-container>\n\n<ng-container *ngIf="currentTab==\'plan\'">\n <ion-button (click)="createPlan()" expand="block">创建规划路线</ion-button>\n\n <div id="container-plan"></div>\n <div id="panel"></div>\n</ng-container>\n\n',styles:["#container-plan{width:100%;height:40%}#panel{width:100%;height:50%}\n"]}]}],ctorParameters:()=>[]}),window._AMapSecurityConfig={securityJsCode:"32aa3f4ab0fa0061de03edd4eafdd50a"};class PageLocaScatterComponent{ngAfterViewInit(){this.initMap()}async initMap(){await this.createMap(),await this.createLoca()}async createLoca(){let e=window.loca=new Loca.Container({map:this.map}),t=new Loca.GeoJSONSource({url:"https://a.amap.com/Loca/static/loca-v2/demos/mock_data/sz_road.json"}),n=new Loca.ScatterLayer({zIndex:111,opacity:1,visible:!0,zooms:[2,22]});n.setSource(t),n.setStyle({color:"rgba(43,156,75,1)",unit:"meter",size:[150,150],borderWidth:0}),e.add(n);let o=new Loca.GeoJSONSource({url:"https://a.amap.com/Loca/static/loca-v2/demos/mock_data/sz_road_F.json"}),i=new Loca.ScatterLayer({loca:e,zIndex:113,opacity:1,visible:!0,zooms:[2,22]});i.setSource(o),i.setStyle({unit:"meter",size:[2600,2600],borderWidth:0,texture:"https://a.amap.com/Loca/static/loca-v2/demos/images/breath_red.png",duration:500,animate:!0});let a=new Loca.GeoJSONSource({url:"https://a.amap.com/Loca/static/loca-v2/demos/mock_data/sz_road_E.json"}),r=new Loca.ScatterLayer({loca:e,zIndex:112,opacity:1,visible:!0,zooms:[2,22]});r.setSource(a),r.setStyle({unit:"meter",size:[1e3,1e3],borderWidth:0,texture:"https://a.amap.com/Loca/static/loca-v2/demos/images/breath_yellow.png",duration:1e3,animate:!0}),e.animate.start();let s=new Loca.Dat;s.addLayer(n," 贴地"),s.addLayer(i,"红色"),s.addLayer(r,"黄色")}async createMap(){this.AMap=await AMapLoader.load({key:"473b52010df7d3a32db0a2f5db245c8e",version:"2.0",Loca:{version:"2.0.0"}}),this.map=new this.AMap.Map("container",{zoom:11.7,center:[113.97199630737305,22.5807295363949],pitch:40,showLabel:!1,mapStyle:"amap://styles/dark",viewMode:"3D"})}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:PageLocaScatterComponent,deps:[],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:PageLocaScatterComponent,selector:"app-page-loca-scatter",ngImport:i0,template:'<div id="container"></div>',styles:["#container{width:100%;height:100%;position:fixed}\n"]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:PageLocaScatterComponent,decorators:[{type:Component,args:[{selector:"app-page-loca-scatter",template:'<div id="container"></div>',styles:["#container{width:100%;height:100%;position:fixed}\n"]}]}]});const routes=[{path:"start",component:PageMapStartComponent},{path:"plan/route",component:PagePlanRouteComponent},{path:"loca/scatter",component:PageLocaScatterComponent}];class FmodeMapModule{static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeMapModule,deps:[],target:i0.ɵɵFactoryTarget.NgModule})}static{this.ɵmod=i0.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:FmodeMapModule,declarations:[PageMapStartComponent,PagePlanRouteComponent,PageLocaScatterComponent],imports:[CommonModule,i1$1.RouterModule,i2.IonicModule,CompPoiPickerModule],exports:[CompPoiPickerModule]})}static{this.ɵinj=i0.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeMapModule,imports:[CommonModule,RouterModule.forChild(routes),IonicModule.forRoot({mode:"ios"}),CompPoiPickerModule,CompPoiPickerModule]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeMapModule,decorators:[{type:NgModule,args:[{declarations:[PageMapStartComponent,PagePlanRouteComponent,PageLocaScatterComponent],imports:[CommonModule,RouterModule.forChild(routes),IonicModule.forRoot({mode:"ios"}),CompPoiPickerModule],exports:[CompPoiPickerModule]}]}]});class HwobsService{constructor(){this.Attachment=Parse__default.Object.extend("Attachment"),this.host="https://web3-test.obs.cn-south-1.myhuaweicloud.com/",this.bucketName="web3-test",this.obsClient=new ObsClient({access_key_id:"6UIET20WHUI5TLXWOVNA",secret_access_key:"YaoY8Kj3TeGZHEcBzplTMZiPGNL13Y3frEavC1kF",server:"https://obs.cn-south-1.myhuaweicloud.com"})}listDir(e){return new Promise(((t,n)=>{this.obsClient.listObjects({Bucket:this.bucketName,Prefix:e,Delimiter:"/"},((e,o)=>{if(e)console.error("Error--\x3e"+e),n(e);else{if(console.log("Status--\x3e"+o.CommonMsg.Status),console.log(o),o.CommonMsg.Status<300&&o.InterfaceResult)for(var i in o.InterfaceResult.Contents)console.log("Contents["+i+"]:"),console.log("Key--\x3e"+o.InterfaceResult.Contents[i].Key),console.log("Owner[ID]--\x3e"+o.InterfaceResult.Contents[i].Owner.ID);let e=o.InterfaceResult.CommonPrefixes,n=o.InterfaceResult.Contents;t({dirs:e,files:n})}}))}))}async uploadFile(e,t){let n=await this.checkFileExists(e);return n?.id?n:new Promise(((n,o)=>{this.obsClient.putObject({Bucket:this.bucketName,Key:t,SourceFile:e},(async(i,a)=>{if(i)console.error("Error--\x3e"+i),o(i);else{console.log("Status--\x3e"+a.CommonMsg.Status);let o=await this.saveAttachment(e,t);n(o)}}))}))}async checkFileExists(e){let t,n=await this.getFileHash(e),o=new Parse__default.Query("Attachment");o.equalTo("hash",n),o.equalTo("size",e.size);let i=await o.first();return i?.id||(i=new this.Attachment),t=i,t}async saveAttachment(e,t){let n=await this.getFileHash(e),o=await this.checkFileExists(e);return o.set("name",e.name),o.set("size",e.size),o.set("mime",e.type),o.set("url",this.host+t),o.set("hash",n),o=await o.save(),o}async getFileHash(e){return new Promise(((t,n)=>{const o=new FileReader;o.onload=async e=>{const n=e.target.result,o=await crypto.subtle.digest("SHA-256",n),i=Array.from(new Uint8Array(o)).map((e=>e.toString(16).padStart(2,"0"))).join("");t(i)},o.onerror=e=>{n(e.target.error)},o.readAsArrayBuffer(e)}))}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:HwobsService,deps:[],target:i0.ɵɵFactoryTarget.Injectable})}static{this.ɵprov=i0.ɵɵngDeclareInjectable({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:HwobsService,providedIn:"root"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:HwobsService,decorators:[{type:Injectable,args:[{providedIn:"root"}]}],ctorParameters:()=>[]});class HwobsManagerComponent{openFile(e){console.log("Opening file:",e)}openDir(e,t="pre"){if(e)this.prefix=e.Prefix,this.listDir(e.Prefix);else if("pre"==t){let e=this.prefix.split("/");if(e.length>1){let t=e.splice(0,e.length-1).join("/");console.log(t),this.prefix=t,this.listDir(t)}}}showName(e){return e.replaceAll(this.prefix,"")}constructor(e){this.hwobs=e,this.dirs=[],this.files=[],this.prefix="storage/",this.listDir(this.prefix)}async listDir(e){let{dirs:t,files:n}=await this.hwobs.listDir(e);this.dirs=t,this.files=n}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:HwobsManagerComponent,deps:[{token:HwobsService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:HwobsManagerComponent,isStandalone:!0,selector:"fm-storage-hwobs-manager",ngImport:i0,template:'<ion-header>\n <ion-toolbar>\n <ion-title>\n File Manager\n </ion-title>\n </ion-toolbar>\n </ion-header>\n \n <ion-content>\n <ion-list>\n <ion-item (click)="openDir(null,\'pre\')">\n <ion-icon [name]="\'folder\'" slot="start"></ion-icon>\n <ion-label>../</ion-label>\n </ion-item>\n <ion-item *ngFor="let item of dirs" (click)="openDir(item)">\n <ion-icon [name]="\'folder\'" slot="start"></ion-icon>\n <ion-label>{{ showName(item.Prefix) }}</ion-label>\n </ion-item>\n <ion-item *ngFor="let item of files" (click)="openFile(item)">\n <ion-icon [name]="\'document\'" slot="start"></ion-icon>\n <ion-label>{{ showName(item.Key) }}</ion-label>\n </ion-item>\n </ion-list>\n </ion-content>',styles:["ion-list ion-item ion-icon{font-size:24px;margin-right:8px}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2$2.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"ngmodule",type:FormsModule},{kind:"ngmodule",type:ReactiveFormsModule},{kind:"ngmodule",type:IonicModule},{kind:"component",type:i2.IonContent,selector:"ion-content",inputs:["color","fixedSlotPlacement","forceOverscroll","fullscreen","scrollEvents","scrollX","scrollY"]},{kind:"component",type:i2.IonHeader,selector:"ion-header",inputs:["collapse","mode","translucent"]},{kind:"component",type:i2.IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:i2.IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:i2.IonLabel,selector:"ion-label",inputs:["color","mode","position"]},{kind:"component",type:i2.IonList,selector:"ion-list",inputs:["inset","lines","mode"]},{kind:"component",type:i2.IonTitle,selector:"ion-title",inputs:["color","size"]},{kind:"component",type:i2.IonToolbar,selector:"ion-toolbar",inputs:["color","mode"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:HwobsManagerComponent,decorators:[{type:Component,args:[{standalone:!0,imports:[CommonModule,FormsModule,ReactiveFormsModule,IonicModule],selector:"fm-storage-hwobs-manager",template:'<ion-header>\n <ion-toolbar>\n <ion-title>\n File Manager\n </ion-title>\n </ion-toolbar>\n </ion-header>\n \n <ion-content>\n <ion-list>\n <ion-item (click)="openDir(null,\'pre\')">\n <ion-icon [name]="\'folder\'" slot="start"></ion-icon>\n <ion-label>../</ion-label>\n </ion-item>\n <ion-item *ngFor="let item of dirs" (click)="openDir(item)">\n <ion-icon [name]="\'folder\'" slot="start"></ion-icon>\n <ion-label>{{ showName(item.Prefix) }}</ion-label>\n </ion-item>\n <ion-item *ngFor="let item of files" (click)="openFile(item)">\n <ion-icon [name]="\'document\'" slot="start"></ion-icon>\n <ion-label>{{ showName(item.Key) }}</ion-label>\n </ion-item>\n </ion-list>\n </ion-content>',styles:["ion-list ion-item ion-icon{font-size:24px;margin-right:8px}\n"]}]}],ctorParameters:()=>[{type:HwobsService}]});class FmodeStorgeModule{static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeStorgeModule,deps:[],target:i0.ɵɵFactoryTarget.NgModule})}static{this.ɵmod=i0.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:FmodeStorgeModule,imports:[CommonModule,i2.IonicModule,HwobsManagerComponent],exports:[HwobsManagerComponent]})}static{this.ɵinj=i0.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeStorgeModule,providers:[Diagnostic,NovaUploadService],imports:[CommonModule,IonicModule.forRoot({mode:"ios"}),HwobsManagerComponent]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmodeStorgeModule,decorators:[{type:NgModule,args:[{declarations:[],imports:[CommonModule,IonicModule.forRoot({mode:"ios"}),HwobsManagerComponent],exports:[HwobsManagerComponent],providers:[Diagnostic,NovaUploadService]}]}]});export{AccountService,AgentPrompt,AuthService,AvatarModule,AvatarRoutes,ChatContentPipe,ChatListComponent,ChatPanelComponent,ChatService,ClipboardService,CompAvatarParticleComponent,CompAvatarRoleImageComponent,CompAvatarRoleVideoComponent,CompAvatarTalkComponent,CompPoiPickerComponent,CompPoiPickerModule,CompRolePromptComponent,CompUserAvatarComponent,CrossService,FmChatHeaderArea,FmChatMessageCard,FmChatMesssageArea,FmChatModalInput,FmaiService,FmodeChat,FmodeChatCompletion,FmodeMapModule,FmodeStorgeModule,FmodeVoiceService,HidexmlPipe,HwobsManagerComponent,HwobsService,ImagineService,MASK_LIST,MarkdownMathJax,MarkdownParse,MarkdownPreviewComponent,MarkdownPreviewModule,ModalChatVoiceInputComponent,NovaCloudService,NovaUploadService,UtilnowPipe,getMessageContentText,getMessageImageUrl};
9
9
  var MODULE_PATH_NEED = `6K+l5paH5Lu25piv5pys6aG555uu55qE5LiA6YOo5YiGIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHRoZSBDb21wb25lbnRzIGluIEZtb2RlIEluYy4KICAgIOeJiOadg+aJgOaciSDCqSDmnKrmnaXpo57pqawgwqkg5rGf6KW/6ISR5o6n56eR5oqA5pyJ6ZmQ5YWs5Y+4IENvcHlyaWdodCDCqSBGbW9kZSBUZWNobm9sb2d5IENvLiwgTHRkLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCBSaWdodHMgUmVzZXJ2ZWQuCiAgICDkuKXnpoHlnKjmnKrnu4/mjojmnYPnmoTmg4XlhrXkuIvvvIzpgJrov4fku7vkvZXlqpLku4vlpI3liLbmraTmlofku7YgVW5hdXRob3JpemVkIGNvcHlpbmcgb2YgdGhpcyBmaWxlLCB2aWEgYW55IG1lZGl1bSBpcyBzdHJpY3RseSBwcm9oaWJpdGVkCiAgICDor6Xmlofku7bmmK/kuJPmnInnmoTmnLrlr4bmlofku7YgUHJvcHJpZXRhcnkgYW5kIGNvbmZpZGVudGlhbAogICAKICAgIENvcHlyaWdodCAyMDIxLW5vdyBGbW9kZSBJbmMuIHN1cHBvcnRAZm1vZGUuY24uIDE4NjA3MDA3MDczLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgUEFUSDovaG9tZS9yeWFuL3dvcmtzcGFjZS9ub3ZhL25vdmEtYWRtaW4vZGlzdC9mbW9kZS1uZy9mZXNtMjAyMi9mbW9kZS1uZy5tanM=`
10
10