Spaces:
Paused
Paused
| import React, { useState, useRef } from 'react'; | |
| import { useNavigate } from 'react-router-dom'; | |
| import Box from '@mui/material/Box'; | |
| import Slider from '@mui/material/Slider'; | |
| import Stack from '@mui/material/Stack'; | |
| import Button from '@mui/material/Button'; | |
| import IconButton from '@mui/material/IconButton'; | |
| import './IntialSetting.css'; | |
| import { FaTimes, FaEye, FaEyeSlash } from 'react-icons/fa'; | |
| function IntialSetting(props) { | |
| // State variables for form controls | |
| const [selectedProvider, setSelectedProvider] = useState("OpenAI"); | |
| const [modelTemperature, setModelTemperature] = useState(0.0); | |
| const [modelTopP, setModelTopP] = useState(1.0); | |
| const [showPassword, setShowPassword] = useState(false); | |
| // Ref for the form and navigation hook | |
| const formRef = useRef(null); | |
| const navigate = useNavigate(); | |
| // Model options for different providers | |
| const modelOptions = { | |
| OpenAI: { | |
| "GPT 4o": "gpt-4o", | |
| "GPT 4o Latest": "gpt-4o-2024-11-20", | |
| "GPT 4o Mini": "gpt-4o-mini", | |
| "GPT 4.1": "gpt-4.1", | |
| "GPT 4.1 Mini": "gpt-4.1-mini", | |
| "GPT 4.1 Nano": "gpt-4.1-nano", | |
| "ChatGPT": "chatgpt-4o-latest" | |
| }, | |
| Anthropic: { | |
| "Claude 4 Opus": "claude-opus-4-20250514", | |
| "Claude Sonnet 4": "claude-sonnet-4-20250514", | |
| "Claude Sonnet 3.7": "claude-3-7-sonnet-20250219", | |
| "Claude Sonnet 3.5": "claude-3-5-sonnet-20241022", | |
| "Claude Haiku 3.5": "claude-3-5-haiku-20241022", | |
| "Claude Opus 3": "claude-3-opus-20240229", | |
| "Claude Sonnet 3": "claude-3-sonnet-20240229", | |
| "Claude Haiku 3": "claude-3-haiku-20240307" | |
| }, | |
| Google: { | |
| "Gemini 2.0 Flash Lite": "gemini-2.0-flash-lite", | |
| "Gemini 2.0 Flash": "gemini-2.0-flash", | |
| "Gemini 2.5 Flash Lite": "gemini-2.5-flash-lite-preview-06-17", | |
| "Gemini 2.5 Flash": "gemini-2.5-flash-preview-04-17", | |
| "Gemini 2.5 Pro": "gemini-2.5-pro" | |
| }, | |
| XAI: { | |
| "Grok 2": "grok-2", | |
| "Grok 3 Mini": "grok-3-mini-latest", | |
| "Grok 3 Mini (Fast)": "grok-3-mini-fast-latest", | |
| "Grok 3": "grok-3-latest", | |
| "Grok 3 (Fast)": "grok-3-fast-latest" | |
| }, | |
| }; | |
| // Reset form and state variables | |
| const handleReset = (e) => { | |
| e.preventDefault(); | |
| if (formRef.current) { | |
| formRef.current.reset(); | |
| } | |
| setSelectedProvider("OpenAI"); | |
| setModelTemperature(0.0); | |
| setModelTopP(1.0); | |
| }; | |
| // Handle form submission and save settings | |
| const handleSave = async (e) => { | |
| e.preventDefault(); | |
| const form = formRef.current; | |
| // Retrieve form values | |
| const modelProvider = form.elements["model-provider"].value; | |
| const modelName = form.elements["model-name"].value; | |
| const modelAPIKeys = form.elements["model-api"].value; | |
| const braveAPIKey = form.elements["brave-api"].value; | |
| const proxyList = form.elements["proxy-list"].value; | |
| // Check for missing required fields | |
| const missingFields = []; | |
| if (!modelProvider || modelProvider.trim() === "") missingFields.push("Model Provider"); | |
| if (!modelName || modelName.trim() === "") missingFields.push("Model Name"); | |
| if (!modelAPIKeys || modelAPIKeys.trim() === "") missingFields.push("Model API Key"); | |
| if (!braveAPIKey || braveAPIKey.trim() === "") missingFields.push("Brave Search API Key"); | |
| if (missingFields.length > 0) { | |
| props.openSnackbar( | |
| "Please fill in the following required fields: " + missingFields.join(", "), | |
| "error" | |
| ); | |
| return; | |
| } | |
| // Build payload for backend | |
| const payload = { | |
| "Model_Provider": modelProvider.toLowerCase(), | |
| "Model_Name": modelName, | |
| "Model_API_Keys": modelAPIKeys, | |
| "Brave_Search_API_Key": braveAPIKey, | |
| "Model_Temperature": modelTemperature, | |
| "Model_Top_P": modelTopP, | |
| }; | |
| if (proxyList && proxyList.trim() !== "") { | |
| payload["Proxy_List"] = proxyList; | |
| } | |
| // Show appropriate notification based on context | |
| if (props.fromAiPage) { | |
| props.openSnackbar( | |
| <Box mt={1} display="flex" alignItems="center"> | |
| <Box className="re-applying-settings-custom-spinner" /> | |
| <Box ml={1} className="re-applying-settings-text"> | |
| <span>Re-applying settings. This may take a few minutes...</span> | |
| </Box> | |
| </Box>, | |
| "info" | |
| ); | |
| } else { | |
| props.openSnackbar("Settings saved successfully!", "success"); | |
| if (props.onInitializationStart) { | |
| props.onInitializationStart(); | |
| } | |
| } | |
| // Send settings to backend | |
| try { | |
| const response = await fetch("/settings", { | |
| method: "POST", | |
| headers: { | |
| "Content-Type": "application/json", | |
| }, | |
| body: JSON.stringify(payload), | |
| }); | |
| if (response.ok) { | |
| const data = await response.json(); | |
| if (data.success === true) { | |
| if (props.fromAiPage) { | |
| props.openSnackbar("Settings saved successfully!", "success"); | |
| } | |
| navigate("/AiPage"); | |
| } else { | |
| props.openSnackbar("Error saving settings. Please try again.", "error"); | |
| } | |
| } else { | |
| props.openSnackbar("Error saving settings. Please try again.", "error"); | |
| } | |
| } catch (error) { | |
| console.error("Error saving settings:", error); | |
| props.openSnackbar("Error saving settings. Please try again.", "error"); | |
| } | |
| }; | |
| // Render the settings modal | |
| return props.trigger ? ( | |
| <div className="showSetting" onClick={() => props.setTrigger(false)}> | |
| <div className="showSetting-inner" onClick={(e) => e.stopPropagation()}> | |
| <label className="setting-size">Settings</label> | |
| <button className="close-btn" onClick={() => props.setTrigger(false)}> | |
| <FaTimes /> | |
| </button> | |
| <form ref={formRef}> | |
| <div className="form-group"> | |
| <label htmlFor="model-provider">Model Provider</label> | |
| <select | |
| id="model-provider" | |
| name="model-provider" | |
| value={selectedProvider} | |
| onChange={(e) => setSelectedProvider(e.target.value)} | |
| > | |
| {Object.keys(modelOptions).map(provider => ( | |
| <option key={provider} value={provider}> | |
| {provider} | |
| </option> | |
| ))} | |
| </select> | |
| </div> | |
| <div className="form-group"> | |
| <label htmlFor="model-name">Model Name</label> | |
| <select id="model-name" name="model-name"> | |
| {Object.entries(modelOptions[selectedProvider]).map( | |
| ([displayName, backendName]) => ( | |
| <option key={backendName} value={backendName}> | |
| {displayName} | |
| </option> | |
| ) | |
| )} | |
| </select> | |
| </div> | |
| <div className="form-group"> | |
| <label htmlFor="model-api">Model API Key</label> | |
| <textarea | |
| id="model-api" | |
| name="model-api" | |
| placeholder="Enter API Key, one per line" | |
| ></textarea> | |
| </div> | |
| <div className="form-group"> | |
| <label htmlFor="brave-api">Brave Search API Key</label> | |
| <input | |
| type="text" | |
| id="brave-api" | |
| name="brave-api" | |
| placeholder="Enter API Key" | |
| /> | |
| </div> | |
| <div className="form-group"> | |
| <label htmlFor="proxy-list">Proxy List</label> | |
| <textarea | |
| id="proxy-list" | |
| name="proxy-list" | |
| placeholder="Enter proxies, one per line" | |
| ></textarea> | |
| </div> | |
| {/* Commented Neo4j configuration fields */} | |
| {/* <div className="form-group"> | |
| <label htmlFor="neo4j-url">Neo4j URL</label> | |
| <input | |
| type="text" | |
| id="neo4j-url" | |
| name="neo4j-url" | |
| placeholder="Enter Neo4j URL" | |
| /> | |
| </div> | |
| <div className="form-group"> | |
| <label htmlFor="neo4j-username">Neo4j Username</label> | |
| <input | |
| type="text" | |
| id="neo4j-username" | |
| name="neo4j-username" | |
| placeholder="Enter Username" | |
| /> | |
| </div> | |
| <div className="form-group"> | |
| <label htmlFor="neo4j-password">Neo4j Password</label> | |
| <div className="password-wrapper"> | |
| <input | |
| type={showPassword ? "text" : "password"} | |
| id="neo4j-password" | |
| name="neo4j-password" | |
| placeholder="Enter Password" | |
| /> | |
| <IconButton | |
| onClick={() => setShowPassword(prev => !prev)} | |
| className="password-toggle" | |
| sx={{ | |
| color: "white", | |
| p: 0, | |
| m: 0 | |
| }} | |
| > | |
| {showPassword ? <FaEyeSlash /> : <FaEye />} | |
| </IconButton> | |
| </div> | |
| </div> */} | |
| <div className="form-group"> | |
| <div className="sliders-container"> | |
| <div className="slider-item"> | |
| <label htmlFor="temperature">Temperature</label> | |
| <Slider | |
| id="temperature" | |
| value={modelTemperature} | |
| onChange={(e, newValue) => setModelTemperature(newValue)} | |
| step={0.05} | |
| min={0.0} | |
| max={1.0} | |
| valueLabelDisplay="auto" | |
| sx={{ width: '100%', color: 'success.main' }} | |
| /> | |
| </div> | |
| <div className="slider-item"> | |
| <label htmlFor="top-p">Top-P</label> | |
| <Slider | |
| id="top-p" | |
| value={modelTopP} | |
| onChange={(e, newValue) => setModelTopP(newValue)} | |
| step={0.05} | |
| min={0.0} | |
| max={1.0} | |
| valueLabelDisplay="auto" | |
| sx={{ width: '100%', color: 'success.main' }} | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| <Stack direction="row" spacing={2} sx={{ justifyContent: 'flex-end' }}> | |
| <Button | |
| type="button" | |
| className="reset-btn" | |
| sx={{ color: "#2196f3" }} | |
| onClick={handleReset} | |
| > | |
| Reset | |
| </Button> | |
| <Button | |
| type="button" | |
| variant="contained" | |
| color="success" | |
| className="save-btn" | |
| onClick={handleSave} | |
| > | |
| Save | |
| </Button> | |
| </Stack> | |
| </form> | |
| {props.children} | |
| </div> | |
| </div> | |
| ) : null; | |
| } | |
| export default IntialSetting; |