| 
									
										
										
										
											2023-03-08 13:30:11 -08:00
										 |  |  | import { useDebouncedValue } from "@mantine/hooks"; | 
					
						
							| 
									
										
										
										
											2023-03-06 05:30:58 -08:00
										 |  |  | import React, { useState, useRef, useMemo, useEffect, useCallback } from "react"; | 
					
						
							| 
									
										
										
										
											2023-03-08 13:30:11 -08:00
										 |  |  | import { useLocation, useNavigate, useParams } from "react-router-dom"; | 
					
						
							| 
									
										
										
										
											2023-03-06 05:30:58 -08:00
										 |  |  | import { backend } from "./backend"; | 
					
						
							|  |  |  | import ChatManagerInstance, { ChatManager } from "./chat-manager"; | 
					
						
							|  |  |  | import { defaultElevenLabsVoiceID } from "./elevenlabs"; | 
					
						
							| 
									
										
										
										
											2023-03-08 13:30:11 -08:00
										 |  |  | import { loadParameters, saveParameters } from "./parameters"; | 
					
						
							|  |  |  | import { Parameters } from "./types"; | 
					
						
							|  |  |  | import { useChat, UseChatResult } from "./use-chat"; | 
					
						
							| 
									
										
										
										
											2023-03-06 05:30:58 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export interface Context { | 
					
						
							|  |  |  |     authenticated: boolean; | 
					
						
							|  |  |  |     chat: ChatManager; | 
					
						
							| 
									
										
										
										
											2023-03-08 13:30:11 -08:00
										 |  |  |     id: string | undefined | null; | 
					
						
							|  |  |  |     currentChat: UseChatResult; | 
					
						
							|  |  |  |     isShare: boolean; | 
					
						
							| 
									
										
										
										
											2023-03-06 05:30:58 -08:00
										 |  |  |     apiKeys: { | 
					
						
							|  |  |  |         openai: string | undefined | null; | 
					
						
							|  |  |  |         setOpenAIApiKey: (apiKey: string | null) => void; | 
					
						
							|  |  |  |         elevenlabs: string | undefined | null; | 
					
						
							|  |  |  |         setElevenLabsApiKey: (apiKey: string | null) => void; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     settings: { | 
					
						
							|  |  |  |         tab: string | undefined | null; | 
					
						
							|  |  |  |         option: string | undefined | null; | 
					
						
							|  |  |  |         open: (tab: string, option?: string | undefined | null) => void; | 
					
						
							|  |  |  |         close: () => void; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     voice: { | 
					
						
							|  |  |  |         id: string; | 
					
						
							|  |  |  |         setVoiceID: (id: string) => void; | 
					
						
							| 
									
										
										
										
											2023-03-08 13:30:11 -08:00
										 |  |  |     }; | 
					
						
							|  |  |  |     generating: boolean; | 
					
						
							|  |  |  |     message: string; | 
					
						
							|  |  |  |     parameters: Parameters; | 
					
						
							|  |  |  |     setMessage: (message: string) => void; | 
					
						
							|  |  |  |     setParameters: (parameters: Parameters) => void; | 
					
						
							|  |  |  |     onNewMessage: (message?: string) => Promise<boolean>; | 
					
						
							| 
									
										
										
										
											2023-03-06 05:30:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const AppContext = React.createContext<Context>({} as any); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function useCreateAppContext(): Context { | 
					
						
							| 
									
										
										
										
											2023-03-08 13:30:11 -08:00
										 |  |  |     const { id } = useParams(); | 
					
						
							|  |  |  |     const pathname = useLocation().pathname; | 
					
						
							|  |  |  |     const isShare = pathname.startsWith('/s/'); | 
					
						
							|  |  |  |     const navigate = useNavigate(); | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     const chatManager = useRef(ChatManagerInstance); | 
					
						
							|  |  |  |     const currentChat = useChat(chatManager.current, id, isShare); | 
					
						
							| 
									
										
										
										
											2023-03-06 05:30:58 -08:00
										 |  |  |     const [authenticated, setAuthenticated] = useState(backend?.isAuthenticated || false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const updateAuth = useCallback((authenticated: boolean) => setAuthenticated(authenticated), []); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     useEffect(() => { | 
					
						
							|  |  |  |         backend?.on('authenticated', updateAuth); | 
					
						
							|  |  |  |         return () => { | 
					
						
							|  |  |  |             backend?.off('authenticated', updateAuth) | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |     }, [backend]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const [openaiApiKey, setOpenAIApiKey] = useState<string | null>( | 
					
						
							|  |  |  |         localStorage.getItem('openai-api-key') || '' | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |     const [elevenLabsApiKey, setElevenLabsApiKey] = useState<string | null>( | 
					
						
							|  |  |  |         localStorage.getItem('elevenlabs-api-key') || '' | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     useEffect(() => { | 
					
						
							| 
									
										
										
										
											2023-03-08 13:30:11 -08:00
										 |  |  |         if (openaiApiKey) { | 
					
						
							|  |  |  |             localStorage.setItem('openai-api-key', openaiApiKey || ''); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-03-06 05:30:58 -08:00
										 |  |  |     }, [openaiApiKey]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     useEffect(() => { | 
					
						
							| 
									
										
										
										
											2023-03-08 13:30:11 -08:00
										 |  |  |         if (elevenLabsApiKey) { | 
					
						
							|  |  |  |             localStorage.setItem('elevenlabs-api-key', elevenLabsApiKey || ''); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-03-06 05:30:58 -08:00
										 |  |  |     }, [elevenLabsApiKey]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const [settingsTab, setSettingsTab] = useState<string | null | undefined>(); | 
					
						
							|  |  |  |     const [option, setOption] = useState<string | null | undefined>(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const [voiceID, setVoiceID] = useState(localStorage.getItem('voice-id') || defaultElevenLabsVoiceID); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     useEffect(() => { | 
					
						
							|  |  |  |         localStorage.setItem('voice-id', voiceID); | 
					
						
							|  |  |  |     }, [voiceID]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-08 13:30:11 -08:00
										 |  |  |     const [generating, setGenerating] = useState(false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const [message, setMessage] = useState(''); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const [_parameters, setParameters] = useState<Parameters>(loadParameters(id)); | 
					
						
							|  |  |  |     useEffect(() => { | 
					
						
							|  |  |  |         setParameters(loadParameters(id)); | 
					
						
							|  |  |  |     }, [id]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const [parameters] = useDebouncedValue(_parameters, 2000); | 
					
						
							|  |  |  |     useEffect(() => { | 
					
						
							|  |  |  |         if (id) { | 
					
						
							|  |  |  |             saveParameters(id, parameters); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         saveParameters('', parameters); | 
					
						
							|  |  |  |     }, [id, parameters]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const onNewMessage = useCallback(async (message?: string) => { | 
					
						
							|  |  |  |         if (isShare) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!message?.trim().length) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!openaiApiKey) { | 
					
						
							|  |  |  |             setSettingsTab('user'); | 
					
						
							|  |  |  |             setOption('openai-api-key'); | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         setGenerating(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (id) { | 
					
						
							|  |  |  |             await chatManager.current.sendMessage({ | 
					
						
							|  |  |  |                 chatID: id, | 
					
						
							|  |  |  |                 content: message.trim(), | 
					
						
							|  |  |  |                 requestedParameters: { | 
					
						
							|  |  |  |                     ...parameters, | 
					
						
							|  |  |  |                     apiKey: openaiApiKey, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 parentID: currentChat.leaf?.id, | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             const id = await chatManager.current.createChat(); | 
					
						
							|  |  |  |             await chatManager.current.sendMessage({ | 
					
						
							|  |  |  |                 chatID: id, | 
					
						
							|  |  |  |                 content: message.trim(), | 
					
						
							|  |  |  |                 requestedParameters: { | 
					
						
							|  |  |  |                     ...parameters, | 
					
						
							|  |  |  |                     apiKey: openaiApiKey, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 parentID: currentChat.leaf?.id, | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |             navigate('/chat/' + id); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         setTimeout(() => setGenerating(false), 4000); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     }, [chatManager, openaiApiKey, id, parameters, message, currentChat.leaf]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-06 05:30:58 -08:00
										 |  |  |     const context = useMemo<Context>(() => ({ | 
					
						
							|  |  |  |         authenticated, | 
					
						
							| 
									
										
										
										
											2023-03-08 13:30:11 -08:00
										 |  |  |         id, | 
					
						
							|  |  |  |         chat: chatManager.current, | 
					
						
							|  |  |  |         currentChat, | 
					
						
							|  |  |  |         isShare, | 
					
						
							| 
									
										
										
										
											2023-03-06 05:30:58 -08:00
										 |  |  |         apiKeys: { | 
					
						
							|  |  |  |             openai: openaiApiKey, | 
					
						
							|  |  |  |             elevenlabs: elevenLabsApiKey, | 
					
						
							|  |  |  |             setOpenAIApiKey, | 
					
						
							|  |  |  |             setElevenLabsApiKey, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         settings: { | 
					
						
							|  |  |  |             tab: settingsTab, | 
					
						
							|  |  |  |             option: option, | 
					
						
							|  |  |  |             open: (tab: string, option?: string | undefined | null) => { | 
					
						
							|  |  |  |                 setSettingsTab(tab); | 
					
						
							|  |  |  |                 setOption(option); | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             close: () => { | 
					
						
							|  |  |  |                 setSettingsTab(null); | 
					
						
							|  |  |  |                 setOption(null); | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         voice: { | 
					
						
							|  |  |  |             id: voiceID, | 
					
						
							|  |  |  |             setVoiceID, | 
					
						
							|  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2023-03-08 13:30:11 -08:00
										 |  |  |         generating, | 
					
						
							|  |  |  |         message, | 
					
						
							|  |  |  |         parameters, | 
					
						
							|  |  |  |         setMessage, | 
					
						
							|  |  |  |         setParameters, | 
					
						
							|  |  |  |         onNewMessage, | 
					
						
							|  |  |  |     }), [chatManager, authenticated, openaiApiKey, elevenLabsApiKey, settingsTab, option, voiceID, | 
					
						
							|  |  |  |         generating, message, parameters, onNewMessage, currentChat]); | 
					
						
							| 
									
										
										
										
											2023-03-06 05:30:58 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return context; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function useAppContext() { | 
					
						
							|  |  |  |     return React.useContext(AppContext); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function AppContextProvider(props: { children: React.ReactNode }) { | 
					
						
							|  |  |  |     const context = useCreateAppContext(); | 
					
						
							|  |  |  |     return <AppContext.Provider value={context}>{props.children}</AppContext.Provider>; | 
					
						
							|  |  |  | } |