Backend integration with the website UI

This commit is contained in:
2026-04-12 03:27:52 +00:00
parent 53c67d569a
commit 2d379bece7
16 changed files with 568 additions and 67 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ FROM python:3.9-slim
# Install ffmpeg and other necessary packages
RUN apt-get update && \
apt-get install -y ffmpeg libgl1-mesa-glx libglib2.0-0 && \
apt-get install -y ffmpeg libgl1 libglib2.0-0 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
+24
View File
@@ -100,6 +100,30 @@ Returns a JSON object detailing the room status, counts, and pairings.
}
```
### `/api/study-rooms` (GET)
Returns a list of all recorded study room data.
### `/api/study-rooms/history` (GET)
Returns a list of all recorded study room data from the last 24 hours, sorted by most recent first.
**Response:**
```json
{
"data": [
{
"location": {
"type": "Point",
"coordinates": [-77.3079, 38.8315]
},
"db": 65.2,
"date": "2026-04-12T14:30:00.000Z"
}
]
}
```
## Client Integration Notes
For the ESP32/M5GO client (`m5go/main.py`), ensure you update the `WS_URL` variable to point to the correct local IP address of the machine running this backend server.
+2
View File
@@ -8,3 +8,5 @@ python-multipart
ultralytics
opencv-python-headless
scipy
pymongo
pydantic
+100
View File
@@ -8,13 +8,46 @@ import json
import base64
import urllib.request
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, File, UploadFile
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from pydantic import BaseModel
from typing import List, Optional
from datetime import datetime, timedelta
from pymongo import MongoClient
from dotenv import load_dotenv
from vision import analyze_room_image
from fastapi.middleware.cors import CORSMiddleware
load_dotenv()
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# MongoDB Setup
MONGO_URI = os.getenv("MONGODB_URI", "mongodb://localhost:27017/")
mongo_client = MongoClient(MONGO_URI)
db = mongo_client.study_buddy_db
study_rooms_collection = db.study_rooms
# Pydantic models for Study Room Data
class GeoJSONPoint(BaseModel):
type: str = "Point"
coordinates: List[float]
class StudyRoomData(BaseModel):
room_id: Optional[str] = None
location: GeoJSONPoint
db: float
date: Optional[datetime] = None
SAMPLE_RATE = 16000
BITS_PER_SAMPLE = 16
NUM_CHANNELS = 1
@@ -253,3 +286,70 @@ async def check_room_status(file: UploadFile = File(...)):
contents = await file.read()
result = analyze_room_image(contents)
return result
UMD_LOCATIONS = [
{ "id": 'esj', "name": 'Edward St. John (ESJ)', "lng": -76.94209511596014, "lat": 38.987133359608755 },
{ "id": 'mckeldin', "name": 'McKeldin Library', "lng": -76.94494907523277, "lat": 38.986021017749366 },
{ "id": 'hornbake', "name": 'Hornbake Library', "lng": -76.94161787005467, "lat": 38.988233373664826 },
{ "id": 'stem', "name": 'STEM Library', "lng": -76.93942003731279, "lat": 38.988991437126195 },
{ "id": 'clarice', "name": 'Clarice Library', "lng": -76.9500912552473, "lat": 38.990547823732285 },
{ "id": 'yahentamitsi', "name": 'Yahentamitsi', "lng": -76.9448027183373, "lat": 38.99108961575231 },
{ "id": 'iribe', "name": 'Iribe', "lng": -76.93643838603555, "lat": 38.98933701397555 },
{ "id": 'reckord', "name": 'Reckord Armory', "lng": -76.93897470250619, "lat": 38.98609556181066 },
{ "id": 'stamp', "name": 'Stamp Student Union', "lng": -76.94473083972326, "lat": 38.988130238874874 }
]
@app.post("/api/study-rooms")
async def create_study_room_data(data: StudyRoomData):
# Check if the coordinates match one of the known locations (with small tolerance)
is_valid_location = False
req_lng, req_lat = data.location.coordinates[0], data.location.coordinates[1]
for loc in UMD_LOCATIONS:
if abs(loc["lng"] - req_lng) < 0.0001 and abs(loc["lat"] - req_lat) < 0.0001:
is_valid_location = True
# Override coordinates to exactly match known location for consistency
data.location.coordinates = [loc["lng"], loc["lat"]]
data.room_id = loc["id"]
break
if not is_valid_location:
from fastapi import HTTPException
raise HTTPException(status_code=400, detail="Invalid location. Coordinates must correspond to a known UMD location.")
if not data.date:
data.date = datetime.utcnow()
doc = data.dict()
result = study_rooms_collection.insert_one(doc)
return {"id": str(result.inserted_id), "room_id": data.room_id, "status": "success"}
@app.get("/api/study-rooms")
async def get_study_room_data():
rooms = list(study_rooms_collection.find({}, {"_id": 0}))
return {"data": rooms}
@app.get("/api/study-rooms/history")
async def get_study_room_history():
"""Get all study room data from the last 24 hours."""
twenty_four_hours_ago = datetime.utcnow() - timedelta(hours=24)
rooms = list(study_rooms_collection.find(
{"date": {"$gte": twenty_four_hours_ago}},
{"_id": 0}
).sort("date", -1))
return {"data": rooms}
@app.get("/{full_path:path}")
async def serve_spa(full_path: str):
static_dir = "static"
if not os.path.exists(static_dir):
return {"error": "Static directory not found. Please build the frontend."}
static_path = os.path.join(static_dir, full_path)
if os.path.isfile(static_path):
return FileResponse(static_path)
index_path = os.path.join(static_dir, "index.html")
if os.path.exists(index_path):
return FileResponse(index_path)
return {"error": "index.html not found in static directory"}