@tanay-wispr/webflow-package 6.0.0 → 6.1.0
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/web-demo/index.js +11 -11
- package/package.json +1 -1
package/dist/web-demo/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
"use strict";(()=>{async function ge(){let h=()=>document.querySelector('.w--tab-active [demo-element="input"]'),n=h(),p=document.querySelector('[demo-element="gradient"]'),v=()=>document.querySelector(".wd_pill-wrap"),x=()=>document.querySelector(".wd_pill"),S=()=>x()?.querySelector(".wd_pill-lottie-wrap"),ee=document.querySelectorAll('[demo-element="start-recording"]'),te=document.querySelectorAll('[demo-element="stop-recording"]'),le=new Audio("https://dl.dropbox.com/scl/fi/zv8278qh9ovwq0r89rch1/dictation-start.wav?rlkey=pk241hf4c8qv7780qsq2m4cgv&st=wgpy7vop&dl=0"),he=new Audio("https://dl.dropbox.com/scl/fi/4mkbgr7om46imcp0l86yd/dictation-stop.wav?rlkey=4t5uwvg9kufphlu58natjn43t&st=9or4oqr0&dl=0");function we(e){let r=document.getSelection();return r.rangeCount>0&&e.contains(r.focusNode)?r.getRangeAt(0):null}function be(e,r,s){s.deleteContents();let t=document.createElement("div");t.innerHTML=r;let o=document.createDocumentFragment();for(;t.firstChild;)o.appendChild(t.firstChild);s.insertNode(o),s.collapse(!1);let u=document.getSelection();u.removeAllRanges(),u.addRange(s)}function $(e){e.dataset.isPlaceholder==="true"?(e.classList.remove("cursor-after"),e.classList.add("cursor-before"),e.style.color="#1a1a1a80"):(e.classList.remove("cursor-before"),e.classList.add("cursor-after"),e.style.color="#1a1a1a")}let J=()=>{ee.forEach(e=>{e&&(e.style.display="flex")}),document.querySelectorAll('[demo-element="start-recording-text"]').forEach(e=>{e&&(e.style.display="block")})},G=()=>{ee.forEach(e=>{e&&(e.style.display="none")}),document.querySelectorAll('[demo-element="start-recording-text"]').forEach(e=>{e&&(e.style.display="none")})},ve=()=>{te.forEach(e=>{e&&(e.style.display="flex")}),document.querySelectorAll('[demo-element="stop-recording-text"]').forEach(e=>{e&&(e.style.display="block")})},j=()=>{te.forEach(e=>{e&&(e.style.display="none")}),document.querySelectorAll('[demo-element="stop-recording-text"]').forEach(e=>{e&&(e.style.display="none")})},z=window.matchMedia("(min-width: 992px)").matches,y=null,d=null,ce=[],_=!1,W=!1,K=!0,V=!0,l=null,I=null,Y=null,Z=null,a=null,B=null,k=null,P=0,L=[],oe=1024,Q=16e3,R=[],F=!1,M=null,re=!1,T=null,E=!1;navigator.mediaDevices.getUserMedia({audio:!0}).then(e=>{y=e,e.getAudioTracks().forEach(r=>r.enabled=!1),V=!1}).catch(e=>{console.error("Initial microphone permission denied:",e),V=!1,alert("Please enable microphone access in your browser settings to continue."),G()}),p&&(p.style.opacity="0",p.style.transition="opacity 0.3s ease"),j(),navigator.userAgent.toLowerCase().includes("firefox")&&(document.querySelectorAll("[wd-para-div]").forEach(e=>{e.style.display="none"}),document.querySelectorAll("[wd-start-stop-button-div]").forEach(e=>{e.style.display="block"})),z&&n&&n.focus({preventScroll:!0}),document.querySelectorAll('[demo-element="input"]').forEach((e,r)=>{e.classList.add("cursor-before"),e.dataset.isFirstRecording="true",e.dataset.placeholderText=e.textContent.trim(),e.dataset.placeholderHtml=e.innerHTML,e.dataset.isPlaceholder="true",e.addEventListener("beforeinput",()=>{e.dataset.isPlaceholder==="true"&&(e.innerHTML=""),e.dataset.isPlaceholder="false",$(e)}),e.addEventListener("input",()=>{if(e.textContent.trim()===""){e.innerHTML=e.dataset.placeholderHtml,e.dataset.isPlaceholder="true";let s=document.createRange();s.setStart(e,0),s.collapse(!0);let t=window.getSelection();t.removeAllRanges(),t.addRange(s)}$(e)}),e.addEventListener("focus",()=>{}),e.addEventListener("blur",()=>{e.textContent.trim()===""&&(e.innerHTML=e.dataset.placeholderHtml,e.dataset.isPlaceholder="true",e.dataset.isFirstRecording="true",$(e))}),e.addEventListener("mousedown",s=>{if(e.dataset.isPlaceholder==="true"){s.preventDefault();let t=document.createRange();t.setStart(e,0),t.collapse(!0);let o=window.getSelection();o.removeAllRanges(),o.addRange(t)}}),e.addEventListener("keydown",s=>{if(e.dataset.isPlaceholder==="true"&&["ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home","End"].includes(s.key)){s.preventDefault();let t=document.createRange();t.setStart(e,0),t.collapse(!0);let o=window.getSelection();o.removeAllRanges(),o.addRange(t)}})});let se=new MutationObserver(()=>{de()});se.observe(n,{childList:!0,subtree:!0,characterData:!0}),ue().catch(e=>{console.error("Initial token generation failed:",e)});let ne,Se=e=>new Promise((r,s)=>{let t=new FileReader;t.onloadend=()=>{typeof t.result=="string"?r(t.result.split(",")[1]):s(new Error("Failed to convert blob to base64"))},t.onerror=s,t.readAsDataURL(e)}),ke=async()=>{let r=L.length*1*2+44,s=new ArrayBuffer(r),t=new DataView(s),o=0,u=(f,w,g)=>{for(let m=0;m<g.length;m++)f.setUint8(w+m,g.charCodeAt(m))};u(t,0,"RIFF"),o+=4,t.setUint32(o,36+L.length*1*2,!0),o+=4,u(t,o,"WAVE"),o+=4,u(t,o,"fmt "),o+=4,t.setUint32(o,16,!0),o+=4,t.setUint16(o,1,!0),o+=2,t.setUint16(o,1,!0),o+=2,t.setUint32(o,Q,!0),o+=4,t.setUint32(o,Q*1*2,!0),o+=4,t.setUint16(o,1*2,!0),o+=2,t.setUint16(o,16,!0),o+=2,u(t,o,"data"),o+=4,t.setUint32(o,L.length*1*2,!0),o+=4;for(let f=0;f<L.length;f++)t.setInt16(o,L[f],!0),o+=2;return new Blob([t],{type:"audio/wav"})};function Le(){if(!F||R.length===0)return;console.log(`Flushing ${R.length} buffered audio chunks...`),R.forEach(r=>{try{a&&a.readyState===WebSocket.OPEN&&a.send(JSON.stringify(r))}catch(s){console.error(`Error sending buffered chunk ${r.position}:`,s)}});let e=M?Date.now()-M:0;console.log(`Buffer flushed! Buffering lasted ${e}ms`),R=[],F=!1,M=null}let de=()=>{n&&(n.scrollHeight>n.clientHeight?n.style.overflowY="auto":n.style.overflowY="visible")};async function ue(){try{let e=await fetch("https://api.wisprflow.ai/api/v1/dash/webflow_demo/generate_token",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_id:"webflow_demo"})});if(!e.ok)throw new Error(`Token generation failed with status: ${e.status}`);let r=await e.json();return localStorage.setItem("accessToken",r.access_token),localStorage.setItem("tokenExpiration",(Date.now()+r.expires_in*1e3).toString()),r.access_token}catch(e){if(console.error("Token generation failed:",e),n||(n=h()),!n)return;throw document.querySelectorAll('[demo-element="input"]').forEach(r=>{r.innerHTML='Our servers are busy processing requests right now. <a href="/get-started" class="text-color-primary text-weight-medium">Try our desktop app instead.</a>',r.removeAttribute("contenteditable")}),n.classList.remove("cursor-before","cursor-after"),G(),K=!1,e}}async function fe(){let e=localStorage.getItem("tokenExpiration");return!e||Date.now()>=parseInt(e)?await ue():localStorage.getItem("accessToken")}async function Te(){a&&a.readyState===WebSocket.CLOSED&&(a=null),a&&(a.readyState===WebSocket.OPEN||a.readyState===WebSocket.CONNECTING)&&(a.onclose=null,a.close(),a=null);let e=await fe(),r=`wss://api.wisprflow.ai/api/v1/dash/client_ws?client_key=Bearer ${e}`;console.log("Connecting to WebSocket"),a=new WebSocket(r),a.onopen=()=>{let t=new URLSearchParams(window.location.search).get("type")==="email"?"email":"other";a.send(JSON.stringify({type:"auth",access_token:`Bearer ${e}`,context:{app:{type:t}}}))},a.onmessage=s=>{try{let t=JSON.parse(s.data);if(t.status==="error"||t.status==="auth_error"){console.error("WebSocket error:",t),N();return}if(t.status==="text"&&t.final){if(re=!0,T&&(clearTimeout(T),T=null),t.body&&t.body.text===null)console.log("Empty recording detected, skipping text display");else{let o="No speech detected.";t.body&&t.body.text?o=t.body.text:t.body.status==="formatted"?o=t.body.llm_text:t.body.status==="raw_transcript"&&(o=t.body.asr_text),me(o+"\xA0")}J(),j(),S()?.classList.remove("show"),v()?.style.setProperty("opacity","0")}}catch(t){console.error("WebSocket message parsing error:",t),N()}},a.onclose=s=>{console.log("WebSocket closed:",s.code,s.reason),a=null,E=!1},a.onerror=s=>{console.error("WebSocket error:",s)}}async function Ee(){if(a&&a.readyState===WebSocket.CONNECTING){console.log("\u23F3 WebSocket already connecting, skipping duplicate call");return}try{E=!1,await Te();let e=0,r=50;for(;(!a||a.readyState!==WebSocket.OPEN)&&e<r;)await new Promise(s=>setTimeout(s,100)),e++;a&&a.readyState===WebSocket.OPEN?(E=!0,console.log("\u2705 WebSocket marked as ready for streaming")):(console.log("WebSocket connection failed, will use fallback"),E=!1)}catch(e){console.error("WebSocket background connection failed:",e),E=!1}}function N(){T&&(clearTimeout(T),T=null),Ae()}async function Ae(){try{console.log("Using Fetch API fallback with collected samples");let e=await ke(),r=await Se(e),s=await fe(),t=await fetch("https://api.wisprflow.ai/api/v1/dash/client_api",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({audio:r,properties:{language:""}})});if(!t.ok)throw new Error("Fallback server error");let o=await t.json();if(o.text===null){console.log("Empty fallback recording detected, skipping text display"),S()?.classList.remove("show"),v()?.style.setProperty("opacity","0"),J(),j();return}me(o.text+"\xA0"),S()?.classList.remove("show"),v()?.style.setProperty("opacity","0"),J(),j()}catch(e){if(console.error("Fallback also failed:",e),n||(n=h()),!n)return;document.querySelectorAll('[demo-element="input"]').forEach(r=>{r.innerHTML='Our servers are busy processing requests right now. <a href="/get-started" class="text-color-primary text-weight-medium">Try our desktop app instead.</a>',r.removeAttribute("contenteditable")}),n.classList.remove("cursor-before","cursor-after"),G(),K=!1,x()?.classList.remove("is-speaking"),S()?.classList.remove("show"),v()?.style.setProperty("opacity","0")}}async function Ce(){try{return y&&y.getAudioTracks().length>0?y.getAudioTracks().forEach(e=>e.enabled=!0):y=await navigator.mediaDevices.getUserMedia({audio:!0}),d=new MediaRecorder(y),d.ondataavailable=e=>{ce.push(e.data)},d.onstop=async()=>{y.getTracks().forEach(e=>{e.enabled=!1}),d=null},!0}catch(e){return console.error("Microphone access error:",e),(e.name==="NotAllowedError"||e.name==="PermissionDeniedError")&&alert("Please enable microphone access in your browser settings to continue."),!1}}function me(e,r=!1){if(e=e.replace(/\n/g,"<br>"),e=e.replace(/<br>(?=\s*<\/?(?:ul|ol|li))|(?<=<\/?(?:ul|ol|li)>\s*)<br>/gi,""),!n)return;n.dataset.isPlaceholder==="true"&&(n.innerHTML=""),n.dataset.isPlaceholder="false",n.classList.remove("no-cursor");let s=we(n);if(s?be(n,e,s):n.textContent.trim()===""?n.innerHTML=e:n.innerHTML+=e,de(),n.dataset.previousText=n.textContent,n.dataset.isFirstRecording==="true"&&(n.classList.remove("cursor-before"),n.classList.add("cursor-after"),n.dataset.isFirstRecording="false"),typeof posthog<"u"){let o=document.querySelector(".w-tab-link.w--current"),u=o?o.textContent.trim().toLowerCase().replace(/\s+/g,"_"):"Unknown";posthog.capture("demo_transcription_completed",{transcribed_text:e,tab_name:u})}document.querySelectorAll(".wd-tab-content-bottom").forEach(o=>{o.style.display="flex"}),$(n),J()}async function pe(e=!1){if(n||(n=h()),!n)return;document.querySelectorAll(".wd-tab-link").forEach(o=>{o.classList.contains("w--current")||o.classList.add("pointer-events-none")}),R=[],F=!1,M=null,P=0,Ee();let s=n.innerHTML||"";s&&!s.includes("Flow is listening")&&!s.includes("Converting...")&&!s.includes("Error")&&(n.dataset.previousText=s);let t=n.dataset.isFirstRecording==="true";n.classList.add("no-cursor");try{le.currentTime=0,le.play()}catch(o){console.error("Error playing start dictation sound:",o)}if(!d&&!await Ce()){n.dataset.previousText?n.innerHTML=n.dataset.previousText:n.innerHTML="",n.classList.remove("no-cursor");return}if(d.state==="inactive"){ce=[],d.start(),_=!0,L=[],P=0,l||(l=new AudioContext),B=l.createMediaStreamSource(y),k=l.createScriptProcessor(oe,1,1),k.onaudioprocess=async f=>{let w=f.inputBuffer.getChannelData(0),g=Math.ceil(oe*Q/l.sampleRate),m=new OfflineAudioContext(1,g,Q),q=l.createBuffer(1,w.length,l.sampleRate);q.copyToChannel(w,0);let D=m.createBufferSource();D.buffer=q,D.connect(m.destination),D.start();let c=(await m.startRendering()).getChannelData(0),C=new Int16Array(c.length),O=0;for(let i=0;i<c.length;i++){let ie=Math.max(-1,Math.min(1,c[i]));C[i]=ie<0?ie*32768:ie*32767,L.push(C[i]),O+=c[i]*c[i]}let H=Math.sqrt(O/c.length),X=new Uint8Array(C.buffer),b="";for(let i=0;i<X.length;i++)b+=String.fromCharCode(X[i]);let Re=btoa(b);try{let i={type:"append",position:P,final:!1,audio_packets:{packets:[Re],volumes:[H],packet_duration:oe/l.sampleRate,audio_encoding:"wav",byte_encoding:"base64"}};E&&a&&a.readyState===WebSocket.OPEN?(F&&Le(),a.send(JSON.stringify(i))):(R.push(i),F=!0,M||(M=Date.now()),P===0&&console.log("WebSocket not ready yet, buffering audio chunks")),P++}catch(i){console.error("Error processing audio chunk:",i)}},B.connect(k),k.connect(l.destination),p&&(p.style.opacity="1"),v()?.style.setProperty("opacity","1"),x()?.classList.remove("is-speaking"),S()?.classList.remove("show");let o=document.querySelector(".wave-svg");o&&(o.style.opacity="1"),ne=p.animate([{transform:"scale(1)"},{transform:"scale(1.3)"},{transform:"scale(1)"}],{duration:1500,iterations:1/0}),G(),ve(),I=l.createAnalyser(),l.createMediaStreamSource(y).connect(I),I.fftSize=32,Y=new Uint8Array(I.frequencyBinCount),Z=setInterval(()=>{I.getByteFrequencyData(Y);let f=Y.reduce((A,c)=>A+c,0)/Y.length,w=8,g=0;f>w&&(g=Math.pow((f-w)/(255-w),1.5));let m=1+g*2,q=x();q&&(g>.06?q.classList.add("is-speaking"):q.classList.remove("is-speaking")),p.animate([{transform:`scale(${m})`}],{duration:300,fill:"forwards"});let D=document.querySelector(".wave-path");if(D){let A=40+g*300,c=Date.now()/1e3,C=b=>A*.3*Math.sin(b/1440*Math.PI*2+c*.8),O=b=>A*.2*Math.sin(b/720*Math.PI*2+c*1.2),H=b=>A*.1*Math.sin(b/360*Math.PI*2+c*1.8),X=`
|
|
1
|
+
"use strict";(()=>{var W=class{constructor(){this.mediaStream=null,this.mediaRecorder=null,this.audioChunks=[],this.audioContext=null,this.analyser=null,this.dataArray=null,this.mediaStreamSource=null,this.processor=null,this.intSamples=[],this.BUFFER_SIZE=1024,this.TARGET_SAMPLE_RATE=16e3}blobToBase64(o){return new Promise((i,n)=>{let r=new FileReader;r.onloadend=()=>{typeof r.result=="string"?i(r.result.split(",")[1]):n(new Error("Failed to convert blob to base64"))},r.onerror=n,r.readAsDataURL(o)})}async convertIntSamplesToWAV(){let i=this.intSamples.length*1*2+44,n=new ArrayBuffer(i),r=new DataView(n),t=0,l=(d,g,u)=>{for(let m=0;m<u.length;m++)d.setUint8(g+m,u.charCodeAt(m))};l(r,0,"RIFF"),t+=4,r.setUint32(t,36+this.intSamples.length*1*2,!0),t+=4,l(r,t,"WAVE"),t+=4,l(r,t,"fmt "),t+=4,r.setUint32(t,16,!0),t+=4,r.setUint16(t,1,!0),t+=2,r.setUint16(t,1,!0),t+=2,r.setUint32(t,this.TARGET_SAMPLE_RATE,!0),t+=4,r.setUint32(t,this.TARGET_SAMPLE_RATE*1*2,!0),t+=4,r.setUint16(t,1*2,!0),t+=2,r.setUint16(t,16,!0),t+=2,l(r,t,"data"),t+=4,r.setUint32(t,this.intSamples.length*1*2,!0),t+=4;for(let d=0;d<this.intSamples.length;d++)r.setInt16(t,this.intSamples[d],!0),t+=2;return new Blob([r],{type:"audio/wav"})}async requestMicrophonePermission(){try{return this.mediaStream=await navigator.mediaDevices.getUserMedia({audio:!0}),this.mediaStream.getAudioTracks().forEach(o=>{o.enabled=!1}),!0}catch(o){return console.error("Initial microphone permission denied:",o),!1}}async setupRecorder(){try{return this.mediaStream&&this.mediaStream.getAudioTracks().length>0?this.mediaStream.getAudioTracks().forEach(o=>{o.enabled=!0}):this.mediaStream=await navigator.mediaDevices.getUserMedia({audio:!0}),this.mediaRecorder=new MediaRecorder(this.mediaStream),this.mediaRecorder.ondataavailable=o=>{this.audioChunks.push(o.data)},this.mediaRecorder.onstop=async()=>{this.mediaStream.getTracks().forEach(o=>{o.enabled=!1}),this.mediaRecorder=null},!0}catch(o){return console.error("Microphone access error:",o),(o.name==="NotAllowedError"||o.name==="PermissionDeniedError")&&alert("Please enable microphone access in your browser settings to continue."),!1}}async startRecording(o){this.mediaRecorder.state==="inactive"&&(this.audioChunks=[],this.mediaRecorder.start(),this.intSamples=[],this.audioContext||(this.audioContext=new AudioContext),this.mediaStreamSource=this.audioContext.createMediaStreamSource(this.mediaStream),this.processor=this.audioContext.createScriptProcessor(this.BUFFER_SIZE,1,1),this.processor.onaudioprocess=async i=>{let n=i.inputBuffer.getChannelData(0),r=Math.ceil(this.BUFFER_SIZE*this.TARGET_SAMPLE_RATE/this.audioContext.sampleRate),t=new OfflineAudioContext(1,r,this.TARGET_SAMPLE_RATE),l=this.audioContext.createBuffer(1,n.length,this.audioContext.sampleRate);l.copyToChannel(n,0);let d=t.createBufferSource();d.buffer=l,d.connect(t.destination),d.start();let u=(await t.startRendering()).getChannelData(0),m=new Int16Array(u.length),w=0;for(let h=0;h<u.length;h++){let b=Math.max(-1,Math.min(1,u[h]));m[h]=b<0?b*32768:b*32767,this.intSamples.push(m[h]),w+=u[h]*u[h]}let E=Math.sqrt(w/u.length),L=new Uint8Array(m.buffer),C="";for(let h=0;h<L.length;h++)C+=String.fromCharCode(L[h]);let F=btoa(C);o&&o({audio:F,volume:E,packetDuration:this.BUFFER_SIZE/this.audioContext.sampleRate})},this.mediaStreamSource.connect(this.processor),this.processor.connect(this.audioContext.destination))}async stopRecording(){this.mediaRecorder&&this.mediaRecorder.state==="recording"&&this.mediaRecorder.stop(),this.processor&&(this.processor.disconnect(),this.processor=null),this.mediaStreamSource&&(this.mediaStreamSource.disconnect(),this.mediaStreamSource=null)}setupAudioAnalysis(){return this.audioContext||(this.audioContext=new AudioContext),this.analyser=this.audioContext.createAnalyser(),this.audioContext.createMediaStreamSource(this.mediaStream).connect(this.analyser),this.analyser.fftSize=32,this.dataArray=new Uint8Array(this.analyser.frequencyBinCount),{analyser:this.analyser,dataArray:this.dataArray}}getVolumeScale(){if(!this.analyser||!this.dataArray)return 0;this.analyser.getByteFrequencyData(this.dataArray);let o=this.dataArray.reduce((r,t)=>r+t,0)/this.dataArray.length,i=8,n=0;return o>i&&(n=Math.pow((o-i)/(255-i),1.5)),n}getIntSamples(){return this.intSamples}async closeAudioContext(){this.audioContext&&(await this.audioContext.close(),this.audioContext=null)}isRecording(){return this.mediaRecorder&&this.mediaRecorder.state==="recording"}};var M=class{constructor(){this.storageKeys={accessToken:"accessToken",tokenExpiration:"tokenExpiration"}}async generateAndStoreToken(){try{let o=await fetch("https://api.wisprflow.ai/api/v1/dash/webflow_demo/generate_token",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_id:"webflow_demo"})});if(!o.ok)throw new Error(`Token generation failed with status: ${o.status}`);let i=await o.json();return localStorage.setItem(this.storageKeys.accessToken,i.access_token),localStorage.setItem(this.storageKeys.tokenExpiration,(Date.now()+i.expires_in*1e3).toString()),i.access_token}catch(o){throw console.error("Token generation failed:",o),o}}async getValidToken(){let o=localStorage.getItem(this.storageKeys.tokenExpiration);return!o||Date.now()>=parseInt(o)?await this.generateAndStoreToken():localStorage.getItem(this.storageKeys.accessToken)}};var _=class{constructor(o,i){this.tokenService=o,this.audioService=i,this.websocket=null,this.isWebSocketReady=!1,this.audioChunkBuffer=[],this.isBufferFlushNeeded=!1,this.bufferStartTime=null,this.packetPosition=0,this.transcriptionReceived=!1,this.commitTimeout=null,this.onTranscriptionReceived=null,this.onError=null}async setupWebSocket(){this.websocket&&this.websocket.readyState===WebSocket.CLOSED&&(this.websocket=null),this.websocket&&(this.websocket.readyState===WebSocket.OPEN||this.websocket.readyState===WebSocket.CONNECTING)&&(this.websocket.onclose=null,this.websocket.close(),this.websocket=null);let o=await this.tokenService.getValidToken(),i=`wss://api.wisprflow.ai/api/v1/dash/client_ws?client_key=Bearer ${o}`;console.log("Connecting to WebSocket"),this.websocket=new WebSocket(i),this.websocket.onopen=()=>{let r=new URLSearchParams(window.location.search).get("type")==="email"?"email":"other";this.websocket.send(JSON.stringify({type:"auth",access_token:`Bearer ${o}`,context:{app:{type:r}}}))},this.websocket.onmessage=n=>{try{let r=JSON.parse(n.data);if(r.status==="error"||r.status==="auth_error"){console.error("WebSocket error:",r),this.triggerFallback();return}if(r.status==="text"&&r.final)if(this.transcriptionReceived=!0,this.commitTimeout&&(clearTimeout(this.commitTimeout),this.commitTimeout=null),r.body&&r.body.text===null)console.log("Empty recording detected, skipping text display"),this.onTranscriptionReceived&&this.onTranscriptionReceived(null);else{let t="No speech detected.";r.body&&r.body.text?t=r.body.text:r.body.status==="formatted"?t=r.body.llm_text:r.body.status==="raw_transcript"&&(t=r.body.asr_text),this.onTranscriptionReceived&&this.onTranscriptionReceived(t)}}catch(r){console.error("WebSocket message parsing error:",r),this.triggerFallback()}},this.websocket.onclose=n=>{console.log("WebSocket closed:",n.code,n.reason),this.websocket=null,this.isWebSocketReady=!1},this.websocket.onerror=n=>{console.error("WebSocket error:",n)}}async connectWebSocketInBackground(){if(this.websocket&&this.websocket.readyState===WebSocket.CONNECTING){console.log("\u23F3 WebSocket already connecting, skipping duplicate call");return}try{this.isWebSocketReady=!1,await this.setupWebSocket();let o=0,i=50;for(;(!this.websocket||this.websocket.readyState!==WebSocket.OPEN)&&o<i;)await new Promise(n=>setTimeout(n,100)),o++;this.websocket&&this.websocket.readyState===WebSocket.OPEN?(this.isWebSocketReady=!0,console.log("\u2705 WebSocket marked as ready for streaming")):(console.log("WebSocket connection failed, will use fallback"),this.isWebSocketReady=!1)}catch(o){console.error("WebSocket background connection failed:",o),this.isWebSocketReady=!1}}flushAudioBuffer(){if(!this.isBufferFlushNeeded||this.audioChunkBuffer.length===0)return;console.log(`Flushing ${this.audioChunkBuffer.length} buffered audio chunks...`),this.audioChunkBuffer.forEach(i=>{try{this.websocket&&this.websocket.readyState===WebSocket.OPEN&&this.websocket.send(JSON.stringify(i))}catch(n){console.error(`Error sending buffered chunk ${i.position}:`,n)}});let o=this.bufferStartTime?Date.now()-this.bufferStartTime:0;console.log(`Buffer flushed! Buffering lasted ${o}ms`),this.audioChunkBuffer=[],this.isBufferFlushNeeded=!1,this.bufferStartTime=null}sendAudioChunk(o){let i={type:"append",position:this.packetPosition,final:!1,audio_packets:{packets:[o.audio],volumes:[o.volume],packet_duration:o.packetDuration,audio_encoding:"wav",byte_encoding:"base64"}};this.isWebSocketReady&&this.websocket&&this.websocket.readyState===WebSocket.OPEN?(this.isBufferFlushNeeded&&this.flushAudioBuffer(),this.websocket.send(JSON.stringify(i))):(this.audioChunkBuffer.push(i),this.isBufferFlushNeeded=!0,this.bufferStartTime||(this.bufferStartTime=Date.now()),this.packetPosition===0&&console.log("WebSocket not ready yet, buffering audio chunks")),this.packetPosition++}async commitRecording(){if(this.transcriptionReceived=!1,this.isWebSocketReady&&this.websocket&&this.websocket.readyState===WebSocket.OPEN)try{this.websocket.send(JSON.stringify({type:"commit",total_packets:this.packetPosition})),this.commitTimeout=setTimeout(()=>{this.transcriptionReceived||(console.log("WebSocket timeout, falling back to Fetch"),this.triggerFallback())},4e3)}catch(o){console.error("WebSocket commit failed:",o),this.triggerFallback()}else console.log("WebSocket not available, using Fetch fallback"),this.triggerFallback()}triggerFallback(){this.commitTimeout&&(clearTimeout(this.commitTimeout),this.commitTimeout=null),this.sendAudioToServerFallback()}async sendAudioToServerFallback(){try{console.log("Using Fetch API fallback with collected samples");let o=await this.audioService.convertIntSamplesToWAV(),i=await this.audioService.blobToBase64(o),n=await this.tokenService.getValidToken(),r=await fetch("https://api.wisprflow.ai/api/v1/dash/client_api",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({audio:i,properties:{language:""}})});if(!r.ok)throw new Error("Fallback server error");let t=await r.json();if(t.text===null){console.log("Empty fallback recording detected, skipping text display"),this.onTranscriptionReceived&&this.onTranscriptionReceived(null);return}this.onTranscriptionReceived&&this.onTranscriptionReceived(t.text)}catch(o){console.error("Fallback also failed:",o),this.onError&&this.onError(o)}}resetSession(){this.audioChunkBuffer=[],this.isBufferFlushNeeded=!1,this.bufferStartTime=null,this.packetPosition=0,this.transcriptionReceived=!1,this.commitTimeout&&(clearTimeout(this.commitTimeout),this.commitTimeout=null)}isReady(){return this.isWebSocketReady}};async function z(p="control"){let o=new M,i=new W,n=new _(o,i),r=()=>document.querySelector('.w--tab-active [demo-element="input"]'),t=r(),l=document.querySelector('[demo-element="gradient"]'),d=()=>document.querySelector(".wd_pill-wrap"),g=()=>document.querySelector(".wd_pill"),u=()=>g()?.querySelector(".wd_pill-lottie-wrap"),m=document.querySelectorAll('[demo-element="start-recording"]'),w=document.querySelectorAll('[demo-element="stop-recording"]'),E=new Audio("https://dl.dropbox.com/scl/fi/zv8278qh9ovwq0r89rch1/dictation-start.wav?rlkey=pk241hf4c8qv7780qsq2m4cgv&st=wgpy7vop&dl=0"),L=new Audio("https://dl.dropbox.com/scl/fi/4mkbgr7om46imcp0l86yd/dictation-stop.wav?rlkey=4t5uwvg9kufphlu58natjn43t&st=9or4oqr0&dl=0");function C(e){let s=document.getSelection();return s.rangeCount>0&&e.contains(s.focusNode)?s.getRangeAt(0):null}function F(e,s,a){a.deleteContents();let c=document.createElement("div");c.innerHTML=s;let y=document.createDocumentFragment();for(;c.firstChild;)y.appendChild(c.firstChild);a.insertNode(y),a.collapse(!1);let f=document.getSelection();f.removeAllRanges(),f.addRange(a)}function h(e){e.dataset.isPlaceholder==="true"?(e.classList.remove("cursor-after"),e.classList.add("cursor-before"),e.style.color="#1a1a1a80"):(e.classList.remove("cursor-before"),e.classList.add("cursor-after"),e.style.color="#1a1a1a")}let b=()=>{m.forEach(e=>{e&&(e.style.display="flex")}),document.querySelectorAll('[demo-element="start-recording-text"]').forEach(e=>{e&&(e.style.display="block")})},k=()=>{m.forEach(e=>{e&&(e.style.display="none")}),document.querySelectorAll('[demo-element="start-recording-text"]').forEach(e=>{e&&(e.style.display="none")})},Y=()=>{w.forEach(e=>{e&&(e.style.display="flex")}),document.querySelectorAll('[demo-element="stop-recording-text"]').forEach(e=>{e&&(e.style.display="block")})},D=()=>{w.forEach(e=>{e&&(e.style.display="none")}),document.querySelectorAll('[demo-element="stop-recording-text"]').forEach(e=>{e&&(e.style.display="none")})},x=window.matchMedia("(min-width: 992px)").matches,v=!1,T=!1,S=!0,P=!0,B=null,G=!1;i.requestMicrophonePermission().then(e=>{if(P=!1,!e){if(alert("Please enable microphone access in your browser settings to continue."),t||(t=r()),!t)return;document.querySelectorAll('[demo-element="input"]').forEach(s=>{s.innerHTML="Please enable microphone access in your browser settings to continue.",s.removeAttribute("contenteditable")}),t.classList.remove("cursor-before","cursor-after"),k(),S=!1,document.querySelectorAll('[ab-test="both-variants"]').forEach(s=>{s.style.display="none"})}}).catch(e=>{console.error("Initial microphone permission denied:",e),P=!1,alert("Please enable microphone access in your browser settings to continue."),t||(t=r()),t&&(document.querySelectorAll('[demo-element="input"]').forEach(s=>{s.innerHTML="Please enable microphone access in your browser settings to continue.",s.removeAttribute("contenteditable")}),t.classList.remove("cursor-before","cursor-after"),k(),S=!1,document.querySelectorAll('[ab-test="both-variants"]').forEach(s=>{s.style.display="none"}))}),l&&(l.style.opacity="0",l.style.transition="opacity 0.3s ease"),D(),navigator.userAgent.toLowerCase().includes("firefox")&&(document.querySelectorAll('[wd-para-div="hero-section"]').forEach(e=>{e.style.display="none"}),document.querySelectorAll('[ab-test="both-variants"]').forEach(e=>{e.querySelectorAll(".hide-tablet").forEach(s=>{s.classList.remove("hide-tablet"),s.classList.add("hide")})})),x&&t&&t.focus({preventScroll:!0}),document.querySelectorAll('[demo-element="input"]').forEach(e=>{e.classList.add("cursor-before"),e.dataset.isFirstRecording="true",e.dataset.placeholderText=e.textContent.trim(),e.dataset.placeholderHtml=e.innerHTML,e.dataset.isPlaceholder="true",e.addEventListener("beforeinput",()=>{e.dataset.isPlaceholder==="true"&&(e.innerHTML=""),e.dataset.isPlaceholder="false",h(e)}),e.addEventListener("input",()=>{if(e.textContent.trim()===""){e.innerHTML=e.dataset.placeholderHtml,e.dataset.isPlaceholder="true";let s=document.createRange();s.setStart(e,0),s.collapse(!0);let a=window.getSelection();a.removeAllRanges(),a.addRange(s)}h(e)}),e.addEventListener("focus",()=>{}),e.addEventListener("blur",()=>{e.textContent.trim()===""&&(e.innerHTML=e.dataset.placeholderHtml,e.dataset.isPlaceholder="true",e.dataset.isFirstRecording="true",h(e))}),e.addEventListener("mousedown",s=>{if(e.dataset.isPlaceholder==="true"){s.preventDefault();let a=document.createRange();a.setStart(e,0),a.collapse(!0);let c=window.getSelection();c.removeAllRanges(),c.addRange(a)}}),e.addEventListener("keydown",s=>{if(e.dataset.isPlaceholder==="true"&&["ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home","End"].includes(s.key)){s.preventDefault();let a=document.createRange();a.setStart(e,0),a.collapse(!0);let c=window.getSelection();c.removeAllRanges(),c.addRange(a)}})});let I=new MutationObserver(()=>{K()});I.observe(t,{childList:!0,subtree:!0,characterData:!0}),o.generateAndStoreToken().catch(e=>{console.error("Initial token generation failed:",e),t||(t=r()),t&&(document.querySelectorAll('[demo-element="input"]').forEach(s=>{s.innerHTML='Our servers are busy processing requests right now. <a href="/get-started" class="text-color-primary text-weight-medium">Try our desktop app instead.</a>',s.removeAttribute("contenteditable")}),t.classList.remove("cursor-before","cursor-after"),k(),S=!1,document.querySelectorAll('[ab-test="both-variants"]').forEach(s=>{s.style.display="none"}))});let N,K=()=>{t&&(t.scrollHeight>t.clientHeight?t.style.overflowY="auto":t.style.overflowY="visible")};n.onTranscriptionReceived=e=>{e===null?(u()?.classList.remove("show"),d()?.style.setProperty("opacity","0"),b(),D()):(Q(e+"\xA0"),b(),D(),u()?.classList.remove("show"),d()?.style.setProperty("opacity","0"))},n.onError=e=>{console.error("WebSocket service error:",e),t||(t=r()),t&&(document.querySelectorAll('[demo-element="input"]').forEach(s=>{s.innerHTML='Our servers are busy processing requests right now. <a href="/get-started" class="text-color-primary text-weight-medium">Try our desktop app instead.</a>',s.removeAttribute("contenteditable")}),t.classList.remove("cursor-before","cursor-after"),k(),S=!1,g()?.classList.remove("is-speaking"),u()?.classList.remove("show"),d()?.style.setProperty("opacity","0"),document.querySelectorAll('[ab-test="both-variants"]').forEach(s=>{s.style.display="none"}))};function Q(e){if(e=e.replace(/\n/g,"<br>"),e=e.replace(/<br>(?=\s*<\/?(?:ul|ol|li))|(?<=<\/?(?:ul|ol|li)>\s*)<br>/gi,""),!t)return;t.dataset.isPlaceholder==="true"&&(t.innerHTML=""),t.dataset.isPlaceholder="false",t.classList.remove("no-cursor");let s=C(t);if(s?F(t,e,s):t.textContent.trim()===""?t.innerHTML=e:t.innerHTML+=e,K(),t.dataset.previousText=t.textContent,t.dataset.isFirstRecording==="true"&&(t.classList.remove("cursor-before"),t.classList.add("cursor-after"),t.dataset.isFirstRecording="false"),typeof posthog<"u"){let c=document.querySelector(".w-tab-link.w--current"),y=c?c.textContent.trim().toLowerCase().replace(/\s+/g,"_"):"Unknown";posthog.capture("demo_transcription_completed",{transcribed_text:e,tab_name:y})}if(!G){G=!0,console.log("\u{1F3A8} Applying post-recording UI updates (first recording completed)"),document.querySelectorAll('[ab-test="download-button"]').forEach(f=>{f.style.display="block",f.style.visibility="visible"});let c=document.querySelectorAll('[demo-element="start-recording"]'),y=document.querySelectorAll('[demo-element="stop-recording"]');c.forEach(f=>f.classList.add("is-secondary")),y.forEach(f=>f.classList.add("is-secondary")),document.querySelectorAll('[ab-test="both-variants"] .wd-para').forEach(f=>{f.classList.add("text-style-muted")}),console.log("\u2705 Post-recording UI updates applied")}h(t),b()}async function J(){if(t||(t=r()),!t)return;m.forEach(a=>{a&&a.classList.remove("glow-purple")}),document.querySelectorAll(".wd-tab-link").forEach(a=>{a.classList.contains("w--current")||a.classList.add("pointer-events-none")}),n.resetSession(),n.connectWebSocketInBackground();let s=t.innerHTML||"";s&&!s.includes("Flow is listening")&&!s.includes("Converting...")&&!s.includes("Error")&&(t.dataset.previousText=s),t.classList.add("no-cursor");try{E.currentTime=0,E.play()}catch(a){console.error("Error playing start dictation sound:",a)}if(!i.mediaRecorder&&!await i.setupRecorder()){t.dataset.previousText?t.innerHTML=t.dataset.previousText:t.innerHTML="",t.classList.remove("no-cursor");return}if(!i.isRecording()){v=!0,await i.startRecording(c=>{n.sendAudioChunk(c)}),l&&(l.style.opacity="1"),d()?.style.setProperty("opacity","1"),g()?.classList.remove("is-speaking"),u()?.classList.remove("show");let a=document.querySelector(".wave-svg");a&&(a.style.opacity="1"),N=l.animate([{transform:"scale(1)"},{transform:"scale(1.3)"},{transform:"scale(1)"}],{duration:1500,iterations:1/0}),k(),Y(),i.setupAudioAnalysis(),B=setInterval(()=>{let c=i.getVolumeScale(),y=1+c*2,f=g();f&&(c>.06?f.classList.add("is-speaking"):f.classList.remove("is-speaking")),l.animate([{transform:`scale(${y})`}],{duration:300,fill:"forwards"});let j=document.querySelector(".wave-path");if(j){let q=40+c*300,U=Date.now()/1e3,H=R=>q*.3*Math.sin(R/1440*Math.PI*2+U*.8),$=R=>q*.2*Math.sin(R/720*Math.PI*2+U*1.2),V=R=>q*.1*Math.sin(R/360*Math.PI*2+U*1.8),te=`
|
|
2
2
|
M0,160
|
|
3
|
-
C120,${100+
|
|
4
|
-
240,${220
|
|
5
|
-
480,${160+
|
|
6
|
-
C720,${100+
|
|
7
|
-
900,${220
|
|
8
|
-
1080,${160+
|
|
9
|
-
C1260,${100+
|
|
10
|
-
1440,${220
|
|
11
|
-
1440,${160+
|
|
3
|
+
C120,${100+H(120)}
|
|
4
|
+
240,${220+$(240)}
|
|
5
|
+
480,${160+V(480)}
|
|
6
|
+
C720,${100+H(720)}
|
|
7
|
+
900,${220+$(900)}
|
|
8
|
+
1080,${160+V(1080)}
|
|
9
|
+
C1260,${100+H(1260)}
|
|
10
|
+
1440,${220+$(1440)}
|
|
11
|
+
1440,${160+V(1440)}
|
|
12
12
|
L1440,320 L0,320 Z
|
|
13
|
-
`;
|
|
13
|
+
`;j.setAttribute("d",te)}},50)}}async function O(){try{L.play()}catch(s){console.error("Error playing stop dictation sound:",s)}if(i.isRecording()){await i.stopRecording(),v=!1,l&&(l.style.opacity="0"),g()?.classList.remove("is-speaking"),d()?.style.setProperty("opacity","1"),u()?.classList.add("show");let s=document.querySelector(".wave-svg");s&&(s.style.opacity="0"),N&&N.cancel()}B&&(clearInterval(B),B=null),await i.closeAudioContext(),await n.commitRecording(),document.querySelectorAll(".wd-tab-link").forEach(s=>{s.classList.remove("pointer-events-none")})}let X=100,A=null;document.addEventListener("keydown",e=>{console.log("Key pressed:",e.key),x&&e.key==="Control"&&!T&&S&&!v&&(e.preventDefault(),T=!0,A=setTimeout(()=>{T&&J(!0)},X))}),document.addEventListener("keyup",async e=>{x&&e.key==="Control"&&(T=!1,clearTimeout(A),v&&await O())}),m.forEach(e=>{e&&e.addEventListener("click",s=>{s.preventDefault(),!P&&S&&J()})}),w.forEach(e=>{e&&e.addEventListener("click",async s=>{s.preventDefault(),!P&&await O()})});async function Z(){T=!1,A&&(clearTimeout(A),A=null),v&&await O(),g()?.classList.remove("is-speaking"),u()?.classList.remove("show"),d()?.style.setProperty("opacity","0")}function ee(){let e=document.querySelector(".wd-tab-link.w--current");if(e){let s=new URL(window.location);e.getAttribute("app-type")==="email"?s.searchParams.set("type","email"):s.searchParams.delete("type"),window.history.replaceState({},"",s)}}document.addEventListener("click",e=>{e.target.closest(".wd-tab-link")&&(x&&setTimeout(()=>{let a=r();if(a&&(a.focus(),a.dataset.isPlaceholder==="false")){let c=document.createRange(),y=window.getSelection();c.selectNodeContents(a),c.collapse(!1),y.removeAllRanges(),y.addRange(c)}},250),setTimeout(()=>{let a=r();a&&a!==t&&(t=a,I.disconnect(),I.observe(t,{childList:!0,subtree:!0,characterData:!0}))},320),setTimeout(()=>{ee()},100))}),window.addEventListener("blur",Z),document.addEventListener("visibilitychange",()=>{document.hidden&&Z()})}document.addEventListener("DOMContentLoaded",async function(){console.log("\u23F3 Waiting for A/B test variant...");let p="control";if(window.webDemoVariantReady)try{p=await Promise.race([window.webDemoVariantReady,new Promise(i=>setTimeout(()=>i("control"),2300))])}catch(o){console.warn("\u26A0\uFE0F Error waiting for variant, using control:",o),p="control"}else window.webDemoVariant&&(p=window.webDemoVariant);console.log(`\u2705 Using variant: ${p}`),document.body.style.visibility="visible",await z(p),console.log("Web demo initialized successfully")});window.addEventListener("pageshow",p=>{p.persisted&&(console.log("Page restored from bfcache - reloading..."),location.reload())});})();
|