Spaces:
Sleeping
Sleeping
fixig some things
Browse files
server.py
CHANGED
|
@@ -75,6 +75,9 @@ audio_processor = AudioProcessor(str(MODEL_DIR))
|
|
| 75 |
# MongoDB state
|
| 76 |
mongo_client: AsyncMongoClient | None = None
|
| 77 |
users_collection = None
|
|
|
|
|
|
|
|
|
|
| 78 |
|
| 79 |
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
| 80 |
|
|
@@ -319,29 +322,76 @@ async def vcam_generator_loop():
|
|
| 319 |
@app.get("/")
|
| 320 |
async def health_check():
|
| 321 |
"""Health check endpoint."""
|
|
|
|
| 322 |
return {
|
| 323 |
"status": "ok",
|
| 324 |
"service": "AFS Tracking Backend",
|
| 325 |
-
"mongodb":
|
| 326 |
}
|
| 327 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 328 |
@app.on_event("startup")
|
| 329 |
async def startup_event():
|
| 330 |
-
global mongo_client, users_collection
|
| 331 |
mongo_uri = os.getenv("MONGODB_URI", "mongodb://localhost:27017")
|
| 332 |
mongo_db_name = os.getenv("MONGODB_DB", "afs")
|
| 333 |
|
| 334 |
try:
|
| 335 |
mongo_client = AsyncMongoClient(mongo_uri, serverSelectionTimeoutMS=5000)
|
| 336 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 337 |
await users_collection.create_index("email", unique=True)
|
| 338 |
-
logger.info("Connected to MongoDB and initialized
|
| 339 |
except Exception as e:
|
| 340 |
-
logger.warning(f"MongoDB connection failed: {e}.
|
| 341 |
mongo_client = None
|
| 342 |
users_collection = None
|
|
|
|
|
|
|
|
|
|
| 343 |
|
| 344 |
asyncio.create_task(vcam_generator_loop())
|
|
|
|
| 345 |
|
| 346 |
|
| 347 |
@app.on_event("shutdown")
|
|
@@ -792,35 +842,34 @@ async def get_audio_angles():
|
|
| 792 |
async def upload_audio_file(
|
| 793 |
file: UploadFile = File(...)
|
| 794 |
):
|
| 795 |
-
"""Upload recorded audio file from frontend."""
|
| 796 |
try:
|
| 797 |
-
|
| 798 |
-
|
| 799 |
-
|
| 800 |
-
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
| 801 |
-
ext = Path(file.filename).suffix
|
| 802 |
-
if not ext:
|
| 803 |
-
ext = ".wav"
|
| 804 |
|
| 805 |
-
|
| 806 |
-
|
| 807 |
-
|
| 808 |
-
|
|
|
|
|
|
|
|
|
|
| 809 |
|
| 810 |
return {
|
| 811 |
"ok": True,
|
| 812 |
-
"message": "Audio file
|
| 813 |
-
"filename":
|
|
|
|
| 814 |
}
|
| 815 |
except Exception as e:
|
| 816 |
-
logger.error(f"Error
|
| 817 |
raise HTTPException(status_code=500, detail=str(e))
|
| 818 |
|
| 819 |
@app.post("/api/audio/set-angle")
|
| 820 |
async def set_desired_angle(
|
| 821 |
angle: float = Form(...)
|
| 822 |
):
|
| 823 |
-
"""Send a desired angle to the audio processing system."""
|
| 824 |
try:
|
| 825 |
if not (0 <= angle <= 360):
|
| 826 |
raise HTTPException(
|
|
@@ -828,24 +877,70 @@ async def set_desired_angle(
|
|
| 828 |
detail="Angle must be between 0 and 360 degrees"
|
| 829 |
)
|
| 830 |
|
| 831 |
-
|
| 832 |
-
|
| 833 |
-
|
| 834 |
-
|
| 835 |
-
|
| 836 |
-
|
| 837 |
|
| 838 |
-
logger.info(f"Set desired angle {angle}°")
|
| 839 |
|
| 840 |
return {
|
| 841 |
"ok": True,
|
| 842 |
-
"message": f"Desired angle set to {angle}°",
|
| 843 |
"angle": angle
|
| 844 |
}
|
| 845 |
except HTTPException:
|
| 846 |
raise
|
| 847 |
except Exception as e:
|
| 848 |
-
logger.error(f"Error setting angle: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 849 |
raise HTTPException(status_code=500, detail=str(e))
|
| 850 |
|
| 851 |
if __name__ == "__main__":
|
|
|
|
| 75 |
# MongoDB state
|
| 76 |
mongo_client: AsyncMongoClient | None = None
|
| 77 |
users_collection = None
|
| 78 |
+
audio_recordings_collection = None
|
| 79 |
+
audio_settings_collection = None
|
| 80 |
+
audio_angles_collection = None
|
| 81 |
|
| 82 |
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
| 83 |
|
|
|
|
| 322 |
@app.get("/")
|
| 323 |
async def health_check():
|
| 324 |
"""Health check endpoint."""
|
| 325 |
+
status_db = "connected" if users_collection is not None else "disconnected"
|
| 326 |
return {
|
| 327 |
"status": "ok",
|
| 328 |
"service": "AFS Tracking Backend",
|
| 329 |
+
"mongodb": status_db
|
| 330 |
}
|
| 331 |
|
| 332 |
+
async def mongodb_reconnect_loop():
|
| 333 |
+
"""Background task to attempt MongoDB reconnection if disconnected."""
|
| 334 |
+
global mongo_client, users_collection, audio_recordings_collection, audio_settings_collection
|
| 335 |
+
while True:
|
| 336 |
+
if users_collection is None:
|
| 337 |
+
mongo_uri = os.getenv("MONGODB_URI", "mongodb://localhost:27017")
|
| 338 |
+
mongo_db_name = os.getenv("MONGODB_DB", "afs")
|
| 339 |
+
try:
|
| 340 |
+
logger.info("Attempting to reconnect to MongoDB...")
|
| 341 |
+
client = AsyncMongoClient(mongo_uri, serverSelectionTimeoutMS=5000)
|
| 342 |
+
# Ping to force connection verification
|
| 343 |
+
await client.admin.command('ping')
|
| 344 |
+
|
| 345 |
+
# Re-initialize
|
| 346 |
+
mongo_client = client
|
| 347 |
+
db = mongo_client[mongo_db_name]
|
| 348 |
+
users_collection = db["users"]
|
| 349 |
+
audio_recordings_collection = db["audio_recordings"]
|
| 350 |
+
audio_settings_collection = db["audio_settings"]
|
| 351 |
+
audio_angles_collection = db["audio_angles"]
|
| 352 |
+
|
| 353 |
+
await users_collection.create_index("email", unique=True)
|
| 354 |
+
logger.info("Successfully reconnected to MongoDB.")
|
| 355 |
+
except Exception as e:
|
| 356 |
+
logger.error(f"MongoDB reconnection failed: {e}")
|
| 357 |
+
mongo_client = None
|
| 358 |
+
users_collection = None
|
| 359 |
+
audio_recordings_collection = None
|
| 360 |
+
audio_settings_collection = None
|
| 361 |
+
audio_angles_collection = None
|
| 362 |
+
|
| 363 |
+
# Wait before next check (e.g., 10 seconds)
|
| 364 |
+
await asyncio.sleep(10)
|
| 365 |
+
|
| 366 |
@app.on_event("startup")
|
| 367 |
async def startup_event():
|
| 368 |
+
global mongo_client, users_collection, audio_recordings_collection, audio_settings_collection, audio_angles_collection
|
| 369 |
mongo_uri = os.getenv("MONGODB_URI", "mongodb://localhost:27017")
|
| 370 |
mongo_db_name = os.getenv("MONGODB_DB", "afs")
|
| 371 |
|
| 372 |
try:
|
| 373 |
mongo_client = AsyncMongoClient(mongo_uri, serverSelectionTimeoutMS=5000)
|
| 374 |
+
# Ping to force connection verification
|
| 375 |
+
await mongo_client.admin.command('ping')
|
| 376 |
+
|
| 377 |
+
db = mongo_client[mongo_db_name]
|
| 378 |
+
users_collection = db["users"]
|
| 379 |
+
audio_recordings_collection = db["audio_recordings"]
|
| 380 |
+
audio_settings_collection = db["audio_settings"]
|
| 381 |
+
audio_angles_collection = db["audio_angles"]
|
| 382 |
+
|
| 383 |
await users_collection.create_index("email", unique=True)
|
| 384 |
+
logger.info("Connected to MongoDB and initialized collections.")
|
| 385 |
except Exception as e:
|
| 386 |
+
logger.warning(f"MongoDB connection failed on startup: {e}. Starting reconnection loop.")
|
| 387 |
mongo_client = None
|
| 388 |
users_collection = None
|
| 389 |
+
audio_recordings_collection = None
|
| 390 |
+
audio_settings_collection = None
|
| 391 |
+
audio_angles_collection = None
|
| 392 |
|
| 393 |
asyncio.create_task(vcam_generator_loop())
|
| 394 |
+
asyncio.create_task(mongodb_reconnect_loop())
|
| 395 |
|
| 396 |
|
| 397 |
@app.on_event("shutdown")
|
|
|
|
| 842 |
async def upload_audio_file(
|
| 843 |
file: UploadFile = File(...)
|
| 844 |
):
|
| 845 |
+
"""Upload recorded audio file from frontend and save to MongoDB."""
|
| 846 |
try:
|
| 847 |
+
# Read file content for DB persistence
|
| 848 |
+
file_content = await file.read()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 849 |
|
| 850 |
+
if audio_recordings_collection is not None:
|
| 851 |
+
await audio_recordings_collection.insert_one({
|
| 852 |
+
"filename": file.filename,
|
| 853 |
+
"content": file_content, # Saved as binary in MongoDB
|
| 854 |
+
"content_type": file.content_type,
|
| 855 |
+
"timestamp": datetime.utcnow()
|
| 856 |
+
})
|
| 857 |
|
| 858 |
return {
|
| 859 |
"ok": True,
|
| 860 |
+
"message": "Audio file saved to database successfully",
|
| 861 |
+
"filename": file.filename,
|
| 862 |
+
"size": len(file_content)
|
| 863 |
}
|
| 864 |
except Exception as e:
|
| 865 |
+
logger.error(f"Error saving audio to DB: {e}")
|
| 866 |
raise HTTPException(status_code=500, detail=str(e))
|
| 867 |
|
| 868 |
@app.post("/api/audio/set-angle")
|
| 869 |
async def set_desired_angle(
|
| 870 |
angle: float = Form(...)
|
| 871 |
):
|
| 872 |
+
"""Send a desired angle to the audio processing system and persist to MongoDB."""
|
| 873 |
try:
|
| 874 |
if not (0 <= angle <= 360):
|
| 875 |
raise HTTPException(
|
|
|
|
| 877 |
detail="Angle must be between 0 and 360 degrees"
|
| 878 |
)
|
| 879 |
|
| 880 |
+
if audio_angles_collection is not None:
|
| 881 |
+
await audio_angles_collection.update_one(
|
| 882 |
+
{"key": "latest_angle"},
|
| 883 |
+
{"$set": {"value": angle, "updated_at": datetime.utcnow()}},
|
| 884 |
+
upsert=True
|
| 885 |
+
)
|
| 886 |
|
| 887 |
+
logger.info(f"Set and persisted desired angle {angle}° to DB")
|
| 888 |
|
| 889 |
return {
|
| 890 |
"ok": True,
|
| 891 |
+
"message": f"Desired angle set to {angle}° and saved to DB",
|
| 892 |
"angle": angle
|
| 893 |
}
|
| 894 |
except HTTPException:
|
| 895 |
raise
|
| 896 |
except Exception as e:
|
| 897 |
+
logger.error(f"Error setting angle in DB: {e}")
|
| 898 |
+
raise HTTPException(status_code=500, detail=str(e))
|
| 899 |
+
|
| 900 |
+
@app.get("/api/audio/settings")
|
| 901 |
+
async def get_audio_settings():
|
| 902 |
+
"""Retrieve all audio settings from MongoDB."""
|
| 903 |
+
try:
|
| 904 |
+
if audio_settings_collection is None:
|
| 905 |
+
return {"ok": False, "message": "Database not connected"}
|
| 906 |
+
|
| 907 |
+
cursor = audio_settings_collection.find({}, {"_id": 0})
|
| 908 |
+
settings_list = await cursor.to_list(length=100)
|
| 909 |
+
|
| 910 |
+
# Convert list to dictionary
|
| 911 |
+
settings_dict = {s["key"]: s["value"] for s in settings_list if "key" in s}
|
| 912 |
+
|
| 913 |
+
return {
|
| 914 |
+
"ok": True,
|
| 915 |
+
"settings": settings_dict
|
| 916 |
+
}
|
| 917 |
+
except Exception as e:
|
| 918 |
+
logger.error(f"Error retrieving audio settings: {e}")
|
| 919 |
+
raise HTTPException(status_code=500, detail=str(e))
|
| 920 |
+
|
| 921 |
+
@app.post("/api/audio/settings")
|
| 922 |
+
async def update_audio_settings(
|
| 923 |
+
settings: dict = Body(...)
|
| 924 |
+
):
|
| 925 |
+
"""Update general audio settings in MongoDB."""
|
| 926 |
+
try:
|
| 927 |
+
if audio_settings_collection is None:
|
| 928 |
+
raise HTTPException(status_code=503, detail="Database not connected")
|
| 929 |
+
|
| 930 |
+
for key, value in settings.items():
|
| 931 |
+
await audio_settings_collection.update_one(
|
| 932 |
+
{"key": key},
|
| 933 |
+
{"$set": {"value": value, "updated_at": datetime.utcnow()}},
|
| 934 |
+
upsert=True
|
| 935 |
+
)
|
| 936 |
+
|
| 937 |
+
return {
|
| 938 |
+
"ok": True,
|
| 939 |
+
"message": "Audio settings updated successfully",
|
| 940 |
+
"updated_keys": list(settings.keys())
|
| 941 |
+
}
|
| 942 |
+
except Exception as e:
|
| 943 |
+
logger.error(f"Error updating audio settings: {e}")
|
| 944 |
raise HTTPException(status_code=500, detail=str(e))
|
| 945 |
|
| 946 |
if __name__ == "__main__":
|