Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/HBAI-209: Python server GUI #38

Merged
merged 6 commits into from
Mar 29, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
HBAI-209 Add a GUI interface and display server info
dieharders committed Mar 29, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 3edd66db1a62fbe7996b4bc7279b4a9fcc966e06
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ Forked from vercel [project](https://github.com/vercel/next.js/tree/canary/examp
- ✅ Provide easy to use desktop installers
- ✅ Embeddings: Create vector embeddings from a text or document files
- ✅ Search: Using a vector database and Llama Index to make semantic or similarity queries
- ✅ Advanced Settings: Fine tune how the model is loaded
- ✅ Build custom bots from a mix of LLM's, software configs and prompt configs
- ❌ Threads: Save/Retrieve chat message history

## Upcoming Features
2 changes: 1 addition & 1 deletion backends/embedding/chunking.py
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
import os
import base64
from typing import List
from PIL import Image
from PIL import Image # use `pip install pillow` instead of PIL
from langchain.text_splitter import (
CharacterTextSplitter,
RecursiveCharacterTextSplitter,
112 changes: 83 additions & 29 deletions backends/main.py
Original file line number Diff line number Diff line change
@@ -81,21 +81,6 @@ def parse_runtime_args():
@asynccontextmanager
async def lifespan(application: FastAPI):
print(f"{common.PRNT_API} Lifespan startup", flush=True)
# Display where the admin can use the web UI
openbrew_studio_url = "https://studio.openbrewai.com"
print(
f"{common.PRNT_API} Navigate your browser to OpenBrew Studio\n-> {openbrew_studio_url} for the admin web UI.",
flush=True,
)
# Display the local IP address of this server
hostname = socket.gethostname()
IPAddr = socket.gethostbyname(hostname)
openbrew_server_ip = f"http://{IPAddr}:{SERVER_PORT}/docs"
openbrew_server_local_ip = f"http://localhost:{SERVER_PORT}/docs"
print(
f"{common.PRNT_API} Refer to API docs for OpenBrew Server \n-> {openbrew_server_local_ip} \nOR\n-> {openbrew_server_ip}",
flush=True,
)
# https://www.python-httpx.org/quickstart/
app.requests_client = httpx.Client()
# Store some state here if you want...
@@ -1257,23 +1242,86 @@ def get_bot_settings() -> classes.BotSettingsResponse:
# Methods...


class Window:
def __init__(self, master):
# @TODO Swap out with a UI or other image
self.img = Image.open("public/splash.png")
self.img = self.img.resize((640, 480), Image.FILTERED)

self.img = ImageTk.PhotoImage(self.img)

label = tk.Label(master, image=self.img)
label.pack(expand=True, fill=tk.BOTH)
def display_server_info():
# Display where the admin can use the web UI
openbrew_studio_url = "https://studio.openbrewai.com"
print(
f"{common.PRNT_API} Navigate your browser to OpenBrew Studio\n-> {openbrew_studio_url} for the admin web UI.",
flush=True,
)
# Display the local IP address of this server
hostname = socket.gethostname()
IPAddr = socket.gethostbyname(hostname)
remote_ip = f"http://{IPAddr}:{SERVER_PORT}/docs"
local_ip = f"http://localhost:{SERVER_PORT}/docs"
print(
f"{common.PRNT_API} Refer to API docs for OpenBrew Server \n-> {local_ip} \nOR\n-> {remote_ip}",
flush=True,
)
return {
"local_ip": local_ip,
"remote_ip": remote_ip,
"web_ui_address": openbrew_studio_url,
}


# Function to create and run the Tkinter window
def run_GUI():
def run_GUI(local_ip: str, remote_ip: str, webui_address: str):
color_bg = "#333333"
color_label = "#ffe135"
root = tk.Tk()
root.title("OpenBrew Server")
window = Window(root)
root.geometry("640x480")
# since /public folder is bundled inside _deps, we need to read from root `sys._MEIPASS`
root.iconbitmap(default=os.path.join(sys._MEIPASS, "public/favicon.ico"))
root.configure(bg=color_bg)
frame = tk.Frame(bg=color_bg)
# Labels
title_label = tk.Label(
frame,
text="Server Info",
bg=color_bg,
fg=color_label,
font=("Arial", 30),
)
local_label = tk.Label(
frame,
text="API Docs (Local)",
bg=color_bg,
fg=color_label,
font=("Arial", 16),
)
remote_label = tk.Label(
frame,
text="API Docs (Remote)",
bg=color_bg,
fg=color_label,
font=("Arial", 16),
)
webui_label = tk.Label(
frame,
text="WebUI Address",
bg=color_bg,
fg=color_label,
font=("Arial", 16),
)
# Inputs
local_entry = tk.Entry(frame, font=("Arial", 24))
local_entry.insert(0, local_ip)
remote_entry = tk.Entry(frame, font=("Arial", 24))
remote_entry.insert(0, remote_ip)
webui_entry = tk.Entry(frame, font=("Arial", 24))
webui_entry.insert(0, webui_address)
# Placement
title_label.grid(row=0, column=0, columnspan=2, sticky="news", pady=40)
local_label.grid(row=1, column=0, padx=20)
local_entry.grid(row=1, column=1, pady=20)
remote_label.grid(row=2, column=0, padx=20)
remote_entry.grid(row=2, column=1, pady=20)
webui_label.grid(row=3, column=0, padx=20)
webui_entry.grid(row=3, column=1, pady=20)
frame.pack()
# Render
root.mainloop()


@@ -1297,9 +1345,15 @@ def run_server():
# Start the API server in a separate thread
fastapi_thread = threading.Thread(target=run_server)
fastapi_thread.start()
# GUI window
# Find IP info
server_info = display_server_info()
# Render GUI window
if isProd:
run_GUI()
run_GUI(
local_ip=server_info["local_ip"],
remote_ip=server_info["remote_ip"],
webui_address=server_info["web_ui_address"],
)
# Handle stopping the server when window is closed
print(f"{common.PRNT_API} Shutting down", flush=True)
os.kill(os.getpid(), signal.SIGINT)
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "openbrew-server",
"version": "0.3.1",
"version": "0.3.2",
"author": "Spread Shot Studios",
"license": "MIT",
"productName": "OpenBrew Server",
@@ -13,8 +13,8 @@
"server:dev": "python ./backends/main.py --mode=dev",
"server:prod": "python ./backends/main.py --mode=prod",
"build": "yarn run build:api && next build renderer",
"build:api:dev": "yarn run python-deps && pyinstaller --noconfirm --onedir --console --icon C:/Project Files/brain-dump-ai/backend-homebrew-ai/public/favicon.ico --name OpenBrew-Server --contents-directory _deps --clean --debug imports --add-data C:/Python311/Lib/site-packages/llama_index/VERSION;./llama_index C:/Project Files/brain-dump-ai/backend-homebrew-ai/backends/main.py",
"build:api:prod": "yarn run python-deps && pyinstaller --noconfirm --onedir --windowed --icon C:/Project Files/brain-dump-ai/backend-homebrew-ai/public/favicon.ico --name OpenBrew-Server --contents-directory _deps --clean --add-data C:/Python311/Lib/site-packages/llama_index/VERSION;./llama_index --add-data C:/Python311/Lib/site-packages/tiktoken_ext;tiktoken_ext/ C:/Project Files/brain-dump-ai/backend-homebrew-ai/backends/main.py",
"build:api:dev": "yarn run python-deps && pyinstaller --noconfirm --onedir --console --icon C:/Project Files/brain-dump-ai/backend-homebrew-ai/public/favicon.ico --name OpenBrew-Server --contents-directory _deps --clean --debug bootloader --add-data C:/Python311/Lib/site-packages/llama_index/VERSION;llama_index --add-data C:/Project Files/brain-dump-ai/backend-homebrew-ai/public;public/ C:/Project Files/brain-dump-ai/backend-homebrew-ai/backends/main.py",
"build:api:prod": "yarn run python-deps && pyinstaller --noconfirm --onedir --windowed --icon C:/Project Files/brain-dump-ai/backend-homebrew-ai/public/favicon.ico --name OpenBrew-Server --contents-directory _deps --clean --add-data C:/Python311/Lib/site-packages/llama_index/VERSION;llama_index --add-data C:/Project Files/brain-dump-ai/backend-homebrew-ai/public;public/ C:/Project Files/brain-dump-ai/backend-homebrew-ai/backends/main.py",
"python-deps": "pip install -r requirements.txt",
"release": "yarn run build && electron-builder",
"release:win": "yarn run build && electron-builder --win --x64",
10 changes: 9 additions & 1 deletion py-to-exe-config.dev.json
Original file line number Diff line number Diff line change
@@ -33,6 +33,10 @@
"optionDest": "clean_build",
"value": true
},
{
"optionDest": "debug",
"value": "bootloader"
},
{
"optionDest": "strip",
"value": false
@@ -63,7 +67,11 @@
},
{
"optionDest": "datas",
"value": "C:/Python311/Lib/site-packages/llama_index/VERSION;./llama_index"
"value": "C:/Python311/Lib/site-packages/llama_index/VERSION;llama_index"
},
{
"optionDest": "datas",
"value": "C:/Project Files/brain-dump-ai/backend-homebrew-ai/public;public/"
}
],
"nonPyinstallerOptions": {
4 changes: 2 additions & 2 deletions py-to-exe-config.prod.json
Original file line number Diff line number Diff line change
@@ -63,11 +63,11 @@
},
{
"optionDest": "datas",
"value": "C:/Python311/Lib/site-packages/llama_index/VERSION;./llama_index"
"value": "C:/Python311/Lib/site-packages/llama_index/VERSION;llama_index"
},
{
"optionDest": "datas",
"value": "C:/Python311/Lib/site-packages/tiktoken_ext;tiktoken_ext/"
"value": "C:/Project Files/brain-dump-ai/backend-homebrew-ai/public;public/"
}
],
"nonPyinstallerOptions": {
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Misc
python-dotenv==1.0.0
# For type safety
pydantic-settings==2.0.3