forked from React-Group/interstellar_ai
main (#137)
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:
parent
f9bce3b22a
commit
91353bd051
34 changed files with 682 additions and 567 deletions
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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
|
||||
});
|
||||
};
|
||||
|
|
|
@ -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
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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'>
|
||||
|
|
|
@ -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'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'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'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'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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -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!');
|
||||
|
|
|
@ -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.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
43
app/page.tsx
43
app/page.tsx
|
@ -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 />}
|
||||
|
|
35
py/ai.py
35
py/ai.py
|
@ -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
122
py/api.py
|
@ -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()
|
||||
|
|
82
py/db.py
82
py/db.py
|
@ -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
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import pyttsx3
|
||||
|
||||
|
||||
class TTS:
|
||||
@staticmethod
|
||||
def gen_tts(text):
|
||||
|
|
14
py/voice.py
14
py/voice.py
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue