Last active
February 20, 2025 13:43
-
-
Save roflsunriz/c4da95f38afdb39f15635e426f458cf3 to your computer and use it in GitHub Desktop.
OpenWebUI.py : Open-WebUIサーバーを127.0.0.1:8081で自動的に開始し、文字列が現れるのを待った後Firefoxでページを開く。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import subprocess | |
import time | |
import psutil | |
import threading | |
import os | |
try: | |
import tkinter as tk | |
from tkinter import ttk | |
except ImportError: | |
subprocess.check_call(["pip", "install", "tk"]) | |
import tkinter as tk | |
from tkinter import ttk | |
# Configuration | |
OPENWEUI_HOST = "127.0.0.1" | |
OPENWEUI_PORT = 8081 | |
OPENWEUI_COMMAND = f"open-webui serve --host {OPENWEUI_HOST} --port {OPENWEUI_PORT}" | |
FIREFOX_PATH = r"C:\Program Files\Mozilla Firefox\firefox.exe" | |
# 必要なライブラリチェック | |
required_packages = ['psutil'] | |
for package in required_packages: | |
try: | |
__import__(package) | |
except ImportError: | |
print(f"Installing {package}...") | |
subprocess.check_call(["pip", "install", package]) | |
def start_openwebui(host, port, log_callback, ready_callback=None): | |
"""GUI用に改造したサーバー起動関数""" | |
# 環境変数を設定 | |
env = os.environ.copy() | |
env.update({ | |
"CORS_ALLOW_ORIGINS": f"http://{host}:{port}", | |
"DISABLE_INSPECTOR": "1", | |
"WEBSOCKET_MODE": "asgi" # WebSocketモードを明示的に指定 | |
}) | |
proc = subprocess.Popen( | |
["open-webui", "serve", "--host", host, "--port", str(port)], | |
stdout=subprocess.PIPE, | |
stderr=subprocess.STDOUT, | |
env=env | |
) | |
def output_reader(): | |
server_ready = False | |
while True: | |
line = proc.stdout.readline() | |
if not line: | |
time.sleep(0.1) | |
continue | |
decoded = line.decode('cp932', errors='replace').strip() | |
log_callback(decoded) | |
# 起動完了検知(1回だけ実行) | |
if not server_ready and any(msg in decoded for msg in ["Application startup complete", "Uvicorn running"]): | |
log_callback("Server ready!") | |
if ready_callback: | |
ready_callback() | |
server_ready = True # フラグを立てて重複実行防止 | |
# プロセスが終了したらループを抜ける | |
if proc.poll() is not None: | |
break | |
threading.Thread(target=output_reader, daemon=True).start() | |
return proc | |
def is_firefox_running(): | |
"""Check if Firefox is already running.""" | |
for proc in psutil.process_iter(): | |
try: | |
if "firefox.exe" in proc.name().lower(): | |
return True | |
except (psutil.NoSuchProcess, psutil.AccessDenied): | |
pass | |
return False | |
class Application(tk.Tk): | |
def __init__(self): | |
super().__init__() | |
self.title("OpenWebUI Controller") | |
# 設定フレーム | |
self.settings_frame = ttk.LabelFrame(self, text="Settings") | |
self.settings_frame.pack(padx=10, pady=5, fill="x") | |
# ホスト設定 | |
ttk.Label(self.settings_frame, text="Host:").grid(row=0, column=0) | |
self.host_entry = ttk.Entry(self.settings_frame) | |
self.host_entry.insert(0, "127.0.0.1") | |
self.host_entry.grid(row=0, column=1) | |
# ポート設定 | |
ttk.Label(self.settings_frame, text="Port:").grid(row=1, column=0) | |
self.port_entry = ttk.Entry(self.settings_frame) | |
self.port_entry.insert(0, "8081") | |
self.port_entry.grid(row=1, column=1) | |
# Firefoxチェックボックス | |
self.use_firefox = tk.BooleanVar(value=True) | |
self.firefox_check = ttk.Checkbutton( | |
self.settings_frame, | |
text="Use Firefox", | |
variable=self.use_firefox | |
) | |
self.firefox_check.grid(row=2, columnspan=2) | |
# 実行ボタン | |
self.start_btn = ttk.Button(self, text="Start", command=self.start_process) | |
self.start_btn.pack(pady=5, side=tk.LEFT) | |
# 停止ボタン追加 | |
self.stop_btn = ttk.Button( | |
self, | |
text="Stop", | |
command=self.stop_process, | |
state=tk.DISABLED | |
) | |
self.stop_btn.pack(pady=5, side=tk.LEFT) | |
# ログ表示エリア | |
self.log_frame = ttk.Frame(self) | |
self.log_frame.pack(fill="both", expand=True, padx=5, pady=5) | |
# スクロールバー追加 | |
self.log_scroll = ttk.Scrollbar(self.log_frame) | |
self.log_text = tk.Text(self.log_frame, wrap="word", yscrollcommand=self.log_scroll.set) | |
self.log_scroll.config(command=self.log_text.yview) | |
self.log_text.pack(side="left", fill="both", expand=True) | |
self.log_scroll.pack(side="right", fill="y") | |
def log_message(self, message): | |
self.log_text.insert("end", message + "\n") | |
self.log_text.see("end") # 自動で最下部にスクロール | |
self.update_idletasks() | |
def start_process(self): | |
self.start_btn.config(state=tk.DISABLED) | |
self.stop_btn.config(state=tk.NORMAL) # 停止ボタンを有効化 | |
host = self.host_entry.get() | |
port = self.port_entry.get() | |
# サーバー起動処理(コールバック付き) | |
self.server_proc = start_openwebui( | |
host, | |
port, | |
self.log_message, | |
ready_callback=lambda: self.launch_firefox(host, port) if self.use_firefox.get() else None | |
) | |
def launch_firefox(self, host, port): | |
url = f"http://{host}:{port}" | |
if not is_firefox_running(): | |
subprocess.Popen([FIREFOX_PATH, url]) | |
else: | |
subprocess.Popen([FIREFOX_PATH, "-new-tab", url]) | |
def stop_process(self): | |
if hasattr(self, 'server_proc'): | |
try: | |
parent = psutil.Process(self.server_proc.pid) | |
children = parent.children(recursive=True) | |
for child in children: | |
child.kill() | |
gone, still_alive = psutil.wait_procs(children, timeout=5) | |
parent.kill() | |
parent.wait(5) | |
except psutil.NoSuchProcess: | |
pass | |
self.log_message("Server stopped!") | |
self.start_btn.config(state=tk.NORMAL) | |
self.stop_btn.config(state=tk.DISABLED) | |
if __name__ == "__main__": | |
root = Application() | |
root.mainloop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment