@charisma-ai/react
Version:
Charisma.ai chat component for React
237 lines (232 loc) • 8.93 kB
JavaScript
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