Skip to content

Commit

Permalink
Feature/HBAI-220: Fix up build version (#47)
Browse files Browse the repository at this point in the history
* HBAI-220 Fix QR code page not loading on startup.
Update build scripts.

* HBAI-220 Draw a giant beer emoji to window in prod build.
Update Readme.

* HBAI-220 Add font

* ...

* HBAI-220 Put html templates folder inside the public folder

* HBAI-220 Edit readme

* HBAI-220 Update requirements
  • Loading branch information
dieharders authored May 7, 2024
1 parent 8a48c33 commit a7ecdbe
Show file tree
Hide file tree
Showing 7 changed files with 281 additions and 181 deletions.
24 changes: 17 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Or
python src/backends/main.py
```

Or (recommended)
Or, using yarn (recommended)

```bash
yarn server:dev
Expand Down Expand Up @@ -164,9 +164,9 @@ Run the command below in powershell to set your env variables:

## Bundling

<!-- ### Bundling Nvida CUDA toolkit deps:
### Bundling Nvida CUDA toolkit deps:

Instructions on how and what files to include in app bundle... -->
If you already have the required toolkit files installed and have built for GPU then the necessary GPU drivers/dlls should be detected by PyInstaller and included in the `_deps` dir.

### Python server

Expand All @@ -188,9 +188,15 @@ pyinstaller -c -F your_program.py

#### Packaging python server with auto-py-to-exe (recommended):

This is a GUI tool that greatly simplifies the process. You can also save and load configs.
This is a GUI tool that greatly simplifies the process. You can also save and load configs. It uses PyInstaller under the hood and requires it to be installed. Please note if using a conda or virtual environment, be sure to install both PyInstaller and auto-py-to-exe in your virtual environment and also run them from there, otherwise one or both will build from incorrect deps.

To install:
**Note**, you will need to edit paths for the following in `auto-py-to-exe` to point to your base project directory:

- Settings -> Output directory
- Additional Files
- Script Location

To run:

```bash
auto-py-to-exe
Expand Down Expand Up @@ -282,6 +288,10 @@ This project deploys several backend servers exposed using the `/v1` endpoint. T

A complete list of endpoint documentation can be found [here](https://localhost:8000/docs) after Obrew Server is started.

## API Keys and .env variables

Put your .env file in the base directory alongside the executable.

## Managing Python dependencies

It is highly recommended to use an package/environment manager like Anaconda to manage Python installations and the versions of dependencies they require. This allows you to create virtual environments from which you can install different versions of software and build/deploy from within this sandboxed environment.
Expand All @@ -290,10 +300,10 @@ It is highly recommended to use an package/environment manager like Anaconda to

The following commands should be done in `Anaconda Prompt` terminal. If on Windows, `run as Admin`.

1. Create a new environment:
1. Create a new environment. This project uses v3.12:

```bash
conda create --name env1 python=3.10
conda create --name env1 python=3.12
```

2. To work in this env, activate it:
Expand Down
57 changes: 41 additions & 16 deletions backends/main.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import os
import signal
import sys
import threading
import uvicorn
import webbrowser
import httpx
import socket
import pyqrcode
import tkinter as tk
from dotenv import load_dotenv
from fastapi import (
FastAPI,
Expand All @@ -24,7 +26,6 @@
from settings.route import router as settings


# server_thread = None
server_info = None
api_version = "0.4.3"
SERVER_PORT = 8008
Expand All @@ -45,10 +46,12 @@ def parse_runtime_args():
return mode


# Check what env is running - prod/dev
buildEnv = parse_runtime_args()
isDebug = hasattr(sys, "gettrace") and sys.gettrace() is not None
isDev = buildEnv == "dev" or isDebug
isProd = buildEnv == "prod" or not isDev
# Comment out if you want to debug on prod build
if isProd:
# Remove prints in prod when deploying in window mode
sys.stdout = open(os.devnull, "w")
Expand All @@ -66,7 +69,7 @@ async def lifespan(application: FastAPI):
print(f"{common.PRNT_API} Lifespan startup", flush=True)
# https://www.python-httpx.org/quickstart/
app.requests_client = httpx.Client()
# Store some state here if you want...
# Initialize global data here
application.state.PORT_HOMEBREW_API = SERVER_PORT
application.state.db_client = None
application.state.llm = None # Set each time user loads a model
Expand All @@ -81,8 +84,6 @@ async def lifespan(application: FastAPI):


app = FastAPI(title="Obrew🍺Server", version=api_version, lifespan=lifespan)
templates_dir = os.path.join(os.path.dirname(__file__), "templates")
templates = Jinja2Templates(directory=templates_dir)

# Get paths for SSL certificate
SSL_KEY: str = common.dep_path("public/key.pem")
Expand All @@ -106,11 +107,9 @@ async def lifespan(application: FastAPI):


def shutdown_server(*args):
print(f"{common.PRNT_API} Shutting down server...", flush=True)
# os.kill(os.getpid(), signal.SIGINT)
# server_thread.join()
print(f"{common.PRNT_API} Server shutdown complete.", flush=True)
sys.exit(0)
print(f"{common.PRNT_API} Force shutting down server...", flush=True)
os.kill(os.getpid(), signal.SIGINT)
# sys.exit(0)


def display_server_info():
Expand Down Expand Up @@ -152,12 +151,30 @@ def start_server():
print(f"{common.PRNT_API} Failed to start API server")


def run_server():
def run_app_window():
# Start the API server in a separate thread from main
fastapi_thread = threading.Thread(target=start_server)
fastapi_thread.daemon = True # let the parent kill the child thread at exit
fastapi_thread.start()
return fastapi_thread
window_thread = threading.Thread(target=GUI)
window_thread.daemon = True # let the parent kill the child thread at exit
window_thread.start()
return window_thread


# Create and run the Tkinter window
def GUI():
color_bg = "#333333"
root = tk.Tk()
root.title("Obrew Server")
root.geometry("500x500")
# Since /public folder is bundled inside _deps, we need to read from root `sys._MEIPASS`
root.iconbitmap(default=common.dep_path("public/favicon.ico"))
root.configure(bg=color_bg)
# Set font
Font_tuple = ("Verdana", 64, "bold")
root.bind("<Escape>", lambda e: e.widget.quit())
tk.Label(root, text="O🍺brew", font=Font_tuple).pack(fill=tk.BOTH, expand=True)
root.mainloop()
# Close server when user closes window
shutdown_server()


##############
Expand Down Expand Up @@ -197,6 +214,9 @@ def run_server():
# QRcode generation -> https://github.com/arjones/qr-generator/tree/main
@app.get("/", response_class=HTMLResponse)
async def connect_page(request: Request):
# Be sure to link `public/templates` to the app's dependency dir (_deps) via PyInstaller
templates_dir = common.dep_path(os.path.join("public", "templates"))
templates = Jinja2Templates(directory=templates_dir)
remote_url = server_info["remote_ip"]
local_url = server_info["local_ip"]
# Generate QR code - direct to remote url
Expand Down Expand Up @@ -252,7 +272,9 @@ def connect() -> classes.ConnectResponse:
### Start ###
#############


if __name__ == "__main__":
App = None
try:
# Find IP info
server_info = display_server_info()
Expand All @@ -262,8 +284,11 @@ def connect() -> classes.ConnectResponse:
print(f"{common.PRNT_API} API server started. Opening WebUI at {local_url}")
webbrowser.open(local_url, new=2)
print(f"{common.PRNT_API} Close this window to shutdown server.")
# Show a window
if isProd:
run_app_window()
# Start API server
start_server()
except KeyboardInterrupt:
print(f"{common.PRNT_API} User pressed Ctrl+C exiting...")
except (KeyboardInterrupt, Exception):
print(f"{common.PRNT_API} Something bad happenned, exiting...")
shutdown_server()
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "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": "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",
"build:api:dev": "pyinstaller --noconfirm --onedir --console --icon C:/Project Files/brain-dump-ai/backend-homebrew-ai/public/favicon.ico --name Obrew-Server --contents-directory _deps --clean --debug bootloader --add-data C:/Project Files/brain-dump-ai/backend-homebrew-ai/public;public/ --add-data C:/ProgramData/anaconda3/envs/llama-index/Lib/site-packages/llama_cpp;llama_cpp/ --add-data C:/Users/cybro/AppData/Roaming/Python/Python312/site-packages/posthog;posthog/ --add-data C:/Users/cybro/AppData/Roaming/Python/Python312/site-packages/chromadb;chromadb/ --add-data C:/Users/cybro/AppData/Roaming/Python/Python312/site-packages/importlib_resources;importlib_resources/ --add-data C:/Users/cybro/AppData/Roaming/Python/Python312/site-packages/backoff;backoff/ --add-data C:/Users/cybro/AppData/Roaming/Python/Python312/site-packages/pypika;pypika/ --add-data C:/Users/cybro/AppData/Roaming/Python/Python312/site-packages/hnswlib.cp312-win_amd64.pyd;. --hidden-import tiktoken_ext.openai_public --hidden-import tiktoken_ext C:/Project Files/brain-dump-ai/backend-homebrew-ai/backends/main.py",
"build:api:prod": "pyinstaller --noconfirm --onedir --windowed --icon C:/Project Files/brain-dump-ai/backend-homebrew-ai/public/favicon.ico --name Obrew-Server --contents-directory _deps --clean --add-data C:/Project Files/brain-dump-ai/backend-homebrew-ai/public;public/ --add-data C:/ProgramData/anaconda3/envs/llama-index/Lib/site-packages/llama_cpp;llama_cpp/ --hidden-import tiktoken_ext.openai_public --hidden-import tiktoken_ext --add-data C:/Users/cybro/AppData/Roaming/Python/Python312/site-packages/posthog;posthog/ --add-data C:/Users/cybro/AppData/Roaming/Python/Python312/site-packages/chromadb;chromadb/ --add-data C:/Users/cybro/AppData/Roaming/Python/Python312/site-packages/importlib_resources;importlib_resources/ --add-data C:/Users/cybro/AppData/Roaming/Python/Python312/site-packages/backoff;backoff/ --add-data C:/Users/cybro/AppData/Roaming/Python/Python312/site-packages/pypika;pypika/ --add-data C:/Users/cybro/AppData/Roaming/Python/Python312/site-packages/hnswlib.cp312-win_amd64.pyd;. 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",
Expand Down
File renamed without changes.
Loading

0 comments on commit a7ecdbe

Please sign in to comment.