Open Web interface within Desktop app in GUI mode (#429)

Previously the GUI mode (with khoj --gui or using the desktop app) would open the web interface in the users default web browser. Now the web interface is just rendered within the app itself using PyQT's Webview. This gives it a more proper app like feel
This commit is contained in:
Debanjum 2023-08-07 17:48:30 -07:00 committed by GitHub
commit 14a816d173
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 33 additions and 43 deletions

View file

@ -24,7 +24,7 @@ For more detailed Windows installation and troubleshooting, see [Windows Install
### 2. Start
Run the following command from your terminal to start the Khoj backend and open Khoj in your browser.
Run the following command in your terminal to start the Khoj backend and open the Khoj native GUI
```shell
khoj --gui

View file

@ -1,13 +1,11 @@
# Standard Packages
import webbrowser
# External Packages
from PySide6 import QtGui, QtWidgets
from PySide6.QtCore import Qt
from PySide6 import QtGui
from PySide6.QtCore import Qt, QThread, QUrl
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtWebEngineCore import QWebEnginePage
# Internal Packages
from khoj.utils import constants
from PySide6.QtCore import QThread
class ServerThread(QThread):
@ -22,11 +20,12 @@ class ServerThread(QThread):
self.start_server_func()
class MainWindow(QtWidgets.QMainWindow):
class MainWindow(QWebEngineView):
"""Create Window to Navigate users to the web UI"""
def __init__(self, host: str, port: int):
def __init__(self, url: str):
super(MainWindow, self).__init__()
self.base_url = url
# Initialize Configure Window
self.setWindowTitle("Khoj")
@ -35,25 +34,23 @@ class MainWindow(QtWidgets.QMainWindow):
icon_path = constants.web_directory / "assets/icons/favicon-128x128.png"
self.setWindowIcon(QtGui.QIcon(f"{icon_path.absolute()}"))
# Initialize Configure Window Layout
self.wlayout = QtWidgets.QVBoxLayout()
# Open Khoj Web App Root
self.webpage = QWebEnginePage()
self.setPage(self.webpage)
self.webpage.load(QUrl(self.base_url))
# Add a Label that says "Khoj Configuration" to the Window
self.wlayout.addWidget(QtWidgets.QLabel("Welcome to Khoj"))
# Add a Button to open the Web UI at http://host:port/config
self.open_web_ui_button = QtWidgets.QPushButton("Open Web UI")
self.open_web_ui_button.clicked.connect(lambda: webbrowser.open(f"http://{host}:{port}/config"))
self.wlayout.addWidget(self.open_web_ui_button)
# Set the central widget of the Window. Widget will expand
# to take up all the space in the window by default.
self.config_window = QtWidgets.QWidget()
self.config_window.setLayout(self.wlayout)
self.setCentralWidget(self.config_window)
self.position_window()
def show_page(self, page: str = "", maximized=False):
def load_page():
self.webpage.load(QUrl(f"{self.base_url}/{page}"))
if maximized:
self.showMaximized()
else:
self.show()
return load_page
def position_window(self):
"Position the window at center of X axis and near top on Y axis"
window_rectangle = self.geometry()

View file

@ -1,11 +1,8 @@
# Standard Packages
import webbrowser
# External Packages
from PySide6 import QtGui, QtWidgets
# Internal Packages
from khoj.utils import constants, state
from khoj.utils import constants
from khoj.interface.desktop.main_window import MainWindow
@ -25,9 +22,9 @@ def create_system_tray(gui: QtWidgets.QApplication, main_window: MainWindow):
# Create the menu and menu actions
menu = QtWidgets.QMenu()
menu_actions = [
("Search", lambda: webbrowser.open(f"http://{state.host}:{state.port}/")),
("Configure", lambda: webbrowser.open(f"http://{state.host}:{state.port}/config")),
("App", main_window.show),
("Search", main_window.show_page()),
("Chat", main_window.show_page("chat")),
("Configure", main_window.show_page("config")),
("Quit", gui.quit),
]

View file

@ -13,7 +13,6 @@ import logging
import threading
import warnings
from platform import system
import webbrowser
# Ignore non-actionable warnings
warnings.filterwarnings("ignore", message=r"snapshot_download.py has been made private", category=FutureWarning)
@ -85,8 +84,9 @@ def run():
from khoj.interface.desktop.system_tray import create_system_tray
# Setup GUI
url = f"http://{args.host}:{args.port}"
gui = QtWidgets.QApplication([])
main_window = MainWindow(args.host, args.port)
main_window = MainWindow(url)
# System tray is only available on Windows, MacOS.
# On Linux (Gnome) the System tray is not supported.
@ -102,17 +102,13 @@ def run():
configure_routes(app)
server = ServerThread(start_server_func=lambda: start_server(app, host=args.host, port=args.port))
url = f"http://{args.host}:{args.port}"
logger.info(f"🌗 Khoj is running at {url}")
try:
startup_url = url if args.config else f"{url}/config"
webbrowser.open(startup_url)
except:
logger.warning(f"🚧 Unable to open browser. Please open {url} manually to configure or use Khoj.")
# Show Main Window on First Run Experience or if on Linux
if args.config is None or system() not in ["Windows", "Darwin"]:
main_window.show()
# Show config window on first run and main window otherwise
startup_window = (
main_window.show_page(maximized=True) if args.config else main_window.show_page("config", maximized=True)
)
startup_window()
# Setup Signal Handlers
signal.signal(signal.SIGINT, sigint_handler)