feat: Add new API endpoints and HTML pages for ML model management
- Implemented HTML pages for datasets, models, training, testing, and results. - Created API endpoints for managing repositories, results, tests, and training sessions. - Added functionality for streaming training progress via Server-Sent Events (SSE). - Introduced a Dockerfile for the ML runner with necessary dependencies. - Developed an SDK for user code execution within the runner container. - Enhanced CSS styles for improved UI layout and navigation. - Established a layout template for consistent HTML structure across pages. - Added JavaScript for dynamic interactions on the models page. - Implemented WebSocket handling for real-time communication with kiosk devices and controllers. - Implemented model registration and management API at /api/models - Added Gitea proxy API for repository interactions at /api/repos - Created results API for listing and comparing training results at /api/results - Developed training management API for enqueueing and retrieving training jobs at /api/trainings - Introduced SSE endpoint for live training progress updates - Added HTML pages for models, datasets, and training management - Created a Dockerfile for the ML runner with necessary dependencies - Developed SDK for user code execution within the runner container - Enhanced CSS styles for improved UI/UX - Implemented WebSocket communication for real-time device and controller interactions in the kiosk system
This commit is contained in:
90
ml/core/model_spec.py
Normal file
90
ml/core/model_spec.py
Normal file
@@ -0,0 +1,90 @@
|
||||
"""Parse e validazione del contratto `model.yml` nelle repo utente.
|
||||
|
||||
Schema sintetico (vedi piano):
|
||||
name, type, version, python
|
||||
train: {entrypoint, inputs, outputs, metrics}
|
||||
test: {entrypoint, io, input_schema[], output_schema[]}
|
||||
resources: {cpu, mem_mb, gpu}
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Optional
|
||||
|
||||
import yaml
|
||||
from pydantic import BaseModel, ValidationError
|
||||
|
||||
from core import gitea, redis_client
|
||||
|
||||
|
||||
class _FieldSpec(BaseModel):
|
||||
name: str
|
||||
dtype: str
|
||||
min: Optional[float] = None
|
||||
max: Optional[float] = None
|
||||
unit: Optional[str] = None
|
||||
|
||||
|
||||
class _Train(BaseModel):
|
||||
entrypoint: str
|
||||
inputs: dict = {}
|
||||
outputs: dict = {}
|
||||
metrics: dict = {}
|
||||
|
||||
|
||||
class _Test(BaseModel):
|
||||
entrypoint: str
|
||||
io: str = "stdio_json"
|
||||
input_schema: list[_FieldSpec] = []
|
||||
output_schema: list[_FieldSpec] = []
|
||||
|
||||
|
||||
class ModelSpec(BaseModel):
|
||||
name: str
|
||||
type: str
|
||||
version: str = "0.1.0"
|
||||
python: str = "3.11"
|
||||
train: _Train
|
||||
test: Optional[_Test] = None
|
||||
resources: dict = {}
|
||||
|
||||
|
||||
def parse_yaml(content: bytes | str) -> dict:
|
||||
"""Parsa stringa YAML → dict validato. Solleva ValueError su errore."""
|
||||
if isinstance(content, bytes):
|
||||
content = content.decode("utf-8")
|
||||
try:
|
||||
raw = yaml.safe_load(content) or {}
|
||||
spec = ModelSpec(**raw)
|
||||
return spec.model_dump()
|
||||
except (yaml.YAMLError, ValidationError) as e:
|
||||
raise ValueError(f"invalid model.yml: {e}") from e
|
||||
|
||||
|
||||
async def fetch_and_parse_spec(owner_repo: str, ref: str) -> Optional[dict]:
|
||||
"""Recupera model.yml dalla repo alla revisione e lo parsa.
|
||||
Cache Redis `ml:modelspec:{repo}:{ref}` TTL 1h.
|
||||
"""
|
||||
cache_key = f"ml:modelspec:{owner_repo}:{ref}"
|
||||
try:
|
||||
cached = await redis_client.client().get(cache_key)
|
||||
if cached:
|
||||
import json
|
||||
return json.loads(cached)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
raw = await gitea.get_file_raw(owner_repo, ref, "model.yml")
|
||||
except Exception:
|
||||
try:
|
||||
raw = await gitea.get_file_raw(owner_repo, ref, "model.yaml")
|
||||
except Exception:
|
||||
return None
|
||||
spec = parse_yaml(raw)
|
||||
|
||||
try:
|
||||
import json
|
||||
await redis_client.client().set(cache_key, json.dumps(spec), ex=3600)
|
||||
except Exception:
|
||||
pass
|
||||
return spec
|
||||
Reference in New Issue
Block a user