Class: AISpec::Core::Reporters::HTML

Inherits:
Base
  • Object
show all
Defined in:
lib/aispec/core/reporters/html.rb

Instance Attribute Summary

Attributes inherited from Base

#output_io, #results

Instance Method Summary collapse

Methods inherited from Base

get, #initialize, register

Constructor Details

This class inherits a constructor from AISpec::Core::Reporters::Base

Instance Method Details

#renderObject



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/aispec/core/reporters/html.rb', line 7

def render
  contract = results[:contract]
  stats = results[:statistics]
  summary = stats.summary

  html = <<~HTML
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>AISpec Contract Verification Report - #{contract.name}</title>
      <style>
        :root {
          --bg: #0f172a;
          --card-bg: #1e293b;
          --text: #f8fafc;
          --text-muted: #94a3b8;
          --accent: #6366f1;
          --success: #22c55e;
          --danger: #ef4444;
          --border: #334155;
        }
        body {
          font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
          background-color: var(--bg);
          color: var(--text);
          margin: 0;
          padding: 2rem;
        }
        .container { max-width: 1100px; margin: 0 auto; }
        header { margin-bottom: 2rem; border-bottom: 1px solid var(--border); padding-bottom: 1rem; }
        h1 { margin: 0 0 0.5rem 0; font-size: 2rem; }
        .subtitle { color: var(--text-muted); font-size: 1.1rem; }
        .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1rem; margin-bottom: 2rem; }
        .card { background: var(--card-bg); border: 1px solid var(--border); border-radius: 12px; padding: 1.25rem; }
        .card-title { color: var(--text-muted); font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.05em; }
        .card-value { font-size: 1.8rem; font-weight: 700; margin-top: 0.5rem; }
        .badge-pass { color: var(--success); }
        .badge-fail { color: var(--danger); }
        section { background: var(--card-bg); border: 1px solid var(--border); border-radius: 12px; padding: 1.5rem; margin-bottom: 1.5rem; }
        h2 { margin-top: 0; font-size: 1.3rem; border-bottom: 1px solid var(--border); padding-bottom: 0.5rem; }
        table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
        th, td { text-align: left; padding: 0.75rem; border-bottom: 1px solid var(--border); }
        th { color: var(--text-muted); font-weight: 600; font-size: 0.9rem; }
        pre { background: #090d16; padding: 1rem; border-radius: 8px; overflow-x: auto; font-size: 0.9rem; color: #e2e8f0; }
      </style>
    </head>
    <body>
      <div class="container">
        <header>
          <h1>AISpec Behavioral Contract Report</h1>
          <div class="subtitle">Contract: <strong>#{contract.name}</strong> | Provider: <strong>#{results[:provider_name]}</strong> | Model: <strong>#{results[:model]}</strong></div>
        </header>

        <div class="grid">
          <div class="card">
            <div class="card-title">Behavior Score</div>
            <div class="card-value #{summary[:success_rate] >= 90 ? 'badge-pass' : 'badge-fail'}">#{summary[:success_rate]}%</div>
            <div style="font-size:0.8rem; color:var(--text-muted);">CI: &plusmn;#{summary[:confidence_interval]}%</div>
          </div>
          <div class="card">
            <div class="card-title">Assertions</div>
            <div class="card-value">#{summary[:passed_assertions]} / #{summary[:total_assertions]}</div>
          </div>
          <div class="card">
            <div class="card-title">Mean Latency</div>
            <div class="card-value">#{summary[:mean_latency]} ms</div>
          </div>
          <div class="card">
            <div class="card-title">Total Cost</div>
            <div class="card-value">$#{sprintf('%.4f', summary[:total_cost])}</div>
          </div>
          <div class="card">
            <div class="card-title">Recommendation</div>
            <div class="card-value" style="font-size:1.2rem; margin-top:0.8rem;">#{summary[:recommendation]}</div>
          </div>
        </div>

        <section>
          <h2>Summary & Analysis</h2>
          <p><strong>Average Judge Score:</strong> #{summary[:average_judge_score] || 'N/A'}</p>
          <p><strong>Variance:</strong> #{summary[:variance]}</p>
        </section>

        <section>
          <h2>Test Runs & Prompt Details</h2>
          #{render_runs_table}
        </section>
      </div>
    </body>
    </html>
  HTML

  output_io.puts html
  html
end