Some checks failed
Release / release (push) Has been cancelled
Full-stack dashboard for controlling, automating, and analyzing Artifacts MMO characters via the game's HTTP API. Backend (FastAPI): - Async Artifacts API client with rate limiting and retry - 6 automation strategies (combat, gathering, crafting, trading, task, leveling) - Automation engine with runner, manager, cooldown tracker, pathfinder - WebSocket relay (game server -> frontend) - Game data cache, character snapshots, price history, analytics - 9 API routers, 7 database tables, 3 Alembic migrations - 108 unit tests Frontend (Next.js 15 + shadcn/ui): - Live character dashboard with HP/XP bars and cooldowns - Character detail with stats, equipment, inventory, skills, manual actions - Automation management with live log streaming - Interactive canvas map with content-type coloring and zoom/pan - Bank management, Grand Exchange with price charts - Events, logs, analytics pages with Recharts - WebSocket auto-reconnect with query cache invalidation - Settings page, error boundaries, dark theme Infrastructure: - Docker Compose (dev + prod) - GitHub Actions CI/CD - Documentation (Architecture, Automation, Deployment, API)
101 lines
3.4 KiB
Python
101 lines
3.4 KiB
Python
"""Character logs and analytics API router."""
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from fastapi import APIRouter, HTTPException, Query, Request
|
|
from httpx import HTTPStatusError
|
|
|
|
from app.database import async_session_factory
|
|
from app.services.analytics_service import AnalyticsService
|
|
from app.services.artifacts_client import ArtifactsClient
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter(prefix="/api/logs", tags=["logs"])
|
|
|
|
|
|
def _get_client(request: Request) -> ArtifactsClient:
|
|
return request.app.state.artifacts_client
|
|
|
|
|
|
@router.get("/")
|
|
async def get_character_logs(
|
|
request: Request,
|
|
character: str = Query(default="", description="Character name to filter logs"),
|
|
limit: int = Query(default=50, ge=1, le=200, description="Max entries to return"),
|
|
) -> dict[str, Any]:
|
|
"""Get character action logs from the Artifacts API.
|
|
|
|
This endpoint retrieves the character's recent action logs directly
|
|
from the game server.
|
|
"""
|
|
client = _get_client(request)
|
|
|
|
try:
|
|
if character:
|
|
# Get logs for a specific character
|
|
char_data = await client.get_character(character)
|
|
return {
|
|
"character": character,
|
|
"logs": [], # The API doesn't have a dedicated logs endpoint per character;
|
|
# action data comes from the automation logs in our DB
|
|
"character_data": {
|
|
"name": char_data.name,
|
|
"level": char_data.level,
|
|
"xp": char_data.xp,
|
|
"gold": char_data.gold,
|
|
"x": char_data.x,
|
|
"y": char_data.y,
|
|
"task": char_data.task,
|
|
"task_progress": char_data.task_progress,
|
|
"task_total": char_data.task_total,
|
|
},
|
|
}
|
|
else:
|
|
# Get all characters as a summary
|
|
characters = await client.get_characters()
|
|
return {
|
|
"characters": [
|
|
{
|
|
"name": c.name,
|
|
"level": c.level,
|
|
"xp": c.xp,
|
|
"gold": c.gold,
|
|
"x": c.x,
|
|
"y": c.y,
|
|
}
|
|
for c in characters
|
|
],
|
|
}
|
|
except HTTPStatusError as exc:
|
|
raise HTTPException(
|
|
status_code=exc.response.status_code,
|
|
detail=f"Artifacts API error: {exc.response.text}",
|
|
) from exc
|
|
|
|
|
|
@router.get("/analytics")
|
|
async def get_analytics(
|
|
request: Request,
|
|
character: str = Query(..., description="Character name"),
|
|
hours: int = Query(default=24, ge=1, le=168, description="Hours of history"),
|
|
) -> dict[str, Any]:
|
|
"""Get analytics aggregations for a character.
|
|
|
|
Returns XP history, gold history, and estimated actions per hour.
|
|
"""
|
|
analytics = AnalyticsService()
|
|
|
|
async with async_session_factory() as db:
|
|
xp_history = await analytics.get_xp_history(db, character, hours)
|
|
gold_history = await analytics.get_gold_history(db, character, hours)
|
|
actions_rate = await analytics.get_actions_per_hour(db, character)
|
|
|
|
return {
|
|
"character": character,
|
|
"hours": hours,
|
|
"xp_history": xp_history,
|
|
"gold_history": gold_history,
|
|
"actions_rate": actions_rate,
|
|
}
|