Reviewed-on: https://interstellardevelopment.org/code/code/React-Group/interstellar_ai/pulls/137
Reviewed-by: Patrick <patrick_pluto@noreply.localhost>
Co-authored-by: sageTheDM <info@photofuel.tech>
Co-committed-by: sageTheDM <info@photofuel.tech>
This commit is contained in:
sageTheDM 2024-10-11 10:18:33 +02:00 committed by Patrick
parent f9bce3b22a
commit 91353bd051
34 changed files with 682 additions and 567 deletions

View file

@ -1,16 +1,19 @@
// getLocalStorageData.ts
// Function to retrieve all items from localStorage
export const getAllLocalStorageItems = (): Record<string, string | null> => {
const allData: Record<string, string | null> = {};
const allData: Record<string, string | null> = {}; // Object to hold key-value pairs from localStorage
// Check if localStorage is available
if (typeof localStorage !== 'undefined') {
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key) {
const value = localStorage.getItem(key);
allData[key] = value;
// Iterate through all localStorage keys
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i); // Get the key at the current index
if (key) {
const value = localStorage.getItem(key); // Retrieve the value associated with the key
allData[key] = value; // Store the key-value pair in the allData object
}
}
}
}
return allData;
};
return allData; // Return the object containing all localStorage items
};

View file

@ -9,7 +9,7 @@ import { getWeather } from "./weather";
import { changeHistory, getHistory } from "./database";
const InputOutputBackend: React.FC = () => {
// # variables
//#region variables
type Message = {
role: string
content: string
@ -37,7 +37,7 @@ const InputOutputBackend: React.FC = () => {
}
console.log(setSelectedIndex)
//#region useEffect
useEffect(() => {
setMessages(chatHistory.chats[chatHistory.selectedIndex].messages)
}, [chatHistory.selectedIndex])
@ -86,6 +86,7 @@ const InputOutputBackend: React.FC = () => {
}
}, [chatHistory])
//#region functions
const getWeatherHere = async () => {
setWeatherData(await getWeather({ "unit_type": preferredMeasurement, "city": localStorage.getItem("weatherInfo") || "New York" }))
console.log("Got the Data!")
@ -104,7 +105,7 @@ const InputOutputBackend: React.FC = () => {
}
setChatHistoryTriggered(true)
}
//#region system-prompt
useEffect(() => {
console.log("creating system prompt")
console.log(weatherData)
@ -133,7 +134,7 @@ const InputOutputBackend: React.FC = () => {
console.log(messages)
}, [systemMessage])
//#region more variables and functions
const conversationRef = useRef<HTMLDivElement>(null)
const [copyClicked, setCopyClicked] = useState(false)
const [accessToken, setAccessToken] = useState("")
@ -144,7 +145,7 @@ const InputOutputBackend: React.FC = () => {
const [isRecording, setIsRecording] = useState(false)
const mediaRecorderRef = useRef<MediaRecorder | null>(null)
const audioChunks = useRef<Blob[]>([])
//#region chat functions
useEffect(() => {
getNewToken()
@ -266,7 +267,7 @@ const InputOutputBackend: React.FC = () => {
}
}
}
//#region speech recognition
const startRecording = async (): Promise<string> => {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const mediaRecorder = new MediaRecorder(stream);
@ -309,7 +310,7 @@ const InputOutputBackend: React.FC = () => {
stopRecording();
}
};
//#region chat buttons
const handleStopClick = () => {
endGetWorker()
getNewToken()
@ -356,7 +357,7 @@ const InputOutputBackend: React.FC = () => {
setCopyClicked(false)
}
//#region The "html" return
return (
<>
<ConversationFrontend

View file

@ -1,55 +1,40 @@
import axios from "axios";
/*
This is the guide on how to user this function:
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.
*/
const apiURL = new URL("http://localhost:5000/interstellar_ai/db")
// Construct the base API URL based on the environment
const apiURL = new URL("http://localhost:5000/interstellar_ai/db");
if (typeof window !== 'undefined') {
apiURL.hostname = window.location.hostname;
apiURL.hostname = window.location.hostname; // Set hostname for browsers
} else {
apiURL.hostname = "localhost"
apiURL.hostname = "localhost"; // Default to localhost for non-browser environments
}
// Function to send data to the database and return a success status
export const sendToDatabase = async (data: object): Promise<boolean> => {
try {
const response = await axios.post(apiURL.href, data);
const status = response.data.status;
const success = response.data.response;
postMessage({ status, success });
return success;
postMessage({ status, success }); // Send status back to the main thread
return success; // Return success status
} catch (error) {
postMessage({ status: 500, success: false });
console.log(error)
return false;
postMessage({ status: 500, success: false }); // Handle errors
console.log(error);
return false; // Return false on error
}
};
// Function to send data and get a string response
export const sendToDatabaseAndGetString = async (data: object): Promise<string> => {
try {
const response = await axios.post(apiURL.href, data);
const status = response.data.status;
const success = response.data.response;
postMessage({ status, success });
return success;
return success; // Return response string
} catch (error) {
postMessage({ status: 500, success: false });
console.log(error)
return "false";
console.log(error);
return "false"; // Return "false" on error
}
};
@ -61,7 +46,7 @@ export const createAccount = async (username: string, email: string, password: s
email: email,
password: password,
};
return await sendToDatabase(data);
return await sendToDatabase(data); // Send account creation request
};
export const changePassword = async (usernameOrEmail: string, password: string, newPassword: string) => {
@ -72,7 +57,7 @@ export const changePassword = async (usernameOrEmail: string, password: string,
password,
new_password: newPassword,
};
return await sendToDatabase(data);
return await sendToDatabase(data); // Send password change request
};
export const getSettings = async (usernameOrEmail: string, password: string) => {
@ -82,7 +67,7 @@ export const getSettings = async (usernameOrEmail: string, password: string) =>
email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined,
password,
};
return await sendToDatabaseAndGetString(data);
return await sendToDatabaseAndGetString(data); // Get user settings
};
export const changeSettings = async (usernameOrEmail: string, password: string, newData: object) => {
@ -93,7 +78,7 @@ export const changeSettings = async (usernameOrEmail: string, password: string,
password,
data: newData,
};
return await sendToDatabase(data);
return await sendToDatabase(data); // Send settings change request
};
export const getHistory = async (usernameOrEmail: string, password: string) => {
@ -103,7 +88,7 @@ export const getHistory = async (usernameOrEmail: string, password: string) => {
email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined,
password,
};
return await sendToDatabaseAndGetString(data);
return await sendToDatabaseAndGetString(data); // Get user history
};
export const changeHistory = async (usernameOrEmail: string, password: string, newData: object) => {
@ -114,7 +99,7 @@ export const changeHistory = async (usernameOrEmail: string, password: string, n
password,
data: newData,
};
return await sendToDatabase(data);
return await sendToDatabase(data); // Send history change request
};
export const getEmail = async (usernameOrEmail: string, password: string): Promise<string> => {
@ -124,7 +109,7 @@ export const getEmail = async (usernameOrEmail: string, password: string): Promi
email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined,
password,
};
return await sendToDatabaseAndGetString(data);
return await sendToDatabaseAndGetString(data); // Get user email
};
export const getName = async (usernameOrEmail: string, password: string): Promise<string> => {
@ -134,10 +119,9 @@ export const getName = async (usernameOrEmail: string, password: string): Promis
email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined,
password,
};
return await sendToDatabaseAndGetString(data);
return await sendToDatabaseAndGetString(data); // Get user name
};
export const checkCredentials = async (usernameOrEmail: string, password: string) => {
const data = {
action: "check_credentials",
@ -145,15 +129,16 @@ export const checkCredentials = async (usernameOrEmail: string, password: string
email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined,
password,
};
const sendBack = await sendToDatabase(data);
const sendBack = await sendToDatabase(data); // Check user credentials
if (sendBack) {
if (typeof localStorage !== 'undefined') {
localStorage.setItem("accountEmail", await getEmail(usernameOrEmail, password))
localStorage.setItem("accountName", await getName(usernameOrEmail, password))
localStorage.setItem("accountPassword", password)
// Store user data in localStorage if credentials are valid
localStorage.setItem("accountEmail", await getEmail(usernameOrEmail, password));
localStorage.setItem("accountName", await getName(usernameOrEmail, password));
localStorage.setItem("accountPassword", password);
}
}
return sendBack
return sendBack; // Return success status
};
export const deleteAccount = async (usernameOrEmail: string, password: string) => {
@ -163,5 +148,5 @@ export const deleteAccount = async (usernameOrEmail: string, password: string) =
email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined,
password,
};
return await sendToDatabase(data);
return await sendToDatabase(data); // Send account deletion request
};

View file

@ -1,37 +1,32 @@
import axios from "axios";
let windownameGlobal = ""
let windownameGlobal = ""; // Global variable to hold the window name
let accesstoken = ""; // Variable to store the access token
let accesstoken = ""
onmessage = (event) => {
const { action, access_token, windowname } = event.data
accesstoken = access_token
windownameGlobal = windowname
const { action, access_token, windowname } = event.data;
accesstoken = access_token;
windownameGlobal = windowname;
if (action === "start") {
fetchData()
} else if (action === "terminate") {
fetchData(); // Start fetching data on 'start' action
}
}
const fetchData = () => {
const apiURL = new URL("http://localhost:5000/interstellar_ai/api/ai_get?access_token=" + accesstoken);
apiURL.hostname = windownameGlobal; // Set the hostname
const apiURL = new URL("http://localhost:5000/interstellar_ai/api/ai_get?access_token=" + accesstoken)
apiURL.hostname = windownameGlobal;
console.log(apiURL.href)
console.log(apiURL.href); // Log the constructed URL
axios.get(apiURL.href)
.then(response => {
const data = response.data
postMessage(data)
setTimeout(fetchData, 100)
postMessage(response.data); // Send data back on success
setTimeout(fetchData, 100); // Schedule next fetch
})
.catch(error => {
console.log('Error fetching data:', error);
postMessage({ error: "failed fetching data" })
setTimeout(() => fetchData(), 1000)
})
}
postMessage({ error: "failed fetching data" }); // Send error message
setTimeout(() => fetchData(), 1000); // Retry after 1 second
});
}

View file

@ -1,31 +1,32 @@
import axios from "axios";
// Event listener for incoming messages
onmessage = (e) => {
const { messages, ai_model, model_type, access_token, api_key, windowname } = e.data
const { messages, ai_model, model_type, access_token, api_key, windowname } = e.data;
// Construct the message object to send to the API
const Message = {
messages: messages,
ai_model: ai_model,
model_type: model_type,
access_token: access_token,
api_key: api_key
}
};
const apiURL = new URL("http://localhost:5000/interstellar_ai/api/ai_send")
console.log(windowname)
apiURL.hostname = windowname;
const apiURL = new URL("http://localhost:5000/interstellar_ai/api/ai_send");
console.log(windowname); // Log the window name
apiURL.hostname = windowname; // Set the hostname for the API request
console.log(apiURL.href)
console.log(apiURL.href); // Log the constructed API URL
// Make a POST request to the API with the message object
axios.post(apiURL.href, Message)
.then(response => {
const status = response.data.status
postMessage({ status })
const status = response.data.status;
postMessage({ status }); // Send the response status back
})
.catch(error => {
console.log("Error calling API:", error)
postMessage({ status: 500 })
})
}
console.log("Error calling API:", error);
postMessage({ status: 500 }); // Send error status if API call fails
});
}

View file

@ -1,24 +1,26 @@
import axios from "axios";
export const sendToVoiceRecognition = (audio_data: Blob): Promise<string> => {
// Create a new FormData instance to send the audio file
const formdata = new FormData();
formdata.append("audio", audio_data); // Append the audio data to the FormData
const formdata = new FormData()
formdata.append("audio", audio_data)
const apiURL = new URL("http://localhost:5000/interstellar_ai/api/voice_recognition")
// Set the API URL dynamically based on the environment
const apiURL = new URL("http://localhost:5000/interstellar_ai/api/voice_recognition");
if (typeof window !== 'undefined') {
apiURL.hostname = window.location.hostname;
apiURL.hostname = window.location.hostname; // Use the current hostname in the browser
} else {
apiURL.hostname = "localhost"
apiURL.hostname = "localhost"; // Fallback for server-side
}
// Send the audio data to the API using POST request
return axios.post(apiURL.href, formdata)
.then((response) => {
return response.data.response
return response.data.response; // Return the response from the API
})
.catch(error => {
console.log("Error calling API:", error)
postMessage({ status: 500 })
return "Error"
})
}
console.log("Error calling API:", error); // Log any error that occurs
postMessage({ status: 500 }); // Indicate an error status to the worker
return "Error"; // Return a fallback error message
});
};

View file

@ -1,23 +1,29 @@
import axios from "axios";
const apiURL = new URL("http://localhost:5000/interstellar_ai/api/weather")
// Initialize the API URL for the weather service
const apiURL = new URL("http://localhost:5000/interstellar_ai/api/weather");
if (typeof window !== 'undefined') {
apiURL.hostname = window.location.hostname;
apiURL.hostname = window.location.hostname; // Use current hostname in the browser
} else {
apiURL.hostname = "localhost"
apiURL.hostname = "localhost"; // Fallback for server-side
}
// Function to get weather data
export const getWeather = async (data: object): Promise<string> => {
try {
// Make a POST request to the weather API with the provided data
const response = await axios.post(apiURL.href, data);
const status = response.data.status;
const success = response.data.response;
const status = response.data.status; // Extract the status from the response
const success = response.data.response; // Extract the actual weather data from the response
// Send the status and success response back to the worker
postMessage({ status, success });
console.log(JSON.stringify(success))
return JSON.stringify(success);
console.log(JSON.stringify(success)); // Log the successful response for debugging
return JSON.stringify(success); // Return the weather data as a JSON string
} catch (error) {
// Handle any errors that occur during the request
postMessage({ status: 500, success: false });
console.log(error)
return "";
console.log(error); // Log the error for debugging
return ""; // Return an empty string in case of an error
}
};
};

View file

@ -5,9 +5,10 @@ import InputOutputBackend from '../backend/InputOutputHandler';
const AI: React.FC = () => {
return (
<div className="ai-container">
{/* Render the InputOutputBackend component for AI input/output handling */}
<InputOutputBackend />
</div>
);
};
export default AI;
export default AI;

View file

@ -1,24 +1,45 @@
import React from 'react';
// Main Credits Component
const Credits: React.FC = () => (
<div className="credits-container">
<section id="credits" className="credits-section">
<h1 className="title">Credits</h1>
<h2 className="subtitle">Icons</h2>
<p className="paragraph">This project utilizes the following icon resources:</p>
<CreditLink href="https://fontawesome.com/v4/license/" label="fontawesome" />
<CreditLink href="https://fontawesome.com/v4/license/" label="FontAwesome" />
<h2 className="subtitle">Fonts</h2>
<p className="paragraph">The fonts used in this project are provided by:</p>
<CreditLink href="https://github.com/itfoundry/Poppins" label="Poppins" />
<CreditLink href="https://openfontlicense.org" label="Inconsolata, Merriweather, Noto Sans, Noto Serif, Playfair Display, Bangers, Caveat, Frederika the Great, Sofadi One, Zilla Slab Highlight" />
<CreditLink href="http://www.apache.org/licenses/LICENSE-2.0" label="Roboto, Rock Salt" />
<CreditLink
href="https://openfontlicense.org"
label="Inconsolata, Merriweather, Noto Sans, Noto Serif, Playfair Display, Bangers, Caveat, Frederika the Great, Sofadi One, Zilla Slab Highlight"
/>
<CreditLink
href="http://www.apache.org/licenses/LICENSE-2.0"
label="Roboto, Rock Salt"
/>
<CreditLink href="https://ubuntu.com/legal/font-licence" label="Ubuntu" />
</section>
</div>
);
const CreditLink = ({ href, label }: { href: string; label: string }) => (
<a href={href} className="credit-btn" target="_blank" rel="noopener noreferrer">{label}</a>
// CreditLink Component for rendering individual credit links
const CreditLink: React.FC<{ href: string; label: string }> = ({ href, label }) => (
<a
href={href}
className="credit-btn"
target="_blank"
rel="noopener noreferrer"
aria-label={`Visit ${label} license page`} // Improve accessibility
>
{label}
</a>
);
export default Credits;
// also thank you Leart and Tristan without you two we would not have come this far
// and a special thanks and why are you so annoying to Eslint

View file

@ -1,6 +1,7 @@
import React from 'react';
const Documentation = () => {
// Documentation Component
const Documentation: React.FC = () => {
return (
<section id="documentation" className="documentation-section">
<div className='docDiv'>

View file

@ -1,107 +1,62 @@
import React from 'react';
// FAQ Component
const FAQ: React.FC = () => {
return (
<section id="faq">
<h2>Frequently Asked Questions</h2>
<section id="faq"> {/* Main section for FAQs */}
<h2>Frequently Asked Questions</h2> {/* Title for the FAQ section */}
<div className="faq-item">
<h3>What is this AI assistant for?</h3>
<p>This AI assistant helps you with various tasks such as answering questions, generating text, and even helping with code or writing tasks.</p>
<h3>Why doesn't my selection in the category dropdown menu apply?</h3>
<p>Currently, the dropdown menu for selecting AI models does not retain your choice after a website refresh.</p>
</div>
<div className="faq-item">
<h3>How does the AI assistant work?</h3>
<p>The assistant uses machine learning algorithms to understand your input and provide contextually relevant answers or generate content based on the task you&apos;ve described.</p>
<h3>Why is the AI suddenly talking about the weather when I didn't select that option?</h3>
<p>The AI is programmed to provide weather information even if you haven't specifically selected the weather option.</p>
</div>
<div className="faq-item">
<h3>Can I trust the answers given by the AI assistant?</h3>
<p>While the AI strives to give accurate and helpful answers, it is important to verify critical information, especially for complex or sensitive queries.</p>
<h3>Why isn't the online API working?</h3>
<p>At the moment, the online APIs for Google and La Plateforme are not operational. However, the OpenAI and Anthropic APIs may still function.</p>
</div>
<div className="faq-item">
<h3>What kind of questions can I ask?</h3>
<p>You can ask a wide range of questions from simple factual queries to more complex requests like generating creative writing or code snippets.</p>
<h3>Why is the AI discussing unrelated topics?</h3>
<p>Try disabling the AI system prompt settings, as the AI sometimes tends to focus on those topics excessively.</p>
</div>
<div className="faq-item">
<h3>Is my data secure when using the AI assistant?</h3>
<p>We take privacy seriously. Your data is handled according to our privacy policy, ensuring that any personal information shared is securely processed and not misused.</p>
<h3>Why isn't the AI responding in the format I specified in the settings?</h3>
<p>Please check if the system prompt settings are enabled. If the issue persists, it may be because the AI is unable to fully adhere to the command.</p>
</div>
<div className="faq-item">
<h3>How can I provide feedback about the AI assistant?</h3>
<p>Feedback can be provided through our feedback form, available on our website. We appreciate your input and use it to improve the AI assistant&apos;s performance.</p>
<h3>Does this AI have the ability to know my location or search the web?</h3>
<p>No, this AI does not possess any capabilities to access your location or browse the web.</p>
</div>
<div className="faq-item">
<h3>Can I customize the AI assistant&apos;s responses?</h3>
<p>Customization options are limited in the current version, but we are working on features that will allow users to tailor responses to better suit their needs.</p>
<h3>Does the AI really work offline?</h3>
<p>Yes! Once you download the necessary models, it can operate fully offline, with the exception of the weather API.</p>
</div>
<div className="faq-item">
<h3>How frequently is the AI assistant updated?</h3>
<p>The AI assistant is updated regularly to improve its functionality and incorporate new features. Stay tuned to our update logs for information on the latest improvements.</p>
<h3>Are my messages encrypted?</h3>
<p>Unfortunately, not at this time. We recommend keeping your messages as anonymous as possible.</p>
</div>
<div className="faq-item">
<h3>What should I do if the AI assistant is not working properly?</h3>
<p>If you encounter any issues with the AI assistant, please contact our support team for assistance. Provide details about the problem to help us resolve it quickly.</p>
<h3>Where is my data saved?</h3>
<p>All data, including accounts, settings, and chats, is stored locally on your computer.</p>
</div>
<div className="faq-item">
<h3>Will the AI assistant be available in multiple languages?</h3>
<p>Yes, the AI assistant is designed to support multiple languages. You can specify your language preference in the settings to receive responses in your chosen language.</p>
<h3>Is this a virus?</h3>
<p>No, this is not a virus. The warning appears because the application is not officially signed.</p>
</div>
<div className="faq-item">
<h3>How can I integrate the AI assistant into my own application?</h3>
<p>Integration guidelines are available in our developer documentation. Follow the instructions to incorporate the AI assistant into your application via our API.</p>
</div>
<div className="faq-item">
<h3>Is there a mobile version of the AI assistant?</h3>
<p>Currently, the AI assistant is optimized for desktop use. We are working on a mobile version to provide a seamless experience on smartphones and tablets.</p>
</div>
<div className="faq-item">
<h3>Can the AI assistant handle multiple simultaneous conversations?</h3>
<p>Yes, the AI assistant is capable of managing multiple conversations at once, ensuring that each interaction is handled efficiently.</p>
</div>
<div className="faq-item">
<h3>What are the system requirements to use the AI assistant?</h3>
<p>The AI assistant can be accessed through most modern web browsers. Ensure your browser is up-to-date for the best experience.</p>
</div>
<div className="faq-item">
<h3>How can I access previous conversations?</h3>
<p>Previous conversations can be accessed through the chat history feature available in the assistant&apos;s interface.</p>
</div>
<div className="faq-item">
<h3>What are the limitations of the current AI assistant?</h3>
<p>The AI assistant may have limitations in understanding highly specialized or nuanced topics. We are continuously working to expand its capabilities.</p>
</div>
<div className="faq-item">
<h3>How do I update my profile or settings?</h3>
<p>Profile and settings updates can be made through the account management section of the application. Ensure you save your changes before exiting.</p>
</div>
<div className="faq-item">
<h3>Can the AI assistant be used offline?</h3>
<p>Currently, the AI assistant requires an internet connection to function. Offline capabilities are being explored for future updates.</p>
</div>
<div className="faq-item">
<h3>Who can I contact for technical support?</h3>
<p>Technical support can be reached through our support contact page on the website. Our team is available to help with any technical issues you may encounter.</p>
</div>
</section>
);
};
export default FAQ;
export default FAQ; // Exporting the FAQ component

View file

@ -1,12 +1,13 @@
import React, { useState, useRef, useEffect } from 'react';
import Login from './Login';
import Login from './Login'; // Importing the Login component
// Define the props for the Header component
interface HeaderProps {
onViewChange: (view: 'AI' | 'FAQ' | 'Documentation' | 'Credits') => void;
showDivs: boolean;
toggleDivs: () => void;
showHistoryModelsToggle: boolean;
showToggle: boolean;
onViewChange: (view: 'AI' | 'FAQ' | 'Documentation' | 'Credits') => void; // Function to change views
showDivs: boolean; // State to show/hide divs
toggleDivs: () => void; // Function to toggle divs
showHistoryModelsToggle: boolean; // State to show/hide history models
showToggle: boolean; // State to show/hide toggle button
}
const Header: React.FC<HeaderProps> = ({
@ -16,50 +17,53 @@ const Header: React.FC<HeaderProps> = ({
showHistoryModelsToggle,
showToggle,
}) => {
// State to manage menu open/closed state
const [menuOpen, setMenuOpen] = useState(false);
const dropdownRef = useRef<HTMLDivElement | null>(null);
const toggleRef = useRef<HTMLDivElement | null>(null);
const dropdownRef = useRef<HTMLDivElement | null>(null); // Ref for dropdown menu
const toggleRef = useRef<HTMLDivElement | null>(null); // Ref for hamburger toggle
// Pages that will be displayed in the menu
// Pages to be displayed in the navigation menu
const pages: ('AI' | 'FAQ' | 'Documentation' | 'Credits')[] = ['AI', 'FAQ', 'Documentation', 'Credits'];
// Toggle menu state
// Function to toggle the dropdown menu state
const toggleMenu = () => {
setMenuOpen((prevMenuOpen) => !prevMenuOpen);
};
// Handle button click
// Function to handle view change when a menu item is clicked
const handleViewChange = (page: 'AI' | 'FAQ' | 'Documentation' | 'Credits') => {
onViewChange(page);
setMenuOpen(false); // Close the menu when a button is clicked
onViewChange(page); // Call the onViewChange function with the selected page
setMenuOpen(false); // Close the menu after selection
};
// Effect to handle clicks outside of the dropdown
// Effect to handle clicks outside the dropdown to close it
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
// Check if the click is outside the dropdown and toggle elements
if (
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node) &&
toggleRef.current &&
!toggleRef.current.contains(event.target as Node)
) {
setMenuOpen(false);
setMenuOpen(false); // Close the menu if the click is outside
}
};
document.addEventListener('mousedown', handleClickOutside);
document.addEventListener('mousedown', handleClickOutside); // Listen for clicks
return () => {
document.removeEventListener('mousedown', handleClickOutside);
document.removeEventListener('mousedown', handleClickOutside); // Cleanup listener on unmount
};
}, []);
return (
<>
<header>
{/* Show the toggle button for divs if conditions are met */}
{showToggle && showHistoryModelsToggle && (
<button onClick={toggleDivs} className="nav-btn show-hide-btn">
{showDivs ? (
{showDivs ? ( // Conditional rendering of icon based on showDivs state
<>
<svg style={{ fill: "var(--text-color)" }} width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512">
<path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c8.4-19.3 10.6-41.4 4.8-63.3c-11.1-41.5-47.8-69.4-88.6-71.1c-5.8-.2-9.2 6.1-7.4 11.7c2.1 6.4 3.3 13.2 3.3 20.3c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zM373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5L373 389.9z"/>
@ -74,27 +78,32 @@ const Header: React.FC<HeaderProps> = ({
)}
</button>
)}
{/* Navigation menu */}
<nav ref={dropdownRef} className={`nav-links ${menuOpen ? "active" : ""}`}>
{pages.map(page => (
{pages.map(page => ( // Map through pages to create buttons
<button key={page} onClick={() => handleViewChange(page)} className="nav-btn">
{page}
</button>
))}
</nav>
{/* Hamburger menu toggle */}
<div ref={toggleRef} className={`hamburger ${menuOpen ? "open" : ""}`} onClick={toggleMenu}>
<span></span>
<span></span>
<span></span>
<span></span> {/* Top bar of the hamburger */}
<span></span> {/* Middle bar of the hamburger */}
<span></span> {/* Bottom bar of the hamburger */}
</div>
<div className="header-logo">
{/* AI logo or text */}
{/* Placeholder for AI logo or text */}
</div>
<div className="login-button-container">
<Login />
<Login /> {/* Include the Login component */}
</div>
</header>
</>
);
};
export default Header;
export default Header; // Exporting the Header component

View file

@ -1,96 +1,114 @@
import React, { useState } from 'react';
import { useChatHistory } from '../hooks/useChatHistory';
import { useChatHistory } from '../hooks/useChatHistory'; // Importing the custom hook for chat history
const History: React.FC = () => {
const [chatHistory, setSelectedIndex, setChatHistory] = useChatHistory()
const [isEditing, setIsEditing] = useState(false);
const [inputValue, setInputValue] = useState<string>('');
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null)
// Destructuring values from the useChatHistory hook
const [chatHistory, setSelectedIndex, setChatHistory] = useChatHistory();
const [isEditing, setIsEditing] = useState(false); // State to manage edit mode
const [inputValue, setInputValue] = useState<string>(''); // State for input field
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null); // State to track hovered chat index
// Function to activate editing mode
const handleEditButtonClick = () => {
setIsEditing(true);
};
// Function to update input value as the user types
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
};
// Function to save the new chat
const handleSaveButtonClick = () => {
setIsEditing(false);
chatHistory.chats.push({ name: inputValue, messages: [], timestamp: 5 })
setInputValue("")
setIsEditing(false); // Exit edit mode
// Add a new chat entry to the history
chatHistory.chats.push({ name: inputValue, messages: [], timestamp: 5 });
setInputValue(''); // Reset input value
};
// Function to select a chat from the history
const handleHistoryClick = (index: number) => {
setSelectedIndex(index)
console.log("index",index);
}
setSelectedIndex(index); // Set the selected index to the clicked chat
console.log("index", index);
};
const handleHistoryHover = (index:number) => {
setHoveredIndex(index)
}
// Function to handle hover over a chat entry
const handleHistoryHover = (index: number) => {
setHoveredIndex(index); // Set hovered index
};
// Function to reset hovered index when not hovering
const handleHistoryNotHover = () => {
setHoveredIndex(null)
}
console.log("chat length",chatHistory.chats.length)
console.log("index",chatHistory.selectedIndex)
setHoveredIndex(null); // Reset hovered index
};
// Debugging information for chat history length and selected index
console.log("chat length", chatHistory.chats.length);
console.log("index", chatHistory.selectedIndex);
// Function to delete a chat entry
const handleHistoryDeletion = (index: number) => {
const currentIndex = chatHistory.selectedIndex;
const currentIndex = chatHistory.selectedIndex; // Get the currently selected index
// Create a new copy of the current chat history
// Create a new copy of the chat history
const copyChats = { ...chatHistory };
copyChats.chats = [...chatHistory.chats]
// Remove the chat at the specified index
copyChats.chats.splice(index,1)
copyChats.chats = [...chatHistory.chats];
// Determine new selectedIndex
let newSelectedIndex = currentIndex;
// Remove the chat at the specified index
copyChats.chats.splice(index, 1);
// Adjust selectedIndex based on the deletion
if (index === currentIndex) {
// If the deleted index is the currently selected one, reset the selected index
newSelectedIndex = copyChats.chats.length > 0 ? (index > 0 ? index - 1 : 0) : -1; // Set to previous or first chat or -1 if no chats left
} else if (index < currentIndex) {
// If the deleted chat is before the current selected index, decrement the selected index
newSelectedIndex = currentIndex - 1;
// Determine the new selectedIndex
let newSelectedIndex = currentIndex;
// Adjust selectedIndex based on the deletion
if (index === currentIndex) {
// If the deleted index is currently selected, reset the selected index
newSelectedIndex = copyChats.chats.length > 0 ? (index > 0 ? index - 1 : 0) : -1; // Set to previous or first chat or -1 if no chats left
} else if (index < currentIndex) {
// If the deleted chat is before the current selected index, decrement the selected index
newSelectedIndex = currentIndex - 1;
}
copyChats.selectedIndex = newSelectedIndex
console.log(copyChats)
// Set the updated chat history
setChatHistory(copyChats);
};
copyChats.selectedIndex = newSelectedIndex; // Update the selected index
// Debugging information to inspect the modified chat history
console.log(copyChats);
// Set the updated chat history
setChatHistory(copyChats);
};
return (
<div className="history-background">
<div className="history">
<ul>
{/* Populate with history items */}
{chatHistory.chats.map((chats, index) => (
<li key={index} onMouseOver={()=>handleHistoryHover(index)} onMouseOut={handleHistoryNotHover} >
<a href="#" onClick={() => handleHistoryClick(index)} style={{
backgroundColor: chatHistory.selectedIndex == index ? "var(--input-button-color)" : "",
borderRadius: "5px",
width: index==hoveredIndex && chatHistory.chats.length >1 ? "85%":"100%"
}}>
{chatHistory.chats[index].name}
</a>
<button id="delete-chat-button"
onClick={()=>handleHistoryDeletion(index)}
disabled={(index == hoveredIndex && chatHistory.chats.length >1) ? false : true}
{/* Render chat history items */}
{chatHistory.chats.map((chat, index) => (
<li key={index} onMouseOver={() => handleHistoryHover(index)} onMouseOut={handleHistoryNotHover}>
<a
href="#"
onClick={() => handleHistoryClick(index)} // Handle click to select chat
style={{
width: index == hoveredIndex && chatHistory.chats.length >1 ? "15%" : "0",
visibility: index == hoveredIndex && chatHistory.chats.length >1 ? "visible" : "hidden",
marginLeft: index == hoveredIndex && chatHistory.chats.length >1? "0.5em":0
}}>
<svg viewBox="0 0 448 512"><path d="M135.2 17.7L128 32 32 32C14.3 32 0 46.3 0 64S14.3 96 32 96l384 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-96 0-7.2-14.3C307.4 6.8 296.3 0 284.2 0L163.8 0c-12.1 0-23.2 6.8-28.6 17.7zM416 128L32 128 53.2 467c1.6 25.3 22.6 45 47.9 45l245.8 0c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>
backgroundColor: chatHistory.selectedIndex === index ? "var(--input-button-color)" : "",
borderRadius: "5px",
width: index === hoveredIndex && chatHistory.chats.length > 1 ? "85%" : "100%"
}}
>
{chat.name} {/* Display chat name */}
</a>
<button
id="delete-chat-button"
onClick={() => handleHistoryDeletion(index)} // Handle chat deletion
disabled={!(index === hoveredIndex && chatHistory.chats.length > 1)} // Disable if not hovered
style={{
width: index === hoveredIndex && chatHistory.chats.length > 1 ? "15%" : "0",
visibility: index === hoveredIndex && chatHistory.chats.length > 1 ? "visible" : "hidden",
marginLeft: index === hoveredIndex && chatHistory.chats.length > 1 ? "0.5em" : 0
}}
>
<svg viewBox="0 0 448 512">
<path d="M135.2 17.7L128 32 32 32C14.3 32 0 46.3 0 64S14.3 96 32 96l384 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-96 0-7.2-14.3C307.4 6.8 296.3 0 284.2 0L163.8 0c-12.1 0-23.2 6.8-28.6 17.7zM416 128L32 128 53.2 467c1.6 25.3 22.6 45 47.9 45l245.8 0c25.3 0 46.3-19.7 47.9-45L416 128z" />
</svg>
</button>
</li>
))}
@ -100,17 +118,17 @@ const History: React.FC = () => {
<input
type="text"
value={inputValue}
onChange={handleInputChange}
onChange={handleInputChange} // Update input value as user types
placeholder="Enter text"
className="chat-input"
/>
/>
<button onClick={handleSaveButtonClick} className="save-btn">
Save
Save {/* Button to save new chat */}
</button>
</div>
) : (
<button onClick={handleEditButtonClick} className="newChat-btn">
New Chat
New Chat {/* Button to initiate a new chat */}
</button>
)}
</li>
@ -120,4 +138,4 @@ const History: React.FC = () => {
);
}
export default History;
export default History; // Exporting the History component

View file

@ -2,6 +2,7 @@
import React, { useState, useEffect } from 'react';
// Define all models that should be available.
//#region modelist
const modelList = {
'Offline Fast': {
model_type: 'local',
@ -112,7 +113,7 @@ const selectedAIFunction = [
'Language',
'Weather'
]
//#region variables
const ModelSection: React.FC = () => {
// Initialize state with value from localStorage or default to ''
const [selectedModelDropdown, setSelectedModelDropdown] = useState('');
@ -120,7 +121,7 @@ const ModelSection: React.FC = () => {
const [activeSelectedAIFunction, setActiveSelectedAIFunction] = useState('');
const [currentSelectedAIFunction, setCurrentSelectedAIFunction] = useState<string | null>("");
const [isOpenSourceMode, setIsOpenSourceMode] = useState<string|null>("false")
//#region functions
useEffect(() => {
if (typeof localStorage !== 'undefined') {
const defaultValues = {
@ -175,7 +176,7 @@ const ModelSection: React.FC = () => {
modelClicked(model)
}
};
//#region dropdown
// Determine the filtered models based on current radioSelection
const filteredModels = (() => {
let models = [];
@ -241,7 +242,7 @@ const ModelSection: React.FC = () => {
localStorage.setItem("type", modelList[selectedAIFunction]['model_type' as keyof typeof modelList[typeof selectedAIFunction]])
}
}
//#region return "html"
return (
<div className="model-background">
<div className="models">

View file

@ -1,17 +1,19 @@
import React from 'react';
// Define the props for the ButtonSetting component
interface ButtonSettingProps {
label: string; // The label to display on the button
onClick: () => void; // The function to call when the button is clicked
className?: string; // Optional additional classes for styling
}
const ButtonSetting: React.FC<ButtonSettingProps> = ({ label, onClick }) => {
// Functional component definition
const ButtonSetting: React.FC<ButtonSettingProps> = ({ label, onClick, className }) => {
return (
<div className="settings-option">
<div className="settings-option"> {/* Container for the button */}
<button
onClick={onClick} // Call the onClick function when the button is clicked
className={"export-button"} // Apply any additional classes
className={`export-button ${className || ''}`} // Apply any additional classes, default to empty if not provided
>
{label} {/* Display the label on the button */}
</button>

View file

@ -1,25 +1,28 @@
import React from 'react';
// Define the props for the CheckboxSetting component
interface CheckboxSettingProps {
label: string; // The label to display
checked: boolean; // The checked state of the checkbox
setChecked: (value: boolean) => void; // Method to update the state
}
// Functional component definition
const CheckboxSetting: React.FC<CheckboxSettingProps> = ({ label, checked, setChecked }) => {
// Handler to toggle the checkbox state
const handleCheckboxChange = () => {
setChecked(!checked);
setChecked(!checked); // Toggle the checked state
};
return (
<div className="settings-option">
<div className="settings-option"> {/* Container for the checkbox setting */}
<label>
<input
type="checkbox"
checked={checked}
onChange={handleCheckboxChange}
type="checkbox" // Checkbox input type
checked={checked} // Set the checked state based on the prop
onChange={handleCheckboxChange} // Call the handler on change
/>
{label}
{label} {/* Display the label next to the checkbox */}
</label>
</div>
);

View file

@ -1,29 +1,32 @@
import React from 'react';
import React from 'react';
interface ColorSettingProps {
// Define the props for the ColorSetting component
interface ColorSettingProps {
name: string; // The name to display in the <p> tag
value: string; // The current color value
setValue: (newColor: string) => void; // The method to update the state
cssVariable: string; // The CSS variable name to set
}
}
const ColorSetting: React.FC<ColorSettingProps> = ({ name, value, setValue, cssVariable }) => {
// Functional component definition
const ColorSetting: React.FC<ColorSettingProps> = ({ name, value, setValue, cssVariable }) => {
// Handler to change the color value
const handleColorChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newColor = e.target.value;
setValue(newColor);
document.documentElement.style.setProperty(cssVariable, newColor);
const newColor = e.target.value; // Get the new color from the input
setValue(newColor); // Update the state with the new color
document.documentElement.style.setProperty(cssVariable, newColor); // Set the CSS variable
};
return (
<div className="settings-option">
<p>{name}</p>
<input
type="color"
value={value}
onChange={handleColorChange}
/>
<div className="settings-option"> {/* Container for the color setting */}
<p>{name}</p> {/* Display the name */}
<input
type="color" // Input type for color picker
value={value} // Set the input value to the current color
onChange={handleColorChange} // Call the handler on change
/>
</div>
);
};
};
export default ColorSetting;
export default ColorSetting;

View file

@ -1,35 +1,39 @@
import React from 'react';
// Define the structure of each option in the dropdown
interface Option {
value: string; // The actual value to be used
label: string; // The label to display for the option
value: string; // The actual value to be used
label: string; // The label to display for the option
}
// Define the props for the DropdownSetting component
interface DropdownSettingProps {
label: string; // The label to display
value: string; // The current selected value
setValue: (newValue: string) => void; // The method to update the state
options: Option[]; // List of options for the dropdown
label: string; // The label to display above the dropdown
value: string; // The currently selected value
setValue: (newValue: string) => void; // Method to update the state with the new value
options: Option[]; // List of options for the dropdown
}
// Functional component definition
const DropdownSetting: React.FC<DropdownSettingProps> = ({ label, value, setValue, options }) => {
const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const newValue = e.target.value;
setValue(newValue);
};
// Handler to change the selected option
const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const newValue = e.target.value; // Get the new selected value
setValue(newValue); // Update the state with the new value
};
return (
<div className="settings-option">
<label>{label}</label>
<select value={value} onChange={handleSelectChange}>
{options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
</div>
);
return (
<div className="settings-option"> {/* Container for the dropdown setting */}
<label>{label}</label> {/* Display the label */}
<select value={value} onChange={handleSelectChange}> {/* Dropdown selection */}
{options.map((option) => ( // Map through options to create <option> elements
<option key={option.value} value={option.value}>
{option.label} {/* Display the label for the option */}
</option>
))}
</select>
</div>
);
};
export default DropdownSetting;

View file

@ -2,9 +2,10 @@
import React from 'react';
const ThemeDropdown: React.FC<{
selectedTheme: string;
setSelectedTheme: (theme: string) => void;
selectedTheme: string; // Currently selected theme
setSelectedTheme: (theme: string) => void; // Function to update the selected theme
}> = ({ selectedTheme, setSelectedTheme }) => {
// Define available theme options
const themeOptions = [
{ value: 'IOMARKET', label: 'IOMARKET' },
{ value: 'WHITE', label: 'WHITE' },
@ -14,22 +15,22 @@ const ThemeDropdown: React.FC<{
];
return (
<div className="settings-option">
<p>Select Theme</p>
<div className="settings-option"> {/* Container for the dropdown */}
<p>Select Theme</p> {/* Label for the dropdown */}
<select
value={selectedTheme}
onChange={(e) => {
const theme = e.target.value;
value={selectedTheme} // Current selected theme
onChange={(e) => { // Handler for dropdown changes
const theme = e.target.value; // Get the selected value
if (theme !== 'default' && typeof localStorage !== 'undefined') {
setSelectedTheme(theme);
localStorage.setItem('selectedTheme', theme);
setSelectedTheme(theme); // Update the selected theme state
localStorage.setItem('selectedTheme', theme); // Save the theme to localStorage
}
}}
>
<option value="default">Select your style...</option>
{themeOptions.map((option) => (
<option value="default">Select your style...</option> {/* Default option */}
{themeOptions.map((option) => ( // Map through theme options to create <option> elements
<option key={option.value} value={option.value}>
{option.label}
{option.label} {/* Display the label for the option */}
</option>
))}
</select>

View file

@ -2,28 +2,29 @@
import React from 'react';
interface FontSizeSettingProps {
fontSize: string; // The current font size
fontSize: string; // The current font size as a string (e.g., "16px")
setFontSize: (newSize: string) => void; // Function to update the font size
}
const FontSizeSetting: React.FC<FontSizeSettingProps> = ({ fontSize, setFontSize }) => {
// Handle changes to the font size input
const handleFontSizeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newSize = `${e.target.value}px`;
setFontSize(newSize);
document.documentElement.style.setProperty('--font-size', newSize);
const newSize = `${e.target.value}px`; // Create the new font size string
setFontSize(newSize); // Update the font size state
document.documentElement.style.setProperty('--font-size', newSize); // Update the CSS variable
};
return (
<div className="settings-option">
<p>Font Size</p>
<div className="settings-option"> {/* Container for the font size setting */}
<p>Font Size</p> {/* Label for the setting */}
<input
type="range"
min="12"
max="30"
value={parseInt(fontSize, 10)} // Ensure value is a number
onChange={handleFontSizeChange}
type="range" // Range input for selecting font size
min="12" // Minimum font size
max="30" // Maximum font size
value={parseInt(fontSize, 10)} // Ensure value is a number for the slider
onChange={handleFontSizeChange} // Update font size on change
/>
<span>{fontSize}</span>
<span>{fontSize}</span> {/* Display the current font size */}
</div>
);
};

View file

@ -12,25 +12,26 @@ const OpenSourceModeToggle: React.FC<OpenSourceModeToggleProps> = ({
setOpenSourceMode,
setSelectedOption
}) => {
// Handle toggle change event
const handleToggleChange = () => {
const newValue = !openSourceMode;
setOpenSourceMode(newValue);
const newValue = !openSourceMode; // Toggle the current state
setOpenSourceMode(newValue); // Update the open source mode state
// Update radio selection based on the new openSourceMode value
if (newValue) {
setSelectedOption('FOSS'); // Set to FOSS if enabling open source mode
} else {
setSelectedOption('None'); // Or any other default value when disabling
setSelectedOption('None'); // Set to a default value when disabling
}
};
return (
<div className="settings-option">
<div className="settings-option"> {/* Container for the toggle setting */}
<label>
<input
type="checkbox"
checked={openSourceMode}
onChange={handleToggleChange}
type="checkbox" // Checkbox for toggling open source mode
checked={openSourceMode} // Check if the mode is currently enabled
onChange={handleToggleChange} // Handle changes to the checkbox
/>
Enable Open Source Mode
</label>

View file

@ -14,28 +14,28 @@ const PrivacySettings: React.FC<PrivacySettingsProps> = ({ selectedOption, handl
<div className="settings-option">
<p>Disable Options:</p>
<div className="slider">
{/* Offline */}
{/* Offline Option */}
<div
className={`slider-option ${selectedOption === 'Offline' ? 'active' : ''}`}
onClick={() => handleRadioChange('Offline')} // Allow selection only if not in open-source mode
className={`slider-option ${selectedOption === 'Offline' ? 'active' : ''}`} // Active class based on selection
onClick={() => handleRadioChange('Offline')} // Handle selection change
>
Offline tools{openSourceMode ? ' (FOSS)' : ''}
Offline tools{openSourceMode ? ' (FOSS)' : ''} {/* Display FOSS label if applicable */}
</div>
{/* Online */}
{/* Online Option */}
<div
className={`slider-option ${selectedOption === 'Online' ? 'active' : ''}`}
onClick={() => handleRadioChange('Online')}
className={`slider-option ${selectedOption === 'Online' ? 'active' : ''}`} // Active class based on selection
onClick={() => handleRadioChange('Online')} // Handle selection change
>
Online tools{openSourceMode ? ' (FOSS)' : ''}
Online tools{openSourceMode ? ' (FOSS)' : ''} {/* Display FOSS label if applicable */}
</div>
{/* None */}
{/* None Option */}
<div
className={`slider-option ${selectedOption === 'None' ? 'active' : ''}`}
onClick={() => handleRadioChange('None')}
className={`slider-option ${selectedOption === 'None' ? 'active' : ''}`} // Active class based on selection
onClick={() => handleRadioChange('None')} // Handle selection change
>
None{openSourceMode ? ' (FOSS)' : ''}
None{openSourceMode ? ' (FOSS)' : ''} {/* Display FOSS label if applicable */}
</div>
</div>
<br />

View file

@ -65,7 +65,7 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
// Measurement setting
const [preferredMeasurement, setPreferredMeasurement] = useState(() => localStorage.getItem('preferredMeasurement') || 'Metric');
// Theme settings
//#region Theme settings
const [backgroundColor, setBackgroundColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--background-color').trim());
const [headerBackground, setHeaderBackground] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--header-background-color').trim());
const [textColor, setTextColor] = useState(() => getComputedStyle(document.documentElement).getPropertyValue('--text-color').trim());
@ -122,6 +122,7 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
const [google, setGoogle] = useState(localStorage.getItem('google') || "");
const [myBoolean, setMyBoolean] = useState<boolean>(() => getItemFromLocalStorage('myBoolean'));
//#region Json
const settings = {
userPreferences: {
activeSection,
@ -185,6 +186,7 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
},
};
//#region color settings
const colorSettings = [
{ name: "Background Color", value: backgroundColor, setValue: setBackgroundColor, cssVariable: "--background-color" },
{ name: "Header Background Color", value: headerBackground, setValue: setHeaderBackground, cssVariable: "--header-background-color" },
@ -219,7 +221,7 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
{ name: "Burger Menu Background Color", value: burgerMenuBackgroundColor, setValue: setBurgerMenuBackgroundColor, cssVariable: "--burger-menu-background-color" },
];
//#region time settings
const timeZoneOptions = [
{ value: 'GMT', label: 'GMT' },
{ value: 'EST', label: 'EST' },
@ -233,7 +235,7 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
{ value: 'JST', label: 'JST' },
];
//#region language settings
const languageOptions = [
{ code: 'en', name: 'English' },
{ code: 'es', name: 'Spanish' },
@ -246,7 +248,7 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
{ code: 'ru', name: 'Russian' },
{ code: 'ar', name: 'Arabic' },
];
//#region currency settings
const currencyOptions = [
{ code: 'usd', name: 'USD' },
{ code: 'eur', name: 'EUR' },
@ -258,7 +260,7 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
{ code: 'cny', name: 'CNY' },
{ code: 'inr', name: 'INR' },
];
//#region date settings
const dateFormatOptions = [
{ value: 'mm/dd/yyyy', label: 'MM/DD/YYYY' },
{ value: 'dd/mm/yyyy', label: 'DD/MM/YYYY' },
@ -276,7 +278,7 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
{ value: 'Metric', label: 'Metric' },
{ value: 'Imperial', label: 'Imperial' },
];
//#region text settings
const fontOptions = [
{ value: "'Poppins', sans-serif", label: 'Poppins' },
{ value: "'Inconsolata', monospace", label: 'Inconsolata' },
@ -294,7 +296,7 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
{ value: "'Zilla Slab Highlight', serif", label: 'Zilla Slab Highlight' },
];
//#region Start of the code
//#region Function
const handleLogout = () => {
localStorage.clear();
alert('Successfully logged out!');

View file

@ -10,6 +10,7 @@ export function exportSettings(): string {
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key) {
// Exclude sensitive information
if (key !== "accountName" && key !== "accountPassword" && key !== "accountEmail") {
settings[key] = localStorage.getItem(key) || "";
}
@ -39,25 +40,28 @@ export function importSettings(jsonData: string): void {
}
}
// Send current settings to the database
export const sendToDatabase = async () => {
const useName = localStorage.getItem("accountName")
const usePassword = localStorage.getItem("accountPassword")
const useName = localStorage.getItem("accountName");
const usePassword = localStorage.getItem("accountPassword");
if (useName && usePassword) {
const result = await changeSettings(useName, usePassword, JSON.parse(exportSettings()))
if (result == true) {
const result = await changeSettings(useName, usePassword, JSON.parse(exportSettings()));
if (result === true) {
// Only reload if the settings change was successful
window.location.reload();
}
}
window.location.reload();
};
// Import settings from the database based on username and password
export const importDatabase = async (useName: string, usePassword: string) => {
const databaseSettings = await getSettings(useName, usePassword);
// Ensure user settings exist before flattening and storing
if (typeof databaseSettings == 'object' && databaseSettings) {
if (typeof databaseSettings === 'object' && databaseSettings) {
importSettings(JSON.stringify(databaseSettings, null, 2)); // Pass only the current user's settings
} else {
console.error('Database settings are not in the expected format.');
}
}
};

View file

@ -1,3 +1,4 @@
//#region IOMARKET
export const applyIOMarketTheme = () => {
document.documentElement.style.setProperty('--header-background-color', '#7e7e7e');
document.documentElement.style.setProperty('--header-text-color', '#ffffff');
@ -35,7 +36,7 @@ export const applyIOMarketTheme = () => {
document.documentElement.style.setProperty('--font-family', "'Poppins', 'sans-serif'");
document.documentElement.style.setProperty('--font-size', '16px');
};
//#region WHITE
export const applyWhiteTheme = () => {
document.documentElement.style.setProperty('--header-background-color', '#f0f0f0'); // Lighter header background
document.documentElement.style.setProperty('--header-text-color', '#333'); // Dark text for contrast
@ -73,7 +74,7 @@ export const applyWhiteTheme = () => {
document.documentElement.style.setProperty('--font-family', "'Poppins', 'sans-serif'"); // Same font family
document.documentElement.style.setProperty('--font-size', '16px'); // Same font size
};
//#region BLACK
export const applyBlackTheme = () => {
document.documentElement.style.setProperty('--header-background-color', '#1a1a1a'); // Dark header background
document.documentElement.style.setProperty('--header-text-color', '#ffffff'); // White text for header
@ -112,7 +113,7 @@ export const applyBlackTheme = () => {
document.documentElement.style.setProperty('--font-size', '16px'); // Font size
};
//#region CUSTOM
export const applyCustomTheme = () => {
if (typeof localStorage !== 'undefined') {
const themeVariables = {
@ -191,6 +192,8 @@ export const applyCustomTheme = () => {
};
}
//#region BASIC-CUSTOM
// TypeScript types for color parameters
type Color = string;
@ -277,6 +280,7 @@ const lightenColor = (color: Color, percent: number): Color => {
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
};
//#region APPLY-THEME
// This is the new function that calls the appropriate theme application
export const applyTheme = (theme: string, primary: string, secondary: string, accent: string, background: string, text: string) => {
switch (theme) {

View file

@ -1,68 +1,98 @@
import { useEffect, useState } from "react"
import { useEffect, useState } from "react";
// Define the structure of a Message
interface Message {
role: string
content:string
role: string; // The role of the message sender (e.g., system, user, assistant)
content: string; // The content of the message
}
// Define the structure for each chat session
interface ChatMessages {
name: string
messages: Message[]
timestamp: number
name: string; // The name or title of the chat
messages: Message[]; // Array of messages in the chat
timestamp: number; // Timestamp for the chat session
}
// Define the structure for the global chat history
interface GlobalChatHistory {
chats: ChatMessages[]
selectedIndex: number
chats: ChatMessages[]; // Array of chat sessions
selectedIndex: number; // Index of the currently selected chat
}
// Initial global chat history state
let globalChatHistory: GlobalChatHistory = {
chats: [
{ name: "Welcome!", messages: [{role:"system",content:"you are a helpful assistant"},{role:"assistant",content:"Hello! How can I help you?"}], timestamp: 4 },
{
name: "Welcome!",
messages: [
{ role: "system", content: "you are a helpful assistant" },
{ role: "assistant", content: "Hello! How can I help you?" }
],
timestamp: 4
},
],
selectedIndex:0
}
let listeners: ((state: GlobalChatHistory) => void)[] = []
selectedIndex: 0
};
// Listeners for state changes
let listeners: ((state: GlobalChatHistory) => void)[] = [];
// Function to set a new global state and notify listeners
const setGlobalState = (newState: GlobalChatHistory): void => {
globalChatHistory = newState;
listeners.forEach((listener) => listener(globalChatHistory))
globalChatHistory = newState; // Update the global state
listeners.forEach((listener) => listener(globalChatHistory)); // Notify all listeners
}
export const useChatHistory = (): [GlobalChatHistory, (index:number)=>void, (newState:GlobalChatHistory) => void,(messageIndex: number, newContent:string)=> void] => {
const [state, setState] = useState<GlobalChatHistory>(globalChatHistory)
// Custom hook to manage chat history
export const useChatHistory = (): [
GlobalChatHistory, // Current state
(index: number) => void, // Function to set selected index
(newState: GlobalChatHistory) => void, // Function to set global state
(messageIndex: number, newContent: string) => void // Function to update a message
] => {
const [state, setState] = useState<GlobalChatHistory>(globalChatHistory); // Local state initialized with global state
useEffect(() => {
console.log("help", globalChatHistory);
// Log the initial state for debugging
console.log("Current global chat history:", globalChatHistory);
// Listener to update local state when global state changes
const listener = (newState: GlobalChatHistory) => {
setState(newState)
}
setState(newState);
};
listeners.push(listener)
listeners.push(listener); // Add the listener to the array
// Cleanup function to remove the listener when the component unmounts
return () => {
listeners = listeners.filter((l) => l!== listener)
}
}, [])
listeners = listeners.filter((l) => l !== listener);
};
}, []);
// Function to set the selected chat index
const setSelectedIndex = (index: number) => {
setGlobalState({...state,selectedIndex:index})
setGlobalState({ ...state, selectedIndex: index }); // Update the global state
}
// Function to update a specific message in the current chat
const updateMessage = (messageIndex: number, newContent: string) => {
const updatedChats = [...state.chats]
const chatIndex = globalChatHistory.selectedIndex
const updatedChats = [...state.chats]; // Make a copy of the current chats
const chatIndex = globalChatHistory.selectedIndex; // Get the currently selected chat index
// Check if the selected chat index is valid
if (chatIndex >= 0 && chatIndex < updatedChats.length) {
const updatedMessages = [...updatedChats[chatIndex].messages]
const updatedMessages = [...updatedChats[chatIndex].messages]; // Copy messages of the selected chat
// Check if the message index is valid
if (messageIndex >= 0 && messageIndex < updatedMessages.length) {
updatedMessages[messageIndex] = { ...updatedMessages[messageIndex], content: newContent }
updatedChats[chatIndex] = { ...updatedChats[chatIndex], messages: updatedMessages }
setGlobalState({...state, chats: updatedChats})
// Update the content of the specified message
updatedMessages[messageIndex] = { ...updatedMessages[messageIndex], content: newContent };
updatedChats[chatIndex] = { ...updatedChats[chatIndex], messages: updatedMessages }; // Update the chat with new messages
setGlobalState({ ...state, chats: updatedChats }); // Set the updated global state
}
}
}
return [state, setSelectedIndex, setGlobalState, updateMessage]
}
// Return the current state and action functions
return [state, setSelectedIndex, setGlobalState, updateMessage];
}

View file

@ -1,24 +1,23 @@
import { ReactNode } from 'react';
// Metadata for the application, used for SEO and page information
export const metadata = {
title: 'AI Assistant | Interstellar Development',
description: 'A little AI chat that is able to assist you in little tasks',
title: 'AI Assistant | Interstellar Development', // Title of the page
description: 'A little AI chat that is able to assist you in little tasks', // Description of the page
};
// RootLayout component definition
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<html lang="en"> {/* Set the language of the document */}
<head>
<title>{metadata.title}</title>
<meta name="description" content={metadata.description} />
{/* Tried adding the favicon here */}
<title>{metadata.title}</title> {/* Set the page title */}
<meta name="description" content={metadata.description} /> {/* Set the page description for SEO */}
{/* Link to the favicon for the site */}
<link rel="icon" href="./favicon.ico" type="image/x-icon" />
</head>
<body>
<main>{children}</main>
<main>{children}</main> {/* Render the child components inside the main element */}
</body>
</html>
);

View file

@ -7,21 +7,30 @@ import Documentation from './components/Documentation'; // Ensure the import pat
import History from './components/History';
import Models from './components/Models';
import Credits from './components/Credits';
import { applyIOMarketTheme, applyWhiteTheme, applyBlackTheme, applyCustomTheme, applyBasicCustomTheme } from './components/settings/theme';
import {
applyIOMarketTheme,
applyWhiteTheme,
applyBlackTheme,
applyCustomTheme,
applyBasicCustomTheme
} from './components/settings/theme';
import './styles/master.css';
const LandingPage: React.FC = () => {
// State to control visibility of the left panels
const [showDivs, setShowDivs] = useState(true);
// State to track which view is currently displayed
const [view, setView] = useState<'AI' | 'FAQ' | 'Documentation' | 'Credits'>('AI');
const conversationRef = useRef<HTMLDivElement>(null);
const [primaryColor, setPrimaryColor] = useState("#fefefe");
const [secondaryColor, setSecondaryColor] = useState("#fefefe");
const [accentColor, setAccentColor] = useState("#fefefe");
const [basicBackgroundColor, setBasicBackgroundColor] = useState("#fefefe");
const [basicTextColor, setBasicTextColor] = useState("#fefefe");
// State for theme colors
const [primaryColor, setPrimaryColor] = useState("#fefefe");
const [secondaryColor, setSecondaryColor] = useState("#fefefe");
const [accentColor, setAccentColor] = useState("#fefefe");
const [basicBackgroundColor, setBasicBackgroundColor] = useState("#fefefe");
const [basicTextColor, setBasicTextColor] = useState("#fefefe");
// Synchronize state with local storage on mount
// Synchronize theme colors with local storage on component mount
useEffect(() => {
if (typeof localStorage !== 'undefined') {
setPrimaryColor(localStorage.getItem("primaryColor") || "#fefefe");
@ -32,18 +41,21 @@ const LandingPage: React.FC = () => {
}
}, [primaryColor, secondaryColor, accentColor, basicBackgroundColor, basicTextColor]);
// Toggle visibility of the left panels
const toggleDivs = () => {
setShowDivs(prevState => !prevState);
};
// Change the current view based on user selection
const handleViewChange = (view: 'AI' | 'FAQ' | 'Documentation' | 'Credits') => {
setView(view);
// Hide left panels if the selected view is not 'AI'
if (view !== 'AI') {
setShowDivs(false);
}
};
// Apply theme based on selectedTheme and color settings
// Apply the selected theme and color settings based on local storage
useEffect(() => {
if (typeof localStorage !== 'undefined') {
const savedTheme = localStorage.getItem('selectedTheme');
@ -52,8 +64,8 @@ const LandingPage: React.FC = () => {
case 'IOMARKET':
applyIOMarketTheme();
break;
case 'WHITE':
applyWhiteTheme();
case 'WHITE':
applyWhiteTheme();
break;
case 'BLACK':
applyBlackTheme();
@ -61,8 +73,8 @@ const LandingPage: React.FC = () => {
case 'CUSTOM':
applyCustomTheme();
break;
case 'BASIC-CUSTOM':
applyBasicCustomTheme(
case 'BASIC-CUSTOM':
applyBasicCustomTheme(
primaryColor,
secondaryColor,
accentColor,
@ -71,15 +83,16 @@ const LandingPage: React.FC = () => {
);
break;
default:
applyIOMarketTheme();
applyIOMarketTheme(); // Fallback theme
break;
}
}
}
}, [primaryColor, secondaryColor, accentColor, basicBackgroundColor, basicTextColor]); // Watch color states and apply themes accordingly
}, [primaryColor, secondaryColor, accentColor, basicBackgroundColor, basicTextColor]); // Apply themes whenever color states change
return (
<>
{/* Header component with props for toggling and view change */}
<Header
toggleDivs={toggleDivs}
showDivs={showDivs}
@ -91,12 +104,14 @@ const LandingPage: React.FC = () => {
<div className={`left-panel ${showDivs ? 'visible' : 'hidden'}`}>
{showDivs && (
<div className="history-models">
{/* Show History and Models components if left panels are visible */}
<History />
<Models />
</div>
)}
</div>
<div className={`conversation-container ${showDivs ? 'collapsed' : 'expanded'}`} ref={conversationRef}>
{/* Render the selected view based on the current state */}
{view === 'AI' && <AI />}
{view === 'FAQ' && <FAQ />}
{view === 'Documentation' && <Documentation />}

View file

@ -4,10 +4,11 @@ import google.generativeai as genai
import anthropic
import ollama
class AI:
@staticmethod
def process_local(model, messages, return_class, access_token):
"""Process chat messages using the Ollama model locally."""
# Stream the chat response from the Ollama model
stream = ollama.chat(
model=model,
messages=messages,
@ -15,50 +16,61 @@ class AI:
options={"temperature": 0.5},
)
# Initialize the AI response for the given access token
with return_class.ai_response_lock:
return_class.ai_response[access_token] = ""
# Collect the response chunks and append to the response for the given access token
for chunk in stream:
with return_class.ai_response_lock:
return_class.ai_response[access_token] += chunk["message"]["content"]
@staticmethod
def process_mistralai(model, messages, return_class, access_token, api_key):
"""Process chat messages using the Mistral AI model."""
client = Mistral(api_key=api_key)
# Stream the chat response from the Mistral model
stream_response = client.chat.stream(model=model, messages=messages)
# Initialize the AI response for the given access token
with return_class.ai_response_lock:
return_class.ai_response[access_token] = ""
# Collect the response chunks and append to the response for the given access token
for chunk in stream_response:
with return_class.ai_response_lock:
return_class.ai_response[access_token] += chunk.data.choices[
0
].delta.content
return_class.ai_response[access_token] += chunk.data.choices[0].delta.content
@staticmethod
def process_openai(model, messages, return_class, access_token, api_key):
"""Process chat messages using the OpenAI model."""
client = OpenAI(api_key=api_key)
# Stream the chat response from the OpenAI model
stream_response = client.chat.completions.create(
model=model, messages=messages, stream=True
)
# Initialize the AI response for the given access token
with return_class.ai_response_lock:
return_class.ai_response[access_token] = ""
# Collect the response chunks and append to the response for the given access token
for chunk in stream_response:
with return_class.ai_response_lock:
return_class.ai_response[access_token] += chunk.choices[0].delta.content
@staticmethod
def process_anthropic(model, messages, return_class, access_token, api_key):
"""Process chat messages using the Anthropic model."""
client = anthropic.Anthropic(api_key=api_key)
# Initialize the AI response for the given access token
with return_class.ai_response_lock:
return_class.ai_response[access_token] = ""
# Stream the chat response from the Anthropic model
with client.messages.stream(
max_tokens=1024,
model=model,
@ -70,24 +82,27 @@ class AI:
@staticmethod
def process_google(model, messages, return_class, access_token, api_key):
message = messages[-1]["content"]
messages.pop()
"""Process chat messages using the Google Generative AI model."""
message = messages[-1]["content"] # Get the latest message content
messages.pop() # Remove the latest message from the list
# Prepare messages for the Google Generative AI format
for msg in messages:
msg["parts"] = msg.pop()["content"]
# Change 'assistant' role to 'model' for compatibility
for msg in messages:
if msg["role"] == "assistant":
msg["role"] = "model"
# Configure the Google Generative AI client
genai.configure(api_key=api_key)
# Start a chat session with the specified model and message history
model = genai.GenerativeModel(model)
chat = model.start_chat(history=messages)
chat = model.start_chat(
history=messages,
)
# Send the message and stream the response
response = chat.send_message(message, stream=True)
for chunk in response:
return_class.ai_response[access_token] += chunk.text

122
py/api.py
View file

@ -1,5 +1,4 @@
from time import sleep
from flask import Flask, request, jsonify
from flask_cors import CORS
import secrets
@ -13,53 +12,58 @@ from tts import TTS
class API:
def __init__(self):
self.crypt_size = 64
self.app = Flask(__name__)
self.ai_response = {}
self.ai = AI()
self.db = DB()
self.weather = Weather()
self.voice = VoiceRecognition()
self.tts = TTS()
self.db.load_database()
self.ai_response_lock = threading.Lock()
CORS(self.app)
# Initialize the API class with necessary components and configurations
self.crypt_size = 64 # Size for generating secure tokens
self.app = Flask(__name__) # Create a Flask app instance
self.ai_response = {} # Dictionary to store AI responses keyed by access token
self.ai = AI() # AI processing instance
self.db = DB() # Database instance
self.weather = Weather() # Weather data retrieval instance
self.voice = VoiceRecognition() # Voice recognition instance
self.tts = TTS() # Text-to-Speech instance
self.db.load_database() # Load the database on startup
self.ai_response_lock = threading.Lock() # Lock for thread-safe access to AI responses
CORS(self.app) # Enable Cross-Origin Resource Sharing
def run(self):
# Route to create a new AI session
@self.app.route("/interstellar_ai/api/ai_create", methods=["GET"])
def create_ai():
access_token = secrets.token_urlsafe(self.crypt_size)
access_token = secrets.token_urlsafe(self.crypt_size) # Generate a secure access token
# Ensure the access token is unique
while access_token in self.ai_response:
access_token = secrets.token_urlsafe(self.crypt_size)
self.ai_response[access_token] = ""
self.ai_response[access_token] = "" # Initialize the response for the new session
return jsonify({"status": 200, "access_token": access_token})
# Route to send messages to the AI
@self.app.route("/interstellar_ai/api/ai_send", methods=["POST"])
def send_ai():
data = request.get_json()
messages = data.get("messages")
model_type = data.get("model_type")
ai_model = data.get("ai_model")
access_token = data.get("access_token")
data = request.get_json() # Get JSON data from the request
messages = data.get("messages") # Extract messages
model_type = data.get("model_type") # Extract model type
ai_model = data.get("ai_model") # Extract AI model name
access_token = data.get("access_token") # Extract access token
print(model_type)
print(model_type) # Debugging output
if access_token not in self.ai_response:
return jsonify({"status": 401, "error": "Invalid access token"})
return jsonify({"status": 401, "error": "Invalid access token"}) # Token validation
# Start a new thread to process AI requests based on the model type
if model_type == "local":
thread = threading.Thread(
target=self.ai.process_local,
args=(ai_model, messages, self, access_token),
)
thread.start()
thread.join()
sleep(0.5)
thread.join() # Wait for the thread to complete
sleep(0.5) # Sleep for a short duration
return jsonify({"status": 200})
elif model_type == "mistral":
print(model_type)
api_key = data.get("api_key")
print(model_type) # Debugging output
api_key = data.get("api_key") # Get API key
thread = threading.Thread(
target=self.ai.process_mistralai,
args=(ai_model, messages, self, access_token, api_key),
@ -69,7 +73,7 @@ class API:
sleep(0.5)
return jsonify({"status": 200})
elif model_type == "openai":
api_key = data.get("api_key")
api_key = data.get("api_key") # Get API key
thread = threading.Thread(
target=self.ai.process_openai,
args=(ai_model, messages, self, access_token, api_key),
@ -79,7 +83,7 @@ class API:
sleep(0.5)
return jsonify({"status": 200})
elif model_type == "anthropic":
api_key = data.get("api_key")
api_key = data.get("api_key") # Get API key
thread = threading.Thread(
target=self.ai.process_anthropic,
args=(ai_model, messages, self, access_token, api_key),
@ -89,7 +93,7 @@ class API:
sleep(0.5)
return jsonify({"status": 200})
elif model_type == "google":
api_key = data.get("api_key")
api_key = data.get("api_key") # Get API key
thread = threading.Thread(
target=self.ai.process_google,
args=(ai_model, messages, self, access_token, api_key),
@ -99,79 +103,85 @@ class API:
sleep(0.5)
return jsonify({"status": 200})
return jsonify({"status": 401, "error": "Invalid AI model type"})
return jsonify({"status": 401, "error": "Invalid AI model type"}) # Model type validation
# Route to retrieve AI response based on access token
@self.app.route("/interstellar_ai/api/ai_get", methods=["GET"])
def get_ai():
data = request.args.get("access_token")
data = request.args.get("access_token") # Get access token from query parameters
if data not in self.ai_response:
return jsonify({"status": 401, "error": "Invalid access token"})
return jsonify({"status": 200, "response": self.ai_response[data]})
return jsonify({"status": 401, "error": "Invalid access token"}) # Token validation
return jsonify({"status": 200, "response": self.ai_response[data]}) # Return AI response
# Route for database operations
@self.app.route("/interstellar_ai/db", methods=["POST"])
def db_manipulate():
sent_data = request.get_json()
action = sent_data.get("action")
sent_data = request.get_json() # Get JSON data from the request
action = sent_data.get("action") # Extract action type
if action == "create_account":
return jsonify({"status": 200, "response": self.db.add_user(sent_data)})
return jsonify({"status": 200, "response": self.db.add_user(sent_data)}) # Add user
elif action == "change_password":
return jsonify(
{"status": 200, "response": self.db.update_password(sent_data)}
{"status": 200, "response": self.db.update_password(sent_data)} # Update password
)
elif action == "get_settings":
return jsonify(
{"status": 200, "response": self.db.get_settings(sent_data)}
{"status": 200, "response": self.db.get_settings(sent_data)} # Get user settings
)
elif action == "change_settings":
return jsonify(
{"status": 200, "response": self.db.change_settings(sent_data)}
{"status": 200, "response": self.db.change_settings(sent_data)} # Change user settings
)
elif action == "get_history":
return jsonify(
{"status": 200, "response": self.db.get_history(sent_data)}
{"status": 200, "response": self.db.get_history(sent_data)} # Get user history
)
elif action == "change_history":
return jsonify(
{"status": 200, "response": self.db.change_history(sent_data)}
{"status": 200, "response": self.db.change_history(sent_data)} # Change user history
)
elif action == "check_credentials":
return jsonify(
{"status": 200, "response": self.db.check_credentials(sent_data)}
{"status": 200, "response": self.db.check_credentials(sent_data)} # Check user credentials
)
elif action == "delete_account":
return jsonify(
{"status": 200, "response": self.db.delete_user(sent_data)}
{"status": 200, "response": self.db.delete_user(sent_data)} # Delete user account
)
elif action == "get_email":
return jsonify(
{"status": 200, "response": self.db.get_email(sent_data)}
{"status": 200, "response": self.db.get_email(sent_data)} # Get user email
)
elif action == "get_name":
return jsonify({"status": 200, "response": self.db.get_name(sent_data)})
return jsonify({"status": 200, "response": self.db.get_name(sent_data)}) # Get user name
return jsonify({"status": 401, "response": "Invalid action"})
return jsonify({"status": 401, "response": "Invalid action"}) # Action validation
# Route for voice recognition
@self.app.route("/interstellar_ai/api/voice_recognition", methods=["POST"])
def voice_recognition():
audio = request.files.get("audio")
text = self.voice.recognition(audio)
return jsonify({"status": 200, "response": text})
audio = request.files.get("audio") # Get audio file from request
text = self.voice.recognition(audio) # Perform voice recognition
return jsonify({"status": 200, "response": text}) # Return recognized text
# Route for weather information retrieval
@self.app.route("/interstellar_ai/api/weather", methods=["POST"])
def get_weather():
sent_data = request.get_json()
unit_type = sent_data.get("unit_type")
city = sent_data.get("city")
weather_data = self.weather.getweather(unit_type, city)
return jsonify({"status": 200, "response": weather_data})
sent_data = request.get_json() # Get JSON data from the request
unit_type = sent_data.get("unit_type") # Extract unit type (metric, imperial)
city = sent_data.get("city") # Extract city name
weather_data = self.weather.getweather(unit_type, city) # Get weather data
return jsonify({"status": 200, "response": weather_data}) # Return weather data
self.app.run(debug=True, host="0.0.0.0", port=5000)
self.app.run(debug=True, host="0.0.0.0", port=5000) # Start the Flask app
# Route for Text-to-Speech conversion
@self.app.route("/interstellar_ai/api/tts", methods=["POST"])
def tts():
text = request.args.get("text")
return jsonify({"status": 200, "response": self.tts.gen_tts(text)})
text = request.args.get("text") # Get text from query parameters
return jsonify({"status": 200, "response": self.tts.gen_tts(text)}) # Generate TTS and return response
# Initialize the API class and run the application
api = API()
api.run()

View file

@ -3,12 +3,13 @@ import json
import os
import pycouchdb
class DB:
def __init__(self):
# Initialize the database dictionary to store user data
self.database = {}
def ensure_username(self, data):
# Ensure a username can be retrieved either from username or email
if "username" in data:
return data.get("username")
elif "email" in data:
@ -18,15 +19,17 @@ class DB:
@staticmethod
def hash_password(password):
salt = "your_secret_salt"
# Hash the password with a salt for secure storage
salt = "your_secret_salt" # Consider using a secure random salt
hashed_password = hashlib.sha256((password + salt).encode()).hexdigest()
return hashed_password
def add_user(self, data):
# Add a new user to the database if username is unique
username = data.get("username")
password = data.get("password")
email = data.get("email")
hashed_password = self.hash_password(password)
hashed_password = self.hash_password(password) # Hash the password
user_data = {
"hashed_password": hashed_password,
"email": email,
@ -35,112 +38,123 @@ class DB:
}
if username not in self.database:
self.database[username] = user_data
self.save_database()
self.save_database() # Save changes to the database
return True
return False
return False # User already exists
def delete_user(self, data):
# Delete a user from the database if credentials are valid
username = self.ensure_username(data)
if not self.check_credentials(data):
return False
return False # Invalid credentials
del self.database[username]
self.save_database()
del self.database[username] # Remove user from database
self.save_database() # Save changes
return True
def update_password(self, data):
# Update the user's password if credentials are valid
username = self.ensure_username(data)
new_password = data.get("new_password")
if not self.check_credentials(data):
return False
return False # Invalid credentials
hashed_new_password = self.hash_password(new_password)
hashed_new_password = self.hash_password(new_password) # Hash the new password
self.database[username].update({"hashed_password": hashed_new_password})
self.save_database()
self.save_database() # Save changes
return True
def check_credentials(self, data):
# Verify if provided credentials match stored data
username = self.ensure_username(data)
password = data.get("password")
if username not in self.database:
return False
return False # User not found
stored_hashed_password = self.database[username]["hashed_password"]
entered_hashed_password = self.hash_password(password)
return stored_hashed_password == entered_hashed_password
return stored_hashed_password == entered_hashed_password # Check hashed password
def change_settings(self, data):
# Change user settings if credentials are valid
username = self.ensure_username(data)
if not self.check_credentials(data):
return False
return False # Invalid credentials
self.database[username]["settings"] = data.get("data")
self.save_database()
self.database[username]["settings"] = data.get("data") # Update settings
self.save_database() # Save changes
return True
def get_settings(self, data):
# Retrieve user settings if credentials are valid
username = self.ensure_username(data)
if not self.check_credentials(data):
return None
return None # Invalid credentials
send_back = self.database[username].get("settings")
send_back = self.database[username].get("settings") # Get settings
return send_back
def change_history(self, data):
# Change user history if credentials are valid
username = self.ensure_username(data)
if not self.check_credentials(data):
return False
return False # Invalid credentials
self.database[username]["history"] = data.get("data")
self.save_database()
self.database[username]["history"] = data.get("data") # Update history
self.save_database() # Save changes
return True
def get_history(self, data):
# Retrieve user history if credentials are valid
username = self.ensure_username(data)
if not self.check_credentials(data):
return None
return None # Invalid credentials
send_back = self.database[username].get("history")
send_back = self.database[username].get("history") # Get history
return send_back
def get_email(self, data):
# Retrieve user email if credentials are valid
username = self.ensure_username(data)
if not self.check_credentials(data):
return None
return None # Invalid credentials
send_back = self.database[username].get("email")
send_back = self.database[username].get("email") # Get email
return send_back
def get_name(self, data):
# Retrieve username if credentials are valid
if not self.check_credentials(data):
return None
return None # Invalid credentials
send_back = self.ensure_username(data)
send_back = self.ensure_username(data) # Get username
return send_back
def save_database(self):
# Save the database to the specified storage (CouchDB or JSON file)
if os.environ.get("PRODUCTION") == "YES":
server = pycouchdb.Server("http://admin:admin@localhost:5984/")
db = server.database("interstellar_ai")
db.save(self.database)
db.save(self.database) # Save to CouchDB
else:
with open("database.json", "w") as file:
json.dump(self.database, file)
json.dump(self.database, file) # Save to JSON file
def load_database(self):
# Load the database from the specified storage (CouchDB or JSON file)
if os.environ.get("PRODUCTION") == "YES":
server = pycouchdb.Server("http://admin:admin@localhost:5984/")
db = server.database("interstellar_ai")
if db:
self.database = db
self.database = db # Load from CouchDB
else:
server.create("interstellar_ai")
server.create("interstellar_ai") # Create database if it doesn't exist
db = server.database("interstellar_ai")
db.save(self.database)
db.save(self.database) # Save initial empty database
else:
try:
with open("database.json", "r") as file:
self.database = json.load(file)
self.database = json.load(file) # Load from JSON file
except FileNotFoundError:
pass
pass # File not found, do nothing

View file

@ -1,6 +1,5 @@
import pyttsx3
class TTS:
@staticmethod
def gen_tts(text):

View file

@ -6,20 +6,28 @@ from pydub import AudioSegment
class VoiceRecognition:
@staticmethod
def recognition(audio):
# Read the audio file into a BytesIO buffer
audio_buffer = io.BytesIO(audio.read())
# Load the audio file using pydub
audio_segment = AudioSegment.from_file(audio_buffer, format="ogg")
# Export the audio to a WAV format in a BytesIO buffer
wav_io = io.BytesIO()
audio_segment.export(wav_io, format="wav")
wav_io.seek(0)
wav_io.seek(0) # Reset the buffer pointer to the start
model_size = "base"
# Load the Whisper model
model_size = "base" # Specify the model size
model = WhisperModel(model_size, device="cpu", compute_type="int8")
# Transcribe the audio
segments, _ = model.transcribe(wav_io)
transcription = ""
# Combine the transcribed segments into a single string
for segment in segments:
transcription += segment.text + " "
result = transcription.strip()
result = transcription.strip() # Strip any leading/trailing whitespace
return result

View file

@ -15,6 +15,7 @@ class Weather:
async with python_weather.Client(unit=unit_type) as client:
weather = await client.get(city)
# Collect weather data
data = {
"temperature": weather.temperature,
"humidity": weather.humidity,