FastAPI로 AI 봇 모니터링 대시보드 만들기 — JARVIS Dashboard 구축

7개 봇이 돌아가는데 상태를 한눈에 보고 싶었다. FastAPI + Jinja2 + 폴링으로 실시간 대시보드 만든 과정.

FastAPI로 AI 봇 모니터링 대시보드 만들기 — JARVIS Dashboard 구축

왜 만들었나

봇이 7개 돌아갑니다. 각각 Telegram 메시지를 보내줘서 어느 정도 파악은 되지만:

  • 지금 어떤 봇이 살아있는지 한눈에 못 봄
  • 봇회의 결과를 PC에서 보려면 Telegram 열어야 함
  • 인텔리전스 피드(수집된 뉴스 요약)를 브라우저에서 보고 싶음

FastAPI로 간단한 대시보드를 만들었습니다.


구조

jarvis_dashboard.py (FastAPI, 포트 8902)
├── GET /           → 메인 대시보드 (HTML)
├── GET /api/status → 봇 상태 JSON
├── GET /api/feed   → 인텔리전스 피드
├── GET /api/meeting → 봇회의 결과
└── GET /api/goals  → goal_state.json

HTML은 Python에서 직접 반환하거나 templates/ 폴더에서 Jinja2로 렌더링.


핵심 코드

from fastapi import FastAPI
from fastapi.responses import HTMLResponse
import json
import os
from pathlib import Path

app = FastAPI()

@app.get("/api/status")
def get_bot_status():
    """각 봇 프로세스 생존 여부 확인"""
    import psutil
    
    bots = {
        "nim_bot": False,
        "qwen36_bot": False,
        "helper_bot": False,
        "gemini_bot": False,
    }
    
    for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
        try:
            cmdline = ' '.join(proc.info['cmdline'] or [])
            for bot_name in bots:
                if bot_name in cmdline:
                    bots[bot_name] = True
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            pass
    
    return bots

@app.get("/api/meeting")
def get_latest_meeting():
    """최신 봇회의 기록 반환"""
    debates_dir = Path("D:/knowledge/debates")
    files = sorted(debates_dir.glob("*.md"), reverse=True)
    
    if not files:
        return {"content": "회의 기록 없음"}
    
    latest = files[0]
    return {
        "date": latest.stem,
        "content": latest.read_text(encoding="utf-8")
    }

@app.get("/api/goals")
def get_goals():
    goal_file = Path("D:/bots/goal_state.json")
    if goal_file.exists():
        return json.loads(goal_file.read_text(encoding="utf-8"))
    return {}

프론트엔드

Jinja2 템플릿 대신 FastAPI에서 HTML 문자열 직접 반환하는 방식으로 시작했습니다. 간단해서 빠르게 만들 수 있었습니다.

@app.get("/", response_class=HTMLResponse)
def dashboard():
    return """
<!DOCTYPE html>
<html>
<head>
    <title>JARVIS Dashboard</title>
    <meta charset="utf-8">
    <style>
        body { font-family: sans-serif; background: #0f172a; color: #e2e8f0; }
        .status-ok { color: #4ade80; }
        .status-fail { color: #f87171; }
    </style>
</head>
<body>
    <h1>JARVIS</h1>
    <div id="status">로딩 중...</div>
    
    <script>
        async function refresh() {
            const res = await fetch('/api/status');
            const data = await res.json();
            let html = '<table>';
            for (const [bot, alive] of Object.entries(data)) {
                const cls = alive ? 'status-ok' : 'status-fail';
                const icon = alive ? '✅' : '❌';
                html += `<tr><td>${bot}</td><td class="${cls}">${icon}</td></tr>`;
            }
            html += '</table>';
            document.getElementById('status').innerHTML = html;
        }
        
        refresh();
        setInterval(refresh, 10000);  // 10초마다 폴링
    </script>
</body>
</html>
"""

10초마다 /api/status를 폴링해서 봇 상태를 갱신합니다.


탭 구조 (나중에 추가)

처음엔 상태만 봤습니다. 나중에 탭으로 나눴습니다:

  • tab1: 봇 상태 (프로세스 생존 여부)
  • tab2: 인텔리전스 피드 (수집된 뉴스)
  • tab3: goal_state.json (수익/포스트 현황)
  • tab4: Dream Reports (야간 합성 결과)
  • tab5: 봇회의 기록 (bot_meeting 결과)

Task Scheduler로 자동 시작

$trigger = New-ScheduledTaskTrigger -AtStartup
$action = New-ScheduledTaskAction `
  -Execute "python" `
  -Argument "D:\bots\jarvis_dashboard.py" `
  -WorkingDirectory "D:\bots"
Register-ScheduledTask `
  -TaskName "JARVIS\Dashboard" `
  -Trigger $trigger `
  -Action $action `
  -RunLevel Highest

겪었던 문제

psutil로 프로세스 이름 매칭 문제

Windows에서 Python 프로세스는 전부 python.exe로 나옵니다. 스크립트 이름은 cmdline에서 찾아야 합니다.

cmdline = ' '.join(proc.info['cmdline'] or [])
if 'nim_bot.py' in cmdline:
    ...

Cloudflare Tunnel 연동

외부에서 접속하려면 Cloudflare Tunnel을 씁니다. Tunnel이 먼저 시작되고 Dashboard가 나중에 올라오면 502 오류가 납니다.

Task Scheduler에서 Dashboard 시작 지연(30초)을 줬습니다.


현재

localhost:8902에서 접속, Cloudflare Tunnel로 외부 접속도 됩니다.

봇 상태를 한눈에 확인하고, 봇회의 결과를 브라우저에서 읽습니다.

#FastAPI#Python#대시보드#모니터링#JARVIS