UNPKG

mind-link-ai-widget

Version:

A react widget for React Web and React-Native Mobile integrations.

12 lines (10 loc) 11.7 kB
(function(o,I){typeof exports=="object"&&typeof module<"u"?module.exports=I(require("react"),require("dompurify"),require("marked"),require("react-icons/io5")):typeof define=="function"&&define.amd?define(["react","dompurify","marked","react-icons/io5"],I):(o=typeof globalThis<"u"?globalThis:o||self,o.AntwellWidget=I(o.React,o.DOMPurify,o.marked,o.io5))})(this,(function(o,I,ue,w){"use strict";var F={exports:{}},R={};/** * @license React * react-jsx-runtime.production.min.js * * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */var V;function pe(){if(V)return R;V=1;var n=o,s=Symbol.for("react.element"),l=Symbol.for("react.fragment"),i=Object.prototype.hasOwnProperty,p=n.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,u={key:!0,ref:!0,__self:!0,__source:!0};function g(k,h,y){var f,b={},j=null,S=null;y!==void 0&&(j=""+y),h.key!==void 0&&(j=""+h.key),h.ref!==void 0&&(S=h.ref);for(f in h)i.call(h,f)&&!u.hasOwnProperty(f)&&(b[f]=h[f]);if(k&&k.defaultProps)for(f in h=k.defaultProps,h)b[f]===void 0&&(b[f]=h[f]);return{$$typeof:s,type:k,key:j,ref:S,props:b,_owner:p.current}}return R.Fragment=l,R.jsx=g,R.jsxs=g,R}var Y;function he(){return Y||(Y=1,F.exports=pe()),F.exports}var t=he();const d=[];for(let n=0;n<256;++n)d.push((n+256).toString(16).slice(1));function me(n,s=0){return(d[n[s+0]]+d[n[s+1]]+d[n[s+2]]+d[n[s+3]]+"-"+d[n[s+4]]+d[n[s+5]]+"-"+d[n[s+6]]+d[n[s+7]]+"-"+d[n[s+8]]+d[n[s+9]]+"-"+d[n[s+10]]+d[n[s+11]]+d[n[s+12]]+d[n[s+13]]+d[n[s+14]]+d[n[s+15]]).toLowerCase()}let L;const fe=new Uint8Array(16);function be(){if(!L){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");L=crypto.getRandomValues.bind(crypto)}return L(fe)}const K={randomUUID:typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto)};function xe(n,s,l){if(K.randomUUID&&!n)return K.randomUUID();n=n||{};const i=n.random??n.rng?.()??be();if(i.length<16)throw new Error("Random bytes length must be >= 16");return i[6]=i[6]&15|64,i[8]=i[8]&63|128,me(i)}const ge=ye();function ye(){return xe()}function _(){return Math.random().toString(36).slice(2)}const H="https://uat.api-az.carelonhealth.com/mindlink/api/v1",we=`${H}/auth/token`,ke=`${H}/antwell/documents/chat`,je=`${H}/antwell/documents/chat-feedback`,z="ai-smart-search",X="7a3b9c2d-5e6f-4a1b-8c2d-3e9f1a7b6c4d",Q="HS256",Se="Basic bWluZGxpbmstYW50d2VsbDo3ZTNiMmMxZC01ZjZhLTRiMWMtOGQyZS0zZjlhMWI3YzZkNGU=";function ve(n){try{const[,s]=n.split("."),l=JSON.parse(atob(s));return typeof l.exp=="number"?l.exp:null}catch{return null}}let D=null;async function q(){const n=Math.floor(Date.now()/1e3);if(D&&n<D.exp-20)return D.accessToken;const s=await fetch(we,{method:"GET",headers:{"Content-Type":"application/json","sender-app":z,alg:Q,Authorization:Se}});if(!s.ok){const u=await s.text().catch(()=>"");throw new Error(`Auth failed (${s.status}) ${u}`)}const l=await s.json(),i=l.access_token,p=ve(i)??Math.floor(Date.now()/1e3)+(l.expires_in??3600);return D={accessToken:i,exp:p},i}async function Ne(n){const s=await q(),l=await fetch(je,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`,apikey:X,"sender-app":z,"x-csid":ge},body:JSON.stringify(n)});if(!l.ok)throw new Error(`Feedback submission failed: ${l.statusText}`)}async function $(n,s,l,i){const p=await q(),u=await fetch(ke,{method:"POST",signal:i,headers:{"sender-app":z,apikey:X,"x-csid":l,alg:Q,Authorization:`Bearer ${p}`,"Content-Type":"application/json"},body:JSON.stringify({config:n,query:s})});if(!u.ok){const g=await u.text().catch(()=>"");throw new Error(`Chat failed (${u.status}) ${g}`)}return await u.json()}const Te=({isOpen:n,onClose:s,onSubmit:l,rating:i})=>{const[p,u]=o.useState(""),[g,k]=o.useState(!1);if(!n)return null;const h=async y=>{if(y.preventDefault(),!g){k(!0);try{await l(p),u(""),s()}catch(f){console.error("Failed to submit feedback:",f)}finally{k(!1)}}};return t.jsx("div",{className:"feedback-dialog-overlay",children:t.jsxs("div",{className:"feedback-dialog",children:[t.jsx("h3",{children:"Provide Additional Feedback"}),t.jsx("p",{children:"Your feedback helps us improve our responses."}),t.jsxs("form",{onSubmit:h,children:[t.jsxs("div",{className:"form-group",children:[t.jsx("label",{htmlFor:"comments",children:i==="like"?"What did you like about this response?":"How can we improve this response?"}),t.jsx("textarea",{id:"comments",value:p,onChange:y=>u(y.target.value),rows:4,placeholder:"Enter your feedback here...",required:!0})]}),t.jsxs("div",{className:"dialog-actions",children:[t.jsx("button",{type:"button",className:"btn-secondary",onClick:s,disabled:g,children:"Cancel"}),t.jsx("button",{type:"submit",className:"btn-primary",disabled:g,children:g?"Submitting...":"Submit Feedback"})]})]})]})})};function Ie(n){const s=ue.marked.parse(n,{breaks:!0});return I.sanitize(s,{ADD_ATTR:["target","rel"]})}function Re({brand:n,stateCode:s,category:l,language:i,userQuery:p,uuid:u}){const[,g]=o.useState(!1),[k,h]=o.useState(new Set),[y,f]=o.useState(!1),[b,j]=o.useState([]),[S,O]=o.useState(""),[v,U]=o.useState(!1),[ee,J]=o.useState(null),[N,Z]=o.useState({}),[C,A]=o.useState(null),[te,B]=o.useState("");o.useEffect(()=>{if(p&&b.length===0){const e={id:_(),role:"user",content:p};j([e])}},[p]);const[T,G]=o.useState({isOpen:!1,messageId:null,rating:null}),ne=10,se=o.useRef(null),E=o.useRef(null),P=o.useRef(null),oe=o.useRef(!1),Ce=e=>{const a=N[e]==="up"?null:"up";Z(c=>({...c,[e]:a})),a==="up"?G({isOpen:!0,messageId:e,rating:"like"}):W(e,"like","")},Ee=e=>{const a=N[e]==="down"?null:"down";Z(c=>({...c,[e]:a})),a==="down"?G({isOpen:!0,messageId:e,rating:"dislike"}):W(e,"dislike","")},W=async(e,r,a)=>{try{const c=b.findIndex(x=>x.id===e);if(c>0){const x=b[c],m=b[c-1];x&&m&&m.role==="user"&&await Ne({message_id:e,rating:r,comments:a||`User gave a thumbs ${r}`,conversation:{query:m.content,response:x.content,context:{brand:n,state:s,category:l,language:i}}})}}catch(c){console.error("Failed to send feedback:",c),Z(x=>({...x,[e]:null}))}},De=async e=>{T.messageId&&T.rating&&await W(T.messageId,T.rating,e)},ae=()=>{se.current?.scrollIntoView({behavior:"smooth"})};o.useEffect(()=>{ae()},[b,v,te]);const re=()=>({brand:n.toLowerCase(),state:s.toUpperCase(),category:l,language:i?.toLowerCase()});o.useEffect(()=>{const e=new ResizeObserver(()=>{ae()});return E.current&&e.observe(E.current),()=>{E.current&&e.unobserve(E.current)}},[]),o.useEffect(()=>{if(!oe.current&&p){oe.current=!0;const e=re();U(!0),$(e,p,u).then(r=>{const a=_(),c=r?.message?.content??"Sorry, I couldn't parse the response.",{cleanContent:x,prompts:m}=ie(c);j(M=>[...M,{id:a,role:"assistant",content:x,followUpPrompts:m.length>0?m:void 0}]),A(a)}).catch(r=>{J(r?.message||"Something went wrong."),j(a=>[...a,{id:_(),role:"assistant",content:"I’m having trouble reaching the service right now. Please try again."}]),A(null)}).finally(()=>{U(!1)})}},[n,s,l,i,p,u]);const ie=e=>{const r=/[-*] \[(.*?)\]\(#followUps\)/g,a=[];let c=e;return c=c.replace(r,(x,m)=>(a.push(m),"")),c=c.replace(/\n{3,}/g,` `).trim(),{cleanContent:c,prompts:a}},ce=o.useCallback(async e=>{J(null),U(!0);const r={id:_(),role:"user",content:e};j(a=>[...a,r]),P.current?.abort(),P.current=new AbortController;try{const a=re(),x=(await $(a,e,u,P.current.signal))?.message?.content??"Sorry, I couldn't parse the response.",{cleanContent:m,prompts:M}=ie(x),de={id:_(),role:"assistant",content:m,followUpPrompts:M.length>0?M:void 0};j(Ue=>[...Ue,de]),A(de.id)}catch(a){a.name!=="AbortError"&&(J("Failed to get response. Please try again."),console.error("API Error:",a))}finally{U(!1),P.current=null}},[n,s,l,i,u]),Oe=o.useCallback(e=>{g(!0),O(e),setTimeout(()=>{const r=document.querySelector(".chat-input-wrap");r&&r.requestSubmit()},100)},[O]);o.useEffect(()=>{if(!C)return;const e=b.find(m=>m.id===C);if(!e)return;let r=0;const a=e.content;B("");function c(){e&&(r<a.length?(B(a.substring(0,r+1)),r++,setTimeout(c,ne)):(A(null),B(""),h(m=>new Set(m).add(e.id))))}const x=setTimeout(c,ne);return()=>clearTimeout(x)},[C,b]);const le=o.useCallback(e=>{e?.preventDefault(),!(v||!S.trim())&&(g(!0),ce(S),O(""))},[S,v,ce]);return t.jsxs("div",{className:"chat-shell",children:[t.jsx("header",{className:"chat-header",children:t.jsxs("div",{className:"chat-header-title",children:[t.jsx(w.IoSparklesSharp,{}),t.jsx("span",{className:"chat-header-title-text",children:"AI Search Assistant"}),t.jsxs("div",{className:"help-button-container",children:[t.jsx("button",{className:"help-icon-button",onClick:()=>f(!y),"aria-label":"Show help information","aria-expanded":y,children:t.jsx(w.IoHelpCircleOutline,{})}),y&&t.jsx("div",{className:"help-tooltip",children:t.jsx("p",{children:"The AI Search Assistant is powered by artificial intelligence. Please double-check important information."})})]})]})}),t.jsxs("main",{className:"chat-main",children:[t.jsx(Te,{isOpen:T.isOpen,onClose:()=>G({isOpen:!1,messageId:null,rating:null}),onSubmit:De,rating:T.rating||"like"}),t.jsxs("div",{className:"messages-container",ref:E,children:[b.map(e=>t.jsx("section",{className:`message ${e.role}`,children:e.role==="assistant"?t.jsx(t.Fragment,{children:t.jsxs(t.Fragment,{children:[t.jsxs("div",{className:"message-assistant",children:[t.jsx("div",{className:"message-content",dangerouslySetInnerHTML:{__html:Ie(C===e.id?te:e.content).replaceAll("<a ",'<a target="_blank" rel="noopener noreferrer" ')}}),e.followUpPrompts&&e.followUpPrompts.length>0&&!C&&t.jsx("div",{className:"followup-prompts",children:e.followUpPrompts.map((r,a)=>t.jsx("button",{type:"button",className:"followup-prompt",onClick:()=>Oe(r),children:r},a))})]}),k.has(e.id)&&t.jsx("div",{className:"message-actions-container",children:t.jsxs("div",{className:"message-actions",children:[t.jsx("button",{type:"button",className:`icon-btn ${N[e.id]==="up"?"active":""}`,"aria-label":"Thumbs up",onClick:()=>Ce(e.id),children:N[e.id]==="up"?t.jsx(w.IoThumbsUp,{color:"#1a3673"}):t.jsx(w.IoThumbsUpOutline,{color:"#1a3673"})}),t.jsx("button",{type:"button",className:`icon-btn ${N[e.id]==="down"?"active":""}`,"aria-label":"Thumbs down",onClick:()=>Ee(e.id),children:N[e.id]==="down"?t.jsx(w.IoThumbsDown,{color:"#1a3673"}):t.jsx(w.IoThumbsDownOutline,{color:"#1a3673"})}),t.jsx("button",{type:"button",className:"icon-btn","aria-label":"Copy",onClick:async()=>{try{await navigator.clipboard.writeText(e.content)}catch{alert("Failed to copy text")}},children:t.jsx(w.IoCopyOutline,{color:"#1a3673"})}),t.jsx("button",{type:"button",className:"icon-btn","aria-label":"Get shareable link",onClick:()=>alert(`Share this response: ${e.content}`),children:t.jsx(w.IoRepeatSharp,{color:"#1a3673"})})]})})]})}):t.jsx("div",{className:"message-user",style:{textAlign:"right",alignSelf:"flex-end"},children:e.content})},e.id)),v&&t.jsx("section",{className:"message assistant",children:t.jsx("div",{className:"message-assistant",children:t.jsx("div",{className:"thinking-indicator",children:"Thinking..."})})}),ee&&t.jsx("div",{className:"error-banner",children:ee}),t.jsx("div",{ref:se})]})]}),t.jsxs("form",{className:"chat-input-wrap",onSubmit:le,children:[t.jsx("input",{className:"chat-input",placeholder:"Send a message",value:S,onChange:e=>O(e.target.value),onKeyDown:e=>{e.key==="Enter"&&!e.shiftKey&&(le(),e.preventDefault())},disabled:v,autoFocus:!0}),t.jsx("button",{type:"submit",className:"send-btn",disabled:!S.trim()||v,children:v?t.jsx(_e,{}):t.jsx(w.IoSendSharp,{})})]})]})}function _e(){return t.jsx("span",{className:"spinner","aria-hidden":"true"})}return Re}));