Agentive
自動化ラボ

AIでレポート自動生成 — データ収集から可視化まで完全自動化

約6分で読めます

AIでレポート自動生成

日次レポートを毎朝手動で作っていないか。データ収集、分析、可視化、配信までの全工程をAIで自動化すれば、毎朝の30分が完全に不要になる。

レポート自動生成パイプライン

データ収集(スクレイピング/API/DB)

データ集計(pandas/SQL)

AI分析(Claude APIで要約・洞察)

HTML/PDF生成(テンプレートエンジン)

配信(メール/Slack/Discord)

Agentiveでは日次レポートをHTMLで自動生成し、visual_inspectorで表示品質も自動検証している。

データ収集: 複数ソースの統合

データベースからの集計

from sqlalchemy import create_engine, text
from datetime import datetime, timedelta

def collect_daily_stats(db_url: str) -> dict:
    """日次統計データの収集"""
    engine = create_engine(db_url)
    yesterday = (datetime.now() - timedelta(days=1)).date()

    with engine.connect() as conn:
        pv = conn.execute(text(
            "SELECT COUNT(*) FROM page_views WHERE date = :d"
        ), {"d": yesterday}).scalar()

        new_users = conn.execute(text(
            "SELECT COUNT(*) FROM users WHERE created_at::date = :d"
        ), {"d": yesterday}).scalar()

        revenue = conn.execute(text(
            "SELECT COALESCE(SUM(amount), 0) FROM orders WHERE date = :d"
        ), {"d": yesterday}).scalar()

    return {
        "date": yesterday.isoformat(),
        "pv": pv,
        "new_users": new_users,
        "revenue": float(revenue)
    }

Web APIからのデータ取得

import requests

def collect_analytics(api_key: str, site_id: str) -> dict:
    """アクセス解析APIからデータ取得"""
    response = requests.get(
        f"https://analytics.example.com/api/v1/sites/{site_id}/stats",
        headers={"Authorization": f"Bearer {api_key}"},
        params={"period": "day"}
    )
    response.raise_for_status()
    return response.json()

AI分析: データから洞察を抽出

Claude APIで日次分析

import anthropic
import json

client = anthropic.Anthropic()

def ai_analyze(stats: dict) -> str:
    """AIでデータを分析し、要約と洞察を生成"""
    response = client.messages.create(
        model="claude-haiku-35-20241022",
        max_tokens=1024,
        messages=[{
            "role": "user",
            "content": f"""以下の日次データを分析し、3つの重要な洞察を日本語で簡潔にまとめてください。

データ:
{json.dumps(stats, indent=2, ensure_ascii=False)}

出力形式:
1. [洞察1]
2. [洞察2]
3. [洞察3]
改善提案: [具体的なアクション]"""
        }]
    )
    return response.content[0].text

前日比・前週比の自動計算

def calculate_trends(current: dict, previous: dict) -> dict:
    """前日比のトレンド計算"""
    trends = {}
    for key in ["pv", "new_users", "revenue"]:
        prev_val = previous.get(key, 0)
        curr_val = current.get(key, 0)
        if prev_val > 0:
            change = ((curr_val - prev_val) / prev_val) * 100
            trends[key] = {
                "current": curr_val,
                "previous": prev_val,
                "change_pct": round(change, 1),
                "direction": "up" if change > 0 else "down"
            }
    return trends

HTMLレポート生成

Jinja2テンプレートでレポート作成

from jinja2 import Template
from pathlib import Path

REPORT_TEMPLATE = """
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>日次レポート - {{ date }}</title>
    <style>
        body { font-family: sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
        .metric { display: inline-block; padding: 16px; margin: 8px; background: #f5f5f5;
                  border-radius: 8px; min-width: 150px; text-align: center; }
        .metric h3 { margin: 0; font-size: 14px; color: #666; }
        .metric .value { font-size: 32px; font-weight: bold; margin: 8px 0; }
        .up { color: #22c55e; }
        .down { color: #ef4444; }
        .insights { background: #f0f9ff; padding: 16px; border-radius: 8px; }
    </style>
</head>
<body>
    <h1>日次レポート: {{ date }}</h1>
    <div class="metrics">
        {% for name, data in trends.items() %}
        <div class="metric">
            <h3>{{ name }}</h3>
            <div class="value">{{ data.current }}</div>
            <span class="{{ data.direction }}">
                {{ "↑" if data.direction == "up" else "↓" }} {{ data.change_pct }}%
            </span>
        </div>
        {% endfor %}
    </div>
    <div class="insights">
        <h2>AI分析</h2>
        <p>{{ ai_insights }}</p>
    </div>
</body>
</html>
"""

def generate_html_report(stats: dict, trends: dict, insights: str) -> str:
    """HTMLレポートの生成"""
    template = Template(REPORT_TEMPLATE)
    html = template.render(
        date=stats["date"], stats=stats,
        trends=trends, ai_insights=insights
    )
    output_path = Path(f"reports/daily_{stats['date']}.html")
    output_path.parent.mkdir(exist_ok=True)
    output_path.write_text(html, encoding="utf-8")
    return str(output_path)

レポート配信

メール配信(SMTP)

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

def send_report_email(html_content: str, recipients: list[str], date: str):
    """HTMLレポートをメール配信"""
    msg = MIMEMultipart("alternative")
    msg["Subject"] = f"日次レポート - {date}"
    msg["From"] = "report@example.com"
    msg["To"] = ", ".join(recipients)
    msg.attach(MIMEText(html_content, "html"))

    with smtplib.SMTP("smtp.gmail.com", 587) as server:
        server.starttls()
        server.login("report@example.com", "APP_PASSWORD")
        server.sendmail(msg["From"], recipients, msg.as_string())
    print(f"メール送信完了: {len(recipients)}件")

Slack/Discord配信

def send_to_slack(webhook_url: str, summary: str, report_url: str):
    """Slackにレポートサマリーを配信"""
    import urllib.request, json

    payload = json.dumps({
        "blocks": [
            {"type": "header", "text": {"type": "plain_text", "text": "日次レポート"}},
            {"type": "section", "text": {"type": "mrkdwn", "text": summary}},
            {"type": "actions", "elements": [{
                "type": "button",
                "text": {"type": "plain_text", "text": "詳細を見る"},
                "url": report_url
            }]}
        ]
    }).encode()

    req = urllib.request.Request(
        webhook_url, data=payload,
        headers={"Content-Type": "application/json"}
    )
    urllib.request.urlopen(req)

パイプライン統合: 完全自動実行

全工程を1つのスクリプトにまとめて定期実行する。

def run_daily_report():
    """日次レポートパイプライン"""
    db_url = "postgresql://user:pass@localhost:5432/mydb"

    # 1. データ収集
    stats = collect_daily_stats(db_url)
    prev_stats = collect_daily_stats(db_url)

    # 2. トレンド計算
    trends = calculate_trends(stats, prev_stats)

    # 3. AI分析
    insights = ai_analyze(stats)

    # 4. HTML生成
    report_path = generate_html_report(stats, trends, insights)

    # 5. 配信
    send_to_slack(SLACK_WEBHOOK, insights, f"https://reports.example.com/{report_path}")

    print(f"日次レポート完了: {stats['date']}")

if __name__ == "__main__":
    run_daily_report()

cronやタスクスケジューラで毎朝7時に実行すれば、出社時にはレポートが届いている。

レポートの品質保証

生成したHTMLレポートの表示品質もAIで検証する。

from visual_inspector import inspect_screenshot
result = inspect_screenshot("reports/daily_2026-04-07.html", "report_check")
# pass=True, confidence=0.95

関連記事

A

Agentive 編集部

AIエージェントを実際に使い倒す個人開発者。サイト制作の自動化を実践しながら、その知見を発信しています。