forked from React-Group/interstellar_ai
		
	Compare commits
	
		
			15 commits
		
	
	
		
			c3f2e05978
			...
			9577d2f252
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 9577d2f252 | |||
| 21589915ff | |||
| 19a9567a5d | |||
| b539c3592a | |||
| 6efa73ee42 | |||
|   | 6d4ac29d83 | ||
| 615a58ce28 | |||
| 37177a7856 | |||
| d037439b4c | |||
| 8821836f3d | |||
| 2243103f8d | |||
| 899b2b11c6 | |||
| 07f109f3c1 | |||
| b4713ea3b2 | |||
| b034292e64 | 
					 9 changed files with 181 additions and 55 deletions
				
			
		|  | @ -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,6 +115,9 @@ const InputOutputBackend: React.FC = () => { | |||
|     setMessages(previous => [...previous,{role,content}]) | ||||
|   }   | ||||
|   const handleSendClick = (inputValue: string) => { | ||||
|     if (inputValue != "") { | ||||
|       if (!inputDisabled) { | ||||
|         setInputDisabled(true) | ||||
|         if (postWorkerRef.current) { | ||||
|           addMessage("user", inputValue) | ||||
|           console.log("input:",inputValue); | ||||
|  | @ -116,6 +125,8 @@ const InputOutputBackend: React.FC = () => { | |||
|           startGetWorker() | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const handleMicClick = () => { | ||||
|     // do stuff
 | ||||
|  | @ -145,6 +156,7 @@ const InputOutputBackend: React.FC = () => { | |||
|         message="" | ||||
|         onSendClick={handleSendClick} | ||||
|         onMicClick={handleMicClick} | ||||
|         inputDisabled={inputDisabled} | ||||
|       /> | ||||
|     </div> | ||||
|     ) | ||||
|  |  | |||
|  | @ -29,6 +29,6 @@ const fetchData = () => { | |||
|         .catch(error => { | ||||
|             console.log('Error fetching data:', error); | ||||
|             postMessage({error:"failed fetching data"}) | ||||
|          | ||||
|             setTimeout(() => fetchData(),1000) | ||||
|     }) | ||||
| } | ||||
|  | @ -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, | ||||
|  |  | |||
|  | @ -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> | ||||
|         <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 && ( | ||||
|             <li> | ||||
|               <button onClick={toggleDivs} className="header-button"> | ||||
|               <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> | ||||
|     </> | ||||
|  |  | |||
|  | @ -4,22 +4,26 @@ 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 (!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)
 | ||||
|         } | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     return ( | ||||
|  | @ -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}> | ||||
|  |  | |||
|  | @ -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; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										14
									
								
								py/api.py
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								py/api.py
									
										
									
									
									
								
							|  | @ -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,9 +25,13 @@ class API: | |||
|         @self.app.route('/interstellar_ai/api/ai_create', methods=['GET']) | ||||
|         def create_ai(): | ||||
|             access_token = secrets.token_urlsafe(self.crypt_size) | ||||
| 
 | ||||
|             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(): | ||||
|             data = request.get_json() | ||||
|  | @ -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) | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,3 +9,4 @@ SpeechRecognition | |||
| PocketSphinx | ||||
| google-cloud-speech | ||||
| google-generativeai | ||||
| python-weather | ||||
							
								
								
									
										39
									
								
								py/weather.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								py/weather.py
									
										
									
									
									
										Normal 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 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue