forked from React-Group/interstellar_ai
		
	Merge pull request 'Backend changes' (#4) from React-Group/interstellar_ai:main into main
Reviewed-on: https://interstellardevelopment.org/code/code/sageTheDm/interstellar_ai/pulls/4
This commit is contained in:
		
						commit
						87559ee61e
					
				
					 16 changed files with 173 additions and 125 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -41,3 +41,4 @@ venv/ | |||
| 
 | ||||
| key.pem | ||||
| cert.pem | ||||
| api_key.txt | ||||
|  |  | |||
|  | @ -27,30 +27,30 @@ const handleCopyClick = () => { | |||
| const InputOutputBackend: React.FC = () => { | ||||
|     const [accessToken, setAccessToken] = useState("") | ||||
|     const workerRef = useRef<Worker | null>(null) | ||||
|     type Message = { | ||||
|       role: string | ||||
|       content: string | ||||
|     } | ||||
| 
 | ||||
|     const handleSendClick = (message: string) => { | ||||
|         var system = "You give really short answers (maximum of 30 sentences). The following is the chat history." | ||||
|         for (let index = 0; index < messages.length; index++) { | ||||
|             system += messages[index] + " "; | ||||
|         }; | ||||
|     const handleSendClick = (message:string) => { | ||||
|       var system:Message = {role:"system" ,content:"You are a helpful assistant."} | ||||
| 
 | ||||
|         HandlePostRequest(message, "phi3.5", system) | ||||
|       addMessage("user", message); | ||||
|       console.log("added User Message") | ||||
|        | ||||
|         addMessage('User: ' + message); | ||||
|       HandlePostRequest([...messages, { role: "user", content: message }], "phi3.5", system); | ||||
|     }; | ||||
| 
 | ||||
|     const [messages, setMessages] = useState([ | ||||
|         'User: Hello!', | ||||
|         'AI: Hi there!', | ||||
|         'User: How are you?', | ||||
|         'AI: I’m good, thank you!' | ||||
|       { role:"assistant", content:'Hello. I\'m Your AI Virtual Assistant' }  | ||||
|     ]); | ||||
| 
 | ||||
|     const addMessage = (message: string) => { | ||||
|         setMessages((prevMessages) => [...prevMessages, message]); | ||||
|     const addMessage = (role:string ,content: string) => { | ||||
|         setMessages((prevMessages) => [...prevMessages, {role,content}]); | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     useEffect(() => { | ||||
|         workerRef.current = new Worker(new URL("./ProcessAPI.js", import.meta.url)) | ||||
|         workerRef.current.postMessage({}) | ||||
|  | @ -65,20 +65,11 @@ const InputOutputBackend: React.FC = () => { | |||
|         } | ||||
|     },[]) | ||||
|          | ||||
|     const HandleGetRequest = (message: string, ai_model: string, system_prompt: string) => { | ||||
|         if (workerRef.current) { | ||||
|             workerRef.current.postMessage({ functionName: "getResponse", access_token: accessToken, message: message, ai_model: ai_model, system_prompt: system_prompt }) | ||||
|         const HandlePostRequest = (messages: Message[], ai_model: string, system_prompt: Message) => { | ||||
|           if (workerRef.current) { | ||||
|             workerRef.current.postMessage({ functionName: "postRequest", access_token: accessToken, messages: messages, ai_model: ai_model, system_prompt: system_prompt }) | ||||
|             workerRef.current.onmessage = (e) => { | ||||
|                 addMessage("AI: " + e.data) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     const HandlePostRequest = (message: string, ai_model: string, system_prompt: string) => { | ||||
|         if (workerRef.current) { | ||||
|             workerRef.current.postMessage({ functionName: "postRequest", access_token: accessToken, message: message, ai_model: ai_model, system_prompt: system_prompt }) | ||||
|             workerRef.current.onmessage = (e) => { | ||||
|                 HandleGetRequest(message,ai_model,system_prompt) | ||||
|               addMessage("assistant",e.data) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | @ -97,7 +88,7 @@ const InputOutputBackend: React.FC = () => { | |||
|         onMicClick={handleMicClick} | ||||
|       /> | ||||
|     </div> | ||||
|   ); | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| export default InputOutputBackend | ||||
|  |  | |||
|  | @ -1,37 +1,49 @@ | |||
| import axios from 'axios' | ||||
| import { type } from 'os'; | ||||
| 
 | ||||
| onmessage = function (e) { | ||||
|     const { functionName = "getAccess", access_token = "", message = "", ai_model = "phi3.5", system_prompt = "You are a helpful assistant" } = e.data | ||||
|     const data = { | ||||
|         "ai_model": ai_model, | ||||
|         "message": message, | ||||
|         "system_prompt": system_prompt, | ||||
|         "access_token": access_token | ||||
|     const { functionName = "getAccess", access_token = "", messages = [], ai_model = "phi3.5", system_prompt = {role:"system" ,content: "You are a helpful assistant that gives short answers"}} = e.data | ||||
|      | ||||
|     let data = { | ||||
|         ai_model: ai_model, | ||||
|         messages: messages, | ||||
|         access_token: access_token | ||||
|     }; | ||||
|     switch (functionName) { | ||||
|         case "getAccess": | ||||
|             axios.get('https://127.0.0.1:5000/interstellar/api/ai_create') | ||||
|                 .then(Response => { | ||||
|                     postMessage(Response.data.access_token) | ||||
|                 }).catch(error => { | ||||
|                     console.error("Error with GET Token request:", error) | ||||
|                 }) | ||||
|             break | ||||
|         case "postRequest": | ||||
|             axios.post('https://127.0.0.1:5000/interstellar/api/ai_send', data) | ||||
|                 .then(Response => { | ||||
|                     postMessage(Response.data) | ||||
|                 }).catch(error => { | ||||
|                     console.error("Error:", error) | ||||
|                 }) | ||||
|             break | ||||
|         case "getResponse": | ||||
|             axios.get('https://127.0.0.1:5000/interstellar/api/ai_get?access_token=' + access_token) | ||||
| 
 | ||||
|     const getResponse = () => { | ||||
|         messageComplete:boolean = false | ||||
|         while(!messageComplete) | ||||
|         axios.get('https://localhost:5000/interstellar/api/ai_get?access_token=' + access_token) | ||||
|                 .then(Response => { | ||||
|                     postMessage(Response.data.response) | ||||
|                     if (Response.data.status == 200) { | ||||
|                         messageComplete = true | ||||
|                     } | ||||
|                 }).catch(error => { | ||||
|                     console.error("Error with GET response request:", error) | ||||
|                 }) | ||||
|     } | ||||
| 
 | ||||
|     switch (functionName) { | ||||
|         case "getAccess": | ||||
|             console.log("getting access...") | ||||
|             axios.get('https://localhost:5000/interstellar/api/ai_create') | ||||
|             .then(Response => { | ||||
|                 postMessage(Response.data.access_token) | ||||
|             }).catch(error => { | ||||
|                 console.error("Error with GET Token request:", error) | ||||
|             }) | ||||
|             break | ||||
|         case "postRequest": | ||||
|             messages.unshift(system_prompt) | ||||
|             console.log("sending...") | ||||
|             console.log(messages) | ||||
|             axios.post('https://localhost:5000/interstellar/api/ai_send', data) | ||||
|             .then(Response => { | ||||
|                 getResponse() | ||||
|             }).catch(error => { | ||||
|                 console.error("Error:", error) | ||||
|             }) | ||||
|             break | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,12 @@ | |||
| import React, { ForwardedRef, useEffect, useRef } from 'react'; | ||||
| 
 | ||||
| type Message = { | ||||
|   role: string | ||||
|   content: string | ||||
| } | ||||
| 
 | ||||
| interface ConversationProps { | ||||
|   messages: string[]; | ||||
|   messages: Message[]; | ||||
|   onResendClick: () => void; | ||||
|   onEditClick: () => void; | ||||
|   onCopyClick: () => void; | ||||
|  | @ -22,14 +27,16 @@ const ConversationFrontend = React.forwardRef<HTMLDivElement, ConversationProps> | |||
|       <div className="output"> | ||||
|         <div className="conversation resize" id="conversation" ref={ref}> | ||||
|           {messages.map((message, index) => { | ||||
|             const isUserMessage = message.startsWith('User:'); | ||||
|             console.log(messages) | ||||
|             let isUserMessage | ||||
|             if (message.role == "user") { | ||||
|               isUserMessage = message | ||||
|             } | ||||
|             return ( | ||||
|               <div | ||||
|                 key={index} | ||||
|                 className={isUserMessage ? 'user-message' : 'ai-message'} | ||||
|               > | ||||
|                 <p> {message}</p> | ||||
|                 <p> {message.content}</p> | ||||
|               </div> | ||||
|             ); | ||||
|           })} | ||||
|  |  | |||
|  | @ -14,19 +14,28 @@ const InputFrontend = React.forwardRef<HTMLDivElement, InputProps>( | |||
|       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)
 | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     return ( | ||||
|       <div className="input" id="inputForm"> | ||||
|       <div className="input" id="inputForm" ref={ref}> | ||||
|         <input | ||||
|           type="text" | ||||
|           name="user_message" | ||||
|           placeholder="Type your message here..." | ||||
|           value={inputValue} | ||||
|           onChange={handleInputChange} | ||||
|           onKeyDown={handleKeyDown} | ||||
|         /> | ||||
|         <button type="submit" onClick={() => onSendClick(inputValue)}> | ||||
|         <button type="button" onClick={() => onSendClick(inputValue)}> | ||||
|           <img src="/img/send.svg" alt="send" /> | ||||
|         </button> | ||||
|         <button type="submit" onClick={onMicClick}> | ||||
|         <button type="button" onClick={onMicClick}> | ||||
|           <img src="/img/microphone.svg" alt="microphone" /> | ||||
|         </button> | ||||
|       </div> | ||||
|  |  | |||
							
								
								
									
										3
									
								
								py/.idea/.gitignore
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								py/.idea/.gitignore
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,3 +0,0 @@ | |||
| # Default ignored files | ||||
| /shelf/ | ||||
| /workspace.xml | ||||
|  | @ -1,6 +0,0 @@ | |||
| <component name="InspectionProjectProfileManager"> | ||||
|   <settings> | ||||
|     <option name="USE_PROJECT_PROFILE" value="false" /> | ||||
|     <version value="1.0" /> | ||||
|   </settings> | ||||
| </component> | ||||
							
								
								
									
										10
									
								
								py/.idea/misc.xml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										10
									
								
								py/.idea/misc.xml
									
										
									
										generated
									
									
									
								
							|  | @ -1,10 +0,0 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="Black"> | ||||
|     <option name="sdkName" value="Python 3.12" /> | ||||
|   </component> | ||||
|   <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12" project-jdk-type="Python SDK" /> | ||||
|   <component name="PyCharmProfessionalAdvertiser"> | ||||
|     <option name="shown" value="true" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										8
									
								
								py/.idea/modules.xml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								py/.idea/modules.xml
									
										
									
										generated
									
									
									
								
							|  | @ -1,8 +0,0 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="ProjectModuleManager"> | ||||
|     <modules> | ||||
|       <module fileurl="file://$PROJECT_DIR$/.idea/py.iml" filepath="$PROJECT_DIR$/.idea/py.iml" /> | ||||
|     </modules> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										13
									
								
								py/.idea/py.iml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										13
									
								
								py/.idea/py.iml
									
										
									
										generated
									
									
									
								
							|  | @ -1,13 +0,0 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <module type="PYTHON_MODULE" version="4"> | ||||
|   <component name="NewModuleRootManager"> | ||||
|     <content url="file://$MODULE_DIR$"> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/venv" /> | ||||
|     </content> | ||||
|     <orderEntry type="inheritedJdk" /> | ||||
|     <orderEntry type="sourceFolder" forTests="false" /> | ||||
|   </component> | ||||
|   <component name="PackageRequirementsSettings"> | ||||
|     <option name="versionSpecifier" value="Greater or equal (>=x.y.z)" /> | ||||
|   </component> | ||||
| </module> | ||||
							
								
								
									
										6
									
								
								py/.idea/vcs.xml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								py/.idea/vcs.xml
									
										
									
										generated
									
									
									
								
							|  | @ -1,6 +0,0 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="VcsDirectoryMappings"> | ||||
|     <mapping directory="$PROJECT_DIR$/.." vcs="Git" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										
											BIN
										
									
								
								py/__pycache__/ai.cpython-312.pyc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								py/__pycache__/ai.cpython-312.pyc
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										39
									
								
								py/ai.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								py/ai.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | |||
| from mistralai import Mistral | ||||
| import ollama | ||||
| 
 | ||||
| 
 | ||||
| class AI: | ||||
|     @staticmethod | ||||
|     def process_local(model, messages, return_class, access_token): | ||||
|         stream = ollama.chat( | ||||
|             model=model, | ||||
|             messages=messages, | ||||
|             stream=True, | ||||
|             options={"temperature": 0.5}, | ||||
|         ) | ||||
| 
 | ||||
|         for i in messages: | ||||
|             print(i) | ||||
| 
 | ||||
|         return_class.ai_response[access_token] = "" | ||||
| 
 | ||||
|         for chunk in stream: | ||||
|             print(chunk['message']['content']) | ||||
|             return_class.ai_response[access_token] += chunk['message']['content'] | ||||
| 
 | ||||
|     @staticmethod | ||||
|     def process_mistralai(model, messages, return_class, access_token): | ||||
|         with open("api_key.txt", 'r') as f: | ||||
|             api_key = f.read().strip() | ||||
| 
 | ||||
|         client = Mistral(api_key=api_key) | ||||
| 
 | ||||
|         stream_response = client.chat.stream( | ||||
|             model=model, | ||||
|             messages=messages | ||||
|         ) | ||||
| 
 | ||||
|         return_class.ai_response[access_token] = "" | ||||
| 
 | ||||
|         for chunk in stream_response: | ||||
|             return_class.ai_response[access_token] += chunk.data.choices[0].delta.content | ||||
							
								
								
									
										27
									
								
								py/api.py
									
										
									
									
									
								
							
							
						
						
									
										27
									
								
								py/api.py
									
										
									
									
									
								
							|  | @ -1,22 +1,8 @@ | |||
| from flask import Flask, request, jsonify | ||||
| from flask_cors import CORS | ||||
| import ollama | ||||
| import secrets | ||||
| 
 | ||||
| 
 | ||||
| class AI: | ||||
|     @staticmethod | ||||
|     def process_local(model, messages, return_class, access_token): | ||||
|         stream = ollama.chat( | ||||
|             model=model, | ||||
|             messages=messages, | ||||
|             stream=True, | ||||
|             options={"temperature": 0}, | ||||
|         ) | ||||
| 
 | ||||
|         for chunk in stream: | ||||
|             print(chunk['message']['content']) | ||||
|             return_class.ai_response[access_token] += chunk['message']['content'] | ||||
| from ai import AI | ||||
| from db import DB | ||||
| 
 | ||||
| 
 | ||||
| class API: | ||||
|  | @ -24,6 +10,7 @@ class API: | |||
|         self.app = Flask(__name__) | ||||
|         self.ai_response = {} | ||||
|         self.ai = AI() | ||||
|         self.db = DB() | ||||
|         CORS(self.app) | ||||
| 
 | ||||
|     def run(self): | ||||
|  | @ -51,6 +38,13 @@ class API: | |||
|                 return jsonify({'status': 401, 'error': 'Invalid access token'}) | ||||
|             return jsonify({'status': 200, 'response': self.ai_response[data]}) | ||||
| 
 | ||||
|         @self.app.route('/interstellar/api/db', methods=['POST']) | ||||
|         def db_manipulate(): | ||||
|             action = request.args.get('action') | ||||
|             if action == "create_account": | ||||
|                 print("ahh") | ||||
| 
 | ||||
| 
 | ||||
|         ssl_context = ('cert.pem', 'key.pem') | ||||
|         self.app.run(debug=True, host='0.0.0.0', port=5000, ssl_context=ssl_context) | ||||
| 
 | ||||
|  | @ -58,4 +52,3 @@ class API: | |||
| if __name__ == '__main__': | ||||
|     api = API() | ||||
|     api.run() | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										41
									
								
								py/db.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								py/db.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | |||
| import json | ||||
| import hashlib | ||||
| 
 | ||||
| 
 | ||||
| class DB: | ||||
|     def __init__(self): | ||||
|         self.database = {} | ||||
| 
 | ||||
|     def _hash_password(self, password: str) -> str: | ||||
|         salt = "your_secret_salt" | ||||
|         hashed_password = hashlib.sha256((password + salt).encode()).hexdigest() | ||||
|         return hashed_password | ||||
| 
 | ||||
|     def add_user(self, username: str, password: str) -> None: | ||||
|         hashed_password = self._hash_password(password) | ||||
|         user_data = {"hashed_password": hashed_password} | ||||
|         self.database[username] = user_data | ||||
| 
 | ||||
|     def update_password(self, username: str, old_password: str, new_password: str) -> bool: | ||||
|         if not self.check_credentials(username, old_password): | ||||
|             return False | ||||
| 
 | ||||
|         hashed_new_password = self._hash_password(new_password) | ||||
|         self.database[username].update({"hashed_password": hashed_new_password}) | ||||
|         return True | ||||
| 
 | ||||
|     def check_credentials(self, username: str, password: str) -> bool: | ||||
|         if username not in self.database: | ||||
|             return False | ||||
| 
 | ||||
|         stored_hashed_password = self.database[username]["hashed_password"] | ||||
|         entered_hashed_password = self._hash_password(password) | ||||
|         return stored_hashed_password == entered_hashed_password | ||||
| 
 | ||||
|     def get_additional_info(self, username: str, password: str) -> dict | None: | ||||
|         if not self.check_credentials(username, password): | ||||
|             return None | ||||
| 
 | ||||
|         send_back = self.database[username] | ||||
|         del send_back['hashed_password'] | ||||
|         return send_back | ||||
|  | @ -1,3 +1,4 @@ | |||
| flask | ||||
| flask-cors | ||||
| ollama | ||||
| mistralai | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue