From 7b6f91c1170a293fb9a8ff7a22a81fdb72ee8fb5 Mon Sep 17 00:00:00 2001
From: Patrick_Pluto <patrick_pluto@noreply.codeberg.org>
Date: Fri, 20 Sep 2024 15:46:02 +0200
Subject: [PATCH 1/5] fixed stuff with the backend and the pesky cpython cache

---
 .gitignore |  1 +
 py/ai.py   |  4 ----
 py/api.py  | 15 ++++++++++-----
 3 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/.gitignore b/.gitignore
index ea5d9c5..93a7e59 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@ next-env.d.ts
 
 .idea/
 venv/
+__pycache__/
 
 key.pem
 cert.pem
diff --git a/py/ai.py b/py/ai.py
index c51f2d2..0a57b57 100644
--- a/py/ai.py
+++ b/py/ai.py
@@ -12,13 +12,9 @@ class AI:
             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
diff --git a/py/api.py b/py/api.py
index 7b09e1d..646af55 100644
--- a/py/api.py
+++ b/py/api.py
@@ -26,11 +26,16 @@ class API:
         def send_ai():
             data = request.get_json()
             messages = data.get('messages')
+            model_type = data.get('model_type')
             ai_model = data.get('ai_model')
             access_token = data.get('access_token')
             if access_token not in self.ai_response:
                 return jsonify({'status': 401, 'error': 'Invalid access token'})
-            self.ai.process_local(ai_model, messages, self, access_token)
+
+            if model_type == "local":
+                self.ai.process_local(ai_model, messages, self, access_token)
+            if model_type == "mistral":
+                self.ai.process_mistralai(ai_model, messages, self, access_token)
             return jsonify({'status': 200})
 
         @self.app.route('/interstellar/api/ai_get', methods=['GET'])
@@ -46,13 +51,13 @@ class API:
             data = request.args.get('data')
             if action == "create_account":
                 self.db.add_user(data)
-            if action == "change_password":
+            elif action == "change_password":
                 self.db.update_password(data)
-            if action == "get_data":
+            elif action == "get_data":
                 self.db.get_data(data)
-            if action == "change_data":
+            elif action == "change_data":
                 self.db.change_data(data)
-            if action == "check_credentials":
+            elif action == "check_credentials":
                 self.db.check_credentials(data)
 
         email_address = "emailAddress"

From 6ed98894f33ed364d13f646badd1cb990648629a Mon Sep 17 00:00:00 2001
From: Patrick_Pluto <patrick_pluto@noreply.localhost>
Date: Fri, 20 Sep 2024 15:48:25 +0200
Subject: [PATCH 2/5] Update .gitignore

---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index ea5d9c5..93a7e59 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@ next-env.d.ts
 
 .idea/
 venv/
+__pycache__/
 
 key.pem
 cert.pem

From 579274000ce6c5e447a8b7ac0d2d5828ede1f394 Mon Sep 17 00:00:00 2001
From: Patrick_Pluto <patrick_pluto@noreply.localhost>
Date: Fri, 20 Sep 2024 15:48:43 +0200
Subject: [PATCH 3/5] Delete py/__pycache__/ai.cpython-312.pyc

---
 py/__pycache__/ai.cpython-312.pyc | Bin 1927 -> 0 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 py/__pycache__/ai.cpython-312.pyc

diff --git a/py/__pycache__/ai.cpython-312.pyc b/py/__pycache__/ai.cpython-312.pyc
deleted file mode 100644
index a1c10a8f80335103a3b77aa85e3690ddecdfa8d8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1927
zcmZ`)O=ufO6rR~X$@a>QWXFzwLRHr`75-~YBPfIhr}=RxHMrzr(XuSN>uA?2tvb6V
zmXT>GJ_zbSOb>2P)v2^NhxXJSOHPGevcw=UZ6T0S=%FB20fSF{qt(iP>67-&%zJO%
zo1OW-*<WL^P6Tpy^q-Y00z%K(AQTukr7;D~F4B>XZIr_qj9H(vxeUjl+eqiPkS^?T
zL2!mIaw+j|Hb`L_dEazBqS}jE;0<&u6txl?D1&vB;S65KTWGHpnGs;jofwNnJ|$3Y
z{*D$dj73J^;o)ig1!@<07@DS7VU^GTZ3&gIj&)AwP5emMYvtJ#O85r)D2C9c=!s!?
zN!)AY!f3lkK)P7sEGhIJw<Z26%Pc^KHz0#_B7>w$gW%I6Odn_azdY;QI>#bQr{-<I
zx-?$nSe5NL0Todyx_Fm%c}A{a5Y<~F#yxO>Ji7+_Bjz04uxT`BxUPE7aH#|bV5m77
zaSER4<Xwtrq~)X$&B=R4-h+9PW7}#@rGl1KJt`K6nfGXyYAVEV3oy+{MMxBikPc8(
zCI%GFE1IpkE|pbHgK~=JtQvX307bD$MJ>CQUv=35B?CE{n9VvlW454r#MD-2p@czP
z&w$EAQO(&xaaJ{F3Pl<#5T}{Zb~M%AxG;Zb=9GmUgZmk%Ptl+8f!*Pq;aXy#cJXqp
z7xZZ5-6wsozvvJXon@)fjS@rU`QPRE!&e_H)Oi@yB{cU|S*}Ktel%Gb@uM@(FAkS)
zvXJpFJN(3G<!wJPy)Vzy<V#g~%$LV1A3l}mzBhil<EL-^T=dgRzPz+A&mD-Uf20Ac
zK&KGN7S}}N7U1V3A{p{Rnp{DEI>BObXC%bG)kflRK<L{Pfq?J}vti`1ZEngZ;v+u9
z+NM;JEOu&V#OgX@fFa`saH7SU%}5jP@=M|Zyhi}<HvsQZK=VtZ+Gvhi-RHAd7tY%P
zwpfYt9;@%X?G!I=F<!ie-b60G&tbHTF#NVZU+0(6eVmFcZgi;yQ&}~NGv2yKF=1Cz
z%aY=baZT8p5Vi%WE-E+$BToe&k4{A(ky#+@xCmQ$6Xb-glnT1)slcSHV*+HU2<-Dz
z!d^MmaUydso5fy(;uSK&T1m4_;2!M>2-+qZ=?AaNXx5@lGD!y5gm}n-TyUwX=0@KM
zX0)xB*!*um0Xt&xhtrkb{n+@o@ml}D?#j-}7untXPX1~CMEUk1kGdybNGLH_8Q71f
z%F?r;<kyp5O;(4d{Gq9UQgsmxPd5-h+*$6acb;d?So!8zp8RP2U{%u#etO}TxSxKn
z3VcZ~RnyBp{N-gv93J(L9}YtCC$aG(mx1xYE7#Nf<Ft7FT4XUL(Ws*2)tsRyv{O;w
zMq9I4UsjZl*HpXZkzG&qOf6@4Sw|=ArO5=S?+{^^XmiU5<4{wvj?2DdTc{?+54axj
z1Ki+|l&Ckm^-<^^aNS}ium;^A5t|AZWJh~{0~qv#smUbkwQC+luLcW#hfITmeM4M!
Ze03gU{0F-H8;TuDqwp2|7ct$O_#dqcoyGtF


From 1d1705ebfae926d4c8e5c555d9dae3d263d06351 Mon Sep 17 00:00:00 2001
From: Patrick_Pluto <patrick_pluto@noreply.codeberg.org>
Date: Fri, 20 Sep 2024 16:06:40 +0200
Subject: [PATCH 4/5] It saves data now yay.

---
 py/api.py |  1 +
 py/db.py  | 15 ++++++++++++++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/py/api.py b/py/api.py
index 646af55..b52870f 100644
--- a/py/api.py
+++ b/py/api.py
@@ -13,6 +13,7 @@ class API:
         self.ai_response = {}
         self.ai = AI()
         self.db = DB()
+        self.db.load_database()
         CORS(self.app)
 
     def run(self):
diff --git a/py/db.py b/py/db.py
index ef82111..76470c9 100644
--- a/py/db.py
+++ b/py/db.py
@@ -1,5 +1,5 @@
-import json
 import hashlib
+import json
 
 
 class DB:
@@ -26,6 +26,7 @@ class DB:
             return False
 
         self.database[username]['data'] = data
+        self.save_database()
         return True
 
     def update_password(self, data):
@@ -36,6 +37,7 @@ class DB:
 
         hashed_new_password = self.hash_password(new_password)
         self.database[username].update({"hashed_password": hashed_new_password})
+        self.save_database()
         return True
 
     def check_credentials(self, data):
@@ -55,3 +57,14 @@ class DB:
 
         send_back = self.database[username].get['data']
         return send_back
+
+    def save_database(self):
+        with open("database.json", 'w') as file:
+            json.dump(self.database, file)
+
+    def load_database(self):
+        try:
+            with open("database.json", 'r') as file:
+                self.database = json.load(file)
+        except FileNotFoundError:
+            pass

From a8f9ba27bdd60d77be356edbec7eb5bf74e8ef5d Mon Sep 17 00:00:00 2001
From: Patrick_Pluto <patrick_pluto@noreply.codeberg.org>
Date: Mon, 23 Sep 2024 11:01:39 +0200
Subject: [PATCH 5/5] Fixes and Multithreading

---
 py/ai.py            | 34 +++++++++++++++++++++++++++-------
 py/api.py           | 22 ++++++++++++++++------
 py/requirements.txt |  1 +
 3 files changed, 44 insertions(+), 13 deletions(-)

diff --git a/py/ai.py b/py/ai.py
index 0a57b57..bfde713 100644
--- a/py/ai.py
+++ b/py/ai.py
@@ -1,4 +1,5 @@
 from mistralai import Mistral
+from openai import OpenAI
 import ollama
 
 
@@ -12,15 +13,15 @@ class AI:
             options={"temperature": 0.5},
         )
 
-        return_class.ai_response[access_token] = ""
+        with return_class.ai_response_lock:
+            return_class.ai_response[access_token] = ""
 
         for chunk in stream:
-            return_class.ai_response[access_token] += chunk['message']['content']
+            with return_class.ai_response_lock:
+                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()
+    def process_mistralai(model, messages, return_class, access_token, api_key):
 
         client = Mistral(api_key=api_key)
 
@@ -29,7 +30,26 @@ class AI:
             messages=messages
         )
 
-        return_class.ai_response[access_token] = ""
+        with return_class.ai_response_lock:
+            return_class.ai_response[access_token] = ""
 
         for chunk in stream_response:
-            return_class.ai_response[access_token] += chunk.data.choices[0].delta.content
+            with return_class.ai_response_lock:
+                return_class.ai_response[access_token] += chunk.data.choices[0].delta.content
+
+    @staticmethod
+    def process_openai(model, messages, return_class, access_token, api_key):
+
+        client = OpenAI(api_key=api_key)
+
+        stream_response = client.chat.completions.create(
+            model=model,
+            messages=messages
+        )
+
+        with return_class.ai_response_lock:
+            return_class.ai_response[access_token] = ""
+
+        for chunk in stream_response:
+            with return_class.ai_response_lock:
+                return_class.ai_response[access_token] += chunk.choices[0].delta.content
\ No newline at end of file
diff --git a/py/api.py b/py/api.py
index b52870f..386cd4f 100644
--- a/py/api.py
+++ b/py/api.py
@@ -1,6 +1,7 @@
 from flask import Flask, request, jsonify
 from flask_cors import CORS
 import secrets
+import threading
 from ai import AI
 from db import DB
 from OpenSSL import crypto
@@ -8,12 +9,13 @@ from OpenSSL import crypto
 
 class API:
     def __init__(self):
-        self.crypt_size = 4096
+        self.crypt_size = 1
         self.app = Flask(__name__)
         self.ai_response = {}
         self.ai = AI()
         self.db = DB()
         self.db.load_database()
+        self.ai_response_lock = threading.Lock()
         CORS(self.app)
 
     def run(self):
@@ -34,10 +36,18 @@ class API:
                 return jsonify({'status': 401, 'error': 'Invalid access token'})
 
             if model_type == "local":
-                self.ai.process_local(ai_model, messages, self, access_token)
-            if model_type == "mistral":
-                self.ai.process_mistralai(ai_model, messages, self, access_token)
-            return jsonify({'status': 200})
+                thread = threading.Thread(target=self.ai.process_local, args=(ai_model, messages, self, access_token))
+                thread.start()
+                thread.join()
+                return jsonify({'status': 200})
+            elif model_type == "mistral":
+                api_key = data.get('api_key')
+                thread = threading.Thread(target=self.ai.process_mistralai, args=(ai_model, messages, self, access_token, api_key))
+                thread.start()
+                thread.join()
+                return jsonify({'status': 200})
+
+            return jsonify({'status': 401, 'error': 'Invalid AI model type'})
 
         @self.app.route('/interstellar/api/ai_get', methods=['GET'])
         def get_ai():
@@ -95,7 +105,7 @@ class API:
             f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k).decode("utf-8"))
 
         ssl_context = ("cert.pem", "key.pem")
-        self.app.run(debug=True, host='0.0.0.0', port=5000, ssl_context=ssl_context)
+        self.app.run(debug=True, host='0.0.0.0', port=5000)
 
 
 if __name__ == '__main__':
diff --git a/py/requirements.txt b/py/requirements.txt
index 144c571..3c2be3b 100644
--- a/py/requirements.txt
+++ b/py/requirements.txt
@@ -2,4 +2,5 @@ flask
 flask-cors
 ollama
 mistralai
+openai
 pyOpenSSL
\ No newline at end of file