completion-kit 0.28.10 → 0.28.12

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8eb41960ab1c047932e577095faa9bd23518a82b2a23ee30c84f862a32afc2d5
4
- data.tar.gz: e4d577875390f29ca7b5ddd78415734fabe9d1b1de910a83ad925248d9a14809
3
+ metadata.gz: b2a34fdd9be7c2b821c749f4bdf7bc8433a774505f5351ed7fd605135a71f7fd
4
+ data.tar.gz: 906ccf1371d03af5a758a66464ffca8924ab4df36653113ea08a087f47237758
5
5
  SHA512:
6
- metadata.gz: 3e820588ee5b204628a8b317d4ce9d66f66053795d9159c6c90ea325c9ac45cf940cb01ba09878cc85cd298b452090f6309654afe3a4db946bff9212a88ee85f
7
- data.tar.gz: 351ea8ff2c5012dfc5221d5dd4daf27e454b90d7c7cf63ac9839e76bc69e3f9e3b6e363331a257d9c65ba8bb73e375e1c9953cba36b875fbeb6f3c38583a1735
6
+ metadata.gz: 4a5a11320e41d14a8de77fc2ad38e60830e6de94aa60e539d517963c9089f8538ccb82abce9f3274976aad5030e2468615ecbbb5b081507e3ecfc222aa3471c6
7
+ data.tar.gz: 5d0d2496547c1b834218b1eed208a186eff5f1cd82924eae22753740d78817609808afb249c25fd66cd7132c26963ce625e921c95803d7cadcf63029c1b8c7f4
@@ -3,6 +3,7 @@ module CompletionKit
3
3
  module V1
4
4
  class DatasetsController < BaseController
5
5
  before_action :set_dataset, only: [:show, :update, :destroy]
6
+ before_action :reject_oversized_upload, only: [:create, :update]
6
7
 
7
8
  def index
8
9
  scope = Dataset.includes(:tags)
@@ -50,6 +51,13 @@ module CompletionKit
50
51
  permitted[:csv_data] = upload.read.to_s.force_encoding("UTF-8") if upload.respond_to?(:read)
51
52
  permitted
52
53
  end
54
+
55
+ def reject_oversized_upload
56
+ upload = params[:file]
57
+ return unless upload.respond_to?(:size) && upload.size > CompletionKit.config.max_upload_bytes
58
+
59
+ render_error("File exceeds the #{CompletionKit.config.max_upload_bytes / (1024 * 1024)} MB upload limit", status: :payload_too_large)
60
+ end
53
61
  end
54
62
  end
55
63
  end
@@ -4,6 +4,11 @@ module CompletionKit
4
4
  end
5
5
 
6
6
  def create
7
+ if upload_too_large?(params[:file])
8
+ flash.now[:alert] = "That file is too large. The limit is #{CompletionKit.config.max_upload_bytes / (1024 * 1024)} MB."
9
+ return render :new, status: :payload_too_large
10
+ end
11
+
7
12
  content = uploaded_content
8
13
 
9
14
  if content.blank?
@@ -27,5 +32,9 @@ module CompletionKit
27
32
  file = params[:file]
28
33
  file.respond_to?(:read) ? file.read : params[:config]
29
34
  end
35
+
36
+ def upload_too_large?(file)
37
+ file.respond_to?(:size) && file.size > CompletionKit.config.max_upload_bytes
38
+ end
30
39
  end
31
40
  end
@@ -6,6 +6,14 @@ module CompletionKit
6
6
 
7
7
  validates :name, presence: true
8
8
  validates :csv_data, presence: true
9
+ validate :csv_data_within_size_limit
10
+
11
+ def csv_data_within_size_limit
12
+ return if csv_data.blank?
13
+ return if csv_data.bytesize <= CompletionKit.config.max_upload_bytes
14
+
15
+ errors.add(:csv_data, "is too large (limit #{CompletionKit.config.max_upload_bytes / (1024 * 1024)} MB)")
16
+ end
9
17
 
10
18
  def as_json(options = {})
11
19
  {
@@ -19,9 +27,13 @@ module CompletionKit
19
27
  return 0 if csv_data.blank?
20
28
 
21
29
  require "csv"
22
- ::CSV.parse(csv_data, headers: true).length
23
- rescue ::CSV::MalformedCSVError
24
- 0
30
+ @row_count ||= begin
31
+ count = 0
32
+ ::CSV.new(csv_data, headers: true).each { count += 1 }
33
+ count
34
+ rescue ::CSV::MalformedCSVError
35
+ 0
36
+ end
25
37
  end
26
38
 
27
39
  def headers
@@ -116,16 +116,19 @@ module CompletionKit
116
116
  end
117
117
  end
118
118
 
119
+ def reviews_for_summary
120
+ @reviews_for_summary ||= Review.where(response_id: responses.select(:id)).to_a
121
+ end
122
+
119
123
  def avg_score
120
- all_reviews = responses.flat_map(&:reviews)
121
- scores = all_reviews.map(&:ai_score).compact.map(&:to_f)
124
+ scores = reviews_for_summary.map(&:ai_score).compact.map(&:to_f)
122
125
  return nil if scores.empty?
123
126
 
124
127
  (scores.sum / scores.length).round(2)
125
128
  end
126
129
 
127
130
  def metric_averages
128
- responses.flat_map(&:reviews).group_by(&:metric_name).filter_map do |name, reviews|
131
+ reviews_for_summary.group_by(&:metric_name).filter_map do |name, reviews|
129
132
  scored = reviews.select { |r| r.ai_score.present? }
130
133
  if scored.any?
131
134
  scores = scored.map { |r| r.ai_score.to_f }
@@ -141,7 +144,7 @@ module CompletionKit
141
144
  end
142
145
 
143
146
  def check_pass_rate
144
- resolved = responses.flat_map(&:reviews).reject { |r| r.passed.nil? }
147
+ resolved = reviews_for_summary.reject { |r| r.passed.nil? }
145
148
  return nil if resolved.empty?
146
149
 
147
150
  passed = resolved.count { |r| r.passed == true }
@@ -16,6 +16,10 @@ module CompletionKit
16
16
  end
17
17
 
18
18
  def call
19
+ if @content.bytesize > CompletionKit.config.max_upload_bytes
20
+ return failure("The import is too large. The limit is #{CompletionKit.config.max_upload_bytes / (1024 * 1024)} MB.")
21
+ end
22
+
19
23
  config = parse
20
24
  return failure("Could not parse YAML: #{@parse_error}") if config.nil?
21
25
  return failure("Top-level YAML must be a mapping of promptfoo config keys.") unless config.is_a?(Hash)
@@ -34,7 +38,7 @@ module CompletionKit
34
38
  private
35
39
 
36
40
  def parse
37
- YAML.safe_load(@content, aliases: true)
41
+ YAML.safe_load(@content)
38
42
  rescue Psych::Exception => e
39
43
  @parse_error = e.message
40
44
  nil
@@ -14,10 +14,6 @@
14
14
  </div>
15
15
  <% end %>
16
16
 
17
- <% if @run.dataset %>
18
- <% dataset_lines = @run.dataset.csv_data.to_s.lines %>
19
- <% dataset_preview_lines = dataset_lines.first(50) %>
20
- <% end %>
21
17
 
22
18
  <% if CompletionKit.config.judge_agreement_enabled %>
23
19
  <% stale_summary = @run.stale_review_summary %>
@@ -130,16 +126,22 @@
130
126
  <div class="ck-modal__body">
131
127
  <%
132
128
  require "csv"
133
- parsed_rows = []
134
129
  parse_error = nil
130
+ headers = []
131
+ body_rows = []
132
+ remaining = 0
135
133
  begin
136
- parsed_rows = ::CSV.parse(@run.dataset.csv_data.to_s)
134
+ reader = ::CSV.new(@run.dataset.csv_data.to_s)
135
+ headers = reader.shift || []
136
+ 50.times do
137
+ row = reader.shift
138
+ break unless row
139
+ body_rows << row
140
+ end
141
+ remaining = [@run.dataset.row_count - body_rows.length, 0].max
137
142
  rescue ::CSV::MalformedCSVError => e
138
143
  parse_error = e.message
139
144
  end
140
- headers = parsed_rows.first || []
141
- body_rows = parsed_rows.drop(1).first(50)
142
- remaining = parsed_rows.drop(1).count - body_rows.count
143
145
  %>
144
146
  <% if parse_error %>
145
147
  <p class="ck-field-hint" style="color: var(--ck-warning); padding: 1rem;">Could not parse CSV: <%= parse_error %></p>
@@ -1,3 +1,3 @@
1
1
  module CompletionKit
2
- VERSION = "0.28.10"
2
+ VERSION = "0.28.12"
3
3
  end
@@ -11,7 +11,7 @@ module CompletionKit
11
11
  attr_accessor :tenant_scope, :tenant_scope_columns
12
12
  attr_accessor :api_reference_authentication_partial
13
13
  attr_accessor :runs_display_scope, :runs_display_footer_partial
14
- attr_accessor :api_rate_limit, :web_rate_limit
14
+ attr_accessor :api_rate_limit, :web_rate_limit, :max_upload_bytes
15
15
  attr_accessor :allow_loopback_endpoints
16
16
  attr_accessor :judge_agreement_enabled
17
17
  attr_accessor :judge_examples_from_reviews
@@ -30,6 +30,7 @@ module CompletionKit
30
30
 
31
31
  @api_rate_limit = 120
32
32
  @web_rate_limit = 300
33
+ @max_upload_bytes = 25 * 1024 * 1024
33
34
 
34
35
  @allow_loopback_endpoints = true
35
36
  @judge_agreement_enabled = true
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: completion-kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.28.10
4
+ version: 0.28.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Damien Bastin