Compare commits

...

15 commits

Author SHA1 Message Date
9577d2f252 Merge pull request 'Backend and frontend tweaks' (#16) from React-Group/interstellar_ai:main into main
Reviewed-on: https://interstellardevelopment.org/code/code/sageTheDm/interstellar_ai/pulls/16
2024-09-24 15:02:53 +02:00
21589915ff Merge pull request 'Settings changes' (#40) from sageTheDm/interstellar_ai:main into main
Reviewed-on: https://interstellardevelopment.org/code/code/React-Group/interstellar_ai/pulls/40
2024-09-24 15:02:31 +02:00
19a9567a5d Merge pull request 'main' (#39) from YasinOnm08/interstellar_ai:main into main
Reviewed-on: https://interstellardevelopment.org/code/code/React-Group/interstellar_ai/pulls/39
2024-09-24 14:55:13 +02:00
b539c3592a started hamburger menu 2024-09-24 14:54:39 +02:00
6efa73ee42 Merge pull request 'main' (#38) from YasinOnm08/interstellar_ai:main into main
Reviewed-on: https://interstellardevelopment.org/code/code/React-Group/interstellar_ai/pulls/38
2024-09-24 14:19:12 +02:00
Patrick_Pluto
6d4ac29d83 Weather API 2024-09-24 14:18:57 +02:00
615a58ce28 no input while generating/empty 2024-09-24 13:50:46 +02:00
37177a7856 OMG FINALY WORKING LIVE TEXT 2024-09-24 10:58:14 +02:00
d037439b4c no empty msg 2024-09-24 10:22:50 +02:00
8821836f3d Merge branch 'main' of interstellardevelopment.org:YasinOnm08/interstellar_ai 2024-09-24 09:58:24 +02:00
2243103f8d Merge pull request 'main' (#19) from React-Group/interstellar_ai:main into main
Reviewed-on: https://interstellardevelopment.org/code/code/YasinOnm08/interstellar_ai/pulls/19
2024-09-24 09:58:19 +02:00
899b2b11c6 Merge branch 'main' of interstellardevelopment.org:YasinOnm08/interstellar_ai 2024-09-24 09:53:31 +02:00
07f109f3c1 Merge pull request 'main' (#18) from React-Group/interstellar_ai:main into main
Reviewed-on: https://interstellardevelopment.org/code/code/YasinOnm08/interstellar_ai/pulls/18
2024-09-24 09:53:24 +02:00
b4713ea3b2 Only 1 msg at a time 2024-09-24 09:51:16 +02:00
b034292e64 Merge pull request 'Backend & CSS tweaks' (#17) from React-Group/interstellar_ai:main into main
Reviewed-on: https://interstellardevelopment.org/code/code/YasinOnm08/interstellar_ai/pulls/17
2024-09-23 16:58:15 +02:00
9 changed files with 181 additions and 55 deletions

View file

@ -3,7 +3,6 @@ import React, { useEffect, useRef, useState } from "react";
import ConversationFrontend from "../components/ConversationFrontend"; import ConversationFrontend from "../components/ConversationFrontend";
import InputFrontend from "../components/InputFrontend"; import InputFrontend from "../components/InputFrontend";
import axios from "axios"; import axios from "axios";
import { log } from 'console';
const InputOutputBackend: React.FC = () => { const InputOutputBackend: React.FC = () => {
type Message = { type Message = {
@ -16,6 +15,7 @@ const InputOutputBackend: React.FC = () => {
const getWorkerRef = useRef<Worker | null>(null) const getWorkerRef = useRef<Worker | null>(null)
const [messages, setMessages] = useState<Message[]>([{role:"assistant", content:"Hello! How can I help you?"}]) const [messages, setMessages] = useState<Message[]>([{role:"assistant", content:"Hello! How can I help you?"}])
const [liveMessage, setLiveMessage] = useState("") const [liveMessage, setLiveMessage] = useState("")
const [inputDisabled, setInputDisabled] = useState(false)
console.log(messages); console.log(messages);
@ -37,8 +37,10 @@ const InputOutputBackend: React.FC = () => {
postWorkerRef.current.onmessage = (event) => { postWorkerRef.current.onmessage = (event) => {
const status = event.data.status const status = event.data.status
if (status == 200) { if (status == 200) {
setInputDisabled(false)
endGetWorker() endGetWorker()
} else if (status == 500) { } else if (status == 500) {
setInputDisabled(false)
if (getWorkerRef.current) { if (getWorkerRef.current) {
addMessage("assistant", "There was an Error with the AI response") addMessage("assistant", "There was an Error with the AI response")
getWorkerRef.current.postMessage("terminate") getWorkerRef.current.postMessage("terminate")
@ -86,11 +88,15 @@ const InputOutputBackend: React.FC = () => {
if (getWorkerRef.current) { if (getWorkerRef.current) {
getWorkerRef.current.postMessage({action:"terminate"}) getWorkerRef.current.postMessage({action:"terminate"})
getWorkerRef.current.terminate() getWorkerRef.current.terminate()
getWorkerRef.current = null
console.log(messages); console.log(messages);
} }
} }
const editLastMessage = (newContent: string) => { const editLastMessage = (newContent: string) => {
if (newContent == "") {
newContent = "Generating answer..."
}
setMessages((prevMessages) => { setMessages((prevMessages) => {
const updatedMessages = prevMessages.slice(); // Create a shallow copy of the current messages const updatedMessages = prevMessages.slice(); // Create a shallow copy of the current messages
if (updatedMessages.length > 0) { if (updatedMessages.length > 0) {
@ -109,11 +115,16 @@ const InputOutputBackend: React.FC = () => {
setMessages(previous => [...previous,{role,content}]) setMessages(previous => [...previous,{role,content}])
} }
const handleSendClick = (inputValue: string) => { const handleSendClick = (inputValue: string) => {
if (postWorkerRef.current) { if (inputValue != "") {
addMessage("user", inputValue) if (!inputDisabled) {
console.log("input:",inputValue); setInputDisabled(true)
postWorkerRef.current.postMessage({messages:[...messages, { role: "user", content: inputValue }], ai_model:"phi3.5", access_token:accessToken}) if (postWorkerRef.current) {
startGetWorker() addMessage("user", inputValue)
console.log("input:",inputValue);
postWorkerRef.current.postMessage({messages:[...messages, { role: "user", content: inputValue }], ai_model:"phi3.5", access_token:accessToken})
startGetWorker()
}
}
} }
} }
@ -145,6 +156,7 @@ const InputOutputBackend: React.FC = () => {
message="" message=""
onSendClick={handleSendClick} onSendClick={handleSendClick}
onMicClick={handleMicClick} onMicClick={handleMicClick}
inputDisabled={inputDisabled}
/> />
</div> </div>
) )

View file

@ -29,6 +29,6 @@ const fetchData = () => {
.catch(error => { .catch(error => {
console.log('Error fetching data:', error); console.log('Error fetching data:', error);
postMessage({error:"failed fetching data"}) postMessage({error:"failed fetching data"})
setTimeout(() => fetchData(),1000)
}) })
} }

View file

@ -2,7 +2,7 @@ import axios from "axios";
onmessage = (e) => { onmessage = (e) => {
const { messages = [{ role: "assistant", content: "Hello! How can I help you?" }], ai_model = "phi3.5", access_token } = e.data const { messages = [{ role: "assistant", content: "Hello! How can I help you?" }], ai_model = "phi3.5", access_token } = e.data
messages.unshift({ role: "system", content: "You are a Helpful assistant" }) messages.unshift({ role: "system", content: "You are a Helpful assistant. you give short answers" })
const Message = { const Message = {
messages: messages, messages: messages,

View file

@ -1,5 +1,5 @@
// Header.tsx // Header.tsx
import React from 'react'; import React, { useState } from 'react';
import Login from './Login'; import Login from './Login';
interface HeaderProps { interface HeaderProps {
@ -11,29 +11,32 @@ interface HeaderProps {
} }
const Header: React.FC<HeaderProps> = ({ onViewChange, showDivs, toggleDivs, showHistoryModelsToggle, showToggle }) => { const Header: React.FC<HeaderProps> = ({ onViewChange, showDivs, toggleDivs, showHistoryModelsToggle, showToggle }) => {
const [menuOpen, setMenuOpen] = useState(false)
const toggleMenu = () => {
setMenuOpen(!menuOpen)
}
return ( return (
<> <>
<header> <header>
<ul> <div className={`hamburger ${menuOpen ? "open" : ""}`} onClick={toggleMenu}>
<li> <span></span>
<button onClick={() => onViewChange('AI')} className="header-button header-logo"> <span></span>
<img src="/img/logo.png" alt="logo" className="header-logo" /> <span></span>
</button> </div>
</li> <nav className={`nav-links ${menuOpen ? "active":""}`}>
<li> <button onClick={() => onViewChange('FAQ')} className="nav-btn">FAQ</button>
<button onClick={() => onViewChange('FAQ')} className="header-button">FAQ</button> <button onClick={() => onViewChange('Documentation')} className="nav-btn">Documentation</button>
</li> {showToggle && showHistoryModelsToggle && (
<li> <button onClick={toggleDivs} className="nav-btn">
<button onClick={() => onViewChange('Documentation')} className="header-button">Documentation</button>
</li>
{showToggle && showHistoryModelsToggle && (
<li>
<button onClick={toggleDivs} className="header-button">
{showDivs ? 'Hide History/Models' : 'Show History/Models'} {showDivs ? 'Hide History/Models' : 'Show History/Models'}
</button> </button>
</li> )}
)} </nav>
</ul> {/* <button onClick={() => onViewChange('AI')} className="header-button header-logo">
<img src="/img/logo.png" alt="logo" className="header-logo" />
</button> */}
<Login /> <Login />
</header> </header>
</> </>

View file

@ -4,21 +4,25 @@ interface InputProps {
message: string; message: string;
onSendClick: (message: string) => void; onSendClick: (message: string) => void;
onMicClick: () => void; onMicClick: () => void;
inputDisabled:boolean
} }
const InputFrontend = React.forwardRef<HTMLDivElement, InputProps>( const InputFrontend = React.forwardRef<HTMLDivElement, InputProps>(
({ message, onSendClick, onMicClick }, ref: ForwardedRef<HTMLDivElement>) => { ({ message, onSendClick, onMicClick, inputDisabled }, ref: ForwardedRef<HTMLDivElement>) => {
const [inputValue, setInputValue] = useState(''); const [inputValue, setInputValue] = useState('');
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value); setInputValue(e.target.value);
}; };
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => { const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (event.key === 'Enter') { if (!inputDisabled) {
onSendClick(inputValue); // Call the function passed via props if (event.key === 'Enter') {
setInputValue(''); // Optionally clear input after submission onSendClick(inputValue); // Call the function passed via props
event.preventDefault(); // Prevent default action (e.g., form submission) setInputValue(''); // Optionally clear input after submission
event.preventDefault(); // Prevent default action (e.g., form submission)
}
} }
}; };
@ -32,7 +36,7 @@ const InputFrontend = React.forwardRef<HTMLDivElement, InputProps>(
onChange={handleInputChange} onChange={handleInputChange}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
/> />
<button type="button" onClick={() => onSendClick(inputValue)}> <button type="button" onClick={() => onSendClick(inputValue)} disabled={inputDisabled?true:false}>
<img src="/img/send.svg" alt="send" /> <img src="/img/send.svg" alt="send" />
</button> </button>
<button type="button" onClick={onMicClick}> <button type="button" onClick={onMicClick}>

View file

@ -10,29 +10,84 @@ header {
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
z-index: 1000; z-index: 1000;
font-family: var(--font-family); font-family: var(--font-family);
display: flex;
justify-content: space-between;
align-items: center;
} }
header li { .nav-links{
display: inline-block; display: flex;
margin: 0 15px; gap: 15px;
} }
header img { .nav-btn{
height: 2em; background: transparent;
vertical-align: middle;
}
header a,
header li button {
color: var(--header-text-color); /* Use the new header text color */
text-decoration: none;
transition: color 0.3s;
border: none; border: none;
background-color: transparent; cursor: pointer;
font-size: 1em; /* color */
} }
header a:hover, .nav-btn:hover{
header li button:hover { /* color */
color: var(--input-button-color); /* Keep the hover color */
} }
.hamburger{
display: none;
flex-direction: column;
cursor: pointer;
}
.hamburger span{
width: 25px;
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;
}
}

View file

@ -4,16 +4,18 @@ import secrets
import threading import threading
from ai import AI from ai import AI
from db import DB from db import DB
from weather import Weather
from voice import VoiceRecognition from voice import VoiceRecognition
class API: class API:
def __init__(self): def __init__(self):
self.crypt_size = 1 self.crypt_size = 4096
self.app = Flask(__name__) self.app = Flask(__name__)
self.ai_response = {} self.ai_response = {}
self.ai = AI() self.ai = AI()
self.db = DB() self.db = DB()
self.weather = Weather()
self.voice = VoiceRecognition() self.voice = VoiceRecognition()
self.db.load_database() self.db.load_database()
self.ai_response_lock = threading.Lock() self.ai_response_lock = threading.Lock()
@ -23,8 +25,12 @@ class API:
@self.app.route('/interstellar_ai/api/ai_create', methods=['GET']) @self.app.route('/interstellar_ai/api/ai_create', methods=['GET'])
def create_ai(): def create_ai():
access_token = secrets.token_urlsafe(self.crypt_size) access_token = secrets.token_urlsafe(self.crypt_size)
self.ai_response[access_token] = ""
return jsonify({'status': 200, 'access_token': access_token}) if access_token not in self.ai_response:
self.ai_response[access_token] = ""
return jsonify({'status': 200, 'access_token': access_token})
return jsonify({'status': 401, 'error': 'An error occurred, please try again.'})
@self.app.route('/interstellar_ai/api/ai_send', methods=['POST']) @self.app.route('/interstellar_ai/api/ai_send', methods=['POST'])
def send_ai(): def send_ai():
@ -99,6 +105,12 @@ class API:
return jsonify({'status': 401, 'response': "Invalid type"}) return jsonify({'status': 401, 'response': "Invalid type"})
@self.app.route('/interstellar_ai/api/weather', methods=['POST'])
def get_weather():
unit_type = request.args.get('unit_type')
city = request.args.get('city')
return jsonify({'status': 200, 'response': self.weather.getweather(unit_type, city)})
self.app.run(debug=True, host='0.0.0.0', port=5000) self.app.run(debug=True, host='0.0.0.0', port=5000)

View file

@ -8,4 +8,5 @@ pyOpenSSL
SpeechRecognition SpeechRecognition
PocketSphinx PocketSphinx
google-cloud-speech google-cloud-speech
google-generativeai google-generativeai
python-weather

39
py/weather.py Normal file
View file

@ -0,0 +1,39 @@
import python_weather
class Weather:
@staticmethod
async def getweather(unit_type, city):
if unit_type == "imperial":
unit_type = python_weather.IMPERIAL
elif unit_type == "metric":
unit_type = python_weather.METRIC
async with python_weather.Client(unit=unit_type) as client:
weather = await client.get(city)
data = {
'temperature': weather.temperature,
'humidity': weather.humidity,
'unit': weather.unit,
'datetime': weather.datetime,
'coordinates': weather.coordinates,
'country': weather.country,
'daily_forecasts': weather.daily_forecasts,
'description': weather.description,
'feels_like': weather.feels_like,
'kind': weather.kind,
'local_population': weather.local_population,
'locale': weather.locale,
'location': weather.location,
'precipitation': weather.precipitation,
'pressure': weather.pressure,
'region': weather.region,
'ultraviolet': weather.ultraviolet,
'visibility': weather.visibility,
'wind_direction': weather.wind_direction,
'wind_speed': weather.wind_speed,
}
return data