@elevenlabs/react-native
Version:
ElevenLabs React Native SDK for Conversational AI
3 lines (2 loc) • 9.23 kB
JavaScript
import e,{useRef as n,useCallback as t,useState as o,useEffect as r,useContext as l,createContext as a}from"react";import{AudioSession as c,useLocalParticipant as s,useDataChannel as i,LiveKitRoom as d,registerGlobals as u}from"@livekit/react-native";function v(){return v=Object.assign?Object.assign.bind():function(e){for(var n=1;n<arguments.length;n++){var t=arguments[n];for(var o in t)({}).hasOwnProperty.call(t,o)&&(e[o]=t[o])}return e},v.apply(null,arguments)}const g="0.3.1",_=({onReady:n,isConnected:t,callbacks:o,sendMessage:l,clientTools:a={},updateCurrentEventId:c})=>{const{localParticipant:d}=s(),u=e.useRef(1);return r(()=>{t&&d&&n(d)},[t,d,n]),i(e=>{var n,t;const r=new TextDecoder,s=JSON.parse(r.decode(e.payload));if(s.type){var i;if(null==o.onMessage||o.onMessage({message:s,source:null!=(n=e.from)&&n.isAgent?"ai":"user"}),null!=(t=e.from)&&t.isAgent&&(null==o.onModeChange||o.onModeChange({mode:null!=(i=e.from)&&i.isSpeaking?"speaking":"listening"}),"agent_response"===s.type&&c)){const e=u.current++;c(e)}switch(s.type){case"ping":l({type:"pong",event_id:s.ping_event.event_id});break;case"client_tool_call":(async e=>{if(Object.prototype.hasOwnProperty.call(a,e.client_tool_call.tool_name))try{var n;const t=null!=(n=await a[e.client_tool_call.tool_name](e.client_tool_call.parameters))?n:"Client tool execution successful.",o="object"==typeof t?JSON.stringify(t):String(t);l({type:"client_tool_result",tool_call_id:e.client_tool_call.tool_call_id,result:o,is_error:!1})}catch(n){null==o.onError||o.onError(`Client tool execution failed with following error: ${null==n?void 0:n.message}`,{clientToolName:e.client_tool_call.tool_name}),l({type:"client_tool_result",tool_call_id:e.client_tool_call.tool_call_id,result:`Client tool execution failed: ${null==n?void 0:n.message}`,is_error:!0})}else{if(o.onUnhandledClientToolCall)return void o.onUnhandledClientToolCall(e);const n=`Client tool with name ${e.client_tool_call.tool_name} is not defined on client`;null==o.onError||o.onError(n,{clientToolName:e.client_tool_call.tool_name}),l({type:"client_tool_result",tool_call_id:e.client_tool_call.tool_call_id,result:n,is_error:!0})}})(s);break;default:null==o.onDebug||o.onDebug(s)}}else null==o.onDebug||o.onDebug({type:"invalid_event",message:s})}),null},m=({children:n,serverUrl:t,token:o,connect:r,onConnected:l,onDisconnected:a,onError:c,roomConnected:s,callbacks:i,onParticipantReady:u,sendMessage:v,clientTools:g,updateCurrentEventId:m})=>/*#__PURE__*/e.createElement(d,{serverUrl:t,token:o,connect:r,audio:!0,video:!1,options:{adaptiveStream:{pixelDensity:"screen"}},onConnected:l,onDisconnected:a,onError:c},/*#__PURE__*/e.createElement(_,{onReady:u,isConnected:s,callbacks:i,sendMessage:v,clientTools:g,updateCurrentEventId:m}),n),C=["serverUrl","tokenFetchUrl","clientTools"],p=/*#__PURE__*/a(null),k=(n={})=>{const t=l(p);if(!t)throw new Error("useConversation must be used within ElevenLabsProvider");const{serverUrl:o,tokenFetchUrl:r,clientTools:a}=n,c=function(e,n){if(null==e)return{};var t={};for(var o in e)if({}.hasOwnProperty.call(e,o)){if(-1!==n.indexOf(o))continue;t[o]=e[o]}return t}(n,C);return e.useEffect(()=>{o&&t.setServerUrl(o)},[t,o]),e.useEffect(()=>{r&&t.setTokenFetchUrl(r)},[t,r]),a&&t.setClientTools(a),t.setCallbacks(c),t.conversation},b=({children:l})=>{u();const[a,s]=o(""),[i,d]=o(!1),[_,C]=o("disconnected"),[k,b]=o("wss://livekit.rtc.elevenlabs.io"),[h,f]=o(void 0),[y,E]=o(""),[S,w]=o(!1),[x,T]=o(!1),I=e.useRef(1),U=e.useRef(1),D=e.useRef({}),{callbacksRef:M,setCallbacks:F}=(()=>{const e=n({}),o=t(n=>{e.current=n},[]);return{callbacksRef:e,setCallbacks:o}})(),R=e.useCallback(e=>{const n=v({},e,{onModeChange:n=>{w("speaking"===n.mode),null==e.onModeChange||e.onModeChange(n)}});F(n)},[F]),{startSession:P,endSession:O,overrides:L,customLlmExtraBody:N,dynamicVariables:A,userId:V}=((e,n,r,l,a,c)=>{const[s,i]=o({}),[d,u]=o(null),[v,_]=o({}),[m,C]=o(void 0);return{startSession:t(async t=>{try{let o;if(n("connecting"),null==e.current.onStatusChange||e.current.onStatusChange({status:"connecting"}),i(t.overrides||{}),u(t.customLlmExtraBody||null),_(t.dynamicVariables||{}),C(t.userId),t.conversationToken)o=t.conversationToken;else{if(!t.agentId)throw new Error("Either conversationToken or agentId is required");{console.info("Getting conversation token for agentId:",t.agentId);const e=t.tokenFetchUrl||c;o=await(async(e,n)=>{const t=n||"https://api.elevenlabs.io/v1/convai/conversation/token",o=await fetch(`${t}?agent_id=${e}&source=react_native_sdk&version=${g}`),r=await o.json();if(!o.ok)throw new Error(`Failed to get conversation token: ${r.detail.message}`);if(!r.token)throw new Error("No conversation token received from API");return r.token})(t.agentId,e)}}const s=(e=>{try{var n,t;return(null==(t=((null==(n=JSON.parse(atob(e.split(".")[1])).video)?void 0:n.room)||"").match(/(conv_[a-zA-Z0-9]+)/))?void 0:t[0])||""}catch(e){return console.warn("Could not extract conversation ID from token"),""}})(o);a(s),l(o),r(!0)}catch(t){throw n("disconnected"),null==e.current.onStatusChange||e.current.onStatusChange({status:"disconnected"}),null==e.current.onError||e.current.onError(t),t}},[e,n,r,l,a,c]),endSession:t(async()=>{try{r(!1),l(""),n("disconnected"),null==e.current.onStatusChange||e.current.onStatusChange({status:"disconnected"}),null==e.current.onDisconnect||e.current.onDisconnect("User ended conversation")}catch(n){throw null==e.current.onError||e.current.onError(n),n}},[e,r,l,n]),overrides:s,customLlmExtraBody:d,dynamicVariables:v,userId:m}})(M,C,d,s,E,h),{roomConnected:$,localParticipant:B,handleParticipantReady:j,handleConnected:J,handleDisconnected:K,handleError:q}=((e,n,l)=>{const[a,s]=o(!1),[i,d]=o(null);return r(()=>((async()=>{await c.startAudioSession()})(),()=>{c.stopAudioSession()}),[]),{roomConnected:a,localParticipant:i,handleParticipantReady:t(e=>{d(e)},[]),handleConnected:t(()=>{s(!0),n("connected"),null==e.current.onConnect||e.current.onConnect({conversationId:l})},[l,e,n]),handleDisconnected:t(()=>{s(!1),n("disconnected"),d(null),null==e.current.onDisconnect||e.current.onDisconnect("disconnected")},[e,n]),handleError:t(n=>{console.error("LiveKit error:",n),null==e.current.onError||e.current.onError(n.message,void 0)},[e])}})(M,C,y),z=e.useCallback(()=>{I.current=1,U.current=1,T(!1),null==M.current.onCanSendFeedbackChange||M.current.onCanSendFeedbackChange({canSendFeedback:!1}),J()},[J,M]),G=e.useCallback(()=>{T(!1),K()},[K]),{sendMessage:W}=((e,n,o)=>({sendMessage:t(async t=>{if("connected"===e&&n)try{const e=(new TextEncoder).encode(JSON.stringify(t));await n.publishData(e,{reliable:!0})}catch(e){console.error("Failed to send message via WebRTC:",e),console.error("Error details:",e),null==o.current.onError||o.current.onError(e)}else console.warn("Cannot send message: room not connected or no local participant")},[e,n,o])}))(_,B,M),Z=e.useCallback(()=>{const e=I.current!==U.current;x!==e&&(T(e),null==M.current.onCanSendFeedbackChange||M.current.onCanSendFeedbackChange({canSendFeedback:e}))},[x,M]),H=e.useCallback(e=>{x?(W({type:"feedback",score:e?"like":"dislike",event_id:I.current}),U.current=I.current,Z()):console.warn(0===U.current?"Cannot send feedback: the conversation has not started yet.":"Cannot send feedback: feedback has already been sent for the current response.")},[x,W,Z]);e.useCallback(e=>{console.warn("setVolume is not yet implemented in React Native SDK")},[]);const Q=e.useCallback(e=>{B&&B.setMicrophoneEnabled(!e)},[B]),X=e.useCallback(e=>{I.current=e,Z()},[Z]),Y=e.useCallback(e=>{if(j(e),B){const e=function(e){const n={type:"conversation_initiation_client_data"};var t,o,r,l,a,c;return e.overrides&&(n.conversation_config_override={agent:{prompt:null==(t=e.overrides.agent)?void 0:t.prompt,first_message:null==(o=e.overrides.agent)?void 0:o.firstMessage,language:null==(r=e.overrides.agent)?void 0:r.language},tts:{voice_id:null==(l=e.overrides.tts)?void 0:l.voiceId},conversation:{text_only:null==(a=e.overrides.conversation)?void 0:a.textOnly},source_info:{source:"react_native_sdk",version:(null==(c=e.overrides)||null==(c=c.client)?void 0:c.version)||g}}),e.customLlmExtraBody&&(n.custom_llm_extra_body=e.customLlmExtraBody),e.dynamicVariables&&(n.dynamic_variables=e.dynamicVariables),e.userId&&(n.user_id=String(e.userId)),n}({overrides:L,customLlmExtraBody:N,dynamicVariables:A,userId:V});W(e)}},[j,B,L,N,A,V,W]),ee={startSession:P,endSession:O,status:_,isSpeaking:S,canSendFeedback:x,getId:()=>y,setMicMuted:Q,sendFeedback:H,sendContextualUpdate:e=>{W({type:"contextual_update",text:e})},sendUserMessage:e=>{W({type:"user_message",text:e})},sendUserActivity:()=>{W({type:"user_activity"})}},ne=e.useCallback(e=>{D.current=e},[]);/*#__PURE__*/return e.createElement(p.Provider,{value:{conversation:ee,callbacksRef:M,serverUrl:k,tokenFetchUrl:h,clientTools:D.current,setCallbacks:R,setServerUrl:b,setTokenFetchUrl:f,setClientTools:ne}},/*#__PURE__*/e.createElement(m,{serverUrl:k,token:a,connect:i,onConnected:z,onDisconnected:G,onError:q,roomConnected:$,callbacks:M.current,onParticipantReady:Y,sendMessage:W,clientTools:D.current,updateCurrentEventId:X},l))};export{b as ElevenLabsProvider,k as useConversation};
//# sourceMappingURL=lib.modern.js.map