Create Native Menu Bar with PyQt to open Search, Config webpages

- Run FastAPI server in a separate thread.
  - This allows starting both the server and gui in parallel

- Create System Tray for Khoj
  - Contains menu items that open search or config pages in browser

- Rearrange code to have only the code required to start Backend and
  GUI in the run() method
  - Move the backend setup code into a separate method
This commit is contained in:
Debanjum Singh Solanky
2022-08-05 23:49:48 +03:00
parent 3a4e5de7fa
commit 083fefdd07
2 changed files with 75 additions and 5 deletions

View File

@@ -39,6 +39,7 @@ setup(
"pillow >= 9.0.1",
"aiofiles == 0.8.0",
"dateparser == 1.1.1",
"pyqt6 == 6.3.1",
],
include_package_data=True,
entry_points={"console_scripts": ["khoj = src.main:run"]},

View File

@@ -4,6 +4,7 @@ import time
from typing import Optional
from pathlib import Path
from functools import lru_cache
import webbrowser
# External Packages
import uvicorn
@@ -12,6 +13,7 @@ from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from PyQt6 import QtCore, QtGui, QtWidgets
# Internal Packages
from src.search_type import image_search, text_search
@@ -285,7 +287,7 @@ def shutdown_event():
print('INFO:\tConversation logs saved to disk.')
def run():
def setup_server():
# Load config from CLI
args = cli(sys.argv[1:])
@@ -312,11 +314,78 @@ def run():
global processor_config
processor_config = initialize_processor(args.config)
return args.host, args.port, args.socket
def run():
# Setup Application Server
host, port, socket = setup_server()
# Setup GUI
gui = QtWidgets.QApplication([])
gui.setQuitOnLastWindowClosed(False)
tray = create_system_tray()
# Start Application Server
if args.socket:
uvicorn.run(app, proxy_headers=True, uds=args.socket)
else:
uvicorn.run(app, host=args.host, port=args.port)
server = ServerThread(app, host, port, socket)
server.start()
gui.aboutToQuit.connect(server.terminate)
# Start the GUI
tray.show()
gui.exec()
class ServerThread(QtCore.QThread):
def __init__(self, app, host=None, port=None, socket=None):
super(ServerThread, self).__init__()
self.app = app
self.host = host
self.port = port
self.socket = socket
def __del__(self):
self.wait()
def run(self):
if self.socket:
uvicorn.run(app, proxy_headers=True, uds=self.socket)
else:
uvicorn.run(app, host=self.host, port=self.port)
def create_system_tray():
"""Create System Tray with Menu
Menu Actions should contain
1. option to open search page at localhost:8000/
2. option to open config page at localhost:8000/config
3. to quit
"""
# Create the system tray with icon
icon_path = web_directory / 'assets/icons/favicon-144x144.png'
icon = QtGui.QIcon(f'{icon_path.absolute()}')
tray = QtWidgets.QSystemTrayIcon(icon)
tray.setVisible(True)
# Create the menu and menu actions
menu = QtWidgets.QMenu()
menu_actions = [
('Search', lambda: webbrowser.open('http://localhost:8000/')),
('Configure', lambda: webbrowser.open('http://localhost:8000/config')),
('Quit', quit),
]
# Add the menu actions to the menu
for action_text, action_function in menu_actions:
menu_action = QtGui.QAction(action_text, menu)
menu_action.triggered.connect(action_function)
menu.addAction(menu_action)
# Add the menu to the system tray
tray.setContextMenu(menu)
return tray
if __name__ == '__main__':