forked from React-Group/interstellar_ai
		
	Compare commits
	
		
			No commits in common. "1e4dda33ad94a44ba998bd0a6c22195011ae5713" and "a1c0bf1294ad02a90b80086317f3872e4c9d3147" have entirely different histories.
		
	
	
		
			1e4dda33ad
			...
			a1c0bf1294
		
	
		
					 5 changed files with 185 additions and 79 deletions
				
			
		|  | @ -1,21 +1,8 @@ | ||||||
| "use client"; | "use client"; | ||||||
| import React, { useState, useEffect } from 'react'; | import React, { useState, useEffect } from 'react'; | ||||||
| 
 | 
 | ||||||
| // Define the types for ModelType and ModelListType
 | // Define all models that should be available.
 | ||||||
| type ModelType = { | const modelList = { | ||||||
|   model_type: string; |  | ||||||
|   Math: string; |  | ||||||
|   Code: string; |  | ||||||
|   Language: string; |  | ||||||
|   Weather: string; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| type ModelListType = { |  | ||||||
|   [key: string]: ModelType; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| // Define the AI models list
 |  | ||||||
| const modelList: ModelListType = { |  | ||||||
|   'Offline Fast': { |   'Offline Fast': { | ||||||
|     model_type: 'local', |     model_type: 'local', | ||||||
|     Math: 'qwen2-math:1.5b', |     Math: 'qwen2-math:1.5b', | ||||||
|  | @ -99,47 +86,161 @@ const modelList: ModelListType = { | ||||||
|     Code: 'open-codestral-mamba', |     Code: 'open-codestral-mamba', | ||||||
|     Language: 'open-mistral-nemo', |     Language: 'open-mistral-nemo', | ||||||
|     Weather: 'open-mistral-nemo', |     Weather: 'open-mistral-nemo', | ||||||
|   }, |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Define the available selectedAIFunction options
 | ||||||
|  | const modelDropdown = { | ||||||
|  |   offlineNonFoss: ['Offline Fast', 'Offline Slow'], | ||||||
|  |   offlineFoss: ['Offline Fast (FOSS)', 'Offline Slow (FOSS)'], | ||||||
|  |   onlineNonFoss: [ | ||||||
|  |     'Online Cheap (OpenAI)', | ||||||
|  |     'Online Expensive (OpenAI)', | ||||||
|  |     'Online Cheap (Anthropic)', | ||||||
|  |     'Online Expensive (Anthropic)', | ||||||
|  |     'Online Cheap (Google)', | ||||||
|  |     'Online Expensive (Google)', | ||||||
|  |     'Online (La Plateforme)' | ||||||
|  |   ], | ||||||
|  |   onlineFoss: ['Online (FOSS) (La Plateforme)'], | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // AI Functions list
 | const selectedAIFunction = [ | ||||||
| const aiFunctions = ['Math', 'Code', 'Language', 'Weather'] as const; |   'Code', | ||||||
| type AIFunction = typeof aiFunctions[number]; // Restrict to these exact function names
 |   'Math', | ||||||
|  |   'Language', | ||||||
|  |   'Weather' | ||||||
|  | ] | ||||||
| 
 | 
 | ||||||
| const ModelSection: React.FC = () => { | const ModelSection: React.FC = () => { | ||||||
|   const [selectedModelDropdown, setSelectedModelDropdown] = useState(() => "Offline Fast"); |   // Initialize state with value from localStorage or default to ''
 | ||||||
|   const [activeSelectedAIFunction, setActiveSelectedAIFunction] = useState(() => "Code"); |   const [selectedModelDropdown, setSelectedModelDropdown] = useState(''); | ||||||
|   const [, setSelectedModel] = useState<string>(""); |   const [radioSelection, setRadioSelection] = useState<string | null>("") | ||||||
|   const [, setSelectedModelType] = useState<string>(""); |   const [activeSelectedAIFunction, setActiveSelectedAIFunction] = useState(''); | ||||||
|  |   const [currentSelectedAIFunction, setCurrentSelectedAIFunction] = useState<string | null>(""); | ||||||
|  |   const [isOpenSourceMode, setIsOpenSourceMode] = useState<string|null>("false") | ||||||
| 
 | 
 | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     setSelectedModelDropdown(localStorage.getItem("selectedModelDropdown")|| "Offline Fast"); |     if (typeof localStorage !== 'undefined') { | ||||||
|     setActiveSelectedAIFunction(localStorage.getItem("activeSelectedAIFunction") || "Code"); |       const defaultValues = { | ||||||
|  |         selectedModelDropdown: 'Offline Fast', | ||||||
|  |         activeSelectedAIFunction: 'Code', | ||||||
|  |         model: 'starcoder2', | ||||||
|  |         radioSelection: 'None', | ||||||
|  |         type: 'local', | ||||||
|  |       }; | ||||||
|  |    | ||||||
|  |       Object.entries(defaultValues).forEach(([key, value]) => { | ||||||
|  |         if (!localStorage.getItem(key)) { | ||||||
|  |           localStorage.setItem(key, value); | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |    | ||||||
|  |       setIsOpenSourceMode(localStorage.getItem("openSourceMode")); | ||||||
|  |       setActiveSelectedAIFunction(localStorage.getItem("activeSelectedAIFunction") || ''); | ||||||
|  |       setRadioSelection(localStorage.getItem("radioSelection") || ''); | ||||||
|  |       setSelectedModelDropdown(localStorage.getItem('selectedModelDropdown') || ''); | ||||||
|  |    | ||||||
|  |       const handleStorageChange = () => { | ||||||
|  |         setSelectedModelDropdown(localStorage.getItem('selectedModelDropdown') || ''); | ||||||
|  |       }; | ||||||
|  |    | ||||||
|  |       // Update immediately when localStorage changes
 | ||||||
|  |       window.addEventListener('storage', handleStorageChange); | ||||||
|  |        | ||||||
|  |       // Cleanup listener on component unmount
 | ||||||
|  |       return () => { | ||||||
|  |         window.removeEventListener('storage', handleStorageChange); | ||||||
|  |       }; | ||||||
|  |     } | ||||||
|   }, []); |   }, []); | ||||||
|    |    | ||||||
|   // Update the model and type when the dropdown or function changes
 | 
 | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     const aiFunctionsActiveSelectedAIFunction = activeSelectedAIFunction as AIFunction |     if (typeof localStorage !== 'undefined') { | ||||||
|     const newSelectedModel = modelList[selectedModelDropdown]?.[aiFunctionsActiveSelectedAIFunction] || ""; |       const storedActiveSelectedAIFunction = localStorage.getItem("activeSelectedAIFunction") || ""; | ||||||
|     const newModelType = modelList[selectedModelDropdown]?.model_type || ""; |       if (storedActiveSelectedAIFunction !== currentSelectedAIFunction) { | ||||||
| 
 |         setCurrentSelectedAIFunction(storedActiveSelectedAIFunction); | ||||||
|     setSelectedModel(newSelectedModel); |       } | ||||||
|     setSelectedModelType(newModelType); |     } | ||||||
| 
 |   }, [activeSelectedAIFunction]); | ||||||
|     localStorage.setItem("model", newSelectedModel); |  | ||||||
|     localStorage.setItem("type", newModelType); |  | ||||||
|   }, [selectedModelDropdown, activeSelectedAIFunction]); |  | ||||||
| 
 | 
 | ||||||
|   const handleModelChange = (event: React.ChangeEvent<HTMLSelectElement>) => { |   const handleModelChange = (event: React.ChangeEvent<HTMLSelectElement>) => { | ||||||
|     const newModel = event.target.value; |     const newModel = event.target.value; | ||||||
|     setSelectedModelDropdown(newModel); |     setSelectedModelDropdown(newModel); | ||||||
|     localStorage.setItem('selectedModelDropdown', newModel); |     if (typeof localStorage !== 'undefined') { | ||||||
|  |       localStorage.setItem('selectedModelDropdown', newModel); // Update localStorage directly
 | ||||||
|  |       const model = localStorage.getItem('activeSelectedAIFunction') || "Code" | ||||||
|  |       modelClicked(model) | ||||||
|  |     } | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   const modelClicked = (functionName: AIFunction) => { |   // Determine the filtered models based on current radioSelection
 | ||||||
|     setActiveSelectedAIFunction(functionName); |   const filteredModels = (() => { | ||||||
|     localStorage.setItem('activeSelectedAIFunction', functionName); |     let models = []; | ||||||
|   }; |     switch (radioSelection) { | ||||||
|  |       case 'Offline': | ||||||
|  |         models = [ | ||||||
|  |           ...modelDropdown.onlineNonFoss, | ||||||
|  |           ...modelDropdown.onlineFoss, | ||||||
|  |         ]; | ||||||
|  |         if (isOpenSourceMode == "true") { | ||||||
|  |           models = [ | ||||||
|  |             ...modelDropdown.onlineFoss, | ||||||
|  |           ]; | ||||||
|  |         } // Show only offline models without FOSS
 | ||||||
|  |         break; | ||||||
|  |       case 'Online': | ||||||
|  |         models = [ | ||||||
|  |           ...modelDropdown.offlineNonFoss, | ||||||
|  |           ...modelDropdown.offlineFoss, | ||||||
|  |         ]; | ||||||
|  |         if (isOpenSourceMode == "true") { | ||||||
|  |           models = [ | ||||||
|  |             ...modelDropdown.offlineFoss, | ||||||
|  |           ]; | ||||||
|  |         } // Show only online models without FOSS
 | ||||||
|  |         break; | ||||||
|  |       case 'None': | ||||||
|  |         models = [ | ||||||
|  |           ...modelDropdown.offlineNonFoss, | ||||||
|  |           ...modelDropdown.offlineFoss, | ||||||
|  |           ...modelDropdown.onlineNonFoss, | ||||||
|  |           ...modelDropdown.onlineFoss, | ||||||
|  |         ]; | ||||||
|  |         if (isOpenSourceMode == "true") { | ||||||
|  |           models = [ | ||||||
|  |             ...modelDropdown.offlineFoss, | ||||||
|  |             ...modelDropdown.onlineFoss, | ||||||
|  |           ]; | ||||||
|  |         } // Show all models if nothing matches
 | ||||||
|  |         break; | ||||||
|  |       default: | ||||||
|  |         models = [ | ||||||
|  |           ...modelDropdown.offlineNonFoss, | ||||||
|  |           ...modelDropdown.offlineFoss, | ||||||
|  |           ...modelDropdown.onlineNonFoss, | ||||||
|  |           ...modelDropdown.onlineFoss, | ||||||
|  |         ]; // Show all models if nothing matches
 | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     return Array.from(new Set(models)); // Remove duplicates using Set
 | ||||||
|  |   })(); | ||||||
|  | 
 | ||||||
|  |   const isOfflineModel = (model: string) => | ||||||
|  |     modelDropdown.offlineNonFoss.includes(model) || modelDropdown.offlineFoss.includes(model); | ||||||
|  | 
 | ||||||
|  |   const modelClicked = (model: string) => { | ||||||
|  |     if (typeof localStorage !== 'undefined') { | ||||||
|  |       localStorage.setItem('activeSelectedAIFunction', model) | ||||||
|  |       setActiveSelectedAIFunction(model) | ||||||
|  |       const modelDropdown = localStorage.getItem('selectedModelDropdown') || 'Offline Fast' | ||||||
|  |       const selectedAIFunction = modelDropdown as keyof typeof modelList; | ||||||
|  |       localStorage.setItem("model", modelList[selectedAIFunction][model as keyof typeof modelList[typeof selectedAIFunction]]) | ||||||
|  |       localStorage.setItem("type", modelList[selectedAIFunction]['model_type' as keyof typeof modelList[typeof selectedAIFunction]]) | ||||||
|  |     } | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     <div className="model-background"> |     <div className="model-background"> | ||||||
|  | @ -148,29 +249,33 @@ const ModelSection: React.FC = () => { | ||||||
|           <h3>Different AI Models</h3> |           <h3>Different AI Models</h3> | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|  |         {/* Model Selection Dropdown */} | ||||||
|         <div className="model-dropdown"> |         <div className="model-dropdown"> | ||||||
|           <label htmlFor="model-select">Select AI Model:</label> |           <label htmlFor="model-select">Select AI Model:</label> | ||||||
|           <select id="model-select" value={selectedModelDropdown} onChange={handleModelChange}> |           <select id="model-select" value={selectedModelDropdown} onChange={handleModelChange}> | ||||||
|             {Object.keys(modelList).map((model) => ( |             {filteredModels.map((model) => ( | ||||||
|               <option key={model} value={model}> |               <option key={model} value={model}> | ||||||
|                 {model} |                 {model} | ||||||
|               </option> |               </option> | ||||||
|             ))} |             ))} | ||||||
|           </select> |           </select> | ||||||
|         </div> |         </div> | ||||||
| 
 |         {/* Model Grid with Cards */} | ||||||
|         <div className="grid"> |         <div className="grid"> | ||||||
|           {aiFunctions.map((functionName) => ( |           {selectedAIFunction.map( | ||||||
|  |             (displayedCategory) => ( | ||||||
|               <button |               <button | ||||||
|               key={functionName} |                 key={displayedCategory} | ||||||
|               className={`${functionName.toLowerCase()}-model model-box ${activeSelectedAIFunction === functionName ? 'selected' : ''}`} |                 className={`${displayedCategory.toLowerCase()}-model model-box ${currentSelectedAIFunction === displayedCategory ? 'selected' : ''}`} | ||||||
|               onClick={() => modelClicked(functionName)} |                 onClick={() => modelClicked(displayedCategory)} | ||||||
|               > |               > | ||||||
|                 <div className="overlay"> |                 <div className="overlay"> | ||||||
|                 <h3>{functionName}</h3> |                   <h3>{displayedCategory}</h3> | ||||||
|  |                   {isOfflineModel(selectedModelDropdown) && <img src="/img/nowifi.svg" alt="No Wi-Fi" />} | ||||||
|                 </div> |                 </div> | ||||||
|               </button> |               </button> | ||||||
|           ))} |             ) | ||||||
|  |           )} | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|  | @ -12,11 +12,9 @@ import PrivacySettings from './PrivacySettings'; | ||||||
| import FontSizeSetting from './FontSize'; | import FontSizeSetting from './FontSize'; | ||||||
| import OpenSourceModeToggle from './OpenSourceToggle'; | import OpenSourceModeToggle from './OpenSourceToggle'; | ||||||
| import { | import { | ||||||
|   changeHistory, |  | ||||||
|   changeSettings, |   changeSettings, | ||||||
|   createAccount, |   createAccount, | ||||||
|   deleteAccount, |   deleteAccount, | ||||||
|   getHistory, |  | ||||||
| } from '../../backend/database'; | } from '../../backend/database'; | ||||||
| import ThemeDropdown from './DropDownTheme'; | import ThemeDropdown from './DropDownTheme'; | ||||||
| 
 | 
 | ||||||
|  | @ -374,11 +372,7 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = ( | ||||||
|           localStorage.setItem("currentEmail", useEmail) |           localStorage.setItem("currentEmail", useEmail) | ||||||
|           alert('Account successfully changed!') |           alert('Account successfully changed!') | ||||||
|           window.location.reload() |           window.location.reload() | ||||||
|         } else { |  | ||||||
|           alert("failed to send settings") |  | ||||||
|         } |         } | ||||||
|       } else { |  | ||||||
|         alert("failed to create account") |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|  | @ -630,7 +624,6 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = ( | ||||||
|               onClick={handleLogout} // Function to call on click
 |               onClick={handleLogout} // Function to call on click
 | ||||||
|               className="update-credentials-button" // Custom styling class
 |               className="update-credentials-button" // Custom styling class
 | ||||||
|             /> |             /> | ||||||
|             <p>WARNING: Will delete your chat history.</p> |  | ||||||
|             <ButtonSetting |             <ButtonSetting | ||||||
|               label="Update Credentials" // Button label
 |               label="Update Credentials" // Button label
 | ||||||
|               onClick={handleUpdateCredentials} // Function to call on click
 |               onClick={handleUpdateCredentials} // Function to call on click
 | ||||||
|  |  | ||||||
|  | @ -49,8 +49,8 @@ | ||||||
|     border-radius: 5%; |     border-radius: 5%; | ||||||
|     overflow: hidden; |     overflow: hidden; | ||||||
|     position: relative; |     position: relative; | ||||||
|     height: 8vw; |     height: 18vh; | ||||||
|     width: 8vw; |     width: 18vh; | ||||||
|     margin: auto; /* Center each model box in the grid cell */ |     margin: auto; /* Center each model box in the grid cell */ | ||||||
| } | } | ||||||
| .model-box.selected { | .model-box.selected { | ||||||
|  |  | ||||||
|  | @ -57,8 +57,8 @@ | ||||||
|   } |   } | ||||||
|   /* Model box styles */ |   /* Model box styles */ | ||||||
|   .model-box { |   .model-box { | ||||||
|     width: 50vw; |     max-width: none; /* Remove max-width */ | ||||||
|     height: 50vw; |     margin: 0 auto; /* Center each model-box */ | ||||||
|   } |   } | ||||||
|   /* Input styles */ |   /* Input styles */ | ||||||
|   .input { |   .input { | ||||||
|  |  | ||||||
							
								
								
									
										28
									
								
								py/ai.py
									
										
									
									
									
								
							
							
						
						
									
										28
									
								
								py/ai.py
									
										
									
									
									
								
							|  | @ -20,29 +20,34 @@ class AI: | ||||||
| 
 | 
 | ||||||
|         for chunk in stream: |         for chunk in stream: | ||||||
|             with return_class.ai_response_lock: |             with return_class.ai_response_lock: | ||||||
|                 return_class.ai_response[access_token] += chunk["message"]["content"] |                 return_class.ai_response[access_token] += chunk['message']['content'] | ||||||
| 
 | 
 | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def process_mistralai(model, messages, return_class, access_token, api_key): |     def process_mistralai(model, messages, return_class, access_token, api_key): | ||||||
|  | 
 | ||||||
|         client = Mistral(api_key=api_key) |         client = Mistral(api_key=api_key) | ||||||
| 
 | 
 | ||||||
|         stream_response = client.chat.stream(model=model, messages=messages) |         stream_response = client.chat.stream( | ||||||
|  |             model=model, | ||||||
|  |             messages=messages | ||||||
|  |         ) | ||||||
| 
 | 
 | ||||||
|         with return_class.ai_response_lock: |         with return_class.ai_response_lock: | ||||||
|             return_class.ai_response[access_token] = "" |             return_class.ai_response[access_token] = "" | ||||||
| 
 | 
 | ||||||
|         for chunk in stream_response: |         for chunk in stream_response: | ||||||
|             with return_class.ai_response_lock: |             with return_class.ai_response_lock: | ||||||
|                 return_class.ai_response[access_token] += chunk.data.choices[ |                 return_class.ai_response[access_token] += chunk.data.choices[0].delta.content | ||||||
|                     0 |  | ||||||
|                 ].delta.content |  | ||||||
| 
 | 
 | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def process_openai(model, messages, return_class, access_token, api_key): |     def process_openai(model, messages, return_class, access_token, api_key): | ||||||
|  | 
 | ||||||
|         client = OpenAI(api_key=api_key) |         client = OpenAI(api_key=api_key) | ||||||
| 
 | 
 | ||||||
|         stream_response = client.chat.completions.create( |         stream_response = client.chat.completions.create( | ||||||
|             model=model, messages=messages, stream=True |             model=model, | ||||||
|  |             messages=messages, | ||||||
|  |             stream=True | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         with return_class.ai_response_lock: |         with return_class.ai_response_lock: | ||||||
|  | @ -54,6 +59,7 @@ class AI: | ||||||
| 
 | 
 | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def process_anthropic(model, messages, return_class, access_token, api_key): |     def process_anthropic(model, messages, return_class, access_token, api_key): | ||||||
|  | 
 | ||||||
|         client = anthropic.Anthropic(api_key=api_key) |         client = anthropic.Anthropic(api_key=api_key) | ||||||
| 
 | 
 | ||||||
|         with return_class.ai_response_lock: |         with return_class.ai_response_lock: | ||||||
|  | @ -70,15 +76,16 @@ class AI: | ||||||
| 
 | 
 | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def process_google(model, messages, return_class, access_token, api_key): |     def process_google(model, messages, return_class, access_token, api_key): | ||||||
|         message = messages[-1]["content"] | 
 | ||||||
|  |         message = messages[-1]['content'] | ||||||
|         messages.pop() |         messages.pop() | ||||||
| 
 | 
 | ||||||
|         for msg in messages: |         for msg in messages: | ||||||
|             msg["parts"] = msg.pop()["content"] |             msg['parts'] = msg.pop('content') | ||||||
| 
 | 
 | ||||||
|         for msg in messages: |         for msg in messages: | ||||||
|             if msg["role"] == "assistant": |             if msg['role'] == 'assistant': | ||||||
|                 msg["role"] = "model" |                 msg['role'] = 'model' | ||||||
| 
 | 
 | ||||||
|         genai.configure(api_key=api_key) |         genai.configure(api_key=api_key) | ||||||
| 
 | 
 | ||||||
|  | @ -86,6 +93,7 @@ class AI: | ||||||
| 
 | 
 | ||||||
|         chat = model.start_chat( |         chat = model.start_chat( | ||||||
|             history=messages, |             history=messages, | ||||||
|  | 
 | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         response = chat.send_message(message, stream=True) |         response = chat.send_message(message, stream=True) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue