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