UNPKG

@charisma-ai/react

Version:

Charisma.ai chat component for React

237 lines (232 loc) 8.93 kB
import React, { createContext, useState, useRef, useEffect, useContext, useMemo } from 'react'; import { Charisma as Charisma$1 } from '@charisma-ai/sdk'; const CharismaContext = createContext(undefined); var __rest = (undefined && undefined.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; const useCharisma = ({ playthroughToken, charismaUrl, onConnect = () => { }, onReady = () => { }, onError = () => { }, isConnected = false }) => { const [charisma, setCharisma] = useState(); const onConnectRef = useRef(onConnect); useEffect(() => { onConnectRef.current = onConnect; }, [onConnect]); const onReadyRef = useRef(onReady); useEffect(() => { onReadyRef.current = onReady; }, [onReady]); const onErrorRef = useRef(onError); useEffect(() => { onErrorRef.current = onError; }, [onError]); useEffect(() => { if (playthroughToken) { const newCharisma = new Charisma$1(playthroughToken, { charismaUrl }); newCharisma.on("connect", onConnectRef.current); newCharisma.on("ready", onReadyRef.current); newCharisma.on("error", onErrorRef.current); setCharisma(newCharisma); return () => { newCharisma.cleanup(); }; } return undefined; }, [playthroughToken]); useEffect(() => { if (charisma) { if (isConnected) { charisma.connect(); } else { charisma.cleanup(); } } }, [isConnected, charisma]); return charisma; }; const Charisma = (_a) => { var { children } = _a, props = __rest(_a, ["children"]); const charisma = useCharisma(props); return (React.createElement(CharismaContext.Provider, { value: charisma || null }, typeof children === "function" ? children(charisma) : children)); }; var __rest$1 = (undefined && undefined.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var ChatMode; (function (ChatMode) { ChatMode["Tap"] = "tap"; ChatMode["Chat"] = "chat"; })(ChatMode || (ChatMode = {})); const useConversation = ({ conversationId, onChangeCharacterMoods, onMessage, onStartTyping, onStopTyping, onSceneCompleted, onStart, onReply, onTap, speechConfig, stopOnSceneComplete }) => { const charisma = useContext(CharismaContext); if (charisma === undefined) { throw new Error(`To use \`Conversation\`, you must wrap it within a \`Charisma\` instance.`); } const [inputValue, setInputValue] = useState(""); const [isTyping, setIsTyping] = useState(false); const [messages, setMessages] = useState([]); const [mode, setMode] = useState(ChatMode.Chat); const onMessageRef = useRef(() => { }); const onStartTypingRef = useRef(() => { }); const onStopTypingRef = useRef(() => { }); const onSceneCompletedRef = useRef(() => { }); const characterMoodsRef = useRef({}); useEffect(() => { onMessageRef.current = (event) => { setMessages([...messages, event]); if (event.tapToContinue) { setMode(ChatMode.Tap); } else { setMode(ChatMode.Chat); } if (event.characterMoods.length > 0) { const newCharacterMoods = Object.assign({}, characterMoodsRef.current); event.characterMoods.forEach(({ id, mood }) => { newCharacterMoods[id] = mood; }); characterMoodsRef.current = newCharacterMoods; if (onChangeCharacterMoods) { onChangeCharacterMoods(newCharacterMoods); } } if (onMessage) { onMessage(event); } }; }, [onMessage, messages, onChangeCharacterMoods]); useEffect(() => { onStartTypingRef.current = (event) => { setIsTyping(true); if (onStartTyping) { onStartTyping(event); } }; }, [onStartTyping]); useEffect(() => { onStopTypingRef.current = (event) => { setIsTyping(false); if (onStopTyping) { onStopTyping(event); } }; }, [onStopTyping]); useEffect(() => { onSceneCompletedRef.current = (event) => { if (onSceneCompleted) { onSceneCompleted(event); } }; }, [onSceneCompleted]); const conversationRef = useRef(); useEffect(() => { if (conversationRef.current) { conversationRef.current.setSpeechConfig(speechConfig); if (typeof stopOnSceneComplete === "boolean") { conversationRef.current.setStopOnSceneEnd(stopOnSceneComplete); } } }, [speechConfig, stopOnSceneComplete]); useEffect(() => { (async function run() { if (charisma && conversationId) { const conversation = await charisma.joinConversation(conversationId); conversation.on("message", event => { onMessageRef.current(event); }); conversation.on("start-typing", event => onStartTypingRef.current(event)); conversation.on("stop-typing", event => onStopTypingRef.current(event)); conversation.on("scene-completed", event => onSceneCompletedRef.current(event)); conversation.setSpeechConfig(speechConfig); if (typeof stopOnSceneComplete === "boolean") { conversation.setStopOnSceneEnd(stopOnSceneComplete); } conversationRef.current = conversation; return () => { charisma.leaveConversation(conversationId); conversationRef.current = undefined; }; } return undefined; })(); }, [charisma, conversationId]); const onStartRef = useRef(onStart); const onReplyRef = useRef(onReply); const onTapRef = useRef(onTap); useEffect(() => { onStartRef.current = onStart; }, [onStart]); useEffect(() => { onReplyRef.current = onReply; }, [onReply]); useEffect(() => { onTapRef.current = onTap; }, [onTap]); const returnedValue = useMemo(() => { return { inputValue, isTyping, messages, mode, type: setInputValue, start: event => { if (onStartRef.current) { onStartRef.current(event || {}); } setMessages([]); if (conversationRef.current) { conversationRef.current.start(event); } }, reply: event => { if (onReplyRef.current) { onReplyRef.current(event); } setMessages([ ...messages, { type: "player", message: { text: event.text } } ]); setInputValue(""); if (conversationRef.current) { conversationRef.current.reply(event); } }, tap: () => { if (onTapRef.current) { onTapRef.current(); } if (conversationRef.current) { conversationRef.current.tap(); } } }; }, [inputValue, isTyping, messages, mode]); return returnedValue; }; const Conversation = (_a) => { var { children } = _a, props = __rest$1(_a, ["children"]); const conversation = useConversation(props); return React.createElement(React.Fragment, null, children(conversation)); }; export { Charisma, CharismaContext, ChatMode, Conversation, useCharisma, useConversation }; //# sourceMappingURL=index.js.map