From d6742b0c85ed13b4d6097bcbbb6d663460af9287 Mon Sep 17 00:00:00 2001 From: koko210Serve Date: Fri, 24 Apr 2026 13:32:55 +0300 Subject: [PATCH] feat: add activities API routes and register in api.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New endpoints: - GET /activities — full data (normal + evil) - GET /activities/{section}/{mood} — per-mood activities - POST /activities/{section}/{mood} — update activities with validation - POST /activities/reload — force reload from disk --- bot/api.py | 2 ++ bot/routes/activities.py | 73 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 bot/routes/activities.py diff --git a/bot/api.py b/bot/api.py index 742b9f8..5ffdc1b 100644 --- a/bot/api.py +++ b/bot/api.py @@ -101,6 +101,7 @@ from routes.config import router as config_router from routes.logging_config import router as logging_config_router from routes.voice import router as voice_router from routes.memory import router as memory_router +from routes.activities import router as activities_router app.include_router(core_router) app.include_router(mood_router) @@ -121,6 +122,7 @@ app.include_router(config_router) app.include_router(logging_config_router) app.include_router(voice_router) app.include_router(memory_router) +app.include_router(activities_router) diff --git a/bot/routes/activities.py b/bot/routes/activities.py new file mode 100644 index 0000000..108d139 --- /dev/null +++ b/bot/routes/activities.py @@ -0,0 +1,73 @@ +"""Activities API routes — CRUD for mood-based song/game activity lists.""" + +from fastapi import APIRouter, Request +from fastapi.responses import JSONResponse +from utils.logger import get_logger + +logger = get_logger('api') + +router = APIRouter() + + +@router.get("/activities") +def get_all_activities(): + """Return the full activities data (normal + evil sections, all moods).""" + from utils.activities import get_all_activities + return get_all_activities() + + +@router.get("/activities/{section}/{mood}") +def get_mood_activities(section: str, mood: str): + """Return activities for a specific mood. + + Args: + section: "normal" or "evil" + mood: mood name (e.g. "bubbly", "aggressive") + """ + if section not in ("normal", "evil"): + return JSONResponse(status_code=400, content={"error": "Section must be 'normal' or 'evil'"}) + + from utils.activities import get_activities_for_mood + activities = get_activities_for_mood(mood, is_evil=(section == "evil")) + return {"section": section, "mood": mood, "activities": activities} + + +@router.post("/activities/{section}/{mood}") +async def set_mood_activities(section: str, mood: str, request: Request): + """Update activities for a specific mood. + + Body: {"activities": [{"type": "listening"|"playing", "name": "...", "weight": 1}]} + """ + if section not in ("normal", "evil"): + return JSONResponse(status_code=400, content={"error": "Section must be 'normal' or 'evil'"}) + + data = await request.json() + activities = data.get("activities") + + if activities is None: + return JSONResponse(status_code=400, content={"error": "Request body must include 'activities' list"}) + + if not isinstance(activities, list): + return JSONResponse(status_code=400, content={"error": "'activities' must be a list"}) + + try: + from utils.activities import set_activities_for_mood + set_activities_for_mood(mood, is_evil=(section == "evil"), activities=activities) + logger.info(f"Updated activities for {section}/{mood}: {len(activities)} entries") + return {"status": "ok", "section": section, "mood": mood, "count": len(activities)} + except ValueError as e: + return JSONResponse(status_code=400, content={"error": str(e)}) + except Exception as e: + logger.error(f"Failed to save activities for {section}/{mood}: {e}") + return JSONResponse(status_code=500, content={"error": "Internal server error"}) + + +@router.post("/activities/reload") +def reload_activities(): + """Force reload activities from disk (useful after hand-editing the YAML).""" + from utils.activities import _load_activities + data = _load_activities(force=True) + normal_count = sum(len(v) for v in data.get("normal", {}).values()) + evil_count = sum(len(v) for v in data.get("evil", {}).values()) + logger.info(f"Force-reloaded activities: {normal_count} normal entries, {evil_count} evil entries") + return {"status": "ok", "normal_entries": normal_count, "evil_entries": evil_count}