@crestapps/ai-chat-ui 2.0.0-preview.193 → 2.0.0-preview.197
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/ai-chat.js +77 -20
- package/dist/ai-chat.js.map +1 -1
- package/dist/ai-chat.min.js +1 -1
- package/dist/ai-chat.min.js.map +1 -1
- package/dist/chat-interaction.js +109 -17
- package/dist/chat-interaction.js.map +1 -1
- package/dist/chat-interaction.min.js +1 -1
- package/dist/chat-interaction.min.js.map +1 -1
- package/dist/realtime-audio.js +16 -2
- package/dist/realtime-audio.js.map +1 -1
- package/dist/realtime-audio.min.js +1 -1
- package/dist/realtime-audio.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(e,t){"use strict";function n(e,t){var n=t.micDb,a="number"==typeof t.assistantDb?t.assistantDb:-100,o=t.nowMs,i=t.mode||{},r=null===e.lastMs?0:Math.max(0,Math.min(50,o-e.lastMs));e.lastMs=o,a>-50&&(e.assistantUntil=o+400);var c=o<e.assistantUntil;if(a>e.assistantPeakDb?e.assistantPeakDb=a:e.assistantPeakDb=Math.max(-100,e.assistantPeakDb-.02*r),n<=-95){if(null===e.floorDb)return e.open=!1,e}else null===e.floorDb&&(e.floorDb=Math.min(n,-50));if(n<e.floorDb)e.floorDb+=(n-e.floorDb)*Math.min(1,.0075*r);else if(!c){var s=null!==e.openSince&&o-e.openSince>1e4,l=e.open&&!s?1e-4:56e-5;e.floorDb+=(n-e.floorDb)*Math.min(1,l*r)}if(e.floorDb<-75&&(e.floorDb=-75),c&&!e.open&&a>-50&&!i.pushToTalk){var u=n-e.assistantPeakDb;if(null===e.echoReturnDb)e.echoReturnDb=u;else{var d=e.echoLearnedMs<1e3,f=u>e.echoReturnDb?d?.02:.0012:6e-4;e.echoReturnDb+=(u-e.echoReturnDb)*Math.min(1,f*r)}e.echoLearnedMs+=r}var p,m,h=null===e.echoReturnDb?-100:e.assistantPeakDb+e.echoReturnDb;c?(p=Math.max(e.floorDb+12,h+8,-45),m=Math.max(e.floorDb+3,h+3)):(p=e.floorDb+9,m=e.floorDb+3);var v=i.speechHangoverMs||2e3;n>p?c&&!e.open?(null===e.aboveSince&&(e.aboveSince=o),o-e.aboveSince>=250&&(e.speakUntil=o+v)):e.speakUntil=o+v:(e.aboveSince=null,e.open&&n>m&&(e.speakUntil=Math.max(e.speakUntil,o+250)));var b=o<e.speakUntil;return!c&&e.wasAssistantSpeaking&&(e.listenGraceUntil=o+1500),e.wasAssistantSpeaking=c,e.assistantSpeaking=c,i.pushToTalk?e.open=!!i.pttActive:i.bargeIn?e.open=b:e.open=!c&&(b||o<e.listenGraceUntil),e.open&&null===e.openSince?e.openSince=o:e.open||(e.openSince=null),e}function a(){return{floorDb:null,lastMs:null,speakUntil:0,assistantUntil:0,assistantPeakDb:-100,echoReturnDb:null,echoLearnedMs:0,aboveSince:null,listenGraceUntil:0,wasAssistantSpeaking:!1,assistantSpeaking:!1,open:!1,openSince:null}}function o(e){if(!e||!e.length)return-100;for(var t=0,n=0;n<e.length;n++)t+=e[n]*e[n];var a=Math.sqrt(t/e.length);return a>1e-7?20*Math.log10(a):-100}var i=["var decide = "+n.toString()+";","var newState = "+a.toString()+";","var rmsDb = "+o.toString()+";","class CoreAiMicGateProcessor extends AudioWorkletProcessor {"," constructor(options) {"," super();"," var o = (options && options.processorOptions) || {};"," this.delay = new Float32Array(Math.max(1, Math.round(sampleRate * (o.lookaheadMs || 80) / 1000)));"," this.delayPos = 0;"," this.gain = 0;"," this.mode = o.mode || {};"," this.state = newState();"," this.lastPost = 0;"," this.port.onmessage = function (e) { this.mode = e.data || {}; }.bind(this);"," }"," process(inputs, outputs) {"," var mic = (inputs[0] && inputs[0][0]) || null;"," var assistant = (inputs[1] && inputs[1][0]) || null;"," var out = (outputs[0] && outputs[0][0]) || null;"," if (!out) { return true; }"," var micDb = rmsDb(mic);"," decide(this.state, { micDb: micDb, assistantDb: rmsDb(assistant), nowMs: currentTime * 1000, mode: this.mode });"," var target = this.state.open ? 1 : 0;"," var step = 1 / (sampleRate * 0.01);"," var delay = this.delay;"," var pos = this.delayPos;"," var len = delay.length;"," for (var i = 0; i < out.length; i++) {"," var delayed = delay[pos];"," delay[pos] = mic ? mic[i] : 0;"," pos = (pos + 1) % len;"," if (this.gain < target) { this.gain = Math.min(target, this.gain + step); }"," else if (this.gain > target) { this.gain = Math.max(target, this.gain - step); }"," out[i] = delayed * this.gain;"," }"," this.delayPos = pos;"," if (currentTime * 1000 - this.lastPost > 100) {"," this.lastPost = currentTime * 1000;"," this.port.postMessage({ micDb: micDb, floorDb: this.state.floorDb, echoReturnDb: this.state.echoReturnDb, open: this.state.open, assistantSpeaking: this.state.assistantSpeaking });"," }"," return true;"," }","}",'registerProcessor("coreai-mic-gate", CoreAiMicGateProcessor);'].join("\n"),r=["class CoreAiCaptureProcessor extends AudioWorkletProcessor {"," constructor(options) {"," super();"," var o = (options && options.processorOptions) || {};"," this.size = Math.max(128, o.frameSamples || 4096);"," this.buf = new Float32Array(this.size);"," this.pos = 0;"," }"," process(inputs) {"," var input = (inputs[0] && inputs[0][0]) || null;"," var n = input ? input.length : 128;"," for (var i = 0; i < n; i++) {"," this.buf[this.pos++] = input ? input[i] : 0;"," if (this.pos === this.size) {"," this.port.postMessage(this.buf);"," this.pos = 0;"," }"," }"," return true;"," }","}",'registerProcessor("coreai-pcm-capture", CoreAiCaptureProcessor);'].join("\n");function c(t,n){var a=t&&t.getAudioTracks&&t.getAudioTracks()[0]||null,o={ctx:null,node:null,micSource:null,remoteSource:null,dest:null,timer:0,level:null,fallback:null,track:a,stopped:!1},r={track:a,usingWorklet:!1,getLevel:function(){return o.level},setMode:function(e){if(n=e||n,o.node&&o.node.port)try{o.node.port.postMessage(n)}catch(e){}o.fallback&&(o.fallback.mode=n)},attachAssistantStream:function(e){s(o,e)},stop:function(){if(o.stopped=!0,o.timer){try{e.clearInterval(o.timer)}catch(e){}o.timer=0}if(o.node){try{o.node.port.onmessage=null,o.node.disconnect()}catch(e){}o.node=null}if(o.micSource){try{o.micSource.disconnect()}catch(e){}o.micSource=null}if(o.remoteSource){try{o.remoteSource.disconnect()}catch(e){}o.remoteSource=null}if(o.dest){try{o.dest.disconnect()}catch(e){}o.dest=null}if(o.ctx){try{o.ctx.close()}catch(e){}o.ctx=null}o.fallback=null}},c=e.AudioContext||e.webkitAudioContext;if(!c||!a)return Promise.resolve(r);try{o.ctx=new c,"suspended"===o.ctx.state&&"function"==typeof o.ctx.resume&&o.ctx.resume().catch(function(){})}catch(e){return o.ctx=null,Promise.resolve(r)}var u=null;if(o.ctx.audioWorklet&&"function"==typeof o.ctx.audioWorklet.addModule)try{u=URL.createObjectURL(new Blob([i],{type:"application/javascript"}))}catch(e){u=null}return u?o.ctx.audioWorklet.addModule(u).then(function(){try{URL.revokeObjectURL(u)}catch(e){}if(o.stopped)return r;var i=new AudioWorkletNode(o.ctx,"coreai-mic-gate",{numberOfInputs:2,numberOfOutputs:1,outputChannelCount:[1],processorOptions:{lookaheadMs:80,mode:n}});return o.node=i,i.port.onmessage=function(t){o.level=t.data||null,e.CoreAIRealtime.lastGateLevel=o.level},o.micSource=o.ctx.createMediaStreamSource(t),o.micSource.connect(i,0,0),o.dest=o.ctx.createMediaStreamDestination(),i.connect(o.dest),o.pendingRemoteStream&&s(o,o.pendingRemoteStream),r.track=o.dest.stream.getAudioTracks()[0]||a,r.usingWorklet=!0,r}).catch(function(i){try{URL.revokeObjectURL(u)}catch(e){}return e.console&&console.warn&&console.warn("The realtime microphone gate worklet could not be loaded; using the simpler gate.",i),r.track=l(o,t,a,n),r}):(r.track=l(o,t,a,n),Promise.resolve(r))}function s(e,t){if(e.pendingRemoteStream=t||null,e.ctx&&t&&!e.stopped)try{if(e.remoteSource)try{e.remoteSource.disconnect()}catch(e){}var n=e.ctx.createMediaStreamSource(t);if(e.remoteSource=n,e.node)return void n.connect(e.node,0,1);if(e.fallback){var a=e.ctx.createAnalyser();a.fftSize=2048,n.connect(a),e.fallback.remoteAnalyser=a,e.fallback.remoteData=new Float32Array(a.fftSize)}}catch(e){}}function l(t,a,i,r){try{var c=t.ctx,l=c.createMediaStreamSource(a);t.micSource=l;var u=c.createAnalyser();u.fftSize=2048,l.connect(u);var d=c.createGain();d.gain.value=0,l.connect(d);var f=c.createMediaStreamDestination();t.dest=f,d.connect(f);var p={mode:r,remoteAnalyser:null,remoteData:null};t.fallback=p,t.pendingRemoteStream&&s(t,t.pendingRemoteStream);var m=new Float32Array(u.fftSize),h={floorDb:null,lastMs:null,speakUntil:0,assistantUntil:0,assistantPeakDb:-100,echoReturnDb:null,echoLearnedMs:0,aboveSince:null,listenGraceUntil:0,wasAssistantSpeaking:!1,assistantSpeaking:!1,open:!1,openSince:null};return t.timer=e.setInterval(function(){u.getFloatTimeDomainData(m);var a=o(m),i=-100;p.remoteAnalyser&&p.remoteData&&(p.remoteAnalyser.getFloatTimeDomainData(p.remoteData),i=o(p.remoteData));var r=e.performance&&performance.now?performance.now():Date.now();n(h,{micDb:a,assistantDb:i,nowMs:r,mode:p.mode||{}}),t.level={micDb:a,floorDb:h.floorDb,open:h.open,assistantSpeaking:h.assistantSpeaking};var s=h.open?1:0;try{d.gain.setTargetAtTime(s,c.currentTime,.015)}catch(e){d.gain.value=s}},20),f.stream.getAudioTracks()[0]||i}catch(e){return i}}function u(e,t){if(e&&"function"==typeof e.setSinkId)if(t)try{e.setSinkId(t).catch(function(){})}catch(e){}else navigator.mediaDevices&&navigator.mediaDevices.enumerateDevices&&navigator.mediaDevices.enumerateDevices().then(function(t){var n=t.filter(function(e){return"audiooutput"===e.kind});if(n.length){for(var a="",o=0;o<n.length;o++)if("communications"===n[o].deviceId){a="communications";break}if(!a){for(var i=null,r=0;r<n.length;r++)if("default"===n[r].deviceId){i=n[r];break}if(i&&i.groupId)for(var c=0;c<n.length;c++)if("default"!==n[c].deviceId&&"communications"!==n[c].deviceId&&n[c].groupId===i.groupId){a=n[c].deviceId;break}}if(a)try{e.setSinkId(a).catch(function(){})}catch(e){}}}).catch(function(){})}function d(t,n){if(t&&"function"==typeof t.play){var a=t.play();a&&"function"==typeof a.catch&&a.catch(function(t){"function"==typeof n&&n(t),e.console&&console.warn&&console.warn("The browser blocked realtime audio playback. Interact with the page to enable audio.",t)})}}e.CoreAIRealtime={attach:function(n){var a=(n=n||{}).connection,o=n.selectors||{},i=n.voiceName||"",s=(n.capableDeployments||[]).map(function(e){return(e||"").toLowerCase()}),l=!!n.realtimeEnabled,f=function(){},p=n.onActivate||f,m=n.onDeactivate||f,h=n.onEnterRealtimeMode||f,v=n.onUserTurnPending||f,b=n.onUserTurnDropped||f,g=n.strings||{};function y(e,t){return"string"==typeof g[e]?g[e]:t}var k=n.ensureConnected||function(){return Promise.resolve(!0)},S=n.sendStart||f,D=n.getVoiceName||null,M=n.sendStartWebRtc||null,T=!0===n.webRtcEnabled&&"function"==typeof e.RTCPeerConnection&&!!M,w=Array.isArray(n.webRtcIceServers)&&n.webRtcIceServers.length?n.webRtcIceServers:null,I=[{urls:"stun:stun.l.google.com:19302"}],C=n.onStateChange||f,E="idle";function A(e){var n=o[e];return n?t.querySelector(n):null}var R=!1,x=!1,L=null,j=null,P=null,U=null,B=null,O=null,W=null,N=null,F=null,G=null,H=0,z=[],q=!1,_=null,V=null,Y=!1,J=!1,K=[],Q=!1,X=null,Z=!1,$="coreai.realtime.webrtcBlocked",ee=null,te=0,ne=!1,ae=null,oe=null,ie=!0,re=!1,ce=!1,se=!1,le=null,ue=null,de=null,fe=null,pe=1,me="",he="",ve="",be=!1;function ge(){var t={bargeIn:!0,pushToTalk:!1,volume:1,micDeviceId:"",outputDeviceId:"",language:"",version:0};try{var n=e.localStorage.getItem("coreai.realtime.audioPrefs");if(n){var a=JSON.parse(n);"boolean"==typeof a.bargeIn&&(t.bargeIn=a.bargeIn),"boolean"==typeof a.pushToTalk&&(t.pushToTalk=a.pushToTalk),"number"==typeof a.volume&&isFinite(a.volume)&&(t.volume=Math.min(1,Math.max(0,a.volume))),"string"==typeof a.micDeviceId&&(t.micDeviceId=a.micDeviceId),"string"==typeof a.outputDeviceId&&(t.outputDeviceId=a.outputDeviceId),"string"==typeof a.language&&(t.language=a.language),"number"==typeof a.version&&(t.version=a.version)}}catch(e){}return function(e){if(3===e.version)return e;return e.version=3,e.bargeIn=!0,e.pushToTalk=!1,ye(e),e}(t)}function ye(t){try{e.localStorage.setItem("coreai.realtime.audioPrefs",JSON.stringify(t))}catch(e){}}function ke(e){ie=!1!==e.bargeIn,re=!!e.pushToTalk,pe="number"==typeof e.volume?e.volume:1,me=e.micDeviceId||"",he=e.outputDeviceId||"",ve=e.language||"",He(),G&&(G.gain.value=pe),V&&(V.volume=Math.max(0,Math.min(1,pe)))}function Se(e){if(!e||!e.tagName)return!1;var t=e.tagName.toLowerCase();return"input"===t||"textarea"===t||"select"===t||!0===e.isContentEditable}function De(){se||(se=!0,ce=!1,le=function(e){!re||Se(e.target)||"Space"!==e.code&&" "!==e.key||(e.preventDefault(),e.repeat||Me(!0))},ue=function(e){!re||Se(e.target)||"Space"!==e.code&&" "!==e.key||(e.preventDefault(),Me(!1))},t.addEventListener("keydown",le,!0),t.addEventListener("keyup",ue,!0))}function Me(e){ce=e,He(),de&&(de.classList.toggle("btn-danger",e),de.classList.toggle("btn-outline-primary",!e),de.innerHTML=e?'<i class="fa-solid fa-microphone me-1"></i> Listening…':'<i class="fa-solid fa-microphone me-1"></i> Hold to talk')}function Te(){var n=A("realtimeButton");if(n&&!fe){var a=e.matchMedia&&e.matchMedia("(pointer: coarse)").matches,o=t.createElement("div");o.className="text-center mt-2";var i=t.createElement("button");i.type="button",i.className="btn btn-outline-primary btn-sm",i.innerHTML='<i class="fa-solid fa-microphone me-1"></i> Hold to talk';var r=t.createElement("div");r.className="form-text mt-1 mb-0",r.innerHTML=a?"Push-to-talk is on — press and hold the button to speak.":"Push-to-talk is on — hold <kbd>Space</kbd> or this button to speak.",o.appendChild(i),o.appendChild(r);var c=n.parentElement;c&&c.parentElement?c.parentElement.appendChild(o):n.insertAdjacentElement("afterend",o),de=i,fe=o,i.addEventListener("pointerdown",function(e){e.preventDefault(),Me(!0)}),i.addEventListener("pointerup",function(){Me(!1)}),i.addEventListener("pointerleave",function(){Me(!1)}),i.addEventListener("pointercancel",function(){Me(!1)}),Me(!1)}}function we(n,a){if(a)if(e.DOMPurify&&"function"==typeof e.DOMPurify.sanitize)n.replaceChildren(e.DOMPurify.sanitize(a,{RETURN_DOM_FRAGMENT:!0}));else{var o=a.replace(/<[^>]*>/g," ").replace(/\s+/g," ").trim();n.replaceChildren(t.createTextNode(o))}}function Ie(){var e=A("realtimeButton");e&&(R?(e.classList.add("active","btn-primary"),e.classList.remove("btn-dark","btn-outline-dark","btn-outline-secondary"),e.title=e.getAttribute("data-end-title")||"End Conversation",we(e,e.getAttribute("data-end-html"))):(e.classList.remove("active","btn-primary","btn-dark","btn-outline-secondary"),e.classList.add("btn-outline-dark"),e.blur(),e.title=e.getAttribute("data-start-title")||"Start speaking",we(e,e.getAttribute("data-start-html"))))}function Ce(e){l=e;var n=A("realtimeButton"),a=A("micButton"),o=A("conversationButton"),i=A("input"),r=A("sendButton"),c=t.getElementById("realtime-audio-settings");e?(h(),i&&(i.hidden=!0),r&&(r.hidden=!0),a&&(a.hidden=!0),o&&(o.hidden=!0),n&&(n.hidden=!1),c&&(c.hidden=!1)):(R&&Je(),n&&(n.hidden=!0),c&&(c.hidden=!0),function(){if(!j)return;try{j.remove()}catch(e){}j=null}(),Le(),i&&(i.hidden=!1),r&&(r.hidden=!1),a&&(a.hidden=!1),o&&(o.hidden=!1)),Ie()}var Ee={"requesting-mic":y("requestingMic","Waiting for microphone access…"),connecting:y("connecting","Connecting…"),listening:y("listening","Listening"),"playback-blocked":y("playbackBlocked","Audio is blocked by the browser — click the page to enable it.")};function Ae(e,t){if(E!==e){E=e;var n=Ee[e];n?xe(n,!1):"idle"===e&&Le();try{C({state:e,transport:q?"webrtc":"websocket",detail:t||null})}catch(e){}}}function Re(t){L=t,Je(),Ae("ended",t),e.console&&console.info&&console.info("The realtime voice session ended ("+t+")."),"idle"===t?xe(y("endedIdle","Voice paused after a period of silence."),!0):"max_duration"===t?xe(y("endedMaxDuration","Voice paused — this session reached its time limit. You can start another."),!0):"disconnected"===t?xe(y("endedDisconnected","Voice session ended — the connection dropped."),!0):"error"===t?xe(y("endedError","Voice session ended unexpectedly."),!0):"device_lost"===t&&xe(y("endedDeviceLost","Voice session ended — the microphone was disconnected."),!0)}function xe(e,n){var a=A("realtimeButton");if(a){if(!P){(P=t.createElement("div")).className="form-text mt-2 mb-0 text-center",P.setAttribute("role","status"),P.setAttribute("aria-live","polite");var o=a.parentElement;o&&o.parentElement?o.parentElement.appendChild(P):a.insertAdjacentElement("afterend",P)}if(P.replaceChildren(),P.appendChild(t.createTextNode(e)),n){var i=t.createElement("button");i.type="button",i.className="btn btn-link btn-sm p-0 ms-2 align-baseline",i.textContent=y("resume","Resume"),i.addEventListener("click",function(){Le(),Be()}),P.appendChild(i)}}}function Le(){if(P){try{P.remove()}catch(e){}P=null}}function je(){return w?Promise.resolve(w):ee?Promise.resolve(ee):a&&"function"==typeof a.invoke?a.invoke("GetRealtimeIceServers").then(function(e){return ee=Array.isArray(e)&&e.length?e:I}).catch(function(t){return e.console&&console.warn&&console.warn("Could not resolve the realtime ICE servers; using the default STUN server.",t),ee=I}):Promise.resolve(I)}function Pe(e){var t=[];try{(e||[]).forEach(function(e){var n=e&&e.urls;"string"==typeof n?t.push(n):Array.isArray(n)&&n.forEach(function(e){e&&t.push(e)})})}catch(e){return"none"}return t.length?t.sort().join("|"):"none"}function Ue(){if(!j){var e=A("realtimeButton");if(e){var n=t.createElement("div");n.className="form-text mt-2 mb-0 text-center",n.setAttribute("role","status"),n.textContent=y("compatibilityMode","Using compatibility audio mode. Echo cancellation may be weaker — headphones are recommended.");var a=e.parentElement;a&&a.parentElement?a.parentElement.appendChild(n):e.insertAdjacentElement("afterend",n),j=n}}}function Be(){if(l&&!R&&a){ke(ge()),ee=null;var n=++te;if(Z=!1,L=null,Le(),!x&&a&&(x=!0,a.on("ReceiveRealtimeEvent",function(e,t,n){R&&("session_ready"===t?Ae("listening"):"session_ended"===t?Re(n||"completed"):"speech_started"===t?ie&&Qe():"playback_flush"===t?Qe():"user_turn_pending"===t?v(n):"user_turn_dropped"===t&&b(n))}),a.on("ReceiveError",function(){R&&(!q||Q||Z?Re("error"):Ye("server reported an error before the peer connected"))}),"function"==typeof a.onclose&&a.onclose(function(){R&&Re("disconnected")}),"function"==typeof a.onreconnecting&&a.onreconnecting(function(){R&&Re("disconnected")})),Ae("requesting-mic"),!T)return Ve("the server did not advertise the WebRTC transport"),void Oe();je().then(function(o){if(n===te&&l&&!R)return function(t){try{return e.sessionStorage.getItem($)===Pe(t)}catch(e){return!1}}(o)?(Ve("a WebRTC attempt already failed earlier in this browser session with the same ICE configuration"),void Oe()):void function(){var e={echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0};me&&(e.deviceId={exact:me});navigator.mediaDevices.getUserMedia({audio:e}).then(function(e){k().then(function(){return je()}).then(function(n){U=e,R=!0,q=!0,p(),Ie(),Ae("connecting"),J=!1,K=[],Q=!1;var o=new RTCPeerConnection({iceServers:n});_=o,De();var r=A("realtimeButton");if(r)try{r.blur()}catch(e){}re&&Te();var c=t.createElement("audio");c.autoplay=!0,c.style.display="none",c.volume=Math.max(0,Math.min(1,null!=pe?pe:1)),t.body.appendChild(c),V=c,u(c,he),o.ontrack=function(e){try{e.receiver&&"jitterBufferTarget"in e.receiver&&(e.receiver.jitterBufferTarget=150)}catch(e){}var t;e.streams&&e.streams[0]&&(c.srcObject=e.streams[0],function(e){d(e,function(){Ae("playback-blocked")})}(c),t=e.streams[0],oe=t||null,ae&&t&&ae.attachAssistantStream(t))},ne=!1,o.onicecandidate=function(e){if(e.candidate){e.candidate.candidate&&-1!==e.candidate.candidate.indexOf(" relay ")&&(ne=!0);try{a.send("AddRealtimeIceCandidate",e.candidate.candidate,e.candidate.sdpMid||"",e.candidate.sdpMLineIndex||0)}catch(e){}}else ne||Q||!X||(clearTimeout(X),X=setTimeout(function(){!Q&&R&&Ye("no relay candidate and no direct connection")},5e3))},o.onconnectionstatechange=function(){"connected"===o.connectionState?Ne():"failed"===o.connectionState?Q?R&&Je():Ye("connection failed"):"closed"===o.connectionState&&R&&Q&&Je()},o.oniceconnectionstatechange=function(){var e=o.iceConnectionState;"connected"===e||"completed"===e?Ne():"failed"!==e||Q||Ye("ICE failed")},function(){if(Y)return;Y=!0,a.on("ReceiveRealtimeAnswer",function(e){_&&_.setRemoteDescription({type:"answer",sdp:e}).then(function(){J=!0;var e=K;K=[],e.forEach(function(e){try{_.addIceCandidate(e).catch(function(){})}catch(e){}})}).catch(function(e){console.error("Failed to apply the WebRTC answer.",e)})}),a.on("ReceiveRealtimeIceCandidate",function(e,t,n){if(_&&e){var a={candidate:e,sdpMid:t,sdpMLineIndex:n};if(J)try{_.addIceCandidate(a).catch(function(){})}catch(e){}else K.push(a)}})}(),X=setTimeout(function(){!Q&&R&&Ye("connection timed out")},8e3),ze(e).then(function(t){return _!==o?null:(t&&o.addTrack(t,e),o.createOffer())}).then(function(e){return e&&_===o?o.setLocalDescription(e).then(function(){return e}):null}).then(function(e){if(e){var t=ve||null,n=D&&D()||i||"";M(e.sdp,n,t,null,null,ie)}}).catch(function(e){console.error("Failed to create the WebRTC offer; falling back to WebSocket.",e),Ye("offer failed")})}).catch(function(t){e.getTracks().forEach(function(e){e.stop()}),R=!1,q=!1,m(),Ie(),console.error("The realtime WebRTC conversation could not start because the chat connection is not available.",t)})}).catch(function(e){console.error("Microphone access denied:",e),R=!1,q=!1,m(),Ie()})}()})}}function Oe(){T&&Ue(),De();var t=A("realtimeButton");if(t)try{t.blur()}catch(e){}var n={channelCount:1,echoCancellation:{ideal:!0},noiseSuppression:!0,autoGainControl:!0,echoCancellationType:{ideal:"system"},voiceIsolation:{ideal:!0}};me&&(n.deviceId={exact:me}),navigator.mediaDevices.getUserMedia({audio:n}).then(function(t){k().then(function(){U=t,R=!0,p(),Ie(),Ae("connecting");var n=e.AudioContext||e.webkitAudioContext;"suspended"===(B=new n({sampleRate:24e3})).state&&"function"==typeof B.resume&&B.resume().catch(function(t){Ae("playback-blocked"),e.console&&console.warn&&console.warn("The browser blocked realtime audio playback. Interact with the page to enable audio.",t)}),H=0,z=[],(G=B.createGain()).gain.value=null!=pe?pe:1,G.connect(B.destination),O=new e.signalR.Subject;var a=B,o=B.createGain();o.gain.value=0,F=o,o.connect(B.destination);var c=B.createMediaStreamDestination();G.connect(c);(function(t,n){function a(){var e=t.createScriptProcessor(4096,1,1);return e.onaudioprocess=function(e){n(e.inputBuffer.getChannelData(0))},e}var o=null;if(t.audioWorklet&&"function"==typeof t.audioWorklet.addModule&&"function"==typeof AudioWorkletNode)try{o=URL.createObjectURL(new Blob([r],{type:"application/javascript"}))}catch(e){o=null}return o?t.audioWorklet.addModule(o).then(function(){try{URL.revokeObjectURL(o)}catch(e){}var e=new AudioWorkletNode(t,"coreai-pcm-capture",{numberOfInputs:1,numberOfOutputs:1,outputChannelCount:[1],processorOptions:{frameSamples:4096}});return e.port.onmessage=function(e){e.data&&n(e.data)},e}).catch(function(t){try{URL.revokeObjectURL(o)}catch(e){}return e.console&&console.warn&&console.warn("The realtime capture worklet could not be loaded; falling back to a ScriptProcessorNode.",t),a()}):Promise.resolve(a())})(B,function(e){var t;t=re?!ce:!ie&&B&&B.currentTime<H+.5;var n=new Int16Array(e.length);if(!t)for(var a=0;a<e.length;a++){var o=Math.max(-1,Math.min(1,e[a]));n[a]=o<0?32768*o:32767*o}for(var i=new Uint8Array(n.buffer),r="",c=0;c<i.length;c++)r+=String.fromCharCode(i[c]);try{O.next(btoa(r))}catch(e){}}).then(function(e){if(R&&B===a)W=e,e.connect(o),ze(t).then(function(t){if(R&&B===a&&t){var n=new MediaStream([t]),o=B.createMediaStreamSource(n);N=o,o.connect(e),ae&&ae.attachAssistantStream(c.stream)}});else try{e.disconnect()}catch(e){}});var s=ve||null,l=D&&D()||i||"";S(O,l,s,null,null,ie),re&&Te()}).catch(function(e){t.getTracks().forEach(function(e){e.stop()}),R=!1,m(),Ie(),console.error("The realtime conversation could not start because the chat connection is not available.",e)})}).catch(function(e){console.error("Microphone access denied:",e),R=!1,m(),Ie()})}function We(){if(qe(),_){try{_.close()}catch(e){}_=null}if(V){try{V.srcObject=null,V.remove()}catch(e){}V=null}q=!1}function Ne(){Q||(Q=!0,X&&(clearTimeout(X),X=null))}var Fe=2e3;function Ge(){return{pushToTalk:!!re,pttActive:!!ce,bargeIn:!!ie,speechHangoverMs:Fe}}function He(){ae&&ae.setMode(Ge())}function ze(e){qe();var t=e&&e.getAudioTracks()[0]||null;return c(e,Ge()).then(function(e){return ae=e,oe&&e.attachAssistantStream(oe),e.track||t})}function qe(){if(ae){try{ae.stop()}catch(e){}ae=null}oe=null}function _e(){u(V,he)}function Ve(t){e.console&&console.warn&&console.warn("Realtime is using the WebSocket transport ("+t+"); acoustic echo cancellation is weaker than on WebRTC.")}function Ye(t){if(!Z){Z=!0,X&&(clearTimeout(X),X=null),e.console&&console.warn&&console.warn("Realtime WebRTC transport unavailable ("+t+"); falling back to the WebSocket transport."),function(){try{e.sessionStorage.setItem($,Pe(ee||w))}catch(e){}}(),Ue();try{U&&U.getTracks().forEach(function(e){e.stop()})}catch(e){}U=null,We(),q=!1,R=!1,Oe()}}function Je(){if(R)if(X&&(clearTimeout(X),X=null),R=!1,m(),Ie(),function(){if(se){se=!1,ce=!1;try{t.removeEventListener("keydown",le,!0)}catch(e){}try{t.removeEventListener("keyup",ue,!0)}catch(e){}}}(),function(){if(de=null,fe){try{fe.remove()}catch(e){}fe=null}}(),L||Ae("idle"),q){We();try{U&&U.getTracks().forEach(function(e){e.stop()})}catch(e){}U=null}else{try{O&&O.complete()}catch(e){}O=null,qe();try{W&&(W.disconnect(),W.onaudioprocess=null,W.port&&(W.port.onmessage=null,W.port.close()))}catch(e){}try{N&&N.disconnect()}catch(e){}try{F&&F.disconnect()}catch(e){}try{G&&G.disconnect()}catch(e){}try{U&&U.getTracks().forEach(function(e){e.stop()})}catch(e){}W=null,N=null,F=null,G=null,U=null,Qe();try{B&&B.close()}catch(e){}B=null}}function Ke(){R?Je():Be()}function Qe(){z.forEach(function(e){try{e.stop()}catch(e){}}),z=[],B&&(H=B.currentTime)}function Xe(e){return!!e&&-1!==s.indexOf(e.toLowerCase())}var Ze=A("realtimeButton");Ze&&(Ze.addEventListener("click",function(e){e&&0===e.detail&&R||Ke()}),function(){var n=A("realtimeButton");if(n&&!be){be=!0;var o=ge();ke(o);var i=t.createElement("span");i.id="realtime-audio-settings",i.style.position="relative",i.style.display="inline-flex";var r=t.createElement("button");r.type="button",r.className="btn btn-outline-secondary",r.title=y("settingsTitle","Voice settings"),r.setAttribute("aria-label",y("settingsTitle","Voice settings")),r.innerHTML='<i class="fa-solid fa-gear"></i>';var c='<option value=""'+(""===o.language?" selected":"")+">"+y("languageAuto","Automatic")+"</option>"+[["en","English"],["es","Spanish"],["fr","French"],["de","German"],["it","Italian"],["pt","Portuguese"],["nl","Dutch"],["zh","Chinese"],["ja","Japanese"],["ko","Korean"],["ar","Arabic"],["hi","Hindi"],["ru","Russian"]].map(function(e){return'<option value="'+e[0]+'"'+(o.language===e[0]?" selected":"")+">"+e[1]+"</option>"}).join(""),s=t.createElement("div");s.className="card shadow-sm",s.style.cssText="position:absolute;bottom:calc(100% + 6px);right:0;z-index:1080;width:290px;max-height:70vh;overflow:auto;display:none;",s.innerHTML='<div class="card-body p-3"><div class="fw-semibold mb-2" style="font-size:0.85rem;">'+y("settingsTitle","Voice settings")+'</div><label class="form-label mb-1 d-block" style="font-size:0.8rem;">'+y("microphone","Microphone")+'</label><select class="form-select form-select-sm js-mic mb-2"><option value="">'+y("defaultMicrophone","Default microphone")+'</option></select><label class="form-label mb-1 d-block" style="font-size:0.8rem;">'+y("speaker","Speaker")+'</label><select class="form-select form-select-sm js-out mb-1"><option value="">'+y("automatic","Automatic")+'</option></select><button type="button" class="btn btn-outline-secondary btn-sm mb-2 js-pick-out" style="display:none;">'+y("chooseSpeaker","Choose speaker…")+'</button><div class="form-text mb-2 js-out-help">'+y("speakerHelp","Automatic uses the device your system uses for calls. If you cannot hear the assistant, pick the speakers you are actually listening to.")+'</div><label class="form-label mb-1 d-block" style="font-size:0.8rem;">'+y("assistantVolume","Assistant volume")+': <strong class="js-vol-val">'+Math.round(100*o.volume)+'</strong>%</label><input type="range" class="form-range js-vol mb-2" min="0" max="100" step="5" value="'+Math.round(100*o.volume)+'"><label class="form-label mb-1 d-block" style="font-size:0.8rem;">'+y("language","Language")+'</label><select class="form-select form-select-sm js-lang mb-2">'+c+'</select><div class="form-check form-switch mb-1"><input class="form-check-input js-barge" type="checkbox" id="realtime-setting-barge"'+(o.bargeIn?" checked":"")+'><label class="form-check-label" for="realtime-setting-barge">'+y("allowInterruptions","Allow interruptions")+'</label></div><div class="form-text mb-2">'+y("allowInterruptionsHelp","Talk over the assistant to interrupt it. Turn this off if the assistant keeps hearing itself through your speakers.")+'</div><div class="form-check form-switch mb-1"><input class="form-check-input js-ptt" type="checkbox" id="realtime-setting-ptt"'+(o.pushToTalk?" checked":"")+'><label class="form-check-label" for="realtime-setting-ptt">'+y("pushToTalk","Push-to-talk")+'</label></div><div class="form-text">'+y("pushToTalkHelp","Hold <kbd>Space</kbd> (or the button) to talk. For very noisy places.")+"</div></div>",i.appendChild(r),i.appendChild(s),n.insertAdjacentElement("afterend",i);var l=s.querySelector(".js-barge"),u=s.querySelector(".js-ptt"),d=s.querySelector(".js-vol"),f=s.querySelector(".js-vol-val"),p=s.querySelector(".js-mic"),m=s.querySelector(".js-out"),h=s.querySelector(".js-pick-out"),v=s.querySelector(".js-lang");g(),navigator.mediaDevices&&"function"==typeof navigator.mediaDevices.addEventListener&&navigator.mediaDevices.addEventListener("devicechange",function(){g(),R&&me&&navigator.mediaDevices.enumerateDevices().then(function(e){e.some(function(e){return"audioinput"===e.kind&&e.deviceId===me})||Re("device_lost")}).catch(function(){})}),r.addEventListener("click",function(n){n.stopPropagation();var a="none"===s.style.display;a&&(s.style.display="block",function(){s.style.right="0px",s.style.left="auto";var n=s.getBoundingClientRect();n.left<8&&(s.style.right=n.left-8+"px");for(var a=r.getBoundingClientRect(),o=8,i=s.parentElement?s.parentElement.parentElement:null;i&&i!==t.body&&i!==t.documentElement;){var c=e.getComputedStyle(i);if("auto"===c.overflowY||"scroll"===c.overflowY||"hidden"===c.overflowY||"fixed"===c.position){o=Math.max(o,i.getBoundingClientRect().top);break}i=i.parentElement}s.style.maxHeight=Math.max(160,a.top-o-10)+"px"}(),g()),s.style.display=a?"block":"none"}),s.addEventListener("click",function(e){e.stopPropagation()}),t.addEventListener("click",function(){s.style.display="none"}),l.addEventListener("change",b),u.addEventListener("change",b),d.addEventListener("input",function(){f.textContent=d.value,b()}),p.addEventListener("change",b),v.addEventListener("change",b),m.addEventListener("change",function(){b(),_e()}),navigator.mediaDevices&&"function"==typeof navigator.mediaDevices.selectAudioOutput&&(h.style.display="",h.addEventListener("click",function(){navigator.mediaDevices.selectAudioOutput().then(function(e){if(e&&e.deviceId){var n=t.createElement("option");n.value=e.deviceId,n.textContent=e.label||y("selectedSpeaker","Selected speaker"),m.appendChild(n),m.value=e.deviceId,b(),_e()}}).catch(function(){})}))}function b(){var e={bargeIn:l.checked,pushToTalk:u.checked,volume:(parseInt(d.value,10)||0)/100,micDeviceId:p.value||"",outputDeviceId:m.value||"",language:v.value||"",version:3};ke(e),ye(e),function(){if(R&&a&&"function"==typeof a.send)try{a.send("UpdateRealtimeSettings",ie,null,null)}catch(e){}}()}function g(){navigator.mediaDevices&&navigator.mediaDevices.enumerateDevices&&navigator.mediaDevices.enumerateDevices().then(function(e){var t=['<option value="">'+y("defaultMicrophone","Default microphone")+"</option>"];e.filter(function(e){return"audioinput"===e.kind}).forEach(function(e,n){var a=e.label||y("microphone","Microphone")+" "+(n+1);t.push('<option value="'+e.deviceId+'"'+(e.deviceId===me?" selected":"")+">"+a.replace(/</g,"")+"</option>")}),p.innerHTML=t.join("");var n=e.filter(function(e){return"audiooutput"===e.kind&&e.deviceId&&"communications"!==e.deviceId&&"default"!==e.deviceId});if(n.length){var a=['<option value="">'+y("automatic","Automatic")+"</option>"];n.forEach(function(e,t){var n=e.label||y("speaker","Speaker")+" "+(t+1);a.push('<option value="'+e.deviceId+'"'+(e.deviceId===he?" selected":"")+">"+n.replace(/</g,"")+"</option>")}),m.innerHTML=a.join("")}}).catch(function(){})}}());var $e=A("deploymentSelect");$e&&$e.addEventListener("change",function(){Ce(Xe($e.value))}),Ce(l||$e&&Xe($e.value));var et={toggle:Ke,start:Be,stop:Je,applyMode:Ce,isRealtimeDeployment:Xe,receivePcm:function(e){if(B&&e&&!(e.length<2)){for(var t=B,n=Math.floor(e.length/2),a=new Int16Array(e.buffer,e.byteOffset,n),o=new Float32Array(n),i=0;i<n;i++)o[i]=a[i]/32768;var r=t.createBuffer(1,n,t.sampleRate);r.copyToChannel(o,0);var c=t.createBufferSource();c.buffer=r,c.connect(G||t.destination);var s=t.currentTime;H<s&&(H=s),c.start(H),H+=r.duration,z.push(c),c.onended=function(){z=z.filter(function(e){return e!==c})}}},isActive:function(){return R},getState:function(){return E},getGateLevel:function(){return ae?ae.getLevel():null},getTransportStats:function(){return _&&"function"==typeof _.getStats?_.getStats().then(function(e){var t={transport:"webrtc",inbound:null,codec:null,sinkId:V&&"string"==typeof V.sinkId?V.sinkId:null,jitterBufferTargetMs:function(){try{var e=_.getReceivers().filter(function(e){return e.track&&"audio"===e.track.kind})[0];return e&&"jitterBufferTarget"in e?e.jitterBufferTarget:null}catch(e){return null}}()};return e.forEach(function(n){if("inbound-rtp"===n.type&&"audio"===n.kind&&(t.inbound={packetsReceived:n.packetsReceived,packetsLost:n.packetsLost,packetsDiscarded:n.packetsDiscarded,jitterMs:"number"==typeof n.jitter?Math.round(1e3*n.jitter):null,jitterBufferDelayMs:"number"==typeof n.jitterBufferDelay&&n.jitterBufferEmittedCount?Math.round(n.jitterBufferDelay/n.jitterBufferEmittedCount*1e3):null,totalSamplesReceived:n.totalSamplesReceived,concealedSamples:n.concealedSamples,concealmentEvents:n.concealmentEvents,silentConcealedSamples:n.silentConcealedSamples,insertedSamplesForDeceleration:n.insertedSamplesForDeceleration,removedSamplesForAcceleration:n.removedSamplesForAcceleration,audioLevel:n.audioLevel},n.codecId)){var a=e.get(n.codecId);a&&(t.codec={mimeType:a.mimeType,clockRate:a.clockRate,channels:a.channels,sdpFmtpLine:a.sdpFmtpLine})}}),t}).catch(function(){return null}):Promise.resolve(null)}};return e.CoreAIRealtime.activeController=et,et},createMicGate:c,decideGate:n,createGateState:a,rmsDb:o,routeOutputToPreferredDevice:u,ensurePlayback:d}}(window,document);
|
|
1
|
+
!function(e,t){"use strict";function n(e,t){var n=t.micDb,a="number"==typeof t.assistantDb?t.assistantDb:-100,o=t.nowMs,i=t.mode||{},r=null===e.lastMs?0:Math.max(0,Math.min(50,o-e.lastMs));e.lastMs=o,a>-50&&(e.assistantUntil=o+400);var c=o<e.assistantUntil;if(a>e.assistantPeakDb?e.assistantPeakDb=a:e.assistantPeakDb=Math.max(-100,e.assistantPeakDb-.02*r),n<=-95){if(null===e.floorDb)return e.open=!1,e}else null===e.floorDb&&(e.floorDb=Math.min(n,-50));if(n<e.floorDb)e.floorDb+=(n-e.floorDb)*Math.min(1,.0075*r);else if(!c){var s=null!==e.openSince&&o-e.openSince>1e4,l=e.open&&!s?1e-4:56e-5;e.floorDb+=(n-e.floorDb)*Math.min(1,l*r)}if(e.floorDb<-75&&(e.floorDb=-75),c&&!e.open&&a>-50&&!i.pushToTalk){var u=n-e.assistantPeakDb;if(null===e.echoReturnDb)e.echoReturnDb=u;else{var d=e.echoLearnedMs<1e3,f=u>e.echoReturnDb?d?.02:.0012:6e-4;e.echoReturnDb+=(u-e.echoReturnDb)*Math.min(1,f*r)}e.echoLearnedMs+=r}var p,m,h=null===e.echoReturnDb?-100:e.assistantPeakDb+e.echoReturnDb;c?(p=Math.max(e.floorDb+12,h+8,-45),m=Math.max(e.floorDb+3,h+3)):(p=e.floorDb+9,m=e.floorDb+3);var v=i.speechHangoverMs||2e3;n>p?c&&!e.open?(null===e.aboveSince&&(e.aboveSince=o),o-e.aboveSince>=250&&(e.speakUntil=o+v)):e.speakUntil=o+v:(e.aboveSince=null,e.open&&n>m&&(e.speakUntil=Math.max(e.speakUntil,o+250)));var b=o<e.speakUntil;return!c&&e.wasAssistantSpeaking&&(e.listenGraceUntil=o+1500),e.wasAssistantSpeaking=c,e.assistantSpeaking=c,i.pushToTalk?e.open=!!i.pttActive:i.bargeIn?e.open=b:e.open=!c&&(b||o<e.listenGraceUntil),e.open&&null===e.openSince?e.openSince=o:e.open||(e.openSince=null),e}function a(){return{floorDb:null,lastMs:null,speakUntil:0,assistantUntil:0,assistantPeakDb:-100,echoReturnDb:null,echoLearnedMs:0,aboveSince:null,listenGraceUntil:0,wasAssistantSpeaking:!1,assistantSpeaking:!1,open:!1,openSince:null}}function o(e){if(!e||!e.length)return-100;for(var t=0,n=0;n<e.length;n++)t+=e[n]*e[n];var a=Math.sqrt(t/e.length);return a>1e-7?20*Math.log10(a):-100}var i=["var decide = "+n.toString()+";","var newState = "+a.toString()+";","var rmsDb = "+o.toString()+";","class CoreAiMicGateProcessor extends AudioWorkletProcessor {"," constructor(options) {"," super();"," var o = (options && options.processorOptions) || {};"," this.delay = new Float32Array(Math.max(1, Math.round(sampleRate * (o.lookaheadMs || 80) / 1000)));"," this.delayPos = 0;"," this.gain = 0;"," this.mode = o.mode || {};"," this.state = newState();"," this.lastPost = 0;"," this.port.onmessage = function (e) { this.mode = e.data || {}; }.bind(this);"," }"," process(inputs, outputs) {"," var mic = (inputs[0] && inputs[0][0]) || null;"," var assistant = (inputs[1] && inputs[1][0]) || null;"," var out = (outputs[0] && outputs[0][0]) || null;"," if (!out) { return true; }"," var micDb = rmsDb(mic);"," decide(this.state, { micDb: micDb, assistantDb: rmsDb(assistant), nowMs: currentTime * 1000, mode: this.mode });"," var target = this.state.open ? 1 : 0;"," var step = 1 / (sampleRate * 0.01);"," var delay = this.delay;"," var pos = this.delayPos;"," var len = delay.length;"," for (var i = 0; i < out.length; i++) {"," var delayed = delay[pos];"," delay[pos] = mic ? mic[i] : 0;"," pos = (pos + 1) % len;"," if (this.gain < target) { this.gain = Math.min(target, this.gain + step); }"," else if (this.gain > target) { this.gain = Math.max(target, this.gain - step); }"," out[i] = delayed * this.gain;"," }"," this.delayPos = pos;"," if (currentTime * 1000 - this.lastPost > 100) {"," this.lastPost = currentTime * 1000;"," this.port.postMessage({ micDb: micDb, floorDb: this.state.floorDb, echoReturnDb: this.state.echoReturnDb, open: this.state.open, assistantSpeaking: this.state.assistantSpeaking });"," }"," return true;"," }","}",'registerProcessor("coreai-mic-gate", CoreAiMicGateProcessor);'].join("\n"),r=["class CoreAiCaptureProcessor extends AudioWorkletProcessor {"," constructor(options) {"," super();"," var o = (options && options.processorOptions) || {};"," this.size = Math.max(128, o.frameSamples || 4096);"," this.buf = new Float32Array(this.size);"," this.pos = 0;"," }"," process(inputs) {"," var input = (inputs[0] && inputs[0][0]) || null;"," var n = input ? input.length : 128;"," for (var i = 0; i < n; i++) {"," this.buf[this.pos++] = input ? input[i] : 0;"," if (this.pos === this.size) {"," this.port.postMessage(this.buf);"," this.pos = 0;"," }"," }"," return true;"," }","}",'registerProcessor("coreai-pcm-capture", CoreAiCaptureProcessor);'].join("\n");function c(t,n){var a=t&&t.getAudioTracks&&t.getAudioTracks()[0]||null,o={ctx:null,node:null,micSource:null,remoteSource:null,dest:null,timer:0,level:null,fallback:null,track:a,stopped:!1},r={track:a,usingWorklet:!1,getLevel:function(){return o.level},setMode:function(e){if(n=e||n,o.node&&o.node.port)try{o.node.port.postMessage(n)}catch(e){}o.fallback&&(o.fallback.mode=n)},attachAssistantStream:function(e){s(o,e)},stop:function(){if(o.stopped=!0,o.timer){try{e.clearInterval(o.timer)}catch(e){}o.timer=0}if(o.node){try{o.node.port.onmessage=null,o.node.disconnect()}catch(e){}o.node=null}if(o.micSource){try{o.micSource.disconnect()}catch(e){}o.micSource=null}if(o.remoteSource){try{o.remoteSource.disconnect()}catch(e){}o.remoteSource=null}if(o.dest){try{o.dest.disconnect()}catch(e){}o.dest=null}if(o.ctx){try{o.ctx.close()}catch(e){}o.ctx=null}o.fallback=null}},c=e.AudioContext||e.webkitAudioContext;if(!c||!a)return Promise.resolve(r);try{o.ctx=new c,"suspended"===o.ctx.state&&"function"==typeof o.ctx.resume&&o.ctx.resume().catch(function(){})}catch(e){return o.ctx=null,Promise.resolve(r)}var u=null;if(o.ctx.audioWorklet&&"function"==typeof o.ctx.audioWorklet.addModule)try{u=URL.createObjectURL(new Blob([i],{type:"application/javascript"}))}catch(e){u=null}return u?o.ctx.audioWorklet.addModule(u).then(function(){try{URL.revokeObjectURL(u)}catch(e){}if(o.stopped)return r;var i=new AudioWorkletNode(o.ctx,"coreai-mic-gate",{numberOfInputs:2,numberOfOutputs:1,outputChannelCount:[1],processorOptions:{lookaheadMs:80,mode:n}});return o.node=i,i.port.onmessage=function(t){o.level=t.data||null,e.CoreAIRealtime.lastGateLevel=o.level},o.micSource=o.ctx.createMediaStreamSource(t),o.micSource.connect(i,0,0),o.dest=o.ctx.createMediaStreamDestination(),i.connect(o.dest),o.pendingRemoteStream&&s(o,o.pendingRemoteStream),r.track=o.dest.stream.getAudioTracks()[0]||a,r.usingWorklet=!0,r}).catch(function(i){try{URL.revokeObjectURL(u)}catch(e){}return e.console&&console.warn&&console.warn("The realtime microphone gate worklet could not be loaded; using the simpler gate.",i),r.track=l(o,t,a,n),r}):(r.track=l(o,t,a,n),Promise.resolve(r))}function s(e,t){if(e.pendingRemoteStream=t||null,e.ctx&&t&&!e.stopped)try{if(e.remoteSource)try{e.remoteSource.disconnect()}catch(e){}var n=e.ctx.createMediaStreamSource(t);if(e.remoteSource=n,e.node)return void n.connect(e.node,0,1);if(e.fallback){var a=e.ctx.createAnalyser();a.fftSize=2048,n.connect(a),e.fallback.remoteAnalyser=a,e.fallback.remoteData=new Float32Array(a.fftSize)}}catch(e){}}function l(t,a,i,r){try{var c=t.ctx,l=c.createMediaStreamSource(a);t.micSource=l;var u=c.createAnalyser();u.fftSize=2048,l.connect(u);var d=c.createGain();d.gain.value=0,l.connect(d);var f=c.createMediaStreamDestination();t.dest=f,d.connect(f);var p={mode:r,remoteAnalyser:null,remoteData:null};t.fallback=p,t.pendingRemoteStream&&s(t,t.pendingRemoteStream);var m=new Float32Array(u.fftSize),h={floorDb:null,lastMs:null,speakUntil:0,assistantUntil:0,assistantPeakDb:-100,echoReturnDb:null,echoLearnedMs:0,aboveSince:null,listenGraceUntil:0,wasAssistantSpeaking:!1,assistantSpeaking:!1,open:!1,openSince:null};return t.timer=e.setInterval(function(){u.getFloatTimeDomainData(m);var a=o(m),i=-100;p.remoteAnalyser&&p.remoteData&&(p.remoteAnalyser.getFloatTimeDomainData(p.remoteData),i=o(p.remoteData));var r=e.performance&&performance.now?performance.now():Date.now();n(h,{micDb:a,assistantDb:i,nowMs:r,mode:p.mode||{}}),t.level={micDb:a,floorDb:h.floorDb,open:h.open,assistantSpeaking:h.assistantSpeaking};var s=h.open?1:0;try{d.gain.setTargetAtTime(s,c.currentTime,.015)}catch(e){d.gain.value=s}},20),f.stream.getAudioTracks()[0]||i}catch(e){return i}}function u(e,t){if(e&&"function"==typeof e.setSinkId)if(t)try{e.setSinkId(t).catch(function(){})}catch(e){}else navigator.mediaDevices&&navigator.mediaDevices.enumerateDevices&&navigator.mediaDevices.enumerateDevices().then(function(t){var n=t.filter(function(e){return"audiooutput"===e.kind});if(n.length){for(var a="",o=0;o<n.length;o++)if("communications"===n[o].deviceId){a="communications";break}if(!a){for(var i=null,r=0;r<n.length;r++)if("default"===n[r].deviceId){i=n[r];break}if(i&&i.groupId)for(var c=0;c<n.length;c++)if("default"!==n[c].deviceId&&"communications"!==n[c].deviceId&&n[c].groupId===i.groupId){a=n[c].deviceId;break}}if(a)try{e.setSinkId(a).catch(function(){})}catch(e){}}}).catch(function(){})}function d(t,n){if(t&&"function"==typeof t.play){var a=t.play();a&&"function"==typeof a.catch&&a.catch(function(t){"function"==typeof n&&n(t),e.console&&console.warn&&console.warn("The browser blocked realtime audio playback. Interact with the page to enable audio.",t)})}}e.CoreAIRealtime={attach:function(n){var a=(n=n||{}).connection,o=n.selectors||{},i=n.voiceName||"",s=(n.capableDeployments||[]).map(function(e){return(e||"").toLowerCase()}),l=!!n.realtimeEnabled,f=function(){},p=n.onActivate||f,m=n.onDeactivate||f,h=n.onSessionStateChanged||f,v=n.onEnterRealtimeMode||f,b=n.onUserTurnPending||f,g=n.onUserTurnDropped||f,y=n.strings||{};function k(e,t){return"string"==typeof y[e]?y[e]:t}var S=n.ensureConnected||function(){return Promise.resolve(!0)},D=n.sendStart||f,M=n.getVoiceName||null,T=n.sendStartWebRtc||null,w=!0===n.webRtcEnabled&&"function"==typeof e.RTCPeerConnection&&!!T,I=Array.isArray(n.webRtcIceServers)&&n.webRtcIceServers.length?n.webRtcIceServers:null,C=[{urls:"stun:stun.l.google.com:19302"}],E=n.onStateChange||f,A="idle";function R(e){var n=o[e];return n?t.querySelector(n):null}var x=!1,L=!1,j=null,P=null,U=null,B=null,O=null,W=null,N=null,F=null,G=null,H=null,z=0,q=[],_=!1,V=null,Y=null,J=!1,K=!1,Q=[],X=!1,Z=null,$=!1,ee="coreai.realtime.webrtcBlocked",te=null,ne=0,ae=!1,oe=null,ie=null,re=!0,ce=!1,se=!1,le=!1,ue=null,de=null,fe=null,pe=null,me=1,he="",ve="",be="",ge=!1,ye=null;function ke(){var t={bargeIn:!0,pushToTalk:!1,volume:1,micDeviceId:"",outputDeviceId:"",language:"",version:0};try{var n=e.localStorage.getItem("coreai.realtime.audioPrefs");if(n){var a=JSON.parse(n);"boolean"==typeof a.bargeIn&&(t.bargeIn=a.bargeIn),"boolean"==typeof a.pushToTalk&&(t.pushToTalk=a.pushToTalk),"number"==typeof a.volume&&isFinite(a.volume)&&(t.volume=Math.min(1,Math.max(0,a.volume))),"string"==typeof a.micDeviceId&&(t.micDeviceId=a.micDeviceId),"string"==typeof a.outputDeviceId&&(t.outputDeviceId=a.outputDeviceId),"string"==typeof a.language&&(t.language=a.language),"number"==typeof a.version&&(t.version=a.version)}}catch(e){}return function(e){if(3===e.version)return e;return e.version=3,e.bargeIn=!0,e.pushToTalk=!1,Se(e),e}(t)}function Se(t){try{e.localStorage.setItem("coreai.realtime.audioPrefs",JSON.stringify(t))}catch(e){}}function De(e){re=!1!==e.bargeIn,ce=!!e.pushToTalk,me="number"==typeof e.volume?e.volume:1,he=e.micDeviceId||"",ve=e.outputDeviceId||"",be=e.language||"",qe(),H&&(H.gain.value=me),Y&&(Y.volume=Math.max(0,Math.min(1,me)))}function Me(e){if(!e||!e.tagName)return!1;var t=e.tagName.toLowerCase();return"input"===t||"textarea"===t||"select"===t||!0===e.isContentEditable}function Te(){le||(le=!0,se=!1,ue=function(e){!ce||Me(e.target)||"Space"!==e.code&&" "!==e.key||(e.preventDefault(),e.repeat||we(!0))},de=function(e){!ce||Me(e.target)||"Space"!==e.code&&" "!==e.key||(e.preventDefault(),we(!1))},t.addEventListener("keydown",ue,!0),t.addEventListener("keyup",de,!0))}function we(e){se=e,qe(),fe&&(fe.classList.toggle("btn-danger",e),fe.classList.toggle("btn-outline-primary",!e),fe.innerHTML=e?'<i class="fa-solid fa-microphone me-1"></i> Listening…':'<i class="fa-solid fa-microphone me-1"></i> Hold to talk')}function Ie(){var n=R("realtimeButton");if(n&&!pe){var a=e.matchMedia&&e.matchMedia("(pointer: coarse)").matches,o=t.createElement("div");o.className="text-center mt-2";var i=t.createElement("button");i.type="button",i.className="btn btn-outline-primary btn-sm",i.innerHTML='<i class="fa-solid fa-microphone me-1"></i> Hold to talk';var r=t.createElement("div");r.className="form-text mt-1 mb-0",r.innerHTML=a?"Push-to-talk is on — press and hold the button to speak.":"Push-to-talk is on — hold <kbd>Space</kbd> or this button to speak.",o.appendChild(i),o.appendChild(r);var c=n.parentElement;c&&c.parentElement?c.parentElement.appendChild(o):n.insertAdjacentElement("afterend",o),fe=i,pe=o,i.addEventListener("pointerdown",function(e){e.preventDefault(),we(!0)}),i.addEventListener("pointerup",function(){we(!1)}),i.addEventListener("pointerleave",function(){we(!1)}),i.addEventListener("pointercancel",function(){we(!1)}),we(!1)}}function Ce(n,a){if(a)if(e.DOMPurify&&"function"==typeof e.DOMPurify.sanitize)n.replaceChildren(e.DOMPurify.sanitize(a,{RETURN_DOM_FRAGMENT:!0}));else{var o=a.replace(/<[^>]*>/g," ").replace(/\s+/g," ").trim();n.replaceChildren(t.createTextNode(o))}}function Ee(){h(x);var e=R("realtimeButton");e&&(x?(e.classList.add("active","btn-primary"),e.classList.remove("btn-dark","btn-outline-dark","btn-outline-secondary"),e.title=e.getAttribute("data-end-title")||"End Conversation",Ce(e,e.getAttribute("data-end-html"))):(e.classList.remove("active","btn-primary","btn-dark","btn-outline-secondary"),e.classList.add("btn-outline-dark"),e.blur(),e.title=e.getAttribute("data-start-title")||"Start speaking",Ce(e,e.getAttribute("data-start-html"))))}function Ae(e){l=e;var t=R("realtimeButton"),n=R("micButton"),a=R("conversationButton"),o=R("input"),i=R("sendButton"),r=ye;e?(v(),o&&(o.hidden=!0),i&&(i.hidden=!0),n&&(n.hidden=!0),a&&(a.hidden=!0),t&&(t.hidden=!1),r&&(r.hidden=!1)):(x&&Qe(),t&&(t.hidden=!0),r&&(r.hidden=!0),function(){if(!P)return;try{P.remove()}catch(e){}P=null}(),Pe(),o&&(o.hidden=!1),i&&(i.hidden=!1),n&&(n.hidden=!1),a&&(a.hidden=!1)),Ee()}var Re={"requesting-mic":k("requestingMic","Waiting for microphone access…"),connecting:k("connecting","Connecting…"),listening:k("listening","Listening"),"playback-blocked":k("playbackBlocked","Audio is blocked by the browser — click the page to enable it.")};function xe(e,t){if(A!==e){A=e;var n=Re[e];n?je(n,!1):"idle"===e&&Pe();try{E({state:e,transport:_?"webrtc":"websocket",detail:t||null})}catch(e){}}}function Le(t){j=t,Qe(),xe("ended",t),e.console&&console.info&&console.info("The realtime voice session ended ("+t+")."),"idle"===t?je(k("endedIdle","Voice paused after a period of silence."),!0):"max_duration"===t?je(k("endedMaxDuration","Voice paused — this session reached its time limit. You can start another."),!0):"disconnected"===t?je(k("endedDisconnected","Voice session ended — the connection dropped."),!0):"error"===t?je(k("endedError","Voice session ended unexpectedly."),!0):"device_lost"===t&&je(k("endedDeviceLost","Voice session ended — the microphone was disconnected."),!0)}function je(e,n){var a=R("realtimeButton");if(a){if(!U){(U=t.createElement("div")).className="form-text mt-2 mb-0 text-center",U.setAttribute("role","status"),U.setAttribute("aria-live","polite");var o=a.parentElement;o&&o.parentElement?o.parentElement.appendChild(U):a.insertAdjacentElement("afterend",U)}if(U.replaceChildren(),U.appendChild(t.createTextNode(e)),n){var i=t.createElement("button");i.type="button",i.className="btn btn-link btn-sm p-0 ms-2 align-baseline",i.textContent=k("resume","Resume"),i.addEventListener("click",function(){Pe(),We()}),U.appendChild(i)}}}function Pe(){if(U){try{U.remove()}catch(e){}U=null}}function Ue(){return I?Promise.resolve(I):te?Promise.resolve(te):a&&"function"==typeof a.invoke?a.invoke("GetRealtimeIceServers").then(function(e){return te=Array.isArray(e)&&e.length?e:C}).catch(function(t){return e.console&&console.warn&&console.warn("Could not resolve the realtime ICE servers; using the default STUN server.",t),te=C}):Promise.resolve(C)}function Be(e){var t=[];try{(e||[]).forEach(function(e){var n=e&&e.urls;"string"==typeof n?t.push(n):Array.isArray(n)&&n.forEach(function(e){e&&t.push(e)})})}catch(e){return"none"}return t.length?t.sort().join("|"):"none"}function Oe(){if(!P){var e=R("realtimeButton");if(e){var n=t.createElement("div");n.className="form-text mt-2 mb-0 text-center",n.setAttribute("role","status"),n.textContent=k("compatibilityMode","Using compatibility audio mode. Echo cancellation may be weaker — headphones are recommended.");var a=e.parentElement;a&&a.parentElement?a.parentElement.appendChild(n):e.insertAdjacentElement("afterend",n),P=n}}}function We(){if(l&&!x&&a){De(ke()),te=null;var n=++ne;if($=!1,j=null,Pe(),!L&&a&&(L=!0,a.on("ReceiveRealtimeEvent",function(e,t,n){x&&("session_ready"===t?xe("listening"):"session_ended"===t?Le(n||"completed"):"speech_started"===t?re&&Ze():"playback_flush"===t?Ze():"user_turn_pending"===t?b(n):"user_turn_dropped"===t&&g(n))}),a.on("ReceiveError",function(){x&&(!_||X||$?Le("error"):Ke("server reported an error before the peer connected"))}),"function"==typeof a.onclose&&a.onclose(function(){x&&Le("disconnected")}),"function"==typeof a.onreconnecting&&a.onreconnecting(function(){x&&Le("disconnected")})),xe("requesting-mic"),!w)return Je("the server did not advertise the WebRTC transport"),void Ne();Ue().then(function(o){if(n===ne&&l&&!x)return function(t){try{return e.sessionStorage.getItem(ee)===Be(t)}catch(e){return!1}}(o)?(Je("a WebRTC attempt already failed earlier in this browser session with the same ICE configuration"),void Ne()):void function(){var e={echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0};he&&(e.deviceId={exact:he});navigator.mediaDevices.getUserMedia({audio:e}).then(function(e){S().then(function(){return Ue()}).then(function(n){B=e,x=!0,_=!0,p(),Ee(),xe("connecting"),K=!1,Q=[],X=!1;var o=new RTCPeerConnection({iceServers:n});V=o,Te();var r=R("realtimeButton");if(r)try{r.blur()}catch(e){}ce&&Ie();var c=t.createElement("audio");c.autoplay=!0,c.style.display="none",c.volume=Math.max(0,Math.min(1,null!=me?me:1)),t.body.appendChild(c),Y=c,u(c,ve),o.ontrack=function(e){try{e.receiver&&"jitterBufferTarget"in e.receiver&&(e.receiver.jitterBufferTarget=150)}catch(e){}var t;e.streams&&e.streams[0]&&(c.srcObject=e.streams[0],function(e){d(e,function(){xe("playback-blocked")})}(c),t=e.streams[0],ie=t||null,oe&&t&&oe.attachAssistantStream(t))},ae=!1,o.onicecandidate=function(e){if(e.candidate){e.candidate.candidate&&-1!==e.candidate.candidate.indexOf(" relay ")&&(ae=!0);try{a.send("AddRealtimeIceCandidate",e.candidate.candidate,e.candidate.sdpMid||"",e.candidate.sdpMLineIndex||0)}catch(e){}}else ae||X||!Z||(clearTimeout(Z),Z=setTimeout(function(){!X&&x&&Ke("no relay candidate and no direct connection")},5e3))},o.onconnectionstatechange=function(){"connected"===o.connectionState?Ge():"failed"===o.connectionState?X?x&&Qe():Ke("connection failed"):"closed"===o.connectionState&&x&&X&&Qe()},o.oniceconnectionstatechange=function(){var e=o.iceConnectionState;"connected"===e||"completed"===e?Ge():"failed"!==e||X||Ke("ICE failed")},function(){if(J)return;J=!0,a.on("ReceiveRealtimeAnswer",function(e){V&&V.setRemoteDescription({type:"answer",sdp:e}).then(function(){K=!0;var e=Q;Q=[],e.forEach(function(e){try{V.addIceCandidate(e).catch(function(){})}catch(e){}})}).catch(function(e){console.error("Failed to apply the WebRTC answer.",e)})}),a.on("ReceiveRealtimeIceCandidate",function(e,t,n){if(V&&e){var a={candidate:e,sdpMid:t,sdpMLineIndex:n};if(K)try{V.addIceCandidate(a).catch(function(){})}catch(e){}else Q.push(a)}})}(),Z=setTimeout(function(){!X&&x&&Ke("connection timed out")},8e3),_e(e).then(function(t){return V!==o?null:(t&&o.addTrack(t,e),o.createOffer())}).then(function(e){return e&&V===o?o.setLocalDescription(e).then(function(){return e}):null}).then(function(e){if(e){var t=be||null,n=M&&M()||i||"";T(e.sdp,n,t,null,null,re)}}).catch(function(e){console.error("Failed to create the WebRTC offer; falling back to WebSocket.",e),Ke("offer failed")})}).catch(function(t){e.getTracks().forEach(function(e){e.stop()}),x=!1,_=!1,m(),Ee(),console.error("The realtime WebRTC conversation could not start because the chat connection is not available.",t)})}).catch(function(e){console.error("Microphone access denied:",e),x=!1,_=!1,m(),Ee()})}()})}}function Ne(){w&&Oe(),Te();var t=R("realtimeButton");if(t)try{t.blur()}catch(e){}var n={channelCount:1,echoCancellation:{ideal:!0},noiseSuppression:!0,autoGainControl:!0,echoCancellationType:{ideal:"system"},voiceIsolation:{ideal:!0}};he&&(n.deviceId={exact:he}),navigator.mediaDevices.getUserMedia({audio:n}).then(function(t){S().then(function(){B=t,x=!0,p(),Ee(),xe("connecting");var n=e.AudioContext||e.webkitAudioContext;"suspended"===(O=new n({sampleRate:24e3})).state&&"function"==typeof O.resume&&O.resume().catch(function(t){xe("playback-blocked"),e.console&&console.warn&&console.warn("The browser blocked realtime audio playback. Interact with the page to enable audio.",t)}),z=0,q=[],(H=O.createGain()).gain.value=null!=me?me:1,H.connect(O.destination),W=new e.signalR.Subject;var a=O,o=O.createGain();o.gain.value=0,G=o,o.connect(O.destination);var c=O.createMediaStreamDestination();H.connect(c);(function(t,n){function a(){var e=t.createScriptProcessor(4096,1,1);return e.onaudioprocess=function(e){n(e.inputBuffer.getChannelData(0))},e}var o=null;if(t.audioWorklet&&"function"==typeof t.audioWorklet.addModule&&"function"==typeof AudioWorkletNode)try{o=URL.createObjectURL(new Blob([r],{type:"application/javascript"}))}catch(e){o=null}return o?t.audioWorklet.addModule(o).then(function(){try{URL.revokeObjectURL(o)}catch(e){}var e=new AudioWorkletNode(t,"coreai-pcm-capture",{numberOfInputs:1,numberOfOutputs:1,outputChannelCount:[1],processorOptions:{frameSamples:4096}});return e.port.onmessage=function(e){e.data&&n(e.data)},e}).catch(function(t){try{URL.revokeObjectURL(o)}catch(e){}return e.console&&console.warn&&console.warn("The realtime capture worklet could not be loaded; falling back to a ScriptProcessorNode.",t),a()}):Promise.resolve(a())})(O,function(e){var t;t=ce?!se:!re&&O&&O.currentTime<z+.5;var n=new Int16Array(e.length);if(!t)for(var a=0;a<e.length;a++){var o=Math.max(-1,Math.min(1,e[a]));n[a]=o<0?32768*o:32767*o}for(var i=new Uint8Array(n.buffer),r="",c=0;c<i.length;c++)r+=String.fromCharCode(i[c]);try{W.next(btoa(r))}catch(e){}}).then(function(e){if(x&&O===a)N=e,e.connect(o),_e(t).then(function(t){if(x&&O===a&&t){var n=new MediaStream([t]),o=O.createMediaStreamSource(n);F=o,o.connect(e),oe&&oe.attachAssistantStream(c.stream)}});else try{e.disconnect()}catch(e){}});var s=be||null,l=M&&M()||i||"";D(W,l,s,null,null,re),ce&&Ie()}).catch(function(e){t.getTracks().forEach(function(e){e.stop()}),x=!1,m(),Ee(),console.error("The realtime conversation could not start because the chat connection is not available.",e)})}).catch(function(e){console.error("Microphone access denied:",e),x=!1,m(),Ee()})}function Fe(){if(Ve(),V){try{V.close()}catch(e){}V=null}if(Y){try{Y.srcObject=null,Y.remove()}catch(e){}Y=null}_=!1}function Ge(){X||(X=!0,Z&&(clearTimeout(Z),Z=null))}var He=2e3;function ze(){return{pushToTalk:!!ce,pttActive:!!se,bargeIn:!!re,speechHangoverMs:He}}function qe(){oe&&oe.setMode(ze())}function _e(e){Ve();var t=e&&e.getAudioTracks()[0]||null;return c(e,ze()).then(function(e){return oe=e,ie&&e.attachAssistantStream(ie),e.track||t})}function Ve(){if(oe){try{oe.stop()}catch(e){}oe=null}ie=null}function Ye(){u(Y,ve)}function Je(t){e.console&&console.warn&&console.warn("Realtime is using the WebSocket transport ("+t+"); acoustic echo cancellation is weaker than on WebRTC.")}function Ke(t){if(!$){$=!0,Z&&(clearTimeout(Z),Z=null),e.console&&console.warn&&console.warn("Realtime WebRTC transport unavailable ("+t+"); falling back to the WebSocket transport."),function(){try{e.sessionStorage.setItem(ee,Be(te||I))}catch(e){}}(),Oe();try{B&&B.getTracks().forEach(function(e){e.stop()})}catch(e){}B=null,Fe(),_=!1,x=!1,Ne()}}function Qe(){if(x)if(Z&&(clearTimeout(Z),Z=null),x=!1,m(),Ee(),function(){if(le){le=!1,se=!1;try{t.removeEventListener("keydown",ue,!0)}catch(e){}try{t.removeEventListener("keyup",de,!0)}catch(e){}}}(),function(){if(fe=null,pe){try{pe.remove()}catch(e){}pe=null}}(),j||xe("idle"),_){Fe();try{B&&B.getTracks().forEach(function(e){e.stop()})}catch(e){}B=null}else{try{W&&W.complete()}catch(e){}W=null,Ve();try{N&&(N.disconnect(),N.onaudioprocess=null,N.port&&(N.port.onmessage=null,N.port.close()))}catch(e){}try{F&&F.disconnect()}catch(e){}try{G&&G.disconnect()}catch(e){}try{H&&H.disconnect()}catch(e){}try{B&&B.getTracks().forEach(function(e){e.stop()})}catch(e){}N=null,F=null,G=null,H=null,B=null,Ze();try{O&&O.close()}catch(e){}O=null}}function Xe(){x?Qe():We()}function Ze(){q.forEach(function(e){try{e.stop()}catch(e){}}),q=[],O&&(z=O.currentTime)}function $e(e){return!!e&&-1!==s.indexOf(e.toLowerCase())}var et=R("realtimeButton");et&&(et.addEventListener("click",function(e){e&&0===e.detail&&x||Xe()}),function(){var n=R("realtimeButton");if(n&&!ge){ge=!0;var o=ke();De(o);var i=t.createElement("span");i.id="realtime-audio-settings",i.style.position="relative",i.style.display="inline-flex";var r=t.createElement("button");r.type="button",r.className="btn btn-outline-secondary",r.title=k("settingsTitle","Voice settings"),r.setAttribute("aria-label",k("settingsTitle","Voice settings")),r.innerHTML='<i class="fa-solid fa-gear"></i>';var c='<option value=""'+(""===o.language?" selected":"")+">"+k("languageAuto","Automatic")+"</option>"+[["en","English"],["es","Spanish"],["fr","French"],["de","German"],["it","Italian"],["pt","Portuguese"],["nl","Dutch"],["zh","Chinese"],["ja","Japanese"],["ko","Korean"],["ar","Arabic"],["hi","Hindi"],["ru","Russian"]].map(function(e){return'<option value="'+e[0]+'"'+(o.language===e[0]?" selected":"")+">"+e[1]+"</option>"}).join(""),s=t.createElement("div");s.className="card shadow-sm",s.style.cssText="position:absolute;bottom:calc(100% + 6px);right:0;z-index:1080;width:290px;max-height:70vh;overflow:auto;display:none;",s.innerHTML='<div class="card-body p-3"><div class="fw-semibold mb-2" style="font-size:0.85rem;">'+k("settingsTitle","Voice settings")+'</div><label class="form-label mb-1 d-block" style="font-size:0.8rem;">'+k("microphone","Microphone")+'</label><select class="form-select form-select-sm js-mic mb-2"><option value="">'+k("defaultMicrophone","Default microphone")+'</option></select><label class="form-label mb-1 d-block" style="font-size:0.8rem;">'+k("speaker","Speaker")+'</label><select class="form-select form-select-sm js-out mb-1"><option value="">'+k("automatic","Automatic")+'</option></select><button type="button" class="btn btn-outline-secondary btn-sm mb-2 js-pick-out" style="display:none;">'+k("chooseSpeaker","Choose speaker…")+'</button><div class="form-text mb-2 js-out-help">'+k("speakerHelp","Automatic uses the device your system uses for calls. If you cannot hear the assistant, pick the speakers you are actually listening to.")+'</div><label class="form-label mb-1 d-block" style="font-size:0.8rem;">'+k("assistantVolume","Assistant volume")+': <strong class="js-vol-val">'+Math.round(100*o.volume)+'</strong>%</label><input type="range" class="form-range js-vol mb-2" min="0" max="100" step="5" value="'+Math.round(100*o.volume)+'"><label class="form-label mb-1 d-block" style="font-size:0.8rem;">'+k("language","Language")+'</label><select class="form-select form-select-sm js-lang mb-2">'+c+'</select><div class="form-check form-switch mb-1"><input class="form-check-input js-barge" type="checkbox" id="realtime-setting-barge"'+(o.bargeIn?" checked":"")+'><label class="form-check-label" for="realtime-setting-barge">'+k("allowInterruptions","Allow interruptions")+'</label></div><div class="form-text mb-2">'+k("allowInterruptionsHelp","Talk over the assistant to interrupt it. Turn this off if the assistant keeps hearing itself through your speakers.")+'</div><div class="form-check form-switch mb-1"><input class="form-check-input js-ptt" type="checkbox" id="realtime-setting-ptt"'+(o.pushToTalk?" checked":"")+'><label class="form-check-label" for="realtime-setting-ptt">'+k("pushToTalk","Push-to-talk")+'</label></div><div class="form-text">'+k("pushToTalkHelp","Hold <kbd>Space</kbd> (or the button) to talk. For very noisy places.")+"</div></div>",i.appendChild(r),i.appendChild(s),n.insertAdjacentElement("afterend",i),ye=i;var l=s.querySelector(".js-barge"),u=s.querySelector(".js-ptt"),d=s.querySelector(".js-vol"),f=s.querySelector(".js-vol-val"),p=s.querySelector(".js-mic"),m=s.querySelector(".js-out"),h=s.querySelector(".js-pick-out"),v=s.querySelector(".js-lang");g(),navigator.mediaDevices&&"function"==typeof navigator.mediaDevices.addEventListener&&navigator.mediaDevices.addEventListener("devicechange",function(){g(),x&&he&&navigator.mediaDevices.enumerateDevices().then(function(e){e.some(function(e){return"audioinput"===e.kind&&e.deviceId===he})||Le("device_lost")}).catch(function(){})}),r.addEventListener("click",function(n){n.stopPropagation();var a="none"===s.style.display;a&&(s.style.display="block",function(){s.style.right="0px",s.style.left="auto";var n=s.getBoundingClientRect();n.left<8&&(s.style.right=n.left-8+"px");for(var a=r.getBoundingClientRect(),o=8,i=s.parentElement?s.parentElement.parentElement:null;i&&i!==t.body&&i!==t.documentElement;){var c=e.getComputedStyle(i);if("auto"===c.overflowY||"scroll"===c.overflowY||"hidden"===c.overflowY||"fixed"===c.position){o=Math.max(o,i.getBoundingClientRect().top);break}i=i.parentElement}s.style.maxHeight=Math.max(160,a.top-o-10)+"px"}(),g()),s.style.display=a?"block":"none"}),s.addEventListener("click",function(e){e.stopPropagation()}),t.addEventListener("click",function(){s.style.display="none"}),l.addEventListener("change",b),u.addEventListener("change",b),d.addEventListener("input",function(){f.textContent=d.value,b()}),p.addEventListener("change",b),v.addEventListener("change",b),m.addEventListener("change",function(){b(),Ye()}),navigator.mediaDevices&&"function"==typeof navigator.mediaDevices.selectAudioOutput&&(h.style.display="",h.addEventListener("click",function(){navigator.mediaDevices.selectAudioOutput().then(function(e){if(e&&e.deviceId){var n=t.createElement("option");n.value=e.deviceId,n.textContent=e.label||k("selectedSpeaker","Selected speaker"),m.appendChild(n),m.value=e.deviceId,b(),Ye()}}).catch(function(){})}))}function b(){var e={bargeIn:l.checked,pushToTalk:u.checked,volume:(parseInt(d.value,10)||0)/100,micDeviceId:p.value||"",outputDeviceId:m.value||"",language:v.value||"",version:3};De(e),Se(e),function(){if(x&&a&&"function"==typeof a.send)try{a.send("UpdateRealtimeSettings",re,null,null)}catch(e){}}()}function g(){navigator.mediaDevices&&navigator.mediaDevices.enumerateDevices&&navigator.mediaDevices.enumerateDevices().then(function(e){var t=['<option value="">'+k("defaultMicrophone","Default microphone")+"</option>"];e.filter(function(e){return"audioinput"===e.kind}).forEach(function(e,n){var a=e.label||k("microphone","Microphone")+" "+(n+1);t.push('<option value="'+e.deviceId+'"'+(e.deviceId===he?" selected":"")+">"+a.replace(/</g,"")+"</option>")}),p.innerHTML=t.join("");var n=e.filter(function(e){return"audiooutput"===e.kind&&e.deviceId&&"communications"!==e.deviceId&&"default"!==e.deviceId});if(n.length){var a=['<option value="">'+k("automatic","Automatic")+"</option>"];n.forEach(function(e,t){var n=e.label||k("speaker","Speaker")+" "+(t+1);a.push('<option value="'+e.deviceId+'"'+(e.deviceId===ve?" selected":"")+">"+n.replace(/</g,"")+"</option>")}),m.innerHTML=a.join("")}}).catch(function(){})}}());var tt=R("deploymentSelect");tt&&tt.addEventListener("change",function(){Ae($e(tt.value))}),Ae(l||tt&&$e(tt.value));var nt={toggle:Xe,start:We,stop:Qe,applyMode:Ae,isRealtimeDeployment:$e,receivePcm:function(e){if(O&&e&&!(e.length<2)){for(var t=O,n=Math.floor(e.length/2),a=new Int16Array(e.buffer,e.byteOffset,n),o=new Float32Array(n),i=0;i<n;i++)o[i]=a[i]/32768;var r=t.createBuffer(1,n,t.sampleRate);r.copyToChannel(o,0);var c=t.createBufferSource();c.buffer=r,c.connect(H||t.destination);var s=t.currentTime;z<s&&(z=s),c.start(z),z+=r.duration,q.push(c),c.onended=function(){q=q.filter(function(e){return e!==c})}}},isActive:function(){return x},getState:function(){return A},getGateLevel:function(){return oe?oe.getLevel():null},getTransportStats:function(){return V&&"function"==typeof V.getStats?V.getStats().then(function(e){var t={transport:"webrtc",inbound:null,codec:null,sinkId:Y&&"string"==typeof Y.sinkId?Y.sinkId:null,jitterBufferTargetMs:function(){try{var e=V.getReceivers().filter(function(e){return e.track&&"audio"===e.track.kind})[0];return e&&"jitterBufferTarget"in e?e.jitterBufferTarget:null}catch(e){return null}}()};return e.forEach(function(n){if("inbound-rtp"===n.type&&"audio"===n.kind&&(t.inbound={packetsReceived:n.packetsReceived,packetsLost:n.packetsLost,packetsDiscarded:n.packetsDiscarded,jitterMs:"number"==typeof n.jitter?Math.round(1e3*n.jitter):null,jitterBufferDelayMs:"number"==typeof n.jitterBufferDelay&&n.jitterBufferEmittedCount?Math.round(n.jitterBufferDelay/n.jitterBufferEmittedCount*1e3):null,totalSamplesReceived:n.totalSamplesReceived,concealedSamples:n.concealedSamples,concealmentEvents:n.concealmentEvents,silentConcealedSamples:n.silentConcealedSamples,insertedSamplesForDeceleration:n.insertedSamplesForDeceleration,removedSamplesForAcceleration:n.removedSamplesForAcceleration,audioLevel:n.audioLevel},n.codecId)){var a=e.get(n.codecId);a&&(t.codec={mimeType:a.mimeType,clockRate:a.clockRate,channels:a.channels,sdpFmtpLine:a.sdpFmtpLine})}}),t}).catch(function(){return null}):Promise.resolve(null)}};return e.CoreAIRealtime.activeController=nt,nt},createMicGate:c,decideGate:n,createGateState:a,rmsDb:o,routeOutputToPreferredDevice:u,ensurePlayback:d}}(window,document);
|
|
2
2
|
//# sourceMappingURL=realtime-audio.min.js.map
|