Add basic backend infrastructure

Signed-off-by: Felipe Cardoso <felipe.cardoso@hotmail.it>
This commit is contained in:
2025-01-22 18:02:07 +01:00
parent 80c8537614
commit 805ed647cd
16 changed files with 179 additions and 0 deletions

0
backend/Dockerfile Normal file
View File

0
backend/app/__init__.py Normal file
View File

View File

View File

View File

@@ -0,0 +1,34 @@
from typing import List
from fastapi import APIRouter, HTTPException, Query
from app.models.sample import Sample
from app.services.sample_manager import SampleManager
router = APIRouter()
sample_manager = SampleManager()
@router.get("/list", response_model=List[Sample])
async def list_samples(
limit: int = Query(20, ge=1, le=100),
offset: int = Query(0, ge=0)
):
"""
List sample images with pagination
"""
try:
return await sample_manager.list_samples(limit, offset)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/latest", response_model=List[Sample])
async def get_latest_samples(count: int = Query(5, ge=1, le=20)):
"""
Get the most recent sample images
"""
try:
return await sample_manager.get_latest_samples(count)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))

View File

@@ -0,0 +1,29 @@
from fastapi import APIRouter, HTTPException
from app.models.training import TrainingStatus
from app.services.training_monitor import TrainingMonitor
router = APIRouter()
monitor = TrainingMonitor()
@router.get("/status", response_model=TrainingStatus)
async def get_training_status():
"""
Get current training status including progress, loss, and learning rate
"""
try:
return await monitor.get_status()
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/log")
async def get_training_log():
"""
Get recent training log entries
"""
try:
return await monitor.get_log()
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))

View File

View File

@@ -0,0 +1,21 @@
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
# SFTP Settings
SFTP_HOST: str
SFTP_USER: str
SFTP_PASSWORD: str
SFTP_PATH: str
SFTP_PORT: int = 22
# API Settings
API_VER_STR: str = "/api/v1"
PROJECT_NAME: str = "Training Monitor"
class Config:
env_file = ".env"
case_sensitive = True
settings = Settings()

29
backend/app/main.py Normal file
View File

@@ -0,0 +1,29 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.api.routes import training, samples
from app.core.config import settings
app = FastAPI(
title="Training Monitor API",
description="API for monitoring ML training progress and samples",
version="1.0.0",
)
# Configure CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # In production, replace with specific origins
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Include routers with versioning
app.include_router(training.router, prefix=f"{settings.API_VER_STR}/training", tags=["training"])
app.include_router(samples.router, prefix=f"{settings.API_VER_STR}/samples", tags=["samples"])
@app.get("/health")
async def health_check():
return {"status": "healthy"}

View File

View File

@@ -0,0 +1,11 @@
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
class Sample(BaseModel):
filename: str
url: str
created_at: datetime
step: Optional[int] = None

View File

@@ -0,0 +1,14 @@
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
class TrainingStatus(BaseModel):
current_step: int
total_steps: int
loss: float
learning_rate: float
eta_seconds: Optional[float]
steps_per_second: float
updated_at: datetime

View File

View File

@@ -0,0 +1,15 @@
from typing import List
from app.models.sample import Sample
class SampleManager:
async def list_samples(self, limit: int, offset: int) -> List[Sample]:
# Implementation for listing samples from SFTP
# This is a placeholder - actual implementation needed
pass
async def get_latest_samples(self, count: int) -> List[Sample]:
# Implementation for getting latest samples
# This is a placeholder - actual implementation needed
pass

View File

@@ -0,0 +1,13 @@
from app.models.training import TrainingStatus
class TrainingMonitor:
async def get_status(self) -> TrainingStatus:
# Implementation for parsing tqdm output
# This is a placeholder - actual implementation needed
pass
async def get_log(self):
# Implementation for getting recent log entries
# This is a placeholder - actual implementation needed
pass

13
backend/requirements.txt Normal file
View File

@@ -0,0 +1,13 @@
fastapi>=0.104.0
uvicorn>=0.24.0
python-multipart>=0.0.6
python-jose[cryptography]>=3.3.0
passlib[bcrypt]>=1.7.4
pydantic>=2.4.2
pydantic-settings>=2.0.3
paramiko>=3.3.1
python-dotenv>=1.0.0
aiofiles>=23.2.1
pytest>=7.4.3
httpx>=0.25.1
pytest-asyncio>=0.21.1