UNPKG

nymia-ai-assistant

Version:

Package for integrating an AI assistant chat into any web application easily and customizable.

480 lines (421 loc) 39 kB
var O=class{type;colors={error:"#ff5252",warning:"#ffb142",info:"#4a90e2",success:"#4caf50"};constructor(e="info"){this.type=e}async send(e,i={}){let o=this.colors[this.type];console.log(`%c${this.type.toUpperCase()}: ${e}`,`color: ${o}; font-weight: bold`)}};var S=class{button;options;mounted=!1;sizes={small:{width:"40px",height:"40px",fontSize:"18px"},medium:{width:"56px",height:"56px",fontSize:"24px"},large:{width:"72px",height:"72px",fontSize:"30px"}};constructor(e={}){this.options={position:e.position||"bottom-right",backgroundColor:e.backgroundColor||"#4a90e2",color:e.color||"#ffffff",icon:e.icon||"\u{1F4AC}",size:e.size||"medium",onClick:e.onClick||(()=>{}),container:e.container||document.body,className:e.className||"",hidden:e.hidden||!1},this.createButton()}createButton(){if(this.button=document.createElement("button"),this.button.className=`floating-button ${this.options.size} ${this.options.position} ${this.options.className}`.trim(),this.options.icon)if(this.options.icon.startsWith("material:")){let e=this.options.icon.replace("material:","");this.button.innerHTML=`<span class="material-icons">${e}</span>`}else this.button.innerHTML=this.options.icon;this.button.setAttribute("aria-label","Assistant"),this.button.setAttribute("type","button"),this.applyStyles(),this.button.addEventListener("click",e=>{e.preventDefault(),this.options.onClick()})}applyStyles(){let{width:e,height:i,fontSize:o}=this.sizes[this.options.size];switch(Object.assign(this.button.style,{backgroundColor:this.options.backgroundColor,color:this.options.color,width:e,height:i,fontSize:o,position:"fixed",zIndex:"1000",borderRadius:"50%",border:"none",boxShadow:"0 4px 8px rgba(0, 0, 0, 0.2)",cursor:"pointer",display:this.options.hidden?"none":"flex",alignItems:"center",justifyContent:"center",transition:"all 0.3s ease",outline:"none"}),this.options.position){case"bottom-right":this.button.style.bottom="20px",this.button.style.right="20px";break;case"bottom-left":this.button.style.bottom="20px",this.button.style.left="20px";break;case"top-right":this.button.style.top="20px",this.button.style.right="20px";break;case"top-left":this.button.style.top="20px",this.button.style.left="20px";break}}mount(e=this.options.container){if(this.mounted)return;let i=typeof e=="string"?document.querySelector(e):e;i&&(i.appendChild(this.button),this.mounted=!0)}unmount(){this.mounted&&this.button.parentNode&&(this.button.parentNode.removeChild(this.button),this.mounted=!1)}update(e){if(this.options={...this.options,...e},this.button.className=`floating-button ${this.options.size} ${this.options.position} ${this.options.className}`.trim(),e.icon!==void 0)if(e.icon.startsWith("material:")){let i=e.icon.replace("material:","");this.button.innerHTML=`<span class="material-icons">${i}</span>`}else this.button.innerHTML=e.icon;this.applyStyles()}show(){this.button.style.display="flex",this.update({hidden:!1})}hide(){this.button.style.display="none",this.update({hidden:!0})}setOnClick(e){this.options.onClick=e}};var $=class{container;chatWindow;messageList;inputArea;isOpen=!1;options;onNewConversationCallback;newConvButton;mediaRecorder;audioChunks=[];isRecording=!1;recordingTimer;constructor(e={}){var i,o,t,n,s,l,c,r,d,h,C,E,T;this.options={title:e.title||"IA Assistant",placeholder:e.placeholder||"Write your message here...",position:e.position||"bottom-right",width:e.width||350,height:e.height||450,onSend:e.onSend||(async M=>`Received: ${M}`),initialMessage:e.initialMessage||"Hello, how can I help you?",theme:{primaryColor:((i=e.theme)==null?void 0:i.primaryColor)||"#4a90e2",textColor:((o=e.theme)==null?void 0:o.textColor)||"#333333",backgroundColor:((t=e.theme)==null?void 0:t.backgroundColor)||"#ffffff",userMessageBgColor:((n=e.theme)==null?void 0:n.userMessageBgColor)||((s=e.theme)==null?void 0:s.primaryColor)||"#4a90e2",userMessageTextColor:((l=e.theme)==null?void 0:l.userMessageTextColor)||"#ffffff",assistantMessageBgColor:((c=e.theme)==null?void 0:c.assistantMessageBgColor)||"#f1f1f1",assistantMessageTextColor:((r=e.theme)==null?void 0:r.assistantMessageTextColor)||((d=e.theme)==null?void 0:d.textColor)||"#333333",inputBorderColor:((h=e.theme)==null?void 0:h.inputBorderColor)||"#e0e0e0",inputBgColor:((C=e.theme)==null?void 0:C.inputBgColor)||"#ffffff",inputTextColor:((E=e.theme)==null?void 0:E.inputTextColor)||((T=e.theme)==null?void 0:T.textColor)||"#333333"},isOpen:e.isOpen||!1,showImagesOption:!!e.showImagesOption,...typeof e.audioAnswers<"u"?{audioAnswers:!!e.audioAnswers}:{}},this.createChatElements(),this.addEventListeners(),this.loadStyles(),this.addInitialMessage(),this.options.isOpen&&this.open()}createChatElements(){this.container=document.createElement("div"),this.container.className="ia-chat-container",this.container.style.display="none",this.chatWindow=document.createElement("div"),this.chatWindow.className=`ia-chat-window ${this.options.position}`;let e=document.createElement("div");e.className="ia-chat-header";let i=document.createElement("div");i.className="ia-chat-title",i.textContent=this.options.title;let o=document.createElement("button");o.className="ia-chat-new-conv",o.innerHTML="Nueva conversaci\xF3n",o.title="Nueva conversaci\xF3n",o.setAttribute("type","button"),o.style.background="none",o.style.border="none",o.style.color="white",o.style.fontSize="11px",o.style.cursor="pointer",o.style.padding="0",o.style.marginLeft="60px",o.style.marginRight="2px",o.style.lineHeight="1",o.style.outline="none",this.newConvButton=o,this.onNewConversationCallback&&(o.onclick=this.onNewConversationCallback);let t=document.createElement("button");t.className="ia-chat-close",t.innerHTML="&times;",t.setAttribute("aria-label","Close chat"),t.setAttribute("type","button"),t.style.background="none",t.style.border="none",t.style.color="white",t.style.fontSize="24px",t.style.cursor="pointer",t.style.padding="0",t.style.marginLeft="0",t.style.lineHeight="1",t.style.outline="none",e.appendChild(i),e.appendChild(o),e.appendChild(t),this.messageList=document.createElement("div"),this.messageList.className="ia-chat-messages",this.inputArea=document.createElement("div"),this.inputArea.className="ia-chat-input-area";let n=document.createElement("div");n.className="ia-chat-checkbox-container",n.style.display=this.options.showImagesOption===!1?"none":"flex";let s=document.createElement("input");s.type="checkbox",s.id="ia-show-images",s.className="ia-chat-checkbox",s.title="Al activar esta opci\xF3n tu respuesta puede demorar m\xE1s de lo esperado";let l=document.createElement("label");l.htmlFor="ia-show-images",l.className="ia-chat-checkbox-label",l.textContent="Mostrar im\xE1genes en la respuesta",l.title="Al activar esta opci\xF3n tu respuesta puede demorar m\xE1s de lo esperado",n.appendChild(s),n.appendChild(l);let c=document.createElement("div");c.className="ia-chat-input-wrapper";let r=document.createElement("textarea");if(r.className="ia-chat-input",r.placeholder=this.options.placeholder,r.rows=1,r.style.height="42px",r.style.minHeight="42px",r.style.maxHeight="120px",r.style.overflowY="hidden",r.style.resize="none",r.setAttribute("aria-label","Message"),console.log("Creating buttons with audioAnswers:",this.options.audioAnswers),this.options.audioAnswers){console.log("Creating both send and record buttons");let d=document.createElement("button");d.className="ia-chat-send",d.innerHTML="&#10148;",d.setAttribute("aria-label","Send message"),d.setAttribute("type","button");let h=document.createElement("button");h.className="ia-chat-record",h.innerHTML=` <svg viewBox="0 0 24 24" width="20" height="20"> <path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3z"/> <path d="M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z"/> </svg> `,h.setAttribute("aria-label","Record audio message"),h.setAttribute("type","button"),h.title="Mant\xE9n presionado para grabar audio",c.appendChild(r),this.inputArea.appendChild(c),this.inputArea.appendChild(d),this.inputArea.appendChild(h)}else{console.log("Creating only send button");let d=document.createElement("button");d.className="ia-chat-send",d.innerHTML="&#10148;",d.setAttribute("aria-label","Send message"),d.setAttribute("type","button"),c.appendChild(r),this.inputArea.appendChild(c),this.inputArea.appendChild(d)}this.chatWindow.appendChild(e),this.chatWindow.appendChild(this.messageList),this.chatWindow.appendChild(n),this.chatWindow.appendChild(this.inputArea),this.container.appendChild(this.chatWindow)}addEventListeners(){let e=this.chatWindow.querySelector(".ia-chat-close");if(e.addEventListener("click",()=>{this.toggle(),e.blur()}),this.options.audioAnswers){let o=this.chatWindow.querySelector(".ia-chat-send"),t=this.chatWindow.querySelector(".ia-chat-record");o.addEventListener("click",()=>{this.sendMessage(),o.blur()}),this.setupAudioRecording(t)}else{let o=this.chatWindow.querySelector(".ia-chat-send");o.addEventListener("click",()=>{this.sendMessage(),o.blur()})}let i=this.chatWindow.querySelector(".ia-chat-input");i.style.height="42px",i.addEventListener("keydown",o=>{o.key==="Enter"&&!o.shiftKey?(o.preventDefault(),this.sendMessage()):setTimeout(()=>this.autoResizeTextarea(i),0)}),i.addEventListener("input",()=>{this.autoResizeTextarea(i)}),i.addEventListener("focus",()=>{this.autoResizeTextarea(i)}),document.addEventListener("click",o=>{this.isOpen&&!this.container.contains(o.target)&&!o.target.closest(".floating-button")&&this.toggle()}),this.messageList.addEventListener("click",o=>{var n;let t=o.target;if(t.classList.contains("ia-audio-play-btn")||t.closest(".ia-audio-play-btn")){let s=t.classList.contains("ia-audio-play-btn")?t:t.closest(".ia-audio-play-btn"),l=(n=s==null?void 0:s.parentElement)==null?void 0:n.querySelector(".ia-audio-player");l&&(l.style.display="block",l.play())}})}setupAudioRecording(e){e.addEventListener("mousedown",i=>{i.preventDefault(),this.startRecordingTimer()}),e.addEventListener("mouseup",()=>{this.stopRecording()}),e.addEventListener("mouseleave",()=>{this.stopRecording()}),e.addEventListener("touchstart",i=>{i.preventDefault(),this.startRecordingTimer()}),e.addEventListener("touchend",i=>{i.preventDefault(),this.stopRecording()}),e.addEventListener("touchcancel",i=>{i.preventDefault(),this.stopRecording()})}startRecordingTimer(){this.recordingTimer=setTimeout(async()=>{await this.startAudioRecording()},200)}async startAudioRecording(){try{let e=await navigator.mediaDevices.getUserMedia({audio:!0});this.mediaRecorder=new MediaRecorder(e),this.audioChunks=[],this.isRecording=!0;let i=this.chatWindow.querySelector(".ia-chat-record");i.classList.add("recording"),i.innerHTML=` <svg viewBox="0 0 24 24" width="20" height="20"> <circle cx="12" cy="12" r="8" fill="red"/> </svg> `,this.mediaRecorder.ondataavailable=o=>{o.data.size>0&&this.audioChunks.push(o.data)},this.mediaRecorder.onstop=()=>{this.processRecordedAudio()},this.mediaRecorder.start()}catch(e){console.error("Error starting audio recording:",e),this.addMessage("Error: No se pudo acceder al micr\xF3fono","error")}}stopRecording(){if(this.recordingTimer&&(clearTimeout(this.recordingTimer),this.recordingTimer=void 0),this.isRecording&&this.mediaRecorder){this.mediaRecorder.stop(),this.mediaRecorder.stream.getTracks().forEach(i=>i.stop()),this.isRecording=!1;let e=this.chatWindow.querySelector(".ia-chat-record");e.classList.remove("recording"),e.innerHTML=` <svg viewBox="0 0 24 24" width="20" height="20"> <path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3z"/> <path d="M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z"/> </svg> `}}async processRecordedAudio(){if(this.audioChunks.length===0)return;let e=new Blob(this.audioChunks,{type:"audio/webm"});try{let i=await this.convertToWav(e),o=this.chatWindow.querySelector(".ia-chat-input"),t=o.value.trim();this.sendAudioMessage(t,i),this.resetTextarea(o)}catch(i){console.error("Error converting audio to WAV:",i),this.addMessage("Error al procesar el audio","error")}}async convertToWav(e){let i=new(window.AudioContext||window.webkitAudioContext),o=await e.arrayBuffer(),t=await i.decodeAudioData(o);return this.audioBufferToWav(t)}audioBufferToWav(e){let i=e.length,o=e.numberOfChannels,t=e.sampleRate,s=o*2,l=t*s,c=i*s,r=44+c,d=new ArrayBuffer(r),h=new DataView(d),C=(T,M)=>{for(let w=0;w<M.length;w++)h.setUint8(T+w,M.charCodeAt(w))};C(0,"RIFF"),h.setUint32(4,r-8,!0),C(8,"WAVE"),C(12,"fmt "),h.setUint32(16,16,!0),h.setUint16(20,1,!0),h.setUint16(22,o,!0),h.setUint32(24,t,!0),h.setUint32(28,l,!0),h.setUint16(32,s,!0),h.setUint16(34,16,!0),C(36,"data"),h.setUint32(40,c,!0);let E=44;for(let T=0;T<i;T++)for(let M=0;M<o;M++){let w=Math.max(-1,Math.min(1,e.getChannelData(M)[T])),H=w<0?w*32768:w*32767;h.setInt16(E,H,!0),E+=2}return new Blob([d],{type:"audio/wav"})}async sendAudioMessage(e,i){let o=e||"\u{1F3A4} Mensaje de audio";this.addMessage(o,"user"),this.showTypingIndicator();let t=new FormData;t.append("content",e),t.append("voice_content",i,"audio.wav"),t.append("context",""),t.append("contextHash",""),console.log("Sending FormData with audio:",{content:e,audioSize:i.size,audioType:i.type});try{let n=await this.options.onSend(t);this.hideTypingIndicator(),typeof n=="string"?this.addMessage(n,"assistant"):n&&typeof n=="object"&&"content"in n?this.addMessage(n.content,"assistant",n.isHtml||!1):this.addMessage("Invalid response format","error")}catch(n){this.hideTypingIndicator(),console.error("Audio message error details:",{error:n,errorMessage:n instanceof Error?n.message:String(n),errorStack:n instanceof Error?n.stack:void 0,formDataEntries:Array.from(t.entries()).map(([s,l])=>({key:s,value:l instanceof Blob?`Blob(${l.size} bytes, ${l.type})`:l}))}),this.addMessage(`Error al procesar mensaje de audio: ${n instanceof Error?n.message:String(n)}`,"error")}this.scrollToBottom()}autoResizeTextarea(e){let i=this.messageList.scrollTop;e.style.height="42px";let o=Math.min(e.scrollHeight,120);e.style.height=`${o}px`,o>42?(e.classList.add("multiline"),e.style.overflowY=o>=120?"auto":"hidden"):(e.classList.remove("multiline"),e.style.overflowY="hidden"),this.messageList.scrollTop=i}resetTextarea(e){e.value="",e.classList.remove("multiline"),e.style.height="42px",e.style.minHeight="42px",e.style.overflowY="hidden"}async sendMessage(){let e=this.chatWindow.querySelector(".ia-chat-input"),i=e.value.trim();if(i){this.addMessage(i,"user"),this.resetTextarea(e),this.showTypingIndicator();try{let o=new FormData;o.append("content",i),o.append("context","");let t=await this.options.onSend(o);this.hideTypingIndicator(),typeof t=="string"?this.addMessage(t,"assistant"):t&&typeof t=="object"&&"content"in t?this.addMessage(t.content,"assistant",t.isHtml||!1):this.addMessage("Invalid response format","error")}catch(o){this.hideTypingIndicator(),this.addMessage("Sorry, an error occurred while processing your message.","error"),console.error("Chat error:",o)}this.scrollToBottom()}}addMessage(e,i,o=!1){let t=document.createElement("div");t.className=`ia-chat-message ${i}`;let n=e;if(this.options.audioAnswers&&i==="assistant")try{let s=JSON.parse(e);s.content&&s.audio_url&&(n=s.content)}catch{}if(o&&i==="assistant")t.innerHTML=this.sanitizeHtml(n);else{let s=this.sanitizeText(n),l=this.options.audioAnswers&&i==="assistant"?this.formatTextWithoutLinks(s):this.formatText(s);t.innerHTML=l}if(this.options.audioAnswers&&i==="assistant"){let s=e.match(/"audio_url"\s*:\s*"([^"]+)"/s);if(s){let l=s[1],c=document.createElement("div");c.className="ia-audio-container",c.style.marginTop="8px";let r=document.createElement("button");r.className="ia-audio-play-btn",r.innerHTML=` <svg class="ia-audio-icon" viewBox="0 0 24 24"> <path d="M8 5v14l11-7z"/> </svg> Audio `;let d=document.createElement("audio");d.className="ia-audio-player",d.src=l,d.controls=!0,d.style.display="none",c.appendChild(r),c.appendChild(d),t.appendChild(c)}}this.messageList.appendChild(t),this.scrollToBottom()}sanitizeText(e){let i=document.createElement("div");return i.textContent=e,i.innerHTML}sanitizeHtml(e){let i=document.createElement("div");i.innerHTML=e;let o=["img","br","p","strong","em","b","i"],t={img:["src","alt","style","width","height"],p:["style"],strong:[],em:[],b:[],i:[],br:[]};return this.cleanElement(i,o,t),i.innerHTML}cleanElement(e,i,o){Array.from(e.children).forEach(n=>{let s=n.tagName.toLowerCase();if(!i.includes(s))e.removeChild(n);else{let l=o[s]||[];Array.from(n.attributes).forEach(r=>{l.includes(r.name)||n.removeAttribute(r.name)}),this.cleanElement(n,i,o)}})}formatText(e){let i=/(https?:\/\/[^\s]+)/g,o=e.replace(i,'<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>');return o=o.replace(/\*\*(.*?)\*\*/g,'<span class="ia-title">$1</span>'),o=o.replace(/(^|\n)-\s+(.*?)(?=\n|$)/g,(t,n,s)=>`${n}<li>${s}</li>`),o=o.replace(/(<li>.*?<\/li>\s*)+/gs,t=>`<ul>${t.replace(/\s*$/,"")}</ul>`),o}formatTextWithoutLinks(e){let i=e;return i=i.replace(/\*\*(.*?)\*\*/g,'<span class="ia-title">$1</span>'),i=i.replace(/(^|\n)-\s+(.*?)(?=\n|$)/g,(o,t,n)=>`${t}<li>${n}</li>`),i=i.replace(/(<li>.*?<\/li>\s*)+/gs,o=>`<ul>${o.replace(/\s*$/,"")}</ul>`),i}showTypingIndicator(){let e=document.createElement("div");e.className="ia-chat-message assistant typing",e.innerHTML='<span class="ia-typing-dot"></span><span class="ia-typing-dot"></span><span class="ia-typing-dot"></span>',e.id="ia-typing-indicator",this.messageList.appendChild(e),this.scrollToBottom()}hideTypingIndicator(){let e=document.getElementById("ia-typing-indicator");e&&e.remove()}scrollToBottom(){this.messageList.scrollTop=this.messageList.scrollHeight}addInitialMessage(){this.options.initialMessage&&this.addMessage(this.options.initialMessage,"assistant")}toggle(){this.isOpen=!this.isOpen,this.container.style.display=this.isOpen?"block":"none",this.isOpen&&(setTimeout(()=>{let e=this.chatWindow.querySelector(".ia-chat-input");e.style.height="42px",e.focus()},100),this.scrollToBottom())}open(){this.isOpen||this.toggle()}close(){this.isOpen&&this.toggle()}mount(e=document.body){let i=typeof e=="string"?document.querySelector(e):e;i&&i.appendChild(this.container)}unmount(){this.container.parentNode&&this.container.parentNode.removeChild(this.container)}getShowImages(){let e=this.chatWindow.querySelector("#ia-show-images");return e?e.checked:!1}getAudioAnswers(){return!!this.options.audioAnswers}setOnNewConversation(e){this.onNewConversationCallback=e,this.newConvButton&&(this.newConvButton.onclick=e)}clearMessages(){this.messageList&&(this.messageList.innerHTML="");let e=this.chatWindow.querySelector(".ia-chat-input");e&&this.resetTextarea(e)}loadStyles(){if(document.getElementById("ia-chat-styles"))return;let{primaryColor:e,textColor:i,backgroundColor:o,userMessageBgColor:t,userMessageTextColor:n,assistantMessageBgColor:s,assistantMessageTextColor:l,inputBorderColor:c,inputBgColor:r,inputTextColor:d}=this.options.theme,h=document.createElement("style");h.id="ia-chat-styles",h.textContent=` .ia-chat-container { position: fixed; z-index: 1001; pointer-events: none; width: 100%; height: 100%; top: 0; left: 0; } .ia-chat-window { position: absolute; width: ${this.options.width}px; height: ${this.options.height}px; background-color: ${o}; border-radius: 10px; box-shadow: 0 5px 20px rgba(0, 0, 0, 0.2); display: flex; flex-direction: column; overflow: hidden; pointer-events: auto; transition: all 0.3s ease; } .ia-chat-window.bottom-right { bottom: 90px; right: 20px; } .ia-chat-window.bottom-left { bottom: 90px; left: 20px; } .ia-chat-window.top-right { top: 20px; right: 20px; } .ia-chat-window.top-left { top: 20px; left: 20px; } .ia-chat-header { background-color: ${e}; color: white; padding: 12px 16px; display: flex; justify-content: space-between; align-items: center; } .ia-chat-title { font-weight: bold; color: white; font-size: 1.08em; display: inline-block; margin-bottom: 2px; } .ia-chat-close { background: none; border: none; color: white; font-size: 24px; cursor: pointer; padding: 0; margin-left: 10px; line-height: 1; outline: none; /* Prevent the outline from being displayed on click */ } /* Prevent focus visual effects on close button */ .ia-chat-close:focus { outline: none; box-shadow: none; } .ia-chat-messages { flex: 1; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 12px; } .ia-chat-message { padding: 10px 14px; border-radius: 16px; max-width: 80%; word-break: break-word; line-height: 1.4; } .ia-chat-message.user { background-color: ${t}; color: ${n}; align-self: flex-end; border-bottom-right-radius: 4px; } .ia-chat-message.assistant { background-color: ${s}; color: ${l}; align-self: flex-start; border-bottom-left-radius: 4px; } .ia-chat-message.error { background-color: #ffe6e6; color: #d32f2f; align-self: flex-start; border-bottom-left-radius: 4px; } .ia-chat-input-area { padding: 12px; border-top: 1px solid #e0e0e0; display: flex; align-items: flex-end; } .ia-chat-input-wrapper { flex: 1; position: relative; display: flex; } .ia-chat-input { flex: 1; border: 1px solid ${c}; border-radius: 20px; padding: 10px 14px; font-family: inherit; resize: none; box-sizing: border-box; outline: none; transition: height 0.1s ease-out, border-color 0.2s; line-height: 1.4; min-height: 42px !important; max-height: 120px; overflow-y: hidden !important; /* Force hide vertical scroll by default */ background-color: ${r}; color: ${d}; } .ia-chat-input.multiline { overflow-y: auto !important; /* Only allow scroll when there are multiple lines */ } .ia-chat-input:focus { border-color: ${e}; } .ia-chat-send { background-color: ${e}; color: white; border: none; border-radius: 50%; width: 40px; height: 40px; margin-left: 8px; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 18px; transition: background-color 0.2s; outline: none; /* Prevent the outline from being displayed on click */ } .ia-chat-send:hover { background-color: ${this.darkenColor(e||"#4a90e2",10)}; } /* Prevent focus visual effects on send button */ .ia-chat-send:focus { outline: none; box-shadow: none; } /* Record button styles */ .ia-chat-record { background-color: ${e}; color: white; border: none; border-radius: 50%; width: 40px; height: 40px; margin-left: 8px; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 18px; transition: all 0.2s; outline: none; user-select: none; } .ia-chat-record:hover { background-color: ${this.darkenColor(e||"#4a90e2",10)}; transform: scale(1.05); } .ia-chat-record.recording { background-color: #ff4444; animation: pulse 1s infinite; } .ia-chat-record:focus { outline: none; box-shadow: none; } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.1); } 100% { transform: scale(1); } } /* Audio container styles */ .ia-audio-container { margin-top: 8px; } .ia-audio-play-btn { background-color: ${e}; color: white; border: none; border-radius: 20px; padding: 8px 12px; cursor: pointer; display: flex; align-items: center; gap: 6px; font-size: 14px; transition: background-color 0.2s; } .ia-audio-play-btn:hover { background-color: ${this.darkenColor(e||"#4a90e2",10)}; } .ia-audio-icon { width: 16px; height: 16px; fill: currentColor; } .ia-audio-player { margin-top: 8px; width: 100%; } /* Typing indicator */ .typing { display: flex; align-items: center; padding: 8px 14px; } .ia-typing-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background-color: #888; margin-right: 4px; animation: typing-dot 1.4s infinite ease-in-out both; } .ia-typing-dot:nth-child(1) { animation-delay: 0s; } .ia-typing-dot:nth-child(2) { animation-delay: 0.2s; } .ia-typing-dot:nth-child(3) { animation-delay: 0.4s; margin-right: 0; } @keyframes typing-dot { 0%, 80%, 100% { transform: scale(0.7); opacity: 0.6; } 40% { transform: scale(1); opacity: 1; } } /* Responsive */ @media (max-width: 480px) { .ia-chat-window { width: calc(100% - 40px); height: 70vh; } } ul { margin: 8px 0 8px 18px; padding-left: 18px; } ul li { margin-bottom: 2px; list-style: disc inside; } .ia-chat-messages::-webkit-scrollbar { width: 8px; background: transparent; } .ia-chat-messages::-webkit-scrollbar-thumb { background: ${c}; border-radius: 8px; } .ia-chat-messages::-webkit-scrollbar-thumb:hover { background: ${e}; } .ia-chat-messages { scrollbar-width: thin; scrollbar-color: ${c} transparent; } .ia-chat-input::-webkit-scrollbar { width: 8px; background: transparent; border-radius: 20px; } .ia-chat-input::-webkit-scrollbar-thumb { background: ${c}; border-radius: 20px; min-height: 24px; border: 2px solid ${r}; } .ia-chat-input::-webkit-scrollbar-thumb:hover { background: ${e}; } .ia-chat-input { scrollbar-width: thin; scrollbar-color: ${c} ${r}; } .ia-chat-checkbox-container { padding: 12px 12px; border-top: 1px solid #e0e0e0; background-color: #f8f9fa; display: flex; align-items: center; gap: 8px; } .ia-chat-checkbox { width: 16px; height: 16px; cursor: pointer; accent-color: ${e}; } .ia-chat-checkbox-label { font-size: 12px; color: ${e}; cursor: pointer; user-select: none; margin: 0; } .ia-chat-checkbox-label:hover { color: ${e}; } .ia-chat-message img { max-width: 100%; height: auto; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); margin: 10px 0; display: block; } .ia-chat-message.assistant img { max-width: 300px; } .ia-chat-message p { margin: 5px 0; line-height: 1.4; } .ia-audio-player { display: none; width: 100%; margin-top: 8px; } .ia-audio-container { display: flex; flex-direction: column; gap: 8px; max-width: 250px; } .ia-audio-play-btn { background-color: ${e}; color: white; border: none; border-radius: 20px; padding: 10px 16px; cursor: pointer; font-size: 14px; font-weight: 500; transition: all 0.2s ease; outline: none; display: inline-flex; align-items: center; gap: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); min-width: 120px; justify-content: center; } .ia-audio-play-btn:hover { background-color: ${this.darkenColor(e||"#4a90e2",10)}; transform: translateY(-1px); box-shadow: 0 4px 8px rgba(0,0,0,0.15); } .ia-audio-play-btn:active { transform: translateY(0); box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .ia-audio-icon { width: 16px; height: 16px; display: inline-block; fill: white; flex-shrink: 0; } .ia-audio-player { width: 100%; margin-top: 8px; border-radius: 8px; outline: none; } .ia-audio-player::-webkit-media-controls-panel { background-color: ${s}; border-radius: 8px; } .ia-audio-player::-webkit-media-controls-play-button, .ia-audio-player::-webkit-media-controls-pause-button { background-color: ${e}; border-radius: 50%; } `,document.head.appendChild(h)}darkenColor(e,i){if(!/^#[0-9A-F]{3,6}$/i.test(e)){let s=document.createElement("div");s.style.color=e,document.body.appendChild(s);let l=getComputedStyle(s).color;document.body.removeChild(s),l.startsWith("rgb")?e=this.rgbToHex(l):e="#4a90e2"}e=e.replace("#","");let o=parseInt(e.substring(0,2),16),t=parseInt(e.substring(2,4),16),n=parseInt(e.substring(4,6),16);return o=Math.floor(o*(100-i)/100),t=Math.floor(t*(100-i)/100),n=Math.floor(n*(100-i)/100),"#"+((1<<24)+(o<<16)+(t<<8)+n).toString(16).slice(1)}rgbToHex(e){let i=e.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);if(!i)return"#000000";let o=parseInt(i[1],10),t=parseInt(i[2],10),n=parseInt(i[3],10);return"#"+((1<<24)+(o<<16)+(t<<8)+n).toString(16).slice(1)}};function X(a){var w,H,N,z,I,R,P,W,_,F,j,q,D,U,K,V,J,Y,G,Q;if(!a.apiKey)throw new Error("apiKey is required to initialize the assistant");let e={position:a.position||"bottom-right",backgroundColor:((w=a.buttonOptions)==null?void 0:w.backgroundColor)||"#4a90e2",color:((H=a.buttonOptions)==null?void 0:H.color)||"#ffffff",icon:((N=a.buttonOptions)==null?void 0:N.icon)||"\u{1F4AC}",size:((z=a.buttonOptions)==null?void 0:z.size)||"medium",container:((I=a.buttonOptions)==null?void 0:I.container)||document.body},i={title:a.title||"Nymia IA Assistant",placeholder:a.placeholder||"Write your message here...",position:a.position||"bottom-right",initialMessage:a.initialMessage,theme:{primaryColor:((R=a.theme)==null?void 0:R.primaryColor)||((P=a.buttonOptions)==null?void 0:P.backgroundColor)||"#4a90e2",textColor:((W=a.theme)==null?void 0:W.textColor)||"#333333",backgroundColor:((_=a.theme)==null?void 0:_.backgroundColor)||"#ffffff",userMessageBgColor:((F=a.theme)==null?void 0:F.userMessageBgColor)||((j=a.theme)==null?void 0:j.primaryColor)||((q=a.buttonOptions)==null?void 0:q.backgroundColor)||"#4a90e2",userMessageTextColor:((D=a.theme)==null?void 0:D.userMessageTextColor)||"#ffffff",assistantMessageBgColor:((U=a.theme)==null?void 0:U.assistantMessageBgColor)||"#f1f1f1",assistantMessageTextColor:((K=a.theme)==null?void 0:K.assistantMessageTextColor)||((V=a.theme)==null?void 0:V.textColor)||"#333333",inputBorderColor:((J=a.theme)==null?void 0:J.inputBorderColor)||"#e0e0e0",inputBgColor:((Y=a.theme)==null?void 0:Y.inputBgColor)||"#ffffff",inputTextColor:((G=a.theme)==null?void 0:G.inputTextColor)||((Q=a.theme)==null?void 0:Q.textColor)||"#333333"},isOpen:a.autoOpen||!1,showImagesOption:a.searchImages??!1,audioAnswers:a.audioAnswers??!1},o=new S(e),t=null,n=null,s=null,l=null,c=!1,r="";o.mount();async function d(){try{let g=await fetch(`${a.apiBaseUrl}/conversation/user`,{method:"GET",mode:"cors",headers:{"Content-Type":"application/json",Authorization:`Bearer ${a.apiKey}`}});if(!g.ok)throw new Error(`Error fetching conversations: ${g.status}`);return(await g.json()).data||[]}catch(g){return console.error("Error fetching conversations:",g),[]}}async function h(g){try{let m=await fetch(`${a.apiBaseUrl}/conversation/${g}`,{method:"GET",mode:"cors",headers:{"Content-Type":"application/json",Authorization:`Bearer ${a.apiKey}`}});if(!m.ok)throw new Error(`Error fetching messages: ${m.status}`);return(await m.json()).data.messages||[]}catch(m){return console.error("Error fetching messages:",m),[]}}function C(g){return g.replace(/\\"/g,'"').replace(/<img ([^>]*style="[^"]*max-width:[^"]*)"([^>]*)>/g,'<img $1; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); margin: 10px 0;"$2>')}async function E(g){if(!n)return"No active conversation.";let m=g.get("context")||"";if(m===""){let b=document.querySelector('main, article, .content, #content, [role="main"]');if(b)m=b.innerText;else{let B=document.body.cloneNode(!0);B.querySelectorAll("nav, header, footer, .sidebar, .navigation, .menu, .ads, script, style, .cookie-banner").forEach(L=>L.remove()),m=B.innerText}}let v=m.replace(/\s+/g," ").trim().substring(0,8e3),u=v===r?"":v;u!==""&&(r=v),g.set("context",u),g.set("contextHash",u?btoa(u.substring(0,100)):"");let p=t&&t.getAudioAnswers?t.getAudioAnswers():!1,y=p?"activate":"deactivate",k=(t&&t.getShowImages?t.getShowImages():!1)?"activate":"deactivate",A=`${a.apiBaseUrl}/conversation/${n}/message?has_image_processor=${k}&has_text_to_voice=${y}`;try{let b=await fetch(A,{method:"POST",mode:"cors",headers:{"x-api-key":`${a.apiKey}`},body:g});if(!b.ok)throw new Error(`Error sending message: ${b.status}`);let x=(await b.json()).data.reverse().find(L=>L.sender==="assistant");return console.log(x),x?p&&x.audio_url?JSON.stringify({content:x.content,audio_url:x.audio_url}):C(x.content):"No response from the assistant."}catch(b){return console.error("Error sending FormData message:",b),"Sorry, there was an error processing your audio message. Please try again."}}async function T(g,m=""){if(!n)return"No active conversation.";if(m===""){let b=document.querySelector('main, article, .content, #content, [role="main"]');if(b)m=b.innerText;else{let B=document.body.cloneNode(!0);B.querySelectorAll("nav, header, footer, .sidebar, .navigation, .menu, .ads, script, style, .cookie-banner").forEach(L=>L.remove()),m=B.innerText}}let v=m.replace(/\s+/g," ").trim().substring(0,8e3),u=v===r?"":v;u!==""&&(r=v);let y=(t&&t.getShowImages?t.getShowImages():!1)?"activate":"deactivate",f=t&&t.getAudioAnswers?t.getAudioAnswers():!1,k=f?"activate":"deactivate",A=`${a.apiBaseUrl}/conversation/${n}/message?has_image_processor=${y}&has_text_to_voice=${k}`;try{let b=await fetch(A,{method:"POST",mode:"cors",headers:{"Content-Type":"application/json","x-api-key":`${a.apiKey}`},body:JSON.stringify({content:g,context:u,contextHash:u?btoa(u.substring(0,100)):null})});if(!b.ok)throw new Error(`Error sending message: ${b.status}`);let x=(await b.json()).data.reverse().find(L=>L.sender==="assistant");return console.log(x),x?f&&x.audio_url?JSON.stringify({content:x.content,audio_url:x.audio_url}):C(x.content):"No response from the assistant."}catch(b){return console.error("Error sending message:",b),"Sorry, there was an error processing your message. Please try again."}}async function M(){try{let g=localStorage.getItem("ai-client-id"),m=await d(),v=!1;if(m.length>0){let u=m[0];if(n=u.id,l=u.client_id,g&&g===u.client_id)v=!0,localStorage.setItem("ai-client-id",u.client_id);else{let p=await fetch(`${a.apiBaseUrl}/conversation/`,{method:"POST",mode:"cors",headers:{"Content-Type":"application/json",Authorization:`Bearer ${a.apiKey}`},body:JSON.stringify({title:i.title})});if(!p.ok)throw new Error(`Error creating conversation: ${p.status}`);let y=await p.json();n=y.data.id,s=y.data.client_id,s&&localStorage.setItem("ai-client-id",s),v=!1}}else{let u=await fetch(`${a.apiBaseUrl}/conversation/`,{method:"POST",mode:"cors",headers:{"Content-Type":"application/json",Authorization:`Bearer ${a.apiKey}`},body:JSON.stringify({title:i.title})});if(!u.ok)throw new Error(`Error creating conversation: ${u.status}`);let p=await u.json();n=p.data.id,s=p.data.client_id,s&&localStorage.setItem("ai-client-id",s),v=!1}t=new $({...i,onSend:async u=>{let p=document.querySelector(".ia-chat-input");if(u instanceof FormData){let f=await E(u);p.value="";let k=f.includes("<img")||f.includes("<p>")||f.includes("<br>"),A=f.includes("audio_url");return{content:f,isHtml:k||A}}let y=u.trim();if(y){let f=await T(y);p.value="";let k=f.includes("<img")||f.includes("<p>")||f.includes("<br>"),A=f.includes("audio_url");return{content:f,isHtml:k||A}}return{content:"Please write a valid message.",isHtml:!1}}}),t.mount(a.container||document.body),t.setOnNewConversation(async()=>{let u=await fetch(`${a.apiBaseUrl}/conversation/`,{method:"POST",mode:"cors",headers:{"Content-Type":"application/json",Authorization:`Bearer ${a.apiKey}`},body:JSON.stringify({title:i.title})});if(u.ok){let p=await u.json();n=p.data.id,s=p.data.client_id,s&&localStorage.setItem("ai-client-id",s),r="",t&&typeof t.clearMessages=="function"&&t.clearMessages()}}),n&&t&&v&&localStorage.getItem("ai-client-id")===l&&(await h(n)).forEach(p=>{if(t&&typeof t.addMessage=="function"){let y=p.content;i.audioAnswers&&p.sender==="assistant"&&p.audio_url&&(y=JSON.stringify({content:p.content,audio_url:p.audio_url}));let f=y.includes("<img")||y.includes("<p>")||y.includes("<br>"),k=y.includes("audio_url");t.addMessage(y,p.sender==="user"?"user":"assistant",f||k)}}),c&&(t.open(),c=!1)}catch(g){console.error("Error initializing chat:",g),t=new $({...i,onSend:async()=>({content:"The assistant is not available at this time. Please try again later.",isHtml:!1}),initialMessage:"Sorry, I couldn't connect to the server. Please check your connection and try again."}),t.mount(a.container||document.body),c&&(t.open(),c=!1)}}return M(),o.setOnClick(()=>{t?t.toggle():c=!0}),{open:()=>t&&t.open(),close:()=>t&&t.close(),toggle:()=>t&&t.toggle(),unmount:()=>{t&&t.unmount(),o.unmount()},isOpen:()=>!!(t&&t.isOpen),hideButton:()=>o.hide(),showButton:()=>o.show()}}var Me=X;export{$ as Chat,S as FloatingButton,O as Notification,X as createAssistant,Me as default};