{
  "dashboard_title": "Model Extraction Quality",
  "description": "Operational dashboard for monitoring Ollama extraction success rates, latency, validation failures, and confidence distributions.",
  "slug": "model-extraction-quality",
  "position_json": {
    "HEADER_ID": {"id": "HEADER_ID", "type": "HEADER", "meta": {"text": "Model Extraction Quality"}},
    "ROW-1": {
      "type": "ROW",
      "children": ["CHART-success-rate-kpi", "CHART-avg-latency-kpi", "CHART-avg-confidence-kpi", "CHART-retry-rate-kpi"]
    },
    "ROW-2": {
      "type": "ROW",
      "children": ["CHART-extraction-timeseries", "CHART-validation-status-pie"]
    },
    "ROW-3": {
      "type": "ROW",
      "children": ["CHART-latency-percentiles", "CHART-confidence-distribution"]
    },
    "ROW-4": {
      "type": "ROW",
      "children": ["CHART-recent-failures-table"]
    }
  },
  "metadata": {
    "refresh_frequency": 300,
    "default_filters": "{}",
    "color_scheme": "supersetColors"
  },
  "charts": [
    {
      "slice_name": "Extraction Success Rate",
      "viz_type": "big_number_total",
      "description": "Overall extraction success rate in the last 24h",
      "datasource_type": "query",
      "query": "SELECT ROUND(COUNT(*) FILTER (WHERE success)::numeric / NULLIF(COUNT(*), 0), 4) AS success_rate FROM model_performance_metrics WHERE recorded_at >= NOW() - INTERVAL '24 hours'"
    },
    {
      "slice_name": "Avg Extraction Latency",
      "viz_type": "big_number_total",
      "description": "Average extraction duration in milliseconds",
      "datasource_type": "query",
      "query": "SELECT ROUND(AVG(total_duration_ms)::numeric, 0) AS avg_latency_ms FROM model_performance_metrics WHERE recorded_at >= NOW() - INTERVAL '24 hours'"
    },
    {
      "slice_name": "Avg Confidence Score",
      "viz_type": "big_number_total",
      "description": "Average confidence of successful extractions",
      "datasource_type": "query",
      "query": "SELECT ROUND(AVG(confidence)::numeric, 3) AS avg_confidence FROM model_performance_metrics WHERE recorded_at >= NOW() - INTERVAL '24 hours' AND success = TRUE"
    },
    {
      "slice_name": "Avg Retry Count",
      "viz_type": "big_number_total",
      "description": "Average retries per extraction attempt",
      "datasource_type": "query",
      "query": "SELECT ROUND(AVG(retry_count)::numeric, 2) AS avg_retries FROM model_performance_metrics WHERE recorded_at >= NOW() - INTERVAL '24 hours'"
    },
    {
      "slice_name": "Extractions Over Time",
      "viz_type": "echarts_timeseries_bar",
      "description": "Hourly extraction counts split by success/failure",
      "datasource_type": "query",
      "query": "SELECT date_trunc('hour', recorded_at) AS bucket, COUNT(*) FILTER (WHERE success) AS successful, COUNT(*) FILTER (WHERE NOT success) AS failed FROM model_performance_metrics WHERE recorded_at >= NOW() - INTERVAL '24 hours' GROUP BY 1 ORDER BY 1"
    },
    {
      "slice_name": "Validation Status Distribution",
      "viz_type": "pie",
      "description": "Breakdown of extraction validation outcomes",
      "datasource_type": "query",
      "query": "SELECT validation_status, COUNT(*) AS count FROM model_performance_metrics WHERE recorded_at >= NOW() - INTERVAL '24 hours' GROUP BY validation_status"
    },
    {
      "slice_name": "Latency Percentiles Over Time",
      "viz_type": "echarts_timeseries_line",
      "description": "P50, P95, P99 extraction latency per hour",
      "datasource_type": "query",
      "query": "SELECT date_trunc('hour', recorded_at) AS bucket, ROUND(PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY total_duration_ms)::numeric, 0) AS p50_ms, ROUND(PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY total_duration_ms)::numeric, 0) AS p95_ms, ROUND(PERCENTILE_CONT(0.99) WITHIN GROUP (ORDER BY total_duration_ms)::numeric, 0) AS p99_ms FROM model_performance_metrics WHERE recorded_at >= NOW() - INTERVAL '24 hours' GROUP BY 1 ORDER BY 1"
    },
    {
      "slice_name": "Confidence Distribution",
      "viz_type": "histogram",
      "description": "Distribution of extraction confidence scores",
      "datasource_type": "query",
      "query": "SELECT CASE WHEN confidence >= 0.9 THEN '0.9-1.0' WHEN confidence >= 0.8 THEN '0.8-0.9' WHEN confidence >= 0.7 THEN '0.7-0.8' WHEN confidence >= 0.6 THEN '0.6-0.7' WHEN confidence >= 0.5 THEN '0.5-0.6' ELSE '<0.5' END AS confidence_bucket, COUNT(*) AS count FROM model_performance_metrics WHERE recorded_at >= NOW() - INTERVAL '24 hours' AND success = TRUE GROUP BY 1 ORDER BY 1"
    },
    {
      "slice_name": "Recent Extraction Failures",
      "viz_type": "table",
      "description": "Most recent failed extractions with error details",
      "datasource_type": "query",
      "query": "SELECT mpm.ticker, mpm.model_name, mpm.validation_status, mpm.validation_error_count, mpm.attempt_count, mpm.total_duration_ms, mpm.recorded_at, d.title, d.document_type FROM model_performance_metrics mpm LEFT JOIN documents d ON d.id = mpm.document_id WHERE mpm.success = FALSE AND mpm.recorded_at >= NOW() - INTERVAL '24 hours' ORDER BY mpm.recorded_at DESC LIMIT 50"
    }
  ]
}
