import React, { useCallback, useEffect, useState } from "react"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Label } from "@/components/ui/label"; import { Slider } from "@/components/ui/slider"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Separator } from "@/components/ui/separator"; import { FileText, Link2, Settings, Volume2, Mic, Circle, CircleDot, Loader2, Text, } from "lucide-react"; import { useAppDispatch, useAppSelector } from "@/redux/hooks"; import { setActiveVoice, setMaxTokens, setSilenceDuration, setTemperature, setThreshold, } from "@/redux/slices/settingsSlice"; import { setEmbeddingsText, clearEmbeddings, setisUploadingEmbeddings, setActiveChatPrompt, toggleSavingPrompt, } from "@/redux/slices/chatSlice"; import api from "@/api/apiClient"; import { toast } from "sonner"; import { Textarea } from "./ui/textarea"; import { cn } from "@/lib/utils"; const voices = [ { id: 0, name: "Tripati (F)", voice_name: "af" }, { id: 1, name: "Bella (F)", voice_name: "af_bella" }, { id: 2, name: "Sarah (F)", voice_name: "af_sarah" }, { id: 3, name: "Adam (M)", voice_name: "am_adam" }, { id: 4, name: "Michael (M)", voice_name: "am_michael" }, { id: 5, name: "Emma (F)", voice_name: "bf_emma" }, { id: 6, name: "Isabella (F)", voice_name: "bf_isabella", }, { id: 7, name: "George (M)", voice_name: "bm_george" }, { id: 8, name: "Lewis (M)", voice_name: "bm_lewis" }, { id: 9, name: "Nicole (F)", voice_name: "af_nicole" }, { id: 10, name: "Sky (M)", voice_name: "af_sky" }, ]; const ControlPanel = () => { const [linkUrl, setLinkUrl] = useState(""); const [text, settext] = useState(""); const [title, setTitle] = useState(""); const [summary, setSummary] = useState(""); const [categories, setCategories] = useState(""); const [selectedTab, setSelectedTab] = useState("voice"); const [contextDeleting, setContextDeleting] = useState(false); const [selectedFile, setSelectedFile] = useState(null); const dispatch = useAppDispatch(); const { activeChat } = useAppSelector((state) => state.chats); const { activeChatContext, uploadingEmbeddings, activeChatPrompt, savingPrompt, } = useAppSelector((state) => state.chat); const [localPromptState, setLocalPromptState] = useState(""); useEffect(() => { setLocalPromptState(activeChatPrompt); }, [activeChatPrompt]); const { activeVoice, temperature, maxTokens, silenceDuration, threshold } = useAppSelector((state) => state.settings); const handleFileChange = (e: React.ChangeEvent) => { if (e.target.files && e.target.files[0]) { setSelectedFile(e.target.files[0]); } }; const handleEmbeddingList = async ( name: string, title: string, summary: string, categories: string ) => { let categoriesList = []; if (categories != null) { if (typeof categories === "string") { categoriesList = categories .split(",") .map((cat) => cat.trim()) .filter((cat) => cat.length > 0); } else if (Array.isArray(categories)) { categoriesList = categories.map((cat) => String(cat)); } else { categoriesList = [String(categories)]; } } dispatch( setEmbeddingsText({ name: name, title: title, summary: summary, categories: categoriesList, }) ); }; const cleatMetaData = () => { setTitle(""); setSummary(""); setCategories(""); }; const handleSavePrompt = async () => { if (localPromptState === activeChatPrompt) return; setLocalPromptState(activeChatPrompt); dispatch(toggleSavingPrompt()); try { if (!activeChatPrompt) { toast.error("Please add prompt to save the prompt."); return; } const response = await api.post("/prompt", { sessionId: activeChat, prompt: localPromptState, }); if (!response.success) { toast.error("Failed to save prompt. Please try again"); return; } dispatch(setActiveChatPrompt(localPromptState)); toast.success("System Prompt saved successfully."); } catch (_) { toast.error("Failed to save prompt. Please try again"); } finally { dispatch(toggleSavingPrompt()); } }; const handleLinkAdd = useCallback(async () => { try { dispatch(setisUploadingEmbeddings(true)); if (!linkUrl.trim()) { toast.error("Please provide a url"); return; } if (!activeChat) { toast.error("Please select or create a chat."); return; } const response = await api.post("/rag/link", { link: linkUrl, sessionId: activeChat, title: title, summary: summary, categories: categories, }); if (!response.success) { toast.error("failed to process link. Please try again"); return; } await handleEmbeddingList(linkUrl, title, summary, categories); setLinkUrl(""); } catch (error) { console.error("Error in processing link : ", error); if ( error.response && error.response.data && error.response.data.message ) { toast.error(error.response.data.message); } else { // Display a generic error message toast.error("Failed to process link. Please try again."); } setLinkUrl(""); } finally { dispatch(setisUploadingEmbeddings(false)); // cleatMetaData(); } }, [activeChat, linkUrl, dispatch, title, summary, categories]); const handleTextUpload = useCallback(async () => { try { dispatch(setisUploadingEmbeddings(true)); console.log("MEtaData : ", { title, summary, categories }); if (!text.trim()) { toast.error("Please provide text"); return; } if (!activeChat) { toast.error("Please select or create a chat."); return; } const name = `${text.slice(0, 10)}...`; const response = await api.post("/rag/text", { text: text, sessionId: activeChat, title: title, name: name, summary: summary, categories: categories, }); if (!response.success) { toast.error("failed to process text. Please try again"); return; } await handleEmbeddingList(name, title, summary, categories); } catch (error) { console.error("Error in processing text : ", error); if ( error.response && error.response.data && error.response.data.message ) { toast.error(error.response.data.message); } else { toast.error("Failed to process text. Please try again."); } } finally { settext(""); dispatch(setisUploadingEmbeddings(false)); cleatMetaData(); } }, [activeChat, text, dispatch, title, summary, categories]); const handlePdfUpload = useCallback(async () => { dispatch(setisUploadingEmbeddings(true)); if (!activeChat) { toast.error("Please select or create a chat."); return; } if (!selectedFile) { toast.error("Please select a PDF file to upload."); return; } const form = new FormData(); form.append("pdfFile", selectedFile); form.append("name", selectedFile.name); form.append("title", title); form.append("summary", summary); form.append("categories", categories); form.append("sessionId", activeChat); const config = { headers: { "Content-Type": "multipart/form-data", }, }; try { const response = await api.post("/rag/pdf", form, config); if (!response.success) { toast.error("Failed to upload PDF. Please try again."); } await handleEmbeddingList(selectedFile.name, title, summary, categories); setSelectedFile(null); toast.success("PDF uploaded successfully!"); } catch (error) { console.error("Error uploading PDF:", error); toast.error("Failed to upload PDF. Please try again."); } finally { dispatch(setisUploadingEmbeddings(false)); cleatMetaData(); } }, [selectedFile, activeChat, dispatch, title, summary, categories]); const handleDelete = async () => { try { if (!activeChat) { toast.error("Please select a chat first"); return; } const response = await api.post("/rag/clear-context", { sessionId: activeChat, }); if (response.success) { toast.success("Context cleard successfully"); dispatch(clearEmbeddings()); return; } else { toast.error("Failed to clear embeddings. Please try again"); } } catch (error) { toast.error("Failed to clear embeddings. Please try again"); } finally { setContextDeleting(false); } }; const metadataForData = () => { return (
setTitle(e.target.value)} />