Community edition generated from private repo via sync pipeline. Includes 9 plugins (WordPress, WooCommerce, WP Advanced, Gitea, n8n, Supabase, OpenPanel, Appwrite, Directus) with ~587 tools. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
528 lines
21 KiB
Python
528 lines
21 KiB
Python
"""Reports Handler - OpenPanel analytics reports (8 tools)
|
|
|
|
Note: project_id is optional if configured in environment variables.
|
|
"""
|
|
|
|
import json
|
|
from typing import Any
|
|
|
|
from plugins.openpanel.client import OpenPanelClient
|
|
from plugins.openpanel.handlers.utils import get_project_id as _get_project_id
|
|
|
|
def get_tool_specifications() -> list[dict[str, Any]]:
|
|
"""Return tool specifications for ToolGenerator (8 tools)"""
|
|
return [
|
|
{
|
|
"name": "get_overview_report",
|
|
"method_name": "get_overview_report",
|
|
"description": "Get overview statistics including total events, users, sessions, and page views. Note: project_id is optional if configured in environment.",
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"project_id": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Project ID (optional if configured in env)",
|
|
},
|
|
"date_range": {
|
|
"type": "string",
|
|
"description": "Date range. Common: today, yesterday, 7d, 14d, 30d, 60d, 90d, 6m, 12m, monthToDate, yearToDate, all",
|
|
"default": "30d",
|
|
},
|
|
},
|
|
"required": [],
|
|
},
|
|
"scope": "read",
|
|
},
|
|
{
|
|
"name": "get_retention_report",
|
|
"method_name": "get_retention_report",
|
|
"description": "Get user retention analysis showing how many users return over time. Note: project_id is optional if configured in environment.",
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"project_id": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Project ID (optional if configured in env)",
|
|
},
|
|
"start_event": {
|
|
"type": "string",
|
|
"description": "Event that marks user acquisition (e.g., 'signup_completed')",
|
|
"default": "session_start",
|
|
},
|
|
"return_event": {
|
|
"type": "string",
|
|
"description": "Event that marks user return (e.g., 'app_opened')",
|
|
"default": "session_start",
|
|
},
|
|
"period": {
|
|
"type": "string",
|
|
"enum": ["day", "week", "month"],
|
|
"description": "Retention period granularity",
|
|
"default": "week",
|
|
},
|
|
"cohorts": {
|
|
"type": "integer",
|
|
"description": "Number of cohorts to analyze",
|
|
"default": 8,
|
|
"maximum": 12,
|
|
},
|
|
},
|
|
"required": [],
|
|
},
|
|
"scope": "read",
|
|
},
|
|
{
|
|
"name": "get_cohort_report",
|
|
"method_name": "get_cohort_report",
|
|
"description": "Get cohort analysis grouping users by acquisition date and tracking their behavior. Note: project_id is optional if configured in environment.",
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"project_id": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Project ID (optional if configured in env)",
|
|
},
|
|
"cohort_type": {
|
|
"type": "string",
|
|
"enum": ["first_seen", "signup", "custom"],
|
|
"description": "How to define cohorts",
|
|
"default": "first_seen",
|
|
},
|
|
"cohort_event": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Custom event for cohort definition (when cohort_type is 'custom')",
|
|
},
|
|
"measure_event": {
|
|
"type": "string",
|
|
"description": "Event to measure for each cohort",
|
|
"default": "session_start",
|
|
},
|
|
"date_range": {
|
|
"type": "string",
|
|
"description": "Date range. Common: 7d, 14d, 30d, 60d, 90d, 6m, 12m, yearToDate, all",
|
|
"default": "6m",
|
|
},
|
|
},
|
|
"required": [],
|
|
},
|
|
"scope": "read",
|
|
},
|
|
{
|
|
"name": "get_paths_report",
|
|
"method_name": "get_paths_report",
|
|
"description": "Get user flow/paths analysis showing common navigation patterns. Note: project_id is optional if configured in environment.",
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"project_id": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Project ID (optional if configured in env)",
|
|
},
|
|
"start_event": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Starting event for path analysis",
|
|
},
|
|
"end_event": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Ending event for path analysis",
|
|
},
|
|
"max_steps": {
|
|
"type": "integer",
|
|
"description": "Maximum path steps to analyze",
|
|
"default": 5,
|
|
"maximum": 10,
|
|
},
|
|
"date_range": {
|
|
"type": "string",
|
|
"description": "Date range. Common: today, yesterday, 7d, 14d, 30d, 60d, 90d, 6m, 12m, all",
|
|
"default": "30d",
|
|
},
|
|
},
|
|
"required": [],
|
|
},
|
|
"scope": "read",
|
|
},
|
|
{
|
|
"name": "get_realtime_stats",
|
|
"method_name": "get_realtime_stats",
|
|
"description": "Get real-time visitor statistics for the last 30 minutes. Note: project_id is optional if configured in environment.",
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"project_id": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Project ID (optional if configured in env)",
|
|
}
|
|
},
|
|
"required": [],
|
|
},
|
|
"scope": "read",
|
|
},
|
|
{
|
|
"name": "get_ab_test_results",
|
|
"method_name": "get_ab_test_results",
|
|
"description": "Get A/B test results comparing variants by conversion rate. Note: project_id is optional if configured in environment.",
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"project_id": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Project ID (optional if configured in env)",
|
|
},
|
|
"test_name": {"type": "string", "description": "Name of the A/B test"},
|
|
"conversion_event": {
|
|
"type": "string",
|
|
"description": "Event that marks conversion",
|
|
},
|
|
"date_range": {
|
|
"type": "string",
|
|
"description": "Date range. Common: today, yesterday, 7d, 14d, 30d, 60d, 90d, 6m, 12m, all",
|
|
"default": "30d",
|
|
},
|
|
},
|
|
"required": ["test_name", "conversion_event"],
|
|
},
|
|
"scope": "read",
|
|
},
|
|
{
|
|
"name": "create_scheduled_report",
|
|
"method_name": "create_scheduled_report",
|
|
"description": "Create a scheduled report to be sent via email. Note: project_id is optional if configured in environment.",
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"project_id": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Project ID (optional if configured in env)",
|
|
},
|
|
"name": {"type": "string", "description": "Report name"},
|
|
"report_type": {
|
|
"type": "string",
|
|
"enum": ["overview", "events", "funnels", "retention"],
|
|
"description": "Type of report",
|
|
},
|
|
"schedule": {
|
|
"type": "string",
|
|
"enum": ["daily", "weekly", "monthly"],
|
|
"description": "Report schedule",
|
|
},
|
|
"recipients": {
|
|
"type": "array",
|
|
"items": {"type": "string", "format": "email"},
|
|
"description": "Email recipients",
|
|
},
|
|
},
|
|
"required": ["name", "report_type", "schedule", "recipients"],
|
|
},
|
|
"scope": "write",
|
|
},
|
|
{
|
|
"name": "export_report_pdf",
|
|
"method_name": "export_report_pdf",
|
|
"description": "Export a report as PDF format. Note: project_id is optional if configured in environment.",
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"project_id": {
|
|
"anyOf": [{"type": "string"}, {"type": "null"}],
|
|
"description": "Project ID (optional if configured in env)",
|
|
},
|
|
"report_type": {
|
|
"type": "string",
|
|
"enum": ["overview", "events", "funnels", "retention", "paths"],
|
|
"description": "Type of report to export",
|
|
},
|
|
"date_range": {
|
|
"type": "string",
|
|
"description": "Date range. Common: today, yesterday, 7d, 14d, 30d, 60d, 90d, 6m, 12m, all",
|
|
"default": "30d",
|
|
},
|
|
},
|
|
"required": ["report_type"],
|
|
},
|
|
"scope": "read",
|
|
},
|
|
]
|
|
|
|
# =====================
|
|
# Report Functions (8)
|
|
# =====================
|
|
|
|
async def get_overview_report(
|
|
client: OpenPanelClient, project_id: str | None = None, date_range: str = "30d"
|
|
) -> str:
|
|
"""Get overview statistics using tRPC overview.stats endpoint"""
|
|
try:
|
|
effective_project_id = _get_project_id(client, project_id)
|
|
|
|
# Use the new tRPC overview.stats endpoint
|
|
result = await client.get_overview_stats(
|
|
project_id=effective_project_id, date_range=date_range
|
|
)
|
|
|
|
# Check for errors
|
|
if "error" in result:
|
|
return json.dumps(
|
|
{
|
|
"success": False,
|
|
"project_id": effective_project_id,
|
|
"date_range": date_range,
|
|
"error": result.get("error"),
|
|
"note": "tRPC overview.stats endpoint may require authentication or the project may not exist",
|
|
},
|
|
indent=2,
|
|
ensure_ascii=False,
|
|
)
|
|
|
|
# Transform tRPC response to our format
|
|
# tRPC overview.stats returns: {current: {...}, previous: {...}}
|
|
current = result.get("current", result)
|
|
|
|
metrics = {
|
|
"unique_visitors": current.get("uniqueVisitors", 0),
|
|
"page_views": current.get("screenViews", 0),
|
|
"sessions": current.get("sessions", 0),
|
|
"bounce_rate": current.get("bounceRate", 0),
|
|
"session_duration": current.get("sessionDuration", 0),
|
|
"revenue": current.get("revenue", 0),
|
|
}
|
|
|
|
# Add previous period comparison if available
|
|
previous = result.get("previous", {})
|
|
if previous:
|
|
metrics["previous_period"] = {
|
|
"unique_visitors": previous.get("uniqueVisitors", 0),
|
|
"page_views": previous.get("screenViews", 0),
|
|
"sessions": previous.get("sessions", 0),
|
|
}
|
|
|
|
return json.dumps(
|
|
{
|
|
"success": True,
|
|
"project_id": effective_project_id,
|
|
"date_range": date_range,
|
|
"overview": metrics,
|
|
"raw": result,
|
|
},
|
|
indent=2,
|
|
ensure_ascii=False,
|
|
)
|
|
except Exception as e:
|
|
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)
|
|
|
|
async def get_retention_report(
|
|
client: OpenPanelClient,
|
|
project_id: str | None = None,
|
|
start_event: str = "session_start",
|
|
return_event: str = "session_start",
|
|
period: str = "week",
|
|
cohorts: int = 8,
|
|
) -> str:
|
|
"""Get user retention analysis"""
|
|
try:
|
|
effective_project_id = _get_project_id(client, project_id)
|
|
# Note: Full retention analysis requires tRPC API access
|
|
# This provides a simplified version using export API
|
|
|
|
return json.dumps(
|
|
{
|
|
"success": True,
|
|
"project_id": effective_project_id,
|
|
"retention_config": {
|
|
"start_event": start_event,
|
|
"return_event": return_event,
|
|
"period": period,
|
|
"cohorts": cohorts,
|
|
},
|
|
"note": "Full retention analysis requires dashboard tRPC API. Use OpenPanel dashboard for detailed retention charts.",
|
|
"message": "Retention report configuration created",
|
|
},
|
|
indent=2,
|
|
ensure_ascii=False,
|
|
)
|
|
except Exception as e:
|
|
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)
|
|
|
|
async def get_cohort_report(
|
|
client: OpenPanelClient,
|
|
project_id: str | None = None,
|
|
cohort_type: str = "first_seen",
|
|
cohort_event: str | None = None,
|
|
measure_event: str = "session_start",
|
|
date_range: str = "6m",
|
|
) -> str:
|
|
"""Get cohort analysis"""
|
|
try:
|
|
effective_project_id = _get_project_id(client, project_id)
|
|
return json.dumps(
|
|
{
|
|
"success": True,
|
|
"project_id": effective_project_id,
|
|
"cohort_config": {
|
|
"cohort_type": cohort_type,
|
|
"cohort_event": cohort_event,
|
|
"measure_event": measure_event,
|
|
"date_range": date_range,
|
|
},
|
|
"note": "Full cohort analysis requires dashboard tRPC API. Use OpenPanel dashboard for detailed cohort charts.",
|
|
"message": "Cohort report configuration created",
|
|
},
|
|
indent=2,
|
|
ensure_ascii=False,
|
|
)
|
|
except Exception as e:
|
|
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)
|
|
|
|
async def get_paths_report(
|
|
client: OpenPanelClient,
|
|
project_id: str | None = None,
|
|
start_event: str | None = None,
|
|
end_event: str | None = None,
|
|
max_steps: int = 5,
|
|
date_range: str = "30d",
|
|
) -> str:
|
|
"""Get user flow/paths analysis"""
|
|
try:
|
|
effective_project_id = _get_project_id(client, project_id)
|
|
return json.dumps(
|
|
{
|
|
"success": True,
|
|
"project_id": effective_project_id,
|
|
"paths_config": {
|
|
"start_event": start_event,
|
|
"end_event": end_event,
|
|
"max_steps": max_steps,
|
|
"date_range": date_range,
|
|
},
|
|
"note": "Full path analysis requires dashboard tRPC API. Use OpenPanel dashboard for user flow visualization.",
|
|
"message": "Paths report configuration created",
|
|
},
|
|
indent=2,
|
|
ensure_ascii=False,
|
|
)
|
|
except Exception as e:
|
|
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)
|
|
|
|
async def get_realtime_stats(client: OpenPanelClient, project_id: str | None = None) -> str:
|
|
"""Get real-time visitor statistics using chart.chart with 30min range"""
|
|
try:
|
|
effective_project_id = _get_project_id(client, project_id)
|
|
|
|
# Use chart.chart with 30min range for realtime data
|
|
result = await client.get_live_visitors(project_id=effective_project_id)
|
|
|
|
active_users = result.get("count", 0) if isinstance(result, dict) else 0
|
|
|
|
# Check for errors
|
|
if isinstance(result, dict) and "error" in result:
|
|
return json.dumps(
|
|
{
|
|
"success": False,
|
|
"project_id": effective_project_id,
|
|
"error": result.get("error"),
|
|
"note": "tRPC chart.chart endpoint may require authentication",
|
|
},
|
|
indent=2,
|
|
ensure_ascii=False,
|
|
)
|
|
|
|
return json.dumps(
|
|
{
|
|
"success": True,
|
|
"project_id": effective_project_id,
|
|
"realtime": {
|
|
"active_visitors_30min": active_users,
|
|
"timestamp": "now",
|
|
"period": "30min",
|
|
},
|
|
"message": "Real-time stats retrieved via chart.chart with 30min range",
|
|
},
|
|
indent=2,
|
|
ensure_ascii=False,
|
|
)
|
|
except Exception as e:
|
|
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)
|
|
|
|
async def get_ab_test_results(
|
|
client: OpenPanelClient,
|
|
test_name: str,
|
|
conversion_event: str,
|
|
project_id: str | None = None,
|
|
date_range: str = "30d",
|
|
) -> str:
|
|
"""Get A/B test results"""
|
|
try:
|
|
effective_project_id = _get_project_id(client, project_id)
|
|
# A/B test results typically tracked via properties
|
|
return json.dumps(
|
|
{
|
|
"success": True,
|
|
"project_id": effective_project_id,
|
|
"test_name": test_name,
|
|
"ab_test_config": {"conversion_event": conversion_event, "date_range": date_range},
|
|
"note": "A/B test analysis requires tracking variants via event properties. Use OpenPanel dashboard for detailed variant comparison.",
|
|
"message": "A/B test configuration retrieved",
|
|
},
|
|
indent=2,
|
|
ensure_ascii=False,
|
|
)
|
|
except Exception as e:
|
|
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)
|
|
|
|
async def create_scheduled_report(
|
|
client: OpenPanelClient,
|
|
name: str,
|
|
report_type: str,
|
|
schedule: str,
|
|
recipients: list[str],
|
|
project_id: str | None = None,
|
|
) -> str:
|
|
"""Create a scheduled report"""
|
|
try:
|
|
effective_project_id = _get_project_id(client, project_id)
|
|
return json.dumps(
|
|
{
|
|
"success": True,
|
|
"project_id": effective_project_id,
|
|
"scheduled_report": {
|
|
"name": name,
|
|
"report_type": report_type,
|
|
"schedule": schedule,
|
|
"recipients": recipients,
|
|
},
|
|
"note": "Scheduled reports require dashboard tRPC API. Configure via OpenPanel dashboard.",
|
|
"message": f"Scheduled report '{name}' configuration created",
|
|
},
|
|
indent=2,
|
|
ensure_ascii=False,
|
|
)
|
|
except Exception as e:
|
|
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)
|
|
|
|
async def export_report_pdf(
|
|
client: OpenPanelClient,
|
|
report_type: str,
|
|
project_id: str | None = None,
|
|
date_range: str = "30d",
|
|
) -> str:
|
|
"""Export report as PDF"""
|
|
try:
|
|
effective_project_id = _get_project_id(client, project_id)
|
|
return json.dumps(
|
|
{
|
|
"success": True,
|
|
"project_id": effective_project_id,
|
|
"export_config": {
|
|
"report_type": report_type,
|
|
"format": "pdf",
|
|
"date_range": date_range,
|
|
},
|
|
"note": "PDF export requires dashboard functionality. Use OpenPanel dashboard to export reports.",
|
|
"message": f"PDF export configuration for {report_type} report",
|
|
},
|
|
indent=2,
|
|
ensure_ascii=False,
|
|
)
|
|
except Exception as e:
|
|
return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)
|