feat: add proper HTTP status codes to all API error responses

- 217 error returns across 18 route files + api.py now use JSONResponse
  with appropriate HTTP status codes instead of returning HTTP 200
- Status code distribution: 500 (121), 400 (39), 503 (28), 404 (24), 409 (3), 502 (2)
- Fixed language.py tuple-return bug (was serializing as JSON array)
- Fixed bare except clauses in bipolar_mode.py and voice.py
- Body-level error schemas preserved (status/error + success/error patterns)
  so web UI continues working without changes
- chat.py (SSE) unchanged: errors sent within stream protocol
- All 170 tests pass
This commit is contained in:
2026-04-15 15:43:18 +03:00
parent 33b2033cc3
commit edc9f27925
19 changed files with 243 additions and 227 deletions

View File

@@ -1,6 +1,7 @@
"""Autonomous action routes: V1, V2, per-server autonomous."""
from fastapi import APIRouter
from fastapi.responses import JSONResponse
import globals
from server_manager import server_manager
from routes.models import CustomPromptRequest
@@ -25,7 +26,7 @@ async def trigger_autonomous_general(guild_id: int = None):
globals.client.loop.create_task(miku_say_something_general())
return {"status": "ok", "message": "Autonomous general message queued for all servers"}
else:
return {"status": "error", "message": "Bot not ready"}
return JSONResponse(status_code=503, content={"status": "error", "message": "Bot not ready"})
@router.post("/autonomous/engage")
@@ -65,7 +66,7 @@ async def trigger_autonomous_engage_user(
return {"status": "ok", "message": " ".join(msg_parts)}
else:
return {"status": "error", "message": "Bot not ready"}
return JSONResponse(status_code=503, content={"status": "error", "message": "Bot not ready"})
@router.post("/autonomous/tweet")
@@ -86,7 +87,7 @@ async def trigger_autonomous_tweet(guild_id: int = None, tweet_url: str = None):
msg += f" with URL {tweet_url}"
return {"status": "ok", "message": msg}
else:
return {"status": "error", "message": "Bot not ready"}
return JSONResponse(status_code=503, content={"status": "error", "message": "Bot not ready"})
@router.post("/autonomous/custom")
@@ -101,7 +102,7 @@ async def custom_autonomous_message(req: CustomPromptRequest, guild_id: int = No
globals.client.loop.create_task(handle_custom_prompt(req.prompt))
return {"status": "ok", "message": "Custom autonomous message queued for all servers"}
else:
return {"status": "error", "message": "Bot not ready"}
return JSONResponse(status_code=503, content={"status": "error", "message": "Bot not ready"})
@router.post("/autonomous/reaction")
@@ -116,7 +117,7 @@ async def trigger_autonomous_reaction(guild_id: int = None):
globals.client.loop.create_task(miku_autonomous_reaction(force=True))
return {"status": "ok", "message": "Autonomous reaction queued for all servers"}
else:
return {"status": "error", "message": "Bot not ready"}
return JSONResponse(status_code=503, content={"status": "error", "message": "Bot not ready"})
@router.post("/autonomous/join-conversation")
@@ -135,7 +136,7 @@ async def trigger_detect_and_join_conversation(guild_id: int = None):
return {"status": "ok", "message": "Detect and join conversation queued for all servers"}
else:
logger.error(f"Bot not ready: client={globals.client}, loop={globals.client.loop if globals.client else None}")
return {"status": "error", "message": "Bot not ready"}
return JSONResponse(status_code=503, content={"status": "error", "message": "Bot not ready"})
# ========== Per-Server Autonomous ==========
@@ -148,7 +149,7 @@ async def trigger_autonomous_general_for_server(guild_id: int):
await miku_say_something_general_for_server(guild_id)
return {"status": "ok", "message": f"Autonomous general message triggered for server {guild_id}"}
except Exception as e:
return {"status": "error", "message": f"Failed to trigger autonomous message: {e}"}
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to trigger autonomous message: {e}"})
@router.post("/servers/{guild_id}/autonomous/engage")
@@ -175,7 +176,7 @@ async def trigger_autonomous_engage_for_server(
return {"status": "ok", "message": " ".join(msg_parts)}
except Exception as e:
return {"status": "error", "message": f"Failed to trigger user engagement: {e}"}
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to trigger user engagement: {e}"})
@router.post("/servers/{guild_id}/autonomous/custom")
@@ -187,9 +188,9 @@ async def custom_autonomous_message_for_server(guild_id: int, req: CustomPromptR
if success:
return {"status": "ok", "message": f"Custom autonomous message sent to server {guild_id}"}
else:
return {"status": "error", "message": f"Failed to send custom message to server {guild_id}"}
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to send custom message to server {guild_id}"})
except Exception as e:
return {"status": "error", "message": f"Error: {e}"}
return JSONResponse(status_code=500, content={"status": "error", "message": f"Error: {e}"})
@router.post("/servers/{guild_id}/autonomous/tweet")
@@ -200,7 +201,7 @@ async def trigger_autonomous_tweet_for_server(guild_id: int):
await share_miku_tweet_for_server(guild_id)
return {"status": "ok", "message": f"Autonomous tweet sharing triggered for server {guild_id}"}
except Exception as e:
return {"status": "error", "message": f"Failed to trigger tweet sharing: {e}"}
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to trigger tweet sharing: {e}"})
# ========== Autonomous V2 ==========
@@ -213,7 +214,7 @@ async def get_v2_stats(guild_id: int):
stats = get_v2_stats_for_server(guild_id)
return {"status": "ok", "guild_id": guild_id, "stats": stats}
except Exception as e:
return {"status": "error", "message": str(e)}
return JSONResponse(status_code=500, content={"status": "error", "message": str(e)})
@router.get("/autonomous/v2/check/{guild_id}")
@@ -223,16 +224,16 @@ async def manual_v2_check(guild_id: int):
from utils.autonomous_v2_integration import manual_trigger_v2_check
if not globals.client:
return {"status": "error", "message": "Bot not ready"}
return JSONResponse(status_code=503, content={"status": "error", "message": "Bot not ready"})
result = await manual_trigger_v2_check(guild_id, globals.client)
if isinstance(result, str):
return {"status": "error", "message": result}
return JSONResponse(status_code=500, content={"status": "error", "message": result})
return {"status": "ok", "guild_id": guild_id, "analysis": result}
except Exception as e:
return {"status": "error", "message": str(e)}
return JSONResponse(status_code=500, content={"status": "error", "message": str(e)})
@router.get("/autonomous/v2/status")
@@ -258,4 +259,4 @@ async def get_v2_status():
return {"status": "ok", "servers": status}
except Exception as e:
return {"status": "error", "message": str(e)}
return JSONResponse(status_code=500, content={"status": "error", "message": str(e)})