Backend and frontend tweaks #16

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

View file

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

View file

@ -2,7 +2,7 @@ import axios from "axios";
onmessage = (e) => {
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 = {
messages: messages,

View file

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

View file

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

View file

@ -10,29 +10,84 @@ header {
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
z-index: 1000;
font-family: var(--font-family);
display: flex;
justify-content: space-between;
align-items: center;
}
header li {
display: inline-block;
margin: 0 15px;
.nav-links{
display: flex;
gap: 15px;
}
header img {
height: 2em;
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;
.nav-btn{
background: transparent;
border: none;
background-color: transparent;
font-size: 1em;
cursor: pointer;
/* color */
}
header a:hover,
header li button:hover {
color: var(--input-button-color); /* Keep the hover color */
.nav-btn: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
from ai import AI
from db import DB
from weather import Weather
from voice import VoiceRecognition
class API:
def __init__(self):
self.crypt_size = 1
self.crypt_size = 4096
self.app = Flask(__name__)
self.ai_response = {}
self.ai = AI()
self.db = DB()
self.weather = Weather()
self.voice = VoiceRecognition()
self.db.load_database()
self.ai_response_lock = threading.Lock()
@ -23,8 +25,12 @@ class API:
@self.app.route('/interstellar_ai/api/ai_create', methods=['GET'])
def create_ai():
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'])
def send_ai():
@ -99,6 +105,12 @@ class API:
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)

View file

@ -8,4 +8,5 @@ pyOpenSSL
SpeechRecognition
PocketSphinx
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