leva 0.1.9 → 0.1.10

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -3
  3. data/app/controllers/leva/application_controller.rb +1 -1
  4. data/app/controllers/leva/dataset_records_controller.rb +1 -1
  5. data/app/controllers/leva/datasets_controller.rb +6 -6
  6. data/app/controllers/leva/experiments_controller.rb +8 -8
  7. data/app/controllers/leva/runner_results_controller.rb +1 -1
  8. data/app/controllers/leva/workbench_controller.rb +26 -15
  9. data/app/helpers/leva/application_helper.rb +7 -7
  10. data/app/jobs/leva/experiment_job.rb +1 -1
  11. data/app/jobs/leva/run_eval_job.rb +1 -1
  12. data/app/models/concerns/leva/recordable.rb +5 -5
  13. data/app/models/leva/dataset.rb +1 -1
  14. data/app/models/leva/evaluation_result.rb +1 -1
  15. data/app/models/leva/experiment.rb +1 -1
  16. data/app/models/leva/prompt.rb +1 -1
  17. data/app/views/layouts/leva/application.html.erb +0 -1
  18. data/app/views/leva/dataset_records/index.html.erb +56 -31
  19. data/app/views/leva/experiments/new.html.erb +28 -1
  20. data/app/views/leva/workbench/_prompt_content.html.erb +60 -14
  21. data/config/routes.rb +9 -9
  22. data/db/migrate/20240813173033_create_leva_dataset_records.rb +1 -0
  23. data/db/migrate/20240813173035_create_leva_experiments.rb +2 -0
  24. data/db/migrate/{20240816201419_create_leva_runner_results.rb → 20240813173040_create_leva_runner_results.rb} +4 -1
  25. data/db/migrate/20240813173050_create_leva_evaluation_results.rb +3 -3
  26. data/lib/generators/leva/eval_generator.rb +4 -4
  27. data/lib/generators/leva/runner_generator.rb +4 -4
  28. data/lib/generators/leva/templates/runner.rb.erb +20 -0
  29. data/lib/leva/version.rb +1 -1
  30. data/lib/leva.rb +24 -2
  31. metadata +3 -11
  32. data/db/migrate/20240816201433_update_leva_evaluation_results.rb +0 -8
  33. data/db/migrate/20240821163608_make_experiment_optional_for_runner_results.rb +0 -6
  34. data/db/migrate/20240821181934_add_prompt_to_leva_runner_results.rb +0 -5
  35. data/db/migrate/20240821183153_add_runner_and_evaluator_to_leva_experiments.rb +0 -6
  36. data/db/migrate/20240821191713_add_actual_result_to_leva_dataset_records.rb +0 -5
  37. data/db/migrate/20240822143201_remove_actual_result_from_leva_runner_results.rb +0 -5
  38. data/db/migrate/20240912183556_add_runner_class_to_leva_runner_results.rb +0 -5
  39. data/lib/tasks/auto_annotate_models.rake +0 -59
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e16081b74e57cb4f198b075e76bc5fc1c07f67e4a14c4d38e27f8df53e26f3cf
4
- data.tar.gz: db9725fdc26fe3542ba8a1b1aaf2f22c2471e112c841224ce3587d1b6e83269c
3
+ metadata.gz: 63fc046c15809b57e461d3c7b8a35635b6a32c439b58d916e4d41e33e0f72827
4
+ data.tar.gz: 0e7f080fcb722d9f9539a139fecc7e0692a202e4e0bc8266f7f4b637750b2942
5
5
  SHA512:
6
- metadata.gz: e1019c0ec416f40854b5b9ef7c4e38df0141c98c5684f01ed26ea145deba92151a0ed908936768819eb1ab11167f2e5b9e075389ef8e8b25fb84786c1571f64d
7
- data.tar.gz: 9de9c5e4ee512a66c8b6a72f5b5d8d7b6b316ddf4be13652df640433a40bf6a06b207cce38ef4bc8631619880d9587f3318a77a8722cee394e617c8fc2995039
6
+ metadata.gz: fa195af952f524ff1d3b33106dc9dae8a58a9f24afeb658395ca255b485ccbcfb6cb78e48f00dbbba0f40e467afe8553ed795f1e3c67391e1b0cf2eebbf65a5c
7
+ data.tar.gz: 2da6f65c79f5e46f70033c24a3f7b30b1a873bd986bcefc556186ffc2b3dd38aae9036a9cb1ec375c480c06233f2fb99b713af6afdc0a4d0d12db0034196362e
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Leva - Flexible Evaluation Framework for Language Models
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/leva.svg)](https://badge.fury.io/rb/leva)
4
+ [![CI](https://github.com/kieranklaassen/leva/actions/workflows/ci.yml/badge.svg)](https://github.com/kieranklaassen/leva/actions/workflows/ci.yml)
4
5
 
5
6
  Leva is a Ruby on Rails framework for evaluating Language Models (LLMs) using ActiveRecord datasets on production models. It provides a flexible structure for creating experiments, managing datasets, and implementing various evaluation logic on production data with security in mind.
6
7
 
@@ -28,13 +29,25 @@ rails leva:install:migrations
28
29
  rails db:migrate
29
30
  ```
30
31
 
32
+ Mount the Leva engine in your application's routes file:
33
+
34
+ ```ruby
35
+ # config/routes.rb
36
+ Rails.application.routes.draw do
37
+ mount Leva::Engine => "/leva"
38
+ # your other routes...
39
+ end
40
+ ```
41
+
42
+ The Leva UI will then be available at `/leva` in your application.
43
+
31
44
  ## Usage
32
45
 
33
46
  ### 1. Setting up Datasets
34
47
 
35
48
  First, create a dataset and add any ActiveRecord records you want to evaluate against. To make your models compatible with Leva, include the `Leva::Recordable` concern in your model:
36
49
 
37
- ````ruby
50
+ ```ruby
38
51
  class TextContent < ApplicationRecord
39
52
  include Leva::Recordable
40
53
 
@@ -71,7 +84,11 @@ class TextContent < ApplicationRecord
71
84
  end
72
85
  end
73
86
 
74
- dataset = Leva::Dataset.create(name: "Sentiment Analysis Dataset") dataset.add_record TextContent.create(text: "I love this product!", expected_label: "Positive") dataset.add_record TextContent.create(text: "Terrible experience", expected_label: "Negative") dataset.add_record TextContent.create(text: "It's ok", expected_label: "Neutral")
87
+ dataset = Leva::Dataset.create(name: "Sentiment Analysis Dataset")
88
+ dataset.add_record TextContent.create(text: "I love this product!", expected_label: "Positive")
89
+ dataset.add_record TextContent.create(text: "Terrible experience", expected_label: "Negative")
90
+ dataset.add_record TextContent.create(text: "It's ok", expected_label: "Neutral")
91
+ ```
75
92
 
76
93
  ### 2. Implementing Runs
77
94
 
@@ -79,7 +96,7 @@ Create a run class to handle the execution of your inference logic:
79
96
 
80
97
  ```bash
81
98
  rails generate leva:runner sentiment
82
- ````
99
+ ```
83
100
 
84
101
  ```ruby
85
102
  class SentimentRun < Leva::BaseRun
@@ -4,4 +4,4 @@ module Leva
4
4
  class ApplicationController < ActionController::Base
5
5
  protect_from_forgery with: :exception
6
6
  end
7
- end
7
+ end
@@ -18,4 +18,4 @@ module Leva
18
18
  @dataset = Dataset.find(params[:dataset_id])
19
19
  end
20
20
  end
21
- end
21
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Leva
4
4
  class DatasetsController < ApplicationController
5
- before_action :set_dataset, only: [:show, :edit, :update, :destroy]
5
+ before_action :set_dataset, only: [ :show, :edit, :update, :destroy ]
6
6
 
7
7
  # GET /datasets
8
8
  # @return [void]
@@ -35,7 +35,7 @@ module Leva
35
35
  @dataset = Dataset.new(dataset_params)
36
36
 
37
37
  if @dataset.save
38
- redirect_to @dataset, notice: 'Dataset was successfully created.'
38
+ redirect_to @dataset, notice: "Dataset was successfully created."
39
39
  else
40
40
  render :new
41
41
  end
@@ -45,7 +45,7 @@ module Leva
45
45
  # @return [void]
46
46
  def update
47
47
  if @dataset.update(dataset_params)
48
- redirect_to @dataset, notice: 'Dataset was successfully updated.'
48
+ redirect_to @dataset, notice: "Dataset was successfully updated."
49
49
  else
50
50
  render :edit
51
51
  end
@@ -55,10 +55,10 @@ module Leva
55
55
  # @return [void]
56
56
  def destroy
57
57
  if @dataset.dataset_records.any?
58
- redirect_to @dataset, alert: 'Cannot delete dataset with existing records.'
58
+ redirect_to @dataset, alert: "Cannot delete dataset with existing records."
59
59
  else
60
60
  @dataset.destroy
61
- redirect_to datasets_url, notice: 'Dataset was successfully destroyed.'
61
+ redirect_to datasets_url, notice: "Dataset was successfully destroyed."
62
62
  end
63
63
  end
64
64
 
@@ -76,4 +76,4 @@ module Leva
76
76
  params.require(:dataset).permit(:name, :description)
77
77
  end
78
78
  end
79
- end
79
+ end
@@ -4,9 +4,9 @@ module Leva
4
4
  class ExperimentsController < ApplicationController
5
5
  include ApplicationHelper
6
6
 
7
- before_action :set_experiment, only: [:show, :edit, :update]
8
- before_action :check_editable, only: [:edit, :update]
9
- before_action :load_runners_and_evaluators, only: [:new, :edit, :create, :update]
7
+ before_action :set_experiment, only: [ :show, :edit, :update ]
8
+ before_action :check_editable, only: [ :edit, :update ]
9
+ before_action :load_runners_and_evaluators, only: [ :new, :edit, :create, :update ]
10
10
 
11
11
  # GET /experiments
12
12
  # @return [void]
@@ -39,7 +39,7 @@ module Leva
39
39
 
40
40
  if @experiment.save
41
41
  ExperimentJob.perform_later(@experiment) unless @experiment.completed?
42
- redirect_to @experiment, notice: 'Experiment was successfully created and is now running.'
42
+ redirect_to @experiment, notice: "Experiment was successfully created and is now running."
43
43
  else
44
44
  render :new
45
45
  end
@@ -49,7 +49,7 @@ module Leva
49
49
  # @return [void]
50
50
  def update
51
51
  if @experiment.update(experiment_params)
52
- redirect_to @experiment, notice: 'Experiment was successfully updated.'
52
+ redirect_to @experiment, notice: "Experiment was successfully updated."
53
53
  else
54
54
  render :edit
55
55
  end
@@ -69,7 +69,7 @@ module Leva
69
69
  # Queue the job again
70
70
  ExperimentJob.perform_later(@experiment)
71
71
 
72
- redirect_to @experiment, notice: 'Experiment has been reset and is now running again.'
72
+ redirect_to @experiment, notice: "Experiment has been reset and is now running again."
73
73
  end
74
74
 
75
75
  private
@@ -92,7 +92,7 @@ module Leva
92
92
  end
93
93
 
94
94
  def check_editable
95
- redirect_to @experiment, alert: 'Completed experiments cannot be edited.' if @experiment.completed?
95
+ redirect_to @experiment, alert: "Completed experiments cannot be edited." if @experiment.completed?
96
96
  end
97
97
  end
98
- end
98
+ end
@@ -5,4 +5,4 @@ module Leva
5
5
  @runner_result = @experiment.runner_results.find(params[:id])
6
6
  end
7
7
  end
8
- end
8
+ end
@@ -4,9 +4,9 @@ module Leva
4
4
  class WorkbenchController < ApplicationController
5
5
  include ApplicationHelper
6
6
 
7
- before_action :set_prompt, only: [:index, :edit, :update, :run, :run_all_evals, :run_evaluator]
8
- before_action :set_dataset_record, only: [:index, :run, :run_all_evals, :run_evaluator]
9
- before_action :set_runner_result, only: [:index, :run_all_evals, :run_evaluator]
7
+ before_action :set_prompt, only: [ :index, :edit, :update, :run, :run_all_evals, :run_evaluator ]
8
+ before_action :set_dataset_record, only: [ :index, :run, :run_all_evals, :run_evaluator ]
9
+ before_action :set_runner_result, only: [ :index, :run_all_evals, :run_evaluator ]
10
10
 
11
11
  # GET /workbench
12
12
  # @return [void]
@@ -17,6 +17,17 @@ module Leva
17
17
  @runners = load_runners
18
18
  @selected_runner = params[:runner] || @runners.first&.name
19
19
  @selected_dataset_record = params[:dataset_record_id] || DatasetRecord.first&.id
20
+
21
+ # Get merged context if runner and dataset record are available
22
+ if @selected_runner && @dataset_record
23
+ runner_class = @selected_runner.constantize rescue nil
24
+ if runner_class && runner_class < Leva::BaseRun
25
+ runner = runner_class.new
26
+ @record_context = @dataset_record.recordable.to_llm_context
27
+ @runner_context = runner.to_llm_context(@dataset_record.recordable)
28
+ @merged_context = @record_context.merge(@runner_context)
29
+ end
30
+ end
20
31
  end
21
32
 
22
33
  # GET /workbench/new
@@ -31,7 +42,7 @@ module Leva
31
42
  def create
32
43
  @prompt = Prompt.new(prompt_params)
33
44
  if @prompt.save
34
- redirect_to workbench_index_path(prompt_id: @prompt.id), notice: 'Prompt was successfully created.'
45
+ redirect_to workbench_index_path(prompt_id: @prompt.id), notice: "Prompt was successfully created."
35
46
  else
36
47
  render :new
37
48
  end
@@ -47,45 +58,45 @@ module Leva
47
58
  def update
48
59
  @prompt = Prompt.find(params[:id])
49
60
  if @prompt.update(prompt_params)
50
- render json: { status: 'success', message: 'Prompt updated successfully' }
61
+ render json: { status: "success", message: "Prompt updated successfully" }
51
62
  else
52
- render json: { status: 'error', errors: @prompt.errors.full_messages }, status: :unprocessable_entity
63
+ render json: { status: "error", errors: @prompt.errors.full_messages }, status: :unprocessable_entity
53
64
  end
54
65
  end
55
66
 
56
67
  def run
57
- return redirect_to workbench_index_path, alert: 'Please select a record and a runner' unless @dataset_record && run_params[:runner]
68
+ return redirect_to workbench_index_path, alert: "Please select a record and a runner" unless @dataset_record && run_params[:runner]
58
69
 
59
70
  runner_class = run_params[:runner].constantize
60
- return redirect_to workbench_index_path, alert: 'Invalid runner selected' unless runner_class < Leva::BaseRun
71
+ return redirect_to workbench_index_path, alert: "Invalid runner selected" unless runner_class < Leva::BaseRun
61
72
 
62
73
  runner = runner_class.new
63
74
  runner_result = runner.execute_and_store(nil, @dataset_record, @prompt)
64
75
 
65
- redirect_to workbench_index_path(prompt_id: @prompt.id, dataset_record_id: @dataset_record.id, runner: run_params[:runner]), notice: 'Run completed successfully'
76
+ redirect_to workbench_index_path(prompt_id: @prompt.id, dataset_record_id: @dataset_record.id, runner: run_params[:runner]), notice: "Run completed successfully"
66
77
  end
67
78
 
68
79
  def run_all_evals
69
- return redirect_to workbench_index_path, alert: 'No runner result available' unless @runner_result
80
+ return redirect_to workbench_index_path, alert: "No runner result available" unless @runner_result
70
81
 
71
82
  load_evaluators.each do |evaluator_class|
72
83
  evaluator = evaluator_class.new
73
84
  evaluator.evaluate_and_store(nil, @runner_result)
74
85
  end
75
86
 
76
- redirect_to workbench_index_path(prompt_id: @prompt.id, dataset_record_id: @dataset_record.id, runner: params[:runner]), notice: 'All evaluations completed successfully'
87
+ redirect_to workbench_index_path(prompt_id: @prompt.id, dataset_record_id: @dataset_record.id, runner: params[:runner]), notice: "All evaluations completed successfully"
77
88
  end
78
89
 
79
90
  def run_evaluator
80
- return redirect_to workbench_index_path, alert: 'No runner result available' unless @runner_result
91
+ return redirect_to workbench_index_path, alert: "No runner result available" unless @runner_result
81
92
 
82
93
  evaluator_class = params[:evaluator].constantize
83
- return redirect_to workbench_index_path, alert: 'Invalid evaluator selected' unless evaluator_class < Leva::BaseEval
94
+ return redirect_to workbench_index_path, alert: "Invalid evaluator selected" unless evaluator_class < Leva::BaseEval
84
95
 
85
96
  evaluator = evaluator_class.new
86
97
  evaluator.evaluate_and_store(nil, @runner_result)
87
98
 
88
- redirect_to workbench_index_path(prompt_id: @prompt.id, dataset_record_id: @dataset_record.id, runner: params[:runner]), notice: 'Evaluator run successfully'
99
+ redirect_to workbench_index_path(prompt_id: @prompt.id, dataset_record_id: @dataset_record.id, runner: params[:runner]), notice: "Evaluator run successfully"
89
100
  end
90
101
 
91
102
  private
@@ -110,4 +121,4 @@ module Leva
110
121
  @runner_result = @dataset_record.runner_results.last if @dataset_record
111
122
  end
112
123
  end
113
- end
124
+ end
@@ -4,24 +4,24 @@ module Leva
4
4
  #
5
5
  # @return [Array<Class>] An array of evaluator classes
6
6
  def load_evaluators
7
- load_classes_from_directory('app/evals', Leva::BaseEval) || []
7
+ load_classes_from_directory("app/evals", Leva::BaseEval) || []
8
8
  end
9
9
 
10
10
  # Loads all runner classes that inherit from Leva::BaseRun
11
11
  #
12
12
  # @return [Array<Class>] An array of runner classes
13
13
  def load_runners
14
- load_classes_from_directory('app/runners', Leva::BaseRun) || []
14
+ load_classes_from_directory("app/runners", Leva::BaseRun) || []
15
15
  end
16
16
 
17
17
  # Loads predefined prompts from markdown files
18
18
  #
19
19
  # @return [Array<Array<String, String>>] An array of prompt name and content pairs
20
20
  def load_predefined_prompts
21
- prompts = Dir.glob(Rails.root.join('app', 'prompts', '*.md')).map do |file|
22
- name = File.basename(file, '.md').titleize
21
+ prompts = Dir.glob(Rails.root.join("app", "prompts", "*.md")).map do |file|
22
+ name = File.basename(file, ".md").titleize
23
23
  content = File.read(file)
24
- [name, content]
24
+ [ name, content ]
25
25
  end
26
26
  prompts
27
27
  end
@@ -34,8 +34,8 @@ module Leva
34
34
  # @param base_class [Class] The base class that loaded classes should inherit from
35
35
  # @return [Array<Class>] An array of loaded classes
36
36
  def load_classes_from_directory(directory, base_class)
37
- classes = Dir[Rails.root.join(directory, '*.rb')].map do |file|
38
- File.basename(file, '.rb').camelize.constantize
37
+ classes = Dir[Rails.root.join(directory, "*.rb")].map do |file|
38
+ File.basename(file, ".rb").camelize.constantize
39
39
  end.select { |klass| klass < base_class }
40
40
  classes.empty? ? [] : classes
41
41
  end
@@ -18,4 +18,4 @@ module Leva
18
18
  end
19
19
  end
20
20
  end
21
- end
21
+ end
@@ -37,4 +37,4 @@ module Leva
37
37
  experiment.dataset.dataset_records.count == experiment.runner_results.count
38
38
  end
39
39
  end
40
- end
40
+ end
@@ -3,10 +3,10 @@ module Leva
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- has_many :dataset_records, as: :recordable, class_name: 'Leva::DatasetRecord', dependent: :destroy
7
- has_many :datasets, through: :dataset_records, class_name: 'Leva::Dataset'
8
- has_many :runner_results, through: :dataset_records, class_name: 'Leva::RunnerResult'
9
- has_many :evaluation_results, through: :runner_results, class_name: 'Leva::EvaluationResult'
6
+ has_many :dataset_records, as: :recordable, class_name: "Leva::DatasetRecord", dependent: :destroy
7
+ has_many :datasets, through: :dataset_records, class_name: "Leva::Dataset"
8
+ has_many :runner_results, through: :dataset_records, class_name: "Leva::RunnerResult"
9
+ has_many :evaluation_results, through: :runner_results, class_name: "Leva::EvaluationResult"
10
10
  end
11
11
 
12
12
  # @return [String] The ground truth label for the record
@@ -34,4 +34,4 @@ module Leva
34
34
  false
35
35
  end
36
36
  end
37
- end
37
+ end
@@ -25,4 +25,4 @@ module Leva
25
25
  end
26
26
  end
27
27
  end
28
- end
28
+ end
@@ -36,4 +36,4 @@ module Leva
36
36
 
37
37
  scope :for_evaluator, ->(evaluator_class) { where(evaluator_class: evaluator_class.name) }
38
38
  end
39
- end
39
+ end
@@ -40,4 +40,4 @@ module Leva
40
40
 
41
41
  serialize :evaluator_classes, coder: JSON, type: Array
42
42
  end
43
- end
43
+ end
@@ -27,4 +27,4 @@ module Leva
27
27
  self.version += 1
28
28
  end
29
29
  end
30
- end
30
+ end
@@ -8,7 +8,6 @@
8
8
  <%= csp_meta_tag %>
9
9
  <script src="https://cdn.tailwindcss.com"></script>
10
10
  <script src="https://cdn.jsdelivr.net/npm/stimulus@3.2.2/dist/stimulus.umd.min.js"></script>
11
- <script src="<%= asset_path 'custom/prompt_preview.js' %>"></script>
12
11
  <%= yield(:head) %>
13
12
  </head>
14
13
  <body class="bg-gray-950 text-white">
@@ -12,38 +12,63 @@
12
12
  </div>
13
13
  </div>
14
14
 
15
- <div class="bg-gray-800 rounded-lg shadow-lg overflow-hidden">
16
- <table class="min-w-full divide-y divide-gray-700">
17
- <thead class="bg-gray-700">
18
- <tr>
19
- <% @records.first.index_attributes.keys.each do |key| %>
20
- <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">
21
- <%= key.to_s.humanize %>
22
- </th>
23
- <% end %>
24
- <th scope="col" class="relative px-6 py-3">
25
- <span class="sr-only">Actions</span>
26
- </th>
27
- </tr>
28
- </thead>
29
- <tbody class="bg-gray-800 divide-y divide-gray-700">
30
- <% @records.each do |record| %>
31
- <tr class="hover:bg-gray-700 transition-colors duration-200">
32
- <% record.index_attributes.values.each do |value| %>
33
- <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-300">
34
- <%= value %>
35
- </td>
15
+ <% if @records.any? %>
16
+ <div class="bg-gray-800 rounded-lg shadow-lg overflow-hidden">
17
+ <table class="min-w-full divide-y divide-gray-700">
18
+ <thead class="bg-gray-700">
19
+ <tr>
20
+ <% @records.first.index_attributes.keys.each do |key| %>
21
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">
22
+ <%= key.to_s.humanize %>
23
+ </th>
36
24
  <% end %>
37
- <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
38
- <%= link_to 'View', dataset_dataset_record_path(@dataset, record), class: 'text-indigo-400 hover:text-indigo-300 transition-colors duration-200' %>
39
- </td>
25
+ <th scope="col" class="relative px-6 py-3">
26
+ <span class="sr-only">Actions</span>
27
+ </th>
40
28
  </tr>
41
- <% end %>
42
- </tbody>
43
- </table>
44
- </div>
29
+ </thead>
30
+ <tbody class="bg-gray-800 divide-y divide-gray-700">
31
+ <% @records.each do |record| %>
32
+ <tr class="hover:bg-gray-700 transition-colors duration-200">
33
+ <% record.index_attributes.values.each do |value| %>
34
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-300">
35
+ <%= value %>
36
+ </td>
37
+ <% end %>
38
+ <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
39
+ <%= link_to 'View', dataset_dataset_record_path(@dataset, record), class: 'text-indigo-400 hover:text-indigo-300 transition-colors duration-200' %>
40
+ </td>
41
+ </tr>
42
+ <% end %>
43
+ </tbody>
44
+ </table>
45
+ </div>
45
46
 
46
- <div class="mt-4 text-gray-400 text-sm">
47
- Total records: <%= @records.count %>
48
- </div>
47
+ <div class="mt-4 text-gray-400 text-sm">
48
+ Total records: <%= @records.count %>
49
+ </div>
50
+ <% else %>
51
+ <div class="bg-gray-800 rounded-lg shadow-lg p-12 text-center">
52
+ <svg class="mx-auto h-12 w-12 text-indigo-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
53
+ <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" />
54
+ </svg>
55
+ <h3 class="mt-2 text-xl font-medium text-indigo-300">No records yet</h3>
56
+ <p class="mt-1 text-gray-400">This dataset doesn't contain any records yet.</p>
57
+ <div class="mt-4 text-sm text-gray-500">
58
+ <p>To add records to this dataset, use the Rails console or create them programmatically:</p>
59
+ <div class="mt-2 bg-gray-900 rounded px-3 py-2 text-left font-mono text-xs text-gray-300">
60
+ <p>dataset = Leva::Dataset.find(<%= @dataset.id %>)</p>
61
+ <p>dataset.add_record(your_model_instance)</p>
62
+ </div>
63
+ </div>
64
+ <div class="mt-6">
65
+ <%= link_to dataset_path(@dataset), class: "btn btn-secondary inline-flex items-center" do %>
66
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
67
+ <path fill-rule="evenodd" d="M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z" clip-rule="evenodd" />
68
+ </svg>
69
+ Back to Dataset
70
+ <% end %>
71
+ </div>
72
+ </div>
73
+ <% end %>
49
74
  </div>
@@ -1,5 +1,32 @@
1
1
  <% content_for :title, 'New Experiment' %>
2
2
  <div class="container mx-auto px-4 py-8 bg-gray-950 text-white">
3
3
  <h1 class="text-3xl font-bold text-indigo-400 mb-6">New Experiment</h1>
4
- <%= render 'form', experiment: @experiment %>
4
+ <% if @runners.present? %>
5
+ <%= render 'form', experiment: @experiment %>
6
+ <% else %>
7
+ <div class="bg-gray-800 rounded-lg shadow-lg p-12 text-center">
8
+ <svg class="mx-auto h-12 w-12 text-yellow-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
9
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z" />
10
+ </svg>
11
+ <h3 class="mt-2 text-xl font-medium text-yellow-300">No runners available</h3>
12
+ <p class="mt-1 text-gray-400">You need at least one runner to create an experiment.</p>
13
+ <div class="mt-6 text-left bg-gray-900 rounded-lg p-6">
14
+ <h4 class="text-lg font-semibold text-indigo-300 mb-3">What are runners?</h4>
15
+ <p class="text-gray-300 mb-4">Runners define how your model processes dataset records. They contain the execution logic that takes a dataset record and returns a prediction.</p>
16
+ <h4 class="text-lg font-semibold text-indigo-300 mb-3">Create your first runner:</h4>
17
+ <div class="bg-gray-800 rounded p-3 mb-4">
18
+ <code class="text-green-400">rails generate leva:runner sentiment</code>
19
+ </div>
20
+ <p class="text-gray-400 text-sm">This will create <code class="text-gray-300">app/runners/sentiment_run.rb</code> with a template to implement your model logic.</p>
21
+ </div>
22
+ <div class="mt-6">
23
+ <%= link_to experiments_path, class: "btn btn-secondary inline-flex items-center" do %>
24
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
25
+ <path fill-rule="evenodd" d="M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z" clip-rule="evenodd" />
26
+ </svg>
27
+ Back to Experiments
28
+ <% end %>
29
+ </div>
30
+ </div>
31
+ <% end %>
5
32
  </div>
@@ -48,19 +48,65 @@
48
48
  </svg>
49
49
  </h2>
50
50
  <div class="bg-gray-800 p-3 rounded-lg text-sm hidden" data-collapsible-target="content">
51
- <% @dataset_record.recordable.to_llm_context.each do |key, value| %>
52
- <details class="mb-2">
53
- <summary class="text-green-400 cursor-pointer flex items-center justify-between">
54
- <span>{{ <%= key %> }}</span>
55
- <button class="btn btn-small text-blue-400 hover:text-blue-300 flex items-center" data-action="clipboard#copy" data-clipboard-source="liquidTag<%= key %>">
56
- <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
57
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" />
58
- </svg>
59
- Copy
60
- </button>
61
- </summary>
62
- <pre class="text-xs text-gray-300 mt-1 whitespace-pre-wrap break-words overflow-x-auto max-w-full" id="liquidTag<%= key %>"><%= value.to_s %></pre>
63
- </details>
51
+ <% # Use merged context if available, otherwise just record context %>
52
+ <% context_to_display = @merged_context || @dataset_record.recordable.to_llm_context %>
53
+
54
+ <% if @record_context && @runner_context %>
55
+ <!-- Record Context -->
56
+ <div class="mb-4">
57
+ <h3 class="text-xs font-semibold text-gray-400 mb-2">FROM RECORD:</h3>
58
+ <% @record_context.each do |key, value| %>
59
+ <details class="mb-2">
60
+ <summary class="text-green-400 cursor-pointer flex items-center justify-between">
61
+ <span>{{ <%= key %> }}</span>
62
+ <button class="btn btn-small text-blue-400 hover:text-blue-300 flex items-center" data-action="clipboard#copy" data-clipboard-source="liquidTag<%= key %>">
63
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
64
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" />
65
+ </svg>
66
+ Copy
67
+ </button>
68
+ </summary>
69
+ <pre class="text-xs text-gray-300 mt-1 whitespace-pre-wrap break-words overflow-x-auto max-w-full" id="liquidTag<%= key %>"><%= value.to_s %></pre>
70
+ </details>
71
+ <% end %>
72
+ </div>
73
+
74
+ <!-- Runner Context -->
75
+ <% if @runner_context.any? %>
76
+ <div class="mb-4">
77
+ <h3 class="text-xs font-semibold text-gray-400 mb-2">FROM RUNNER:</h3>
78
+ <% @runner_context.each do |key, value| %>
79
+ <details class="mb-2">
80
+ <summary class="text-yellow-400 cursor-pointer flex items-center justify-between">
81
+ <span>{{ <%= key %> }}</span>
82
+ <button class="btn btn-small text-blue-400 hover:text-blue-300 flex items-center" data-action="clipboard#copy" data-clipboard-source="liquidTag<%= key %>">
83
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
84
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" />
85
+ </svg>
86
+ Copy
87
+ </button>
88
+ </summary>
89
+ <pre class="text-xs text-gray-300 mt-1 whitespace-pre-wrap break-words overflow-x-auto max-w-full" id="liquidTag<%= key %>"><%= value.to_s %></pre>
90
+ </details>
91
+ <% end %>
92
+ </div>
93
+ <% end %>
94
+ <% else %>
95
+ <!-- Fallback to original display -->
96
+ <% context_to_display.each do |key, value| %>
97
+ <details class="mb-2">
98
+ <summary class="text-green-400 cursor-pointer flex items-center justify-between">
99
+ <span>{{ <%= key %> }}</span>
100
+ <button class="btn btn-small text-blue-400 hover:text-blue-300 flex items-center" data-action="clipboard#copy" data-clipboard-source="liquidTag<%= key %>">
101
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
102
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" />
103
+ </svg>
104
+ Copy
105
+ </button>
106
+ </summary>
107
+ <pre class="text-xs text-gray-300 mt-1 whitespace-pre-wrap break-words overflow-x-auto max-w-full" id="liquidTag<%= key %>"><%= value.to_s %></pre>
108
+ </details>
109
+ <% end %>
64
110
  <% end %>
65
111
  </div>
66
112
  </div>
@@ -77,7 +123,7 @@
77
123
  Copy
78
124
  </button>
79
125
  </div>
80
- <pre class="w-full bg-gray-800 text-white p-3 rounded-lg text-sm whitespace-pre-wrap overflow-x-auto break-words max-w-full" id="fullPrompt"><%= Liquid::Template.parse(@selected_prompt.user_prompt).render(@dataset_record.recordable.to_llm_context.stringify_keys) %></pre>
126
+ <pre class="w-full bg-gray-800 text-white p-3 rounded-lg text-sm whitespace-pre-wrap overflow-x-auto break-words max-w-full" id="fullPrompt"><%= Liquid::Template.parse(@selected_prompt.user_prompt).render((@merged_context || @dataset_record.recordable.to_llm_context).stringify_keys) %></pre>
81
127
  </div>
82
128
  <% end %>
83
129
  <div class="text-sm text-center" data-prompt-autosave-target="status"></div>
data/config/routes.rb CHANGED
@@ -1,21 +1,21 @@
1
1
  Leva::Engine.routes.draw do
2
- root 'workbench#index'
2
+ root "workbench#index"
3
3
 
4
4
  resources :datasets do
5
- resources :dataset_records, path: 'records', only: [:index, :show]
5
+ resources :dataset_records, path: "records", only: [ :index, :show ]
6
6
  end
7
- resources :experiments, except: [:destroy] do
7
+ resources :experiments, except: [ :destroy ] do
8
8
  member do
9
9
  post :rerun
10
10
  end
11
- resources :runner_results, only: [:show]
11
+ resources :runner_results, only: [ :show ]
12
12
  end
13
13
  resources :prompts
14
- resources :workbench, only: [:index, :new, :create, :edit, :update] do
14
+ resources :workbench, only: [ :index, :new, :create, :edit, :update ] do
15
15
  collection do
16
- post 'run'
17
- post 'run_all_evals'
18
- post 'run_evaluator'
16
+ post "run"
17
+ post "run_all_evals"
18
+ post "run_evaluator"
19
19
  end
20
20
  end
21
- end
21
+ end
@@ -3,6 +3,7 @@ class CreateLevaDatasetRecords < ActiveRecord::Migration[7.2]
3
3
  create_table :leva_dataset_records do |t|
4
4
  t.references :dataset, null: false, foreign_key: { to_table: :leva_datasets }
5
5
  t.references :recordable, polymorphic: true, null: false
6
+ t.text :actual_result
6
7
 
7
8
  t.timestamps
8
9
  end
@@ -7,6 +7,8 @@ class CreateLevaExperiments < ActiveRecord::Migration[7.2]
7
7
  t.references :prompt, null: true, foreign_key: { to_table: :leva_prompts }
8
8
  t.integer :status
9
9
  t.text :metadata
10
+ t.string :runner_class
11
+ t.text :evaluator_classes
10
12
 
11
13
  t.timestamps
12
14
  end
@@ -1,9 +1,12 @@
1
1
  class CreateLevaRunnerResults < ActiveRecord::Migration[7.2]
2
2
  def change
3
3
  create_table :leva_runner_results do |t|
4
- t.references :experiment, null: false, foreign_key: { to_table: :leva_experiments }
4
+ t.references :experiment, null: true, foreign_key: { to_table: :leva_experiments }
5
5
  t.references :dataset_record, null: false, foreign_key: { to_table: :leva_dataset_records }
6
+ t.references :prompt, null: false, foreign_key: { to_table: :leva_prompts }
7
+ t.integer :prompt_version
6
8
  t.text :prediction
9
+ t.string :runner_class
7
10
 
8
11
  t.timestamps
9
12
  end
@@ -1,11 +1,11 @@
1
1
  class CreateLevaEvaluationResults < ActiveRecord::Migration[7.2]
2
2
  def change
3
3
  create_table :leva_evaluation_results do |t|
4
- t.references :experiment, null: false, foreign_key: { to_table: :leva_experiments }
4
+ t.references :experiment, null: true, foreign_key: { to_table: :leva_experiments }
5
5
  t.references :dataset_record, null: false, foreign_key: { to_table: :leva_dataset_records }
6
- t.string :prediction
6
+ t.references :runner_result, null: false, foreign_key: { to_table: :leva_runner_results }
7
+ t.string :evaluator_class, null: false
7
8
  t.float :score
8
- t.string :label
9
9
 
10
10
  t.timestamps
11
11
  end
@@ -3,10 +3,10 @@
3
3
  module Leva
4
4
  module Generators
5
5
  class EvalGenerator < Rails::Generators::NamedBase
6
- source_root File.expand_path('templates', __dir__)
6
+ source_root File.expand_path("templates", __dir__)
7
7
 
8
8
  def create_eval_file
9
- template 'eval.rb.erb', File.join('app/evals', class_path, "#{file_name}_eval.rb")
9
+ template "eval.rb.erb", File.join("app/evals", class_path, "#{file_name}_eval.rb")
10
10
  end
11
11
 
12
12
  private
@@ -16,8 +16,8 @@ module Leva
16
16
  end
17
17
 
18
18
  def remove_possible_suffix(name)
19
- name.sub(/_?eval$/i, '')
19
+ name.sub(/_?eval$/i, "")
20
20
  end
21
21
  end
22
22
  end
23
- end
23
+ end
@@ -3,10 +3,10 @@
3
3
  module Leva
4
4
  module Generators
5
5
  class RunnerGenerator < Rails::Generators::NamedBase
6
- source_root File.expand_path('templates', __dir__)
6
+ source_root File.expand_path("templates", __dir__)
7
7
 
8
8
  def create_runner_file
9
- template 'runner.rb.erb', File.join('app/runners', class_path, "#{file_name}_run.rb")
9
+ template "runner.rb.erb", File.join("app/runners", class_path, "#{file_name}_run.rb")
10
10
  end
11
11
 
12
12
  private
@@ -16,8 +16,8 @@ module Leva
16
16
  end
17
17
 
18
18
  def remove_possible_suffix(name)
19
- name.sub(/_?runner$/i, '')
19
+ name.sub(/_?runner$/i, "")
20
20
  end
21
21
  end
22
22
  end
23
- end
23
+ end
@@ -33,4 +33,24 @@ class <%= class_name %>Run < Leva::BaseRun
33
33
  # # For example:
34
34
  # # /\<result\>(.*?)\<\/result\>/
35
35
  # end
36
+
37
+ # Override this method to provide additional context for LLM prompts
38
+ # This is useful for expensive operations or runner-specific data
39
+ # that you don't want to compute in the record's to_llm_context
40
+ #
41
+ # @param record [YourRecordClass] The record to generate context for
42
+ # @return [Hash] Additional context to merge with the record's context
43
+ # def to_llm_context(record)
44
+ # # Example: Add runner-specific expensive computations
45
+ # {
46
+ # # Count of similar records (expensive database query)
47
+ # similar_<%= singular_name %>_count: record.class.where(
48
+ # "some_field LIKE ?", "%#{record.some_field.split.first}%"
49
+ # ).count,
50
+ #
51
+ # # Runner-specific configuration
52
+ # model_version: "v1.2.3",
53
+ # temperature: 0.7
54
+ # }
55
+ # end
36
56
  end
data/lib/leva/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Leva
2
- VERSION = "0.1.9"
2
+ VERSION = "0.1.10"
3
3
  end
data/lib/leva.rb CHANGED
@@ -65,6 +65,7 @@ module Leva
65
65
  # Expose these to the subclass execution
66
66
  @experiment = experiment
67
67
  @prompt = prompt
68
+ @dataset_record = dataset_record
68
69
 
69
70
  result = execute(dataset_record.recordable)
70
71
  RunnerResult.create!(
@@ -76,13 +77,25 @@ module Leva
76
77
  )
77
78
  end
78
79
 
80
+ # Gets the merged LLM context for the current execution.
81
+ # Combines the record's context with the runner's additional context.
82
+ #
83
+ # @return [Hash] The merged context for LLM prompt rendering
84
+ def merged_llm_context
85
+ return {} unless @dataset_record
86
+
87
+ record_context = @dataset_record.recordable.to_llm_context
88
+ runner_context = to_llm_context(@dataset_record.recordable)
89
+ record_context.merge(runner_context)
90
+ end
91
+
79
92
  # @param runner_result [Leva::RunnerResult] The runner result to parse
80
93
  # @return [Array<String>] The parsed predictions
81
94
  def parsed_predictions(runner_result)
82
95
  if extract_regex_pattern(runner_result)
83
96
  runner_result.prediction.scan(extract_regex_pattern(runner_result)).map { |match| match.first&.strip }.compact
84
97
  else
85
- [runner_result.prediction]
98
+ [ runner_result.prediction ]
86
99
  end
87
100
  end
88
101
 
@@ -97,6 +110,15 @@ module Leva
97
110
  def ground_truth(runner_result)
98
111
  runner_result.dataset_record.ground_truth
99
112
  end
113
+
114
+ # Provides additional LLM context specific to this runner.
115
+ # Override in subclasses to add expensive or runner-specific context.
116
+ #
117
+ # @param record [Object] The recordable object to generate context for
118
+ # @return [Hash] Additional context to merge with the record's context
119
+ def to_llm_context(record)
120
+ {}
121
+ end
100
122
  end
101
123
 
102
124
  # Base class for all evaluation implementations in Leva.
@@ -134,4 +156,4 @@ module Leva
134
156
  )
135
157
  end
136
158
  end
137
- end
159
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leva
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kieran Klaassen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-25 00:00:00.000000000 Z
11
+ date: 2025-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -103,15 +103,8 @@ files:
103
103
  - db/migrate/20240813173033_create_leva_dataset_records.rb
104
104
  - db/migrate/20240813173034_create_leva_prompts.rb
105
105
  - db/migrate/20240813173035_create_leva_experiments.rb
106
+ - db/migrate/20240813173040_create_leva_runner_results.rb
106
107
  - db/migrate/20240813173050_create_leva_evaluation_results.rb
107
- - db/migrate/20240816201419_create_leva_runner_results.rb
108
- - db/migrate/20240816201433_update_leva_evaluation_results.rb
109
- - db/migrate/20240821163608_make_experiment_optional_for_runner_results.rb
110
- - db/migrate/20240821181934_add_prompt_to_leva_runner_results.rb
111
- - db/migrate/20240821183153_add_runner_and_evaluator_to_leva_experiments.rb
112
- - db/migrate/20240821191713_add_actual_result_to_leva_dataset_records.rb
113
- - db/migrate/20240822143201_remove_actual_result_from_leva_runner_results.rb
114
- - db/migrate/20240912183556_add_runner_class_to_leva_runner_results.rb
115
108
  - lib/generators/leva/eval_generator.rb
116
109
  - lib/generators/leva/runner_generator.rb
117
110
  - lib/generators/leva/templates/eval.rb.erb
@@ -119,7 +112,6 @@ files:
119
112
  - lib/leva.rb
120
113
  - lib/leva/engine.rb
121
114
  - lib/leva/version.rb
122
- - lib/tasks/auto_annotate_models.rake
123
115
  - lib/tasks/leva_tasks.rake
124
116
  homepage: https://github.com/kieranklaassen/leva
125
117
  licenses:
@@ -1,8 +0,0 @@
1
- class UpdateLevaEvaluationResults < ActiveRecord::Migration[7.2]
2
- def change
3
- add_reference :leva_evaluation_results, :runner_result, null: false, foreign_key: { to_table: :leva_runner_results }
4
- add_column :leva_evaluation_results, :evaluator_class, :string, null: false
5
- remove_column :leva_evaluation_results, :prediction, :string
6
- remove_column :leva_evaluation_results, :label, :string
7
- end
8
- end
@@ -1,6 +0,0 @@
1
- class MakeExperimentOptionalForRunnerResults < ActiveRecord::Migration[7.2]
2
- def change
3
- change_column_null :leva_runner_results, :experiment_id, true
4
- change_column_null :leva_evaluation_results, :experiment_id, true
5
- end
6
- end
@@ -1,5 +0,0 @@
1
- class AddPromptToLevaRunnerResults < ActiveRecord::Migration[7.2]
2
- def change
3
- add_reference :leva_runner_results, :prompt, null: false, foreign_key: { to_table: :leva_prompts }
4
- end
5
- end
@@ -1,6 +0,0 @@
1
- class AddRunnerAndEvaluatorToLevaExperiments < ActiveRecord::Migration[7.2]
2
- def change
3
- add_column :leva_experiments, :runner_class, :string
4
- add_column :leva_experiments, :evaluator_classes, :text
5
- end
6
- end
@@ -1,5 +0,0 @@
1
- class AddActualResultToLevaDatasetRecords < ActiveRecord::Migration[7.2]
2
- def change
3
- add_column :leva_runner_results, :actual_result, :text
4
- end
5
- end
@@ -1,5 +0,0 @@
1
- class RemoveActualResultFromLevaRunnerResults < ActiveRecord::Migration[7.2]
2
- def change
3
- remove_column :leva_runner_results, :actual_result, :text
4
- end
5
- end
@@ -1,5 +0,0 @@
1
- class AddRunnerClassToLevaRunnerResults < ActiveRecord::Migration[7.2]
2
- def change
3
- add_column :leva_runner_results, :runner_class, :string
4
- end
5
- end
@@ -1,59 +0,0 @@
1
- # NOTE: only doing this in development as some production environments (Heroku)
2
- # NOTE: are sensitive to local FS writes, and besides -- it's just not proper
3
- # NOTE: to have a dev-mode tool do its thing in production.
4
- if Rails.env.development?
5
- require 'annotate'
6
- task :set_annotation_options do
7
- # You can override any of these by setting an environment variable of the
8
- # same name.
9
- Annotate.set_defaults(
10
- 'active_admin' => 'false',
11
- 'additional_file_patterns' => [],
12
- 'routes' => 'false',
13
- 'models' => 'true',
14
- 'position_in_routes' => 'before',
15
- 'position_in_class' => 'before',
16
- 'position_in_test' => 'before',
17
- 'position_in_fixture' => 'before',
18
- 'position_in_factory' => 'before',
19
- 'position_in_serializer' => 'before',
20
- 'show_foreign_keys' => 'true',
21
- 'show_complete_foreign_keys' => 'false',
22
- 'show_indexes' => 'true',
23
- 'simple_indexes' => 'false',
24
- 'model_dir' => 'app/models',
25
- 'root_dir' => '',
26
- 'include_version' => 'false',
27
- 'require' => '',
28
- 'exclude_tests' => 'false',
29
- 'exclude_fixtures' => 'false',
30
- 'exclude_factories' => 'false',
31
- 'exclude_serializers' => 'false',
32
- 'exclude_scaffolds' => 'true',
33
- 'exclude_controllers' => 'true',
34
- 'exclude_helpers' => 'true',
35
- 'exclude_sti_subclasses' => 'false',
36
- 'ignore_model_sub_dir' => 'false',
37
- 'ignore_columns' => nil,
38
- 'ignore_routes' => nil,
39
- 'ignore_unknown_models' => 'false',
40
- 'hide_limit_column_types' => 'integer,bigint,boolean',
41
- 'hide_default_column_types' => 'json,jsonb,hstore',
42
- 'skip_on_db_migrate' => 'false',
43
- 'format_bare' => 'true',
44
- 'format_rdoc' => 'false',
45
- 'format_yard' => 'false',
46
- 'format_markdown' => 'false',
47
- 'sort' => 'false',
48
- 'force' => 'false',
49
- 'frozen' => 'false',
50
- 'classified_sort' => 'true',
51
- 'trace' => 'false',
52
- 'wrapper_open' => nil,
53
- 'wrapper_close' => nil,
54
- 'with_comment' => 'true'
55
- )
56
- end
57
-
58
- Annotate.load_tasks
59
- end