Files
ArchGPUFrontend/src/main.py

141 lines
4.5 KiB
Python

import os
from dotenv import load_dotenv
from nicegui import ui, app
from langfuse import get_client
from pydantic_ai.agent import Agent
from components import Header, Sidebar
from pages import DashboardPage, OllamaManagerPage
from utils import GPUMonitor, SystemMonitor, OllamaMonitor
import logging
from tools import TOOLS
from tools.base_tool import ToolContext, set_tool_context
load_dotenv()
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logging.getLogger('watchfiles').setLevel(logging.WARNING)
if all(var in os.environ for var in ['LANGFUSE_PUBLIC_KEY', 'LANGFUSE_SECRET_KEY', 'LANGFUSE_HOST']):
langfuse = get_client()
if langfuse.auth_check():
print("Langfuse client is authenticated and ready!")
else:
print("Authentication failed. Please check your credentials and host.")
Agent.instrument_all()
app.add_static_files('/static', 'src/static')
# Create monitor instances (bindable dataclasses)
system_monitor = SystemMonitor()
gpu_monitor = GPUMonitor()
ollama_monitor = OllamaMonitor()
app.timer(2.0, system_monitor.update)
app.timer(2.0, gpu_monitor.update)
app.timer(2.0, ollama_monitor.update)
# Initialize tool context
tool_context = ToolContext(
system_monitor=system_monitor,
gpu_monitor=gpu_monitor,
ollama_monitor=ollama_monitor
)
set_tool_context(tool_context)
def create_layout(current_route='/'):
# Force dark mode
ui.dark_mode(True)
ui.query('.nicegui-content').classes('p-0 m-0')
# Add custom CSS
ui.add_head_html('<link rel="stylesheet" type="text/css" href="/static/style.css">')
Header(system_monitor, gpu_monitor, ollama_monitor)
Sidebar(current_route)
# Create tool routes with sub-pages support
for tool_baseroute, tool in TOOLS.items():
# Register all routes defined by the tool
for sub_path, handler in tool.routes.items():
# Construct full route path
full_route = tool.baseroute + sub_path if sub_path else tool.baseroute
# Create a closure to capture the current handler and route
def create_route_handler(route, handler_func):
@ui.page(route)
async def tool_page():
create_layout(route)
await handler_func()
return tool_page
# Register the route
create_route_handler(full_route, handler)
@ui.page('/')
async def index_page():
create_layout('/')
DashboardPage(system_monitor, gpu_monitor, ollama_monitor)
@ui.page('/ollama')
async def ollama_page():
create_layout('/ollama')
await OllamaManagerPage.create()
# await page._load_models()
@ui.page('/settings')
async def settings_page():
create_layout('/settings')
with ui.element('div').classes('main-content w-full'):
with ui.column().classes('w-full max-w-4xl mx-auto p-6 gap-6'):
ui.label('Settings').classes('text-2xl font-bold text-white')
with ui.card().classes('metric-card p-6'):
ui.label('Refresh Intervals').classes('text-lg font-bold text-white mb-4')
with ui.column().classes('gap-4'):
with ui.row().classes('items-center justify-between'):
ui.label('System Stats').classes('text-white')
ui.select(['1s', '2s', '5s', '10s'], value='2s').props('outlined dense color=cyan')
with ui.row().classes('items-center justify-between'):
ui.label('GPU Temperature').classes('text-white')
ui.select(['1s', '2s', '5s', '10s'], value='5s').props('outlined dense color=cyan')
with ui.card().classes('metric-card p-6 mt-4'):
ui.label('About').classes('text-lg font-bold text-white mb-4')
with ui.column().classes('gap-2'):
with ui.row().classes('items-center gap-2'):
ui.icon('computer', color='cyan')
ui.label('ArchGPU Frontend v0.1.0').classes('text-white')
with ui.row().classes('items-center gap-2'):
ui.icon('smart_toy', color='orange')
ui.label('Ollama v0.11.11').classes('text-white')
if __name__ in {"__main__", "__mp_main__"}:
ui.run(
title=os.getenv('APP_TITLE', 'ArchGPU Frontend'),
storage_secret=os.getenv('APP_STORAGE_SECRET'),
port=int(os.getenv('APP_PORT', '8080')),
show=os.getenv("APP_SHOW", 'false').lower() == "true",
dark=True
)