leva 0.1.10 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -2
  3. data/app/assets/stylesheets/leva/application.css +3083 -15
  4. data/app/controllers/leva/design_system_controller.rb +9 -0
  5. data/app/views/layouts/leva/application.html.erb +23 -24
  6. data/app/views/leva/dataset_records/index.html.erb +63 -61
  7. data/app/views/leva/dataset_records/show.html.erb +115 -25
  8. data/app/views/leva/datasets/_dataset.html.erb +11 -18
  9. data/app/views/leva/datasets/_form.html.erb +18 -14
  10. data/app/views/leva/datasets/edit.html.erb +16 -4
  11. data/app/views/leva/datasets/index.html.erb +33 -41
  12. data/app/views/leva/datasets/new.html.erb +15 -4
  13. data/app/views/leva/datasets/show.html.erb +120 -139
  14. data/app/views/leva/design_system/index.html.erb +1731 -0
  15. data/app/views/leva/experiments/_experiment.html.erb +46 -31
  16. data/app/views/leva/experiments/_form.html.erb +62 -35
  17. data/app/views/leva/experiments/edit.html.erb +17 -3
  18. data/app/views/leva/experiments/index.html.erb +41 -36
  19. data/app/views/leva/experiments/new.html.erb +40 -19
  20. data/app/views/leva/experiments/show.html.erb +155 -98
  21. data/app/views/leva/runner_results/show.html.erb +271 -54
  22. data/app/views/leva/workbench/_evaluation_area.html.erb +18 -4
  23. data/app/views/leva/workbench/_prompt_content.html.erb +116 -111
  24. data/app/views/leva/workbench/_prompt_form.html.erb +24 -23
  25. data/app/views/leva/workbench/_prompt_sidebar.html.erb +57 -12
  26. data/app/views/leva/workbench/_results_section.html.erb +274 -112
  27. data/app/views/leva/workbench/_top_bar.html.erb +16 -6
  28. data/app/views/leva/workbench/edit.html.erb +46 -15
  29. data/app/views/leva/workbench/index.html.erb +5 -8
  30. data/app/views/leva/workbench/new.html.erb +74 -42
  31. data/config/routes.rb +2 -0
  32. data/lib/leva/engine.rb +10 -0
  33. data/lib/leva/version.rb +1 -1
  34. metadata +4 -2
@@ -1,165 +1,146 @@
1
1
  <% content_for :title, @dataset.name %>
2
- <div class="container mx-auto px-4 py-8 bg-gray-950 text-white">
3
- <div class="mb-8">
4
- <div class="flex justify-between items-center">
5
- <h1 class="text-3xl font-bold text-indigo-400 mb-2"><%= @dataset.name %></h1>
6
- <div class="flex items-center space-x-4">
7
- <%= link_to edit_dataset_path(@dataset), class: 'btn btn-secondary flex items-center' do %>
8
- <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
9
- <path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" />
10
- </svg>
11
- Edit Dataset
12
- <% end %>
13
- <% if @dataset.dataset_records.empty? %>
14
- <%= button_to dataset_path(@dataset), method: :delete, class: 'btn btn-danger flex items-center', data: { confirm: 'Are you sure you want to delete this dataset?' } do %>
15
- <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
16
- <path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
17
- </svg>
18
- Delete Dataset
19
- <% end %>
20
- <% else %>
21
- <button class="btn btn-danger flex items-center opacity-50 cursor-not-allowed" disabled title="Cannot delete dataset with existing records">
22
- <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
23
- <path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
24
- </svg>
25
- Delete Dataset
26
- </button>
27
- <% end %>
2
+ <div class="container page">
3
+ <div class="page-header">
4
+ <div>
5
+ <div class="breadcrumb mb-2">
6
+ <%= link_to "Datasets", datasets_path, class: "breadcrumb-link" %>
7
+ <span class="breadcrumb-sep">/</span>
8
+ <span class="breadcrumb-current"><%= @dataset.name %></span>
28
9
  </div>
10
+ <h1 class="page-title"><%= @dataset.name %></h1>
11
+ <% if @dataset.description.present? %>
12
+ <p class="text-muted text-sm mt-2" style="max-width: 600px;"><%= @dataset.description %></p>
13
+ <% end %>
29
14
  </div>
30
- <p class="text-gray-400"><%= @dataset.description %></p>
31
- </div>
32
- <div class="mb-8">
33
- <div class="flex justify-between items-center mb-4">
34
- <h2 class="text-2xl font-semibold text-indigo-300">Dataset Records</h2>
35
- <div class="flex space-x-2">
36
- <%= link_to dataset_dataset_records_path(@dataset), class: "btn btn-secondary flex items-center" do %>
37
- <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
38
- <path d="M10 12a2 2 0 100-4 2 2 0 000 4z" />
39
- <path fill-rule="evenodd" d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clip-rule="evenodd" />
15
+ <div class="btn-group">
16
+ <%= link_to edit_dataset_path(@dataset), class: 'btn btn-ghost' do %>
17
+ <svg class="icon-sm" viewBox="0 0 20 20" fill="currentColor">
18
+ <path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" />
19
+ </svg>
20
+ Edit
21
+ <% end %>
22
+ <% if @dataset.dataset_records.empty? %>
23
+ <%= button_to dataset_path(@dataset), method: :delete, class: 'btn btn-ghost text-error', data: { confirm: 'Are you sure you want to delete this dataset?' } do %>
24
+ <svg class="icon-sm" viewBox="0 0 20 20" fill="currentColor">
25
+ <path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
40
26
  </svg>
41
- View All Records
27
+ Delete
42
28
  <% end %>
43
- <%= link_to '#', class: "btn btn-primary flex items-center" do %>
44
- <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
45
- <path fill-rule="evenodd" d="M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z" clip-rule="evenodd" />
29
+ <% else %>
30
+ <button class="btn btn-ghost text-muted" disabled title="Cannot delete dataset with existing records">
31
+ <svg class="icon-sm" viewBox="0 0 20 20" fill="currentColor">
32
+ <path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
46
33
  </svg>
47
- Add Record
34
+ Delete
35
+ </button>
36
+ <% end %>
37
+ </div>
38
+ </div>
39
+
40
+ <%# Dataset Records Section %>
41
+ <section class="mb-8">
42
+ <div class="section-header">
43
+ <h3 class="section-title">Records</h3>
44
+ <span class="section-count"><%= @dataset.dataset_records.count %></span>
45
+ <div class="ml-auto btn-group">
46
+ <% if @dataset.dataset_records.count > 10 %>
47
+ <%= link_to dataset_dataset_records_path(@dataset), class: "btn btn-ghost btn-sm" do %>
48
+ View all
49
+ <% end %>
48
50
  <% end %>
49
51
  </div>
50
52
  </div>
53
+
51
54
  <% if @dataset.dataset_records.any? %>
52
- <div class="bg-gray-800 rounded-lg shadow-lg overflow-hidden">
53
- <table class="min-w-full divide-y divide-gray-700">
54
- <thead class="bg-gray-700">
55
- <tr>
56
- <% @dataset.dataset_records.first.index_attributes.keys.each do |key| %>
57
- <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">
58
- <%= key.to_s.humanize %>
59
- </th>
60
- <% end %>
61
- <th scope="col" class="relative px-6 py-3">
62
- <span class="sr-only">Actions</span>
63
- </th>
64
- </tr>
65
- </thead>
66
- <tbody class="bg-gray-800 divide-y divide-gray-700">
67
- <% @dataset.dataset_records.first(10).each do |record| %>
68
- <tr class="hover:bg-gray-700 transition-colors duration-200">
69
- <% record.index_attributes.values.each do |value| %>
70
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-300">
71
- <%= value %>
72
- </td>
55
+ <div class="table-wrapper">
56
+ <div class="table-scroll">
57
+ <table class="table table-clickable">
58
+ <thead>
59
+ <tr>
60
+ <% @dataset.dataset_records.first.index_attributes.keys.each do |key| %>
61
+ <th><%= key.to_s.humanize %></th>
73
62
  <% end %>
74
- <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
75
- <%= link_to 'View', dataset_dataset_record_path(@dataset, record), class: 'text-indigo-400 hover:text-indigo-300 transition-colors duration-200' %>
76
- </td>
77
63
  </tr>
78
- <% end %>
79
- </tbody>
80
- </table>
81
- </div>
82
- <% total_records = @dataset.dataset_records.count %>
83
- <% displayed_records = [total_records, 10].min %>
84
- <div class="mt-4 text-gray-400 text-sm">
85
- Showing <%= displayed_records %> of <%= total_records %> records.
86
- <% if total_records > 10 %>
87
- <%= link_to 'View all records', dataset_dataset_records_path(@dataset), class: 'text-indigo-400 hover:text-indigo-300' %>
88
- <% end %>
64
+ </thead>
65
+ <tbody>
66
+ <% @dataset.dataset_records.first(10).each do |record| %>
67
+ <tr class="clickable-row" onclick="window.location='<%= dataset_dataset_record_path(@dataset, record) %>'">
68
+ <% record.index_attributes.each_with_index do |(key, value), index| %>
69
+ <td class="<%= index == 0 ? '' : 'cell-truncate' %>">
70
+ <%= index == 0 ? content_tag(:span, value, class: 'row-title') : value %>
71
+ </td>
72
+ <% end %>
73
+ </tr>
74
+ <% end %>
75
+ </tbody>
76
+ </table>
77
+ </div>
89
78
  </div>
90
79
  <% else %>
91
- <div class="bg-gray-800 rounded-lg shadow-lg p-12 text-center">
92
- <svg class="mx-auto h-12 w-12 text-indigo-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
93
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 13h6m-3-3v6m5 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
94
- </svg>
95
- <h3 class="mt-2 text-xl font-medium text-indigo-300">No records yet</h3>
96
- <p class="mt-1 text-gray-400">Start adding records to your dataset.</p>
97
- <div class="mt-6">
98
- <%= link_to '#', class: "btn btn-primary inline-flex items-center" do %>
99
- <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
100
- <path fill-rule="evenodd" d="M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z" clip-rule="evenodd" />
101
- </svg>
102
- Add your first record
103
- <% end %>
104
- </div>
80
+ <div class="empty-state-inline">
81
+ <p class="text-muted text-sm">No records in this dataset yet.</p>
82
+ <p class="text-xs text-subtle mt-2">Records are added programmatically via the Leva API.</p>
105
83
  </div>
106
84
  <% end %>
107
- </div>
108
- <div class="mb-8">
109
- <div class="flex justify-between items-center mb-4">
110
- <h2 class="text-2xl font-semibold text-indigo-300">Experiments</h2>
111
- <%= link_to new_experiment_path(dataset_id: @dataset.id), class: "btn btn-primary flex items-center" do %>
112
- <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
113
- <path fill-rule="evenodd" d="M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z" clip-rule="evenodd" />
114
- </svg>
115
- New Experiment
116
- <% end %>
85
+ </section>
86
+
87
+ <%# Experiments Section %>
88
+ <section>
89
+ <div class="section-header">
90
+ <h3 class="section-title">Experiments</h3>
91
+ <span class="section-count"><%= @dataset.experiments.count %></span>
92
+ <div class="ml-auto">
93
+ <%= link_to new_experiment_path(dataset_id: @dataset.id), class: "btn btn-primary btn-sm" do %>
94
+ <svg class="icon-sm" viewBox="0 0 20 20" fill="currentColor">
95
+ <path fill-rule="evenodd" d="M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z" clip-rule="evenodd" />
96
+ </svg>
97
+ New Experiment
98
+ <% end %>
99
+ </div>
117
100
  </div>
101
+
118
102
  <% if @dataset.experiments.any? %>
119
- <div class="bg-gray-800 rounded-lg shadow-lg overflow-hidden">
120
- <table class="min-w-full divide-y divide-gray-700">
121
- <thead class="bg-gray-700">
122
- <tr>
123
- <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">
124
- Name
125
- </th>
126
- <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">
127
- Status
128
- </th>
129
- <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">
130
- Total Results
131
- </th>
132
- <% Leva::EvaluationResult.distinct.pluck(:evaluator_class).each do |evaluator_class| %>
133
- <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">
134
- <%= evaluator_class.demodulize %>
135
- </th>
136
- <% end %>
137
- <th scope="col" class="relative px-6 py-3">
138
- <span class="sr-only">Actions</span>
139
- </th>
140
- </tr>
141
- </thead>
142
- <tbody class="bg-gray-800 divide-y divide-gray-700">
143
- <%= render partial: 'leva/experiments/experiment', collection: @dataset.experiments %>
144
- </tbody>
145
- </table>
103
+ <div class="table-wrapper">
104
+ <div class="table-scroll">
105
+ <table class="table table-clickable">
106
+ <thead>
107
+ <tr>
108
+ <th>Name</th>
109
+ <th class="text-right" style="width: 90px;">Created</th>
110
+ <th class="text-center" style="width: 80px;">Status</th>
111
+ <th class="text-right" style="width: 60px;">Runs</th>
112
+ <% Leva::EvaluationResult.distinct.pluck(:evaluator_class).each do |evaluator_class| %>
113
+ <%
114
+ short_name = evaluator_class.demodulize
115
+ .gsub(/Evaluator$/, '')
116
+ .gsub(/Eval$/, '')
117
+ .gsub(/^Sentiment/, '')
118
+ .gsub(/^[A-Z][a-z]+(?=[A-Z])/, '')
119
+ short_name = short_name.presence || evaluator_class.demodulize.gsub(/Eval(uator)?$/, '')
120
+ %>
121
+ <th class="text-right" style="width: 80px;"><%= short_name %></th>
122
+ <% end %>
123
+ </tr>
124
+ </thead>
125
+ <tbody>
126
+ <%= render partial: 'leva/experiments/experiment', collection: @dataset.experiments %>
127
+ </tbody>
128
+ </table>
129
+ </div>
146
130
  </div>
147
131
  <% else %>
148
- <div class="bg-gray-800 rounded-lg shadow-lg p-12 text-center">
149
- <svg class="mx-auto h-12 w-12 text-indigo-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
150
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z" />
151
- </svg>
152
- <h3 class="mt-2 text-xl font-medium text-indigo-300">No experiments yet</h3>
153
- <p class="mt-1 text-gray-400">Create an experiment to start evaluating your dataset.</p>
154
- <div class="mt-6">
155
- <%= link_to new_experiment_path(dataset_id: @dataset.id), class: "btn btn-primary inline-flex items-center" do %>
156
- <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
132
+ <div class="empty-state-inline">
133
+ <p class="text-muted text-sm">No experiments for this dataset yet.</p>
134
+ <p class="text-xs text-subtle mt-2">Create an experiment to start evaluating your prompts.</p>
135
+ <div class="mt-4">
136
+ <%= link_to new_experiment_path(dataset_id: @dataset.id), class: "btn btn-primary" do %>
137
+ <svg class="icon-sm" viewBox="0 0 20 20" fill="currentColor">
157
138
  <path fill-rule="evenodd" d="M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z" clip-rule="evenodd" />
158
139
  </svg>
159
- Create your first experiment
140
+ Create first experiment
160
141
  <% end %>
161
142
  </div>
162
143
  </div>
163
144
  <% end %>
164
- </div>
165
- </div>
145
+ </section>
146
+ </div>