feat: enhance application functionality and telemetry monitoring

- Added new scripts in `package.json` for Python dependency installation and sidecar compilation.
- Integrated telemetry fetching in `src/App.tsx` to monitor CPU, RAM, GPU, and disk usage.
- Implemented model downloading functionality with progress tracking in `src/App.tsx`.
- Updated `Footer` and `Header` components to display telemetry data and settings options.
- Enhanced Tauri configuration for sidecar execution and application window settings.
- Updated Python requirements in `requirements.txt` to include additional dependencies for improved functionality.
This commit is contained in:
Evandro Fonseca Junior committed 2026-01-14 23:57:14 -03:00
1 parent 482b28513e
commit 08e154894a
24 files changed
+1110 -91

No files matched your search

+139
View File
@@ -0,0 +1,139 @@
"""
Servidor FastAPI para expor telemetria e download de modelos.
Utiliza Server-Sent Events (SSE) para streaming de progresso em tempo real.
"""
import sys
import os
import json
from pathlib import Path
from typing import Dict, List
from fastapi import FastAPI, HTTPException
from fastapi.responses import StreamingResponse, JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
import asyncio
# Detecta se está rodando como binário ou script
if getattr(sys, 'frozen', False):
# Caminho do executável (PyInstaller)
BASE_DIR = os.path.dirname(sys.executable)
CONFIG_PATH = os.path.join(BASE_DIR, "modelConfig.yaml")
MODELS_DIR = os.path.join(BASE_DIR, "models")
else:
# Rodando como script Python
# Ajusta PYTHONPATH antes dos imports relativos
script_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.dirname(os.path.dirname(script_dir)) # Sobe para raiz do projeto
if project_root not in sys.path:
sys.path.insert(0, project_root)
BASE_DIR = project_root
CONFIG_PATH = os.path.join(BASE_DIR, "modelConfig.yaml")
MODELS_DIR = os.path.join(BASE_DIR, "src-python", "app", "models")
# Importações relativas (funcionam quando executado como módulo)
from .telemetry import SystemTelemetry
from .model_downloader import ModelDownloader
app = FastAPI(title="LocalAI API", version="1.0.0")
# CORS para permitir comunicação com frontend Tauri
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Em produção, restringir ao localhost
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Instâncias globais
downloader = ModelDownloader(models_dir=MODELS_DIR)
# Modelos de dados
class ModelInfo(BaseModel):
id: str
name: str
quant: str
size_gb: float
repo: str
filename: str
description: str
class DownloadRequest(BaseModel):
model_id: str
repo_id: str
filename: str
# Cache de modelos disponíveis (pode ser carregado de JSON)
MODELS_REGISTRY: List[Dict] = [
{
"id": "lfm-2.5-1.2b",
"name": "Liquid LFM 2.5",
"quant": "Q6_K",
"size_gb": 1.12,
"repo": "LiquidAI/LFM2.5-1.2B-Instruct-GGUF",
"filename": "LFM2.5-1.2B-Instruct-Q6_K.gguf",
"description": "Otimizado para arquitetura sequencial de alta performance."
}
]
@app.get("/api/telemetry")
async def get_telemetry():
"""Retorna telemetria do sistema em tempo real."""
return SystemTelemetry.get_stats()
@app.get("/api/models")
async def list_models():
"""Lista todos os modelos disponíveis com status de download."""
models_with_status = []
for model in MODELS_REGISTRY:
model_path = downloader.get_model_path(model["repo"], model["filename"])
model_copy = model.copy()
model_copy["downloaded"] = model_path.exists() if model_path else False
models_with_status.append(model_copy)
return {"models": models_with_status}
@app.post("/api/models/download")
async def download_model(request: DownloadRequest):
"""
Inicia download de modelo com progresso via SSE.
O frontend deve consumir como EventSource.
"""
async def generate_progress():
try:
async for progress_event in downloader.download_with_progress(
repo_id=request.repo_id,
filename=request.filename
):
yield f"data: {json.dumps(progress_event)}\n\n"
except Exception as e:
error_event = {"type": "error", "message": str(e)}
yield f"data: {json.dumps(error_event)}\n\n"
return StreamingResponse(
generate_progress(),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"X-Accel-Buffering": "no"
}
)
@app.get("/api/models/{model_id}/status")
async def get_model_status(model_id: str):
"""Verifica se um modelo específico está baixado."""
model = next((m for m in MODELS_REGISTRY if m["id"] == model_id), None)
if not model:
raise HTTPException(status_code=404, detail="Modelo não encontrado")
model_path = downloader.get_model_path(model["repo"], model["filename"])
return {
"model_id": model_id,
"downloaded": model_path.exists() if model_path else False,
"path": str(model_path) if model_path else None
}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8000)