changed to custom package

This commit is contained in:
2025-09-23 05:45:24 +02:00
parent b37cb1bb9f
commit e3a28f1589
13 changed files with 26 additions and 132 deletions

View File

@@ -9,11 +9,11 @@ dependencies = [
"httpx>=0.28.1", "httpx>=0.28.1",
"langfuse>=3.5.0", "langfuse>=3.5.0",
"nicegui>=2.24.1", "nicegui>=2.24.1",
"niceguiasyncelement", "niceguiex",
"psutil>=6.1.0", "psutil>=6.1.0",
"pydantic-ai>=1.0.9", "pydantic-ai>=1.0.9",
"pyyaml>=6.0.2", "pyyaml>=6.0.2",
] ]
[tool.uv.sources] [tool.uv.sources]
niceguiasyncelement = { git = "https://git.project-insanity.de/gmarth/NiceGuiAsyncElement.git" } niceguiex = { git = "https://git.project-insanity.de/gmarth/NiceGUIEx.git" }

View File

@@ -1,16 +1,17 @@
from nicegui import ui from nicegui import ui
from niceguiasyncelement import AsyncCard from niceguiex.async_elements import AsyncColumn
from pathlib import Path from pathlib import Path
from utils import ollama from utils import ollama
from typing import Optional from typing import Optional
class ModelInfoComponent(AsyncCard): class ModelInfoComponent(AsyncColumn):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
async def build(self, model_info: dict) -> None: async def build(self, model_name: dict) -> None:
model_info = await ollama.model_info(model_name)
# self.classes('max-w-1/2') # self.classes('max-w-1/2')
self.style('width: 1200px; max-width: none') self.style('width: 1200px; max-width: none')
with self: with self:

View File

@@ -1,10 +1,10 @@
from nicegui import ui, binding from nicegui import ui, binding
from niceguiasyncelement import AsyncCard from niceguiex.async_elements import AsyncColumn
from pathlib import Path from pathlib import Path
from utils import ollama from utils import ollama
class OllamaDownloaderComponent(AsyncCard): class OllamaDownloaderComponent(AsyncColumn):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)

View File

@@ -1,12 +1,12 @@
from nicegui import ui, binding from nicegui import ui, binding
from niceguiasyncelement import AsyncCard from niceguiex.async_elements import AsyncColumn
from pathlib import Path from pathlib import Path
from utils import ollama from utils import ollama
from typing import Optional from typing import Optional
from pprint import pprint from pprint import pprint
class OllamaModelEditComponent(AsyncCard): class OllamaModelEditComponent(AsyncColumn):
model_info: dict model_info: dict
model_name_original: str model_name_original: str
@@ -73,6 +73,7 @@ class OllamaModelEditComponent(AsyncCard):
self.use_stop = False self.use_stop = False
async def build(self, model_name: str, model_info: dict) -> None: async def build(self, model_name: str, model_info: dict) -> None:
self.dialog_size = 'w-1/2'
self.classes('w-full') self.classes('w-full')
self.model_name = model_name self.model_name = model_name
self.model_name_original = model_name self.model_name_original = model_name

View File

@@ -1,11 +1,11 @@
from nicegui import ui from nicegui import ui
from niceguiasyncelement import AsyncCard from niceguiex.async_elements import AsyncColumn
from pathlib import Path from pathlib import Path
from utils import ollama from utils import ollama
from typing import Optional from typing import Optional
class ModelQuickTestComponent(AsyncCard): class ModelQuickTestComponent(AsyncColumn):
model: Optional[str] model: Optional[str]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):

View File

@@ -1,5 +1,4 @@
from .welcome import WelcomePage
from .ollama_manager import OllamaManagerPage from .ollama_manager import OllamaManagerPage
from .dashboard import DashboardPage from .dashboard import DashboardPage
__all__ = ['WelcomePage', 'OllamaManagerPage', 'DashboardPage'] __all__ = ['OllamaManagerPage', 'DashboardPage']

View File

@@ -2,7 +2,7 @@ from nicegui import ui
from utils import ollama from utils import ollama
from typing import Literal, List, Dict, Optional from typing import Literal, List, Dict, Optional
from pprint import pprint from pprint import pprint
from niceguiasyncelement import AsyncColumn from niceguiex.async_elements import AsyncColumn
from components.ollama_downloader import OllamaDownloaderComponent from components.ollama_downloader import OllamaDownloaderComponent
from components.ollama_model_edit import OllamaModelEditComponent from components.ollama_model_edit import OllamaModelEditComponent
from components.ollama_quick_test import ModelQuickTestComponent from components.ollama_quick_test import ModelQuickTestComponent
@@ -61,20 +61,9 @@ class OllamaManagerPage(AsyncColumn):
self.models_container.refresh() self.models_container.refresh()
async def _download_model_dialog(self): async def _download_model_dialog(self):
with ui.dialog().classes('max-w-none') as dialog: await OllamaDownloaderComponent.as_dialog()
await OllamaDownloaderComponent.create()
await dialog
self.models_container.refresh() self.models_container.refresh()
async def _test_model_dialog(self, model):
with ui.dialog() as dialog:
await ModelQuickTestComponent.create(model)
await dialog
async def _loaded_models(self):
loaded = await ollama.active_models()
print(loaded)
async def _delete_model(self, model): async def _delete_model(self, model):
with ui.dialog() as dialog, ui.card(): with ui.dialog() as dialog, ui.card():
ui.label('Are you sure?') ui.label('Are you sure?')
@@ -198,26 +187,14 @@ class OllamaManagerPage(AsyncColumn):
ui.label(f"Modified: {time_ago}").classes('text-xs text-grey-5') ui.label(f"Modified: {time_ago}").classes('text-xs text-grey-5')
except: except:
pass pass
with ui.row().classes('gap-2'): with ui.row().classes('gap-2'):
ui.button(icon='chat', on_click=lambda m=model['name']: self._test_model_dialog(m)).props('round flat').tooltip('Test Model') ui.button(icon='chat', on_click=lambda m=model['name']: ModelQuickTestComponent.as_dialog(m)).props('round flat').tooltip('Test Model')
ui.button(icon='edit', on_click=lambda m=model['name']: self._model_edit_model_dialog(m)).props('round flat').tooltip('Model Info') ui.button(icon='edit', on_click=lambda m=model['name']: self._model_edit_model_dialog(m)).props('round flat').tooltip('Model Info')
ui.button(icon='info', on_click=lambda m=model['name']: self._model_information_dialog(m)).props('round flat').tooltip('Model Info') ui.button(icon='info', on_click=lambda m=model['name']: ModelInfoComponent.as_dialog(m)).props('round flat').tooltip('Model Info')
ui.button(icon='delete', on_click=lambda m=model['name']: self._delete_model(m)).props('round flat color=negative').tooltip('Delete Model') ui.button(icon='delete', on_click=lambda m=model['name']: self._delete_model(m)).props('round flat color=negative').tooltip('Delete Model')
async def _model_edit_model_dialog(self, model_name): async def _model_edit_model_dialog(self, model_name):
model_info = await ollama.model_info(model_name) model_info = await ollama.model_info(model_name)
with ui.dialog() as dialog: result = await OllamaModelEditComponent.as_dialog(model_name, model_info)
await OllamaModelEditComponent.create(model_name, model_info)
result = await dialog
if result: if result:
self.models_container.refresh() # type: ignore self.models_container.refresh() # type: ignore
async def _model_information_dialog(self, model_name):
model_info = await ollama.model_info(model_name)
with ui.dialog().classes('max-w-none') as dialog:
await ModelInfoComponent.create(model_info)
await dialog

View File

@@ -1,10 +0,0 @@
from typing import Literal
from nicegui import ui
class WelcomePage(ui.column):
def __init__(self, *, wrap: bool = False, align_items: None | Literal['start'] | Literal['end'] | Literal['center'] | Literal['baseline'] | Literal['stretch'] = None) -> None:
super().__init__(wrap=wrap, align_items=align_items)
with self:
ui.label('something')

View File

@@ -1,7 +1,7 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Dict, Callable, Awaitable, Optional, Any from typing import Dict, Callable, Awaitable, Optional, Any
from nicegui import app from nicegui import app
from niceguiasyncelement import AsyncColumn from niceguiex.async_elements import AsyncColumn
import inspect import inspect
from utils import SystemMonitor, GPUMonitor, OllamaMonitor from utils import SystemMonitor, GPUMonitor, OllamaMonitor

View File

@@ -2,10 +2,8 @@ from typing import Dict, Callable, Awaitable
from nicegui import ui, binding, app from nicegui import ui, binding, app
from tools.base_tool import BaseTool, BasePage from tools.base_tool import BaseTool, BasePage
from utils import ollama from utils import ollama
from typing import Literal, List, Optional, Any from typing import Literal, List, Optional
from datetime import datetime from datetime import datetime
from dataclasses import dataclass
from niceguiasyncelement import AsyncColumn
import json import json

View File

@@ -1,72 +0,0 @@
from typing import Optional
from nicegui import ui
class AutoScrollArea(ui.scroll_area):
"""A scroll area that automatically scrolls to bottom when new content is added
Features:
- Auto-scrolls to bottom when at bottom and new content arrives
- Stops auto-scroll when user scrolls up manually
- Resumes auto-scroll when user scrolls back to bottom
"""
_auto_scroll_enabled: bool = True
_auto_scroll_timer: Optional[ui.timer] = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Set up scroll monitoring
# self._handle_scroll
self.on_scroll(self._handle_scroll_event)
self.on('wheel', self._handle_wheel, ['deltaY'])
# Create timer for auto-scrolling
self._auto_scroll_timer = ui.timer(0.1, lambda: self.scroll_to(percent=1))
self._auto_scroll_timer.activate()
def _scroll_event_test(self, e):
print(e.vertical_percentage)
def _handle_scroll_event(self, event_data):
"""Handle scroll events to detect when user is at bottom"""
if not self._auto_scroll_timer:
print('no timer instantiated.')
return
# If scrolled to bottom (100%), enable auto-scroll
if event_data.vertical_percentage > 0.99: # Using 0.99 for some tolerance
if not self._auto_scroll_timer.active:
self._auto_scroll_timer.activate()
def _handle_wheel(self, event_data):
"""Handle mouse wheel events to detect manual scrolling"""
delta_y = event_data.args['deltaY']
if not self._auto_scroll_timer:
print('no timer instantiated.')
return
# If scrolling up (negative delta), disable auto-scroll
if delta_y < 0:
if self._auto_scroll_timer.active:
self._auto_scroll_timer.deactivate()
def enable_auto_scroll(self):
"""Manually enable auto-scrolling"""
if self._auto_scroll_timer:
if not self._auto_scroll_timer.active:
self._auto_scroll_timer.activate()
def disable_auto_scroll(self):
"""Manually disable auto-scrolling"""
if self._auto_scroll_timer:
if self._auto_scroll_timer.active:
self._auto_scroll_timer.deactivate()
def cleanup(self):
"""Clean up timer when component is destroyed"""
if self._auto_scroll_timer:
self._auto_scroll_timer.deactivate()
self._auto_scroll_timer = None

View File

@@ -8,7 +8,7 @@ from pydantic_ai.models.openai import OpenAIChatModel
from pydantic_ai.providers.ollama import OllamaProvider from pydantic_ai.providers.ollama import OllamaProvider
from .chat_message import ChatMessageComponent from .chat_message import ChatMessageComponent
from .auto_scroll_area import AutoScrollArea from niceguiex.components import AutoScrollArea
class SimpleChatTool(BaseTool): class SimpleChatTool(BaseTool):

8
uv.lock generated
View File

@@ -128,7 +128,7 @@ dependencies = [
{ name = "httpx" }, { name = "httpx" },
{ name = "langfuse" }, { name = "langfuse" },
{ name = "nicegui" }, { name = "nicegui" },
{ name = "niceguiasyncelement" }, { name = "niceguiex" },
{ name = "psutil" }, { name = "psutil" },
{ name = "pydantic-ai" }, { name = "pydantic-ai" },
{ name = "pyyaml" }, { name = "pyyaml" },
@@ -140,7 +140,7 @@ requires-dist = [
{ name = "httpx", specifier = ">=0.28.1" }, { name = "httpx", specifier = ">=0.28.1" },
{ name = "langfuse", specifier = ">=3.5.0" }, { name = "langfuse", specifier = ">=3.5.0" },
{ name = "nicegui", specifier = ">=2.24.1" }, { name = "nicegui", specifier = ">=2.24.1" },
{ name = "niceguiasyncelement", git = "https://git.project-insanity.de/gmarth/NiceGuiAsyncElement.git" }, { name = "niceguiex", git = "https://git.project-insanity.de/gmarth/NiceGUIEx.git" },
{ name = "psutil", specifier = ">=6.1.0" }, { name = "psutil", specifier = ">=6.1.0" },
{ name = "pydantic-ai", specifier = ">=1.0.9" }, { name = "pydantic-ai", specifier = ">=1.0.9" },
{ name = "pyyaml", specifier = ">=6.0.2" }, { name = "pyyaml", specifier = ">=6.0.2" },
@@ -1009,9 +1009,9 @@ wheels = [
] ]
[[package]] [[package]]
name = "niceguiasyncelement" name = "niceguiex"
version = "0.1.0" version = "0.1.0"
source = { git = "https://git.project-insanity.de/gmarth/NiceGuiAsyncElement.git#2475cc8bd27b5f9b5047908968ab6d46b69dd4ca" } source = { git = "https://git.project-insanity.de/gmarth/NiceGUIEx.git#1012cf3d73f3d88485287ec819ef65ee9cb6fb64" }
dependencies = [ dependencies = [
{ name = "nicegui" }, { name = "nicegui" },
] ]