import React, { useState, useEffect, ReactElement } from 'react'; import FormGroup from '@mui/material/FormGroup'; import FormControlLabel from '@mui/material/FormControlLabel'; import Switch from '@mui/material/Switch'; import Divider from '@mui/material/Divider'; import TextField from '@mui/material/TextField'; import Accordion from '@mui/material/Accordion'; import AccordionActions from '@mui/material/AccordionActions'; import AccordionSummary from '@mui/material/AccordionSummary'; import AccordionDetails from '@mui/material/AccordionDetails'; import Typography from '@mui/material/Typography'; import Button from '@mui/material/Button'; import Box from '@mui/material/Box'; import ResetIcon from '@mui/icons-material/History'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { SetSnackType } from './Snack'; type Tool = { type: string, function?: { name: string, description: string, parameters?: any, returns?: any }, name?: string, description?: string, enabled: boolean }; interface ControlsParams { connectionBase: string, sessionId: string | undefined, setSnack: SetSnackType, }; type GPUInfo = { name: string, memory: number, discrete: boolean } type SystemInfo = { "Installed RAM": string, "Graphics Card": GPUInfo[], "CPU": string }; const SystemInfoComponent: React.FC<{ systemInfo: SystemInfo | undefined }> = ({ systemInfo }) => { const [systemElements, setSystemElements] = useState([]); const convertToSymbols = (text: string) => { return text .replace(/\(R\)/g, '®') // Replace (R) with the ® symbol .replace(/\(C\)/g, '©') // Replace (C) with the © symbol .replace(/\(TM\)/g, '™'); // Replace (TM) with the ™ symbol }; useEffect(() => { if (systemInfo === undefined) { return; } const elements = Object.entries(systemInfo).flatMap(([k, v]) => { // If v is an array, repeat for each card if (Array.isArray(v)) { return v.map((card, index) => (
{convertToSymbols(k)} {index}
{convertToSymbols(card.name)} {card.discrete ? `w/ ${Math.round(card.memory / (1024 * 1024 * 1024))}GB RAM` : "(integrated)"}
)); } // If it's not an array, handle normally return (
{convertToSymbols(k)}
{convertToSymbols(String(v))}
); }); setSystemElements(elements); }, [systemInfo]); return
{systemElements}
; }; const Controls = ({ sessionId, setSnack, connectionBase }: ControlsParams) => { const [editSystemPrompt, setEditSystemPrompt] = useState(""); const [systemInfo, setSystemInfo] = useState(undefined); const [tools, setTools] = useState([]); const [rags, setRags] = useState([]); const [systemPrompt, setSystemPrompt] = useState(""); const [serverSystemPrompt, setServerSystemPrompt] = useState(""); const [messageHistoryLength, setMessageHistoryLength] = useState(5); useEffect(() => { if (systemPrompt === serverSystemPrompt || !systemPrompt.trim() || sessionId === undefined) { return; } const sendSystemPrompt = async (prompt: string) => { try { const response = await fetch(connectionBase + `/api/tunables/${sessionId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify({ "system_prompt": prompt }), }); const data = await response.json(); const newPrompt = data["system_prompt"]; if (newPrompt !== serverSystemPrompt) { setServerSystemPrompt(newPrompt); setSystemPrompt(newPrompt) setSnack("System prompt updated", "success"); } } catch (error) { console.error('Fetch error:', error); setSnack("System prompt update failed", "error"); } }; sendSystemPrompt(systemPrompt); }, [systemPrompt, setServerSystemPrompt, serverSystemPrompt, connectionBase, sessionId, setSnack]); useEffect(() => { if (sessionId === undefined) { return; } const sendMessageHistoryLength = async (length: number) => { try { const response = await fetch(connectionBase + `/api/tunables/${sessionId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify({ "message_history_length": length }), }); const data = await response.json(); const newLength = data["message_history_length"]; if (newLength !== messageHistoryLength) { setMessageHistoryLength(newLength); setSnack("Message history length updated", "success"); } } catch (error) { console.error('Fetch error:', error); setSnack("Message history length update failed", "error"); } }; sendMessageHistoryLength(messageHistoryLength); }, [messageHistoryLength, setMessageHistoryLength, connectionBase, sessionId, setSnack]); const reset = async (types: ("rags" | "tools" | "history" | "system_prompt" | "message_history_length")[], message: string = "Update successful.") => { try { const response = await fetch(connectionBase + `/api/reset/${sessionId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify({ "reset": types }), }); if (response.ok) { const data = await response.json(); if (data.error) { throw Error() } for (const [key, value] of Object.entries(data)) { switch (key) { case "rags": setRags(value as Tool[]); break; case "tools": setTools(value as Tool[]); break; case "system_prompt": setServerSystemPrompt((value as any)["system_prompt"].trim()); setSystemPrompt((value as any)["system_prompt"].trim()); break; case "history": console.log('TODO: handle history reset'); break; } } setSnack(message, "success"); } else { throw Error(`${{ status: response.status, message: response.statusText }}`); } } catch (error) { console.error('Fetch error:', error); setSnack("Unable to restore defaults", "error"); } }; // Get the system information useEffect(() => { if (systemInfo !== undefined || sessionId === undefined) { return; } fetch(connectionBase + `/api/system-info/${sessionId}`, { method: 'GET', headers: { 'Content-Type': 'application/json', }, }) .then(response => response.json()) .then(data => { setSystemInfo(data); }) .catch(error => { console.error('Error obtaining system information:', error); setSnack("Unable to obtain system information.", "error"); }); }, [systemInfo, setSystemInfo, connectionBase, setSnack, sessionId]) useEffect(() => { setEditSystemPrompt(systemPrompt); }, [systemPrompt, setEditSystemPrompt]); const toggleRag = async (tool: Tool) => { tool.enabled = !tool.enabled try { const response = await fetch(connectionBase + `/api/rags/${sessionId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify({ "tool": tool?.name, "enabled": tool.enabled }), }); const rags = await response.json(); setRags([...rags]) setSnack(`${tool?.name} ${tool.enabled ? "enabled" : "disabled"}`); } catch (error) { console.error('Fetch error:', error); setSnack(`${tool?.name} ${tool.enabled ? "enabling" : "disabling"} failed.`, "error"); tool.enabled = !tool.enabled } }; const toggleTool = async (tool: Tool) => { tool.enabled = !tool.enabled try { const response = await fetch(connectionBase + `/api/tools/${sessionId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify({ "tool": tool?.function?.name, "enabled": tool.enabled }), }); const tools = await response.json(); setTools([...tools]) setSnack(`${tool?.function?.name} ${tool.enabled ? "enabled" : "disabled"}`); } catch (error) { console.error('Fetch error:', error); setSnack(`${tool?.function?.name} ${tool.enabled ? "enabling" : "disabling"} failed.`, "error"); tool.enabled = !tool.enabled } }; // If the tools have not been set, fetch them from the server useEffect(() => { if (tools.length || sessionId === undefined) { return; } const fetchTools = async () => { try { // Make the fetch request with proper headers const response = await fetch(connectionBase + `/api/tools/${sessionId}`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, }); if (!response.ok) { throw Error(); } const tools = await response.json(); setTools(tools); } catch (error: any) { setSnack("Unable to fetch tools", "error"); console.error(error); } } fetchTools(); }, [sessionId, tools, setTools, setSnack, connectionBase]); // If the RAGs have not been set, fetch them from the server useEffect(() => { if (rags.length || sessionId === undefined) { return; } const fetchRags = async () => { try { // Make the fetch request with proper headers const response = await fetch(connectionBase + `/api/rags/${sessionId}`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, }); if (!response.ok) { throw Error(); } const rags = await response.json(); setRags(rags); } catch (error: any) { setSnack("Unable to fetch RAGs", "error"); console.error(error); } } fetchRags(); }, [sessionId, rags, setRags, setSnack, connectionBase]); // If the systemPrompt has not been set, fetch it from the server useEffect(() => { if (serverSystemPrompt !== "" || sessionId === undefined) { return; } const fetchTunables = async () => { // Make the fetch request with proper headers const response = await fetch(connectionBase + `/api/tunables/${sessionId}`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, }); const data = await response.json(); const serverSystemPrompt = data["system_prompt"].trim(); setServerSystemPrompt(serverSystemPrompt); setSystemPrompt(serverSystemPrompt); setMessageHistoryLength(data["message_history_length"]); } fetchTunables(); }, [sessionId, serverSystemPrompt, setServerSystemPrompt, connectionBase]); const toggle = async (type: string, index: number) => { switch (type) { case "rag": toggleRag(rags[index]) break; case "tool": toggleTool(tools[index]); } }; const handleKeyPress = (event: any) => { if (event.key === 'Enter' && event.ctrlKey) { switch (event.target.id) { case 'SystemPromptInput': setSystemPrompt(editSystemPrompt); break; } } }; return (
You can change the information available to the LLM by adjusting the following settings: }> System Prompt setEditSystemPrompt(e.target.value)} onKeyDown={handleKeyPress} placeholder="Enter the new system prompt.." id="SystemPromptInput" />
}> Tunables setMessageHistoryLength(e.target.value)} slotProps={{ htmlInput: { min: 0 }, inputLabel: { shrink: true, }, }} /> }> Tools These tools can be made available to the LLM for obtaining real-time information from the Internet. The description provided to the LLM is provided for reference. { tools.map((tool, index) => } onChange={() => toggle("tool", index)} label={tool?.function?.name} /> {tool?.function?.description} ) } }> RAG These RAG databases can be enabled / disabled for adding additional context based on the chat request. { rags.map((rag, index) => } onChange={() => toggle("rag", index)} label={rag?.name} /> {rag?.description} ) } }> System Information The server is running on the following hardware:
); } export type { ControlsParams }; export { Controls };