feat: add multi-server control panel and host-aware sync

This commit is contained in:
Luca Sacchi Ricciardi
2026-04-25 15:40:20 +02:00
parent 3ba6a9a41c
commit f60781bd7f
13 changed files with 641 additions and 41 deletions
+26 -9
View File
@@ -2,12 +2,13 @@
Models endpoints - Gestione dei modelli Ollama
"""
from fastapi import APIRouter, HTTPException
from fastapi import APIRouter, HTTPException, Query
from pydantic import BaseModel
from typing import Any, Dict, List, Optional
from datetime import datetime
import requests
import logging
from urllib.parse import urlparse
from app.config import settings
logger = logging.getLogger(__name__)
@@ -22,6 +23,18 @@ def ensure_rw_api_enabled() -> None:
detail="Endpoint non disponibile"
)
def resolve_ollama_host(host: Optional[str]) -> str:
"""Resolve target Ollama host, optionally overridden by query parameter."""
if not host:
return settings.OLLAMA_HOST
parsed = urlparse(host.strip())
if parsed.scheme not in {"http", "https"} or not parsed.netloc:
raise HTTPException(status_code=422, detail="Invalid Ollama host URL")
return host.rstrip("/")
class ModelInfo(BaseModel):
"""Informazioni su un modello"""
name: str
@@ -60,7 +73,7 @@ class ModelsResponse(BaseModel):
}
@router.get("/models", response_model=ModelsResponse)
async def get_models():
async def get_models(host: Optional[str] = Query(default=None)):
"""
Recupera l'elenco di tutti i modelli caricati in Ollama
@@ -70,9 +83,10 @@ async def get_models():
Raises:
HTTPException: Se Ollama non è disponibile
"""
target_host = resolve_ollama_host(host)
try:
response = requests.get(
f"{settings.OLLAMA_HOST}/api/tags",
f"{target_host}/api/tags",
timeout=settings.OLLAMA_TIMEOUT
)
@@ -121,16 +135,17 @@ async def get_models():
@router.get("/models/running")
async def get_running_models() -> Dict[str, Any]:
async def get_running_models(host: Optional[str] = Query(default=None)) -> Dict[str, Any]:
"""
Recupera i modelli attualmente residenti in memoria, equivalenti a `ollama ps`.
Returns:
Dict[str, Any]: Payload con modelli running e conteggio
"""
target_host = resolve_ollama_host(host)
try:
response = requests.get(
f"{settings.OLLAMA_HOST}/api/ps",
f"{target_host}/api/ps",
timeout=settings.OLLAMA_TIMEOUT
)
@@ -168,7 +183,7 @@ async def get_running_models() -> Dict[str, Any]:
)
@router.get("/models/{model_name}", response_model=ModelInfo)
async def get_model(model_name: str):
async def get_model(model_name: str, host: Optional[str] = Query(default=None)):
"""
Recupera le informazioni di un modello specifico
@@ -181,9 +196,10 @@ async def get_model(model_name: str):
Raises:
HTTPException: Se il modello non esiste o Ollama non è disponibile
"""
target_host = resolve_ollama_host(host)
try:
response = requests.get(
f"{settings.OLLAMA_HOST}/api/tags",
f"{target_host}/api/tags",
timeout=settings.OLLAMA_TIMEOUT
)
@@ -224,7 +240,7 @@ async def get_model(model_name: str):
@router.get("/models/{model_name}/show")
async def get_model_show(model_name: str) -> Dict[str, Any]:
async def get_model_show(model_name: str, host: Optional[str] = Query(default=None)) -> Dict[str, Any]:
"""
Recupera le informazioni estese di un modello tramite endpoint Ollama /api/show.
@@ -234,9 +250,10 @@ async def get_model_show(model_name: str) -> Dict[str, Any]:
Returns:
Dict[str, Any]: Dati estesi del modello
"""
target_host = resolve_ollama_host(host)
try:
response = requests.post(
f"{settings.OLLAMA_HOST}/api/show",
f"{target_host}/api/show",
json={"model": model_name},
timeout=settings.OLLAMA_TIMEOUT
)