Add basic backend infrastructure
Signed-off-by: Felipe Cardoso <felipe.cardoso@hotmail.it>
This commit is contained in:
0
backend/Dockerfile
Normal file
0
backend/Dockerfile
Normal file
0
backend/app/__init__.py
Normal file
0
backend/app/__init__.py
Normal file
0
backend/app/api/__init__.py
Normal file
0
backend/app/api/__init__.py
Normal file
0
backend/app/api/routes/__init__.py
Normal file
0
backend/app/api/routes/__init__.py
Normal file
34
backend/app/api/routes/samples.py
Normal file
34
backend/app/api/routes/samples.py
Normal 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))
|
||||
29
backend/app/api/routes/training.py
Normal file
29
backend/app/api/routes/training.py
Normal 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))
|
||||
0
backend/app/core/__init__.py
Normal file
0
backend/app/core/__init__.py
Normal file
21
backend/app/core/config.py
Normal file
21
backend/app/core/config.py
Normal 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
29
backend/app/main.py
Normal 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"}
|
||||
0
backend/app/models/__init__.py
Normal file
0
backend/app/models/__init__.py
Normal file
11
backend/app/models/sample.py
Normal file
11
backend/app/models/sample.py
Normal 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
|
||||
14
backend/app/models/training.py
Normal file
14
backend/app/models/training.py
Normal 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
|
||||
0
backend/app/services/__init__.py
Normal file
0
backend/app/services/__init__.py
Normal file
15
backend/app/services/sample_manager.py
Normal file
15
backend/app/services/sample_manager.py
Normal 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
|
||||
13
backend/app/services/training_monitor.py
Normal file
13
backend/app/services/training_monitor.py
Normal 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
13
backend/requirements.txt
Normal 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
|
||||
Reference in New Issue
Block a user