diff --git a/app/backend/ProcessMemory.ts b/app/backend/ProcessMemory.ts new file mode 100644 index 0000000..d66d8e5 --- /dev/null +++ b/app/backend/ProcessMemory.ts @@ -0,0 +1,20 @@ +import { Settings } from 'electron' +import React from 'react' + +type Message = { + role: string + content: string +} + +type Chat = { + name: string + messages: Message[] +} + +type Data = { + chats: Chat[] + settings: Settings[] +} + + + diff --git a/app/backend/ProcessMemory.tsx b/app/backend/ProcessMemory.tsx deleted file mode 100644 index c402e15..0000000 --- a/app/backend/ProcessMemory.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react' - -type Chat = { - name:string - messages:string[] -} - -type History = { - chats:Chat[] -} - - - diff --git a/app/backend/database.ts b/app/backend/database.ts index 7b7437d..054302b 100644 --- a/app/backend/database.ts +++ b/app/backend/database.ts @@ -1,16 +1,96 @@ import axios from "axios"; -const sendToDatabase = (data: any) => { - axios.post("http://localhost:5000/interstellar_ai/db", data) - .then(response => { - const status = response.data.status - console.log(status); - postMessage({ status }) - console.log('message posted'); +/* +This is the guide on how to user this function: - }) - .catch(error => { - console.log("Error calling Database:", error) - postMessage({ status: 500 }) - }) -} \ No newline at end of file +data should be the json containing everything relevant, the json can contain the following keys: + +action -> contains the action you want to do, there are: create_account, change_password, get_data, change_data, check_credentials, delete_account +username -> contains the current username, required for create_account, but can be omitted in favor of email in other requests. Preffered over email authentication. +email -> contains the current email, required for create_account, but just like the username, it can be omitted, in favor of the other, sending both is possible too. +password -> contains the password, required for all requests. +new_password -> in the case you are changing your password, you will need to use this in addition to password, to specify the new password. +data -> data contains all the data you want to store, you have to always give the entire data, because the data you give here overwrites the data in the database, +so if you only give the chat history for example, all settings will be deleted, and if you only give settings, all chat histories will get deleted. + + +if all went well, you will get the status 200 in response.data.status +to check if the request was accepted or declined, check response.data.response, it will be either true or false depending on if it worked, or not. +*/ + +export const sendToDatabase = (data: any): Promise => { + return axios.post("http://localhost:5000/interstellar_ai/db", data) + .then(response => { + const status = response.data.status; + const success = response.data.response; + postMessage({ status, success }); + return success; // Ensure success is returned to the caller + }) + .catch(error => { + postMessage({ status: 500, success: false }); + return false; // Return false in case of an error + }); +}; + +// Functions for each action +export const createAccount = async (username: string, email: string, password: string) => { + const data = { + action: "create_account", + username, + email, + password, + }; + return await sendToDatabase(data); +}; + +export const changePassword = async (usernameOrEmail: string, password: string, newPassword: string) => { + const data = { + action: "change_password", + username: usernameOrEmail.includes('@') ? undefined : usernameOrEmail, + email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined, + password, + new_password: newPassword, + }; + return await sendToDatabase(data); +}; + +export const getData = async (usernameOrEmail: string, password: string) => { + const data = { + action: "get_data", + username: usernameOrEmail.includes('@') ? undefined : usernameOrEmail, + email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined, + password, + }; + return await sendToDatabase(data); +}; + +export const changeData = async (usernameOrEmail: string, password: string, newData: any) => { + const data = { + action: "change_data", + username: usernameOrEmail.includes('@') ? undefined : usernameOrEmail, + email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined, + password, + data: newData, + }; + return await sendToDatabase(data); +}; + +export const checkCredentials = async (usernameOrEmail: string, password: string) => { + const data = { + action: "check_credentials", + username: usernameOrEmail.includes('@') ? undefined : usernameOrEmail, + email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined, + password, + }; + return await sendToDatabase(data); +}; + +export const deleteAccount = async (usernameOrEmail: string, password: string) => { + const data = { + action: "delete_account", + username: usernameOrEmail.includes('@') ? undefined : usernameOrEmail, + email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined, + password, + }; + return await sendToDatabase(data); +}; diff --git a/app/components/Login.tsx b/app/components/Login.tsx index 665a7b3..c766f09 100644 --- a/app/components/Login.tsx +++ b/app/components/Login.tsx @@ -1,8 +1,11 @@ import React, { useState, useEffect } from 'react'; +import { + createAccount, + checkCredentials, +} from '../backend/database'; import Settings from './Settings'; // Import the Settings component const Login: React.FC = () => { - // State to handle popup visibility const [showLoginPopup, setShowLoginPopup] = useState(false); const [showSignUpPopup, setShowSignUpPopup] = useState(false); @@ -28,7 +31,11 @@ const Login: React.FC = () => { setAccountName(savedAccountName); setEmail(savedAccountEmail); setPassword(savedAccountPassword); - setIsLoggedIn(true); // Automatically log in + const check = async () => { + const success = await checkCredentials(savedAccountName, savedAccountPassword); + setIsLoggedIn(success); // Automatically log in + }; + check(); } }, []); @@ -42,33 +49,40 @@ const Login: React.FC = () => { }; // Function to handle login - const handleLogin = () => { + const handleLogin = async () => { const savedAccountEmail = localStorage.getItem('accountEmail'); const savedAccountPassword = localStorage.getItem('accountPassword'); const savedAccountName = localStorage.getItem('accountName'); - if ( - (email === savedAccountEmail || accountName === savedAccountName) && - password === savedAccountPassword - ) { - setIsLoggedIn(true); // Successful login - setShowLoginPopup(false); // Close the login popup - // Save credentials to localStorage (optional in case of changes) - localStorage.setItem('accountName', savedAccountName || accountName); - localStorage.setItem('accountEmail', savedAccountEmail || email); - localStorage.setItem('accountPassword', savedAccountPassword || password); + // Check if savedAccountName or savedAccountEmail is not null before passing to checkCredentials + const accountIdentifier = savedAccountName || savedAccountEmail; + + if (accountIdentifier && password === savedAccountPassword) { + const success = await checkCredentials(accountIdentifier, password); + if (success) { + setIsLoggedIn(true); // Successful login + setShowLoginPopup(false); // Close the login popup + // Save credentials to localStorage (optional in case of changes) + localStorage.setItem('accountName', savedAccountName || accountName); + localStorage.setItem('accountEmail', savedAccountEmail || email); + localStorage.setItem('accountPassword', savedAccountPassword || password); + } else { + alert('Incorrect credentials'); + } } else { alert('Incorrect credentials'); } }; // Function to handle account creation - const handleCreateAccount = () => { - localStorage.setItem('accountName', newAccountName); - localStorage.setItem('accountEmail', newAccountEmail); - localStorage.setItem('accountPassword', newAccountPassword); - alert('Account created successfully! You can now log in.'); - toggleSignUpPopup(); // Close sign-up popup + const handleCreateAccount = async () => { + const success = await createAccount(newAccountName, newAccountEmail, newAccountPassword); + if (success) { + alert('Account created successfully! You can now log in.'); + toggleSignUpPopup(); // Close sign-up popup + } else { + alert('Account creation failed. Please try again.'); + } }; // Function to toggle the settings popup diff --git a/app/components/Models.tsx b/app/components/Models.tsx index 894623a..1f9dc56 100644 --- a/app/components/Models.tsx +++ b/app/components/Models.tsx @@ -1,7 +1,143 @@ "use client"; import React, { useState, useEffect } from 'react'; -// Define the available model options +// Define all models that should be available. +const modelList = { + 'Offline Fast': { + 'model_type': 'local', + 'Math': 'qwen2-math:1.5b', + 'Code': 'starcoder2', + 'Language': 'llama3.2', + 'Character': 'dolphin-phi', + 'Finance': 'qwen2-math:1.5b', + 'Weather': 'llama3.2', + 'Time': 'llama3.2', + 'Image': 'llava-phi3' + }, + 'Offline Slow': { + 'model_type': 'local', + 'Math': 'wizard-math', + 'Code': 'starcoder2:7b', + 'Language': 'llama3.1', + 'Character': 'dolphin-llama3', + 'Finance': 'wizard-math', + 'Weather': 'llama3.1', + 'Time': 'llama3.1', + 'Image': 'llava' + }, + 'Offline Fast (FOSS)': { + 'model_type': 'local', + 'Math': 'qwen2-math:1.5b', + 'Code': 'qwen2.5-coder:1.5b', + 'Language': 'phi3.5', + 'Character': 'dolphin-mistral', + 'Finance': 'qwen2-math:1.5b', + 'Weather': 'phi3.5', + 'Time': 'phi3.5', + 'Image': 'llava' + }, + 'Offline Slow (FOSS)': { + 'model_type': 'local', + 'Math': 'mathstral', + 'Code': 'qwen2.5-coder', + 'Language': 'qwen2.5', + 'Character': 'dolphin-mistral', + 'Finance': 'mathstral', + 'Weather': 'qwen2.5', + 'Time': 'qwen2.5', + 'Image': 'llava' + }, + 'Online Cheap (OpenAI)': { + 'model_type': 'openai', + 'Math': 'gpt-4o-mini', + 'Code': 'gpt-4o-mini', + 'Language': 'gpt-4o-mini', + 'Character': 'gpt-4o-mini', + 'Finance': 'gpt-4o-mini', + 'Weather': 'gpt-4o-mini', + 'Time': 'gpt-4o-mini', + 'Image': 'gpt-4o-mini' + }, + 'Online Expensive (OpenAI)': { + 'model_type': 'openai', + 'Math': 'gpt-4o', + 'Code': 'gpt-4o', + 'Language': 'gpt-4o', + 'Character': 'gpt-4o', + 'Finance': 'gpt-4o', + 'Weather': 'gpt-4o', + 'Time': 'gpt-4o', + 'Image': 'gpt-4o' + }, + 'Online Cheap (Anthropic)': { + 'model_type': 'anthropic', + 'Math': 'claude-3-haiku', + 'Code': 'claude-3-haiku', + 'Language': 'claude-3-haiku', + 'Character': 'claude-3-haiku', + 'Finance': 'claude-3-haiku', + 'Weather': 'claude-3-haiku', + 'Time': 'claude-3-haiku', + 'Image': 'claude-3-haiku' + }, + 'Online Expensive (Anthropic)': { + 'model_type': 'anthropic', + 'Math': 'claude-3-5-sonnet', + 'Code': 'claude-3-5-sonnet', + 'Language': 'claude-3-5-sonnet', + 'Character': 'claude-3-5-sonnet', + 'Finance': 'claude-3-5-sonnet', + 'Weather': 'claude-3-5-sonnet', + 'Time': 'claude-3-5-sonnet', + 'Image': 'claude-3-5-sonnet' + }, + 'Online Cheap (Google)': { + 'model_type': 'google', + 'Math': 'gemini-1.5-flash-latest', + 'Code': 'gemini-1.5-flash-latest', + 'Language': 'gemini-1.5-flash-latest', + 'Character': 'gemini-1.5-flash-latest', + 'Finance': 'gemini-1.5-flash-latest', + 'Weather': 'gemini-1.5-flash-latest', + 'Time': 'gemini-1.5-flash-latest', + 'Image': 'gemini-1.5-flash-latest' + }, + 'Online Expensive (Google)': { + 'model_type': 'google', + 'Math': 'gemini-1.5-pro-latest', + 'Code': 'gemini-1.5-pro-latest', + 'Language': 'gemini-1.5-pro-latest', + 'Character': 'gemini-1.5-pro-latest', + 'Finance': 'gemini-1.5-pro-latest', + 'Weather': 'gemini-1.5-pro-latest', + 'Time': 'gemini-1.5-pro-latest', + 'Image': 'gemini-1.5-pro-latest' + }, + 'Online (La Plateforme)': { + 'model_type': 'mistral', + 'Math': 'open-mistral-nemo', + 'Code': 'codestral-latest', + 'Language': 'mistral-small-latest', + 'Character': 'mistral-large-latest', + 'Finance': 'open-mistral-nemo', + 'Weather': 'mistral-small-latest', + 'Time': 'mistral-small-latest', + 'Image': 'pixtral-12b-2409' + }, + 'Online (FOSS) (La Plateforme)': { + 'model_type': 'mistral', + 'Math': 'open-mistral-nemo', + 'Code': 'open-codestral-mamba', + 'Language': 'open-mistral-nemo', + 'Character': 'open-mixtral-8x22b', + 'Finance': 'open-mixtral-8x22b', + 'Weather': 'open-mistral-nemo', + 'Time': 'open-mistral-nemo', + 'Image': 'pixtral-12b-2409' + } +} + +// Define the available category options const modelDropdown = { offlineWithoutFoss: ['Offline Fast', 'Offline Slow'], offlineFoss: ['Offline Fast (FOSS)', 'Offline Slow (FOSS)'], @@ -12,6 +148,7 @@ const modelDropdown = { 'Online Expensive (Anthropic)', 'Online Cheap (Google)', 'Online Expensive (Google)', + 'Online (La Plateforme)' ], onlineFoss: ['Online (FOSS) (La Plateforme)'], }; @@ -20,7 +157,7 @@ const Models: React.FC = () => { // Initialize state with value from localStorage or default to '' const [selectedModel, setSelectedModel] = useState(''); const [radioSelection, setRadioSelection] = useState("") - + useEffect(() => { setRadioSelection(localStorage.getItem('radioSelection')) const handleStorageChange = () => { @@ -98,6 +235,13 @@ const Models: React.FC = () => { const isOfflineModel = (model: string) => modelDropdown.offlineWithoutFoss.includes(model) || modelDropdown.offlineFoss.includes(model); + const modelClicked = (model: string) => { + const category = selectedModel as keyof typeof modelList; + console.log(model) + console.log(category) + console.log(modelList[category][model as keyof typeof modelList[typeof category]]); + } + return (
@@ -122,7 +266,7 @@ const Models: React.FC = () => {
{['Code', 'Math', 'Language', 'Character', 'Finance', 'Weather', 'Time', 'Image', 'Custom1', 'Custom2'].map( (category) => ( - +
+
+
@@ -881,16 +938,16 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = ( setLaPlateforme(e.target.value)} + value={mistral} + onChange={(e) => setmistral(e.target.value)} />
setOpenAI(e.target.value)} + value={openai} + onChange={(e) => setopenai(e.target.value)} />
@@ -973,8 +1030,8 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = ( openSourceMode, // API Keys - laPlateforme, - openAI, + mistral, + openai, anthropic, google }; diff --git a/py/ai.py b/py/ai.py index 5879e9d..2554fd5 100644 --- a/py/ai.py +++ b/py/ai.py @@ -80,11 +80,6 @@ class AI: message = messages[-1]['content'] messages.pop() - system = None - if messages and messages[0]['role'] == 'system': - system = messages[0]['content'] - messages.pop(0) - for msg in messages: msg['parts'] = msg.pop('content') @@ -97,8 +92,8 @@ class AI: model = genai.GenerativeModel(model) chat = model.start_chat( - system_instruction=system, - history=messages + history=messages, + ) response = chat.send_message(message, stream=True) diff --git a/py/api.py b/py/api.py index 18af5e4..75fbfd4 100644 --- a/py/api.py +++ b/py/api.py @@ -70,6 +70,13 @@ class API: thread.start() thread.join() return jsonify({'status': 200}) + elif model_type == "google": + api_key = data.get('api_key') + thread = threading.Thread(target=self.ai.process_google, + args=(ai_model, messages, self, access_token, api_key)) + thread.start() + thread.join() + return jsonify({'status': 200}) return jsonify({'status': 401, 'error': 'Invalid AI model type'}) @@ -94,6 +101,8 @@ class API: return jsonify({'status': 200, 'response': self.db.change_data(data)}) elif action == "check_credentials": return jsonify({'status': 200, 'response': self.db.check_credentials(data)}) + elif action == "delete_account": + return jsonify({'status': 200, 'response': self.db.delete_user(data)}) return jsonify({'status': 401, 'response': "Invalid action"}) diff --git a/py/voice.py b/py/voice.py index dc0d28b..24d12ac 100644 --- a/py/voice.py +++ b/py/voice.py @@ -1,5 +1,4 @@ import io -import numpy as np from faster_whisper import WhisperModel from pydub import AudioSegment @@ -19,7 +18,7 @@ class VoiceRecognition: print("audio to wav failed") model_size = "base" - model = WhisperModel(model_size, device="cpu", compute_type="int8") + model = WhisperModel(model_size, device="cpu", compute_type=" ") segments, _ = model.transcribe(wav_io) transcription = ""