glim_ai 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.
- checksums.yaml +7 -0
- data/Gemfile +25 -0
- data/Gemfile.lock +49 -0
- data/LICENSE.txt +21 -0
- data/README.md +125 -0
- data/Rakefile +31 -0
- data/examples/autocode/autocode.rb +166 -0
- data/examples/autocode/solargraph_test.rb +59 -0
- data/examples/autocode/templates/changed_files_now_evaluate_output.erb +29 -0
- data/examples/autocode/templates/task.erb +16 -0
- data/examples/calc/calc.rb +50 -0
- data/examples/code_competition/code_competition.rb +78 -0
- data/examples/code_competition/output/python_claude-2.rb +33 -0
- data/examples/code_competition/output/python_claude-instant-1.rb +18 -0
- data/examples/code_competition/output/python_gpt-3.5-turbo-16k.rb +69 -0
- data/examples/code_competition/output/python_gpt-3.5-turbo.rb +43 -0
- data/examples/code_competition/output/python_gpt-4.rb +34 -0
- data/examples/code_competition/output/ruby_claude-2.rb +22 -0
- data/examples/code_competition/output/ruby_claude-instant-1.rb +20 -0
- data/examples/code_competition/output/ruby_gpt-3.5-turbo-16k.rb +27 -0
- data/examples/code_competition/output/ruby_gpt-3.5-turbo.rb +30 -0
- data/examples/code_competition/output/ruby_gpt-4.rb +31 -0
- data/examples/code_competition/output/ruby_human.rb +41 -0
- data/examples/code_competition/templates/analyze_code.erb +33 -0
- data/examples/code_competition/templates/write_code.erb +26 -0
- data/examples/glim_demo/ask_all.rb +35 -0
- data/examples/glim_demo/templates/rate_all.erb +24 -0
- data/examples/improve_prompt/improve_prompt.rb +62 -0
- data/examples/improve_prompt/templates/stashed/prompt_attempt_explicit_steps.erb +15 -0
- data/examples/improve_prompt/templates/stashed/prompt_attempt_explicit_steps_user_message.erb +15 -0
- data/examples/improve_prompt/templates/stashed/prompt_attempt_initial.erb +8 -0
- data/examples/improve_prompt/templates/stashed/prompt_attempt_nothing.erb +19 -0
- data/examples/improve_prompt/templates/try_code_first.erb +13 -0
- data/examples/improve_prompt/templates/try_code_first_system.erb +22 -0
- data/examples/old/econ/discounting.rb +27 -0
- data/examples/old/econ/templates/discounting.erb +10 -0
- data/examples/old/generate_glim_code/generate_glim_code.rb +34 -0
- data/examples/old/generate_glim_code/templates/generate_glim_code.erb +17 -0
- data/examples/old/generate_glim_code/templates/improve_code.erb +27 -0
- data/examples/old/glim_dev_tools/ask_code_question.rb +38 -0
- data/examples/old/glim_dev_tools/templates/ask_code_question.erb +12 -0
- data/examples/old/glim_dev_tools/templates/write_globals_test.erb +28 -0
- data/examples/old/glim_dev_tools/write_globals_test.rb +20 -0
- data/examples/old/linguistics/nine.rb +0 -0
- data/examples/old/rewrite_code/input/hello.py +1 -0
- data/examples/old/rewrite_code/input/subdir/hello.py +1 -0
- data/examples/old/rewrite_code/input/world.py +1 -0
- data/examples/old/rewrite_code/rewrite_code.rb +18 -0
- data/examples/old/rewrite_code/templates/rewrite_code.erb +32 -0
- data/examples/window_check/data.rb +1260 -0
- data/examples/window_check/fruits.rb +118 -0
- data/examples/window_check/tools.rb +56 -0
- data/examples/window_check/window_check.rb +214 -0
- data/glim_generated_tests/make_special_code_with_fixed_length_test.rb +44 -0
- data/glim_generated_tests/old-20230831120513-make_special_code_with_fixed_length_test.rb +1 -0
- data/glim_generated_tests/old-20230831121222-make_special_code_with_fixed_length_test.rb +55 -0
- data/glim_generated_tests/old-20230831124501-make_special_code_with_fixed_length_test.rb +33 -0
- data/glim_generated_tests/test/make_special_code_with_fixed_length_test.rb +58 -0
- data/lib/anthropic_request_details.rb +37 -0
- data/lib/anthropic_response.rb +101 -0
- data/lib/chat_request_details.rb +140 -0
- data/lib/chat_response.rb +303 -0
- data/lib/glim_ai/version.rb +5 -0
- data/lib/glim_ai.rb +8 -0
- data/lib/glim_ai_callable.rb +151 -0
- data/lib/glim_context.rb +62 -0
- data/lib/glim_helpers.rb +54 -0
- data/lib/glim_request.rb +266 -0
- data/lib/glim_response.rb +155 -0
- data/lib/globals.rb +255 -0
- data/lib/html_templates/chat_request.erb +86 -0
- data/sample.env +9 -0
- metadata +131 -0
@@ -0,0 +1,118 @@
|
|
1
|
+
require_relative '../../lib/globals'
|
2
|
+
require_relative 'data'
|
3
|
+
|
4
|
+
glim = GlimContext.new(log_name: "ask_all")
|
5
|
+
|
6
|
+
# Given item_count items, get a list of indices into data
|
7
|
+
# that are equidistant and include 0 and item_count-1
|
8
|
+
def select_data_point_indices(data_point_count, item_count)
|
9
|
+
delta = item_count / (data_point_count - 1.0)
|
10
|
+
indices = []
|
11
|
+
for i in 0..(data_point_count - 2)
|
12
|
+
indices << (i * delta).round
|
13
|
+
end
|
14
|
+
indices << (item_count - 1)
|
15
|
+
end
|
16
|
+
|
17
|
+
def extract_between_markers(str, start_marker, end_marker)
|
18
|
+
str[/#{Regexp.escape(start_marker)}(.*?)#{Regexp.escape(end_marker)}/m, 1]
|
19
|
+
end
|
20
|
+
|
21
|
+
#models = ["claude-instant-1", "gpt-3.5-turbo"]
|
22
|
+
#models = ["claude-instant-1"] # , "gpt-3.5-turbo"]
|
23
|
+
# models = ["gpt-4"]
|
24
|
+
|
25
|
+
models = ["gpt-3.5-turbo"]
|
26
|
+
|
27
|
+
models = ["meta-llama/Llama-2-70b-chat-hf"] # 7,13,70 all 4k
|
28
|
+
|
29
|
+
models = ["codellama/CodeLlama-34b-Instruct-hf"]
|
30
|
+
|
31
|
+
# models = ["claude-instant-1"]
|
32
|
+
|
33
|
+
|
34
|
+
srand 0
|
35
|
+
|
36
|
+
names = raw_names
|
37
|
+
fruits = raw_fruits
|
38
|
+
|
39
|
+
puts "We have #{names.length} names and #{fruits.length} fruits."
|
40
|
+
|
41
|
+
fruit_counts = [] # name_index -> fruit -> count
|
42
|
+
sentences = []
|
43
|
+
|
44
|
+
index_for_name = {}
|
45
|
+
|
46
|
+
names.each_with_index do |name, i|
|
47
|
+
index_for_name[name] = i
|
48
|
+
my_fruits = fruits.sample(10)
|
49
|
+
for mf in my_fruits
|
50
|
+
count = rand(1000000) + 2
|
51
|
+
fruit_counts[i] ||= {}
|
52
|
+
fruit_counts[i][mf] = count
|
53
|
+
end
|
54
|
+
s = "#{name} has: "
|
55
|
+
s << my_fruits[0..-2].map { |fruit| "#{fruit_counts[i][fruit]} #{fruit}" }.join(", ")
|
56
|
+
s << ", and 42 #{my_fruits[0]}.\n"
|
57
|
+
sentences [i] = s
|
58
|
+
end
|
59
|
+
|
60
|
+
question1 = "\n\n\n\nHow many of each fruit did "
|
61
|
+
question2 = " have? Respond with a json that maps names to a dictionary with number of each fruit they had."
|
62
|
+
|
63
|
+
data_point_count = 8
|
64
|
+
|
65
|
+
for model in models
|
66
|
+
request = glim.request(model:)
|
67
|
+
|
68
|
+
request.prompt = question1 + question2
|
69
|
+
question_length = request.prompt_token_count
|
70
|
+
reserve = question_length + 100 * data_point_count
|
71
|
+
|
72
|
+
p = ""
|
73
|
+
sentence_count = 0
|
74
|
+
for sentence in sentences
|
75
|
+
request.prompt = p + sentence
|
76
|
+
if (request.prompt_token_count + reserve) > request.context_length
|
77
|
+
break
|
78
|
+
end
|
79
|
+
p += sentence
|
80
|
+
sentence_count += 1
|
81
|
+
end
|
82
|
+
|
83
|
+
# get relatively evenly spaced data points
|
84
|
+
indices = select_data_point_indices(data_point_count, sentence_count)
|
85
|
+
puts "Data point indices: #{indices.inspect}"
|
86
|
+
|
87
|
+
name_list = indices[0..-2].map { |i| names[i] }.join(", ")
|
88
|
+
name_list += ", and #{names[indices.last]}"
|
89
|
+
request.prompt = p + question1 + name_list + question2
|
90
|
+
|
91
|
+
request.prepare!
|
92
|
+
puts "Ready to send to API. Cost will be at least $ #{request.min_cost}"
|
93
|
+
puts "Tokens: #{request.prompt_token_count}"
|
94
|
+
|
95
|
+
response = request.response
|
96
|
+
r = response.completion
|
97
|
+
puts "\n\nResponse from #{model}: \n#{r}"
|
98
|
+
# r = extract_between_markers(r, "```json","```")
|
99
|
+
puts "\n\JSON from #{model}: \n#{r}"
|
100
|
+
|
101
|
+
all_counts = JSON.parse(r)
|
102
|
+
scores = []
|
103
|
+
for name in all_counts.keys
|
104
|
+
# name = my_counts["name"]
|
105
|
+
my_counts = all_counts[name]
|
106
|
+
index = index_for_name[name]
|
107
|
+
ground_truth = fruit_counts[index]
|
108
|
+
score = 0
|
109
|
+
ground_truth.each_pair do |k, v|
|
110
|
+
if my_counts[k] == v
|
111
|
+
score += 1
|
112
|
+
end
|
113
|
+
end
|
114
|
+
scores << score
|
115
|
+
end
|
116
|
+
puts "#{model}: score = #{scores}"
|
117
|
+
|
118
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
# Given item_count items, get a list of indices into data
|
3
|
+
# that are equidistant and include 0 and item_count-1
|
4
|
+
def select_data_point_indices(data_point_count, item_count)
|
5
|
+
delta = item_count / (data_point_count - 1.0)
|
6
|
+
indices = []
|
7
|
+
for i in 0..(data_point_count - 2)
|
8
|
+
indices << (i * delta).round
|
9
|
+
end
|
10
|
+
indices << (item_count - 1)
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
def make_code(length)
|
16
|
+
chars = ([*('0'..'9'), *('a'..'z')])
|
17
|
+
(Array.new(length) { chars.sample }).join
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
# if false
|
22
|
+
# pos = rand(len-1)
|
23
|
+
# t = s[pos]
|
24
|
+
# s[pos] = s[pos+1]
|
25
|
+
# s[pos+1] = t
|
26
|
+
# end
|
27
|
+
|
28
|
+
# this generates a string of length len that will be
|
29
|
+
# a repeating sequence of an extended alphabet, but with
|
30
|
+
# deletions chars missing in random locations.
|
31
|
+
# the length will always be the same, but the levenshtein distance
|
32
|
+
# can be up to 2*deletions + 2*flips. Of course it can be less,
|
33
|
+
# if somehow some of these edits simplify or cancel out.
|
34
|
+
# safest to use only deletions or only flips, not both.
|
35
|
+
def make_special_code_with_fixed_length(len, deletions: 0, flips: 0)
|
36
|
+
raise ArgumentError.new("len must be > 0") unless len > 0
|
37
|
+
raise ArgumentError.new("deletions must be >= 0") unless deletions >= 0
|
38
|
+
raise ArgumentError.new("flips must be >= 0") unless flips >= 0
|
39
|
+
raise ArgumentError.new("deletions + flips must be <= len") unless deletions + flips <= len
|
40
|
+
|
41
|
+
alphabet = ((0..9).to_a + ("a".."z").to_a + ("A".."Z").to_a).join
|
42
|
+
count = (len+deletions+10)/alphabet.length+1
|
43
|
+
s = alphabet * count
|
44
|
+
deletions.times do
|
45
|
+
pos = rand(len-3)
|
46
|
+
s[pos] = ""
|
47
|
+
end
|
48
|
+
flips.times do
|
49
|
+
pos = 2+rand(len-5)
|
50
|
+
t = s[pos]
|
51
|
+
s[pos] = s[pos+1]
|
52
|
+
s[pos+1] = t
|
53
|
+
end
|
54
|
+
s = s[0..len-1]
|
55
|
+
return s
|
56
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
require_relative '../../lib/globals'
|
2
|
+
require_relative 'data'
|
3
|
+
require_relative 'tools'
|
4
|
+
|
5
|
+
glim = GlimContext.new(log_name: "ask_all")
|
6
|
+
|
7
|
+
# llm_name = "gpt-3.5-turbo"
|
8
|
+
# llm_name = "claude-instant-1"
|
9
|
+
|
10
|
+
llm_scores = []
|
11
|
+
|
12
|
+
data_point_count = 20
|
13
|
+
row_count = 18
|
14
|
+
|
15
|
+
for run in 0..100
|
16
|
+
puts "run = #{run}"
|
17
|
+
llm_scores[run] = {}
|
18
|
+
|
19
|
+
for llm_name in GlimRequest.llama2_llms[1..1]
|
20
|
+
puts "llm_name = #{llm_name}"
|
21
|
+
|
22
|
+
srand run+2000
|
23
|
+
|
24
|
+
names = raw_names
|
25
|
+
sentences = []
|
26
|
+
index_for_name = {}
|
27
|
+
codes = []
|
28
|
+
|
29
|
+
code_length = 100
|
30
|
+
|
31
|
+
names.each_with_index do |name, i|
|
32
|
+
index_for_name[name] = i
|
33
|
+
if i % 2 == 0
|
34
|
+
code = make_special_code_with_fixed_length(code_length,flips: 2)
|
35
|
+
else
|
36
|
+
code = make_code(code_length)
|
37
|
+
end
|
38
|
+
codes[i] = code
|
39
|
+
sentences[i] = "#{name}'s code: #{code}\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
instructions = "\n\nGenerate a json that maps each name to its code."
|
43
|
+
|
44
|
+
answer_line = " \"#{names[1]}\": \"#{codes[1]}\",\n"
|
45
|
+
|
46
|
+
request = glim.request(llm_name:, max_tokens: 4000)
|
47
|
+
|
48
|
+
long_code = make_code(10000)
|
49
|
+
token_length = long_code.length/request.count_tokens(long_code).to_f
|
50
|
+
puts "1 token is on average #{token_length} chars long."
|
51
|
+
|
52
|
+
# estimate how many rows will fit into the context window, including response
|
53
|
+
instructions_length = request.count_tokens(instructions)
|
54
|
+
answer_line_length = request.count_tokens(answer_line)
|
55
|
+
sentence_length = request.count_tokens(sentences[0])
|
56
|
+
max_row_count = ((request.context_length - instructions_length - 80) / (sentence_length + answer_line_length + 10)) - 1
|
57
|
+
|
58
|
+
puts "row_count = #{row_count} < max_row_count = #{max_row_count}"
|
59
|
+
|
60
|
+
data = sentences[0..row_count-1].join
|
61
|
+
request.prompt = data + instructions
|
62
|
+
|
63
|
+
puts "Prompt:\n#{request.prompt}"
|
64
|
+
|
65
|
+
answer_length = answer_line_length * row_count
|
66
|
+
data_length = request.count_tokens(data)
|
67
|
+
puts "Instructions: #{instructions_length} tokens"
|
68
|
+
puts "Each sentence: roughly #{sentence_length} tokens, #{data_length} in total"
|
69
|
+
puts "Each answer line: #{answer_line_length} tokens, #{answer_length} in total"
|
70
|
+
puts "Estimated total: #{instructions_length + answer_length + data_length} tokens"
|
71
|
+
|
72
|
+
puts "Ready to send #{request.prompt_token_count} tokens to API. Cost will be at least $ #{request.min_cost}"
|
73
|
+
|
74
|
+
response = request.response
|
75
|
+
r = response.completion.strip
|
76
|
+
#puts "\n\nResponse from #{model}: \n#{r}"
|
77
|
+
|
78
|
+
begin
|
79
|
+
result = extract_json(r)
|
80
|
+
rescue
|
81
|
+
puts "ERROR "*10
|
82
|
+
puts "Failed to parse JSON:"
|
83
|
+
puts r
|
84
|
+
next
|
85
|
+
end
|
86
|
+
scores = []
|
87
|
+
result.each_pair do |name, v|
|
88
|
+
index = index_for_name[name]
|
89
|
+
distance, explanation = levenshtein_distance(codes[index],v)
|
90
|
+
scores[index] = (code_length - distance) / code_length.to_f
|
91
|
+
puts explanation
|
92
|
+
end
|
93
|
+
puts "#{llm_name}: run = #{run}, scores = #{scores}"
|
94
|
+
llm_scores[run][llm_name] = scores
|
95
|
+
end
|
96
|
+
puts JSON.pretty_generate(llm_scores)
|
97
|
+
|
98
|
+
clean_llm_scores = []
|
99
|
+
for i in 0..llm_scores.length-1
|
100
|
+
if llm_scores[i]["meta-llama/Llama-2-13b-chat-hf"].length == row_count
|
101
|
+
clean_llm_scores << llm_scores[i]
|
102
|
+
else
|
103
|
+
puts "Skipping #{i}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
sums = []
|
108
|
+
for i in 0..row_count-1
|
109
|
+
sums[i] = clean_llm_scores.map { |x| x["meta-llama/Llama-2-13b-chat-hf"][i] }.count { |x| x >= 0.999 }
|
110
|
+
end
|
111
|
+
|
112
|
+
puts sums.inspect
|
113
|
+
|
114
|
+
|
115
|
+
# sums = llm_scores[0]["meta-llama/Llama-2-13b-chat-hf"].map { |x| (x >= 0.999) ? 1 : 0 }
|
116
|
+
|
117
|
+
# raise "sums.length = #{sums.length}" unless sums.length == row_count
|
118
|
+
# for runscores in llm_scores[1..-1]
|
119
|
+
# runscores13b = runscores["meta-llama/Llama-2-13b-chat-hf"]
|
120
|
+
# raise "runscores13b.length = #{runscores13b.length}" unless runscores13b.length == row_count
|
121
|
+
# sums = sums.zip(runscores13b).map do |a,b|
|
122
|
+
# (b >= 0.999) ? a : a+1
|
123
|
+
# end
|
124
|
+
# puts sums.inspect
|
125
|
+
|
126
|
+
# end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
|
132
|
+
|
133
|
+
# Instructions: 12 tokens
|
134
|
+
# Each sentence: roughly 83 tokens, 1646 in total
|
135
|
+
# Each answer line: 83 tokens, 1660 in total
|
136
|
+
# Estimated total: 3318 tokens
|
137
|
+
# 0.237: Tiktoken doesn't know model meta-llama/Llama-2-70b-chat-hf
|
138
|
+
# 0.237: Tiktoken doesn't know model meta-llama/Llama-2-70b-chat-hf
|
139
|
+
# Ready to send 1657 tokens to API. Cost will be at least $ 0.0016569999999999998
|
140
|
+
# meta-llama/Llama-2-70b-chat-hf: scores = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
|
141
|
+
# {
|
142
|
+
# "meta-llama/Llama-2-7b-chat-hf": [
|
143
|
+
# 1.0,
|
144
|
+
# 1.0,
|
145
|
+
# 0.8083333333333333,
|
146
|
+
# 0.9916666666666667,
|
147
|
+
# 0.7583333333333333,
|
148
|
+
# 0.9916666666666667,
|
149
|
+
# 0.5416666666666666,
|
150
|
+
# 0.9083333333333333,
|
151
|
+
# 0.7666666666666667,
|
152
|
+
# 0.30833333333333335,
|
153
|
+
# 0.7083333333333334,
|
154
|
+
# 0.75,
|
155
|
+
# 0.8166666666666667,
|
156
|
+
# 0.75,
|
157
|
+
# 0.825,
|
158
|
+
# 0.75,
|
159
|
+
# 0.7916666666666666
|
160
|
+
# ],
|
161
|
+
# "meta-llama/Llama-2-13b-chat-hf": [
|
162
|
+
# 1.0,
|
163
|
+
# 1.0,
|
164
|
+
# 1.0,
|
165
|
+
# 1.0,
|
166
|
+
# 1.0,
|
167
|
+
# 1.0,
|
168
|
+
# 1.0,
|
169
|
+
# 1.0,
|
170
|
+
# 1.0,
|
171
|
+
# 1.0,
|
172
|
+
# 1.0,
|
173
|
+
# 1.0,
|
174
|
+
# 1.0,
|
175
|
+
# 1.0,
|
176
|
+
# 1.0,
|
177
|
+
# 1.0,
|
178
|
+
# 1.0,
|
179
|
+
# 1.0
|
180
|
+
# ],
|
181
|
+
# "meta-llama/Llama-2-70b-chat-hf": [
|
182
|
+
# 1.0,
|
183
|
+
# 1.0,
|
184
|
+
# 1.0,
|
185
|
+
# 1.0,
|
186
|
+
# 1.0,
|
187
|
+
# 1.0,
|
188
|
+
# 1.0,
|
189
|
+
# 1.0,
|
190
|
+
# 1.0,
|
191
|
+
# 1.0,
|
192
|
+
# 1.0,
|
193
|
+
# 1.0,
|
194
|
+
# 1.0,
|
195
|
+
# 1.0,
|
196
|
+
# 1.0,
|
197
|
+
# 1.0,
|
198
|
+
# 1.0,
|
199
|
+
# 1.0,
|
200
|
+
# 1.0,
|
201
|
+
# 1.0
|
202
|
+
# ]
|
203
|
+
# }
|
204
|
+
|
205
|
+
# 13b / 20
|
206
|
+
# [38.920000000000016, 41.0, 40.82000000000001, 41.0, 40.839999999999996, 40.980000000000004, 40.809999999999995, 41.0, 40.84, 40.989999999999995, 40.72, 41.0, 40.77, 40.99, 40.88, 40.99, 40.55, 40.98, 40.76]
|
207
|
+
|
208
|
+
|
209
|
+
# srand 1000+
|
210
|
+
# [96.21999999999993, 100.99, 100.78, 100.99, 100.65999999999998, 101.0, 100.72, 101.0, 100.64, 100.98, 100.72999999999999, 100.97999999999999, 100.78, 100.99000000000001, 100.74000000000001, 100.99000000000001, 100.6, 100.99000000000001]
|
211
|
+
|
212
|
+
# srand 1000+
|
213
|
+
# counting pnly
|
214
|
+
# [35, 100, 91, 100, 87, 101, 87, 101, 88, 99, 90, 99, 92, 100, 89, 100, 83, 100]
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# File: make_special_code_with_fixed_length_test.rb
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require_relative '../lib/globals'
|
4
|
+
|
5
|
+
class MakeSpecialCodeWithFixedLengthTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@base = "0123456789" + ("a".."z").to_a.join + ("A".."Z").to_a.join
|
8
|
+
@base_len = @base.length
|
9
|
+
@len = 100
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_basic_function
|
13
|
+
test_string = make_special_code_with_fixed_length(@len, deletions: 0, flips: 0)
|
14
|
+
# Length should be @len
|
15
|
+
assert_equal @len, test_string.length
|
16
|
+
# There should be no randomness introduced
|
17
|
+
assert_equal @base[0...@len], test_string
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_deletions
|
21
|
+
test_string = make_special_code_with_fixed_length(@len, deletions: 10, flips: 0)
|
22
|
+
assert_equal @len, test_string.length
|
23
|
+
# Deletion is random, but levenshtein distance should be 10
|
24
|
+
assert_equal 10, levenshtein_distance(@base[0...@len], test_string).first
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_flips
|
28
|
+
test_string = make_special_code_with_fixed_length(@len, deletions: 0, flips: 10)
|
29
|
+
assert_equal @len, test_string.length
|
30
|
+
# Flips is random, but levenshtein distance should be 20
|
31
|
+
assert_equal 20, levenshtein_distance(@base[0...@len], test_string).first
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_argument_errors
|
35
|
+
# Raises error for non positive length
|
36
|
+
assert_raises(ArgumentError) { make_special_code_with_fixed_length(0, deletions: 0, flips: 0) }
|
37
|
+
assert_raises(ArgumentError) { make_special_code_with_fixed_length(-10, deletions: 0, flips: 0) }
|
38
|
+
# Raises error for negative deletions and flips
|
39
|
+
assert_raises(ArgumentError) { make_special_code_with_fixed_length(@len, deletions: -1, flips: 0) }
|
40
|
+
assert_raises(ArgumentError) { make_special_code_with_fixed_length(@len, deletions: 0, flips: -10) }
|
41
|
+
# Raises error if deletions + flips > len
|
42
|
+
assert_raises(ArgumentError) { make_special_code_with_fixed_length(@len, deletions: 50, flips: 60) }
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# File: make_special_code_with_fixed_length_test.rb
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# File: make_special_code_with_fixed_length_test.rb
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require_relative "../lib/globals"
|
4
|
+
|
5
|
+
class MakeSpecialCodeWithFixedLengthTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@alphabet = ((0..9).to_a + ("a".."z").to_a + ("A".."Z").to_a).join
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_normal_case
|
11
|
+
result = make_special_code_with_fixed_length(15, 2)
|
12
|
+
assert_kind_of String, result
|
13
|
+
assert_equal 15, result.length
|
14
|
+
assert_equal 2, @alphabet.length*5 - levenshtein_distance(@alphabet*5, result)[0]
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_zero_deletions
|
18
|
+
result = make_special_code_with_fixed_length(15, 0)
|
19
|
+
assert_kind_of String, result
|
20
|
+
assert_equal 15, result.length
|
21
|
+
assert_equal 0, @alphabet.length*5 - levenshtein_distance(@alphabet*5, result)[0]
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_string_has_more_than_requested_length
|
25
|
+
result = make_special_code_with_fixed_length(50, 2)
|
26
|
+
assert_kind_of String, result
|
27
|
+
assert_equal 50, result.length
|
28
|
+
assert_equal 2, @alphabet.length*2 - levenshtein_distance(@alphabet*2, result)[0]
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_zero_length
|
32
|
+
result = make_special_code_with_fixed_length(0, 2)
|
33
|
+
assert_kind_of String, result
|
34
|
+
assert_equal 0, result.length
|
35
|
+
assert_equal 2, @alphabet.length*5 - levenshtein_distance(@alphabet*5, result)[0]
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_negative_length
|
39
|
+
assert_raises do
|
40
|
+
make_special_code_with_fixed_length(-1, 2)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_negative_deletions
|
45
|
+
assert_raises do
|
46
|
+
make_special_code_with_fixed_length(15, -1)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_length_less_than_deletions
|
51
|
+
assert_raises do
|
52
|
+
make_special_code_with_fixed_length(2, 15)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# File: make_special_code_with_fixed_length_test.rb
|
2
|
+
require_relative '../lib/globals'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
|
5
|
+
class TestMakeSpecialCodeWithFixedLength < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@len = 10
|
8
|
+
@deletions = 2
|
9
|
+
@test_string = make_special_code_with_fixed_length(@len, @deletions)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_length
|
13
|
+
assert_equal @len, @test_string.length, "Output string length does not match requested length."
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_levenshtein_distance
|
17
|
+
original_string = make_special_code_with_fixed_length(@len, 0)
|
18
|
+
expected_distance, _ = levenshtein_distance(original_string, @test_string)
|
19
|
+
assert_equal @deletions, expected_distance, "Levenshtein distance does not match the number of deletions."
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_negative_length
|
23
|
+
assert_raises { make_special_code_with_fixed_length(-1, @deletions) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_negative_deletions
|
27
|
+
assert_raises { make_special_code_with_fixed_length(@len, -1) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_deletion_greater_than_length
|
31
|
+
assert_raises { make_special_code_with_fixed_length(@len, @len + 1) }
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# File: test/make_special_code_with_fixed_length_test.rb
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require_relative '../lib/globals'
|
4
|
+
|
5
|
+
class TestMakeSpecialCodeWithFixedLength < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@len = 20
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_normal_case
|
11
|
+
code = make_special_code_with_fixed_length(@len, deletions: 2, flips: 3)
|
12
|
+
assert_equal @len, code.length, "Failed on test where code length != len"
|
13
|
+
orig_code = make_special_code_with_fixed_length(@len, deletions: 0, flips: 0)
|
14
|
+
distance, _ = levenshtein_distance(orig_code, code)
|
15
|
+
assert_equal 4, distance, "Failed on test where levenshtein distance != 2*deletions"
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_zero_len
|
19
|
+
code = make_special_code_with_fixed_length(0, deletions: 2, flips: 2)
|
20
|
+
assert_equal "", code, "Failed on test where len = 0"
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_large_len
|
24
|
+
@len = 1_000_000
|
25
|
+
code = make_special_code_with_fixed_length(@len, deletions: 2, flips: 2)
|
26
|
+
assert_equal @len, code.length, "Failed on test where len is very large"
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_negative_len
|
30
|
+
assert_raises(ArgumentError) do
|
31
|
+
make_special_code_with_fixed_length(-1, deletions: 2, flips: 2)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_negative_deletions
|
36
|
+
assert_raises(ArgumentError) do
|
37
|
+
make_special_code_with_fixed_length(@len, deletions: -2, flips: 2)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_negative_flips
|
42
|
+
assert_raises(ArgumentError) do
|
43
|
+
make_special_code_with_fixed_length(@len, deletions: 2, flips: -2)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_deletions_plus_flips_greater_than_len
|
48
|
+
assert_raises(ArgumentError) do
|
49
|
+
make_special_code_with_fixed_length(@len, deletions: @len + 1, flips: 1)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_fractional_len
|
54
|
+
assert_raises(ArgumentError) do
|
55
|
+
make_special_code_with_fixed_length(1.5, deletions: 2, flips: 2)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'tiktoken_ruby' # TODO only for token counting while anthropic doesn't support it
|
2
|
+
|
3
|
+
require 'anthropic'
|
4
|
+
#require_relative 'globals'
|
5
|
+
|
6
|
+
Anthropic.configure do |config|
|
7
|
+
config.access_token = ENV.fetch('ANTHROPIC_API_KEY')
|
8
|
+
config.request_timeout = 480 # Optional
|
9
|
+
end
|
10
|
+
|
11
|
+
# GlimRequest delegates to this
|
12
|
+
class AnthropicRequestDetails # only for requests that involve a message array, like OpenAI
|
13
|
+
|
14
|
+
def initialize(req)
|
15
|
+
@req = req
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_accessor :req
|
19
|
+
|
20
|
+
def response_class
|
21
|
+
AnthropicResponse
|
22
|
+
end
|
23
|
+
|
24
|
+
def llm_class_changed
|
25
|
+
update_request_hash
|
26
|
+
end
|
27
|
+
|
28
|
+
def update_request_hash
|
29
|
+
req.request_hash[:max_tokens_to_sample] = req.max_tokens || 2000
|
30
|
+
req.request_hash[:prompt] = req.prompt
|
31
|
+
req.request_hash[:temperature] = req.temperature
|
32
|
+
req.request_hash[:model] = req.llm_name
|
33
|
+
# deeply remove keys for any values that are nil
|
34
|
+
req.request_hash.delete_if { |k, v| v.nil? }
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|