"""Core routes: index, logs, prompts, status, conversation.""" from fastapi import APIRouter from fastapi.responses import FileResponse, JSONResponse import globals from server_manager import server_manager from utils.conversation_history import conversation_history from utils.logger import get_logger logger = get_logger('api') router = APIRouter() @router.get("/") def read_index(): return FileResponse("static/index.html") @router.get("/logs") def get_logs(): try: # Read last 100 lines of the log file with open("/app/bot.log", "r", encoding="utf-8") as f: lines = f.readlines() last_100 = lines[-100:] if len(lines) >= 100 else lines return "".join(last_100) except Exception as e: return JSONResponse(status_code=500, content={"status": "error", "message": f"Error reading log file: {e}"}) @router.get("/prompt") def get_last_prompt(): """Legacy endpoint: returns the most recent fallback prompt (backward compat).""" prompt_text = globals._get_last_fallback_prompt() return {"prompt": prompt_text or "No prompt has been issued yet."} @router.get("/prompt/cat") def get_last_cat_prompt(): """Legacy endpoint: returns the most recent Cat interaction (backward compat).""" interaction = globals._get_last_cat_interaction() if not interaction.get("full_prompt"): return {"full_prompt": "No Cheshire Cat interaction has occurred yet.", "response": "", "user": "", "mood": "", "timestamp": ""} return interaction @router.get("/prompts") def get_prompt_history(source: str = None): """ Return the unified prompt history. Optional query param ?source=cat or ?source=fallback to filter. """ history = list(globals.PROMPT_HISTORY) if source and source in ("cat", "fallback"): history = [e for e in history if e.get("source") == source] return {"history": history} @router.get("/prompts/{prompt_id}") def get_prompt_by_id(prompt_id: int): """Return a single prompt history entry by ID.""" for entry in globals.PROMPT_HISTORY: if entry.get("id") == prompt_id: return entry return JSONResponse( status_code=404, content={"status": "error", "message": f"Prompt #{prompt_id} not found"} ) @router.get("/status") def status(): # Get per-server mood summary server_moods = {} for guild_id in server_manager.servers: mood_name, _ = server_manager.get_server_mood(guild_id) server_moods[str(guild_id)] = mood_name # Return evil mood when in evil mode current_mood = globals.EVIL_DM_MOOD if globals.EVIL_MODE else globals.DM_MOOD return { "status": "online", "mood": current_mood, "evil_mode": globals.EVIL_MODE, "servers": len(server_manager.servers), "active_schedulers": len(server_manager.schedulers), "server_moods": server_moods } @router.get("/autonomous/stats") def get_autonomous_stats(): """Get autonomous engine stats for all servers""" from utils.autonomous import autonomous_engine stats = {} for guild_id in server_manager.servers: server_info = server_manager.servers[guild_id] mood_name, _ = server_manager.get_server_mood(guild_id) # Get context signals for this server if guild_id in autonomous_engine.server_contexts: ctx = autonomous_engine.server_contexts[guild_id] # Get mood profile mood_profile = autonomous_engine.mood_profiles.get(mood_name, { "energy": 0.5, "sociability": 0.5, "impulsiveness": 0.5 }) # Sanitize float values for JSON serialization (replace inf with large number) time_since_action = ctx.time_since_last_action if time_since_action == float('inf'): time_since_action = 999999 time_since_interaction = ctx.time_since_last_interaction if time_since_interaction == float('inf'): time_since_interaction = 999999 stats[str(guild_id)] = { "guild_name": server_info.guild_name, "mood": mood_name, "mood_profile": mood_profile, "context": { "messages_last_5min": ctx.messages_last_5min, "messages_last_hour": ctx.messages_last_hour, "unique_users_active": ctx.unique_users_active, "conversation_momentum": round(ctx.conversation_momentum, 2), "users_joined_recently": ctx.users_joined_recently, "users_status_changed": ctx.users_status_changed, "users_started_activity": ctx.users_started_activity, "time_since_last_action": round(time_since_action, 1), "time_since_last_interaction": round(time_since_interaction, 1), "messages_since_last_appearance": ctx.messages_since_last_appearance, "hour_of_day": ctx.hour_of_day, "is_weekend": ctx.is_weekend, "mood_energy_level": round(ctx.mood_energy_level, 2) } } else: # Server not yet initialized in autonomous engine mood_profile = autonomous_engine.mood_profiles.get(mood_name, { "energy": 0.5, "sociability": 0.5, "impulsiveness": 0.5 }) stats[str(guild_id)] = { "guild_name": server_info.guild_name, "mood": mood_name, "mood_profile": mood_profile, "context": None } return {"servers": stats} @router.get("/conversation/{user_id}") def get_conversation(user_id: str): """Get conversation history for a user/channel (uses centralized ConversationHistory).""" messages = conversation_history.get_recent_messages(user_id) return {"conversation": [{"author": author, "content": content, "is_bot": is_bot} for author, content, is_bot in messages]}