diff --git a/backend/api/v1/chat.py b/backend/api/v1/chat.py index 0fe2c06..3a128b1 100644 --- a/backend/api/v1/chat.py +++ b/backend/api/v1/chat.py @@ -14,19 +14,6 @@ from config import settings router = APIRouter() -@router.get("/models", response_model=List[str]) -async def list_models(): - try: - async with httpx.AsyncClient(timeout=settings.REQUEST_TIMEOUT) as client: - resp = await client.get(settings.LM_STUDIO_MODELS) - resp.raise_for_status() - data = resp.json() - return [m["id"] for m in data.get("data", [])] - except Exception: - logger.exception("Error fetching models") - raise HTTPException(status_code=500, detail="Failed to fetch models") - - @router.post("/chat", response_model=ChatResponse) async def chat_endpoint(payload: ChatRequest): try: diff --git a/backend/api/v1/models.py b/backend/api/v1/models.py new file mode 100644 index 0000000..7344b6e --- /dev/null +++ b/backend/api/v1/models.py @@ -0,0 +1,69 @@ +# api/v1/models_info.py +import httpx +import json +from fastapi import APIRouter +from config import settings +from models.llm_model import LmModelMeta +from services import redis_service +from typing import List +from utils.logging import logger +from config import settings + +router = APIRouter() + +@router.get("/models", response_model=List[str]) +async def list_models(): + try: + async with httpx.AsyncClient(timeout=settings.REQUEST_TIMEOUT) as client: + resp = await client.get(settings.LM_STUDIO_MODELS) + resp.raise_for_status() + data = resp.json() + return [m["id"] for m in data.get("data", [])] + except Exception: + logger.exception("Error fetching models") + raise HTTPException(status_code=500, detail="Failed to fetch models") + +@router.get("/default-model", response_model=str) +async def get_default_model(): + return settings.MODEL_NAME + +@router.get("/models-info", response_model=List[LmModelMeta]) +async def get_model_info(): + raw = redis_service.r.get("modelInfoList") + if not raw: + return [] + try: + data = json.loads(raw) + return [LmModelMeta(**item) for item in data] + except Exception: + return [] + +@router.post("/models-info/update", response_model=List[LmModelMeta]) +async def update_model_info(): + import httpx + + try: + async with httpx.AsyncClient(timeout=settings.REQUEST_TIMEOUT) as client: + resp = await client.get(settings.LM_STUDIO_MODELS) + resp.raise_for_status() + model_list = [m["id"] for m in resp.json().get("data", [])] + except Exception: + raise HTTPException(status_code=500, detail="Failed to fetch models") + + enriched = [] + for name in model_list: + enriched.append(LmModelMeta( + name=name, + description=f"Modello {name.split('/')[-1]}", + year=2024, # puoi migliorare con heuristics + features=[ + "Quantizzazione INT4" if "int4" in name.lower() else "Precisione standard", + f"{name.split('-')[0].upper()} origin", + f"{name.split('-')[1]} variant" if "-" in name else "Generico" + ] + )) + + redis_service.r.set("modelInfoList", json.dumps([m.dict() for m in enriched]), ex=86400) + return enriched + + diff --git a/backend/main.py b/backend/main.py index 4d03048..51c3207 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,7 +1,7 @@ # main.py (new project entrypoint) from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware -from api.v1 import chat, sessions # import the routers +from api.v1 import chat, sessions, models # import the routersS app = FastAPI() @@ -15,3 +15,4 @@ app.add_middleware( # Mount the router under /v1 app.include_router(chat.router, prefix="/v1") app.include_router(sessions.router, prefix="/v1") +app.include_router(models.router, prefix="/v1") diff --git a/backend/models/llm_model.py b/backend/models/llm_model.py new file mode 100644 index 0000000..cff8cd0 --- /dev/null +++ b/backend/models/llm_model.py @@ -0,0 +1,11 @@ +# models/llm_model.py +from pydantic import BaseModel +from typing import List, Optional + +class LmModelMeta(BaseModel): + name: str + description: Optional[str] = None + year: Optional[int] = 0 + features: Optional[List[str]] = [] + + diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 785c1ee..7da389a 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -19,6 +19,14 @@ export default function App() { const sessionId = getSessionId(); const [showEditor, setShowEditor] = useState(false); const [editorMode, setEditorMode] = useState("create"); + const [defaultModelName, setDefaultModelName] = useState(""); + + useEffect(() => { + fetch("/v1/default-model") + .then(res => res.text()) + .then(setDefaultModelName) + .catch(err => console.error("Errore nel recupero modello di default", err)); + }, []); useEffect(() => { const saved = localStorage.getItem("preferredTheme"); @@ -124,6 +132,7 @@ export default function App() { sessionId={sessionId} sessionModelName={sessionModelName} sessionName={sessionName} + defaultModelName={defaultModelName} /> {showEditor && ( diff --git a/frontend/src/ChatHeader.jsx b/frontend/src/ChatHeader.jsx index c3fe0b5..c785bd5 100644 --- a/frontend/src/ChatHeader.jsx +++ b/frontend/src/ChatHeader.jsx @@ -8,8 +8,10 @@ export default function ChatHeader({ onFreshStart, onCreateSession, onManageSession, + onShowModels, sessionId, - sessionName + sessionName, + defaultModelName }) { const hasSession = Boolean(sessionId); @@ -70,7 +72,12 @@ export default function ChatHeader({ {/* Center column: titolo solo se c'è sessione */}
+ {defaultModel || "Non disponibile"} +
+| Nome | +Descrizione | +Anno | +Caratteristiche | +
|---|---|---|---|
| Caricamento… | +|||
| Nessun modello disponibile | +|||
| {model.name} | +{model.description || "—"} | +{model.year || "—"} | +
+
|
+