Merge pull request 'Backend and CSS' (#17) from React-Group/interstellar_ai:main into main
Reviewed-on: https://interstellardevelopment.org/code/code/sageTheDm/interstellar_ai/pulls/17
This commit is contained in:
commit
8e20971ded
12 changed files with 742 additions and 174 deletions
16
app/backend/database.ts
Normal file
16
app/backend/database.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const sendToDatabase = (data: any) => {
|
||||||
|
axios.post("http://localhost:5000/interstellar_ai/db", data)
|
||||||
|
.then(response => {
|
||||||
|
const status = response.data.status
|
||||||
|
console.log(status);
|
||||||
|
postMessage({ status })
|
||||||
|
console.log('message posted');
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log("Error calling Database:", error)
|
||||||
|
postMessage({ status: 500 })
|
||||||
|
})
|
||||||
|
}
|
|
@ -17,6 +17,11 @@ const Header: React.FC<HeaderProps> = ({ onViewChange, showDivs, toggleDivs, sho
|
||||||
setMenuOpen(!menuOpen)
|
setMenuOpen(!menuOpen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const buttonClicked = (page: "AI" | "Documentation" | "FAQ") => {
|
||||||
|
onViewChange(page)
|
||||||
|
toggleMenu()
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<header>
|
<header>
|
||||||
|
@ -26,18 +31,20 @@ const Header: React.FC<HeaderProps> = ({ onViewChange, showDivs, toggleDivs, sho
|
||||||
<span></span>
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
<nav className={`nav-links ${menuOpen ? "active":""}`}>
|
<nav className={`nav-links ${menuOpen ? "active":""}`}>
|
||||||
<button onClick={() => onViewChange('FAQ')} className="nav-btn">FAQ</button>
|
<button onClick={() => buttonClicked("FAQ")} className="nav-btn">FAQ</button>
|
||||||
<button onClick={() => onViewChange('Documentation')} className="nav-btn">Documentation</button>
|
<button onClick={() => buttonClicked("Documentation")} className="nav-btn">Documentation</button>
|
||||||
{showToggle && showHistoryModelsToggle && (
|
{showToggle && showHistoryModelsToggle && (
|
||||||
<button onClick={toggleDivs} className="nav-btn">
|
<button onClick={toggleDivs} className="nav-btn">
|
||||||
{showDivs ? 'Hide History/Models' : 'Show History/Models'}
|
{showDivs ? 'Hide History/Models' : 'Show History/Models'}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</nav>
|
</nav>
|
||||||
{/* <button onClick={() => onViewChange('AI')} className="header-button header-logo">
|
<button onClick={() => onViewChange('AI')} className="header-button header-logo">
|
||||||
<img src="/img/logo.png" alt="logo" className="header-logo" />
|
<p>1</p>
|
||||||
</button> */}
|
</button>
|
||||||
<Login />
|
<div className="login-button">
|
||||||
|
<Login />
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -53,11 +53,10 @@ const Login: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{/* Login or Settings Button */}
|
{/* Login or Settings Button */}
|
||||||
<div className="login-button">
|
|
||||||
<button onClick={isLoggedIn ? toggleSettingsPopup : toggleLoginPopup}>
|
<button onClick={isLoggedIn ? toggleSettingsPopup : toggleLoginPopup}>
|
||||||
{isLoggedIn ? 'Settings' : 'Log In'}
|
{isLoggedIn ? 'Settings' : 'Log In'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Conditional rendering of the Login Popup */}
|
{/* Conditional rendering of the Login Popup */}
|
||||||
{showLoginPopup && (
|
{showLoginPopup && (
|
||||||
|
|
|
@ -1,34 +1,3 @@
|
||||||
/* Container for the login layout */
|
|
||||||
.login-container {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 3fr; /* 1fr for sidebar, 3fr for main content */
|
|
||||||
grid-auto-flow: column;
|
|
||||||
overflow-x: hidden;
|
|
||||||
height: 100%; /* Ensure it takes full height */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Button for login action */
|
|
||||||
.login-button {
|
|
||||||
position: absolute;
|
|
||||||
top: 5px;
|
|
||||||
right: 10px;
|
|
||||||
z-index: 9999; /* Highest z-index for the login button */
|
|
||||||
margin: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-button button {
|
|
||||||
padding: 10px 20px;
|
|
||||||
background-color: var(--input-button-color);
|
|
||||||
color: var(--text-color);
|
|
||||||
border: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-button button:hover {
|
|
||||||
background-color: var(--input-button-hover-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Overlay for popup - full screen and centered */
|
/* Overlay for popup - full screen and centered */
|
||||||
.popup-overlay {
|
.popup-overlay {
|
||||||
|
|
|
@ -1,93 +1,29 @@
|
||||||
header {
|
header{
|
||||||
background-color: var(--header-background-color); /* Use the new header background color */
|
position: absolute;
|
||||||
color: var(--header-text-color); /* Use the new header text color */
|
padding: 0 20px;
|
||||||
width: 100%;
|
|
||||||
text-decoration: none;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
padding: 10px 20px;
|
width: 100%;
|
||||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
height: 10vh;
|
||||||
z-index: 1000;
|
|
||||||
font-family: var(--font-family);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-links{
|
|
||||||
display: flex;
|
|
||||||
gap: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-btn{
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
/* color */
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-btn:hover{
|
|
||||||
/* color */
|
|
||||||
}
|
|
||||||
|
|
||||||
.hamburger{
|
.hamburger{
|
||||||
display: none;
|
display: none;
|
||||||
flex-direction: column;
|
}
|
||||||
|
|
||||||
|
.login-button button{
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: var(--input-button-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hamburger span{
|
.login-button button:hover {
|
||||||
width: 25px;
|
background-color: var(--input-button-hover-color);
|
||||||
height: 3px;
|
|
||||||
background-color: var(--header-text-color);
|
|
||||||
margin: 4px;
|
|
||||||
transition: 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hamburger.open span:nth-child(1){
|
|
||||||
transform: rotate(45deg) translate(5px, 5px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hamburger.open span:nth-child(2){
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hamburger.open span:nth-child(3){
|
|
||||||
transform: rotate(-45deg) translate(5px, -5px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-button{
|
|
||||||
|
|
||||||
}
|
|
||||||
.header-button img{
|
|
||||||
height: 8vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width:768px) {
|
|
||||||
.nav-links{
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 60px;
|
|
||||||
right: 0;
|
|
||||||
/* background color */
|
|
||||||
width: 100%;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-links.active{
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-btn{
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hamburger{
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -8,8 +8,6 @@
|
||||||
|
|
||||||
/* Header styles */
|
/* Header styles */
|
||||||
header {
|
header {
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -36,17 +34,6 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
header li button {
|
|
||||||
margin: 2px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
header li img {
|
|
||||||
height: 1.5em;
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Left panel styles */
|
/* Left panel styles */
|
||||||
.left-panel {
|
.left-panel {
|
||||||
display: hidden; /* Initially hidden */
|
display: hidden; /* Initially hidden */
|
||||||
|
@ -120,6 +107,18 @@
|
||||||
.login-button button{
|
.login-button button{
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hamburger.open{
|
||||||
|
margin-top: 0.5vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links{
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Responsive adjustments for the settings */
|
/* Responsive adjustments for the settings */
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
--conversation-background-color: #79832e; /* Background color for conversation container */
|
--conversation-background-color: #79832e; /* Background color for conversation container */
|
||||||
--doc-background-color: #ffffff; /* Background color for documents */
|
--doc-background-color: #ffffff; /* Background color for documents */
|
||||||
--close-button-color: red;
|
--close-button-color: red;
|
||||||
|
--burger-menu-background-color: #79832e;
|
||||||
|
|
||||||
/* FAQ Colors */
|
/* FAQ Colors */
|
||||||
--faq-background-color: #474D22; /* Background color for FAQ section */
|
--faq-background-color: #474D22; /* Background color for FAQ section */
|
||||||
|
|
28
main.js
Normal file
28
main.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
const { app, BrowserWindow } = require('electron');
|
||||||
|
|
||||||
|
function createWindow() {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
nodeIntegration: true,
|
||||||
|
},
|
||||||
|
autoHideMenuBar: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
win.loadURL('http://localhost:3000');
|
||||||
|
}
|
||||||
|
|
||||||
|
app.whenReady().then(createWindow);
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow();
|
||||||
|
}
|
||||||
|
});
|
615
package-lock.json
generated
615
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -2,15 +2,18 @@
|
||||||
"name": "interstellar_ai",
|
"name": "interstellar_ai",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint"
|
"lint": "next lint",
|
||||||
|
"electron": "npx electron . & next dev"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mistralai/mistralai": "^1.0.4",
|
"@mistralai/mistralai": "^1.0.4",
|
||||||
"axios": "^1.7.7",
|
"axios": "^1.7.7",
|
||||||
|
"electron": "^32.1.2",
|
||||||
"fs": "^0.0.1-security",
|
"fs": "^0.0.1-security",
|
||||||
"next": "14.2.12",
|
"next": "14.2.12",
|
||||||
"ollama": "^0.5.9",
|
"ollama": "^0.5.9",
|
||||||
|
|
66
py/db.py
66
py/db.py
|
@ -1,11 +1,21 @@
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
|
import pycouchdb
|
||||||
|
|
||||||
|
|
||||||
class DB:
|
class DB:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.database = {}
|
self.database = {}
|
||||||
|
|
||||||
|
def ensure_username(self, data):
|
||||||
|
if hasattr(data, 'username'):
|
||||||
|
return data.get['username']
|
||||||
|
elif hasattr(data, 'email'):
|
||||||
|
for index, entry in self.database:
|
||||||
|
if entry.get['email'] == data.get['email']:
|
||||||
|
return index
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def hash_password(password):
|
def hash_password(password):
|
||||||
salt = "your_secret_salt"
|
salt = "your_secret_salt"
|
||||||
|
@ -15,12 +25,26 @@ class DB:
|
||||||
def add_user(self, data):
|
def add_user(self, data):
|
||||||
username = data.get['username']
|
username = data.get['username']
|
||||||
password = data.get['password']
|
password = data.get['password']
|
||||||
|
email = data.get['email']
|
||||||
hashed_password = self.hash_password(password)
|
hashed_password = self.hash_password(password)
|
||||||
user_data = {"hashed_password": hashed_password}
|
user_data = {"hashed_password": hashed_password, "email": email, "data": None}
|
||||||
self.database[username] = user_data
|
if username not in self.database:
|
||||||
|
self.database[username] = user_data
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def delete_user(self, data):
|
||||||
|
username = self.ensure_username(data)
|
||||||
|
data = data.get['data']
|
||||||
|
if not self.check_credentials(data):
|
||||||
|
return False
|
||||||
|
|
||||||
|
del self.database[username]
|
||||||
|
self.save_database()
|
||||||
|
return True
|
||||||
|
|
||||||
def change_data(self, data):
|
def change_data(self, data):
|
||||||
username = data.get['username']
|
username = self.ensure_username(data)
|
||||||
data = data.get['data']
|
data = data.get['data']
|
||||||
if not self.check_credentials(data):
|
if not self.check_credentials(data):
|
||||||
return False
|
return False
|
||||||
|
@ -30,7 +54,7 @@ class DB:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def update_password(self, data):
|
def update_password(self, data):
|
||||||
username = data.get['username']
|
username = self.ensure_username(data)
|
||||||
new_password = data.get['new_password']
|
new_password = data.get['new_password']
|
||||||
if not self.check_credentials(data):
|
if not self.check_credentials(data):
|
||||||
return False
|
return False
|
||||||
|
@ -41,7 +65,7 @@ class DB:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def check_credentials(self, data):
|
def check_credentials(self, data):
|
||||||
username = data.get['username']
|
username = self.ensure_username(data)
|
||||||
password = data.get['password']
|
password = data.get['password']
|
||||||
if username not in self.database:
|
if username not in self.database:
|
||||||
return False
|
return False
|
||||||
|
@ -51,7 +75,7 @@ class DB:
|
||||||
return stored_hashed_password == entered_hashed_password
|
return stored_hashed_password == entered_hashed_password
|
||||||
|
|
||||||
def get_data(self, data):
|
def get_data(self, data):
|
||||||
username = data.get['username']
|
username = self.ensure_username(data)
|
||||||
if not self.check_credentials(data):
|
if not self.check_credentials(data):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -59,12 +83,28 @@ class DB:
|
||||||
return send_back
|
return send_back
|
||||||
|
|
||||||
def save_database(self):
|
def save_database(self):
|
||||||
with open("database.json", 'w') as file:
|
if os.environ.get('PRODUCTION') == "YES":
|
||||||
json.dump(self.database, file)
|
server = pycouchdb.Server("http://admin:admin@localhost:5984/")
|
||||||
|
db = server.database("interstellar_ai")
|
||||||
|
db.save(self.database)
|
||||||
|
|
||||||
|
else:
|
||||||
|
with open("database.json", 'w') as file:
|
||||||
|
json.dump(self.database, file)
|
||||||
|
|
||||||
def load_database(self):
|
def load_database(self):
|
||||||
try:
|
if os.environ.get('PRODUCTION') == "YES":
|
||||||
with open("database.json", 'r') as file:
|
server = pycouchdb.Server("http://admin:admin@localhost:5984/")
|
||||||
self.database = json.load(file)
|
db = server.database("interstellar_ai")
|
||||||
except FileNotFoundError:
|
if db:
|
||||||
pass
|
self.database = db
|
||||||
|
else:
|
||||||
|
server.create("interstellar_ai")
|
||||||
|
db = server.database("interstellar_ai")
|
||||||
|
db.save(self.database)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
with open("database.json", 'r') as file:
|
||||||
|
self.database = json.load(file)
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
|
@ -10,3 +10,4 @@ PocketSphinx
|
||||||
google-cloud-speech
|
google-cloud-speech
|
||||||
google-generativeai
|
google-generativeai
|
||||||
python-weather
|
python-weather
|
||||||
|
pycouchdb
|
Loading…
Reference in a new issue