@graphen.ai/aiia-sdk 1.0.13 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.cjs +1 -1
- package/dist/browser.d.ts +257 -4
- package/dist/browser.mjs +1 -1
- package/dist/node.cjs +1 -1
- package/dist/node.d.ts +8 -0
- package/dist/node.mjs +1 -1
- package/package.json +2 -1
package/dist/browser.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e,t=require("lodash-es"),i=require("moment"),s=require("rxjs"),a=require("@mediapipe/tasks-vision"),n=require("socket.io-client");!function(e){e["網絡錯誤"]="ERROR CODE: 500",e["環境錯誤(browser)"]="ERROR CODE: 1001",e["Worklet模組載入失敗"]="ERROR CODE: 1002",e["未獲得媒體裝置權限"]="ERROR CODE: 1003",e["實例已摧毀"]="ERROR CODE: 1004",e["環境錯誤(nodejs)"]="ERROR CODE: 2001",e["未提供憑證"]="ERROR CODE: 2002",e["獲取權杖失敗"]="ERROR CODE: 2003",e["沒有可用專案"]="ERROR CODE: 2004",e["重複初始化"]="ERROR CODE: 2005"}(e||(e={}));const o="undefined"!=typeof window;"undefined"!=typeof process&&null!=process.versions&&process.versions.node;class r{config;get webserver(){return this.config.webserver}get environment(){return this.config.env}get license(){return this.config.license??""}get port(){return function(e,t){const i=t??NaN;if(e){const t=parseInt(e);return isNaN(t)?i:t}return i}(process.env.PORT,this.config.port??3e3)}get ws_url(){return this.config.ws_url??""}get worklet_url(){return this.config.worklet_url??""}get project(){const{project:e}=t.assign({},this.config);return void 0===e?{specific:!1}:"string"==typeof e?{name:e,id:e,specific:!1}:t.assign({},e,{specific:!0})}get endPoint(){return this.environment,{api:"https://aiia-content-management-dev-21193779403.asia-east1.run.app",socket:"wss://graphen-agentic-workflow-dev-21193779403.asia-east1.run.app"}}get debug(){return this.config.debug??!0}get mediaStream(){return this.config.mediaStream}get chunkTimeInSeconds(){return"number"==typeof this.config.chunkTimeInSeconds&&this.config.chunkTimeInSeconds>0?this.config.chunkTimeInSeconds:.3}get llmSampleRate(){return"number"==typeof this.config.llmSampleRate&&this.config.llmSampleRate>0?this.config.llmSampleRate:16e3}get faceDetection(){return t.assign({perSecond:3,confidence:80},this.config.faceDetection)}get autoClearSubtitle(){const{user:e,aiia:i}=t.assign({},this.config.autoClearSubtitle);let s=5e3,a=5e3;return"number"==typeof e?s=e>=0?e:s:!1===e&&(s=NaN),"number"==typeof i?a=i>=0?i:a:!1===i&&(a=NaN),{userDelayTime:s,aiiaDelayTime:a}}constructor(e){this.config=e}}var c;!function(e){e["通道、雲端服務、麥克風都已就緒"]="CODE: 1000",e["未取得媒體裝置權限,請重新設定或忽略此訊息"]="CODE: 1001",e["請訂閱專案列表"]="CODE: 1002",e["初始化必要依賴"]="CODE: 1010",e["指定依賴已完成"]="CODE: 1011",e["啟動SDK"]="CODE: 1012",e["結束SDK"]="CODE: 1013",e["安全的關閉連線"]="CODE: 2000",e["無副作用的關閉連線"]="CODE: 2001",e["與雲端的服務中斷"]="CODE: 2002",e["沒有授權,請聯繫Graphen"]="CODE: 2003",e["自動重新連線連端服務"]="CODE: 2004",e["未預期的斷線,請聯繫Graphen"]="CODE: 2005",e["開始初始化必要模組"]="CODE: 2010",e["指定模組初始化完成"]="CODE: 2011",e["啟動服務"]="CODE: 2012",e["服務結束"]="CODE: 2013"}(c||(c={}));const u={code:console.log,debug:console.log,info:console.log,warn:console.warn,error:console.error,fatal:console.error},h=[];const d=new Proxy(u,{get(e,s,a){if("string"==typeof s)switch(s){case"debug":case"info":case"error":case"warn":case"fatal":case"code":return(...a)=>{const n=i().format("yyyy-MM-DD[T]HH:mm:ss");t.forEach(h,e=>{e.next(s,n,...a)}),e[s](`[Aiia::${s}_${n}_]`,...a)};default:return}},set:(e,t,i,s)=>!0});var l,b;function p(e,t,i){return Math.max(i,Math.min(e,t))}function m(e){const t=new DataView(e.buffer),i=[];for(let s=0;s<e.length;s++){const e=t.getInt16(2*s,!0)/32768;i.push(e)}return new Float32Array(i)}function g(e){const t=new DataView(e.buffer),i=[];for(let s=0;s<e.length;s++){const e=p(32768*t.getFloat32(4*s,!0),32767,-32768);i.push(e)}return i}!function(e){e[e.unknow=0]="unknow",e[e.allowed=1]="allowed",e[e.rejected=2]="rejected"}(l||(l={}));class f{audioContext;type="audio";currentNode;bufferQueue;gainNode;set volume(e){e<0&&(e=0),e>100&&(e=100),this.gainNode.gain.value=e/100}get volume(){return Math.round(100*this.gainNode.gain.value)}constructor(e){this.audioContext=e,this.bufferQueue=[],this.currentNode=null,this.gainNode=this.audioContext.createGain(),this.gainNode.connect(this.audioContext.destination)}addBuffer(e){this.bufferQueue.push(e)}addBufferByFloat32(e,t=1){const i=e.length,s=this.audioContext.sampleRate,a=this.audioContext.createBuffer(t,i,s),n=e.slice();for(let e=0;e<t;e++)a.copyToChannel(n,e);this.addBuffer(a)}addBufferByInt16(e,t=1){this.addBufferByFloat32(m(e),t)}startSpeech(){null===this.currentNode&&this.continue()}pauseSpeech(){this.audioContext.suspend().catch(e=>{d.error("pause speech fail",e)})}resumeSpeech(){this.audioContext.resume().catch(e=>{d.error("resume speech fail",e)})}nextSpeech(){this.bufferQueue.length>0&&(this.clearNode(),this.continue())}stopSpeech(){this.bufferQueue=[],this.clearNode()}clearNode(){this.currentNode&&(this.currentNode.onended=function(){},this.currentNode.stop(),this.currentNode.disconnect(),this.currentNode=null)}continue(){const e=this.bufferQueue.shift();if(e){this.currentNode=this.audioContext.createBufferSource(),this.currentNode.buffer=e,this.currentNode.connect(this.gainNode);const t=this.continue.bind(this);this.currentNode.onended=t,this.currentNode.start()}else this.clearNode()}}class S{stream;audioContext;type="vad";workletNode;source;isRecording=!1;outputSampleRate;chunkTimeInSeconds;pcmSub;get pcm(){return this.pcmSub.asObservable()}constructor(e,t,i){this.stream=e,this.audioContext=t,this.outputSampleRate=i?.llmSampleRate??16e3,this.chunkTimeInSeconds=i?.chunkTimeInSeconds??1,this.pcmSub=new s.Subject}async startRecord(){this.isRecording||(this.source=this.audioContext.createMediaStreamSource(this.stream),this.workletNode=new AudioWorkletNode(this.audioContext,"aiia-vad",{processorOptions:{outputSampleRate:this.outputSampleRate,chunkTimeInSeconds:this.chunkTimeInSeconds}}),this.source.connect(this.workletNode),this.workletNode.port.onmessage=e=>{const{float32:t}=e.data;t&&this.pcmSub.next(new Float32Array(t))},this.isRecording=!0)}stopRecord(){this.isRecording&&(this.workletNode&&(this.workletNode.port.onmessage=null,this.workletNode.disconnect()),this.source&&this.source.disconnect(),this.isRecording=!1)}}class y{type="camera";aiiaCamera;get detections(){return this.aiiaCamera.detections}constructor(e){const{perSecond:i}=t.assign({perSecond:3},e);this.aiiaCamera=new C,this.aiiaCamera.setFrequency(i),document.body.append(this.aiiaCamera)}async init(e){try{const t=await a.FilesetResolver.forVisionTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.0/wasm"),i=await a.FaceDetector.createFromOptions(t,{baseOptions:{modelAssetPath:"https://storage.googleapis.com/mediapipe-models/face_detector/blaze_face_short_range/float16/1/blaze_face_short_range.tflite",delegate:"GPU"},runningMode:"VIDEO"});this.aiiaCamera.setStream(e),this.aiiaCamera.setFaceDetector(i)}catch(e){d.error("Camera init fail",e)}}startCapture(){this.aiiaCamera.startCapture()}stopCapture(){this.aiiaCamera.stopCapture()}onDestroy(){this.aiiaCamera.remove()}}class C extends HTMLElement{static get observedAttributes(){return["debug"]}_shadow;_containerEl;_styleEl;_videoEl;_isDebug;_debugElements;_interval;_lastTimestamp;_loopFrameID;_faceDetector;_detectionsSub;_isReady;get detections(){return this._detectionsSub.asObservable()}constructor(){super(),this._isDebug=!1,this._isReady=!1,this._shadow=this.attachShadow({mode:"open"}),this._containerEl=document.createElement("div"),this._videoEl=document.createElement("video"),this._styleEl=document.createElement("style"),this._debugElements=[],this._loopFrameID=null,this._detectionsSub=new s.Subject,this._interval=Math.ceil(1e3/3),this._lastTimestamp=0,this.predictWebcam=this.predictWebcam.bind(this),this._settingContainer(),this._settingStyle(),this._settingVideo(),this._containerEl.appendChild(this._videoEl),this._shadow.appendChild(this._styleEl),this._shadow.appendChild(this._containerEl)}connectedCallback(){this.startCapture()}disconnectedCallback(){this.stopCapture()}attributeChangedCallback(e,t,i){"debug"===e&&(this._isDebug=null!==i&&("true"===i||""===i),this._containerEl.style.visibility=this._isDebug?"visible":"hidden")}setStream(e){this._videoEl.onloadedmetadata=()=>{this._isReady=!0},this._videoEl.srcObject=e}setFaceDetector(e){this._faceDetector=e}setFrequency(e){this._interval=Math.ceil(1e3/e)}_settingStyle(){this._styleEl.textContent="\n .aiia_container {\n visibility: hidden;\n position: fixed;\n top: 0;\n left: 0;\n }\n .aiia_container .highlighter {\n background: rgba(0, 255, 0, 0.25);\n border: 1px dashed #fff;\n z-index: 1;\n position: absolute;\n }\n .aiia_container .confidence {\n position: absolute;\n padding-bottom: 5px;\n padding-top: 5px;\n background-color: #007f8b;\n color: #fff;\n border: 1px dashed rgba(255, 255, 255, 0.7);\n z-index: 2;\n font-size: 12px;\n margin: 0;\n }\n "}_settingContainer(){this._containerEl.classList.add("aiia_container")}_settingVideo(){this._videoEl.autoplay=!0,this._videoEl.playsInline=!0,this._videoEl.muted=!0}getVideo(){return this._videoEl}startCapture(){null===this._loopFrameID&&(this._videoEl.play(),this._loopFrameID=window.requestAnimationFrame(this.predictWebcam))}stopCapture(){null!==this._loopFrameID&&(window.cancelAnimationFrame(this._loopFrameID),this._loopFrameID=null),this._videoEl.pause()}async predictWebcam(){if(this._loopFrameID=window.requestAnimationFrame(this.predictWebcam),void 0===this._faceDetector||!this._isReady)return;const e=performance.now();if(this._lastTimestamp+this._interval<=e){this._lastTimestamp=e;const t=this._faceDetector.detectForVideo(this._videoEl,e).detections;this._isDebug&&this._drawRect(t),this._detectionsSub.next(t)}}_drawRect(e){t.forEach(e,(e,t)=>{const{categories:i,boundingBox:s}=e;if(s){let e=this._debugElements[2*t],a=this._debugElements[2*t+1];e&&a||(e=document.createElement("div"),e.classList.add("highlighter"),a=document.createElement("p"),a.classList.add("confidence"),this._containerEl.append(a,e),this._debugElements.push(e,a)),e.style.display="block",a.style.display="block";const n=100*i[0].score;a.innerText=`Confidence: ${Math.round(n)} %`,a.style.right=this._videoEl.offsetWidth-s.width-s.originX+"px",a.style.top=s.originY-30+"px",a.style.width=s.width-10+"px",e.style.right=this._videoEl.offsetWidth-s.width-s.originX+"px",e.style.top=`${s.originY}px`,e.style.width=s.width-10+"px",e.style.height=`${s.height}px`}});for(let t=2*e.length;t<this._debugElements.length;t++)this._debugElements[t].style.display="none"}destroy(){this._detectionsSub.complete(),this.remove()}}customElements.define("aiia-camera",C),function(e){e[e.padding=0]="padding",e[e.rejected=1]="rejected",e[e.loadfail=2]="loadfail",e[e.allowed=3]="allowed"}(b||(b={}));class w{stream;_state;stateSub;audioCtx;audioManager;vadManager;camManager;destory;pcmSub;detectionsSub;get sampleRate(){return this.audioCtx?this.audioCtx.sampleRate:16e3}get pcm(){return this.pcmSub.asObservable()}get detections(){return this.detectionsSub.asObservable()}get state(){return this._state}set state(e){e!==this._state&&(this._state=e,this.stateSub.next(e))}get stateObs(){return this.stateSub.asObservable()}constructor(e){this.stream=e,this.stateSub=new s.Subject,this.pcmSub=new s.Subject,this.destory=new s.Subject,this.detectionsSub=new s.Subject,this.state=b.padding}async init(t,i){const a=this.stream??await async function(e){try{return await navigator.mediaDevices.getUserMedia(e)}catch(e){return null}}({audio:{echoCancellation:!0,noiseSuppression:!0},video:!0});if(null===a)throw this.state=b.rejected,new Error(e["未獲得媒體裝置權限"]);this.stream=a,this.audioCtx=new AudioContext;try{await this.audioCtx.audioWorklet.addModule(t)}catch(t){throw d.fatal(t),this.state=b.loadfail,new Error(e["Worklet模組載入失敗"])}this.state=b.allowed,this.audioManager=new f(this.audioCtx),this.vadManager=new S(a,this.audioCtx,i),this.vadManager.pcm.pipe(s.takeUntil(this.destory)).subscribe(e=>{this.pcmSub.next(e)}),this.camManager=new y(i?.faceDetection),this.camManager.detections.pipe(s.takeUntil(this.destory)).subscribe(e=>{this.detectionsSub.next(e)}),this.camManager.init(a)}addAudioQueue(e){const i=t.get(e,"buffer",void 0),s=t.get(e,"float32",void 0),a=t.get(e,"int16",void 0),n=t.get(e,"numberOfChannels",void 0);i?this.audioManager?.addBuffer(i):s?this.audioManager?.addBufferByFloat32(s,n):a&&this.audioManager?.addBufferByInt16(a,n)}playAudio(){this.audioManager?.startSpeech()}stopAudio(){this.audioManager?.stopSpeech()}startRecord(){this.vadManager?.startRecord()}stopRecord(){this.vadManager?.stopRecord()}setVolume(e){this.audioManager&&(this.audioManager.volume=e)}getVolume(){return this.audioManager?this.audioManager.volume:0}startCapture(){this.camManager?.startCapture()}stopCapture(){this.camManager?.stopCapture()}onDestroy(){this.camManager?.onDestroy(),this.audioCtx?.close(),this.destory.next(),this.destory.complete()}}class _{socket;messageSub;destorySub;get message(){return this.messageSub.asObservable()}constructor(e){this.destorySub=new s.Subject,this.messageSub=new s.Subject;const{specific:i,id:a}=e.project;this.socket=n.io(e.ws_url,t.assign({autoConnect:!1},i&&void 0!==a?{query:{uuid:a}}:{}))}start(){const e="list",t="cloud",i="channel";s.fromEvent(this.socket,"connect").pipe(s.takeUntil(this.destorySub)).subscribe(()=>{d.debug("Client ID: ",this.socket.id)}),s.fromEvent(this.socket,e).pipe(s.take(1),s.takeUntil(this.destorySub)).subscribe(t=>{this.messageSub.next({event:e,data:t})}),s.fromEvent(this.socket,t).pipe(s.takeUntil(this.destorySub)).subscribe(e=>{this.messageSub.next({event:t,data:e})}),s.fromEvent(this.socket,i).pipe(s.takeUntil(this.destorySub)).subscribe(e=>{this.messageSub.next({event:i,data:e})}),this.socket.connect()}send(e,t){this.socket.emit(e,t)}sendToCloud(e){this.send("cloud",JSON.stringify(e))}onDestroy(){this.destorySub.next(),this.destorySub.complete(),this.messageSub.complete(),this.socket.disconnect()}}class v{config;media;chat;destorySub;projectsSub;layoutSub;aiiaSubtitleSub;userSubtitleSub;sampleRateOfWhisper;channelState;stateSub;_currentState;isMuteAiia;aiiaSubtitleClearSub;userSubtitleClearSub;_lastProjects;get state(){return this.stateSub.asObservable()}get currentState(){return this._currentState}get layout(){return this.layoutSub.asObservable()}get projects(){return this.projectsSub.asObservable()}get lastProjects(){return t.map(this._lastProjects,e=>({...e}))}get aiiaSubtitle(){return this.aiiaSubtitleSub.asObservable()}get userSubtitle(){return this.userSubtitleSub.asObservable()}set volume(e){this.media.setVolume(e)}get volume(){return this.media.getVolume()}constructor(e,t){this.config=e,this.media=t,this.layoutSub=new s.Subject,this.projectsSub=new s.ReplaySubject(1),this.destorySub=new s.Subject,this.aiiaSubtitleSub=new s.Subject,this.userSubtitleSub=new s.Subject,this.aiiaSubtitleClearSub=new s.Subject,this.userSubtitleClearSub=new s.Subject,this.stateSub=new s.BehaviorSubject("NotStart"),this.sampleRateOfWhisper={input:e.llmSampleRate,output:16e3},this.channelState={proxy:!1,cloud:!1},this.isMuteAiia=!1,this._lastProjects=[],this.chat=new _(e),d.code(c["指定依賴已完成"],"chat"),this.close=this.onDestroy,this.behavior=this.behavior.bind(this),this.cloudToObj=this.cloudToObj.bind(this);const{userDelayTime:i,aiiaDelayTime:a}=e.autoClearSubtitle;isNaN(a)||this.aiiaSubtitleClearSub.pipe(s.debounceTime(a),s.takeUntil(this.destorySub)).subscribe(()=>{this.aiiaSubtitleSub.next("")}),isNaN(i)||this.userSubtitleClearSub.pipe(s.debounceTime(i),s.takeUntil(this.destorySub)).subscribe(()=>{this.userSubtitleSub.next("")}),this.stateSub.pipe(s.takeUntil(this.destorySub)).subscribe(e=>{this._currentState=e}),this.projectsSub.pipe(s.takeUntil(this.destorySub)).subscribe(e=>{this._lastProjects=e})}start(){this.media.stateObs.pipe(s.takeUntil(this.destorySub)).subscribe(()=>{this.channelCheck()}),this.chat.message.pipe(s.takeUntil(this.destorySub)).subscribe(({event:e,data:i})=>{switch(e){case"cloud":this.cloudToObj(i);break;case"list":{const{id:e,name:s,specific:a}=this.config.project;let n=null;if(a&&void 0!==e)n=e;else{const a=t.find(i,t=>t.name===s||t.id===e);a&&(n=a.id)}null!==n?this.chooseProject(n):(this.projectsSub.next(i),this.stateSub.next("WattingProjectID"),d.code(c["請訂閱專案列表"]));break}case"channel":switch(i){case"open":this.channelState.proxy=!0,this.channelCheck();break;case"close":this.channelState.proxy=!1,this.media.stopRecord(),this.media.stopCapture(),this.stateSub.next("CloseService");break;case"no_permissions":this.channelState.proxy=!1,this.media.stopRecord(),this.media.stopCapture(),this.stateSub.next("NoPermissions");break;case"reconnect":this.channelState.proxy=!1,this.media.stopRecord(),this.media.stopCapture(),this.stateSub.next("ReconnectingCloud")}}}),this.chat.start(),this.stateSub.next("ConnectingCloud"),d.code(c["啟動SDK"])}close;resetSession(){this.chat.sendToCloud({request:"reset"}),this.media.stopAudio(),this.userSubtitleSub.next(""),this.aiiaSubtitleSub.next(""),this.layoutSub.next({type:"resetLayout"})}skip(){this.chat.sendToCloud({request:"skip"}),this.media.stopAudio(),this.userSubtitleSub.next(""),this.aiiaSubtitleSub.next("")}chooseProject(e){this.chat.send("uuid",e),this.stateSub.next("ConnectingCloud")}mute(){this.isMuteAiia=!0,this.media.stopAudio(),this.media.stopRecord()}unmute(){this.isMuteAiia=!1,this.media.startRecord()}cloudToObj(e){try{const i=JSON.parse(e);void 0!==t.get(i,"signal")?this.behavior(i):t.isArray(i)?t.map(i,this.behavior):t.map(t.values(i),this.behavior)}catch(e){d.error("message transfer fail",e)}}behavior(e){switch(e.signal){case"layout":this.layoutSub.next(e.content);break;case"audio":if("sampleRate"===e.command)this.sampleRateOfWhisper.output=e.content;else switch(e.command){case"pcm":if(!this.isMuteAiia){const t=function(e,t,i){if(t===i)return e;const s=i/t,a=Math.ceil(e.length*s),n=new Float32Array(a);for(let t=0;t<a;t++){const i=t/s,a=Math.floor(i),o=i-a,r=e[a],c=e[Math.min(a+1,e.length-1)];n[t]=r+(c-r)*o}return n}(m(new Int16Array(e.content)),this.sampleRateOfWhisper.output,this.media.sampleRate);this.media.addAudioQueue({float32:t}),this.media.playAudio()}break;case"interrupted":this.media.stopAudio(),this.aiiaSubtitleSub.next("")}break;case"status":"Connected"===t.get(e,"content")&&(this.channelState.cloud=!0,this.channelCheck(),this.layoutSub.next({type:"resetLayout"}));break;case"agent":if(!this.isMuteAiia){const i=t.get(e,"content.function_result.response");void 0!==i&&(this.aiiaSubtitleSub.next(i),this.aiiaSubtitleClearSub.next())}break;case"asr":if(!this.isMuteAiia&&"ASR"===t.get(e,"content.function_type")){const i=t.get(e,"content.function_result.result");void 0!==i&&(this.userSubtitleSub.next(i),this.userSubtitleClearSub.next())}break;default:d.debug(e.signal)}}channelCheck(){const{proxy:e,cloud:i}=this.channelState;if(e&&i&&this.media.state===b.allowed){this.chat.sendToCloud({request:"audio",command:"sampleRate",content:this.sampleRateOfWhisper.input}),this.media.pcm.pipe(s.takeUntil(this.destorySub)).subscribe(e=>{this.chat.sendToCloud({request:"audio",command:"pcm",content:g(e)})});const e=(a=this.config.faceDetection.confidence,function(e){const i=t.filter(e,e=>100*(e.categories[0]?.score??0)>=a),s=t.compact(t.map(i,e=>{if(void 0!==e.boundingBox){const t=e.boundingBox,i=t.width*t.height,s=e.categories[0]?.score??0;return{...t,area:i,score:100*s}}return null}));return t.sortBy(s,["area","confidenceScore"])[0]??null});this.media.detections.pipe(s.takeUntil(this.destorySub),s.map(e)).subscribe(e=>{this.chat.sendToCloud({request:"face_detect",content:null!==e})}),this.media.startRecord(),this.media.startCapture(),this.stateSub.next("InService"),d.code(c["通道、雲端服務、麥克風都已就緒"])}else e&&i&&this.media.state!==b.allowed&&(this.stateSub.next("InServiceNoMedia"),d.code(c["未取得媒體裝置權限,請重新設定或忽略此訊息"]));var a}onDestroy(){this.chat.onDestroy(),this.media.onDestroy(),this.destorySub.next(),this.destorySub.complete(),this.stateSub.next("Destroy"),this.stateSub.complete(),d.code(c["結束SDK"])}}exports.initSdk=function(i){if(o){!function(e){const{info:t,error:i,warn:s,debug:a,fatal:n,code:o}=function(e){if(void 0===e||"all"===e)return{code:!0,error:!0,warn:!0,info:!0,debug:!0,fatal:!0};if("none"===e)return{error:!1,code:!1,warn:!1,info:!1,debug:!1,fatal:!1};if("boolean"==typeof e)return{code:e,error:e,warn:e,info:e,debug:e,fatal:e};{const t=new Set(e);return{code:t.has("code"),debug:t.has("debug"),fatal:t.has("fatal"),error:t.has("error"),warn:t.has("warn"),info:t.has("info")}}}(e);o||(u.code=()=>{}),a||(u.debug=()=>{}),t||(u.info=()=>{}),s||(u.warn=()=>{}),i||(u.error=()=>{}),n||(u.fatal=()=>{})}(t.get(i,"debug",!0)),d.code(c["初始化必要依賴"]);const e=new r(t.assign({},i));d.code(c["指定依賴已完成"],"config");const s=new w(e.mediaStream);d.code(c["指定依賴已完成"],"config");const a=new v(e,s);return d.code(c["指定依賴已完成"],"sdk"),""!==e.worklet_url&&s.init(e.worklet_url,e),a}throw new Error(e["環境錯誤(browser)"])};
|
|
1
|
+
"use strict";var e=require("lodash-es"),t=require("moment");require("mathjs");var i,s=require("rxjs"),a=require("@mediapipe/tasks-vision"),n=require("socket.io-client");!function(e){e["網絡錯誤"]="ERROR CODE: 500",e["環境錯誤(browser)"]="ERROR CODE: 1001",e["Worklet模組載入失敗"]="ERROR CODE: 1002",e["未獲得媒體裝置權限"]="ERROR CODE: 1003",e["實例已摧毀"]="ERROR CODE: 1004",e["環境錯誤(nodejs)"]="ERROR CODE: 2001",e["未提供憑證"]="ERROR CODE: 2002",e["獲取權杖失敗"]="ERROR CODE: 2003",e["沒有可用專案"]="ERROR CODE: 2004",e["重複初始化"]="ERROR CODE: 2005"}(i||(i={}));const o="undefined"!=typeof window;"undefined"!=typeof process&&null!=process.versions&&process.versions.node;class r{config;get webserver(){return this.config.webserver}get environment(){return this.config.env}get license(){return this.config.license??""}get port(){return function(e,t){const i=t??NaN;if(e){const t=parseInt(e);return isNaN(t)?i:t}return i}(process.env.PORT,this.config.port??3e3)}get ws_url(){return this.config.ws_url??""}get worklet_url(){return this.config.worklet_url??""}get project(){const{project:t}=e.assign({},this.config);return void 0===t?{specific:!1}:"string"==typeof t?{name:t,id:t,specific:!1}:e.assign({},t,{specific:!0})}get endPoint(){return this.environment,{api:"https://aiia-content-management-dev-21193779403.asia-east1.run.app",socket:"wss://graphen-agentic-workflow-dev-21193779403.asia-east1.run.app"}}get debug(){return this.config.debug??!0}get mediaStream(){return this.config.mediaStream}get chunkTimeInSeconds(){return"number"==typeof this.config.chunkTimeInSeconds&&this.config.chunkTimeInSeconds>0?this.config.chunkTimeInSeconds:.3}get llmSampleRate(){return"number"==typeof this.config.llmSampleRate&&this.config.llmSampleRate>0?this.config.llmSampleRate:16e3}get faceDetection(){return e.assign({perSecond:3,confidence:80},this.config.faceDetection)}get autoClearSubtitle(){const{user:t,aiia:i}=e.assign({},this.config.autoClearSubtitle);let s=5e3,a=5e3;return"number"==typeof t?s=t>=0?t:s:!1===t&&(s=NaN),"number"==typeof i?a=i>=0?i:a:!1===i&&(a=NaN),{userDelayTime:s,aiiaDelayTime:a}}get eyeTrackEnable(){return this.config.eyeTrackEnable??!1}constructor(e){this.config=e}}var c;!function(e){e["通道、雲端服務、麥克風都已就緒"]="CODE: 1000",e["未取得媒體裝置權限,請重新設定或忽略此訊息"]="CODE: 1001",e["請訂閱專案列表"]="CODE: 1002",e["初始化必要依賴"]="CODE: 1010",e["指定依賴已完成"]="CODE: 1011",e["啟動SDK"]="CODE: 1012",e["結束SDK"]="CODE: 1013",e["安全的關閉連線"]="CODE: 2000",e["無副作用的關閉連線"]="CODE: 2001",e["與雲端的服務中斷"]="CODE: 2002",e["沒有授權,請聯繫Graphen"]="CODE: 2003",e["自動重新連線連端服務"]="CODE: 2004",e["未預期的斷線,請聯繫Graphen"]="CODE: 2005",e["開始初始化必要模組"]="CODE: 2010",e["指定模組初始化完成"]="CODE: 2011",e["啟動服務"]="CODE: 2012",e["服務結束"]="CODE: 2013"}(c||(c={}));const u={code:console.log,debug:console.log,info:console.log,warn:console.warn,error:console.error,fatal:console.error},h=[];const d=new Proxy(u,{get(i,s,a){if("string"==typeof s)switch(s){case"debug":case"info":case"error":case"warn":case"fatal":case"code":return(...a)=>{const n=t().format("yyyy-MM-DD[T]HH:mm:ss");e.forEach(h,e=>{e.next(s,n,...a)}),i[s](`[Aiia::${s}_${n}_]`,...a)};default:return}},set:(e,t,i,s)=>!0});var l,b;function p(e,t,i){return Math.max(i,Math.min(e,t))}function m(e){const t=new DataView(e.buffer),i=[];for(let s=0;s<e.length;s++){const e=t.getInt16(2*s,!0)/32768;i.push(e)}return new Float32Array(i)}function g(e){const t=new DataView(e.buffer),i=[];for(let s=0;s<e.length;s++){const e=p(32768*t.getFloat32(4*s,!0),32767,-32768);i.push(e)}return i}!function(e){e[e.unknow=0]="unknow",e[e.allowed=1]="allowed",e[e.rejected=2]="rejected"}(l||(l={}));class f{audioContext;type="audio";currentNode;bufferQueue;gainNode;set volume(e){e<0&&(e=0),e>100&&(e=100),this.gainNode.gain.value=e/100}get volume(){return Math.round(100*this.gainNode.gain.value)}constructor(e){this.audioContext=e,this.bufferQueue=[],this.currentNode=null,this.gainNode=this.audioContext.createGain(),this.gainNode.connect(this.audioContext.destination)}addBuffer(e){this.bufferQueue.push(e)}addBufferByFloat32(e,t=1){const i=e.length,s=this.audioContext.sampleRate,a=this.audioContext.createBuffer(t,i,s),n=e.slice();for(let e=0;e<t;e++)a.copyToChannel(n,e);this.addBuffer(a)}addBufferByInt16(e,t=1){this.addBufferByFloat32(m(e),t)}startSpeech(){null===this.currentNode&&this.continue()}pauseSpeech(){this.audioContext.suspend().catch(e=>{d.error("pause speech fail",e)})}resumeSpeech(){this.audioContext.resume().catch(e=>{d.error("resume speech fail",e)})}nextSpeech(){this.bufferQueue.length>0&&(this.clearNode(),this.continue())}stopSpeech(){this.bufferQueue=[],this.clearNode()}clearNode(){this.currentNode&&(this.currentNode.onended=function(){},this.currentNode.stop(),this.currentNode.disconnect(),this.currentNode=null)}continue(){const e=this.bufferQueue.shift();if(e){this.currentNode=this.audioContext.createBufferSource(),this.currentNode.buffer=e,this.currentNode.connect(this.gainNode);const t=this.continue.bind(this);this.currentNode.onended=t,this.currentNode.start()}else this.clearNode()}}class S{stream;audioContext;type="vad";workletNode;source;isRecording=!1;outputSampleRate;chunkTimeInSeconds;pcmSub;get pcm(){return this.pcmSub.asObservable()}constructor(e,t,i){this.stream=e,this.audioContext=t,this.outputSampleRate=i?.llmSampleRate??16e3,this.chunkTimeInSeconds=i?.chunkTimeInSeconds??1,this.pcmSub=new s.Subject}async startRecord(){this.isRecording||(this.source=this.audioContext.createMediaStreamSource(this.stream),this.workletNode=new AudioWorkletNode(this.audioContext,"aiia-vad",{processorOptions:{outputSampleRate:this.outputSampleRate,chunkTimeInSeconds:this.chunkTimeInSeconds}}),this.source.connect(this.workletNode),this.workletNode.port.onmessage=e=>{const{float32:t}=e.data;t&&this.pcmSub.next(new Float32Array(t))},this.isRecording=!0)}stopRecord(){this.isRecording&&(this.workletNode&&(this.workletNode.port.onmessage=null,this.workletNode.disconnect()),this.source&&this.source.disconnect(),this.isRecording=!1)}}class y{type="camera";aiiaCamera;get detections(){return this.aiiaCamera.detections}get videoSize(){return this.aiiaCamera.videoSize}constructor(t){const{perSecond:i}=e.assign({perSecond:3},t);this.aiiaCamera=new w,this.aiiaCamera.setFrequency(i),document.body.append(this.aiiaCamera)}async init(e){try{const t=await a.FilesetResolver.forVisionTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.0/wasm"),i=await a.FaceDetector.createFromOptions(t,{baseOptions:{modelAssetPath:"https://storage.googleapis.com/mediapipe-models/face_detector/blaze_face_short_range/float16/1/blaze_face_short_range.tflite",delegate:"GPU"},runningMode:"VIDEO"});this.aiiaCamera.setStream(e),this.aiiaCamera.setFaceDetector(i)}catch(e){d.error("Camera init fail",e)}}startCapture(){this.aiiaCamera.startCapture()}stopCapture(){this.aiiaCamera.stopCapture()}onDestroy(){this.aiiaCamera.remove()}}class w extends HTMLElement{static get observedAttributes(){return["debug"]}_shadow;_containerEl;_styleEl;_videoEl;_isDebug;_debugElements;_interval;_lastTimestamp;_loopFrameID;_faceDetector;_detectionsSub;_isReady;get detections(){return this._detectionsSub.asObservable()}get videoSize(){return{width:this._videoEl.videoWidth,height:this._videoEl.videoHeight}}constructor(){super(),this._isDebug=!1,this._isReady=!1,this._shadow=this.attachShadow({mode:"open"}),this._containerEl=document.createElement("div"),this._videoEl=document.createElement("video"),this._styleEl=document.createElement("style"),this._debugElements=[],this._loopFrameID=null,this._detectionsSub=new s.Subject,this._interval=Math.ceil(1e3/3),this._lastTimestamp=0,this.predictWebcam=this.predictWebcam.bind(this),this._settingContainer(),this._settingStyle(),this._settingVideo(),this._containerEl.appendChild(this._videoEl),this._shadow.appendChild(this._styleEl),this._shadow.appendChild(this._containerEl)}connectedCallback(){this.startCapture()}disconnectedCallback(){this.stopCapture()}attributeChangedCallback(e,t,i){"debug"===e&&(this._isDebug=null!==i&&("true"===i||""===i),this._containerEl.style.visibility=this._isDebug?"visible":"hidden")}setStream(e){this._videoEl.onloadedmetadata=()=>{this._isReady=!0},this._videoEl.srcObject=e}setFaceDetector(e){this._faceDetector=e}setFrequency(e){this._interval=Math.ceil(1e3/e)}_settingStyle(){this._styleEl.textContent="\n .aiia_container {\n visibility: hidden;\n position: fixed;\n top: 0;\n left: 0;\n }\n .aiia_container .highlighter {\n background: rgba(0, 255, 0, 0.25);\n border: 1px dashed #fff;\n z-index: 1;\n position: absolute;\n }\n .aiia_container .confidence {\n position: absolute;\n padding-bottom: 5px;\n padding-top: 5px;\n background-color: #007f8b;\n color: #fff;\n border: 1px dashed rgba(255, 255, 255, 0.7);\n z-index: 2;\n font-size: 12px;\n margin: 0;\n }\n "}_settingContainer(){this._containerEl.classList.add("aiia_container")}_settingVideo(){this._videoEl.autoplay=!0,this._videoEl.playsInline=!0,this._videoEl.muted=!0}getVideo(){return this._videoEl}startCapture(){null===this._loopFrameID&&(this._videoEl.play(),this._loopFrameID=window.requestAnimationFrame(this.predictWebcam))}stopCapture(){null!==this._loopFrameID&&(window.cancelAnimationFrame(this._loopFrameID),this._loopFrameID=null),this._videoEl.pause()}async predictWebcam(){if(this._loopFrameID=window.requestAnimationFrame(this.predictWebcam),void 0===this._faceDetector||!this._isReady)return;const e=performance.now();if(this._lastTimestamp+this._interval<=e){this._lastTimestamp=e;const t=this._faceDetector.detectForVideo(this._videoEl,e).detections;this._isDebug&&this._drawRect(t),this._detectionsSub.next(t)}}_drawRect(t){e.forEach(t,(e,t)=>{const{categories:i,boundingBox:s}=e;if(s){let e=this._debugElements[2*t],a=this._debugElements[2*t+1];e&&a||(e=document.createElement("div"),e.classList.add("highlighter"),a=document.createElement("p"),a.classList.add("confidence"),this._containerEl.append(a,e),this._debugElements.push(e,a)),e.style.display="block",a.style.display="block";const n=100*i[0].score;a.innerText=`Confidence: ${Math.round(n)} %`,a.style.right=this._videoEl.offsetWidth-s.width-s.originX+"px",a.style.top=s.originY-30+"px",a.style.width=s.width-10+"px",e.style.right=this._videoEl.offsetWidth-s.width-s.originX+"px",e.style.top=`${s.originY}px`,e.style.width=s.width-10+"px",e.style.height=`${s.height}px`}});for(let e=2*t.length;e<this._debugElements.length;e++)this._debugElements[e].style.display="none"}destroy(){this._detectionsSub.complete(),this.remove()}}customElements.define("aiia-camera",w),function(e){e[e.padding=0]="padding",e[e.rejected=1]="rejected",e[e.loadfail=2]="loadfail",e[e.allowed=3]="allowed"}(b||(b={}));class C{stream;_state;stateSub;audioCtx;audioManager;vadManager;camManager;destory;pcmSub;detectionsSub;get sampleRate(){return this.audioCtx?this.audioCtx.sampleRate:16e3}get pcm(){return this.pcmSub.asObservable()}get detections(){return this.detectionsSub.asObservable()}get state(){return this._state}set state(e){e!==this._state&&(this._state=e,this.stateSub.next(e))}get stateObs(){return this.stateSub.asObservable()}constructor(e){this.stream=e,this.stateSub=new s.Subject,this.pcmSub=new s.Subject,this.destory=new s.Subject,this.detectionsSub=new s.Subject,this.state=b.padding}async init(e,t){const a=this.stream??await async function(e){try{return await navigator.mediaDevices.getUserMedia(e)}catch(e){return null}}({audio:{echoCancellation:!0,noiseSuppression:!0},video:!0});if(null===a)throw this.state=b.rejected,new Error(i["未獲得媒體裝置權限"]);this.stream=a,this.audioCtx=new AudioContext;try{await this.audioCtx.audioWorklet.addModule(e)}catch(e){throw d.fatal(e),this.state=b.loadfail,new Error(i["Worklet模組載入失敗"])}this.state=b.allowed,this.audioManager=new f(this.audioCtx),this.vadManager=new S(a,this.audioCtx,t),this.vadManager.pcm.pipe(s.takeUntil(this.destory)).subscribe(e=>{this.pcmSub.next(e)});const n=new y(t?.faceDetection);n.detections.pipe(s.takeUntil(this.destory)).subscribe(e=>{const{width:t,height:i}=n.videoSize;this.detectionsSub.next({detections:e,clientWidth:t,clientHeight:i})}),n.init(a),this.camManager=n}addAudioQueue(t){const i=e.get(t,"buffer",void 0),s=e.get(t,"float32",void 0),a=e.get(t,"int16",void 0),n=e.get(t,"numberOfChannels",void 0);i?this.audioManager?.addBuffer(i):s?this.audioManager?.addBufferByFloat32(s,n):a&&this.audioManager?.addBufferByInt16(a,n)}playAudio(){this.audioManager?.startSpeech()}stopAudio(){this.audioManager?.stopSpeech()}startRecord(){this.vadManager?.startRecord()}stopRecord(){this.vadManager?.stopRecord()}setVolume(e){this.audioManager&&(this.audioManager.volume=e)}getVolume(){return this.audioManager?this.audioManager.volume:0}startCapture(){this.camManager?.startCapture()}stopCapture(){this.camManager?.stopCapture()}onDestroy(){this.camManager?.onDestroy(),this.audioCtx?.close(),this.destory.next(),this.destory.complete()}}class v{socket;messageSub;destorySub;get message(){return this.messageSub.asObservable()}constructor(t){this.destorySub=new s.Subject,this.messageSub=new s.Subject;const{specific:i,id:a}=t.project;this.socket=n.io(t.ws_url,e.assign({autoConnect:!1},i&&void 0!==a?{query:{uuid:a}}:{}))}start(){const e="list",t="cloud",i="channel";s.fromEvent(this.socket,"connect").pipe(s.takeUntil(this.destorySub)).subscribe(()=>{d.debug("Client ID: ",this.socket.id)}),s.fromEvent(this.socket,e).pipe(s.take(1),s.takeUntil(this.destorySub)).subscribe(t=>{this.messageSub.next({event:e,data:t})}),s.fromEvent(this.socket,t).pipe(s.takeUntil(this.destorySub)).subscribe(e=>{this.messageSub.next({event:t,data:e})}),s.fromEvent(this.socket,i).pipe(s.takeUntil(this.destorySub)).subscribe(e=>{this.messageSub.next({event:i,data:e})}),this.socket.connect()}send(e,t){this.socket.emit(e,t)}sendToCloud(e){this.send("cloud",JSON.stringify(e))}onDestroy(){this.destorySub.next(),this.destorySub.complete(),this.messageSub.complete(),this.socket.disconnect()}}class _{config;media;chat;destorySub;projectsSub;layoutSub;aiiaSubtitleSub;userSubtitleSub;sampleRateOfWhisper;channelState;stateSub;_currentState;isMuteAiia;aiiaSubtitleClearSub;userSubtitleClearSub;_lastProjects;get state(){return this.stateSub.asObservable()}get currentState(){return this._currentState}get layout(){return this.layoutSub.asObservable()}get projects(){return this.projectsSub.asObservable()}get lastProjects(){return e.map(this._lastProjects,e=>({...e}))}get aiiaSubtitle(){return this.aiiaSubtitleSub.asObservable()}get userSubtitle(){return this.userSubtitleSub.asObservable()}set volume(e){this.media.setVolume(e)}get volume(){return this.media.getVolume()}constructor(e,t){this.config=e,this.media=t,this.layoutSub=new s.Subject,this.projectsSub=new s.ReplaySubject(1),this.destorySub=new s.Subject,this.aiiaSubtitleSub=new s.Subject,this.userSubtitleSub=new s.Subject,this.aiiaSubtitleClearSub=new s.Subject,this.userSubtitleClearSub=new s.Subject,this.stateSub=new s.BehaviorSubject("NotStart"),this.sampleRateOfWhisper={input:e.llmSampleRate,output:16e3},this.channelState={proxy:!1,cloud:!1},this.isMuteAiia=!1,this._lastProjects=[],this.chat=new v(e),d.code(c["指定依賴已完成"],"chat"),this.close=this.onDestroy,this.behavior=this.behavior.bind(this),this.cloudToObj=this.cloudToObj.bind(this);const{userDelayTime:i,aiiaDelayTime:a}=e.autoClearSubtitle;isNaN(a)||this.aiiaSubtitleClearSub.pipe(s.debounceTime(a),s.takeUntil(this.destorySub)).subscribe(()=>{this.aiiaSubtitleSub.next("")}),isNaN(i)||this.userSubtitleClearSub.pipe(s.debounceTime(i),s.takeUntil(this.destorySub)).subscribe(()=>{this.userSubtitleSub.next("")}),this.stateSub.pipe(s.takeUntil(this.destorySub)).subscribe(e=>{this._currentState=e}),this.projectsSub.pipe(s.takeUntil(this.destorySub)).subscribe(e=>{this._lastProjects=e})}start(){this.media.stateObs.pipe(s.takeUntil(this.destorySub)).subscribe(()=>{this.channelCheck()}),this.chat.message.pipe(s.takeUntil(this.destorySub)).subscribe(({event:t,data:i})=>{switch(t){case"cloud":this.cloudToObj(i);break;case"list":{const{id:t,name:s,specific:a}=this.config.project;let n=null;if(a&&void 0!==t)n=t;else{const a=e.find(i,e=>e.name===s||e.id===t);a&&(n=a.id)}null!==n?this.chooseProject(n):(this.projectsSub.next(i),this.stateSub.next("WattingProjectID"),d.code(c["請訂閱專案列表"]));break}case"channel":switch(i){case"open":this.channelState.proxy=!0,this.channelCheck();break;case"close":this.channelState.proxy=!1,this.media.stopRecord(),this.media.stopCapture(),this.stateSub.next("CloseService");break;case"no_permissions":this.channelState.proxy=!1,this.media.stopRecord(),this.media.stopCapture(),this.stateSub.next("NoPermissions");break;case"reconnect":this.channelState.proxy=!1,this.media.stopRecord(),this.media.stopCapture(),this.stateSub.next("ReconnectingCloud")}}}),this.chat.start(),this.stateSub.next("ConnectingCloud"),d.code(c["啟動SDK"])}close;resetSession(){throw new Error("Please use `reset` instead, 請使用`reset`代替")}skip(){this.chat.sendToCloud({request:"skip"})}reset(){this.chat.sendToCloud({request:"reset"})}chooseProject(e){this.chat.send("uuid",e),this.stateSub.next("ConnectingCloud")}mute(){this.isMuteAiia=!0,this.media.stopAudio(),this.media.stopRecord()}unmute(){this.isMuteAiia=!1,this.media.startRecord()}cloudToObj(t){try{const i=JSON.parse(t);void 0!==e.get(i,"signal")?this.behavior(i):e.isArray(i)?e.map(i,this.behavior):e.map(e.values(i),this.behavior)}catch(e){d.error("message transfer fail",e)}}behavior(t){switch(t.signal){case"layout":this.layoutSub.next(t.content);break;case"audio":if("sampleRate"===t.command)this.sampleRateOfWhisper.output=t.content;else switch(t.command){case"pcm":if(!this.isMuteAiia){const e=function(e,t,i){if(t===i)return e;const s=i/t,a=Math.ceil(e.length*s),n=new Float32Array(a);for(let t=0;t<a;t++){const i=t/s,a=Math.floor(i),o=i-a,r=e[a],c=e[Math.min(a+1,e.length-1)];n[t]=r+(c-r)*o}return n}(m(new Int16Array(t.content)),this.sampleRateOfWhisper.output,this.media.sampleRate);this.media.addAudioQueue({float32:e}),this.media.playAudio()}break;case"interrupted":this.media.stopAudio(),this.aiiaSubtitleSub.next("")}break;case"status":"Connected"===e.get(t,"content")&&(this.channelState.cloud=!0,this.channelCheck(),this.layoutSub.next({type:"resetLayout"}));break;case"agent":if(!this.isMuteAiia){const i=e.get(t,"content.function_result.response");void 0!==i&&(this.aiiaSubtitleSub.next(i),this.aiiaSubtitleClearSub.next())}break;case"asr":if(!this.isMuteAiia&&"ASR"===e.get(t,"content.function_type")){const i=e.get(t,"content.function_result.result");void 0!==i&&(this.userSubtitleSub.next(i),this.userSubtitleClearSub.next())}break;default:d.debug(t.signal)}}channelCheck(){const{proxy:t,cloud:i}=this.channelState;if(t&&i&&this.media.state===b.allowed){this.chat.sendToCloud({request:"audio",command:"sampleRate",content:this.sampleRateOfWhisper.input}),this.media.pcm.pipe(s.takeUntil(this.destorySub)).subscribe(e=>{this.chat.sendToCloud({request:"audio",command:"pcm",content:g(e)})});const t=(a=this.config.faceDetection.confidence,function(t,i){const{width:s,height:n}=i,o=e.filter(t,e=>100*(e.categories[0]?.score??0)>=a),r=e.compact(e.map(o,e=>{if(void 0!==e.boundingBox){const t=e.boundingBox,i=t.width*t.height,a=e.categories[0]?.score??0;return{...t,area:i,score:100*a,clientWidth:s,clientHeight:n}}return null}));return e.sortBy(r,["area","score"])[0]??null});this.media.detections.pipe(s.takeUntil(this.destorySub),s.map(({detections:e,clientHeight:i,clientWidth:s})=>t(e,{width:s,height:i}))).subscribe(e=>{this.chat.send("face",e)}),this.media.startRecord(),this.media.startCapture(),this.stateSub.next("InService"),d.code(c["通道、雲端服務、麥克風都已就緒"])}else t&&i&&this.media.state!==b.allowed&&(this.stateSub.next("InServiceNoMedia"),d.code(c["未取得媒體裝置權限,請重新設定或忽略此訊息"]));var a}onDestroy(){this.chat.onDestroy(),this.media.onDestroy(),this.destorySub.next(),this.destorySub.complete(),this.stateSub.next("Destroy"),this.stateSub.complete(),d.code(c["結束SDK"])}}exports.initSdk=function(t){if(o){!function(e){const{info:t,error:i,warn:s,debug:a,fatal:n,code:o}=function(e){if(void 0===e||"all"===e)return{code:!0,error:!0,warn:!0,info:!0,debug:!0,fatal:!0};if("none"===e)return{error:!1,code:!1,warn:!1,info:!1,debug:!1,fatal:!1};if("boolean"==typeof e)return{code:e,error:e,warn:e,info:e,debug:e,fatal:e};{const t=new Set(e);return{code:t.has("code"),debug:t.has("debug"),fatal:t.has("fatal"),error:t.has("error"),warn:t.has("warn"),info:t.has("info")}}}(e);o||(u.code=()=>{}),a||(u.debug=()=>{}),t||(u.info=()=>{}),s||(u.warn=()=>{}),i||(u.error=()=>{}),n||(u.fatal=()=>{})}(e.get(t,"debug",!0)),d.code(c["初始化必要依賴"]);const i=new r(e.assign({},t));d.code(c["指定依賴已完成"],"config");const s=new C(i.mediaStream);d.code(c["指定依賴已完成"],"config");const a=new _(i,s);return d.code(c["指定依賴已完成"],"sdk"),""!==i.worklet_url&&s.init(i.worklet_url,i),a}throw new Error(i["環境錯誤(browser)"])};
|
package/dist/browser.d.ts
CHANGED
|
@@ -5,6 +5,68 @@ import { Observable } from 'rxjs';
|
|
|
5
5
|
import { Server } from 'http';
|
|
6
6
|
import { Server as Server_2 } from 'https';
|
|
7
7
|
|
|
8
|
+
declare interface AGENT {
|
|
9
|
+
signal: "agent";
|
|
10
|
+
content: {
|
|
11
|
+
function_type: "response";
|
|
12
|
+
function_result: AGENT_function_result;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
declare interface AGENT_function_result {
|
|
17
|
+
response: string;
|
|
18
|
+
resp_type: string;
|
|
19
|
+
lang: number;
|
|
20
|
+
string: string;
|
|
21
|
+
control: AGENT_function_result_control;
|
|
22
|
+
properties: AGENT_function_result_properties;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
declare interface AGENT_function_result_control {
|
|
26
|
+
panel: string | null;
|
|
27
|
+
chat: boolean;
|
|
28
|
+
auto_continue: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
declare interface AGENT_function_result_properties {
|
|
32
|
+
panel: string | null;
|
|
33
|
+
chat?: number;
|
|
34
|
+
auto_continue?: number;
|
|
35
|
+
title?: string;
|
|
36
|
+
images: string[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export declare namespace aiia_msg {
|
|
40
|
+
export {
|
|
41
|
+
TTS,
|
|
42
|
+
MIC,
|
|
43
|
+
ASR,
|
|
44
|
+
OLD_ASR,
|
|
45
|
+
RATINGS,
|
|
46
|
+
AGENT_function_result_control,
|
|
47
|
+
AGENT_function_result_properties,
|
|
48
|
+
AGENT_function_result,
|
|
49
|
+
AGENT,
|
|
50
|
+
OLD_AGENT_content_1,
|
|
51
|
+
OLD_AGENT_content_2,
|
|
52
|
+
OLD_AGENT,
|
|
53
|
+
QUESTIONNAIRE,
|
|
54
|
+
LayoutID,
|
|
55
|
+
LAYOUT,
|
|
56
|
+
AUDIO,
|
|
57
|
+
CLOUD_SOCKET_MSG,
|
|
58
|
+
Signal,
|
|
59
|
+
SendMessage_MiniGame,
|
|
60
|
+
SendMessage_Layout,
|
|
61
|
+
SendMessage_Audio_Init,
|
|
62
|
+
SendMessage_Audio_PCM,
|
|
63
|
+
SendMessage_Audio,
|
|
64
|
+
SendMessage_Origin,
|
|
65
|
+
SendMessage_Face,
|
|
66
|
+
SendMessage
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
8
70
|
declare class AiiaConfig {
|
|
9
71
|
private config;
|
|
10
72
|
get webserver(): (Server<any, any> | Server_2<any, any> | Http2SecureServer<any, any, any, any> | Http2Server<any, any, any, any>) | undefined;
|
|
@@ -32,6 +94,7 @@ declare class AiiaConfig {
|
|
|
32
94
|
userDelayTime: number;
|
|
33
95
|
aiiaDelayTime: number;
|
|
34
96
|
};
|
|
97
|
+
get eyeTrackEnable(): boolean;
|
|
35
98
|
constructor(config: InitOptions);
|
|
36
99
|
}
|
|
37
100
|
|
|
@@ -82,18 +145,18 @@ declare class AiiaSdk {
|
|
|
82
145
|
*/
|
|
83
146
|
get layout(): Observable< {
|
|
84
147
|
type: "mount";
|
|
85
|
-
id: LayoutID;
|
|
148
|
+
id: aiia_msg.LayoutID;
|
|
86
149
|
panel: string;
|
|
87
150
|
props?: Record<string, unknown>;
|
|
88
151
|
zIndex?: number;
|
|
89
152
|
} | {
|
|
90
153
|
type: "update";
|
|
91
|
-
id: LayoutID;
|
|
154
|
+
id: aiia_msg.LayoutID;
|
|
92
155
|
props?: Record<string, unknown>;
|
|
93
156
|
zIndex?: number;
|
|
94
157
|
} | {
|
|
95
158
|
type: "unmount";
|
|
96
|
-
id: LayoutID;
|
|
159
|
+
id: aiia_msg.LayoutID;
|
|
97
160
|
} | {
|
|
98
161
|
type: "resetLayout";
|
|
99
162
|
}>;
|
|
@@ -184,6 +247,14 @@ declare class AiiaSdk {
|
|
|
184
247
|
* Interrupt the current conversation
|
|
185
248
|
*/
|
|
186
249
|
skip(): void;
|
|
250
|
+
/**
|
|
251
|
+
* [zh]
|
|
252
|
+
* 重置對話記憶
|
|
253
|
+
*
|
|
254
|
+
* [en]
|
|
255
|
+
* Reset conversation memory
|
|
256
|
+
*/
|
|
257
|
+
reset(): void;
|
|
187
258
|
/**
|
|
188
259
|
* [zh]
|
|
189
260
|
* 若沒有明確指定 Project 時,請呼叫此方法
|
|
@@ -228,8 +299,43 @@ declare class AiiaSdk {
|
|
|
228
299
|
|
|
229
300
|
export declare type AiiaState = "NotStart" | "WattingProjectID" | "ConnectingCloud" | "ReconnectingCloud" | "InService" | "InServiceNoMedia" | "NoPermissions" | "CloseService" | "Destroy";
|
|
230
301
|
|
|
302
|
+
declare interface ASR {
|
|
303
|
+
signal: "asr";
|
|
304
|
+
content: {
|
|
305
|
+
function_type: undefined;
|
|
306
|
+
status: "voice";
|
|
307
|
+
} | {
|
|
308
|
+
function_type: "voice_detection";
|
|
309
|
+
} | {
|
|
310
|
+
function_type: "ASR";
|
|
311
|
+
function_result: {
|
|
312
|
+
lang: string;
|
|
313
|
+
result: string;
|
|
314
|
+
filename: string | null;
|
|
315
|
+
};
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
declare type AUDIO = {
|
|
320
|
+
signal: "audio";
|
|
321
|
+
content: number[];
|
|
322
|
+
command: "pcm";
|
|
323
|
+
} | {
|
|
324
|
+
signal: "audio";
|
|
325
|
+
content: number;
|
|
326
|
+
command: "sampleRate";
|
|
327
|
+
} | {
|
|
328
|
+
signal: "status";
|
|
329
|
+
content: "Connected";
|
|
330
|
+
} | {
|
|
331
|
+
signal: "audio";
|
|
332
|
+
command: "interrupted";
|
|
333
|
+
};
|
|
334
|
+
|
|
231
335
|
export declare type BrowserInitOptions = Omit<InitOptions, "webserver" | "port" | "license">;
|
|
232
336
|
|
|
337
|
+
declare type CLOUD_SOCKET_MSG = TTS | MIC | ASR | AGENT | OLD_ASR | OLD_AGENT | RATINGS | QUESTIONNAIRE | LAYOUT | AUDIO;
|
|
338
|
+
|
|
233
339
|
declare interface InitOptions {
|
|
234
340
|
/**
|
|
235
341
|
* [zh]
|
|
@@ -353,10 +459,37 @@ declare interface InitOptions {
|
|
|
353
459
|
user?: boolean | number;
|
|
354
460
|
aiia?: boolean | number;
|
|
355
461
|
};
|
|
462
|
+
/**
|
|
463
|
+
* [zh]
|
|
464
|
+
* 啟動眼球追蹤
|
|
465
|
+
*
|
|
466
|
+
* [en]
|
|
467
|
+
*
|
|
468
|
+
*/
|
|
469
|
+
eyeTrackEnable?: boolean;
|
|
356
470
|
}
|
|
357
471
|
|
|
358
472
|
export declare function initSdk(options?: BrowserInitOptions): AiiaSdk;
|
|
359
473
|
|
|
474
|
+
declare interface LAYOUT {
|
|
475
|
+
signal: "layout";
|
|
476
|
+
content: {
|
|
477
|
+
type: "mount";
|
|
478
|
+
id: LayoutID;
|
|
479
|
+
panel: string;
|
|
480
|
+
props?: Record<string, unknown>;
|
|
481
|
+
zIndex?: number;
|
|
482
|
+
} | {
|
|
483
|
+
type: "update";
|
|
484
|
+
id: LayoutID;
|
|
485
|
+
props?: Record<string, unknown>;
|
|
486
|
+
zIndex?: number;
|
|
487
|
+
} | {
|
|
488
|
+
type: "unmount";
|
|
489
|
+
id: LayoutID;
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
|
|
360
493
|
declare type LayoutID = string | number;
|
|
361
494
|
|
|
362
495
|
declare type LoggerLevel = "info" | "error" | "warn" | "debug" | "fatal" | "code";
|
|
@@ -374,7 +507,11 @@ declare class MediaManager {
|
|
|
374
507
|
private detectionsSub;
|
|
375
508
|
get sampleRate(): number;
|
|
376
509
|
get pcm(): Observable<Float32Array<ArrayBufferLike>>;
|
|
377
|
-
get detections(): Observable<
|
|
510
|
+
get detections(): Observable< {
|
|
511
|
+
detections: Detection[];
|
|
512
|
+
clientWidth: number;
|
|
513
|
+
clientHeight: number;
|
|
514
|
+
}>;
|
|
378
515
|
get state(): MediaStateEnum;
|
|
379
516
|
set state(v: MediaStateEnum);
|
|
380
517
|
get stateObs(): Observable<MediaStateEnum>;
|
|
@@ -411,6 +548,122 @@ declare enum MediaStateEnum {
|
|
|
411
548
|
allowed = 3
|
|
412
549
|
}
|
|
413
550
|
|
|
551
|
+
declare interface MIC {
|
|
552
|
+
signal: "mic";
|
|
553
|
+
content: {
|
|
554
|
+
status: "on" | "off" | "wait" | "waitting";
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/** @deprecated */
|
|
559
|
+
declare interface OLD_AGENT {
|
|
560
|
+
signal: "response";
|
|
561
|
+
content: OLD_AGENT_content_1 | OLD_AGENT_content_2;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
declare interface OLD_AGENT_content_1 {
|
|
565
|
+
id: string;
|
|
566
|
+
type: undefined;
|
|
567
|
+
scenario: "tutorial" | undefined;
|
|
568
|
+
state: string;
|
|
569
|
+
auto_continue: number;
|
|
570
|
+
chat: number;
|
|
571
|
+
res: string;
|
|
572
|
+
fe_pre_msg: null;
|
|
573
|
+
photo?: string;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
declare interface OLD_AGENT_content_2 {
|
|
577
|
+
type: "nlu" | "scenario";
|
|
578
|
+
scenario: string;
|
|
579
|
+
state: string;
|
|
580
|
+
res: string[];
|
|
581
|
+
photo?: string;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/** @deprecated */
|
|
585
|
+
declare interface OLD_ASR {
|
|
586
|
+
signal: "transcribe";
|
|
587
|
+
content: {
|
|
588
|
+
status: string;
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
declare interface QUESTIONNAIRE {
|
|
593
|
+
signal: "questionnaire";
|
|
594
|
+
content: {
|
|
595
|
+
status: unknown;
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
declare interface RATINGS {
|
|
600
|
+
signal: "rating";
|
|
601
|
+
content: {
|
|
602
|
+
status: string;
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
declare type SendMessage = {
|
|
607
|
+
request: "reset";
|
|
608
|
+
} | {
|
|
609
|
+
request: "skip";
|
|
610
|
+
} | SendMessage_Layout | SendMessage_MiniGame | SendMessage_Audio | SendMessage_Face;
|
|
611
|
+
|
|
612
|
+
declare type SendMessage_Audio = SendMessage_Audio_Init | SendMessage_Audio_PCM;
|
|
613
|
+
|
|
614
|
+
declare interface SendMessage_Audio_Init {
|
|
615
|
+
request: "audio";
|
|
616
|
+
userCtrl?: boolean;
|
|
617
|
+
command: "sampleRate";
|
|
618
|
+
content: number;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
declare interface SendMessage_Audio_PCM {
|
|
622
|
+
request: "audio";
|
|
623
|
+
userCtrl?: boolean;
|
|
624
|
+
command: "pcm";
|
|
625
|
+
content: number[];
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
declare interface SendMessage_Face {
|
|
629
|
+
request: "face_detect";
|
|
630
|
+
content: boolean;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
declare interface SendMessage_Layout {
|
|
634
|
+
request: "layout";
|
|
635
|
+
userCtrl?: boolean;
|
|
636
|
+
content: {
|
|
637
|
+
type: "duplicate_id" | "miss_panel_name" | "id_not_find" | "props_error";
|
|
638
|
+
} & Record<string, string | string[]>;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
declare interface SendMessage_MiniGame {
|
|
642
|
+
request: "minigame";
|
|
643
|
+
userCtrl?: boolean;
|
|
644
|
+
content: {
|
|
645
|
+
type: "start" | "open" | "next" | "answer" | "rank";
|
|
646
|
+
quizId?: string;
|
|
647
|
+
ansId?: string;
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
declare interface SendMessage_Origin {
|
|
652
|
+
request: string;
|
|
653
|
+
userCtrl?: boolean;
|
|
654
|
+
command?: string;
|
|
655
|
+
content?: any;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
declare type Signal = CLOUD_SOCKET_MSG["signal"];
|
|
659
|
+
|
|
660
|
+
declare interface TTS {
|
|
661
|
+
signal: "tts";
|
|
662
|
+
content: {
|
|
663
|
+
status: "start" | "next" | "end";
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
|
|
414
667
|
declare type Webserver = Server<any, any> | Server_2<any, any> | Http2SecureServer<any, any, any, any> | Http2Server<any, any, any, any>;
|
|
415
668
|
|
|
416
669
|
export { }
|
package/dist/browser.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{assign as e,forEach as t,filter as i,compact as s,map as a,sortBy as o,get as n,find as r,isArray as c,values as u}from"lodash-es";import h from"moment";import{Subject as d,takeUntil as l,fromEvent as p,take as b,ReplaySubject as m,BehaviorSubject as g,debounceTime as f,map as S}from"rxjs";import{FilesetResolver as y,FaceDetector as C}from"@mediapipe/tasks-vision";import{io as w}from"socket.io-client";var _;!function(e){e["網絡錯誤"]="ERROR CODE: 500",e["環境錯誤(browser)"]="ERROR CODE: 1001",e["Worklet模組載入失敗"]="ERROR CODE: 1002",e["未獲得媒體裝置權限"]="ERROR CODE: 1003",e["實例已摧毀"]="ERROR CODE: 1004",e["環境錯誤(nodejs)"]="ERROR CODE: 2001",e["未提供憑證"]="ERROR CODE: 2002",e["獲取權杖失敗"]="ERROR CODE: 2003",e["沒有可用專案"]="ERROR CODE: 2004",e["重複初始化"]="ERROR CODE: 2005"}(_||(_={}));const v="undefined"!=typeof window;"undefined"!=typeof process&&null!=process.versions&&process.versions.node;class x{config;get webserver(){return this.config.webserver}get environment(){return this.config.env}get license(){return this.config.license??""}get port(){return function(e,t){const i=t??NaN;if(e){const t=parseInt(e);return isNaN(t)?i:t}return i}(process.env.PORT,this.config.port??3e3)}get ws_url(){return this.config.ws_url??""}get worklet_url(){return this.config.worklet_url??""}get project(){const{project:t}=e({},this.config);return void 0===t?{specific:!1}:"string"==typeof t?{name:t,id:t,specific:!1}:e({},t,{specific:!0})}get endPoint(){return this.environment,{api:"https://aiia-content-management-dev-21193779403.asia-east1.run.app",socket:"wss://graphen-agentic-workflow-dev-21193779403.asia-east1.run.app"}}get debug(){return this.config.debug??!0}get mediaStream(){return this.config.mediaStream}get chunkTimeInSeconds(){return"number"==typeof this.config.chunkTimeInSeconds&&this.config.chunkTimeInSeconds>0?this.config.chunkTimeInSeconds:.3}get llmSampleRate(){return"number"==typeof this.config.llmSampleRate&&this.config.llmSampleRate>0?this.config.llmSampleRate:16e3}get faceDetection(){return e({perSecond:3,confidence:80},this.config.faceDetection)}get autoClearSubtitle(){const{user:t,aiia:i}=e({},this.config.autoClearSubtitle);let s=5e3,a=5e3;return"number"==typeof t?s=t>=0?t:s:!1===t&&(s=NaN),"number"==typeof i?a=i>=0?i:a:!1===i&&(a=NaN),{userDelayTime:s,aiiaDelayTime:a}}constructor(e){this.config=e}}var E;!function(e){e["通道、雲端服務、麥克風都已就緒"]="CODE: 1000",e["未取得媒體裝置權限,請重新設定或忽略此訊息"]="CODE: 1001",e["請訂閱專案列表"]="CODE: 1002",e["初始化必要依賴"]="CODE: 1010",e["指定依賴已完成"]="CODE: 1011",e["啟動SDK"]="CODE: 1012",e["結束SDK"]="CODE: 1013",e["安全的關閉連線"]="CODE: 2000",e["無副作用的關閉連線"]="CODE: 2001",e["與雲端的服務中斷"]="CODE: 2002",e["沒有授權,請聯繫Graphen"]="CODE: 2003",e["自動重新連線連端服務"]="CODE: 2004",e["未預期的斷線,請聯繫Graphen"]="CODE: 2005",e["開始初始化必要模組"]="CODE: 2010",e["指定模組初始化完成"]="CODE: 2011",e["啟動服務"]="CODE: 2012",e["服務結束"]="CODE: 2013"}(E||(E={}));const R={code:console.log,debug:console.log,info:console.log,warn:console.warn,error:console.error,fatal:console.error},D=[];const O=new Proxy(R,{get(e,i,s){if("string"==typeof i)switch(i){case"debug":case"info":case"error":case"warn":case"fatal":case"code":return(...s)=>{const a=h().format("yyyy-MM-DD[T]HH:mm:ss");t(D,e=>{e.next(i,a,...s)}),e[i](`[Aiia::${i}_${a}_]`,...s)};default:return}},set:(e,t,i,s)=>!0});var k,N;function M(e,t,i){return Math.max(i,Math.min(e,t))}function T(e){const t=new DataView(e.buffer),i=[];for(let s=0;s<e.length;s++){const e=t.getInt16(2*s,!0)/32768;i.push(e)}return new Float32Array(i)}function j(e){const t=new DataView(e.buffer),i=[];for(let s=0;s<e.length;s++){const e=M(32768*t.getFloat32(4*s,!0),32767,-32768);i.push(e)}return i}!function(e){e[e.unknow=0]="unknow",e[e.allowed=1]="allowed",e[e.rejected=2]="rejected"}(k||(k={}));class A{audioContext;type="audio";currentNode;bufferQueue;gainNode;set volume(e){e<0&&(e=0),e>100&&(e=100),this.gainNode.gain.value=e/100}get volume(){return Math.round(100*this.gainNode.gain.value)}constructor(e){this.audioContext=e,this.bufferQueue=[],this.currentNode=null,this.gainNode=this.audioContext.createGain(),this.gainNode.connect(this.audioContext.destination)}addBuffer(e){this.bufferQueue.push(e)}addBufferByFloat32(e,t=1){const i=e.length,s=this.audioContext.sampleRate,a=this.audioContext.createBuffer(t,i,s),o=e.slice();for(let e=0;e<t;e++)a.copyToChannel(o,e);this.addBuffer(a)}addBufferByInt16(e,t=1){this.addBufferByFloat32(T(e),t)}startSpeech(){null===this.currentNode&&this.continue()}pauseSpeech(){this.audioContext.suspend().catch(e=>{O.error("pause speech fail",e)})}resumeSpeech(){this.audioContext.resume().catch(e=>{O.error("resume speech fail",e)})}nextSpeech(){this.bufferQueue.length>0&&(this.clearNode(),this.continue())}stopSpeech(){this.bufferQueue=[],this.clearNode()}clearNode(){this.currentNode&&(this.currentNode.onended=function(){},this.currentNode.stop(),this.currentNode.disconnect(),this.currentNode=null)}continue(){const e=this.bufferQueue.shift();if(e){this.currentNode=this.audioContext.createBufferSource(),this.currentNode.buffer=e,this.currentNode.connect(this.gainNode);const t=this.continue.bind(this);this.currentNode.onended=t,this.currentNode.start()}else this.clearNode()}}class I{stream;audioContext;type="vad";workletNode;source;isRecording=!1;outputSampleRate;chunkTimeInSeconds;pcmSub;get pcm(){return this.pcmSub.asObservable()}constructor(e,t,i){this.stream=e,this.audioContext=t,this.outputSampleRate=i?.llmSampleRate??16e3,this.chunkTimeInSeconds=i?.chunkTimeInSeconds??1,this.pcmSub=new d}async startRecord(){this.isRecording||(this.source=this.audioContext.createMediaStreamSource(this.stream),this.workletNode=new AudioWorkletNode(this.audioContext,"aiia-vad",{processorOptions:{outputSampleRate:this.outputSampleRate,chunkTimeInSeconds:this.chunkTimeInSeconds}}),this.source.connect(this.workletNode),this.workletNode.port.onmessage=e=>{const{float32:t}=e.data;t&&this.pcmSub.next(new Float32Array(t))},this.isRecording=!0)}stopRecord(){this.isRecording&&(this.workletNode&&(this.workletNode.port.onmessage=null,this.workletNode.disconnect()),this.source&&this.source.disconnect(),this.isRecording=!1)}}class F{type="camera";aiiaCamera;get detections(){return this.aiiaCamera.detections}constructor(t){const{perSecond:i}=e({perSecond:3},t);this.aiiaCamera=new B,this.aiiaCamera.setFrequency(i),document.body.append(this.aiiaCamera)}async init(e){try{const t=await y.forVisionTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.0/wasm"),i=await C.createFromOptions(t,{baseOptions:{modelAssetPath:"https://storage.googleapis.com/mediapipe-models/face_detector/blaze_face_short_range/float16/1/blaze_face_short_range.tflite",delegate:"GPU"},runningMode:"VIDEO"});this.aiiaCamera.setStream(e),this.aiiaCamera.setFaceDetector(i)}catch(e){O.error("Camera init fail",e)}}startCapture(){this.aiiaCamera.startCapture()}stopCapture(){this.aiiaCamera.stopCapture()}onDestroy(){this.aiiaCamera.remove()}}class B extends HTMLElement{static get observedAttributes(){return["debug"]}_shadow;_containerEl;_styleEl;_videoEl;_isDebug;_debugElements;_interval;_lastTimestamp;_loopFrameID;_faceDetector;_detectionsSub;_isReady;get detections(){return this._detectionsSub.asObservable()}constructor(){super(),this._isDebug=!1,this._isReady=!1,this._shadow=this.attachShadow({mode:"open"}),this._containerEl=document.createElement("div"),this._videoEl=document.createElement("video"),this._styleEl=document.createElement("style"),this._debugElements=[],this._loopFrameID=null,this._detectionsSub=new d,this._interval=Math.ceil(1e3/3),this._lastTimestamp=0,this.predictWebcam=this.predictWebcam.bind(this),this._settingContainer(),this._settingStyle(),this._settingVideo(),this._containerEl.appendChild(this._videoEl),this._shadow.appendChild(this._styleEl),this._shadow.appendChild(this._containerEl)}connectedCallback(){this.startCapture()}disconnectedCallback(){this.stopCapture()}attributeChangedCallback(e,t,i){"debug"===e&&(this._isDebug=null!==i&&("true"===i||""===i),this._containerEl.style.visibility=this._isDebug?"visible":"hidden")}setStream(e){this._videoEl.onloadedmetadata=()=>{this._isReady=!0},this._videoEl.srcObject=e}setFaceDetector(e){this._faceDetector=e}setFrequency(e){this._interval=Math.ceil(1e3/e)}_settingStyle(){this._styleEl.textContent="\n .aiia_container {\n visibility: hidden;\n position: fixed;\n top: 0;\n left: 0;\n }\n .aiia_container .highlighter {\n background: rgba(0, 255, 0, 0.25);\n border: 1px dashed #fff;\n z-index: 1;\n position: absolute;\n }\n .aiia_container .confidence {\n position: absolute;\n padding-bottom: 5px;\n padding-top: 5px;\n background-color: #007f8b;\n color: #fff;\n border: 1px dashed rgba(255, 255, 255, 0.7);\n z-index: 2;\n font-size: 12px;\n margin: 0;\n }\n "}_settingContainer(){this._containerEl.classList.add("aiia_container")}_settingVideo(){this._videoEl.autoplay=!0,this._videoEl.playsInline=!0,this._videoEl.muted=!0}getVideo(){return this._videoEl}startCapture(){null===this._loopFrameID&&(this._videoEl.play(),this._loopFrameID=window.requestAnimationFrame(this.predictWebcam))}stopCapture(){null!==this._loopFrameID&&(window.cancelAnimationFrame(this._loopFrameID),this._loopFrameID=null),this._videoEl.pause()}async predictWebcam(){if(this._loopFrameID=window.requestAnimationFrame(this.predictWebcam),void 0===this._faceDetector||!this._isReady)return;const e=performance.now();if(this._lastTimestamp+this._interval<=e){this._lastTimestamp=e;const t=this._faceDetector.detectForVideo(this._videoEl,e).detections;this._isDebug&&this._drawRect(t),this._detectionsSub.next(t)}}_drawRect(e){t(e,(e,t)=>{const{categories:i,boundingBox:s}=e;if(s){let e=this._debugElements[2*t],a=this._debugElements[2*t+1];e&&a||(e=document.createElement("div"),e.classList.add("highlighter"),a=document.createElement("p"),a.classList.add("confidence"),this._containerEl.append(a,e),this._debugElements.push(e,a)),e.style.display="block",a.style.display="block";const o=100*i[0].score;a.innerText=`Confidence: ${Math.round(o)} %`,a.style.right=this._videoEl.offsetWidth-s.width-s.originX+"px",a.style.top=s.originY-30+"px",a.style.width=s.width-10+"px",e.style.right=this._videoEl.offsetWidth-s.width-s.originX+"px",e.style.top=`${s.originY}px`,e.style.width=s.width-10+"px",e.style.height=`${s.height}px`}});for(let t=2*e.length;t<this._debugElements.length;t++)this._debugElements[t].style.display="none"}destroy(){this._detectionsSub.complete(),this.remove()}}customElements.define("aiia-camera",B),function(e){e[e.padding=0]="padding",e[e.rejected=1]="rejected",e[e.loadfail=2]="loadfail",e[e.allowed=3]="allowed"}(N||(N={}));class W{stream;_state;stateSub;audioCtx;audioManager;vadManager;camManager;destory;pcmSub;detectionsSub;get sampleRate(){return this.audioCtx?this.audioCtx.sampleRate:16e3}get pcm(){return this.pcmSub.asObservable()}get detections(){return this.detectionsSub.asObservable()}get state(){return this._state}set state(e){e!==this._state&&(this._state=e,this.stateSub.next(e))}get stateObs(){return this.stateSub.asObservable()}constructor(e){this.stream=e,this.stateSub=new d,this.pcmSub=new d,this.destory=new d,this.detectionsSub=new d,this.state=N.padding}async init(e,t){const i=this.stream??await async function(e){try{return await navigator.mediaDevices.getUserMedia(e)}catch(e){return null}}({audio:{echoCancellation:!0,noiseSuppression:!0},video:!0});if(null===i)throw this.state=N.rejected,new Error(_["未獲得媒體裝置權限"]);this.stream=i,this.audioCtx=new AudioContext;try{await this.audioCtx.audioWorklet.addModule(e)}catch(e){throw O.fatal(e),this.state=N.loadfail,new Error(_["Worklet模組載入失敗"])}this.state=N.allowed,this.audioManager=new A(this.audioCtx),this.vadManager=new I(i,this.audioCtx,t),this.vadManager.pcm.pipe(l(this.destory)).subscribe(e=>{this.pcmSub.next(e)}),this.camManager=new F(t?.faceDetection),this.camManager.detections.pipe(l(this.destory)).subscribe(e=>{this.detectionsSub.next(e)}),this.camManager.init(i)}addAudioQueue(e){const t=n(e,"buffer",void 0),i=n(e,"float32",void 0),s=n(e,"int16",void 0),a=n(e,"numberOfChannels",void 0);t?this.audioManager?.addBuffer(t):i?this.audioManager?.addBufferByFloat32(i,a):s&&this.audioManager?.addBufferByInt16(s,a)}playAudio(){this.audioManager?.startSpeech()}stopAudio(){this.audioManager?.stopSpeech()}startRecord(){this.vadManager?.startRecord()}stopRecord(){this.vadManager?.stopRecord()}setVolume(e){this.audioManager&&(this.audioManager.volume=e)}getVolume(){return this.audioManager?this.audioManager.volume:0}startCapture(){this.camManager?.startCapture()}stopCapture(){this.camManager?.stopCapture()}onDestroy(){this.camManager?.onDestroy(),this.audioCtx?.close(),this.destory.next(),this.destory.complete()}}class P{socket;messageSub;destorySub;get message(){return this.messageSub.asObservable()}constructor(t){this.destorySub=new d,this.messageSub=new d;const{specific:i,id:s}=t.project;this.socket=w(t.ws_url,e({autoConnect:!1},i&&void 0!==s?{query:{uuid:s}}:{}))}start(){const e="list",t="cloud",i="channel";p(this.socket,"connect").pipe(l(this.destorySub)).subscribe(()=>{O.debug("Client ID: ",this.socket.id)}),p(this.socket,e).pipe(b(1),l(this.destorySub)).subscribe(t=>{this.messageSub.next({event:e,data:t})}),p(this.socket,t).pipe(l(this.destorySub)).subscribe(e=>{this.messageSub.next({event:t,data:e})}),p(this.socket,i).pipe(l(this.destorySub)).subscribe(e=>{this.messageSub.next({event:i,data:e})}),this.socket.connect()}send(e,t){this.socket.emit(e,t)}sendToCloud(e){this.send("cloud",JSON.stringify(e))}onDestroy(){this.destorySub.next(),this.destorySub.complete(),this.messageSub.complete(),this.socket.disconnect()}}class V{config;media;chat;destorySub;projectsSub;layoutSub;aiiaSubtitleSub;userSubtitleSub;sampleRateOfWhisper;channelState;stateSub;_currentState;isMuteAiia;aiiaSubtitleClearSub;userSubtitleClearSub;_lastProjects;get state(){return this.stateSub.asObservable()}get currentState(){return this._currentState}get layout(){return this.layoutSub.asObservable()}get projects(){return this.projectsSub.asObservable()}get lastProjects(){return a(this._lastProjects,e=>({...e}))}get aiiaSubtitle(){return this.aiiaSubtitleSub.asObservable()}get userSubtitle(){return this.userSubtitleSub.asObservable()}set volume(e){this.media.setVolume(e)}get volume(){return this.media.getVolume()}constructor(e,t){this.config=e,this.media=t,this.layoutSub=new d,this.projectsSub=new m(1),this.destorySub=new d,this.aiiaSubtitleSub=new d,this.userSubtitleSub=new d,this.aiiaSubtitleClearSub=new d,this.userSubtitleClearSub=new d,this.stateSub=new g("NotStart"),this.sampleRateOfWhisper={input:e.llmSampleRate,output:16e3},this.channelState={proxy:!1,cloud:!1},this.isMuteAiia=!1,this._lastProjects=[],this.chat=new P(e),O.code(E["指定依賴已完成"],"chat"),this.close=this.onDestroy,this.behavior=this.behavior.bind(this),this.cloudToObj=this.cloudToObj.bind(this);const{userDelayTime:i,aiiaDelayTime:s}=e.autoClearSubtitle;isNaN(s)||this.aiiaSubtitleClearSub.pipe(f(s),l(this.destorySub)).subscribe(()=>{this.aiiaSubtitleSub.next("")}),isNaN(i)||this.userSubtitleClearSub.pipe(f(i),l(this.destorySub)).subscribe(()=>{this.userSubtitleSub.next("")}),this.stateSub.pipe(l(this.destorySub)).subscribe(e=>{this._currentState=e}),this.projectsSub.pipe(l(this.destorySub)).subscribe(e=>{this._lastProjects=e})}start(){this.media.stateObs.pipe(l(this.destorySub)).subscribe(()=>{this.channelCheck()}),this.chat.message.pipe(l(this.destorySub)).subscribe(({event:e,data:t})=>{switch(e){case"cloud":this.cloudToObj(t);break;case"list":{const{id:e,name:i,specific:s}=this.config.project;let a=null;if(s&&void 0!==e)a=e;else{const s=r(t,t=>t.name===i||t.id===e);s&&(a=s.id)}null!==a?this.chooseProject(a):(this.projectsSub.next(t),this.stateSub.next("WattingProjectID"),O.code(E["請訂閱專案列表"]));break}case"channel":switch(t){case"open":this.channelState.proxy=!0,this.channelCheck();break;case"close":this.channelState.proxy=!1,this.media.stopRecord(),this.media.stopCapture(),this.stateSub.next("CloseService");break;case"no_permissions":this.channelState.proxy=!1,this.media.stopRecord(),this.media.stopCapture(),this.stateSub.next("NoPermissions");break;case"reconnect":this.channelState.proxy=!1,this.media.stopRecord(),this.media.stopCapture(),this.stateSub.next("ReconnectingCloud")}}}),this.chat.start(),this.stateSub.next("ConnectingCloud"),O.code(E["啟動SDK"])}close;resetSession(){this.chat.sendToCloud({request:"reset"}),this.media.stopAudio(),this.userSubtitleSub.next(""),this.aiiaSubtitleSub.next(""),this.layoutSub.next({type:"resetLayout"})}skip(){this.chat.sendToCloud({request:"skip"}),this.media.stopAudio(),this.userSubtitleSub.next(""),this.aiiaSubtitleSub.next("")}chooseProject(e){this.chat.send("uuid",e),this.stateSub.next("ConnectingCloud")}mute(){this.isMuteAiia=!0,this.media.stopAudio(),this.media.stopRecord()}unmute(){this.isMuteAiia=!1,this.media.startRecord()}cloudToObj(e){try{const t=JSON.parse(e);void 0!==n(t,"signal")?this.behavior(t):c(t)?a(t,this.behavior):a(u(t),this.behavior)}catch(e){O.error("message transfer fail",e)}}behavior(e){switch(e.signal){case"layout":this.layoutSub.next(e.content);break;case"audio":if("sampleRate"===e.command)this.sampleRateOfWhisper.output=e.content;else switch(e.command){case"pcm":if(!this.isMuteAiia){const t=function(e,t,i){if(t===i)return e;const s=i/t,a=Math.ceil(e.length*s),o=new Float32Array(a);for(let t=0;t<a;t++){const i=t/s,a=Math.floor(i),n=i-a,r=e[a],c=e[Math.min(a+1,e.length-1)];o[t]=r+(c-r)*n}return o}(T(new Int16Array(e.content)),this.sampleRateOfWhisper.output,this.media.sampleRate);this.media.addAudioQueue({float32:t}),this.media.playAudio()}break;case"interrupted":this.media.stopAudio(),this.aiiaSubtitleSub.next("")}break;case"status":"Connected"===n(e,"content")&&(this.channelState.cloud=!0,this.channelCheck(),this.layoutSub.next({type:"resetLayout"}));break;case"agent":if(!this.isMuteAiia){const t=n(e,"content.function_result.response");void 0!==t&&(this.aiiaSubtitleSub.next(t),this.aiiaSubtitleClearSub.next())}break;case"asr":if(!this.isMuteAiia&&"ASR"===n(e,"content.function_type")){const t=n(e,"content.function_result.result");void 0!==t&&(this.userSubtitleSub.next(t),this.userSubtitleClearSub.next())}break;default:O.debug(e.signal)}}channelCheck(){const{proxy:e,cloud:t}=this.channelState;if(e&&t&&this.media.state===N.allowed){this.chat.sendToCloud({request:"audio",command:"sampleRate",content:this.sampleRateOfWhisper.input}),this.media.pcm.pipe(l(this.destorySub)).subscribe(e=>{this.chat.sendToCloud({request:"audio",command:"pcm",content:j(e)})});const e=(n=this.config.faceDetection.confidence,function(e){const t=i(e,e=>100*(e.categories[0]?.score??0)>=n),r=s(a(t,e=>{if(void 0!==e.boundingBox){const t=e.boundingBox,i=t.width*t.height,s=e.categories[0]?.score??0;return{...t,area:i,score:100*s}}return null}));return o(r,["area","confidenceScore"])[0]??null});this.media.detections.pipe(l(this.destorySub),S(e)).subscribe(e=>{this.chat.sendToCloud({request:"face_detect",content:null!==e})}),this.media.startRecord(),this.media.startCapture(),this.stateSub.next("InService"),O.code(E["通道、雲端服務、麥克風都已就緒"])}else e&&t&&this.media.state!==N.allowed&&(this.stateSub.next("InServiceNoMedia"),O.code(E["未取得媒體裝置權限,請重新設定或忽略此訊息"]));var n}onDestroy(){this.chat.onDestroy(),this.media.onDestroy(),this.destorySub.next(),this.destorySub.complete(),this.stateSub.next("Destroy"),this.stateSub.complete(),O.code(E["結束SDK"])}}function q(t){if(v){!function(e){const{info:t,error:i,warn:s,debug:a,fatal:o,code:n}=function(e){if(void 0===e||"all"===e)return{code:!0,error:!0,warn:!0,info:!0,debug:!0,fatal:!0};if("none"===e)return{error:!1,code:!1,warn:!1,info:!1,debug:!1,fatal:!1};if("boolean"==typeof e)return{code:e,error:e,warn:e,info:e,debug:e,fatal:e};{const t=new Set(e);return{code:t.has("code"),debug:t.has("debug"),fatal:t.has("fatal"),error:t.has("error"),warn:t.has("warn"),info:t.has("info")}}}(e);n||(R.code=()=>{}),a||(R.debug=()=>{}),t||(R.info=()=>{}),s||(R.warn=()=>{}),i||(R.error=()=>{}),o||(R.fatal=()=>{})}(n(t,"debug",!0)),O.code(E["初始化必要依賴"]);const i=new x(e({},t));O.code(E["指定依賴已完成"],"config");const s=new W(i.mediaStream);O.code(E["指定依賴已完成"],"config");const a=new V(i,s);return O.code(E["指定依賴已完成"],"sdk"),""!==i.worklet_url&&s.init(i.worklet_url,i),a}throw new Error(_["環境錯誤(browser)"])}export{q as initSdk};
|
|
1
|
+
import{assign as e,forEach as t,filter as i,compact as s,map as a,sortBy as o,get as n,find as r,isArray as c,values as u}from"lodash-es";import h from"moment";import"mathjs";import{Subject as d,takeUntil as l,fromEvent as p,take as b,ReplaySubject as m,BehaviorSubject as g,debounceTime as f,map as S}from"rxjs";import{FilesetResolver as y,FaceDetector as w}from"@mediapipe/tasks-vision";import{io as C}from"socket.io-client";var _;!function(e){e["網絡錯誤"]="ERROR CODE: 500",e["環境錯誤(browser)"]="ERROR CODE: 1001",e["Worklet模組載入失敗"]="ERROR CODE: 1002",e["未獲得媒體裝置權限"]="ERROR CODE: 1003",e["實例已摧毀"]="ERROR CODE: 1004",e["環境錯誤(nodejs)"]="ERROR CODE: 2001",e["未提供憑證"]="ERROR CODE: 2002",e["獲取權杖失敗"]="ERROR CODE: 2003",e["沒有可用專案"]="ERROR CODE: 2004",e["重複初始化"]="ERROR CODE: 2005"}(_||(_={}));const v="undefined"!=typeof window;"undefined"!=typeof process&&null!=process.versions&&process.versions.node;class x{config;get webserver(){return this.config.webserver}get environment(){return this.config.env}get license(){return this.config.license??""}get port(){return function(e,t){const i=t??NaN;if(e){const t=parseInt(e);return isNaN(t)?i:t}return i}(process.env.PORT,this.config.port??3e3)}get ws_url(){return this.config.ws_url??""}get worklet_url(){return this.config.worklet_url??""}get project(){const{project:t}=e({},this.config);return void 0===t?{specific:!1}:"string"==typeof t?{name:t,id:t,specific:!1}:e({},t,{specific:!0})}get endPoint(){return this.environment,{api:"https://aiia-content-management-dev-21193779403.asia-east1.run.app",socket:"wss://graphen-agentic-workflow-dev-21193779403.asia-east1.run.app"}}get debug(){return this.config.debug??!0}get mediaStream(){return this.config.mediaStream}get chunkTimeInSeconds(){return"number"==typeof this.config.chunkTimeInSeconds&&this.config.chunkTimeInSeconds>0?this.config.chunkTimeInSeconds:.3}get llmSampleRate(){return"number"==typeof this.config.llmSampleRate&&this.config.llmSampleRate>0?this.config.llmSampleRate:16e3}get faceDetection(){return e({perSecond:3,confidence:80},this.config.faceDetection)}get autoClearSubtitle(){const{user:t,aiia:i}=e({},this.config.autoClearSubtitle);let s=5e3,a=5e3;return"number"==typeof t?s=t>=0?t:s:!1===t&&(s=NaN),"number"==typeof i?a=i>=0?i:a:!1===i&&(a=NaN),{userDelayTime:s,aiiaDelayTime:a}}get eyeTrackEnable(){return this.config.eyeTrackEnable??!1}constructor(e){this.config=e}}var E;!function(e){e["通道、雲端服務、麥克風都已就緒"]="CODE: 1000",e["未取得媒體裝置權限,請重新設定或忽略此訊息"]="CODE: 1001",e["請訂閱專案列表"]="CODE: 1002",e["初始化必要依賴"]="CODE: 1010",e["指定依賴已完成"]="CODE: 1011",e["啟動SDK"]="CODE: 1012",e["結束SDK"]="CODE: 1013",e["安全的關閉連線"]="CODE: 2000",e["無副作用的關閉連線"]="CODE: 2001",e["與雲端的服務中斷"]="CODE: 2002",e["沒有授權,請聯繫Graphen"]="CODE: 2003",e["自動重新連線連端服務"]="CODE: 2004",e["未預期的斷線,請聯繫Graphen"]="CODE: 2005",e["開始初始化必要模組"]="CODE: 2010",e["指定模組初始化完成"]="CODE: 2011",e["啟動服務"]="CODE: 2012",e["服務結束"]="CODE: 2013"}(E||(E={}));const R={code:console.log,debug:console.log,info:console.log,warn:console.warn,error:console.error,fatal:console.error},D=[];const k=new Proxy(R,{get(e,i,s){if("string"==typeof i)switch(i){case"debug":case"info":case"error":case"warn":case"fatal":case"code":return(...s)=>{const a=h().format("yyyy-MM-DD[T]HH:mm:ss");t(D,e=>{e.next(i,a,...s)}),e[i](`[Aiia::${i}_${a}_]`,...s)};default:return}},set:(e,t,i,s)=>!0});var O,N;function M(e,t,i){return Math.max(i,Math.min(e,t))}function T(e){const t=new DataView(e.buffer),i=[];for(let s=0;s<e.length;s++){const e=t.getInt16(2*s,!0)/32768;i.push(e)}return new Float32Array(i)}function j(e){const t=new DataView(e.buffer),i=[];for(let s=0;s<e.length;s++){const e=M(32768*t.getFloat32(4*s,!0),32767,-32768);i.push(e)}return i}!function(e){e[e.unknow=0]="unknow",e[e.allowed=1]="allowed",e[e.rejected=2]="rejected"}(O||(O={}));class I{audioContext;type="audio";currentNode;bufferQueue;gainNode;set volume(e){e<0&&(e=0),e>100&&(e=100),this.gainNode.gain.value=e/100}get volume(){return Math.round(100*this.gainNode.gain.value)}constructor(e){this.audioContext=e,this.bufferQueue=[],this.currentNode=null,this.gainNode=this.audioContext.createGain(),this.gainNode.connect(this.audioContext.destination)}addBuffer(e){this.bufferQueue.push(e)}addBufferByFloat32(e,t=1){const i=e.length,s=this.audioContext.sampleRate,a=this.audioContext.createBuffer(t,i,s),o=e.slice();for(let e=0;e<t;e++)a.copyToChannel(o,e);this.addBuffer(a)}addBufferByInt16(e,t=1){this.addBufferByFloat32(T(e),t)}startSpeech(){null===this.currentNode&&this.continue()}pauseSpeech(){this.audioContext.suspend().catch(e=>{k.error("pause speech fail",e)})}resumeSpeech(){this.audioContext.resume().catch(e=>{k.error("resume speech fail",e)})}nextSpeech(){this.bufferQueue.length>0&&(this.clearNode(),this.continue())}stopSpeech(){this.bufferQueue=[],this.clearNode()}clearNode(){this.currentNode&&(this.currentNode.onended=function(){},this.currentNode.stop(),this.currentNode.disconnect(),this.currentNode=null)}continue(){const e=this.bufferQueue.shift();if(e){this.currentNode=this.audioContext.createBufferSource(),this.currentNode.buffer=e,this.currentNode.connect(this.gainNode);const t=this.continue.bind(this);this.currentNode.onended=t,this.currentNode.start()}else this.clearNode()}}class A{stream;audioContext;type="vad";workletNode;source;isRecording=!1;outputSampleRate;chunkTimeInSeconds;pcmSub;get pcm(){return this.pcmSub.asObservable()}constructor(e,t,i){this.stream=e,this.audioContext=t,this.outputSampleRate=i?.llmSampleRate??16e3,this.chunkTimeInSeconds=i?.chunkTimeInSeconds??1,this.pcmSub=new d}async startRecord(){this.isRecording||(this.source=this.audioContext.createMediaStreamSource(this.stream),this.workletNode=new AudioWorkletNode(this.audioContext,"aiia-vad",{processorOptions:{outputSampleRate:this.outputSampleRate,chunkTimeInSeconds:this.chunkTimeInSeconds}}),this.source.connect(this.workletNode),this.workletNode.port.onmessage=e=>{const{float32:t}=e.data;t&&this.pcmSub.next(new Float32Array(t))},this.isRecording=!0)}stopRecord(){this.isRecording&&(this.workletNode&&(this.workletNode.port.onmessage=null,this.workletNode.disconnect()),this.source&&this.source.disconnect(),this.isRecording=!1)}}class F{type="camera";aiiaCamera;get detections(){return this.aiiaCamera.detections}get videoSize(){return this.aiiaCamera.videoSize}constructor(t){const{perSecond:i}=e({perSecond:3},t);this.aiiaCamera=new W,this.aiiaCamera.setFrequency(i),document.body.append(this.aiiaCamera)}async init(e){try{const t=await y.forVisionTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.0/wasm"),i=await w.createFromOptions(t,{baseOptions:{modelAssetPath:"https://storage.googleapis.com/mediapipe-models/face_detector/blaze_face_short_range/float16/1/blaze_face_short_range.tflite",delegate:"GPU"},runningMode:"VIDEO"});this.aiiaCamera.setStream(e),this.aiiaCamera.setFaceDetector(i)}catch(e){k.error("Camera init fail",e)}}startCapture(){this.aiiaCamera.startCapture()}stopCapture(){this.aiiaCamera.stopCapture()}onDestroy(){this.aiiaCamera.remove()}}class W extends HTMLElement{static get observedAttributes(){return["debug"]}_shadow;_containerEl;_styleEl;_videoEl;_isDebug;_debugElements;_interval;_lastTimestamp;_loopFrameID;_faceDetector;_detectionsSub;_isReady;get detections(){return this._detectionsSub.asObservable()}get videoSize(){return{width:this._videoEl.videoWidth,height:this._videoEl.videoHeight}}constructor(){super(),this._isDebug=!1,this._isReady=!1,this._shadow=this.attachShadow({mode:"open"}),this._containerEl=document.createElement("div"),this._videoEl=document.createElement("video"),this._styleEl=document.createElement("style"),this._debugElements=[],this._loopFrameID=null,this._detectionsSub=new d,this._interval=Math.ceil(1e3/3),this._lastTimestamp=0,this.predictWebcam=this.predictWebcam.bind(this),this._settingContainer(),this._settingStyle(),this._settingVideo(),this._containerEl.appendChild(this._videoEl),this._shadow.appendChild(this._styleEl),this._shadow.appendChild(this._containerEl)}connectedCallback(){this.startCapture()}disconnectedCallback(){this.stopCapture()}attributeChangedCallback(e,t,i){"debug"===e&&(this._isDebug=null!==i&&("true"===i||""===i),this._containerEl.style.visibility=this._isDebug?"visible":"hidden")}setStream(e){this._videoEl.onloadedmetadata=()=>{this._isReady=!0},this._videoEl.srcObject=e}setFaceDetector(e){this._faceDetector=e}setFrequency(e){this._interval=Math.ceil(1e3/e)}_settingStyle(){this._styleEl.textContent="\n .aiia_container {\n visibility: hidden;\n position: fixed;\n top: 0;\n left: 0;\n }\n .aiia_container .highlighter {\n background: rgba(0, 255, 0, 0.25);\n border: 1px dashed #fff;\n z-index: 1;\n position: absolute;\n }\n .aiia_container .confidence {\n position: absolute;\n padding-bottom: 5px;\n padding-top: 5px;\n background-color: #007f8b;\n color: #fff;\n border: 1px dashed rgba(255, 255, 255, 0.7);\n z-index: 2;\n font-size: 12px;\n margin: 0;\n }\n "}_settingContainer(){this._containerEl.classList.add("aiia_container")}_settingVideo(){this._videoEl.autoplay=!0,this._videoEl.playsInline=!0,this._videoEl.muted=!0}getVideo(){return this._videoEl}startCapture(){null===this._loopFrameID&&(this._videoEl.play(),this._loopFrameID=window.requestAnimationFrame(this.predictWebcam))}stopCapture(){null!==this._loopFrameID&&(window.cancelAnimationFrame(this._loopFrameID),this._loopFrameID=null),this._videoEl.pause()}async predictWebcam(){if(this._loopFrameID=window.requestAnimationFrame(this.predictWebcam),void 0===this._faceDetector||!this._isReady)return;const e=performance.now();if(this._lastTimestamp+this._interval<=e){this._lastTimestamp=e;const t=this._faceDetector.detectForVideo(this._videoEl,e).detections;this._isDebug&&this._drawRect(t),this._detectionsSub.next(t)}}_drawRect(e){t(e,(e,t)=>{const{categories:i,boundingBox:s}=e;if(s){let e=this._debugElements[2*t],a=this._debugElements[2*t+1];e&&a||(e=document.createElement("div"),e.classList.add("highlighter"),a=document.createElement("p"),a.classList.add("confidence"),this._containerEl.append(a,e),this._debugElements.push(e,a)),e.style.display="block",a.style.display="block";const o=100*i[0].score;a.innerText=`Confidence: ${Math.round(o)} %`,a.style.right=this._videoEl.offsetWidth-s.width-s.originX+"px",a.style.top=s.originY-30+"px",a.style.width=s.width-10+"px",e.style.right=this._videoEl.offsetWidth-s.width-s.originX+"px",e.style.top=`${s.originY}px`,e.style.width=s.width-10+"px",e.style.height=`${s.height}px`}});for(let t=2*e.length;t<this._debugElements.length;t++)this._debugElements[t].style.display="none"}destroy(){this._detectionsSub.complete(),this.remove()}}customElements.define("aiia-camera",W),function(e){e[e.padding=0]="padding",e[e.rejected=1]="rejected",e[e.loadfail=2]="loadfail",e[e.allowed=3]="allowed"}(N||(N={}));class B{stream;_state;stateSub;audioCtx;audioManager;vadManager;camManager;destory;pcmSub;detectionsSub;get sampleRate(){return this.audioCtx?this.audioCtx.sampleRate:16e3}get pcm(){return this.pcmSub.asObservable()}get detections(){return this.detectionsSub.asObservable()}get state(){return this._state}set state(e){e!==this._state&&(this._state=e,this.stateSub.next(e))}get stateObs(){return this.stateSub.asObservable()}constructor(e){this.stream=e,this.stateSub=new d,this.pcmSub=new d,this.destory=new d,this.detectionsSub=new d,this.state=N.padding}async init(e,t){const i=this.stream??await async function(e){try{return await navigator.mediaDevices.getUserMedia(e)}catch(e){return null}}({audio:{echoCancellation:!0,noiseSuppression:!0},video:!0});if(null===i)throw this.state=N.rejected,new Error(_["未獲得媒體裝置權限"]);this.stream=i,this.audioCtx=new AudioContext;try{await this.audioCtx.audioWorklet.addModule(e)}catch(e){throw k.fatal(e),this.state=N.loadfail,new Error(_["Worklet模組載入失敗"])}this.state=N.allowed,this.audioManager=new I(this.audioCtx),this.vadManager=new A(i,this.audioCtx,t),this.vadManager.pcm.pipe(l(this.destory)).subscribe(e=>{this.pcmSub.next(e)});const s=new F(t?.faceDetection);s.detections.pipe(l(this.destory)).subscribe(e=>{const{width:t,height:i}=s.videoSize;this.detectionsSub.next({detections:e,clientWidth:t,clientHeight:i})}),s.init(i),this.camManager=s}addAudioQueue(e){const t=n(e,"buffer",void 0),i=n(e,"float32",void 0),s=n(e,"int16",void 0),a=n(e,"numberOfChannels",void 0);t?this.audioManager?.addBuffer(t):i?this.audioManager?.addBufferByFloat32(i,a):s&&this.audioManager?.addBufferByInt16(s,a)}playAudio(){this.audioManager?.startSpeech()}stopAudio(){this.audioManager?.stopSpeech()}startRecord(){this.vadManager?.startRecord()}stopRecord(){this.vadManager?.stopRecord()}setVolume(e){this.audioManager&&(this.audioManager.volume=e)}getVolume(){return this.audioManager?this.audioManager.volume:0}startCapture(){this.camManager?.startCapture()}stopCapture(){this.camManager?.stopCapture()}onDestroy(){this.camManager?.onDestroy(),this.audioCtx?.close(),this.destory.next(),this.destory.complete()}}class P{socket;messageSub;destorySub;get message(){return this.messageSub.asObservable()}constructor(t){this.destorySub=new d,this.messageSub=new d;const{specific:i,id:s}=t.project;this.socket=C(t.ws_url,e({autoConnect:!1},i&&void 0!==s?{query:{uuid:s}}:{}))}start(){const e="list",t="cloud",i="channel";p(this.socket,"connect").pipe(l(this.destorySub)).subscribe(()=>{k.debug("Client ID: ",this.socket.id)}),p(this.socket,e).pipe(b(1),l(this.destorySub)).subscribe(t=>{this.messageSub.next({event:e,data:t})}),p(this.socket,t).pipe(l(this.destorySub)).subscribe(e=>{this.messageSub.next({event:t,data:e})}),p(this.socket,i).pipe(l(this.destorySub)).subscribe(e=>{this.messageSub.next({event:i,data:e})}),this.socket.connect()}send(e,t){this.socket.emit(e,t)}sendToCloud(e){this.send("cloud",JSON.stringify(e))}onDestroy(){this.destorySub.next(),this.destorySub.complete(),this.messageSub.complete(),this.socket.disconnect()}}class V{config;media;chat;destorySub;projectsSub;layoutSub;aiiaSubtitleSub;userSubtitleSub;sampleRateOfWhisper;channelState;stateSub;_currentState;isMuteAiia;aiiaSubtitleClearSub;userSubtitleClearSub;_lastProjects;get state(){return this.stateSub.asObservable()}get currentState(){return this._currentState}get layout(){return this.layoutSub.asObservable()}get projects(){return this.projectsSub.asObservable()}get lastProjects(){return a(this._lastProjects,e=>({...e}))}get aiiaSubtitle(){return this.aiiaSubtitleSub.asObservable()}get userSubtitle(){return this.userSubtitleSub.asObservable()}set volume(e){this.media.setVolume(e)}get volume(){return this.media.getVolume()}constructor(e,t){this.config=e,this.media=t,this.layoutSub=new d,this.projectsSub=new m(1),this.destorySub=new d,this.aiiaSubtitleSub=new d,this.userSubtitleSub=new d,this.aiiaSubtitleClearSub=new d,this.userSubtitleClearSub=new d,this.stateSub=new g("NotStart"),this.sampleRateOfWhisper={input:e.llmSampleRate,output:16e3},this.channelState={proxy:!1,cloud:!1},this.isMuteAiia=!1,this._lastProjects=[],this.chat=new P(e),k.code(E["指定依賴已完成"],"chat"),this.close=this.onDestroy,this.behavior=this.behavior.bind(this),this.cloudToObj=this.cloudToObj.bind(this);const{userDelayTime:i,aiiaDelayTime:s}=e.autoClearSubtitle;isNaN(s)||this.aiiaSubtitleClearSub.pipe(f(s),l(this.destorySub)).subscribe(()=>{this.aiiaSubtitleSub.next("")}),isNaN(i)||this.userSubtitleClearSub.pipe(f(i),l(this.destorySub)).subscribe(()=>{this.userSubtitleSub.next("")}),this.stateSub.pipe(l(this.destorySub)).subscribe(e=>{this._currentState=e}),this.projectsSub.pipe(l(this.destorySub)).subscribe(e=>{this._lastProjects=e})}start(){this.media.stateObs.pipe(l(this.destorySub)).subscribe(()=>{this.channelCheck()}),this.chat.message.pipe(l(this.destorySub)).subscribe(({event:e,data:t})=>{switch(e){case"cloud":this.cloudToObj(t);break;case"list":{const{id:e,name:i,specific:s}=this.config.project;let a=null;if(s&&void 0!==e)a=e;else{const s=r(t,t=>t.name===i||t.id===e);s&&(a=s.id)}null!==a?this.chooseProject(a):(this.projectsSub.next(t),this.stateSub.next("WattingProjectID"),k.code(E["請訂閱專案列表"]));break}case"channel":switch(t){case"open":this.channelState.proxy=!0,this.channelCheck();break;case"close":this.channelState.proxy=!1,this.media.stopRecord(),this.media.stopCapture(),this.stateSub.next("CloseService");break;case"no_permissions":this.channelState.proxy=!1,this.media.stopRecord(),this.media.stopCapture(),this.stateSub.next("NoPermissions");break;case"reconnect":this.channelState.proxy=!1,this.media.stopRecord(),this.media.stopCapture(),this.stateSub.next("ReconnectingCloud")}}}),this.chat.start(),this.stateSub.next("ConnectingCloud"),k.code(E["啟動SDK"])}close;resetSession(){throw new Error("Please use `reset` instead, 請使用`reset`代替")}skip(){this.chat.sendToCloud({request:"skip"})}reset(){this.chat.sendToCloud({request:"reset"})}chooseProject(e){this.chat.send("uuid",e),this.stateSub.next("ConnectingCloud")}mute(){this.isMuteAiia=!0,this.media.stopAudio(),this.media.stopRecord()}unmute(){this.isMuteAiia=!1,this.media.startRecord()}cloudToObj(e){try{const t=JSON.parse(e);void 0!==n(t,"signal")?this.behavior(t):c(t)?a(t,this.behavior):a(u(t),this.behavior)}catch(e){k.error("message transfer fail",e)}}behavior(e){switch(e.signal){case"layout":this.layoutSub.next(e.content);break;case"audio":if("sampleRate"===e.command)this.sampleRateOfWhisper.output=e.content;else switch(e.command){case"pcm":if(!this.isMuteAiia){const t=function(e,t,i){if(t===i)return e;const s=i/t,a=Math.ceil(e.length*s),o=new Float32Array(a);for(let t=0;t<a;t++){const i=t/s,a=Math.floor(i),n=i-a,r=e[a],c=e[Math.min(a+1,e.length-1)];o[t]=r+(c-r)*n}return o}(T(new Int16Array(e.content)),this.sampleRateOfWhisper.output,this.media.sampleRate);this.media.addAudioQueue({float32:t}),this.media.playAudio()}break;case"interrupted":this.media.stopAudio(),this.aiiaSubtitleSub.next("")}break;case"status":"Connected"===n(e,"content")&&(this.channelState.cloud=!0,this.channelCheck(),this.layoutSub.next({type:"resetLayout"}));break;case"agent":if(!this.isMuteAiia){const t=n(e,"content.function_result.response");void 0!==t&&(this.aiiaSubtitleSub.next(t),this.aiiaSubtitleClearSub.next())}break;case"asr":if(!this.isMuteAiia&&"ASR"===n(e,"content.function_type")){const t=n(e,"content.function_result.result");void 0!==t&&(this.userSubtitleSub.next(t),this.userSubtitleClearSub.next())}break;default:k.debug(e.signal)}}channelCheck(){const{proxy:e,cloud:t}=this.channelState;if(e&&t&&this.media.state===N.allowed){this.chat.sendToCloud({request:"audio",command:"sampleRate",content:this.sampleRateOfWhisper.input}),this.media.pcm.pipe(l(this.destorySub)).subscribe(e=>{this.chat.sendToCloud({request:"audio",command:"pcm",content:j(e)})});const e=(n=this.config.faceDetection.confidence,function(e,t){const{width:r,height:c}=t,u=i(e,e=>100*(e.categories[0]?.score??0)>=n),h=s(a(u,e=>{if(void 0!==e.boundingBox){const t=e.boundingBox,i=t.width*t.height,s=e.categories[0]?.score??0;return{...t,area:i,score:100*s,clientWidth:r,clientHeight:c}}return null}));return o(h,["area","score"])[0]??null});this.media.detections.pipe(l(this.destorySub),S(({detections:t,clientHeight:i,clientWidth:s})=>e(t,{width:s,height:i}))).subscribe(e=>{this.chat.send("face",e)}),this.media.startRecord(),this.media.startCapture(),this.stateSub.next("InService"),k.code(E["通道、雲端服務、麥克風都已就緒"])}else e&&t&&this.media.state!==N.allowed&&(this.stateSub.next("InServiceNoMedia"),k.code(E["未取得媒體裝置權限,請重新設定或忽略此訊息"]));var n}onDestroy(){this.chat.onDestroy(),this.media.onDestroy(),this.destorySub.next(),this.destorySub.complete(),this.stateSub.next("Destroy"),this.stateSub.complete(),k.code(E["結束SDK"])}}function q(t){if(v){!function(e){const{info:t,error:i,warn:s,debug:a,fatal:o,code:n}=function(e){if(void 0===e||"all"===e)return{code:!0,error:!0,warn:!0,info:!0,debug:!0,fatal:!0};if("none"===e)return{error:!1,code:!1,warn:!1,info:!1,debug:!1,fatal:!1};if("boolean"==typeof e)return{code:e,error:e,warn:e,info:e,debug:e,fatal:e};{const t=new Set(e);return{code:t.has("code"),debug:t.has("debug"),fatal:t.has("fatal"),error:t.has("error"),warn:t.has("warn"),info:t.has("info")}}}(e);n||(R.code=()=>{}),a||(R.debug=()=>{}),t||(R.info=()=>{}),s||(R.warn=()=>{}),i||(R.error=()=>{}),o||(R.fatal=()=>{})}(n(t,"debug",!0)),k.code(E["初始化必要依賴"]);const i=new x(e({},t));k.code(E["指定依賴已完成"],"config");const s=new B(i.mediaStream);k.code(E["指定依賴已完成"],"config");const a=new V(i,s);return k.code(E["指定依賴已完成"],"sdk"),""!==i.worklet_url&&s.init(i.worklet_url,i),a}throw new Error(_["環境錯誤(browser)"])}export{q as initSdk};
|
package/dist/node.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e,t=require("lodash-es"),s=require("moment"),o=require("socket.io"),i=require("rxjs"),r=require("axios"),n=require("ws"),c=require("fs"),a=require("os"),h=require("path"),u=require("node-osc");!function(e){e["網絡錯誤"]="ERROR CODE: 500",e["環境錯誤(browser)"]="ERROR CODE: 1001",e["Worklet模組載入失敗"]="ERROR CODE: 1002",e["未獲得媒體裝置權限"]="ERROR CODE: 1003",e["實例已摧毀"]="ERROR CODE: 1004",e["環境錯誤(nodejs)"]="ERROR CODE: 2001",e["未提供憑證"]="ERROR CODE: 2002",e["獲取權杖失敗"]="ERROR CODE: 2003",e["沒有可用專案"]="ERROR CODE: 2004",e["重複初始化"]="ERROR CODE: 2005"}(e||(e={}));const l="access_token",d="undefined"!=typeof process&&null!=process.versions&&null!=process.versions.node;class S{config;get webserver(){return this.config.webserver}get environment(){return this.config.env}get license(){return this.config.license??""}get port(){return function(e,t){const s=t??NaN;if(e){const t=parseInt(e);return isNaN(t)?s:t}return s}(process.env.PORT,this.config.port??3e3)}get ws_url(){return this.config.ws_url??""}get worklet_url(){return this.config.worklet_url??""}get project(){const{project:e}=t.assign({},this.config);return void 0===e?{specific:!1}:"string"==typeof e?{name:e,id:e,specific:!1}:t.assign({},e,{specific:!0})}get endPoint(){return this.environment,{api:"https://aiia-content-management-dev-21193779403.asia-east1.run.app",socket:"wss://graphen-agentic-workflow-dev-21193779403.asia-east1.run.app"}}get debug(){return this.config.debug??!0}get mediaStream(){return this.config.mediaStream}get chunkTimeInSeconds(){return"number"==typeof this.config.chunkTimeInSeconds&&this.config.chunkTimeInSeconds>0?this.config.chunkTimeInSeconds:.3}get llmSampleRate(){return"number"==typeof this.config.llmSampleRate&&this.config.llmSampleRate>0?this.config.llmSampleRate:16e3}get faceDetection(){return t.assign({perSecond:3,confidence:80},this.config.faceDetection)}get autoClearSubtitle(){const{user:e,aiia:s}=t.assign({},this.config.autoClearSubtitle);let o=5e3,i=5e3;return"number"==typeof e?o=e>=0?e:o:!1===e&&(o=NaN),"number"==typeof s?i=s>=0?s:i:!1===s&&(i=NaN),{userDelayTime:o,aiiaDelayTime:i}}constructor(e){this.config=e}}var b;!function(e){e["通道、雲端服務、麥克風都已就緒"]="CODE: 1000",e["未取得媒體裝置權限,請重新設定或忽略此訊息"]="CODE: 1001",e["請訂閱專案列表"]="CODE: 1002",e["初始化必要依賴"]="CODE: 1010",e["指定依賴已完成"]="CODE: 1011",e["啟動SDK"]="CODE: 1012",e["結束SDK"]="CODE: 1013",e["安全的關閉連線"]="CODE: 2000",e["無副作用的關閉連線"]="CODE: 2001",e["與雲端的服務中斷"]="CODE: 2002",e["沒有授權,請聯繫Graphen"]="CODE: 2003",e["自動重新連線連端服務"]="CODE: 2004",e["未預期的斷線,請聯繫Graphen"]="CODE: 2005",e["開始初始化必要模組"]="CODE: 2010",e["指定模組初始化完成"]="CODE: 2011",e["啟動服務"]="CODE: 2012",e["服務結束"]="CODE: 2013"}(b||(b={}));const g={code:console.log,debug:console.log,info:console.log,warn:console.warn,error:console.error,fatal:console.error},p=[];function _(e){return p.push(e),_}const E=new Proxy(g,{get(e,o,i){if("string"==typeof o)switch(o){case"debug":case"info":case"error":case"warn":case"fatal":case"code":return(...i)=>{const r=s().format("yyyy-MM-DD[T]HH:mm:ss");t.forEach(p,e=>{e.next(o,r,...i)}),e[o](`[Aiia::${o}_${r}_]`,...i)};default:return}},set:(e,t,s,o)=>!0});class f{config;server;memberSub;get port(){return this.config.port}get webserver(){return this.config.webserver}get memberChange(){return this.memberSub.asObservable()}constructor(e){this.config=e,this.memberSub=new i.Subject}start(){if(this.server=new o.Server(this.webserver,{cors:{origin:"*"}}),this.server.on("connection",e=>{this.memberSub.next({type:"in",socket:e}),E.debug("client on",e.id),e.on("disconnect",t=>{this.memberSub.next({type:"out",socket:e}),E.debug("client off",t)})}),void 0===this.webserver){const e=this.port;this.server.listen(e),E.info("Websocket server run on",e)}else E.info("Websocket server rely your webserver.")}onDestroy(){this.server&&this.server.close()}}class y{instance;controller;constructor(e){this.controller=new AbortController,this.instance=r.create({baseURL:e,signal:this.controller.signal})}async getAccessToken(s,o){const i={license_number:s,token_value:o??""},r=await this.instance.post("/api/v1/license/agent_token",i).then(e=>t.get(e.data,"token_value","")).catch(()=>null);if(null===r)throw new Error(e["網絡錯誤"]);if(""===r)throw new Error(e["獲取權杖失敗"]);return r}async getProjectList(s){const o=await this.instance.post("/api/v1/license/projects",{license_number:s}).then(e=>t.map(t.get(e,"data.projects",[]),({id:e,sub_project_name:t})=>({id:e,name:t}))).catch(e=>null);if(null===o)throw new Error(e["網絡錯誤"]);if(0===o.length)throw new Error(e["沒有可用專案"]);return o}onDestroy(){this.controller.abort()}}var m;!function(e){e[e.MDN_NORMAL_CLOSURE=1e3]="MDN_NORMAL_CLOSURE",e[e.MDN_GOING_AWAY=1001]="MDN_GOING_AWAY",e[e.MDN_PROTOCOL_ERROR=1002]="MDN_PROTOCOL_ERROR",e[e.MDN_UNSUPPORTED_DATA=1003]="MDN_UNSUPPORTED_DATA",e[e.MDN_RESERVED_1004=1004]="MDN_RESERVED_1004",e[e.MDN_NO_STATUS_RECEIVED=1005]="MDN_NO_STATUS_RECEIVED",e[e.MDN_ABNORMAL_CLOSURE=1006]="MDN_ABNORMAL_CLOSURE",e[e.MDN_INVALID_FRAME_PAYLOAD=1007]="MDN_INVALID_FRAME_PAYLOAD",e[e.MDN_POLICY_VIOLATION=1008]="MDN_POLICY_VIOLATION",e[e.MDN_MESSAGE_TOO_BIG=1009]="MDN_MESSAGE_TOO_BIG",e[e.MDN_MANDATORY_EXTENSION=1010]="MDN_MANDATORY_EXTENSION",e[e.MDN_INTERNAL_ERROR=1011]="MDN_INTERNAL_ERROR",e[e.MDN_SERVICE_RESTART=1012]="MDN_SERVICE_RESTART",e[e.MDN_TRY_AGAIN_LATER=1013]="MDN_TRY_AGAIN_LATER",e[e.MDN_BAD_GATEWAY=1014]="MDN_BAD_GATEWAY",e[e.MDN_TLS_HANDSHAKE=1015]="MDN_TLS_HANDSHAKE",e[e.WHEN_BROWSER_CLOSE=4001]="WHEN_BROWSER_CLOSE",e[e.MANUAL_CLOSE=4002]="MANUAL_CLOSE",e[e.WS_5000_NORAML_CLOSURE=4100]="WS_5000_NORAML_CLOSURE",e[e.WS_5001_UNAUTHORIZED=4101]="WS_5001_UNAUTHORIZED",e[e.WS_5002_LICENSE_EXPIRED=4102]="WS_5002_LICENSE_EXPIRED",e[e.WS_5003_TOKEN_EXPIRED=4103]="WS_5003_TOKEN_EXPIRED"}(m||(m={}));class O{socket;messageSub;linkStartSub;destorySub;closeSub;get message(){return this.messageSub.asObservable()}get close(){return this.closeSub.asObservable()}get linkStart(){return this.linkStartSub.asObservable()}messageQueue=[];isConnected;constructor(){this.isConnected=!1,this.messageSub=new i.Subject,this.linkStartSub=new i.Subject,this.closeSub=new i.Subject,this.destorySub=new i.Subject}start(e){this.socket=new n(e,{autoPong:!0}),i.fromEvent(this.socket,"open").pipe(i.takeUntil(this.destorySub)).subscribe(()=>{this.isConnected=!0,E.code(b["啟動服務"],"proxy"),this.flushMessageQueue(),this.linkStartSub.next()}),i.fromEvent(this.socket,"message").pipe(i.takeUntil(this.destorySub)).subscribe(e=>{const{data:t}=e;this.messageSub.next(t)}),i.fromEvent(this.socket,"error").pipe(i.takeUntil(this.destorySub)).subscribe(e=>{const{error:t}=e;E.error("Proxy has some problem",t)}),i.fromEvent(this.socket,"close").pipe(i.takeUntil(this.destorySub)).subscribe(e=>{this.isConnected=!1;const{code:t,reason:s,type:o,wasClean:i}=e;switch(t){case m.WHEN_BROWSER_CLOSE:E.code(b["無副作用的關閉連線"]);break;case m.MDN_NORMAL_CLOSURE:case m.MDN_GOING_AWAY:this.closeSub.next("close"),E.code(b["安全的關閉連線"]);break;case m.MDN_NO_STATUS_RECEIVED:case m.MDN_ABNORMAL_CLOSURE:this.closeSub.next("close"),E.code(b["與雲端的服務中斷"],{code:t,reason:s,type:o,wasClean:i});break;case m.WS_5001_UNAUTHORIZED:case m.WS_5002_LICENSE_EXPIRED:this.closeSub.next("no_permissions"),E.code(b["沒有授權,請聯繫Graphen"]);break;case m.WS_5000_NORAML_CLOSURE:case m.WS_5003_TOKEN_EXPIRED:this.closeSub.next("reconnect"),E.code(b["自動重新連線連端服務"]);break;default:this.closeSub.next("close"),E.code(b["未預期的斷線,請聯繫Graphen"],{code:t,reason:s,type:o,wasClean:i})}})}reconnect(e){this.onDestroy(),this.destorySub=new i.Subject,this.start(e)}flushMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected&&void 0!==this.socket;){const e=this.messageQueue.shift();e&&this.socket.send(e,e=>{e&&E.error("send message fail",e?.message,e)})}}send(e){this.isConnected&&void 0!==this.socket?this.socket.send(e,e=>{e&&E.error("send message fail",e?.message,e)}):this.messageQueue.push(e)}onClose(){this.socket?.close(m.WHEN_BROWSER_CLOSE)}onDestroy(){this.destorySub.next(),this.destorySub.complete()}}const D=new class{AppName;platform;isMAC;isWIN;isLINUX;saveFolder;homedir;appFolder;EOL;constructor(e){switch(this.AppName=e,this.platform=process.platform,this.homedir=a.homedir(),this.EOL=a.EOL,this.platform){case"darwin":this.isMAC=!0,this.isWIN=!1,this.isLINUX=!1,this.saveFolder=h.join(this.homedir,"Library","Application Support");break;case"win32":this.isMAC=!1,this.isWIN=!0,this.isLINUX=!1,this.saveFolder=process.env.APPDATA||h.join(this.homedir,"AppData","Roaming");break;case"linux":this.isMAC=!1,this.isWIN=!1,this.isLINUX=!0,this.saveFolder=process.env.XDG_CONFIG_HOME||h.join(this.homedir,".config");break;default:console.log(`當前系統是未知的平台: ${this.platform}`),this.isMAC=!1,this.isWIN=!1,this.isLINUX=!1,this.saveFolder=this.homedir}this.appFolder=h.join(this.saveFolder,this.AppName),this.folderCheck(this.appFolder)}addPath(...e){return h.join(...e)}folderCheck(e){c.mkdirSync(e,{recursive:!0})}fileCheck(e){c.existsSync(e)||c.writeFileSync(e,"",{encoding:"utf8"})}}("aiia-sdk");class N{type="node";filePath;fileName;constructor(){this.fileName="storage.json",this.filePath=D.addPath(D.appFolder,this.fileName),D.fileCheck(this.filePath)}getFileDataSync(){const e=c.readFileSync(this.filePath,"utf8");try{return JSON.parse(e)}catch(e){return{}}}setFileDataSync(e){try{const t=JSON.stringify(e);c.writeFileSync(this.filePath,t,"utf8")}catch(e){}}async getFileData(){return new Promise(e=>{c.readFile(this.filePath,"utf8",(t,s)=>{if(t)e({});else try{e(JSON.parse(s))}catch(t){e({})}})})}async setFileData(e){return new Promise(t=>{try{const s=JSON.stringify(e);c.writeFile(this.filePath,s,"utf8",e=>{t()})}catch(e){}})}async getItem(e){return(await this.getFileData())[e]??null}async setItem(e,t){const s=await this.getFileData();s[e]=t,await this.setFileData(s)}async removeItem(e){const s=await this.getFileData(),o=t.omit(s,e);await this.setFileData(o)}async clear(){await this.setFileData({})}getItemSync(e){return this.getFileDataSync()[e]??null}setItemSync(e,t){const s=this.getFileDataSync();s[e]=t,this.setFileDataSync(s)}removeItemSync(e){const s=t.omit(this.getFileDataSync(),e);this.setFileDataSync(s)}clearSync(){this.setFileDataSync({})}}class R{config;constructor(e){this.config=e,E.info("UEProxy, config=",e)}start(){E.info("UEProxy, start proxy")}send(e){let t=this.cloudToObj(e);if(t&&t.signal&&"osc"===t.signal){E.info("UEProxy, payload=",t);try{let e=t.content;const s=new u.Client(e.host,e.port);E.debug("UEProxy, client open to port "+e.port),s.send(e.message,e=>{e&&E.error(e),s.close(),E.debug("UEProxy, client closed")})}catch(e){E.error(e)}}}cloudToObj(e){try{return JSON.parse(e)}catch(e){E.error("message transfer fail",e)}}onDestroy(){E.info("UEProxy, destroy proxy")}}class k{socket;messageSub;linkStartSub;destorySub;closeSub;get message(){return this.messageSub.asObservable()}get close(){return this.closeSub.asObservable()}get linkStart(){return this.linkStartSub.asObservable()}messageQueue=[];isConnected;constructor(){this.isConnected=!1,this.messageSub=new i.Subject,this.linkStartSub=new i.Subject,this.closeSub=new i.Subject,this.destorySub=new i.Subject}url="ws://localhost:8080";start(){this.socket=new n(this.url,{autoPong:!0}),i.fromEvent(this.socket,"open").pipe(i.takeUntil(this.destorySub)).subscribe(()=>{this.isConnected=!0,E.code(b["啟動服務"],"proxy"),this.flushMessageQueue(),this.linkStartSub.next()}),i.fromEvent(this.socket,"message").pipe(i.takeUntil(this.destorySub)).subscribe(e=>{const{data:t}=e;this.messageSub.next(t)}),i.fromEvent(this.socket,"error").pipe(i.takeUntil(this.destorySub)).subscribe(e=>{const{error:t}=e;E.error("Proxy has some problem",t)}),i.fromEvent(this.socket,"close").pipe(i.takeUntil(this.destorySub)).subscribe(e=>{this.isConnected=!1;const{code:t,reason:s}=e;switch(t){case m.MANUAL_CLOSE:E.code(b["無副作用的關閉連線"]);break;case m.WS_5000_NORAML_CLOSURE:case m.MDN_NORMAL_CLOSURE:case m.MDN_GOING_AWAY:this.closeSub.next("close"),E.code(b["安全的關閉連線"]);break;case m.MDN_NO_STATUS_RECEIVED:case m.MDN_ABNORMAL_CLOSURE:this.closeSub.next("close"),E.code(b["與雲端的服務中斷"],{code:t,reason:s});break;case m.WS_5001_UNAUTHORIZED:case m.WS_5002_LICENSE_EXPIRED:this.closeSub.next("no_permissions"),E.code(b["沒有授權,請聯繫Graphen"]);break;case m.WS_5003_TOKEN_EXPIRED:this.closeSub.next("reconnect"),E.code(b["自動重新連線連端服務"]);break;default:this.closeSub.next("close"),E.code(b["未預期的斷線,請聯繫Graphen"],{code:t,reason:s})}})}reconnect(){this.onDestroy(),this.destorySub=new i.Subject,this.start()}flushMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected&&void 0!==this.socket;){const e=this.messageQueue.shift();e&&this.socket.send(e)}}send(e){let t=this.cloudToObj(e);if(t&&t.signal&&"audio"===t.signal&&"pcm"===t.command&&(E.info("AudioSocketProxy, payload=",t),this.isConnected&&void 0!==this.socket))try{const e=t.content,s=Buffer.allocUnsafe(2*e.length);for(let t=0;t<e.length;t++)s.writeInt16LE(e[t],2*t);this.socket.send(s)}catch(e){E.error(e)}}cloudToObj(e){try{return JSON.parse(e)}catch(e){E.error("message transfer fail",e)}}onClose(){this.socket?.close(m.MANUAL_CLOSE)}onDestroy(){this.destorySub.next(),this.destorySub.complete()}}class C{socket;messageSub;linkStartSub;destorySub;closeSub;get message(){return this.messageSub.asObservable()}get close(){return this.closeSub.asObservable()}get linkStart(){return this.linkStartSub.asObservable()}messageQueue=[];isConnected;constructor(){this.isConnected=!1,this.messageSub=new i.Subject,this.linkStartSub=new i.Subject,this.closeSub=new i.Subject,this.destorySub=new i.Subject}url="ws://localhost:8081";start(){this.socket=new n(this.url,{autoPong:!0}),i.fromEvent(this.socket,"open").pipe(i.takeUntil(this.destorySub)).subscribe(()=>{this.isConnected=!0,E.code(b["啟動服務"],"proxy"),this.flushMessageQueue(),this.linkStartSub.next()}),i.fromEvent(this.socket,"message").pipe(i.takeUntil(this.destorySub)).subscribe(e=>{const{data:t}=e;this.messageSub.next(t)}),i.fromEvent(this.socket,"error").pipe(i.takeUntil(this.destorySub)).subscribe(e=>{const{error:t}=e;E.error("Proxy has some problem",t)}),i.fromEvent(this.socket,"close").pipe(i.takeUntil(this.destorySub)).subscribe(e=>{this.isConnected=!1;const{code:t,reason:s}=e;switch(t){case m.MANUAL_CLOSE:E.code(b["無副作用的關閉連線"]);break;case m.WS_5000_NORAML_CLOSURE:case m.MDN_NORMAL_CLOSURE:case m.MDN_GOING_AWAY:this.closeSub.next("close"),E.code(b["安全的關閉連線"]);break;case m.MDN_NO_STATUS_RECEIVED:case m.MDN_ABNORMAL_CLOSURE:this.closeSub.next("close"),E.code(b["與雲端的服務中斷"],{code:t,reason:s});break;case m.WS_5001_UNAUTHORIZED:case m.WS_5002_LICENSE_EXPIRED:this.closeSub.next("no_permissions"),E.code(b["沒有授權,請聯繫Graphen"]);break;case m.WS_5003_TOKEN_EXPIRED:this.closeSub.next("reconnect"),E.code(b["自動重新連線連端服務"]);break;default:this.closeSub.next("close"),E.code(b["未預期的斷線,請聯繫Graphen"],{code:t,reason:s})}})}reconnect(){this.onDestroy(),this.destorySub=new i.Subject,this.start()}flushMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected&&void 0!==this.socket;){const e=this.messageQueue.shift();e&&this.socket.send(e)}}send(e){let t=this.cloudToObj(e);if(t&&t.signal&&"audio"===t.signal&&"interrupted"===t.command&&(E.info("AudioInterruptSocketProxy, payload=",t),this.isConnected&&void 0!==this.socket))try{this.socket.send(t.command)}catch(e){E.error(e)}}cloudToObj(e){try{return JSON.parse(e)}catch(e){E.error("message transfer fail",e)}}onClose(){this.socket?.close(m.MANUAL_CLOSE)}onDestroy(){this.destorySub.next(),this.destorySub.complete()}}class A{next(e,t,...o){const i=`log_${s().format("yyyy-MM-DD")}.txt`,r=D.addPath(D.appFolder,i);try{const s=o.reduce((e,t)=>{switch(typeof t){case"string":case"number":case"bigint":return`${e} ${t.toString()}`;case"boolean":return`${e} ${t?"true":"false"}`;case"object":try{return`${e} ${JSON.stringify(t)}`}catch(t){return e}case"symbol":case"undefined":case"function":return`${e} [${typeof t}]`}},"");c.appendFileSync(r,`LOG(${e})__${t}__::${s}${D.EOL}`,{encoding:"utf8"})}catch(e){}}}class w{config;stroage;apiProxy;chat;udpProxy;audioProxy;audioIntrProxy;isStart;channelMap;destorySub;access_token;get accessToken(){return this.access_token}constructor(e,t){this.config=e,this.stroage=t,this.isStart=!1,this.destorySub=new i.Subject,this.channelMap=new Map,this.access_token=t.getItemSync(l),this.apiProxy=new y(this.config.endPoint.api),E.code(b["指定模組初始化完成"],"api"),this.chat=new f(this.config),E.code(b["指定模組初始化完成"],"chat"),this.udpProxy=new R(this.config),E.code(b["指定模組初始化完成"],"udp"),this.audioProxy=new k,E.code(b["指定模組初始化完成"],"audio"),this.audioIntrProxy=new C,E.code(b["指定模組初始化完成"],"audio intr"),this.openChannel=this.openChannel.bind(this)}async start(){if(this.isStart)throw new Error(e["重複初始化"]);this.isStart=!0,await this.replaceAccessToken(),this.chat.memberChange.pipe(i.takeUntil(this.destorySub)).subscribe(({type:e,socket:s})=>{switch(e){case"in":{const e=new O,r=new i.Subject,n=(o=s.handshake.query.uuid,t.isArray(o)?t.get(o,"[0]",void 0):o??void 0);void 0===n?(this.getProjectList().then(e=>{s.emit("list",e)}),i.fromEvent(s,"uuid").pipe(i.take(1),i.takeUntil(r)).subscribe(t=>{this.openChannel(t,s,e,r)})):this.openChannel(n,s,e,r),this.channelMap.set(s.id,()=>{r.next(),r.complete()});break}case"out":this.channelMap.has(s.id)&&(this.channelMap.get(s.id)(),this.channelMap.delete(s.id))}var o}),this.chat.start(),E.code(b["啟動服務"],"chat"),this.udpProxy.start(),E.code(b["啟動服務"],"udp")}async replaceAccessToken(){const e=await this.apiProxy.getAccessToken(this.config.license,this.access_token);return this.access_token=e,this.stroage.setItemSync(l,e),e}async getProjectList(){return await this.apiProxy.getProjectList(this.config.license)}getProxySocketURL(e){return`${this.config.endPoint.socket}/v1/chat/project/${this.accessToken}/${e}`}openChannel(e,t,s,o){i.fromEvent(t,"cloud").pipe(i.takeUntil(o)).subscribe(e=>{s.send(e)}),s.message.pipe(i.takeUntil(o)).subscribe(e=>{t.emit("cloud",e),this.udpProxy.send(e),this.audioProxy.send(e),this.audioIntrProxy.send(e)}),s.close.pipe(i.takeUntil(o)).subscribe(async o=>{switch(t.emit("channel",o),o){case"close":case"no_permissions":s.onDestroy();break;case"reconnect":await this.replaceAccessToken(),s.reconnect(this.getProxySocketURL(e))}}),s.linkStart.pipe(i.takeUntil(o)).subscribe(()=>{t.emit("channel","open")}),o.subscribe(()=>{s.onClose(),this.audioProxy.onClose(),this.audioIntrProxy.onClose()}),s.start(this.getProxySocketURL(e)),this.audioProxy.start(),this.audioIntrProxy.start()}onDestroy(){this.apiProxy.onDestroy(),this.chat.onDestroy(),this.udpProxy.onDestroy(),this.destorySub.next(),this.destorySub.complete(),E.code(b["服務結束"])}}exports.aiiaCore=function(s){if(d){if(void 0===t.get(s,"license",void 0))throw new Error(e["未提供憑證"]);!function(e){const{info:t,error:s,warn:o,debug:i,fatal:r,code:n}=function(e){if(void 0===e||"all"===e)return{code:!0,error:!0,warn:!0,info:!0,debug:!0,fatal:!0};if("none"===e)return{error:!1,code:!1,warn:!1,info:!1,debug:!1,fatal:!1};if("boolean"==typeof e)return{code:e,error:e,warn:e,info:e,debug:e,fatal:e};{const t=new Set(e);return{code:t.has("code"),debug:t.has("debug"),fatal:t.has("fatal"),error:t.has("error"),warn:t.has("warn"),info:t.has("info")}}}(e);return n||(g.code=()=>{}),i||(g.debug=()=>{}),t||(g.info=()=>{}),o||(g.warn=()=>{}),s||(g.error=()=>{}),r||(g.fatal=()=>{}),_}(t.get(s,"debug",!0))(new A),E.code(b["開始初始化必要模組"]);const o=new S(t.assign({},s));E.code(b["指定模組初始化完成"],"config");const i=new N;E.code(b["指定模組初始化完成"],"storage");const r=new w(o,i);return E.code(b["指定模組初始化完成"],"core"),r.start(),E.code(b["啟動服務"]),()=>{r.onDestroy()}}throw new Error(e["環境錯誤(nodejs)"])};
|
|
1
|
+
"use strict";var e,t=require("lodash-es"),s=require("moment"),o=require("mathjs"),i=require("socket.io"),r=require("rxjs"),n=require("axios"),c=require("ws"),a=require("fs"),h=require("os"),u=require("path"),l=require("node-osc");!function(e){e["網絡錯誤"]="ERROR CODE: 500",e["環境錯誤(browser)"]="ERROR CODE: 1001",e["Worklet模組載入失敗"]="ERROR CODE: 1002",e["未獲得媒體裝置權限"]="ERROR CODE: 1003",e["實例已摧毀"]="ERROR CODE: 1004",e["環境錯誤(nodejs)"]="ERROR CODE: 2001",e["未提供憑證"]="ERROR CODE: 2002",e["獲取權杖失敗"]="ERROR CODE: 2003",e["沒有可用專案"]="ERROR CODE: 2004",e["重複初始化"]="ERROR CODE: 2005"}(e||(e={}));const d="access_token",S="undefined"!=typeof process&&null!=process.versions&&null!=process.versions.node;class b{config;get webserver(){return this.config.webserver}get environment(){return this.config.env}get license(){return this.config.license??""}get port(){return function(e,t){const s=t??NaN;if(e){const t=parseInt(e);return isNaN(t)?s:t}return s}(process.env.PORT,this.config.port??3e3)}get ws_url(){return this.config.ws_url??""}get worklet_url(){return this.config.worklet_url??""}get project(){const{project:e}=t.assign({},this.config);return void 0===e?{specific:!1}:"string"==typeof e?{name:e,id:e,specific:!1}:t.assign({},e,{specific:!0})}get endPoint(){return this.environment,{api:"https://aiia-content-management-dev-21193779403.asia-east1.run.app",socket:"wss://graphen-agentic-workflow-dev-21193779403.asia-east1.run.app"}}get debug(){return this.config.debug??!0}get mediaStream(){return this.config.mediaStream}get chunkTimeInSeconds(){return"number"==typeof this.config.chunkTimeInSeconds&&this.config.chunkTimeInSeconds>0?this.config.chunkTimeInSeconds:.3}get llmSampleRate(){return"number"==typeof this.config.llmSampleRate&&this.config.llmSampleRate>0?this.config.llmSampleRate:16e3}get faceDetection(){return t.assign({perSecond:3,confidence:80},this.config.faceDetection)}get autoClearSubtitle(){const{user:e,aiia:s}=t.assign({},this.config.autoClearSubtitle);let o=5e3,i=5e3;return"number"==typeof e?o=e>=0?e:o:!1===e&&(o=NaN),"number"==typeof s?i=s>=0?s:i:!1===s&&(i=NaN),{userDelayTime:o,aiiaDelayTime:i}}get eyeTrackEnable(){return this.config.eyeTrackEnable??!1}constructor(e){this.config=e}}var g;!function(e){e["通道、雲端服務、麥克風都已就緒"]="CODE: 1000",e["未取得媒體裝置權限,請重新設定或忽略此訊息"]="CODE: 1001",e["請訂閱專案列表"]="CODE: 1002",e["初始化必要依賴"]="CODE: 1010",e["指定依賴已完成"]="CODE: 1011",e["啟動SDK"]="CODE: 1012",e["結束SDK"]="CODE: 1013",e["安全的關閉連線"]="CODE: 2000",e["無副作用的關閉連線"]="CODE: 2001",e["與雲端的服務中斷"]="CODE: 2002",e["沒有授權,請聯繫Graphen"]="CODE: 2003",e["自動重新連線連端服務"]="CODE: 2004",e["未預期的斷線,請聯繫Graphen"]="CODE: 2005",e["開始初始化必要模組"]="CODE: 2010",e["指定模組初始化完成"]="CODE: 2011",e["啟動服務"]="CODE: 2012",e["服務結束"]="CODE: 2013"}(g||(g={}));const p={code:console.log,debug:console.log,info:console.log,warn:console.warn,error:console.error,fatal:console.error},E=[];function _(e){return E.push(e),_}const f=new Proxy(p,{get(e,o,i){if("string"==typeof o)switch(o){case"debug":case"info":case"error":case"warn":case"fatal":case"code":return(...i)=>{const r=s().format("yyyy-MM-DD[T]HH:mm:ss");t.forEach(E,e=>{e.next(o,r,...i)}),e[o](`[Aiia::${o}_${r}_]`,...i)};default:return}},set:(e,t,s,o)=>!0});class y{config;server;memberSub;get port(){return this.config.port}get webserver(){return this.config.webserver}get memberChange(){return this.memberSub.asObservable()}constructor(e){this.config=e,this.memberSub=new r.Subject}start(){if(this.server=new i.Server(this.webserver,{cors:{origin:"*"}}),this.server.on("connection",e=>{this.memberSub.next({type:"in",socket:e}),f.debug("client on",e.id),e.on("disconnect",t=>{this.memberSub.next({type:"out",socket:e}),f.debug("client off",t)})}),void 0===this.webserver){const e=this.port;this.server.listen(e),f.info("Websocket server run on",e)}else f.info("Websocket server rely your webserver.")}onDestroy(){this.server&&this.server.close()}}class m{instance;controller;constructor(e){this.controller=new AbortController,this.instance=n.create({baseURL:e,signal:this.controller.signal})}async getAccessToken(s,o){const i={license_number:s,token_value:o??""},r=await this.instance.post("/api/v1/license/agent_token",i).then(e=>t.get(e.data,"token_value","")).catch(()=>null);if(null===r)throw new Error(e["網絡錯誤"]);if(""===r)throw new Error(e["獲取權杖失敗"]);return r}async getProjectList(s){const o=await this.instance.post("/api/v1/license/projects",{license_number:s}).then(e=>t.map(t.get(e,"data.projects",[]),({id:e,sub_project_name:t})=>({id:e,name:t}))).catch(e=>null);if(null===o)throw new Error(e["網絡錯誤"]);if(0===o.length)throw new Error(e["沒有可用專案"]);return o}onDestroy(){this.controller.abort()}}var O;!function(e){e[e.MDN_NORMAL_CLOSURE=1e3]="MDN_NORMAL_CLOSURE",e[e.MDN_GOING_AWAY=1001]="MDN_GOING_AWAY",e[e.MDN_PROTOCOL_ERROR=1002]="MDN_PROTOCOL_ERROR",e[e.MDN_UNSUPPORTED_DATA=1003]="MDN_UNSUPPORTED_DATA",e[e.MDN_RESERVED_1004=1004]="MDN_RESERVED_1004",e[e.MDN_NO_STATUS_RECEIVED=1005]="MDN_NO_STATUS_RECEIVED",e[e.MDN_ABNORMAL_CLOSURE=1006]="MDN_ABNORMAL_CLOSURE",e[e.MDN_INVALID_FRAME_PAYLOAD=1007]="MDN_INVALID_FRAME_PAYLOAD",e[e.MDN_POLICY_VIOLATION=1008]="MDN_POLICY_VIOLATION",e[e.MDN_MESSAGE_TOO_BIG=1009]="MDN_MESSAGE_TOO_BIG",e[e.MDN_MANDATORY_EXTENSION=1010]="MDN_MANDATORY_EXTENSION",e[e.MDN_INTERNAL_ERROR=1011]="MDN_INTERNAL_ERROR",e[e.MDN_SERVICE_RESTART=1012]="MDN_SERVICE_RESTART",e[e.MDN_TRY_AGAIN_LATER=1013]="MDN_TRY_AGAIN_LATER",e[e.MDN_BAD_GATEWAY=1014]="MDN_BAD_GATEWAY",e[e.MDN_TLS_HANDSHAKE=1015]="MDN_TLS_HANDSHAKE",e[e.WHEN_BROWSER_CLOSE=4001]="WHEN_BROWSER_CLOSE",e[e.MANUAL_CLOSE=4002]="MANUAL_CLOSE",e[e.WS_5000_NORAML_CLOSURE=4100]="WS_5000_NORAML_CLOSURE",e[e.WS_5001_UNAUTHORIZED=4101]="WS_5001_UNAUTHORIZED",e[e.WS_5002_LICENSE_EXPIRED=4102]="WS_5002_LICENSE_EXPIRED",e[e.WS_5003_TOKEN_EXPIRED=4103]="WS_5003_TOKEN_EXPIRED"}(O||(O={}));class D{socket;messageSub;linkStartSub;destorySub;closeSub;get message(){return this.messageSub.asObservable()}get close(){return this.closeSub.asObservable()}get linkStart(){return this.linkStartSub.asObservable()}messageQueue=[];isConnected;constructor(){this.isConnected=!1,this.messageSub=new r.Subject,this.linkStartSub=new r.Subject,this.closeSub=new r.Subject,this.destorySub=new r.Subject}start(e){this.socket=new c(e,{autoPong:!0}),r.fromEvent(this.socket,"open").pipe(r.takeUntil(this.destorySub)).subscribe(()=>{this.isConnected=!0,f.code(g["啟動服務"],"proxy"),this.flushMessageQueue(),this.linkStartSub.next()}),r.fromEvent(this.socket,"message").pipe(r.takeUntil(this.destorySub)).subscribe(e=>{const{data:t}=e;this.messageSub.next(t)}),r.fromEvent(this.socket,"error").pipe(r.takeUntil(this.destorySub)).subscribe(e=>{const{error:t}=e;f.error("Proxy has some problem",t)}),r.fromEvent(this.socket,"close").pipe(r.takeUntil(this.destorySub)).subscribe(e=>{this.isConnected=!1;const{code:t,reason:s,type:o,wasClean:i}=e;switch(t){case O.WHEN_BROWSER_CLOSE:f.code(g["無副作用的關閉連線"]);break;case O.MDN_NORMAL_CLOSURE:case O.MDN_GOING_AWAY:this.closeSub.next("close"),f.code(g["安全的關閉連線"]);break;case O.MDN_NO_STATUS_RECEIVED:case O.MDN_ABNORMAL_CLOSURE:this.closeSub.next("close"),f.code(g["與雲端的服務中斷"],{code:t,reason:s,type:o,wasClean:i});break;case O.WS_5001_UNAUTHORIZED:case O.WS_5002_LICENSE_EXPIRED:this.closeSub.next("no_permissions"),f.code(g["沒有授權,請聯繫Graphen"]);break;case O.WS_5000_NORAML_CLOSURE:case O.WS_5003_TOKEN_EXPIRED:this.closeSub.next("reconnect"),f.code(g["自動重新連線連端服務"]);break;default:this.closeSub.next("close"),f.code(g["未預期的斷線,請聯繫Graphen"],{code:t,reason:s,type:o,wasClean:i})}})}reconnect(e){this.onDestroy(),this.destorySub=new r.Subject,this.start(e)}flushMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected&&void 0!==this.socket;){const e=this.messageQueue.shift();e&&this.socket.send(e,e=>{e&&f.error("send message fail",e?.message,e)})}}send(e){this.isConnected&&void 0!==this.socket?this.socket.send(e,e=>{e&&f.error("send message fail",e?.message,e)}):this.messageQueue.push(e)}sendToCloud(e){this.send(JSON.stringify(e))}onClose(){this.socket?.close(O.WHEN_BROWSER_CLOSE)}onDestroy(){this.destorySub.next(),this.destorySub.complete()}}const N=new class{AppName;platform;isMAC;isWIN;isLINUX;saveFolder;homedir;appFolder;EOL;constructor(e){switch(this.AppName=e,this.platform=process.platform,this.homedir=h.homedir(),this.EOL=h.EOL,this.platform){case"darwin":this.isMAC=!0,this.isWIN=!1,this.isLINUX=!1,this.saveFolder=u.join(this.homedir,"Library","Application Support");break;case"win32":this.isMAC=!1,this.isWIN=!0,this.isLINUX=!1,this.saveFolder=process.env.APPDATA||u.join(this.homedir,"AppData","Roaming");break;case"linux":this.isMAC=!1,this.isWIN=!1,this.isLINUX=!0,this.saveFolder=process.env.XDG_CONFIG_HOME||u.join(this.homedir,".config");break;default:console.log(`當前系統是未知的平台: ${this.platform}`),this.isMAC=!1,this.isWIN=!1,this.isLINUX=!1,this.saveFolder=this.homedir}this.appFolder=u.join(this.saveFolder,this.AppName),this.folderCheck(this.appFolder)}addPath(...e){return u.join(...e)}folderCheck(e){a.mkdirSync(e,{recursive:!0})}fileCheck(e){a.existsSync(e)||a.writeFileSync(e,"",{encoding:"utf8"})}}("aiia-sdk");class k{type="node";filePath;fileName;constructor(){this.fileName="storage.json",this.filePath=N.addPath(N.appFolder,this.fileName),N.fileCheck(this.filePath)}getFileDataSync(){const e=a.readFileSync(this.filePath,"utf8");try{return JSON.parse(e)}catch(e){return{}}}setFileDataSync(e){try{const t=JSON.stringify(e);a.writeFileSync(this.filePath,t,"utf8")}catch(e){}}async getFileData(){return new Promise(e=>{a.readFile(this.filePath,"utf8",(t,s)=>{if(t)e({});else try{e(JSON.parse(s))}catch(t){e({})}})})}async setFileData(e){return new Promise(t=>{try{const s=JSON.stringify(e);a.writeFile(this.filePath,s,"utf8",e=>{t()})}catch(e){}})}async getItem(e){return(await this.getFileData())[e]??null}async setItem(e,t){const s=await this.getFileData();s[e]=t,await this.setFileData(s)}async removeItem(e){const s=await this.getFileData(),o=t.omit(s,e);await this.setFileData(o)}async clear(){await this.setFileData({})}getItemSync(e){return this.getFileDataSync()[e]??null}setItemSync(e,t){const s=this.getFileDataSync();s[e]=t,this.setFileDataSync(s)}removeItemSync(e){const s=t.omit(this.getFileDataSync(),e);this.setFileDataSync(s)}clearSync(){this.setFileDataSync({})}}class R{config;constructor(e){this.config=e,f.info("UEProxy, config=",e)}start(){f.info("UEProxy, start proxy")}send(e){let t=this.cloudToObj(e);if(t&&t.signal&&"osc"===t.signal){f.info("UEProxy, payload=",t);try{let e=t.content;const s=new l.Client(e.host,e.port);f.debug("UEProxy, client open to port "+e.port),s.send(e.message,e=>{e&&f.error(e),s.close(),f.debug("UEProxy, client closed")})}catch(e){f.error(e)}}}cloudToObj(e){try{return JSON.parse(e)}catch(e){f.error("message transfer fail",e)}}onDestroy(){f.info("UEProxy, destroy proxy")}}class C{socket;messageSub;linkStartSub;destorySub;closeSub;get message(){return this.messageSub.asObservable()}get close(){return this.closeSub.asObservable()}get linkStart(){return this.linkStartSub.asObservable()}messageQueue=[];isConnected;constructor(){this.isConnected=!1,this.messageSub=new r.Subject,this.linkStartSub=new r.Subject,this.closeSub=new r.Subject,this.destorySub=new r.Subject}url="ws://localhost:8080";start(){this.socket=new c(this.url,{autoPong:!0}),r.fromEvent(this.socket,"open").pipe(r.takeUntil(this.destorySub)).subscribe(()=>{this.isConnected=!0,f.code(g["啟動服務"],"proxy"),this.flushMessageQueue(),this.linkStartSub.next()}),r.fromEvent(this.socket,"message").pipe(r.takeUntil(this.destorySub)).subscribe(e=>{const{data:t}=e;this.messageSub.next(t)}),r.fromEvent(this.socket,"error").pipe(r.takeUntil(this.destorySub)).subscribe(e=>{const{error:t}=e;f.error("Proxy has some problem",t)}),r.fromEvent(this.socket,"close").pipe(r.takeUntil(this.destorySub)).subscribe(e=>{this.isConnected=!1;const{code:t,reason:s}=e;switch(t){case O.MANUAL_CLOSE:f.code(g["無副作用的關閉連線"]);break;case O.WS_5000_NORAML_CLOSURE:case O.MDN_NORMAL_CLOSURE:case O.MDN_GOING_AWAY:this.closeSub.next("close"),f.code(g["安全的關閉連線"]);break;case O.MDN_NO_STATUS_RECEIVED:case O.MDN_ABNORMAL_CLOSURE:this.closeSub.next("close"),f.code(g["與雲端的服務中斷"],{code:t,reason:s});break;case O.WS_5001_UNAUTHORIZED:case O.WS_5002_LICENSE_EXPIRED:this.closeSub.next("no_permissions"),f.code(g["沒有授權,請聯繫Graphen"]);break;case O.WS_5003_TOKEN_EXPIRED:this.closeSub.next("reconnect"),f.code(g["自動重新連線連端服務"]);break;default:this.closeSub.next("close"),f.code(g["未預期的斷線,請聯繫Graphen"],{code:t,reason:s})}})}reconnect(){this.onDestroy(),this.destorySub=new r.Subject,this.start()}flushMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected&&void 0!==this.socket;){const e=this.messageQueue.shift();e&&this.socket.send(e)}}send(e){let t=this.cloudToObj(e);if(t&&t.signal&&"audio"===t.signal&&"pcm"===t.command&&(f.info("AudioSocketProxy, payload=",t),this.isConnected&&void 0!==this.socket))try{const e=t.content,s=Buffer.allocUnsafe(2*e.length);for(let t=0;t<e.length;t++)s.writeInt16LE(e[t],2*t);this.socket.send(s)}catch(e){f.error(e)}}cloudToObj(e){try{return JSON.parse(e)}catch(e){f.error("message transfer fail",e)}}onClose(){this.socket?.close(O.MANUAL_CLOSE)}onDestroy(){this.destorySub.next(),this.destorySub.complete()}}class A{socket;messageSub;linkStartSub;destorySub;closeSub;get message(){return this.messageSub.asObservable()}get close(){return this.closeSub.asObservable()}get linkStart(){return this.linkStartSub.asObservable()}messageQueue=[];isConnected;constructor(){this.isConnected=!1,this.messageSub=new r.Subject,this.linkStartSub=new r.Subject,this.closeSub=new r.Subject,this.destorySub=new r.Subject}url="ws://localhost:8081";start(){this.socket=new c(this.url,{autoPong:!0}),r.fromEvent(this.socket,"open").pipe(r.takeUntil(this.destorySub)).subscribe(()=>{this.isConnected=!0,f.code(g["啟動服務"],"proxy"),this.flushMessageQueue(),this.linkStartSub.next()}),r.fromEvent(this.socket,"message").pipe(r.takeUntil(this.destorySub)).subscribe(e=>{const{data:t}=e;this.messageSub.next(t)}),r.fromEvent(this.socket,"error").pipe(r.takeUntil(this.destorySub)).subscribe(e=>{const{error:t}=e;f.error("Proxy has some problem",t)}),r.fromEvent(this.socket,"close").pipe(r.takeUntil(this.destorySub)).subscribe(e=>{this.isConnected=!1;const{code:t,reason:s}=e;switch(t){case O.MANUAL_CLOSE:f.code(g["無副作用的關閉連線"]);break;case O.WS_5000_NORAML_CLOSURE:case O.MDN_NORMAL_CLOSURE:case O.MDN_GOING_AWAY:this.closeSub.next("close"),f.code(g["安全的關閉連線"]);break;case O.MDN_NO_STATUS_RECEIVED:case O.MDN_ABNORMAL_CLOSURE:this.closeSub.next("close"),f.code(g["與雲端的服務中斷"],{code:t,reason:s});break;case O.WS_5001_UNAUTHORIZED:case O.WS_5002_LICENSE_EXPIRED:this.closeSub.next("no_permissions"),f.code(g["沒有授權,請聯繫Graphen"]);break;case O.WS_5003_TOKEN_EXPIRED:this.closeSub.next("reconnect"),f.code(g["自動重新連線連端服務"]);break;default:this.closeSub.next("close"),f.code(g["未預期的斷線,請聯繫Graphen"],{code:t,reason:s})}})}reconnect(){this.onDestroy(),this.destorySub=new r.Subject,this.start()}flushMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected&&void 0!==this.socket;){const e=this.messageQueue.shift();e&&this.socket.send(e)}}send(e){let t=this.cloudToObj(e);if(t&&t.signal&&"audio"===t.signal&&"interrupted"===t.command&&(f.info("AudioInterruptSocketProxy, payload=",t),this.isConnected&&void 0!==this.socket))try{this.socket.send(t.command)}catch(e){f.error(e)}}cloudToObj(e){try{return JSON.parse(e)}catch(e){f.error("message transfer fail",e)}}onClose(){this.socket?.close(O.MANUAL_CLOSE)}onDestroy(){this.destorySub.next(),this.destorySub.complete()}}class w{next(e,t,...o){const i=`log_${s().format("yyyy-MM-DD")}.txt`,r=N.addPath(N.appFolder,i);try{const s=o.reduce((e,t)=>{switch(typeof t){case"string":case"number":case"bigint":return`${e} ${t.toString()}`;case"boolean":return`${e} ${t?"true":"false"}`;case"object":try{return`${e} ${JSON.stringify(t)}`}catch(t){return e}case"symbol":case"undefined":case"function":return`${e} [${typeof t}]`}},"");a.appendFileSync(r,`LOG(${e})__${t}__::${s}${N.EOL}`,{encoding:"utf8"})}catch(e){}}}class M{config;stroage;apiProxy;chat;udpProxy;audioProxy;audioIntrProxy;isStart;channelMap;destorySub;access_token;eyeBallUdp;get accessToken(){return this.access_token}constructor(e,t){this.config=e,this.stroage=t,this.isStart=!1,this.destorySub=new r.Subject,this.channelMap=new Map,this.access_token=t.getItemSync(d),this.apiProxy=new m(this.config.endPoint.api),f.code(g["指定模組初始化完成"],"api"),this.chat=new y(this.config),f.code(g["指定模組初始化完成"],"chat"),this.udpProxy=new R(this.config),f.code(g["指定模組初始化完成"],"udp"),this.audioProxy=new C,f.code(g["指定模組初始化完成"],"audio"),this.audioIntrProxy=new A,f.code(g["指定模組初始化完成"],"audio intr"),this.eyeBallUdp=e.eyeTrackEnable?new l.Client("127.0.0.1",6745):void 0,this.openChannel=this.openChannel.bind(this)}async start(){if(this.isStart)throw new Error(e["重複初始化"]);this.isStart=!0,await this.replaceAccessToken(),this.chat.memberChange.pipe(r.takeUntil(this.destorySub)).subscribe(({type:e,socket:s})=>{switch(e){case"in":{const e=new D,i=new r.Subject,n=(o=s.handshake.query.uuid,t.isArray(o)?t.get(o,"[0]",void 0):o??void 0);void 0===n?(this.getProjectList().then(e=>{s.emit("list",e)}),r.fromEvent(s,"uuid").pipe(r.take(1),r.takeUntil(i)).subscribe(t=>{this.openChannel(t,s,e,i)})):this.openChannel(n,s,e,i),this.channelMap.set(s.id,()=>{i.next(),i.complete()});break}case"out":this.channelMap.has(s.id)&&(this.channelMap.get(s.id)(),this.channelMap.delete(s.id))}var o}),this.chat.start(),f.code(g["啟動服務"],"chat"),this.udpProxy.start(),f.code(g["啟動服務"],"udp")}async replaceAccessToken(){const e=await this.apiProxy.getAccessToken(this.config.license,this.access_token);return this.access_token=e,this.stroage.setItemSync(d,e),e}async getProjectList(){return await this.apiProxy.getProjectList(this.config.license)}getProxySocketURL(e){return`${this.config.endPoint.socket}/v1/chat/project/${this.accessToken}/${e}`}openChannel(e,s,i,n){r.fromEvent(s,"cloud").pipe(r.takeUntil(n)).subscribe(e=>{i.send(e)}),r.fromEvent(s,"face").pipe(r.takeUntil(n)).subscribe(e=>{const s=e,r=null!==s;if(r&&void 0!==this.eyeBallUdp){const{x:e,y:i}=function(e,s){const{maxX:i,maxY:r,minX:n,minY:c}=t.assign({maxX:25,minX:-25,maxY:50,minY:-50},s),a=o.abs(i)+o.abs(n),h=o.abs(r)+o.abs(c),{clientHeight:u,clientWidth:l,originX:d,originY:S,width:b,height:g}=e,p=o.matrix([[a/l,0,n],[0,h/u,c],[0,0,1]]),E=d+b/2,_=u-(S+g/2),f=E>l?l:E<0?0:E,y=_>u?u:_<0?0:_,m=o.matrix([[f],[y],[1]]),O=o.multiply(p,m);return{x:O.get([0,0]),y:O.get([1,0])}}(s);this.eyeBallUdp.send(-1*e,i,e=>{null!=e&&f.error("eye track error:",e)})}i.sendToCloud({request:"face_detect",content:r})}),i.message.pipe(r.takeUntil(n)).subscribe(e=>{s.emit("cloud",e),this.udpProxy.send(e),this.audioProxy.send(e),this.audioIntrProxy.send(e)}),i.close.pipe(r.takeUntil(n)).subscribe(async t=>{switch(s.emit("channel",t),t){case"close":case"no_permissions":i.onDestroy();break;case"reconnect":await this.replaceAccessToken(),i.reconnect(this.getProxySocketURL(e))}}),i.linkStart.pipe(r.takeUntil(n)).subscribe(()=>{s.emit("channel","open")}),n.subscribe(()=>{i.onClose(),this.audioProxy.onClose(),this.audioIntrProxy.onClose()}),i.start(this.getProxySocketURL(e)),this.audioProxy.start(),this.audioIntrProxy.start()}onDestroy(){this.apiProxy.onDestroy(),this.chat.onDestroy(),this.udpProxy.onDestroy(),this.destorySub.next(),this.destorySub.complete(),this.eyeBallUdp?.close(),f.code(g["服務結束"])}}exports.aiiaCore=function(s){if(S){if(void 0===t.get(s,"license",void 0))throw new Error(e["未提供憑證"]);!function(e){const{info:t,error:s,warn:o,debug:i,fatal:r,code:n}=function(e){if(void 0===e||"all"===e)return{code:!0,error:!0,warn:!0,info:!0,debug:!0,fatal:!0};if("none"===e)return{error:!1,code:!1,warn:!1,info:!1,debug:!1,fatal:!1};if("boolean"==typeof e)return{code:e,error:e,warn:e,info:e,debug:e,fatal:e};{const t=new Set(e);return{code:t.has("code"),debug:t.has("debug"),fatal:t.has("fatal"),error:t.has("error"),warn:t.has("warn"),info:t.has("info")}}}(e);return n||(p.code=()=>{}),i||(p.debug=()=>{}),t||(p.info=()=>{}),o||(p.warn=()=>{}),s||(p.error=()=>{}),r||(p.fatal=()=>{}),_}(t.get(s,"debug",!0))(new w),f.code(g["開始初始化必要模組"]);const o=new b(t.assign({},s));f.code(g["指定模組初始化完成"],"config");const i=new k;f.code(g["指定模組初始化完成"],"storage");const r=new M(o,i);return f.code(g["指定模組初始化完成"],"core"),r.start(),f.code(g["啟動服務"]),()=>{r.onDestroy()}}throw new Error(e["環境錯誤(nodejs)"])};
|
package/dist/node.d.ts
CHANGED
|
@@ -138,6 +138,14 @@ declare interface InitOptions {
|
|
|
138
138
|
user?: boolean | number;
|
|
139
139
|
aiia?: boolean | number;
|
|
140
140
|
};
|
|
141
|
+
/**
|
|
142
|
+
* [zh]
|
|
143
|
+
* 啟動眼球追蹤
|
|
144
|
+
*
|
|
145
|
+
* [en]
|
|
146
|
+
*
|
|
147
|
+
*/
|
|
148
|
+
eyeTrackEnable?: boolean;
|
|
141
149
|
}
|
|
142
150
|
|
|
143
151
|
declare type LoggerLevel = "info" | "error" | "warn" | "debug" | "fatal" | "code";
|
package/dist/node.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{assign as e,forEach as t,get as s,map as o,omit as r,isArray as i}from"lodash-es";import n from"moment";import{Server as c}from"socket.io";import{Subject as a,fromEvent as h,takeUntil as u,take as l}from"rxjs";import d from"axios";import S from"ws";import b from"fs";import p from"os";import _ from"path";import{Client as g}from"node-osc";var f;!function(e){e["網絡錯誤"]="ERROR CODE: 500",e["環境錯誤(browser)"]="ERROR CODE: 1001",e["Worklet模組載入失敗"]="ERROR CODE: 1002",e["未獲得媒體裝置權限"]="ERROR CODE: 1003",e["實例已摧毀"]="ERROR CODE: 1004",e["環境錯誤(nodejs)"]="ERROR CODE: 2001",e["未提供憑證"]="ERROR CODE: 2002",e["獲取權杖失敗"]="ERROR CODE: 2003",e["沒有可用專案"]="ERROR CODE: 2004",e["重複初始化"]="ERROR CODE: 2005"}(f||(f={}));const E="access_token",y="undefined"!=typeof process&&null!=process.versions&&null!=process.versions.node;class m{config;get webserver(){return this.config.webserver}get environment(){return this.config.env}get license(){return this.config.license??""}get port(){return function(e,t){const s=t??NaN;if(e){const t=parseInt(e);return isNaN(t)?s:t}return s}(process.env.PORT,this.config.port??3e3)}get ws_url(){return this.config.ws_url??""}get worklet_url(){return this.config.worklet_url??""}get project(){const{project:t}=e({},this.config);return void 0===t?{specific:!1}:"string"==typeof t?{name:t,id:t,specific:!1}:e({},t,{specific:!0})}get endPoint(){return this.environment,{api:"https://aiia-content-management-dev-21193779403.asia-east1.run.app",socket:"wss://graphen-agentic-workflow-dev-21193779403.asia-east1.run.app"}}get debug(){return this.config.debug??!0}get mediaStream(){return this.config.mediaStream}get chunkTimeInSeconds(){return"number"==typeof this.config.chunkTimeInSeconds&&this.config.chunkTimeInSeconds>0?this.config.chunkTimeInSeconds:.3}get llmSampleRate(){return"number"==typeof this.config.llmSampleRate&&this.config.llmSampleRate>0?this.config.llmSampleRate:16e3}get faceDetection(){return e({perSecond:3,confidence:80},this.config.faceDetection)}get autoClearSubtitle(){const{user:t,aiia:s}=e({},this.config.autoClearSubtitle);let o=5e3,r=5e3;return"number"==typeof t?o=t>=0?t:o:!1===t&&(o=NaN),"number"==typeof s?r=s>=0?s:r:!1===s&&(r=NaN),{userDelayTime:o,aiiaDelayTime:r}}constructor(e){this.config=e}}var O;!function(e){e["通道、雲端服務、麥克風都已就緒"]="CODE: 1000",e["未取得媒體裝置權限,請重新設定或忽略此訊息"]="CODE: 1001",e["請訂閱專案列表"]="CODE: 1002",e["初始化必要依賴"]="CODE: 1010",e["指定依賴已完成"]="CODE: 1011",e["啟動SDK"]="CODE: 1012",e["結束SDK"]="CODE: 1013",e["安全的關閉連線"]="CODE: 2000",e["無副作用的關閉連線"]="CODE: 2001",e["與雲端的服務中斷"]="CODE: 2002",e["沒有授權,請聯繫Graphen"]="CODE: 2003",e["自動重新連線連端服務"]="CODE: 2004",e["未預期的斷線,請聯繫Graphen"]="CODE: 2005",e["開始初始化必要模組"]="CODE: 2010",e["指定模組初始化完成"]="CODE: 2011",e["啟動服務"]="CODE: 2012",e["服務結束"]="CODE: 2013"}(O||(O={}));const D={code:console.log,debug:console.log,info:console.log,warn:console.warn,error:console.error,fatal:console.error},N=[];function R(e){return N.push(e),R}const C=new Proxy(D,{get(e,s,o){if("string"==typeof s)switch(s){case"debug":case"info":case"error":case"warn":case"fatal":case"code":return(...o)=>{const r=n().format("yyyy-MM-DD[T]HH:mm:ss");t(N,e=>{e.next(s,r,...o)}),e[s](`[Aiia::${s}_${r}_]`,...o)};default:return}},set:(e,t,s,o)=>!0});class A{config;server;memberSub;get port(){return this.config.port}get webserver(){return this.config.webserver}get memberChange(){return this.memberSub.asObservable()}constructor(e){this.config=e,this.memberSub=new a}start(){if(this.server=new c(this.webserver,{cors:{origin:"*"}}),this.server.on("connection",e=>{this.memberSub.next({type:"in",socket:e}),C.debug("client on",e.id),e.on("disconnect",t=>{this.memberSub.next({type:"out",socket:e}),C.debug("client off",t)})}),void 0===this.webserver){const e=this.port;this.server.listen(e),C.info("Websocket server run on",e)}else C.info("Websocket server rely your webserver.")}onDestroy(){this.server&&this.server.close()}}class k{instance;controller;constructor(e){this.controller=new AbortController,this.instance=d.create({baseURL:e,signal:this.controller.signal})}async getAccessToken(e,t){const o={license_number:e,token_value:t??""},r=await this.instance.post("/api/v1/license/agent_token",o).then(e=>s(e.data,"token_value","")).catch(()=>null);if(null===r)throw new Error(f["網絡錯誤"]);if(""===r)throw new Error(f["獲取權杖失敗"]);return r}async getProjectList(e){const t=await this.instance.post("/api/v1/license/projects",{license_number:e}).then(e=>o(s(e,"data.projects",[]),({id:e,sub_project_name:t})=>({id:e,name:t}))).catch(e=>null);if(null===t)throw new Error(f["網絡錯誤"]);if(0===t.length)throw new Error(f["沒有可用專案"]);return t}onDestroy(){this.controller.abort()}}var w;!function(e){e[e.MDN_NORMAL_CLOSURE=1e3]="MDN_NORMAL_CLOSURE",e[e.MDN_GOING_AWAY=1001]="MDN_GOING_AWAY",e[e.MDN_PROTOCOL_ERROR=1002]="MDN_PROTOCOL_ERROR",e[e.MDN_UNSUPPORTED_DATA=1003]="MDN_UNSUPPORTED_DATA",e[e.MDN_RESERVED_1004=1004]="MDN_RESERVED_1004",e[e.MDN_NO_STATUS_RECEIVED=1005]="MDN_NO_STATUS_RECEIVED",e[e.MDN_ABNORMAL_CLOSURE=1006]="MDN_ABNORMAL_CLOSURE",e[e.MDN_INVALID_FRAME_PAYLOAD=1007]="MDN_INVALID_FRAME_PAYLOAD",e[e.MDN_POLICY_VIOLATION=1008]="MDN_POLICY_VIOLATION",e[e.MDN_MESSAGE_TOO_BIG=1009]="MDN_MESSAGE_TOO_BIG",e[e.MDN_MANDATORY_EXTENSION=1010]="MDN_MANDATORY_EXTENSION",e[e.MDN_INTERNAL_ERROR=1011]="MDN_INTERNAL_ERROR",e[e.MDN_SERVICE_RESTART=1012]="MDN_SERVICE_RESTART",e[e.MDN_TRY_AGAIN_LATER=1013]="MDN_TRY_AGAIN_LATER",e[e.MDN_BAD_GATEWAY=1014]="MDN_BAD_GATEWAY",e[e.MDN_TLS_HANDSHAKE=1015]="MDN_TLS_HANDSHAKE",e[e.WHEN_BROWSER_CLOSE=4001]="WHEN_BROWSER_CLOSE",e[e.MANUAL_CLOSE=4002]="MANUAL_CLOSE",e[e.WS_5000_NORAML_CLOSURE=4100]="WS_5000_NORAML_CLOSURE",e[e.WS_5001_UNAUTHORIZED=4101]="WS_5001_UNAUTHORIZED",e[e.WS_5002_LICENSE_EXPIRED=4102]="WS_5002_LICENSE_EXPIRED",e[e.WS_5003_TOKEN_EXPIRED=4103]="WS_5003_TOKEN_EXPIRED"}(w||(w={}));class M{socket;messageSub;linkStartSub;destorySub;closeSub;get message(){return this.messageSub.asObservable()}get close(){return this.closeSub.asObservable()}get linkStart(){return this.linkStartSub.asObservable()}messageQueue=[];isConnected;constructor(){this.isConnected=!1,this.messageSub=new a,this.linkStartSub=new a,this.closeSub=new a,this.destorySub=new a}start(e){this.socket=new S(e,{autoPong:!0}),h(this.socket,"open").pipe(u(this.destorySub)).subscribe(()=>{this.isConnected=!0,C.code(O["啟動服務"],"proxy"),this.flushMessageQueue(),this.linkStartSub.next()}),h(this.socket,"message").pipe(u(this.destorySub)).subscribe(e=>{const{data:t}=e;this.messageSub.next(t)}),h(this.socket,"error").pipe(u(this.destorySub)).subscribe(e=>{const{error:t}=e;C.error("Proxy has some problem",t)}),h(this.socket,"close").pipe(u(this.destorySub)).subscribe(e=>{this.isConnected=!1;const{code:t,reason:s,type:o,wasClean:r}=e;switch(t){case w.WHEN_BROWSER_CLOSE:C.code(O["無副作用的關閉連線"]);break;case w.MDN_NORMAL_CLOSURE:case w.MDN_GOING_AWAY:this.closeSub.next("close"),C.code(O["安全的關閉連線"]);break;case w.MDN_NO_STATUS_RECEIVED:case w.MDN_ABNORMAL_CLOSURE:this.closeSub.next("close"),C.code(O["與雲端的服務中斷"],{code:t,reason:s,type:o,wasClean:r});break;case w.WS_5001_UNAUTHORIZED:case w.WS_5002_LICENSE_EXPIRED:this.closeSub.next("no_permissions"),C.code(O["沒有授權,請聯繫Graphen"]);break;case w.WS_5000_NORAML_CLOSURE:case w.WS_5003_TOKEN_EXPIRED:this.closeSub.next("reconnect"),C.code(O["自動重新連線連端服務"]);break;default:this.closeSub.next("close"),C.code(O["未預期的斷線,請聯繫Graphen"],{code:t,reason:s,type:o,wasClean:r})}})}reconnect(e){this.onDestroy(),this.destorySub=new a,this.start(e)}flushMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected&&void 0!==this.socket;){const e=this.messageQueue.shift();e&&this.socket.send(e,e=>{e&&C.error("send message fail",e?.message,e)})}}send(e){this.isConnected&&void 0!==this.socket?this.socket.send(e,e=>{e&&C.error("send message fail",e?.message,e)}):this.messageQueue.push(e)}onClose(){this.socket?.close(w.WHEN_BROWSER_CLOSE)}onDestroy(){this.destorySub.next(),this.destorySub.complete()}}const L=new class{AppName;platform;isMAC;isWIN;isLINUX;saveFolder;homedir;appFolder;EOL;constructor(e){switch(this.AppName=e,this.platform=process.platform,this.homedir=p.homedir(),this.EOL=p.EOL,this.platform){case"darwin":this.isMAC=!0,this.isWIN=!1,this.isLINUX=!1,this.saveFolder=_.join(this.homedir,"Library","Application Support");break;case"win32":this.isMAC=!1,this.isWIN=!0,this.isLINUX=!1,this.saveFolder=process.env.APPDATA||_.join(this.homedir,"AppData","Roaming");break;case"linux":this.isMAC=!1,this.isWIN=!1,this.isLINUX=!0,this.saveFolder=process.env.XDG_CONFIG_HOME||_.join(this.homedir,".config");break;default:console.log(`當前系統是未知的平台: ${this.platform}`),this.isMAC=!1,this.isWIN=!1,this.isLINUX=!1,this.saveFolder=this.homedir}this.appFolder=_.join(this.saveFolder,this.AppName),this.folderCheck(this.appFolder)}addPath(...e){return _.join(...e)}folderCheck(e){b.mkdirSync(e,{recursive:!0})}fileCheck(e){b.existsSync(e)||b.writeFileSync(e,"",{encoding:"utf8"})}}("aiia-sdk");class I{type="node";filePath;fileName;constructor(){this.fileName="storage.json",this.filePath=L.addPath(L.appFolder,this.fileName),L.fileCheck(this.filePath)}getFileDataSync(){const e=b.readFileSync(this.filePath,"utf8");try{return JSON.parse(e)}catch(e){return{}}}setFileDataSync(e){try{const t=JSON.stringify(e);b.writeFileSync(this.filePath,t,"utf8")}catch(e){}}async getFileData(){return new Promise(e=>{b.readFile(this.filePath,"utf8",(t,s)=>{if(t)e({});else try{e(JSON.parse(s))}catch(t){e({})}})})}async setFileData(e){return new Promise(t=>{try{const s=JSON.stringify(e);b.writeFile(this.filePath,s,"utf8",e=>{t()})}catch(e){}})}async getItem(e){return(await this.getFileData())[e]??null}async setItem(e,t){const s=await this.getFileData();s[e]=t,await this.setFileData(s)}async removeItem(e){const t=await this.getFileData(),s=r(t,e);await this.setFileData(s)}async clear(){await this.setFileData({})}getItemSync(e){return this.getFileDataSync()[e]??null}setItemSync(e,t){const s=this.getFileDataSync();s[e]=t,this.setFileDataSync(s)}removeItemSync(e){const t=r(this.getFileDataSync(),e);this.setFileDataSync(t)}clearSync(){this.setFileDataSync({})}}class P{config;constructor(e){this.config=e,C.info("UEProxy, config=",e)}start(){C.info("UEProxy, start proxy")}send(e){let t=this.cloudToObj(e);if(t&&t.signal&&"osc"===t.signal){C.info("UEProxy, payload=",t);try{let e=t.content;const s=new g(e.host,e.port);C.debug("UEProxy, client open to port "+e.port),s.send(e.message,e=>{e&&C.error(e),s.close(),C.debug("UEProxy, client closed")})}catch(e){C.error(e)}}}cloudToObj(e){try{return JSON.parse(e)}catch(e){C.error("message transfer fail",e)}}onDestroy(){C.info("UEProxy, destroy proxy")}}class x{socket;messageSub;linkStartSub;destorySub;closeSub;get message(){return this.messageSub.asObservable()}get close(){return this.closeSub.asObservable()}get linkStart(){return this.linkStartSub.asObservable()}messageQueue=[];isConnected;constructor(){this.isConnected=!1,this.messageSub=new a,this.linkStartSub=new a,this.closeSub=new a,this.destorySub=new a}url="ws://localhost:8080";start(){this.socket=new S(this.url,{autoPong:!0}),h(this.socket,"open").pipe(u(this.destorySub)).subscribe(()=>{this.isConnected=!0,C.code(O["啟動服務"],"proxy"),this.flushMessageQueue(),this.linkStartSub.next()}),h(this.socket,"message").pipe(u(this.destorySub)).subscribe(e=>{const{data:t}=e;this.messageSub.next(t)}),h(this.socket,"error").pipe(u(this.destorySub)).subscribe(e=>{const{error:t}=e;C.error("Proxy has some problem",t)}),h(this.socket,"close").pipe(u(this.destorySub)).subscribe(e=>{this.isConnected=!1;const{code:t,reason:s}=e;switch(t){case w.MANUAL_CLOSE:C.code(O["無副作用的關閉連線"]);break;case w.WS_5000_NORAML_CLOSURE:case w.MDN_NORMAL_CLOSURE:case w.MDN_GOING_AWAY:this.closeSub.next("close"),C.code(O["安全的關閉連線"]);break;case w.MDN_NO_STATUS_RECEIVED:case w.MDN_ABNORMAL_CLOSURE:this.closeSub.next("close"),C.code(O["與雲端的服務中斷"],{code:t,reason:s});break;case w.WS_5001_UNAUTHORIZED:case w.WS_5002_LICENSE_EXPIRED:this.closeSub.next("no_permissions"),C.code(O["沒有授權,請聯繫Graphen"]);break;case w.WS_5003_TOKEN_EXPIRED:this.closeSub.next("reconnect"),C.code(O["自動重新連線連端服務"]);break;default:this.closeSub.next("close"),C.code(O["未預期的斷線,請聯繫Graphen"],{code:t,reason:s})}})}reconnect(){this.onDestroy(),this.destorySub=new a,this.start()}flushMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected&&void 0!==this.socket;){const e=this.messageQueue.shift();e&&this.socket.send(e)}}send(e){let t=this.cloudToObj(e);if(t&&t.signal&&"audio"===t.signal&&"pcm"===t.command&&(C.info("AudioSocketProxy, payload=",t),this.isConnected&&void 0!==this.socket))try{const e=t.content,s=Buffer.allocUnsafe(2*e.length);for(let t=0;t<e.length;t++)s.writeInt16LE(e[t],2*t);this.socket.send(s)}catch(e){C.error(e)}}cloudToObj(e){try{return JSON.parse(e)}catch(e){C.error("message transfer fail",e)}}onClose(){this.socket?.close(w.MANUAL_CLOSE)}onDestroy(){this.destorySub.next(),this.destorySub.complete()}}class T{socket;messageSub;linkStartSub;destorySub;closeSub;get message(){return this.messageSub.asObservable()}get close(){return this.closeSub.asObservable()}get linkStart(){return this.linkStartSub.asObservable()}messageQueue=[];isConnected;constructor(){this.isConnected=!1,this.messageSub=new a,this.linkStartSub=new a,this.closeSub=new a,this.destorySub=new a}url="ws://localhost:8081";start(){this.socket=new S(this.url,{autoPong:!0}),h(this.socket,"open").pipe(u(this.destorySub)).subscribe(()=>{this.isConnected=!0,C.code(O["啟動服務"],"proxy"),this.flushMessageQueue(),this.linkStartSub.next()}),h(this.socket,"message").pipe(u(this.destorySub)).subscribe(e=>{const{data:t}=e;this.messageSub.next(t)}),h(this.socket,"error").pipe(u(this.destorySub)).subscribe(e=>{const{error:t}=e;C.error("Proxy has some problem",t)}),h(this.socket,"close").pipe(u(this.destorySub)).subscribe(e=>{this.isConnected=!1;const{code:t,reason:s}=e;switch(t){case w.MANUAL_CLOSE:C.code(O["無副作用的關閉連線"]);break;case w.WS_5000_NORAML_CLOSURE:case w.MDN_NORMAL_CLOSURE:case w.MDN_GOING_AWAY:this.closeSub.next("close"),C.code(O["安全的關閉連線"]);break;case w.MDN_NO_STATUS_RECEIVED:case w.MDN_ABNORMAL_CLOSURE:this.closeSub.next("close"),C.code(O["與雲端的服務中斷"],{code:t,reason:s});break;case w.WS_5001_UNAUTHORIZED:case w.WS_5002_LICENSE_EXPIRED:this.closeSub.next("no_permissions"),C.code(O["沒有授權,請聯繫Graphen"]);break;case w.WS_5003_TOKEN_EXPIRED:this.closeSub.next("reconnect"),C.code(O["自動重新連線連端服務"]);break;default:this.closeSub.next("close"),C.code(O["未預期的斷線,請聯繫Graphen"],{code:t,reason:s})}})}reconnect(){this.onDestroy(),this.destorySub=new a,this.start()}flushMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected&&void 0!==this.socket;){const e=this.messageQueue.shift();e&&this.socket.send(e)}}send(e){let t=this.cloudToObj(e);if(t&&t.signal&&"audio"===t.signal&&"interrupted"===t.command&&(C.info("AudioInterruptSocketProxy, payload=",t),this.isConnected&&void 0!==this.socket))try{this.socket.send(t.command)}catch(e){C.error(e)}}cloudToObj(e){try{return JSON.parse(e)}catch(e){C.error("message transfer fail",e)}}onClose(){this.socket?.close(w.MANUAL_CLOSE)}onDestroy(){this.destorySub.next(),this.destorySub.complete()}}class v{next(e,t,...s){const o=`log_${n().format("yyyy-MM-DD")}.txt`,r=L.addPath(L.appFolder,o);try{const o=s.reduce((e,t)=>{switch(typeof t){case"string":case"number":case"bigint":return`${e} ${t.toString()}`;case"boolean":return`${e} ${t?"true":"false"}`;case"object":try{return`${e} ${JSON.stringify(t)}`}catch(t){return e}case"symbol":case"undefined":case"function":return`${e} [${typeof t}]`}},"");b.appendFileSync(r,`LOG(${e})__${t}__::${o}${L.EOL}`,{encoding:"utf8"})}catch(e){}}}class U{config;stroage;apiProxy;chat;udpProxy;audioProxy;audioIntrProxy;isStart;channelMap;destorySub;access_token;get accessToken(){return this.access_token}constructor(e,t){this.config=e,this.stroage=t,this.isStart=!1,this.destorySub=new a,this.channelMap=new Map,this.access_token=t.getItemSync(E),this.apiProxy=new k(this.config.endPoint.api),C.code(O["指定模組初始化完成"],"api"),this.chat=new A(this.config),C.code(O["指定模組初始化完成"],"chat"),this.udpProxy=new P(this.config),C.code(O["指定模組初始化完成"],"udp"),this.audioProxy=new x,C.code(O["指定模組初始化完成"],"audio"),this.audioIntrProxy=new T,C.code(O["指定模組初始化完成"],"audio intr"),this.openChannel=this.openChannel.bind(this)}async start(){if(this.isStart)throw new Error(f["重複初始化"]);this.isStart=!0,await this.replaceAccessToken(),this.chat.memberChange.pipe(u(this.destorySub)).subscribe(({type:e,socket:t})=>{switch(e){case"in":{const e=new M,r=new a,n=(o=t.handshake.query.uuid,i(o)?s(o,"[0]",void 0):o??void 0);void 0===n?(this.getProjectList().then(e=>{t.emit("list",e)}),h(t,"uuid").pipe(l(1),u(r)).subscribe(s=>{this.openChannel(s,t,e,r)})):this.openChannel(n,t,e,r),this.channelMap.set(t.id,()=>{r.next(),r.complete()});break}case"out":this.channelMap.has(t.id)&&(this.channelMap.get(t.id)(),this.channelMap.delete(t.id))}var o}),this.chat.start(),C.code(O["啟動服務"],"chat"),this.udpProxy.start(),C.code(O["啟動服務"],"udp")}async replaceAccessToken(){const e=await this.apiProxy.getAccessToken(this.config.license,this.access_token);return this.access_token=e,this.stroage.setItemSync(E,e),e}async getProjectList(){return await this.apiProxy.getProjectList(this.config.license)}getProxySocketURL(e){return`${this.config.endPoint.socket}/v1/chat/project/${this.accessToken}/${e}`}openChannel(e,t,s,o){h(t,"cloud").pipe(u(o)).subscribe(e=>{s.send(e)}),s.message.pipe(u(o)).subscribe(e=>{t.emit("cloud",e),this.udpProxy.send(e),this.audioProxy.send(e),this.audioIntrProxy.send(e)}),s.close.pipe(u(o)).subscribe(async o=>{switch(t.emit("channel",o),o){case"close":case"no_permissions":s.onDestroy();break;case"reconnect":await this.replaceAccessToken(),s.reconnect(this.getProxySocketURL(e))}}),s.linkStart.pipe(u(o)).subscribe(()=>{t.emit("channel","open")}),o.subscribe(()=>{s.onClose(),this.audioProxy.onClose(),this.audioIntrProxy.onClose()}),s.start(this.getProxySocketURL(e)),this.audioProxy.start(),this.audioIntrProxy.start()}onDestroy(){this.apiProxy.onDestroy(),this.chat.onDestroy(),this.udpProxy.onDestroy(),this.destorySub.next(),this.destorySub.complete(),C.code(O["服務結束"])}}function W(t){if(y){if(void 0===s(t,"license",void 0))throw new Error(f["未提供憑證"]);!function(e){const{info:t,error:s,warn:o,debug:r,fatal:i,code:n}=function(e){if(void 0===e||"all"===e)return{code:!0,error:!0,warn:!0,info:!0,debug:!0,fatal:!0};if("none"===e)return{error:!1,code:!1,warn:!1,info:!1,debug:!1,fatal:!1};if("boolean"==typeof e)return{code:e,error:e,warn:e,info:e,debug:e,fatal:e};{const t=new Set(e);return{code:t.has("code"),debug:t.has("debug"),fatal:t.has("fatal"),error:t.has("error"),warn:t.has("warn"),info:t.has("info")}}}(e);return n||(D.code=()=>{}),r||(D.debug=()=>{}),t||(D.info=()=>{}),o||(D.warn=()=>{}),s||(D.error=()=>{}),i||(D.fatal=()=>{}),R}(s(t,"debug",!0))(new v),C.code(O["開始初始化必要模組"]);const o=new m(e({},t));C.code(O["指定模組初始化完成"],"config");const r=new I;C.code(O["指定模組初始化完成"],"storage");const i=new U(o,r);return C.code(O["指定模組初始化完成"],"core"),i.start(),C.code(O["啟動服務"]),()=>{i.onDestroy()}}throw new Error(f["環境錯誤(nodejs)"])}export{W as aiiaCore};
|
|
1
|
+
import{assign as e,forEach as t,get as s,map as o,omit as i,isArray as r}from"lodash-es";import n from"moment";import{abs as c,matrix as a,multiply as h}from"mathjs";import{Server as l}from"socket.io";import{Subject as u,fromEvent as d,takeUntil as S,take as b}from"rxjs";import p from"axios";import _ from"ws";import g from"fs";import f from"os";import E from"path";import{Client as y}from"node-osc";var m;!function(e){e["網絡錯誤"]="ERROR CODE: 500",e["環境錯誤(browser)"]="ERROR CODE: 1001",e["Worklet模組載入失敗"]="ERROR CODE: 1002",e["未獲得媒體裝置權限"]="ERROR CODE: 1003",e["實例已摧毀"]="ERROR CODE: 1004",e["環境錯誤(nodejs)"]="ERROR CODE: 2001",e["未提供憑證"]="ERROR CODE: 2002",e["獲取權杖失敗"]="ERROR CODE: 2003",e["沒有可用專案"]="ERROR CODE: 2004",e["重複初始化"]="ERROR CODE: 2005"}(m||(m={}));const O="access_token",D="undefined"!=typeof process&&null!=process.versions&&null!=process.versions.node;class N{config;get webserver(){return this.config.webserver}get environment(){return this.config.env}get license(){return this.config.license??""}get port(){return function(e,t){const s=t??NaN;if(e){const t=parseInt(e);return isNaN(t)?s:t}return s}(process.env.PORT,this.config.port??3e3)}get ws_url(){return this.config.ws_url??""}get worklet_url(){return this.config.worklet_url??""}get project(){const{project:t}=e({},this.config);return void 0===t?{specific:!1}:"string"==typeof t?{name:t,id:t,specific:!1}:e({},t,{specific:!0})}get endPoint(){return this.environment,{api:"https://aiia-content-management-dev-21193779403.asia-east1.run.app",socket:"wss://graphen-agentic-workflow-dev-21193779403.asia-east1.run.app"}}get debug(){return this.config.debug??!0}get mediaStream(){return this.config.mediaStream}get chunkTimeInSeconds(){return"number"==typeof this.config.chunkTimeInSeconds&&this.config.chunkTimeInSeconds>0?this.config.chunkTimeInSeconds:.3}get llmSampleRate(){return"number"==typeof this.config.llmSampleRate&&this.config.llmSampleRate>0?this.config.llmSampleRate:16e3}get faceDetection(){return e({perSecond:3,confidence:80},this.config.faceDetection)}get autoClearSubtitle(){const{user:t,aiia:s}=e({},this.config.autoClearSubtitle);let o=5e3,i=5e3;return"number"==typeof t?o=t>=0?t:o:!1===t&&(o=NaN),"number"==typeof s?i=s>=0?s:i:!1===s&&(i=NaN),{userDelayTime:o,aiiaDelayTime:i}}get eyeTrackEnable(){return this.config.eyeTrackEnable??!1}constructor(e){this.config=e}}var R;!function(e){e["通道、雲端服務、麥克風都已就緒"]="CODE: 1000",e["未取得媒體裝置權限,請重新設定或忽略此訊息"]="CODE: 1001",e["請訂閱專案列表"]="CODE: 1002",e["初始化必要依賴"]="CODE: 1010",e["指定依賴已完成"]="CODE: 1011",e["啟動SDK"]="CODE: 1012",e["結束SDK"]="CODE: 1013",e["安全的關閉連線"]="CODE: 2000",e["無副作用的關閉連線"]="CODE: 2001",e["與雲端的服務中斷"]="CODE: 2002",e["沒有授權,請聯繫Graphen"]="CODE: 2003",e["自動重新連線連端服務"]="CODE: 2004",e["未預期的斷線,請聯繫Graphen"]="CODE: 2005",e["開始初始化必要模組"]="CODE: 2010",e["指定模組初始化完成"]="CODE: 2011",e["啟動服務"]="CODE: 2012",e["服務結束"]="CODE: 2013"}(R||(R={}));const k={code:console.log,debug:console.log,info:console.log,warn:console.warn,error:console.error,fatal:console.error},C=[];function A(e){return C.push(e),A}const w=new Proxy(k,{get(e,s,o){if("string"==typeof s)switch(s){case"debug":case"info":case"error":case"warn":case"fatal":case"code":return(...o)=>{const i=n().format("yyyy-MM-DD[T]HH:mm:ss");t(C,e=>{e.next(s,i,...o)}),e[s](`[Aiia::${s}_${i}_]`,...o)};default:return}},set:(e,t,s,o)=>!0});class M{config;server;memberSub;get port(){return this.config.port}get webserver(){return this.config.webserver}get memberChange(){return this.memberSub.asObservable()}constructor(e){this.config=e,this.memberSub=new u}start(){if(this.server=new l(this.webserver,{cors:{origin:"*"}}),this.server.on("connection",e=>{this.memberSub.next({type:"in",socket:e}),w.debug("client on",e.id),e.on("disconnect",t=>{this.memberSub.next({type:"out",socket:e}),w.debug("client off",t)})}),void 0===this.webserver){const e=this.port;this.server.listen(e),w.info("Websocket server run on",e)}else w.info("Websocket server rely your webserver.")}onDestroy(){this.server&&this.server.close()}}class L{instance;controller;constructor(e){this.controller=new AbortController,this.instance=p.create({baseURL:e,signal:this.controller.signal})}async getAccessToken(e,t){const o={license_number:e,token_value:t??""},i=await this.instance.post("/api/v1/license/agent_token",o).then(e=>s(e.data,"token_value","")).catch(()=>null);if(null===i)throw new Error(m["網絡錯誤"]);if(""===i)throw new Error(m["獲取權杖失敗"]);return i}async getProjectList(e){const t=await this.instance.post("/api/v1/license/projects",{license_number:e}).then(e=>o(s(e,"data.projects",[]),({id:e,sub_project_name:t})=>({id:e,name:t}))).catch(e=>null);if(null===t)throw new Error(m["網絡錯誤"]);if(0===t.length)throw new Error(m["沒有可用專案"]);return t}onDestroy(){this.controller.abort()}}var x;!function(e){e[e.MDN_NORMAL_CLOSURE=1e3]="MDN_NORMAL_CLOSURE",e[e.MDN_GOING_AWAY=1001]="MDN_GOING_AWAY",e[e.MDN_PROTOCOL_ERROR=1002]="MDN_PROTOCOL_ERROR",e[e.MDN_UNSUPPORTED_DATA=1003]="MDN_UNSUPPORTED_DATA",e[e.MDN_RESERVED_1004=1004]="MDN_RESERVED_1004",e[e.MDN_NO_STATUS_RECEIVED=1005]="MDN_NO_STATUS_RECEIVED",e[e.MDN_ABNORMAL_CLOSURE=1006]="MDN_ABNORMAL_CLOSURE",e[e.MDN_INVALID_FRAME_PAYLOAD=1007]="MDN_INVALID_FRAME_PAYLOAD",e[e.MDN_POLICY_VIOLATION=1008]="MDN_POLICY_VIOLATION",e[e.MDN_MESSAGE_TOO_BIG=1009]="MDN_MESSAGE_TOO_BIG",e[e.MDN_MANDATORY_EXTENSION=1010]="MDN_MANDATORY_EXTENSION",e[e.MDN_INTERNAL_ERROR=1011]="MDN_INTERNAL_ERROR",e[e.MDN_SERVICE_RESTART=1012]="MDN_SERVICE_RESTART",e[e.MDN_TRY_AGAIN_LATER=1013]="MDN_TRY_AGAIN_LATER",e[e.MDN_BAD_GATEWAY=1014]="MDN_BAD_GATEWAY",e[e.MDN_TLS_HANDSHAKE=1015]="MDN_TLS_HANDSHAKE",e[e.WHEN_BROWSER_CLOSE=4001]="WHEN_BROWSER_CLOSE",e[e.MANUAL_CLOSE=4002]="MANUAL_CLOSE",e[e.WS_5000_NORAML_CLOSURE=4100]="WS_5000_NORAML_CLOSURE",e[e.WS_5001_UNAUTHORIZED=4101]="WS_5001_UNAUTHORIZED",e[e.WS_5002_LICENSE_EXPIRED=4102]="WS_5002_LICENSE_EXPIRED",e[e.WS_5003_TOKEN_EXPIRED=4103]="WS_5003_TOKEN_EXPIRED"}(x||(x={}));class I{socket;messageSub;linkStartSub;destorySub;closeSub;get message(){return this.messageSub.asObservable()}get close(){return this.closeSub.asObservable()}get linkStart(){return this.linkStartSub.asObservable()}messageQueue=[];isConnected;constructor(){this.isConnected=!1,this.messageSub=new u,this.linkStartSub=new u,this.closeSub=new u,this.destorySub=new u}start(e){this.socket=new _(e,{autoPong:!0}),d(this.socket,"open").pipe(S(this.destorySub)).subscribe(()=>{this.isConnected=!0,w.code(R["啟動服務"],"proxy"),this.flushMessageQueue(),this.linkStartSub.next()}),d(this.socket,"message").pipe(S(this.destorySub)).subscribe(e=>{const{data:t}=e;this.messageSub.next(t)}),d(this.socket,"error").pipe(S(this.destorySub)).subscribe(e=>{const{error:t}=e;w.error("Proxy has some problem",t)}),d(this.socket,"close").pipe(S(this.destorySub)).subscribe(e=>{this.isConnected=!1;const{code:t,reason:s,type:o,wasClean:i}=e;switch(t){case x.WHEN_BROWSER_CLOSE:w.code(R["無副作用的關閉連線"]);break;case x.MDN_NORMAL_CLOSURE:case x.MDN_GOING_AWAY:this.closeSub.next("close"),w.code(R["安全的關閉連線"]);break;case x.MDN_NO_STATUS_RECEIVED:case x.MDN_ABNORMAL_CLOSURE:this.closeSub.next("close"),w.code(R["與雲端的服務中斷"],{code:t,reason:s,type:o,wasClean:i});break;case x.WS_5001_UNAUTHORIZED:case x.WS_5002_LICENSE_EXPIRED:this.closeSub.next("no_permissions"),w.code(R["沒有授權,請聯繫Graphen"]);break;case x.WS_5000_NORAML_CLOSURE:case x.WS_5003_TOKEN_EXPIRED:this.closeSub.next("reconnect"),w.code(R["自動重新連線連端服務"]);break;default:this.closeSub.next("close"),w.code(R["未預期的斷線,請聯繫Graphen"],{code:t,reason:s,type:o,wasClean:i})}})}reconnect(e){this.onDestroy(),this.destorySub=new u,this.start(e)}flushMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected&&void 0!==this.socket;){const e=this.messageQueue.shift();e&&this.socket.send(e,e=>{e&&w.error("send message fail",e?.message,e)})}}send(e){this.isConnected&&void 0!==this.socket?this.socket.send(e,e=>{e&&w.error("send message fail",e?.message,e)}):this.messageQueue.push(e)}sendToCloud(e){this.send(JSON.stringify(e))}onClose(){this.socket?.close(x.WHEN_BROWSER_CLOSE)}onDestroy(){this.destorySub.next(),this.destorySub.complete()}}const P=new class{AppName;platform;isMAC;isWIN;isLINUX;saveFolder;homedir;appFolder;EOL;constructor(e){switch(this.AppName=e,this.platform=process.platform,this.homedir=f.homedir(),this.EOL=f.EOL,this.platform){case"darwin":this.isMAC=!0,this.isWIN=!1,this.isLINUX=!1,this.saveFolder=E.join(this.homedir,"Library","Application Support");break;case"win32":this.isMAC=!1,this.isWIN=!0,this.isLINUX=!1,this.saveFolder=process.env.APPDATA||E.join(this.homedir,"AppData","Roaming");break;case"linux":this.isMAC=!1,this.isWIN=!1,this.isLINUX=!0,this.saveFolder=process.env.XDG_CONFIG_HOME||E.join(this.homedir,".config");break;default:console.log(`當前系統是未知的平台: ${this.platform}`),this.isMAC=!1,this.isWIN=!1,this.isLINUX=!1,this.saveFolder=this.homedir}this.appFolder=E.join(this.saveFolder,this.AppName),this.folderCheck(this.appFolder)}addPath(...e){return E.join(...e)}folderCheck(e){g.mkdirSync(e,{recursive:!0})}fileCheck(e){g.existsSync(e)||g.writeFileSync(e,"",{encoding:"utf8"})}}("aiia-sdk");class T{type="node";filePath;fileName;constructor(){this.fileName="storage.json",this.filePath=P.addPath(P.appFolder,this.fileName),P.fileCheck(this.filePath)}getFileDataSync(){const e=g.readFileSync(this.filePath,"utf8");try{return JSON.parse(e)}catch(e){return{}}}setFileDataSync(e){try{const t=JSON.stringify(e);g.writeFileSync(this.filePath,t,"utf8")}catch(e){}}async getFileData(){return new Promise(e=>{g.readFile(this.filePath,"utf8",(t,s)=>{if(t)e({});else try{e(JSON.parse(s))}catch(t){e({})}})})}async setFileData(e){return new Promise(t=>{try{const s=JSON.stringify(e);g.writeFile(this.filePath,s,"utf8",e=>{t()})}catch(e){}})}async getItem(e){return(await this.getFileData())[e]??null}async setItem(e,t){const s=await this.getFileData();s[e]=t,await this.setFileData(s)}async removeItem(e){const t=await this.getFileData(),s=i(t,e);await this.setFileData(s)}async clear(){await this.setFileData({})}getItemSync(e){return this.getFileDataSync()[e]??null}setItemSync(e,t){const s=this.getFileDataSync();s[e]=t,this.setFileDataSync(s)}removeItemSync(e){const t=i(this.getFileDataSync(),e);this.setFileDataSync(t)}clearSync(){this.setFileDataSync({})}}class v{config;constructor(e){this.config=e,w.info("UEProxy, config=",e)}start(){w.info("UEProxy, start proxy")}send(e){let t=this.cloudToObj(e);if(t&&t.signal&&"osc"===t.signal){w.info("UEProxy, payload=",t);try{let e=t.content;const s=new y(e.host,e.port);w.debug("UEProxy, client open to port "+e.port),s.send(e.message,e=>{e&&w.error(e),s.close(),w.debug("UEProxy, client closed")})}catch(e){w.error(e)}}}cloudToObj(e){try{return JSON.parse(e)}catch(e){w.error("message transfer fail",e)}}onDestroy(){w.info("UEProxy, destroy proxy")}}class U{socket;messageSub;linkStartSub;destorySub;closeSub;get message(){return this.messageSub.asObservable()}get close(){return this.closeSub.asObservable()}get linkStart(){return this.linkStartSub.asObservable()}messageQueue=[];isConnected;constructor(){this.isConnected=!1,this.messageSub=new u,this.linkStartSub=new u,this.closeSub=new u,this.destorySub=new u}url="ws://localhost:8080";start(){this.socket=new _(this.url,{autoPong:!0}),d(this.socket,"open").pipe(S(this.destorySub)).subscribe(()=>{this.isConnected=!0,w.code(R["啟動服務"],"proxy"),this.flushMessageQueue(),this.linkStartSub.next()}),d(this.socket,"message").pipe(S(this.destorySub)).subscribe(e=>{const{data:t}=e;this.messageSub.next(t)}),d(this.socket,"error").pipe(S(this.destorySub)).subscribe(e=>{const{error:t}=e;w.error("Proxy has some problem",t)}),d(this.socket,"close").pipe(S(this.destorySub)).subscribe(e=>{this.isConnected=!1;const{code:t,reason:s}=e;switch(t){case x.MANUAL_CLOSE:w.code(R["無副作用的關閉連線"]);break;case x.WS_5000_NORAML_CLOSURE:case x.MDN_NORMAL_CLOSURE:case x.MDN_GOING_AWAY:this.closeSub.next("close"),w.code(R["安全的關閉連線"]);break;case x.MDN_NO_STATUS_RECEIVED:case x.MDN_ABNORMAL_CLOSURE:this.closeSub.next("close"),w.code(R["與雲端的服務中斷"],{code:t,reason:s});break;case x.WS_5001_UNAUTHORIZED:case x.WS_5002_LICENSE_EXPIRED:this.closeSub.next("no_permissions"),w.code(R["沒有授權,請聯繫Graphen"]);break;case x.WS_5003_TOKEN_EXPIRED:this.closeSub.next("reconnect"),w.code(R["自動重新連線連端服務"]);break;default:this.closeSub.next("close"),w.code(R["未預期的斷線,請聯繫Graphen"],{code:t,reason:s})}})}reconnect(){this.onDestroy(),this.destorySub=new u,this.start()}flushMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected&&void 0!==this.socket;){const e=this.messageQueue.shift();e&&this.socket.send(e)}}send(e){let t=this.cloudToObj(e);if(t&&t.signal&&"audio"===t.signal&&"pcm"===t.command&&(w.info("AudioSocketProxy, payload=",t),this.isConnected&&void 0!==this.socket))try{const e=t.content,s=Buffer.allocUnsafe(2*e.length);for(let t=0;t<e.length;t++)s.writeInt16LE(e[t],2*t);this.socket.send(s)}catch(e){w.error(e)}}cloudToObj(e){try{return JSON.parse(e)}catch(e){w.error("message transfer fail",e)}}onClose(){this.socket?.close(x.MANUAL_CLOSE)}onDestroy(){this.destorySub.next(),this.destorySub.complete()}}class W{socket;messageSub;linkStartSub;destorySub;closeSub;get message(){return this.messageSub.asObservable()}get close(){return this.closeSub.asObservable()}get linkStart(){return this.linkStartSub.asObservable()}messageQueue=[];isConnected;constructor(){this.isConnected=!1,this.messageSub=new u,this.linkStartSub=new u,this.closeSub=new u,this.destorySub=new u}url="ws://localhost:8081";start(){this.socket=new _(this.url,{autoPong:!0}),d(this.socket,"open").pipe(S(this.destorySub)).subscribe(()=>{this.isConnected=!0,w.code(R["啟動服務"],"proxy"),this.flushMessageQueue(),this.linkStartSub.next()}),d(this.socket,"message").pipe(S(this.destorySub)).subscribe(e=>{const{data:t}=e;this.messageSub.next(t)}),d(this.socket,"error").pipe(S(this.destorySub)).subscribe(e=>{const{error:t}=e;w.error("Proxy has some problem",t)}),d(this.socket,"close").pipe(S(this.destorySub)).subscribe(e=>{this.isConnected=!1;const{code:t,reason:s}=e;switch(t){case x.MANUAL_CLOSE:w.code(R["無副作用的關閉連線"]);break;case x.WS_5000_NORAML_CLOSURE:case x.MDN_NORMAL_CLOSURE:case x.MDN_GOING_AWAY:this.closeSub.next("close"),w.code(R["安全的關閉連線"]);break;case x.MDN_NO_STATUS_RECEIVED:case x.MDN_ABNORMAL_CLOSURE:this.closeSub.next("close"),w.code(R["與雲端的服務中斷"],{code:t,reason:s});break;case x.WS_5001_UNAUTHORIZED:case x.WS_5002_LICENSE_EXPIRED:this.closeSub.next("no_permissions"),w.code(R["沒有授權,請聯繫Graphen"]);break;case x.WS_5003_TOKEN_EXPIRED:this.closeSub.next("reconnect"),w.code(R["自動重新連線連端服務"]);break;default:this.closeSub.next("close"),w.code(R["未預期的斷線,請聯繫Graphen"],{code:t,reason:s})}})}reconnect(){this.onDestroy(),this.destorySub=new u,this.start()}flushMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected&&void 0!==this.socket;){const e=this.messageQueue.shift();e&&this.socket.send(e)}}send(e){let t=this.cloudToObj(e);if(t&&t.signal&&"audio"===t.signal&&"interrupted"===t.command&&(w.info("AudioInterruptSocketProxy, payload=",t),this.isConnected&&void 0!==this.socket))try{this.socket.send(t.command)}catch(e){w.error(e)}}cloudToObj(e){try{return JSON.parse(e)}catch(e){w.error("message transfer fail",e)}}onClose(){this.socket?.close(x.MANUAL_CLOSE)}onDestroy(){this.destorySub.next(),this.destorySub.complete()}}class F{next(e,t,...s){const o=`log_${n().format("yyyy-MM-DD")}.txt`,i=P.addPath(P.appFolder,o);try{const o=s.reduce((e,t)=>{switch(typeof t){case"string":case"number":case"bigint":return`${e} ${t.toString()}`;case"boolean":return`${e} ${t?"true":"false"}`;case"object":try{return`${e} ${JSON.stringify(t)}`}catch(t){return e}case"symbol":case"undefined":case"function":return`${e} [${typeof t}]`}},"");g.appendFileSync(i,`LOG(${e})__${t}__::${o}${P.EOL}`,{encoding:"utf8"})}catch(e){}}}class G{config;stroage;apiProxy;chat;udpProxy;audioProxy;audioIntrProxy;isStart;channelMap;destorySub;access_token;eyeBallUdp;get accessToken(){return this.access_token}constructor(e,t){this.config=e,this.stroage=t,this.isStart=!1,this.destorySub=new u,this.channelMap=new Map,this.access_token=t.getItemSync(O),this.apiProxy=new L(this.config.endPoint.api),w.code(R["指定模組初始化完成"],"api"),this.chat=new M(this.config),w.code(R["指定模組初始化完成"],"chat"),this.udpProxy=new v(this.config),w.code(R["指定模組初始化完成"],"udp"),this.audioProxy=new U,w.code(R["指定模組初始化完成"],"audio"),this.audioIntrProxy=new W,w.code(R["指定模組初始化完成"],"audio intr"),this.eyeBallUdp=e.eyeTrackEnable?new y("127.0.0.1",6745):void 0,this.openChannel=this.openChannel.bind(this)}async start(){if(this.isStart)throw new Error(m["重複初始化"]);this.isStart=!0,await this.replaceAccessToken(),this.chat.memberChange.pipe(S(this.destorySub)).subscribe(({type:e,socket:t})=>{switch(e){case"in":{const e=new I,i=new u,n=(o=t.handshake.query.uuid,r(o)?s(o,"[0]",void 0):o??void 0);void 0===n?(this.getProjectList().then(e=>{t.emit("list",e)}),d(t,"uuid").pipe(b(1),S(i)).subscribe(s=>{this.openChannel(s,t,e,i)})):this.openChannel(n,t,e,i),this.channelMap.set(t.id,()=>{i.next(),i.complete()});break}case"out":this.channelMap.has(t.id)&&(this.channelMap.get(t.id)(),this.channelMap.delete(t.id))}var o}),this.chat.start(),w.code(R["啟動服務"],"chat"),this.udpProxy.start(),w.code(R["啟動服務"],"udp")}async replaceAccessToken(){const e=await this.apiProxy.getAccessToken(this.config.license,this.access_token);return this.access_token=e,this.stroage.setItemSync(O,e),e}async getProjectList(){return await this.apiProxy.getProjectList(this.config.license)}getProxySocketURL(e){return`${this.config.endPoint.socket}/v1/chat/project/${this.accessToken}/${e}`}openChannel(t,s,o,i){d(s,"cloud").pipe(S(i)).subscribe(e=>{o.send(e)}),d(s,"face").pipe(S(i)).subscribe(t=>{const s=t,i=null!==s;if(i&&void 0!==this.eyeBallUdp){const{x:t,y:o}=function(t,s){const{maxX:o,maxY:i,minX:r,minY:n}=e({maxX:25,minX:-25,maxY:50,minY:-50},s),l=c(o)+c(r),u=c(i)+c(n),{clientHeight:d,clientWidth:S,originX:b,originY:p,width:_,height:g}=t,f=a([[l/S,0,r],[0,u/d,n],[0,0,1]]),E=b+_/2,y=d-(p+g/2),m=a([[E>S?S:E<0?0:E],[y>d?d:y<0?0:y],[1]]),O=h(f,m);return{x:O.get([0,0]),y:O.get([1,0])}}(s);this.eyeBallUdp.send(-1*t,o,e=>{null!=e&&w.error("eye track error:",e)})}o.sendToCloud({request:"face_detect",content:i})}),o.message.pipe(S(i)).subscribe(e=>{s.emit("cloud",e),this.udpProxy.send(e),this.audioProxy.send(e),this.audioIntrProxy.send(e)}),o.close.pipe(S(i)).subscribe(async e=>{switch(s.emit("channel",e),e){case"close":case"no_permissions":o.onDestroy();break;case"reconnect":await this.replaceAccessToken(),o.reconnect(this.getProxySocketURL(t))}}),o.linkStart.pipe(S(i)).subscribe(()=>{s.emit("channel","open")}),i.subscribe(()=>{o.onClose(),this.audioProxy.onClose(),this.audioIntrProxy.onClose()}),o.start(this.getProxySocketURL(t)),this.audioProxy.start(),this.audioIntrProxy.start()}onDestroy(){this.apiProxy.onDestroy(),this.chat.onDestroy(),this.udpProxy.onDestroy(),this.destorySub.next(),this.destorySub.complete(),this.eyeBallUdp?.close(),w.code(R["服務結束"])}}function j(t){if(D){if(void 0===s(t,"license",void 0))throw new Error(m["未提供憑證"]);!function(e){const{info:t,error:s,warn:o,debug:i,fatal:r,code:n}=function(e){if(void 0===e||"all"===e)return{code:!0,error:!0,warn:!0,info:!0,debug:!0,fatal:!0};if("none"===e)return{error:!1,code:!1,warn:!1,info:!1,debug:!1,fatal:!1};if("boolean"==typeof e)return{code:e,error:e,warn:e,info:e,debug:e,fatal:e};{const t=new Set(e);return{code:t.has("code"),debug:t.has("debug"),fatal:t.has("fatal"),error:t.has("error"),warn:t.has("warn"),info:t.has("info")}}}(e);return n||(k.code=()=>{}),i||(k.debug=()=>{}),t||(k.info=()=>{}),o||(k.warn=()=>{}),s||(k.error=()=>{}),r||(k.fatal=()=>{}),A}(s(t,"debug",!0))(new F),w.code(R["開始初始化必要模組"]);const o=new N(e({},t));w.code(R["指定模組初始化完成"],"config");const i=new T;w.code(R["指定模組初始化完成"],"storage");const r=new G(o,i);return w.code(R["指定模組初始化完成"],"core"),r.start(),w.code(R["啟動服務"]),()=>{r.onDestroy()}}throw new Error(m["環境錯誤(nodejs)"])}export{j as aiiaCore};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphen.ai/aiia-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
4
|
"keywords": [],
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Jay Huang",
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
"@mediapipe/tasks-vision": "^0.10.22-rc.20250304",
|
|
73
73
|
"axios": "^1.11.0",
|
|
74
74
|
"lodash-es": "^4.17.21",
|
|
75
|
+
"mathjs": "^14.8.1",
|
|
75
76
|
"moment": "^2.30.1",
|
|
76
77
|
"node-osc": "^11.0.0",
|
|
77
78
|
"rxjs": "^7.8.2",
|