demeter

Autonomous Hydroponic Intelligence

backend/server/main.py (2707B)


  1import sys
  2import os
  3from dotenv import load_dotenv
  4
  5# --- PATH FIX ---
  6current_dir = os.path.dirname(os.path.abspath(__file__))
  7# Adjust this depending on where main.py sits relative to root folder
  8project_root = os.path.abspath(os.path.join(current_dir, "../../"))
  9sys.path.append(project_root)
 10
 11agent_root = os.path.abspath(os.path.join(project_root, "agent"))
 12sys.path.append(agent_root)
 13
 14# Load env from root
 15env_path = os.path.join(project_root, ".env")
 16if os.path.exists(env_path):
 17    load_dotenv(env_path)
 18# ----------------
 19
 20from fastapi import FastAPI, UploadFile, File, Form
 21from fastapi.middleware.cors import CORSMiddleware
 22from fastapi.responses import StreamingResponse
 23
 24from Sentinel.agent import FMUBuilder
 25
 26# Import the logic functions
 27from backend.server.functions import (
 28    process_ingest,
 29    process_search,
 30    process_text_query,
 31    process_audio_search,
 32    process_cycle_stream,
 33    process_ask_query,
 34    process_similar_crops,
 35)
 36
 37app = FastAPI()
 38
 39app.add_middleware(
 40    CORSMiddleware,
 41    allow_origins=["*"],  # Allow all for dev
 42    allow_credentials=True,
 43    allow_methods=["*"],
 44    allow_headers=["*"],
 45)
 46
 47print("🌱 Server Starting...")
 48
 49builder = FMUBuilder()
 50
 51print("✅ Server Ready.")
 52
 53
 54@app.post("/ingest")
 55async def ingest_endpoint(
 56    file: UploadFile = File(...), sensors: str = Form(...), metadata: str = Form(...)
 57):
 58    return await process_ingest(file, sensors, metadata, builder)
 59
 60
 61@app.post("/search")
 62async def search_endpoint(file: UploadFile = File(...), sensors: str = Form(...)):
 63    return await process_search(file, sensors, builder)
 64
 65
 66@app.post("/run-cycle-stream")
 67async def run_cycle_stream_endpoint(
 68    file: UploadFile = File(...), sensors: str = Form(...)
 69):
 70    return StreamingResponse(
 71        process_cycle_stream(file, sensors, builder),
 72        media_type="text/event-stream",
 73    )
 74
 75
 76@app.post("/query-text")
 77async def text_query_endpoint(
 78    query: str = Form(...),
 79    crop_id: str = Form(None),  # optional
 80):
 81    return await process_text_query(query, crop_id)
 82
 83
 84@app.post("/query-similar")
 85async def similar_crops_endpoint(
 86    crop_id: str = Form(...),
 87    crop_name: str = Form(...),
 88    payload: str = Form(...),
 89):
 90    return await process_similar_crops(crop_id, crop_name, payload)
 91
 92
 93@app.post("/query-audio")
 94async def audio_query_endpoint(file: UploadFile = File(...)):
 95    return await process_audio_search(file)
 96
 97
 98@app.post("/ask-demeter")
 99async def ask_demeter_endpoint(
100    query: str = Form(...), context: str = Form(...), language: str = Form(...)
101):
102    return await process_ask_query(query, context, language)
103
104
105if __name__ == "__main__":
106    import uvicorn
107
108    uvicorn.run(app, host="0.0.0.0", port=8000)