change to NAS
This commit is contained in:
+205
@@ -764,6 +764,211 @@ async def upload_cloud_removal_model(
|
||||
raise HTTPException(status_code=500, detail=f"Upload failed: {str(e)}")
|
||||
|
||||
|
||||
@app.post("/api/land-classification/upload")
|
||||
async def upload_land_classification_model(
|
||||
file: UploadFile = File(...),
|
||||
model_type: str = Form("mobilenet"), # mobilenet, cnn, swin, xgboost, etc.
|
||||
epoch: int = Form(0),
|
||||
train_accuracy: float = Form(0.0),
|
||||
val_accuracy: float = Form(0.0),
|
||||
train_loss: float = Form(0.0),
|
||||
val_loss: float = Form(0.0),
|
||||
num_classes: int = Form(10),
|
||||
input_size: int = Form(64),
|
||||
description: str = Form("")
|
||||
):
|
||||
"""Upload land classification model with metadata"""
|
||||
|
||||
# Debug logging
|
||||
print(f"[Land Upload] Received parameters:")
|
||||
print(f" File: {file.filename}")
|
||||
print(f" Model Type: {model_type}")
|
||||
print(f" Epoch: {epoch}")
|
||||
print(f" Train Accuracy: {train_accuracy}")
|
||||
print(f" Val Accuracy: {val_accuracy}")
|
||||
print(f" Train Loss: {train_loss}")
|
||||
print(f" Val Loss: {val_loss}")
|
||||
print(f" Num Classes: {num_classes}")
|
||||
print(f" Input Size: {input_size}")
|
||||
print(f" Description: {description}")
|
||||
|
||||
# Validate file extension
|
||||
valid_extensions = ['.pth', '.pkl', '.joblib', '.h5', '.keras']
|
||||
if not any(file.filename.endswith(ext) for ext in valid_extensions):
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Only {', '.join(valid_extensions)} files are allowed"
|
||||
)
|
||||
|
||||
# Security check
|
||||
if ".." in file.filename or "/" in file.filename or "\\" in file.filename:
|
||||
raise HTTPException(status_code=400, detail="Invalid filename")
|
||||
|
||||
try:
|
||||
model_dir = Path("land_classification_model")
|
||||
model_dir.mkdir(exist_ok=True)
|
||||
|
||||
# Save uploaded file
|
||||
file_path = model_dir / file.filename
|
||||
|
||||
# Check if file already exists
|
||||
if file_path.exists():
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Model {file.filename} already exists"
|
||||
)
|
||||
|
||||
# Write file
|
||||
with open(file_path, "wb") as f:
|
||||
content = await file.read()
|
||||
f.write(content)
|
||||
|
||||
file_size = file_path.stat().st_size
|
||||
|
||||
# Save metadata as JSON sidecar file
|
||||
metadata_file = file_path.with_suffix(file_path.suffix + '.json')
|
||||
|
||||
metadata_dict = {
|
||||
"filename": file.filename,
|
||||
"model_type": model_type,
|
||||
"epoch": epoch,
|
||||
"train_accuracy": train_accuracy,
|
||||
"val_accuracy": val_accuracy,
|
||||
"train_loss": train_loss,
|
||||
"val_loss": val_loss,
|
||||
"num_classes": num_classes,
|
||||
"input_size": input_size,
|
||||
"description": description,
|
||||
"uploaded_at": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
with open(metadata_file, 'w') as f:
|
||||
json.dump(metadata_dict, f, indent=2)
|
||||
|
||||
print(f"[Land Upload] Saved model: {file_path}")
|
||||
print(f"[Land Upload] Saved metadata: {metadata_file}")
|
||||
|
||||
return {
|
||||
"message": f"Successfully uploaded {file.filename}",
|
||||
"filename": file.filename,
|
||||
"size_mb": round(file_size / 1024 / 1024, 2),
|
||||
"path": str(file_path),
|
||||
"metadata": metadata_dict
|
||||
}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
print(f"[Land Upload] Error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
raise HTTPException(status_code=500, detail=f"Upload failed: {str(e)}")
|
||||
|
||||
|
||||
@app.get("/api/land-classification/models")
|
||||
async def list_land_classification_models():
|
||||
"""List all uploaded land classification models"""
|
||||
model_dir = Path("land_classification_model")
|
||||
if not model_dir.exists():
|
||||
return {"models": [], "count": 0}
|
||||
|
||||
models = []
|
||||
# Search for model files
|
||||
for model_file in model_dir.rglob("*"):
|
||||
# Skip JSON metadata files
|
||||
if model_file.suffix == '.json':
|
||||
continue
|
||||
|
||||
# Only include model files
|
||||
valid_extensions = ['.pth', '.pkl', '.joblib', '.h5', '.keras']
|
||||
if not any(model_file.name.endswith(ext) for ext in valid_extensions):
|
||||
continue
|
||||
|
||||
try:
|
||||
# Try to load metadata from JSON sidecar file
|
||||
metadata_file = Path(str(model_file) + '.json')
|
||||
if metadata_file.exists():
|
||||
with open(metadata_file, 'r') as f:
|
||||
metadata = json.load(f)
|
||||
|
||||
models.append({
|
||||
"filename": model_file.name,
|
||||
"path": str(model_file),
|
||||
"relative_path": str(model_file.relative_to(model_dir)),
|
||||
"model_type": metadata.get('model_type', 'unknown'),
|
||||
"epoch": metadata.get('epoch', 0),
|
||||
"train_accuracy": metadata.get('train_accuracy', 0),
|
||||
"val_accuracy": metadata.get('val_accuracy', 0),
|
||||
"train_loss": metadata.get('train_loss', 0),
|
||||
"val_loss": metadata.get('val_loss', 0),
|
||||
"num_classes": metadata.get('num_classes', 10),
|
||||
"input_size": metadata.get('input_size', 64),
|
||||
"description": metadata.get('description', ''),
|
||||
"created": model_file.stat().st_mtime,
|
||||
"size_mb": model_file.stat().st_size / (1024 * 1024),
|
||||
"has_metadata": True
|
||||
})
|
||||
else:
|
||||
# No metadata file, use defaults
|
||||
models.append({
|
||||
"filename": model_file.name,
|
||||
"path": str(model_file),
|
||||
"relative_path": str(model_file.relative_to(model_dir)),
|
||||
"model_type": "unknown",
|
||||
"epoch": 0,
|
||||
"train_accuracy": 0,
|
||||
"val_accuracy": 0,
|
||||
"train_loss": 0,
|
||||
"val_loss": 0,
|
||||
"num_classes": 10,
|
||||
"input_size": 64,
|
||||
"description": "",
|
||||
"created": model_file.stat().st_mtime,
|
||||
"size_mb": model_file.stat().st_size / (1024 * 1024),
|
||||
"has_metadata": False
|
||||
})
|
||||
except Exception as e:
|
||||
print(f"[Land Models] Error loading {model_file}: {e}")
|
||||
continue
|
||||
|
||||
# Sort by creation time (newest first)
|
||||
models.sort(key=lambda x: x['created'], reverse=True)
|
||||
|
||||
return {
|
||||
"models": models,
|
||||
"count": len(models)
|
||||
}
|
||||
|
||||
|
||||
@app.delete("/api/land-classification/models/{filename}")
|
||||
async def delete_land_classification_model(filename: str):
|
||||
"""Delete a land classification model"""
|
||||
model_dir = Path("land_classification_model")
|
||||
model_path = model_dir / filename
|
||||
|
||||
# Security check
|
||||
if ".." in filename or "/" in filename or "\\" in filename:
|
||||
raise HTTPException(status_code=400, detail="Invalid filename")
|
||||
|
||||
if not model_path.exists():
|
||||
raise HTTPException(status_code=404, detail=f"Model not found: {filename}")
|
||||
|
||||
try:
|
||||
# Delete model file
|
||||
model_path.unlink()
|
||||
|
||||
# Delete metadata file if exists
|
||||
metadata_file = Path(str(model_path) + '.json')
|
||||
if metadata_file.exists():
|
||||
metadata_file.unlink()
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Deleted land classification model: {filename}"
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to delete: {str(e)}")
|
||||
|
||||
|
||||
@app.delete("/api/cloud-removal/models/{filename}")
|
||||
async def delete_cloud_removal_model(filename: str):
|
||||
"""Xóa cloud removal model"""
|
||||
|
||||
Reference in New Issue
Block a user