|
|
@@ -0,0 +1,76 @@
|
|
|
+import os
|
|
|
+from fastapi import FastAPI, File, UploadFile
|
|
|
+from ultralytics import YOLO
|
|
|
+from dotenv import load_dotenv
|
|
|
+import io
|
|
|
+import shutil
|
|
|
+from PIL import Image
|
|
|
+
|
|
|
+from src.infrastructure.vision_service import VertexVisionService
|
|
|
+from src.infrastructure.repository import MongoPalmOilRepository
|
|
|
+from src.application.analyze_bunch import AnalyzeBunchUseCase
|
|
|
+
|
|
|
+# Load environment variables
|
|
|
+load_dotenv()
|
|
|
+
|
|
|
+app = FastAPI(title="Palm Oil Ripeness Service (DDD)")
|
|
|
+
|
|
|
+# Initialize YOLO model
|
|
|
+yolo_model = YOLO('best.pt')
|
|
|
+
|
|
|
+# Initialize DDD Components
|
|
|
+vision_service = VertexVisionService(
|
|
|
+ project_id=os.getenv("PROJECT_ID", "your-project-id"),
|
|
|
+ location=os.getenv("LOCATION", "us-central1")
|
|
|
+)
|
|
|
+repo = MongoPalmOilRepository(
|
|
|
+ uri=os.getenv("MONGO_URI"),
|
|
|
+ db_name=os.getenv("DB_NAME", "palm_oil_db")
|
|
|
+)
|
|
|
+analyze_use_case = AnalyzeBunchUseCase(vision_service, repo)
|
|
|
+
|
|
|
+@app.post("/detect")
|
|
|
+async def detect_ripeness(file: UploadFile = File(...)):
|
|
|
+ # 1. Save file temporarily for YOLO and Vertex
|
|
|
+ temp_path = f"temp_{file.filename}"
|
|
|
+ with open(temp_path, "wb") as buffer:
|
|
|
+ shutil.copyfileobj(file.file, buffer)
|
|
|
+
|
|
|
+ try:
|
|
|
+ # 2. Run YOLO detection
|
|
|
+ img = Image.open(temp_path)
|
|
|
+ results = yolo_model(img)
|
|
|
+
|
|
|
+ detections = []
|
|
|
+ for r in results:
|
|
|
+ for box in r.boxes:
|
|
|
+ detections.append({
|
|
|
+ "class": yolo_model.names[int(box.cls)],
|
|
|
+ "confidence": round(float(box.conf), 2),
|
|
|
+ "box": box.xyxy.tolist()[0]
|
|
|
+ })
|
|
|
+
|
|
|
+ # 3. If detections found, analyze the first one (or all) for deeper insights
|
|
|
+ results_summary = []
|
|
|
+ if detections:
|
|
|
+ # For this MVP, we analyze the primary detection
|
|
|
+ primary_detection = detections[0]
|
|
|
+ record_id = analyze_use_case.execute(temp_path, primary_detection)
|
|
|
+
|
|
|
+ return {
|
|
|
+ "status": "success",
|
|
|
+ "record_id": record_id,
|
|
|
+ "detections": detections,
|
|
|
+ "message": "FFB processed and archived successfully"
|
|
|
+ }
|
|
|
+
|
|
|
+ return {"status": "no_detection", "message": "No palm oil FFB detected"}
|
|
|
+
|
|
|
+ finally:
|
|
|
+ # Clean up temp file
|
|
|
+ if os.path.exists(temp_path):
|
|
|
+ os.remove(temp_path)
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ import uvicorn
|
|
|
+ uvicorn.run(app, host="0.0.0.0", port=8000)
|