activeai 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -0
- data/lib/activeai/behavior/llm/conversation.rb +1 -1
- data/lib/activeai/behavior/llm/follow_structured_examples.rb +3 -3
- data/lib/activeai/behavior/llm/write_function_call.rb +35 -0
- data/lib/activeai/behavior/llm.rb +3 -2
- data/lib/activeai/controller.rb +21 -8
- data/lib/activeai/router.rb +33 -17
- data/lib/activeai/version.rb +1 -1
- data/lib/activeai.rb +12 -0
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a327faafb1ed168dfbbfce2c3f5beed3b6090c8ed5c95d24913d988e39227143
|
4
|
+
data.tar.gz: f3bb5b04eabc7838193f099e649f5dbe48ae3f151537b28469d1b6738848fb00
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3530fdce13cab64414b9b921a49672cd2dae8c170e6f50af5486fe30b33055403a1ef37b6a8c2e3172178ff61ac8c4d26292a3708877111d329cecb0dc59a72
|
7
|
+
data.tar.gz: 9dc7550488f4dab988b11719a065f0e7fd0c17afa2712c6670b97e8300969fb9d218ac47e2939d295134e5313594f00f45e8838c34c5d9fb178237e3292adcce
|
data/README.md
CHANGED
@@ -39,6 +39,12 @@ puts result
|
|
39
39
|
#=> 'tomatoes, jam'
|
40
40
|
```
|
41
41
|
|
42
|
+
### Behavior: WriteFunctionCall
|
43
|
+
|
44
|
+
#### TODO
|
45
|
+
|
46
|
+
This lets you use `code-davinci-002` or `code-cushman-001` to run logic. The router uses this internally. Supply a list of example pairs that are a "description" and "code", and then you can complete another one.
|
47
|
+
|
42
48
|
### TODO: with other patterns
|
43
49
|
|
44
50
|
### TODO: auto-detected behavior pattern from config
|
@@ -20,7 +20,7 @@ class ActiveAI::Behavior::LLM::Conversation < ActiveAI::Behavior::LLM
|
|
20
20
|
# TODO use the label key they provide in the yml file
|
21
21
|
end,
|
22
22
|
"Conversation:\n" + @state['conversation']
|
23
|
-
].join(
|
23
|
+
].join(LINE_SEPARATOR)
|
24
24
|
end
|
25
25
|
|
26
26
|
def add(speaker, message)
|
@@ -15,12 +15,12 @@ class ActiveAI::Behavior::LLM::FollowStructuredExamples < ActiveAI::Behavior::LL
|
|
15
15
|
example.map do |key, value|
|
16
16
|
"#{key}: #{value}"
|
17
17
|
end.join("\n")
|
18
|
-
end.join(
|
19
|
-
].join(
|
18
|
+
end.join(LINE_SEPARATOR)
|
19
|
+
].join(LINE_SEPARATOR)
|
20
20
|
end
|
21
21
|
|
22
22
|
def call(input={}, extract: []) # TODO cool splat stuff?
|
23
|
-
prompt = base_prompt +
|
23
|
+
prompt = base_prompt + LINE_SEPARATOR
|
24
24
|
|
25
25
|
prompt += input.map do |key, value|
|
26
26
|
"#{key}: #{value}"
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class ActiveAI::Behavior::LLM::WriteFunctionCall < ActiveAI::Behavior::LLM
|
2
|
+
def initialize(llm, state)
|
3
|
+
super(llm)
|
4
|
+
@state = state
|
5
|
+
# TODO raise errors if not expected thingies available in the config
|
6
|
+
end
|
7
|
+
|
8
|
+
def base_prompt
|
9
|
+
@state[:examples].map do |example|
|
10
|
+
[
|
11
|
+
"// #{example[:description]}",
|
12
|
+
example[:code]
|
13
|
+
].join("\n")
|
14
|
+
end.join("\n\n") + "\n\n"
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(comment)
|
18
|
+
prompt = base_prompt + "\n\n"
|
19
|
+
prompt += "//#{comment}\n"
|
20
|
+
complete_result = complete(prompt, stop: "\n")
|
21
|
+
|
22
|
+
# TODO stop \n works for the router but not for other stuff, later
|
23
|
+
|
24
|
+
completion = complete_result['choices'][0]['text']
|
25
|
+
|
26
|
+
matcher = /(.*)\((.*)\)/
|
27
|
+
matches = matcher.match(completion)
|
28
|
+
|
29
|
+
return {
|
30
|
+
text: completion.strip,
|
31
|
+
path: matches[1],
|
32
|
+
params: matches[2].presence && JSON.parse(matches[2])
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
@@ -7,7 +7,7 @@ class ActiveAI::Behavior::LLM < ActiveAI::Behavior::Base
|
|
7
7
|
@llm.complete(prompt: prompt, stop: stop)
|
8
8
|
end
|
9
9
|
|
10
|
-
|
10
|
+
LINE_SEPARATOR = "\n\n###\n\n"
|
11
11
|
|
12
12
|
def extract_keys(completion, extract)
|
13
13
|
matcher_string = extract.map{ |key| "#{key}:(.*)" }.join
|
@@ -25,5 +25,6 @@ class ActiveAI::Behavior::LLM < ActiveAI::Behavior::Base
|
|
25
25
|
end
|
26
26
|
|
27
27
|
require_relative "llm/conversation"
|
28
|
-
require_relative "llm/unstructured"
|
29
28
|
require_relative "llm/follow_structured_examples"
|
29
|
+
require_relative "llm/unstructured"
|
30
|
+
require_relative "llm/write_function_call"
|
data/lib/activeai/controller.rb
CHANGED
@@ -9,20 +9,33 @@ class ActiveAI::Controller
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.load_routing(routes_config)
|
12
|
-
@llm = ActiveAI::NeuralNetwork::GPT3.new(ActiveAI.config[:gpt3_token], model: '
|
13
|
-
|
12
|
+
@llm = ActiveAI::NeuralNetwork::GPT3.new(ActiveAI.config[:gpt3_token], model: 'code-davinci-002', temperature: 0.2)
|
13
|
+
|
14
|
+
examples = ActiveAI.route_examples_to_function_call_examples(routes_config['examples'])
|
15
|
+
self.routing_behavior = ActiveAI::Behavior::LLM::WriteFunctionCall.new(@llm, { examples: examples })
|
14
16
|
end
|
15
17
|
|
16
18
|
attr_accessor :params
|
17
19
|
|
18
20
|
def prepare_action(request)
|
19
|
-
|
20
|
-
|
21
|
+
# samples to parse:
|
22
|
+
# plugins.slack.send_message({ \"channel\": \"#general\", \"text\": \"Hi\" })
|
23
|
+
# unmatched()
|
24
|
+
|
25
|
+
function = self.class.routing_behavior.call(request)
|
26
|
+
*controller_path, action_name = function[:path].split(".")
|
27
|
+
controller_name = controller_path.join("/").presence
|
28
|
+
|
21
29
|
# TODO verify it's the right controller and the action name exists and it's not a reserved / internal thing
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
30
|
+
|
31
|
+
if controller_name.present?
|
32
|
+
return {
|
33
|
+
action: action_name,
|
34
|
+
params: function[:params]
|
35
|
+
}
|
36
|
+
else
|
37
|
+
return nil
|
38
|
+
end
|
26
39
|
end
|
27
40
|
|
28
41
|
def call(request)
|
data/lib/activeai/router.rb
CHANGED
@@ -4,7 +4,7 @@ class ActiveAI::Router
|
|
4
4
|
|
5
5
|
def initialize
|
6
6
|
@routings = []
|
7
|
-
@llm = ActiveAI::NeuralNetwork::GPT3.new(ActiveAI.config[:gpt3_token], model: '
|
7
|
+
@llm = ActiveAI::NeuralNetwork::GPT3.new(ActiveAI.config[:gpt3_token], model: 'code-davinci-002', temperature: 0.2)
|
8
8
|
end
|
9
9
|
|
10
10
|
def add_controller_routing(routing)
|
@@ -24,26 +24,42 @@ class ActiveAI::Router
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def behavior
|
27
|
-
|
28
|
-
'
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
}
|
37
|
-
|
38
|
-
ActiveAI::Behavior::LLM::FollowStructuredExamples.new(@llm, config)
|
27
|
+
raw_examples = [UNMATCHED] + @routings.map do |routing|
|
28
|
+
routing['examples'].reject do |example|
|
29
|
+
example['Route'] == 'None'
|
30
|
+
end.map do |example|
|
31
|
+
example.slice('Match', 'Route')
|
32
|
+
end
|
33
|
+
end.flatten
|
34
|
+
examples = ActiveAI.route_examples_to_function_call_examples(raw_examples)
|
35
|
+
|
36
|
+
ActiveAI::Behavior::LLM::WriteFunctionCall.new(@llm, { examples: examples })
|
39
37
|
end
|
40
38
|
|
39
|
+
# def behavior_via_structured_examples
|
40
|
+
# config = {
|
41
|
+
# 'instruction' => INSTRUCTION,
|
42
|
+
# 'examples' => [UNMATCHED] + @routings.map do |routing|
|
43
|
+
# routing['examples'].reject do |example|
|
44
|
+
# example['Route'] == 'None'
|
45
|
+
# end.map do |example|
|
46
|
+
# example.slice('Match', 'Route')
|
47
|
+
# end
|
48
|
+
# end.flatten
|
49
|
+
# }
|
50
|
+
|
51
|
+
# ActiveAI::Behavior::LLM::FollowStructuredExamples.new(@llm, config)
|
52
|
+
# end
|
53
|
+
|
41
54
|
def find_controller(request)
|
42
|
-
# should return
|
43
|
-
routing = behavior.call({ 'Request' => request }, extract: %W[Route])
|
44
|
-
controller_name, action_name = routing['Route'].split('#')
|
55
|
+
function = behavior.call(request) # TODO maybe the behavior should return function and params as well. seems right
|
45
56
|
|
46
|
-
|
57
|
+
*controller_path, action_name = function[:path].split(".")
|
58
|
+
controller_name = controller_path.join("/").presence
|
59
|
+
|
60
|
+
# TODO verify it's the right controller and the action name exists and it's not a reserved / internal thing
|
61
|
+
|
62
|
+
if controller_name.blank? || action_name.blank? || action_name == 'unmatched'
|
47
63
|
return nil
|
48
64
|
else
|
49
65
|
return (controller_name + "_controller").classify.constantize
|
data/lib/activeai/version.rb
CHANGED
data/lib/activeai.rb
CHANGED
@@ -16,5 +16,17 @@ module ActiveAI
|
|
16
16
|
}
|
17
17
|
end
|
18
18
|
|
19
|
+
def self.route_examples_to_function_call_examples(examples)
|
20
|
+
examples.map do |example|
|
21
|
+
function = example['Route'].gsub('/','.').gsub('#','.')
|
22
|
+
function = "unmatched" if function == "None"
|
23
|
+
|
24
|
+
{
|
25
|
+
description: example['Match'],
|
26
|
+
code: "#{function}(#{example['Params']&.strip})"
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
19
31
|
end
|
20
32
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activeai
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jeriko
|
@@ -64,6 +64,7 @@ files:
|
|
64
64
|
- lib/activeai/behavior/llm/conversation.rb
|
65
65
|
- lib/activeai/behavior/llm/follow_structured_examples.rb
|
66
66
|
- lib/activeai/behavior/llm/unstructured.rb
|
67
|
+
- lib/activeai/behavior/llm/write_function_call.rb
|
67
68
|
- lib/activeai/configuration.rb
|
68
69
|
- lib/activeai/controller.rb
|
69
70
|
- lib/activeai/neural_network.rb
|