forked from React-Group/interstellar_ai
Compare commits
No commits in common. "237909c164bce186a70582a21957b952ec353d39" and "35151b2c539cef498d03d7dd292c183d6f0ebcf7" have entirely different histories.
237909c164
...
35151b2c53
34 changed files with 567 additions and 682 deletions
app
backend
components
hooks
layout.tsxpage.tsxpy
|
@ -1,19 +1,16 @@
|
|||
// getLocalStorageData.ts
|
||||
|
||||
// Function to retrieve all items from localStorage
|
||||
export const getAllLocalStorageItems = (): Record<string, string | null> => {
|
||||
const allData: Record<string, string | null> = {}; // Object to hold key-value pairs from localStorage
|
||||
|
||||
// Check if localStorage is available
|
||||
const allData: Record<string, string | null> = {};
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
// 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
|
||||
}
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
if (key) {
|
||||
const value = localStorage.getItem(key);
|
||||
allData[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return allData; // Return the object containing all localStorage items
|
||||
};
|
||||
return allData;
|
||||
};
|
||||
|
|
@ -9,7 +9,7 @@ import { getWeather } from "./weather";
|
|||
import { changeHistory, getHistory } from "./database";
|
||||
|
||||
const InputOutputBackend: React.FC = () => {
|
||||
//#region variables
|
||||
// # 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,7 +86,6 @@ 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!")
|
||||
|
@ -105,7 +104,7 @@ const InputOutputBackend: React.FC = () => {
|
|||
}
|
||||
setChatHistoryTriggered(true)
|
||||
}
|
||||
//#region system-prompt
|
||||
|
||||
useEffect(() => {
|
||||
console.log("creating system prompt")
|
||||
console.log(weatherData)
|
||||
|
@ -134,7 +133,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("")
|
||||
|
@ -145,7 +144,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()
|
||||
|
||||
|
@ -267,7 +266,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);
|
||||
|
@ -310,7 +309,7 @@ const InputOutputBackend: React.FC = () => {
|
|||
stopRecording();
|
||||
}
|
||||
};
|
||||
//#region chat buttons
|
||||
|
||||
const handleStopClick = () => {
|
||||
endGetWorker()
|
||||
getNewToken()
|
||||
|
@ -357,7 +356,7 @@ const InputOutputBackend: React.FC = () => {
|
|||
setCopyClicked(false)
|
||||
}
|
||||
|
||||
//#region The "html" return
|
||||
|
||||
return (
|
||||
<>
|
||||
<ConversationFrontend
|
||||
|
|
|
@ -1,40 +1,55 @@
|
|||
import axios from "axios";
|
||||
|
||||
// Construct the base API URL based on the environment
|
||||
const apiURL = new URL("http://localhost:5000/interstellar_ai/db");
|
||||
/*
|
||||
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")
|
||||
if (typeof window !== 'undefined') {
|
||||
apiURL.hostname = window.location.hostname; // Set hostname for browsers
|
||||
apiURL.hostname = window.location.hostname;
|
||||
} else {
|
||||
apiURL.hostname = "localhost"; // Default to localhost for non-browser environments
|
||||
apiURL.hostname = "localhost"
|
||||
}
|
||||
|
||||
// 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 }); // Send status back to the main thread
|
||||
return success; // Return success status
|
||||
postMessage({ status, success });
|
||||
return success;
|
||||
} catch (error) {
|
||||
postMessage({ status: 500, success: false }); // Handle errors
|
||||
console.log(error);
|
||||
return false; // Return false on error
|
||||
postMessage({ status: 500, success: false });
|
||||
console.log(error)
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 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 response string
|
||||
return success;
|
||||
} catch (error) {
|
||||
postMessage({ status: 500, success: false });
|
||||
console.log(error);
|
||||
return "false"; // Return "false" on error
|
||||
console.log(error)
|
||||
return "false";
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -46,7 +61,7 @@ export const createAccount = async (username: string, email: string, password: s
|
|||
email: email,
|
||||
password: password,
|
||||
};
|
||||
return await sendToDatabase(data); // Send account creation request
|
||||
return await sendToDatabase(data);
|
||||
};
|
||||
|
||||
export const changePassword = async (usernameOrEmail: string, password: string, newPassword: string) => {
|
||||
|
@ -57,7 +72,7 @@ export const changePassword = async (usernameOrEmail: string, password: string,
|
|||
password,
|
||||
new_password: newPassword,
|
||||
};
|
||||
return await sendToDatabase(data); // Send password change request
|
||||
return await sendToDatabase(data);
|
||||
};
|
||||
|
||||
export const getSettings = async (usernameOrEmail: string, password: string) => {
|
||||
|
@ -67,7 +82,7 @@ export const getSettings = async (usernameOrEmail: string, password: string) =>
|
|||
email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined,
|
||||
password,
|
||||
};
|
||||
return await sendToDatabaseAndGetString(data); // Get user settings
|
||||
return await sendToDatabaseAndGetString(data);
|
||||
};
|
||||
|
||||
export const changeSettings = async (usernameOrEmail: string, password: string, newData: object) => {
|
||||
|
@ -78,7 +93,7 @@ export const changeSettings = async (usernameOrEmail: string, password: string,
|
|||
password,
|
||||
data: newData,
|
||||
};
|
||||
return await sendToDatabase(data); // Send settings change request
|
||||
return await sendToDatabase(data);
|
||||
};
|
||||
|
||||
export const getHistory = async (usernameOrEmail: string, password: string) => {
|
||||
|
@ -88,7 +103,7 @@ export const getHistory = async (usernameOrEmail: string, password: string) => {
|
|||
email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined,
|
||||
password,
|
||||
};
|
||||
return await sendToDatabaseAndGetString(data); // Get user history
|
||||
return await sendToDatabaseAndGetString(data);
|
||||
};
|
||||
|
||||
export const changeHistory = async (usernameOrEmail: string, password: string, newData: object) => {
|
||||
|
@ -99,7 +114,7 @@ export const changeHistory = async (usernameOrEmail: string, password: string, n
|
|||
password,
|
||||
data: newData,
|
||||
};
|
||||
return await sendToDatabase(data); // Send history change request
|
||||
return await sendToDatabase(data);
|
||||
};
|
||||
|
||||
export const getEmail = async (usernameOrEmail: string, password: string): Promise<string> => {
|
||||
|
@ -109,7 +124,7 @@ export const getEmail = async (usernameOrEmail: string, password: string): Promi
|
|||
email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined,
|
||||
password,
|
||||
};
|
||||
return await sendToDatabaseAndGetString(data); // Get user email
|
||||
return await sendToDatabaseAndGetString(data);
|
||||
};
|
||||
|
||||
export const getName = async (usernameOrEmail: string, password: string): Promise<string> => {
|
||||
|
@ -119,9 +134,10 @@ export const getName = async (usernameOrEmail: string, password: string): Promis
|
|||
email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined,
|
||||
password,
|
||||
};
|
||||
return await sendToDatabaseAndGetString(data); // Get user name
|
||||
return await sendToDatabaseAndGetString(data);
|
||||
};
|
||||
|
||||
|
||||
export const checkCredentials = async (usernameOrEmail: string, password: string) => {
|
||||
const data = {
|
||||
action: "check_credentials",
|
||||
|
@ -129,16 +145,15 @@ export const checkCredentials = async (usernameOrEmail: string, password: string
|
|||
email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined,
|
||||
password,
|
||||
};
|
||||
const sendBack = await sendToDatabase(data); // Check user credentials
|
||||
const sendBack = await sendToDatabase(data);
|
||||
if (sendBack) {
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
// 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);
|
||||
localStorage.setItem("accountEmail", await getEmail(usernameOrEmail, password))
|
||||
localStorage.setItem("accountName", await getName(usernameOrEmail, password))
|
||||
localStorage.setItem("accountPassword", password)
|
||||
}
|
||||
}
|
||||
return sendBack; // Return success status
|
||||
return sendBack
|
||||
};
|
||||
|
||||
export const deleteAccount = async (usernameOrEmail: string, password: string) => {
|
||||
|
@ -148,5 +163,5 @@ export const deleteAccount = async (usernameOrEmail: string, password: string) =
|
|||
email: usernameOrEmail.includes('@') ? usernameOrEmail : undefined,
|
||||
password,
|
||||
};
|
||||
return await sendToDatabase(data); // Send account deletion request
|
||||
return await sendToDatabase(data);
|
||||
};
|
||||
|
|
|
@ -1,32 +1,37 @@
|
|||
import axios from "axios";
|
||||
|
||||
let windownameGlobal = ""; // Global variable to hold the window name
|
||||
let accesstoken = ""; // Variable to store the access token
|
||||
let windownameGlobal = ""
|
||||
|
||||
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(); // Start fetching data on 'start' action
|
||||
fetchData()
|
||||
} else if (action === "terminate") {
|
||||
}
|
||||
}
|
||||
|
||||
const fetchData = () => {
|
||||
const apiURL = new URL("http://localhost:5000/interstellar_ai/api/ai_get?access_token=" + accesstoken);
|
||||
apiURL.hostname = windownameGlobal; // Set the hostname
|
||||
|
||||
console.log(apiURL.href); // Log the constructed URL
|
||||
const fetchData = () => {
|
||||
|
||||
const apiURL = new URL("http://localhost:5000/interstellar_ai/api/ai_get?access_token=" + accesstoken)
|
||||
apiURL.hostname = windownameGlobal;
|
||||
|
||||
console.log(apiURL.href)
|
||||
|
||||
axios.get(apiURL.href)
|
||||
.then(response => {
|
||||
postMessage(response.data); // Send data back on success
|
||||
setTimeout(fetchData, 100); // Schedule next fetch
|
||||
const data = response.data
|
||||
postMessage(data)
|
||||
setTimeout(fetchData, 100)
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('Error fetching data:', error);
|
||||
postMessage({ error: "failed fetching data" }); // Send error message
|
||||
setTimeout(() => fetchData(), 1000); // Retry after 1 second
|
||||
});
|
||||
postMessage({ error: "failed fetching data" })
|
||||
setTimeout(() => fetchData(), 1000)
|
||||
})
|
||||
}
|
|
@ -1,32 +1,31 @@
|
|||
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); // Log the window name
|
||||
apiURL.hostname = windowname; // Set the hostname for the API request
|
||||
const apiURL = new URL("http://localhost:5000/interstellar_ai/api/ai_send")
|
||||
console.log(windowname)
|
||||
apiURL.hostname = windowname;
|
||||
|
||||
console.log(apiURL.href); // Log the constructed API URL
|
||||
console.log(apiURL.href)
|
||||
|
||||
// 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 }); // Send the response status back
|
||||
const status = response.data.status
|
||||
postMessage({ status })
|
||||
|
||||
})
|
||||
.catch(error => {
|
||||
console.log("Error calling API:", error);
|
||||
postMessage({ status: 500 }); // Send error status if API call fails
|
||||
});
|
||||
console.log("Error calling API:", error)
|
||||
postMessage({ status: 500 })
|
||||
})
|
||||
}
|
|
@ -1,26 +1,24 @@
|
|||
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
|
||||
|
||||
// Set the API URL dynamically based on the environment
|
||||
const apiURL = new URL("http://localhost:5000/interstellar_ai/api/voice_recognition");
|
||||
const formdata = new FormData()
|
||||
formdata.append("audio", audio_data)
|
||||
|
||||
const apiURL = new URL("http://localhost:5000/interstellar_ai/api/voice_recognition")
|
||||
if (typeof window !== 'undefined') {
|
||||
apiURL.hostname = window.location.hostname; // Use the current hostname in the browser
|
||||
apiURL.hostname = window.location.hostname;
|
||||
} else {
|
||||
apiURL.hostname = "localhost"; // Fallback for server-side
|
||||
apiURL.hostname = "localhost"
|
||||
}
|
||||
|
||||
// Send the audio data to the API using POST request
|
||||
return axios.post(apiURL.href, formdata)
|
||||
.then((response) => {
|
||||
return response.data.response; // Return the response from the API
|
||||
return response.data.response
|
||||
})
|
||||
.catch(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
|
||||
});
|
||||
};
|
||||
console.log("Error calling API:", error)
|
||||
postMessage({ status: 500 })
|
||||
return "Error"
|
||||
})
|
||||
}
|
|
@ -1,29 +1,23 @@
|
|||
import axios from "axios";
|
||||
|
||||
// Initialize the API URL for the weather service
|
||||
const apiURL = new URL("http://localhost:5000/interstellar_ai/api/weather");
|
||||
const apiURL = new URL("http://localhost:5000/interstellar_ai/api/weather")
|
||||
if (typeof window !== 'undefined') {
|
||||
apiURL.hostname = window.location.hostname; // Use current hostname in the browser
|
||||
apiURL.hostname = window.location.hostname;
|
||||
} else {
|
||||
apiURL.hostname = "localhost"; // Fallback for server-side
|
||||
apiURL.hostname = "localhost"
|
||||
}
|
||||
|
||||
// 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; // 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
|
||||
const status = response.data.status;
|
||||
const success = response.data.response;
|
||||
postMessage({ status, success });
|
||||
console.log(JSON.stringify(success)); // Log the successful response for debugging
|
||||
return JSON.stringify(success); // Return the weather data as a JSON string
|
||||
console.log(JSON.stringify(success))
|
||||
return JSON.stringify(success);
|
||||
} catch (error) {
|
||||
// Handle any errors that occur during the request
|
||||
postMessage({ status: 500, success: false });
|
||||
console.log(error); // Log the error for debugging
|
||||
return ""; // Return an empty string in case of an error
|
||||
console.log(error)
|
||||
return "";
|
||||
}
|
||||
};
|
|
@ -5,7 +5,6 @@ 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>
|
||||
);
|
||||
|
|
|
@ -1,45 +1,24 @@
|
|||
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>
|
||||
);
|
||||
|
||||
// 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>
|
||||
const CreditLink = ({ href, label }: { href: string; label: string }) => (
|
||||
<a href={href} className="credit-btn" target="_blank" rel="noopener noreferrer">{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,7 +1,6 @@
|
|||
import React from 'react';
|
||||
|
||||
// Documentation Component
|
||||
const Documentation: React.FC = () => {
|
||||
const Documentation = () => {
|
||||
return (
|
||||
<section id="documentation" className="documentation-section">
|
||||
<div className='docDiv'>
|
||||
|
|
|
@ -1,62 +1,107 @@
|
|||
import React from 'react';
|
||||
|
||||
// FAQ Component
|
||||
const FAQ: React.FC = () => {
|
||||
return (
|
||||
<section id="faq"> {/* Main section for FAQs */}
|
||||
<h2>Frequently Asked Questions</h2> {/* Title for the FAQ section */}
|
||||
<section id="faq">
|
||||
<h2>Frequently Asked Questions</h2>
|
||||
|
||||
<div className="faq-item">
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div className="faq-item">
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div className="faq-item">
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div className="faq-item">
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div className="faq-item">
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div className="faq-item">
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div className="faq-item">
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div className="faq-item">
|
||||
<h3>Are my messages encrypted?</h3>
|
||||
<p>Unfortunately, not at this time. We recommend keeping your messages as anonymous as possible.</p>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div className="faq-item">
|
||||
<h3>Where is my data saved?</h3>
|
||||
<p>All data, including accounts, settings, and chats, is stored locally on your computer.</p>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div className="faq-item">
|
||||
<h3>Is this a virus?</h3>
|
||||
<p>No, this is not a virus. The warning appears because the application is not officially signed.</p>
|
||||
<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>
|
||||
</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; // Exporting the FAQ component
|
||||
export default FAQ;
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import Login from './Login'; // Importing the Login component
|
||||
import Login from './Login';
|
||||
|
||||
// Define the props for the Header component
|
||||
interface HeaderProps {
|
||||
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
|
||||
onViewChange: (view: 'AI' | 'FAQ' | 'Documentation' | 'Credits') => void;
|
||||
showDivs: boolean;
|
||||
toggleDivs: () => void;
|
||||
showHistoryModelsToggle: boolean;
|
||||
showToggle: boolean;
|
||||
}
|
||||
|
||||
const Header: React.FC<HeaderProps> = ({
|
||||
|
@ -17,53 +16,50 @@ 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); // Ref for dropdown menu
|
||||
const toggleRef = useRef<HTMLDivElement | null>(null); // Ref for hamburger toggle
|
||||
const dropdownRef = useRef<HTMLDivElement | null>(null);
|
||||
const toggleRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
// Pages to be displayed in the navigation menu
|
||||
// Pages that will be displayed in the menu
|
||||
const pages: ('AI' | 'FAQ' | 'Documentation' | 'Credits')[] = ['AI', 'FAQ', 'Documentation', 'Credits'];
|
||||
|
||||
// Function to toggle the dropdown menu state
|
||||
// Toggle menu state
|
||||
const toggleMenu = () => {
|
||||
setMenuOpen((prevMenuOpen) => !prevMenuOpen);
|
||||
};
|
||||
|
||||
// Function to handle view change when a menu item is clicked
|
||||
// Handle button click
|
||||
const handleViewChange = (page: 'AI' | 'FAQ' | 'Documentation' | 'Credits') => {
|
||||
onViewChange(page); // Call the onViewChange function with the selected page
|
||||
setMenuOpen(false); // Close the menu after selection
|
||||
onViewChange(page);
|
||||
setMenuOpen(false); // Close the menu when a button is clicked
|
||||
};
|
||||
|
||||
// Effect to handle clicks outside the dropdown to close it
|
||||
// Effect to handle clicks outside of the dropdown
|
||||
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); // Close the menu if the click is outside
|
||||
setMenuOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('mousedown', handleClickOutside); // Listen for clicks
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside); // Cleanup listener on unmount
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<header>
|
||||
{/* Show the toggle button for divs if conditions are met */}
|
||||
{showToggle && showHistoryModelsToggle && (
|
||||
<button onClick={toggleDivs} className="nav-btn show-hide-btn">
|
||||
{showDivs ? ( // Conditional rendering of icon based on showDivs state
|
||||
{showDivs ? (
|
||||
<>
|
||||
<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"/>
|
||||
|
@ -78,32 +74,27 @@ const Header: React.FC<HeaderProps> = ({
|
|||
)}
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Navigation menu */}
|
||||
<nav ref={dropdownRef} className={`nav-links ${menuOpen ? "active" : ""}`}>
|
||||
{pages.map(page => ( // Map through pages to create buttons
|
||||
{pages.map(page => (
|
||||
<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> {/* Top bar of the hamburger */}
|
||||
<span></span> {/* Middle bar of the hamburger */}
|
||||
<span></span> {/* Bottom bar of the hamburger */}
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
|
||||
<div className="header-logo">
|
||||
{/* Placeholder for AI logo or text */}
|
||||
{/* AI logo or text */}
|
||||
</div>
|
||||
<div className="login-button-container">
|
||||
<Login /> {/* Include the Login component */}
|
||||
<Login />
|
||||
</div>
|
||||
</header>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header; // Exporting the Header component
|
||||
export default Header;
|
||||
|
|
|
@ -1,114 +1,96 @@
|
|||
import React, { useState } from 'react';
|
||||
import { useChatHistory } from '../hooks/useChatHistory'; // Importing the custom hook for chat history
|
||||
import { useChatHistory } from '../hooks/useChatHistory';
|
||||
|
||||
const History: React.FC = () => {
|
||||
// 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
|
||||
const [chatHistory, setSelectedIndex, setChatHistory] = useChatHistory()
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [inputValue, setInputValue] = useState<string>('');
|
||||
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null)
|
||||
|
||||
|
||||
// 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); // Exit edit mode
|
||||
// Add a new chat entry to the history
|
||||
chatHistory.chats.push({ name: inputValue, messages: [], timestamp: 5 });
|
||||
setInputValue(''); // Reset input value
|
||||
setIsEditing(false);
|
||||
chatHistory.chats.push({ name: inputValue, messages: [], timestamp: 5 })
|
||||
setInputValue("")
|
||||
};
|
||||
|
||||
// Function to select a chat from the history
|
||||
const handleHistoryClick = (index: number) => {
|
||||
setSelectedIndex(index); // Set the selected index to the clicked chat
|
||||
console.log("index", index);
|
||||
};
|
||||
setSelectedIndex(index)
|
||||
console.log("index",index);
|
||||
}
|
||||
|
||||
// Function to handle hover over a chat entry
|
||||
const handleHistoryHover = (index: number) => {
|
||||
setHoveredIndex(index); // Set hovered index
|
||||
};
|
||||
const handleHistoryHover = (index:number) => {
|
||||
setHoveredIndex(index)
|
||||
}
|
||||
|
||||
// Function to reset hovered index when not hovering
|
||||
const handleHistoryNotHover = () => {
|
||||
setHoveredIndex(null); // Reset hovered index
|
||||
};
|
||||
setHoveredIndex(null)
|
||||
}
|
||||
|
||||
// Debugging information for chat history length and selected index
|
||||
console.log("chat length", chatHistory.chats.length);
|
||||
console.log("index", chatHistory.selectedIndex);
|
||||
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; // Get the currently selected index
|
||||
const currentIndex = chatHistory.selectedIndex;
|
||||
|
||||
// Create a new copy of the chat history
|
||||
// Create a new copy of the current chat history
|
||||
const copyChats = { ...chatHistory };
|
||||
copyChats.chats = [...chatHistory.chats];
|
||||
copyChats.chats = [...chatHistory.chats]
|
||||
|
||||
// Remove the chat at the specified index
|
||||
copyChats.chats.splice(index, 1);
|
||||
// Remove the chat at the specified index
|
||||
copyChats.chats.splice(index,1)
|
||||
|
||||
// Determine the new selectedIndex
|
||||
let newSelectedIndex = currentIndex;
|
||||
// Determine 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;
|
||||
// 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;
|
||||
}
|
||||
|
||||
copyChats.selectedIndex = newSelectedIndex; // Update the selected index
|
||||
copyChats.selectedIndex = newSelectedIndex
|
||||
|
||||
// Debugging information to inspect the modified chat history
|
||||
console.log(copyChats);
|
||||
console.log(copyChats)
|
||||
|
||||
// Set the updated chat history
|
||||
setChatHistory(copyChats);
|
||||
};
|
||||
// Set the updated chat history
|
||||
setChatHistory(copyChats);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="history-background">
|
||||
<div className="history">
|
||||
<ul>
|
||||
{/* 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={{
|
||||
backgroundColor: chatHistory.selectedIndex === index ? "var(--input-button-color)" : "",
|
||||
borderRadius: "5px",
|
||||
width: index === hoveredIndex && chatHistory.chats.length > 1 ? "85%" : "100%"
|
||||
}}
|
||||
>
|
||||
{chat.name} {/* Display chat name */}
|
||||
{/* 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)} // Handle chat deletion
|
||||
disabled={!(index === hoveredIndex && chatHistory.chats.length > 1)} // Disable if not hovered
|
||||
<button id="delete-chat-button"
|
||||
onClick={()=>handleHistoryDeletion(index)}
|
||||
disabled={(index == hoveredIndex && chatHistory.chats.length >1) ? false : true}
|
||||
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>
|
||||
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>
|
||||
))}
|
||||
|
@ -118,17 +100,17 @@ const History: React.FC = () => {
|
|||
<input
|
||||
type="text"
|
||||
value={inputValue}
|
||||
onChange={handleInputChange} // Update input value as user types
|
||||
onChange={handleInputChange}
|
||||
placeholder="Enter text"
|
||||
className="chat-input"
|
||||
/>
|
||||
/>
|
||||
<button onClick={handleSaveButtonClick} className="save-btn">
|
||||
Save {/* Button to save new chat */}
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<button onClick={handleEditButtonClick} className="newChat-btn">
|
||||
New Chat {/* Button to initiate a new chat */}
|
||||
New Chat
|
||||
</button>
|
||||
)}
|
||||
</li>
|
||||
|
@ -138,4 +120,4 @@ const History: React.FC = () => {
|
|||
);
|
||||
}
|
||||
|
||||
export default History; // Exporting the History component
|
||||
export default History;
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
// Define all models that should be available.
|
||||
//#region modelist
|
||||
const modelList = {
|
||||
'Offline Fast': {
|
||||
model_type: 'local',
|
||||
|
@ -113,7 +112,7 @@ const selectedAIFunction = [
|
|||
'Language',
|
||||
'Weather'
|
||||
]
|
||||
//#region variables
|
||||
|
||||
const ModelSection: React.FC = () => {
|
||||
// Initialize state with value from localStorage or default to ''
|
||||
const [selectedModelDropdown, setSelectedModelDropdown] = useState('');
|
||||
|
@ -121,7 +120,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 = {
|
||||
|
@ -176,7 +175,7 @@ const ModelSection: React.FC = () => {
|
|||
modelClicked(model)
|
||||
}
|
||||
};
|
||||
//#region dropdown
|
||||
|
||||
// Determine the filtered models based on current radioSelection
|
||||
const filteredModels = (() => {
|
||||
let models = [];
|
||||
|
@ -242,7 +241,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,19 +1,17 @@
|
|||
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
|
||||
}
|
||||
|
||||
// Functional component definition
|
||||
const ButtonSetting: React.FC<ButtonSettingProps> = ({ label, onClick, className }) => {
|
||||
const ButtonSetting: React.FC<ButtonSettingProps> = ({ label, onClick }) => {
|
||||
return (
|
||||
<div className="settings-option"> {/* Container for the button */}
|
||||
<div className="settings-option">
|
||||
<button
|
||||
onClick={onClick} // Call the onClick function when the button is clicked
|
||||
className={`export-button ${className || ''}`} // Apply any additional classes, default to empty if not provided
|
||||
className={"export-button"} // Apply any additional classes
|
||||
>
|
||||
{label} {/* Display the label on the button */}
|
||||
</button>
|
||||
|
|
|
@ -1,28 +1,25 @@
|
|||
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); // Toggle the checked state
|
||||
setChecked(!checked);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="settings-option"> {/* Container for the checkbox setting */}
|
||||
<div className="settings-option">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox" // Checkbox input type
|
||||
checked={checked} // Set the checked state based on the prop
|
||||
onChange={handleCheckboxChange} // Call the handler on change
|
||||
type="checkbox"
|
||||
checked={checked}
|
||||
onChange={handleCheckboxChange}
|
||||
/>
|
||||
{label} {/* Display the label next to the checkbox */}
|
||||
{label}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,32 +1,29 @@
|
|||
import React from 'react';
|
||||
import React from 'react';
|
||||
|
||||
// Define the props for the ColorSetting component
|
||||
interface ColorSettingProps {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// Functional component definition
|
||||
const ColorSetting: React.FC<ColorSettingProps> = ({ name, value, setValue, cssVariable }) => {
|
||||
// Handler to change the color value
|
||||
const ColorSetting: React.FC<ColorSettingProps> = ({ name, value, setValue, cssVariable }) => {
|
||||
const handleColorChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
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
|
||||
const newColor = e.target.value;
|
||||
setValue(newColor);
|
||||
document.documentElement.style.setProperty(cssVariable, newColor);
|
||||
};
|
||||
|
||||
return (
|
||||
<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 className="settings-option">
|
||||
<p>{name}</p>
|
||||
<input
|
||||
type="color"
|
||||
value={value}
|
||||
onChange={handleColorChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
export default ColorSetting;
|
||||
export default ColorSetting;
|
||||
|
|
|
@ -1,39 +1,35 @@
|
|||
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 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
|
||||
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
|
||||
}
|
||||
|
||||
// Functional component definition
|
||||
const DropdownSetting: React.FC<DropdownSettingProps> = ({ label, value, setValue, options }) => {
|
||||
// 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
|
||||
};
|
||||
const handleSelectChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const newValue = e.target.value;
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
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>
|
||||
);
|
||||
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>
|
||||
);
|
||||
};
|
||||
|
||||
export default DropdownSetting;
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
import React from 'react';
|
||||
|
||||
const ThemeDropdown: React.FC<{
|
||||
selectedTheme: string; // Currently selected theme
|
||||
setSelectedTheme: (theme: string) => void; // Function to update the selected theme
|
||||
selectedTheme: string;
|
||||
setSelectedTheme: (theme: string) => void;
|
||||
}> = ({ selectedTheme, setSelectedTheme }) => {
|
||||
// Define available theme options
|
||||
const themeOptions = [
|
||||
{ value: 'IOMARKET', label: 'IOMARKET' },
|
||||
{ value: 'WHITE', label: 'WHITE' },
|
||||
|
@ -15,22 +14,22 @@ const ThemeDropdown: React.FC<{
|
|||
];
|
||||
|
||||
return (
|
||||
<div className="settings-option"> {/* Container for the dropdown */}
|
||||
<p>Select Theme</p> {/* Label for the dropdown */}
|
||||
<div className="settings-option">
|
||||
<p>Select Theme</p>
|
||||
<select
|
||||
value={selectedTheme} // Current selected theme
|
||||
onChange={(e) => { // Handler for dropdown changes
|
||||
const theme = e.target.value; // Get the selected value
|
||||
value={selectedTheme}
|
||||
onChange={(e) => {
|
||||
const theme = e.target.value;
|
||||
if (theme !== 'default' && typeof localStorage !== 'undefined') {
|
||||
setSelectedTheme(theme); // Update the selected theme state
|
||||
localStorage.setItem('selectedTheme', theme); // Save the theme to localStorage
|
||||
setSelectedTheme(theme);
|
||||
localStorage.setItem('selectedTheme', theme);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<option value="default">Select your style...</option> {/* Default option */}
|
||||
{themeOptions.map((option) => ( // Map through theme options to create <option> elements
|
||||
<option value="default">Select your style...</option>
|
||||
{themeOptions.map((option) => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label} {/* Display the label for the option */}
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
|
|
@ -2,29 +2,28 @@
|
|||
import React from 'react';
|
||||
|
||||
interface FontSizeSettingProps {
|
||||
fontSize: string; // The current font size as a string (e.g., "16px")
|
||||
fontSize: string; // The current font size
|
||||
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`; // Create the new font size string
|
||||
setFontSize(newSize); // Update the font size state
|
||||
document.documentElement.style.setProperty('--font-size', newSize); // Update the CSS variable
|
||||
const newSize = `${e.target.value}px`;
|
||||
setFontSize(newSize);
|
||||
document.documentElement.style.setProperty('--font-size', newSize);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="settings-option"> {/* Container for the font size setting */}
|
||||
<p>Font Size</p> {/* Label for the setting */}
|
||||
<div className="settings-option">
|
||||
<p>Font Size</p>
|
||||
<input
|
||||
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
|
||||
type="range"
|
||||
min="12"
|
||||
max="30"
|
||||
value={parseInt(fontSize, 10)} // Ensure value is a number
|
||||
onChange={handleFontSizeChange}
|
||||
/>
|
||||
<span>{fontSize}</span> {/* Display the current font size */}
|
||||
<span>{fontSize}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -12,26 +12,25 @@ const OpenSourceModeToggle: React.FC<OpenSourceModeToggleProps> = ({
|
|||
setOpenSourceMode,
|
||||
setSelectedOption
|
||||
}) => {
|
||||
// Handle toggle change event
|
||||
const handleToggleChange = () => {
|
||||
const newValue = !openSourceMode; // Toggle the current state
|
||||
setOpenSourceMode(newValue); // Update the open source mode state
|
||||
const newValue = !openSourceMode;
|
||||
setOpenSourceMode(newValue);
|
||||
|
||||
// Update radio selection based on the new openSourceMode value
|
||||
if (newValue) {
|
||||
setSelectedOption('FOSS'); // Set to FOSS if enabling open source mode
|
||||
} else {
|
||||
setSelectedOption('None'); // Set to a default value when disabling
|
||||
setSelectedOption('None'); // Or any other default value when disabling
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="settings-option"> {/* Container for the toggle setting */}
|
||||
<div className="settings-option">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox" // Checkbox for toggling open source mode
|
||||
checked={openSourceMode} // Check if the mode is currently enabled
|
||||
onChange={handleToggleChange} // Handle changes to the checkbox
|
||||
type="checkbox"
|
||||
checked={openSourceMode}
|
||||
onChange={handleToggleChange}
|
||||
/>
|
||||
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 Option */}
|
||||
{/* Offline */}
|
||||
<div
|
||||
className={`slider-option ${selectedOption === 'Offline' ? 'active' : ''}`} // Active class based on selection
|
||||
onClick={() => handleRadioChange('Offline')} // Handle selection change
|
||||
className={`slider-option ${selectedOption === 'Offline' ? 'active' : ''}`}
|
||||
onClick={() => handleRadioChange('Offline')} // Allow selection only if not in open-source mode
|
||||
>
|
||||
Offline tools{openSourceMode ? ' (FOSS)' : ''} {/* Display FOSS label if applicable */}
|
||||
Offline tools{openSourceMode ? ' (FOSS)' : ''}
|
||||
</div>
|
||||
|
||||
{/* Online Option */}
|
||||
{/* Online */}
|
||||
<div
|
||||
className={`slider-option ${selectedOption === 'Online' ? 'active' : ''}`} // Active class based on selection
|
||||
onClick={() => handleRadioChange('Online')} // Handle selection change
|
||||
className={`slider-option ${selectedOption === 'Online' ? 'active' : ''}`}
|
||||
onClick={() => handleRadioChange('Online')}
|
||||
>
|
||||
Online tools{openSourceMode ? ' (FOSS)' : ''} {/* Display FOSS label if applicable */}
|
||||
Online tools{openSourceMode ? ' (FOSS)' : ''}
|
||||
</div>
|
||||
|
||||
{/* None Option */}
|
||||
{/* None */}
|
||||
<div
|
||||
className={`slider-option ${selectedOption === 'None' ? 'active' : ''}`} // Active class based on selection
|
||||
onClick={() => handleRadioChange('None')} // Handle selection change
|
||||
className={`slider-option ${selectedOption === 'None' ? 'active' : ''}`}
|
||||
onClick={() => handleRadioChange('None')}
|
||||
>
|
||||
None{openSourceMode ? ' (FOSS)' : ''} {/* Display FOSS label if applicable */}
|
||||
None{openSourceMode ? ' (FOSS)' : ''}
|
||||
</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');
|
||||
|
||||
//#region Theme settings
|
||||
// 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,7 +122,6 @@ 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,
|
||||
|
@ -186,7 +185,6 @@ 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" },
|
||||
|
@ -221,7 +219,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' },
|
||||
|
@ -235,7 +233,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' },
|
||||
|
@ -248,7 +246,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' },
|
||||
|
@ -260,7 +258,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' },
|
||||
|
@ -278,7 +276,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' },
|
||||
|
@ -296,7 +294,7 @@ const Settings: React.FC<{ closeSettings: () => void; accountName: string }> = (
|
|||
{ value: "'Zilla Slab Highlight', serif", label: 'Zilla Slab Highlight' },
|
||||
];
|
||||
|
||||
//#region Function
|
||||
//#region Start of the code
|
||||
const handleLogout = () => {
|
||||
localStorage.clear();
|
||||
alert('Successfully logged out!');
|
||||
|
|
|
@ -10,7 +10,6 @@ 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) || "";
|
||||
}
|
||||
|
@ -40,28 +39,25 @@ 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) {
|
||||
// Only reload if the settings change was successful
|
||||
const result = await changeSettings(useName, usePassword, JSON.parse(exportSettings()))
|
||||
if (result == true) {
|
||||
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,4 +1,3 @@
|
|||
//#region IOMARKET
|
||||
export const applyIOMarketTheme = () => {
|
||||
document.documentElement.style.setProperty('--header-background-color', '#7e7e7e');
|
||||
document.documentElement.style.setProperty('--header-text-color', '#ffffff');
|
||||
|
@ -36,7 +35,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
|
||||
|
@ -74,7 +73,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
|
||||
|
@ -113,7 +112,7 @@ export const applyBlackTheme = () => {
|
|||
document.documentElement.style.setProperty('--font-size', '16px'); // Font size
|
||||
|
||||
};
|
||||
//#region CUSTOM
|
||||
|
||||
export const applyCustomTheme = () => {
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
const themeVariables = {
|
||||
|
@ -192,8 +191,6 @@ export const applyCustomTheme = () => {
|
|||
};
|
||||
}
|
||||
|
||||
//#region BASIC-CUSTOM
|
||||
|
||||
// TypeScript types for color parameters
|
||||
type Color = string;
|
||||
|
||||
|
@ -280,7 +277,6 @@ 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,98 +1,68 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
// Define the structure of a Message
|
||||
interface Message {
|
||||
role: string; // The role of the message sender (e.g., system, user, assistant)
|
||||
content: string; // The content of the message
|
||||
role: string
|
||||
content:string
|
||||
}
|
||||
|
||||
// Define the structure for each chat session
|
||||
interface ChatMessages {
|
||||
name: string; // The name or title of the chat
|
||||
messages: Message[]; // Array of messages in the chat
|
||||
timestamp: number; // Timestamp for the chat session
|
||||
name: string
|
||||
messages: Message[]
|
||||
timestamp: number
|
||||
|
||||
}
|
||||
|
||||
// Define the structure for the global chat history
|
||||
interface GlobalChatHistory {
|
||||
chats: ChatMessages[]; // Array of chat sessions
|
||||
selectedIndex: number; // Index of the currently selected chat
|
||||
chats: ChatMessages[]
|
||||
selectedIndex: number
|
||||
}
|
||||
|
||||
// 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
|
||||
};
|
||||
selectedIndex:0
|
||||
}
|
||||
let listeners: ((state: GlobalChatHistory) => void)[] = []
|
||||
|
||||
// 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; // Update the global state
|
||||
listeners.forEach((listener) => listener(globalChatHistory)); // Notify all listeners
|
||||
globalChatHistory = newState;
|
||||
listeners.forEach((listener) => listener(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
|
||||
export const useChatHistory = (): [GlobalChatHistory, (index:number)=>void, (newState:GlobalChatHistory) => void,(messageIndex: number, newContent:string)=> void] => {
|
||||
const [state, setState] = useState<GlobalChatHistory>(globalChatHistory)
|
||||
|
||||
useEffect(() => {
|
||||
// Log the initial state for debugging
|
||||
console.log("Current global chat history:", globalChatHistory);
|
||||
console.log("help", globalChatHistory);
|
||||
|
||||
// Listener to update local state when global state changes
|
||||
const listener = (newState: GlobalChatHistory) => {
|
||||
setState(newState);
|
||||
};
|
||||
setState(newState)
|
||||
}
|
||||
|
||||
listeners.push(listener); // Add the listener to the array
|
||||
listeners.push(listener)
|
||||
|
||||
// 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 }); // Update the global state
|
||||
setGlobalState({...state,selectedIndex:index})
|
||||
}
|
||||
|
||||
// Function to update a specific message in the current chat
|
||||
const updateMessage = (messageIndex: number, newContent: string) => {
|
||||
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
|
||||
const updatedChats = [...state.chats]
|
||||
const chatIndex = globalChatHistory.selectedIndex
|
||||
if (chatIndex >= 0 && chatIndex < updatedChats.length) {
|
||||
const updatedMessages = [...updatedChats[chatIndex].messages]; // Copy messages of the selected chat
|
||||
|
||||
// Check if the message index is valid
|
||||
const updatedMessages = [...updatedChats[chatIndex].messages]
|
||||
if (messageIndex >= 0 && messageIndex < updatedMessages.length) {
|
||||
// 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
|
||||
updatedMessages[messageIndex] = { ...updatedMessages[messageIndex], content: newContent }
|
||||
updatedChats[chatIndex] = { ...updatedChats[chatIndex], messages: updatedMessages }
|
||||
setGlobalState({...state, chats: updatedChats})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the current state and action functions
|
||||
return [state, setSelectedIndex, setGlobalState, updateMessage];
|
||||
return [state, setSelectedIndex, setGlobalState, updateMessage]
|
||||
}
|
|
@ -1,23 +1,24 @@
|
|||
import { ReactNode } from 'react';
|
||||
|
||||
// Metadata for the application, used for SEO and page information
|
||||
export const metadata = {
|
||||
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
|
||||
title: 'AI Assistant | Interstellar Development',
|
||||
description: 'A little AI chat that is able to assist you in little tasks',
|
||||
};
|
||||
|
||||
// RootLayout component definition
|
||||
|
||||
|
||||
|
||||
export default function RootLayout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<html lang="en"> {/* Set the language of the document */}
|
||||
<html lang="en">
|
||||
<head>
|
||||
<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 */}
|
||||
<title>{metadata.title}</title>
|
||||
<meta name="description" content={metadata.description} />
|
||||
{/* Tried adding the favicon here */}
|
||||
<link rel="icon" href="./favicon.ico" type="image/x-icon" />
|
||||
</head>
|
||||
<body>
|
||||
<main>{children}</main> {/* Render the child components inside the main element */}
|
||||
<main>{children}</main>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
|
43
app/page.tsx
43
app/page.tsx
|
@ -7,30 +7,21 @@ 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);
|
||||
|
||||
// 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");
|
||||
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 theme colors with local storage on component mount
|
||||
// Synchronize state with local storage on mount
|
||||
useEffect(() => {
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
setPrimaryColor(localStorage.getItem("primaryColor") || "#fefefe");
|
||||
|
@ -41,21 +32,18 @@ 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 the selected theme and color settings based on local storage
|
||||
// Apply theme based on selectedTheme and color settings
|
||||
useEffect(() => {
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
const savedTheme = localStorage.getItem('selectedTheme');
|
||||
|
@ -64,8 +52,8 @@ const LandingPage: React.FC = () => {
|
|||
case 'IOMARKET':
|
||||
applyIOMarketTheme();
|
||||
break;
|
||||
case 'WHITE':
|
||||
applyWhiteTheme();
|
||||
case 'WHITE':
|
||||
applyWhiteTheme();
|
||||
break;
|
||||
case 'BLACK':
|
||||
applyBlackTheme();
|
||||
|
@ -73,8 +61,8 @@ const LandingPage: React.FC = () => {
|
|||
case 'CUSTOM':
|
||||
applyCustomTheme();
|
||||
break;
|
||||
case 'BASIC-CUSTOM':
|
||||
applyBasicCustomTheme(
|
||||
case 'BASIC-CUSTOM':
|
||||
applyBasicCustomTheme(
|
||||
primaryColor,
|
||||
secondaryColor,
|
||||
accentColor,
|
||||
|
@ -83,16 +71,15 @@ const LandingPage: React.FC = () => {
|
|||
);
|
||||
break;
|
||||
default:
|
||||
applyIOMarketTheme(); // Fallback theme
|
||||
applyIOMarketTheme();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [primaryColor, secondaryColor, accentColor, basicBackgroundColor, basicTextColor]); // Apply themes whenever color states change
|
||||
}, [primaryColor, secondaryColor, accentColor, basicBackgroundColor, basicTextColor]); // Watch color states and apply themes accordingly
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Header component with props for toggling and view change */}
|
||||
<Header
|
||||
toggleDivs={toggleDivs}
|
||||
showDivs={showDivs}
|
||||
|
@ -104,14 +91,12 @@ 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,11 +4,10 @@ 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,
|
||||
|
@ -16,61 +15,50 @@ 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,
|
||||
|
@ -82,27 +70,24 @@ class AI:
|
|||
|
||||
@staticmethod
|
||||
def process_google(model, messages, return_class, access_token, api_key):
|
||||
"""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
|
||||
message = messages[-1]["content"]
|
||||
messages.pop()
|
||||
|
||||
# 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)
|
||||
|
||||
# Send the message and stream the response
|
||||
chat = model.start_chat(
|
||||
history=messages,
|
||||
)
|
||||
|
||||
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,4 +1,5 @@
|
|||
from time import sleep
|
||||
|
||||
from flask import Flask, request, jsonify
|
||||
from flask_cors import CORS
|
||||
import secrets
|
||||
|
@ -12,58 +13,53 @@ from tts import TTS
|
|||
|
||||
class API:
|
||||
def __init__(self):
|
||||
# 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
|
||||
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)
|
||||
|
||||
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) # Generate a secure access token
|
||||
access_token = secrets.token_urlsafe(self.crypt_size)
|
||||
|
||||
# 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] = "" # Initialize the response for the new session
|
||||
self.ai_response[access_token] = ""
|
||||
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() # 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
|
||||
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")
|
||||
|
||||
print(model_type) # Debugging output
|
||||
print(model_type)
|
||||
if access_token not in self.ai_response:
|
||||
return jsonify({"status": 401, "error": "Invalid access token"}) # Token validation
|
||||
return jsonify({"status": 401, "error": "Invalid access token"})
|
||||
|
||||
# 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() # Wait for the thread to complete
|
||||
sleep(0.5) # Sleep for a short duration
|
||||
thread.join()
|
||||
sleep(0.5)
|
||||
return jsonify({"status": 200})
|
||||
elif model_type == "mistral":
|
||||
print(model_type) # Debugging output
|
||||
api_key = data.get("api_key") # Get API key
|
||||
print(model_type)
|
||||
api_key = data.get("api_key")
|
||||
thread = threading.Thread(
|
||||
target=self.ai.process_mistralai,
|
||||
args=(ai_model, messages, self, access_token, api_key),
|
||||
|
@ -73,7 +69,7 @@ class API:
|
|||
sleep(0.5)
|
||||
return jsonify({"status": 200})
|
||||
elif model_type == "openai":
|
||||
api_key = data.get("api_key") # Get API key
|
||||
api_key = data.get("api_key")
|
||||
thread = threading.Thread(
|
||||
target=self.ai.process_openai,
|
||||
args=(ai_model, messages, self, access_token, api_key),
|
||||
|
@ -83,7 +79,7 @@ class API:
|
|||
sleep(0.5)
|
||||
return jsonify({"status": 200})
|
||||
elif model_type == "anthropic":
|
||||
api_key = data.get("api_key") # Get API key
|
||||
api_key = data.get("api_key")
|
||||
thread = threading.Thread(
|
||||
target=self.ai.process_anthropic,
|
||||
args=(ai_model, messages, self, access_token, api_key),
|
||||
|
@ -93,7 +89,7 @@ class API:
|
|||
sleep(0.5)
|
||||
return jsonify({"status": 200})
|
||||
elif model_type == "google":
|
||||
api_key = data.get("api_key") # Get API key
|
||||
api_key = data.get("api_key")
|
||||
thread = threading.Thread(
|
||||
target=self.ai.process_google,
|
||||
args=(ai_model, messages, self, access_token, api_key),
|
||||
|
@ -103,85 +99,79 @@ class API:
|
|||
sleep(0.5)
|
||||
return jsonify({"status": 200})
|
||||
|
||||
return jsonify({"status": 401, "error": "Invalid AI model type"}) # Model type validation
|
||||
return jsonify({"status": 401, "error": "Invalid AI model type"})
|
||||
|
||||
# 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") # Get access token from query parameters
|
||||
data = request.args.get("access_token")
|
||||
if data not in self.ai_response:
|
||||
return jsonify({"status": 401, "error": "Invalid access token"}) # Token validation
|
||||
return jsonify({"status": 200, "response": self.ai_response[data]}) # Return AI response
|
||||
return jsonify({"status": 401, "error": "Invalid access token"})
|
||||
return jsonify({"status": 200, "response": self.ai_response[data]})
|
||||
|
||||
# Route for database operations
|
||||
@self.app.route("/interstellar_ai/db", methods=["POST"])
|
||||
def db_manipulate():
|
||||
sent_data = request.get_json() # Get JSON data from the request
|
||||
action = sent_data.get("action") # Extract action type
|
||||
sent_data = request.get_json()
|
||||
action = sent_data.get("action")
|
||||
if action == "create_account":
|
||||
return jsonify({"status": 200, "response": self.db.add_user(sent_data)}) # Add user
|
||||
return jsonify({"status": 200, "response": self.db.add_user(sent_data)})
|
||||
elif action == "change_password":
|
||||
return jsonify(
|
||||
{"status": 200, "response": self.db.update_password(sent_data)} # Update password
|
||||
{"status": 200, "response": self.db.update_password(sent_data)}
|
||||
)
|
||||
elif action == "get_settings":
|
||||
return jsonify(
|
||||
{"status": 200, "response": self.db.get_settings(sent_data)} # Get user settings
|
||||
{"status": 200, "response": self.db.get_settings(sent_data)}
|
||||
)
|
||||
elif action == "change_settings":
|
||||
return jsonify(
|
||||
{"status": 200, "response": self.db.change_settings(sent_data)} # Change user settings
|
||||
{"status": 200, "response": self.db.change_settings(sent_data)}
|
||||
)
|
||||
elif action == "get_history":
|
||||
return jsonify(
|
||||
{"status": 200, "response": self.db.get_history(sent_data)} # Get user history
|
||||
{"status": 200, "response": self.db.get_history(sent_data)}
|
||||
)
|
||||
elif action == "change_history":
|
||||
return jsonify(
|
||||
{"status": 200, "response": self.db.change_history(sent_data)} # Change user history
|
||||
{"status": 200, "response": self.db.change_history(sent_data)}
|
||||
)
|
||||
elif action == "check_credentials":
|
||||
return jsonify(
|
||||
{"status": 200, "response": self.db.check_credentials(sent_data)} # Check user credentials
|
||||
{"status": 200, "response": self.db.check_credentials(sent_data)}
|
||||
)
|
||||
elif action == "delete_account":
|
||||
return jsonify(
|
||||
{"status": 200, "response": self.db.delete_user(sent_data)} # Delete user account
|
||||
{"status": 200, "response": self.db.delete_user(sent_data)}
|
||||
)
|
||||
elif action == "get_email":
|
||||
return jsonify(
|
||||
{"status": 200, "response": self.db.get_email(sent_data)} # Get user email
|
||||
{"status": 200, "response": self.db.get_email(sent_data)}
|
||||
)
|
||||
elif action == "get_name":
|
||||
return jsonify({"status": 200, "response": self.db.get_name(sent_data)}) # Get user name
|
||||
return jsonify({"status": 200, "response": self.db.get_name(sent_data)})
|
||||
|
||||
return jsonify({"status": 401, "response": "Invalid action"}) # Action validation
|
||||
return jsonify({"status": 401, "response": "Invalid action"})
|
||||
|
||||
# Route for voice recognition
|
||||
@self.app.route("/interstellar_ai/api/voice_recognition", methods=["POST"])
|
||||
def voice_recognition():
|
||||
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
|
||||
audio = request.files.get("audio")
|
||||
text = self.voice.recognition(audio)
|
||||
return jsonify({"status": 200, "response": text})
|
||||
|
||||
# Route for weather information retrieval
|
||||
@self.app.route("/interstellar_ai/api/weather", methods=["POST"])
|
||||
def get_weather():
|
||||
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
|
||||
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})
|
||||
|
||||
self.app.run(debug=True, host="0.0.0.0", port=5000) # Start the Flask app
|
||||
self.app.run(debug=True, host="0.0.0.0", port=5000)
|
||||
|
||||
# Route for Text-to-Speech conversion
|
||||
@self.app.route("/interstellar_ai/api/tts", methods=["POST"])
|
||||
def tts():
|
||||
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
|
||||
text = request.args.get("text")
|
||||
return jsonify({"status": 200, "response": self.tts.gen_tts(text)})
|
||||
|
||||
|
||||
# Initialize the API class and run the application
|
||||
api = API()
|
||||
api.run()
|
||||
|
|
82
py/db.py
82
py/db.py
|
@ -3,13 +3,12 @@ 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:
|
||||
|
@ -19,17 +18,15 @@ class DB:
|
|||
|
||||
@staticmethod
|
||||
def hash_password(password):
|
||||
# Hash the password with a salt for secure storage
|
||||
salt = "your_secret_salt" # Consider using a secure random salt
|
||||
salt = "your_secret_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) # Hash the password
|
||||
hashed_password = self.hash_password(password)
|
||||
user_data = {
|
||||
"hashed_password": hashed_password,
|
||||
"email": email,
|
||||
|
@ -38,123 +35,112 @@ class DB:
|
|||
}
|
||||
if username not in self.database:
|
||||
self.database[username] = user_data
|
||||
self.save_database() # Save changes to the database
|
||||
self.save_database()
|
||||
return True
|
||||
return False # User already exists
|
||||
return False
|
||||
|
||||
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 # Invalid credentials
|
||||
return False
|
||||
|
||||
del self.database[username] # Remove user from database
|
||||
self.save_database() # Save changes
|
||||
del self.database[username]
|
||||
self.save_database()
|
||||
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 # Invalid credentials
|
||||
return False
|
||||
|
||||
hashed_new_password = self.hash_password(new_password) # Hash the new password
|
||||
hashed_new_password = self.hash_password(new_password)
|
||||
self.database[username].update({"hashed_password": hashed_new_password})
|
||||
self.save_database() # Save changes
|
||||
self.save_database()
|
||||
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 # User not found
|
||||
return False
|
||||
|
||||
stored_hashed_password = self.database[username]["hashed_password"]
|
||||
entered_hashed_password = self.hash_password(password)
|
||||
return stored_hashed_password == entered_hashed_password # Check hashed password
|
||||
return stored_hashed_password == entered_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 # Invalid credentials
|
||||
return False
|
||||
|
||||
self.database[username]["settings"] = data.get("data") # Update settings
|
||||
self.save_database() # Save changes
|
||||
self.database[username]["settings"] = data.get("data")
|
||||
self.save_database()
|
||||
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 # Invalid credentials
|
||||
return None
|
||||
|
||||
send_back = self.database[username].get("settings") # Get settings
|
||||
send_back = self.database[username].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 # Invalid credentials
|
||||
return False
|
||||
|
||||
self.database[username]["history"] = data.get("data") # Update history
|
||||
self.save_database() # Save changes
|
||||
self.database[username]["history"] = data.get("data")
|
||||
self.save_database()
|
||||
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 # Invalid credentials
|
||||
return None
|
||||
|
||||
send_back = self.database[username].get("history") # Get history
|
||||
send_back = self.database[username].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 # Invalid credentials
|
||||
return None
|
||||
|
||||
send_back = self.database[username].get("email") # Get email
|
||||
send_back = self.database[username].get("email")
|
||||
return send_back
|
||||
|
||||
def get_name(self, data):
|
||||
# Retrieve username if credentials are valid
|
||||
if not self.check_credentials(data):
|
||||
return None # Invalid credentials
|
||||
return None
|
||||
|
||||
send_back = self.ensure_username(data) # Get username
|
||||
send_back = self.ensure_username(data)
|
||||
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) # Save to CouchDB
|
||||
db.save(self.database)
|
||||
|
||||
else:
|
||||
with open("database.json", "w") as file:
|
||||
json.dump(self.database, file) # Save to JSON file
|
||||
json.dump(self.database, 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 # Load from CouchDB
|
||||
self.database = db
|
||||
else:
|
||||
server.create("interstellar_ai") # Create database if it doesn't exist
|
||||
server.create("interstellar_ai")
|
||||
db = server.database("interstellar_ai")
|
||||
db.save(self.database) # Save initial empty database
|
||||
db.save(self.database)
|
||||
else:
|
||||
try:
|
||||
with open("database.json", "r") as file:
|
||||
self.database = json.load(file) # Load from JSON file
|
||||
self.database = json.load(file)
|
||||
except FileNotFoundError:
|
||||
pass # File not found, do nothing
|
||||
pass
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import pyttsx3
|
||||
|
||||
|
||||
class TTS:
|
||||
@staticmethod
|
||||
def gen_tts(text):
|
||||
|
|
14
py/voice.py
14
py/voice.py
|
@ -6,28 +6,20 @@ 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) # Reset the buffer pointer to the start
|
||||
wav_io.seek(0)
|
||||
|
||||
# Load the Whisper model
|
||||
model_size = "base" # Specify the model size
|
||||
model_size = "base"
|
||||
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() # Strip any leading/trailing whitespace
|
||||
result = transcription.strip()
|
||||
return result
|
||||
|
|
|
@ -15,7 +15,6 @@ 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…
Add table
Add a link
Reference in a new issue