active_intelligence 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +50 -1
- data/app/models/active_intelligence/chat.rb +31 -0
- data/app/models/active_intelligence/chat_message.rb +12 -0
- data/app/models/concerns/active_intelligence/promptable.rb +6 -5
- data/app/services/active_intelligence/application_service.rb +13 -0
- data/app/services/active_intelligence/chat_repl_service.rb +73 -0
- data/config/initializers/inflections.rb +1 -0
- data/db/migrate/20240520181009_create_active_intelligence_chats.rb +8 -0
- data/db/migrate/20240520185221_create_active_intelligence_chat_messages.rb +10 -0
- data/lib/active_intelligence/asr/aws_adapter.rb +2 -1
- data/lib/active_intelligence/concerns/openai.rb +1 -0
- data/lib/active_intelligence/config.rb +2 -1
- data/lib/active_intelligence/llm/adapter.rb +4 -0
- data/lib/active_intelligence/llm/openai_adapter.rb +19 -2
- data/lib/active_intelligence/version.rb +1 -1
- data/lib/tasks/active_intelligence_tasks.rake +9 -4
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ca1684233da615710eb4627d5f5dd36de700412b55ab9d3bfc33f28ba1b19b6
|
4
|
+
data.tar.gz: b7916597e70b62d5c70af58df106fa881d678d96d378eaae44434c993f0c60d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 179e855f89af509ab9fd3860344df57cefde149b36fccdad3bf9b4d7cbc49f91f5486bcaf01c3f551a7e4e0c83d600ceeef6652951cf0ffcb22b8887d369d841
|
7
|
+
data.tar.gz: a933ec32b319a915ed17a9c1bb4266595fba0a538805046ee4ac98337a678bf6a7664e44472d5ed7a156f34db32f9cb0ca87856ab5035cca49fe59aa7dba4673
|
data/README.md
CHANGED
@@ -19,6 +19,11 @@ And then execute:
|
|
19
19
|
$ bundle
|
20
20
|
```
|
21
21
|
|
22
|
+
To install migrations:
|
23
|
+
```bash
|
24
|
+
rails active_intelligence:install:migrations
|
25
|
+
```
|
26
|
+
|
22
27
|
## LLM Usage
|
23
28
|
|
24
29
|
### 1. Configuration
|
@@ -32,7 +37,7 @@ openai: &openai
|
|
32
37
|
|
33
38
|
development:
|
34
39
|
<<: *openai
|
35
|
-
model: gpt-4-
|
40
|
+
model: gpt-4-turbo
|
36
41
|
temperature: 0.0
|
37
42
|
```
|
38
43
|
|
@@ -62,6 +67,50 @@ default_response = user.from_llm
|
|
62
67
|
invite_response = user.from_llm(:invite)
|
63
68
|
```
|
64
69
|
|
70
|
+
## Chat
|
71
|
+
|
72
|
+
|
73
|
+
```mermaid
|
74
|
+
erDiagram
|
75
|
+
Chat {
|
76
|
+
integer id
|
77
|
+
}
|
78
|
+
ChatMessage {
|
79
|
+
integer id
|
80
|
+
integer chat_id
|
81
|
+
string role
|
82
|
+
string content
|
83
|
+
}
|
84
|
+
Chat ||--o{ ChatMessage : has_many
|
85
|
+
```
|
86
|
+
|
87
|
+
### 6. Create a chat prompt
|
88
|
+
|
89
|
+
```
|
90
|
+
# app/prompts/active_intelligence/chat.erb
|
91
|
+
|
92
|
+
* Your name is Poe. You are a fan of Edgar Allan Poe.
|
93
|
+
* You are the AI propritor of the Raven Hotel.
|
94
|
+
* You exhibit the utmost sincerity and hostpitality.
|
95
|
+
```
|
96
|
+
|
97
|
+
### 7. Create a chat, add a message, and get a reply
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
include ActiveIntelligence
|
101
|
+
|
102
|
+
chat = Chat.create!
|
103
|
+
chat.messages.create!(role: 'user', content: "Hi! Who are you?")
|
104
|
+
puts chat.reply.content
|
105
|
+
````
|
106
|
+
|
107
|
+
### 8. Chat using the REPL
|
108
|
+
|
109
|
+
```
|
110
|
+
rake active_intelligence:chat
|
111
|
+
rake active_intelligence:chat[id]
|
112
|
+
```
|
113
|
+
|
65
114
|
## ASR Usage
|
66
115
|
|
67
116
|
### 1. Configuration
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveIntelligence
|
4
|
+
class Chat < ApplicationRecord
|
5
|
+
include Promptable
|
6
|
+
|
7
|
+
has_many :messages,
|
8
|
+
class_name: ActiveIntelligence::ChatMessage.to_s,
|
9
|
+
dependent: :destroy,
|
10
|
+
counter_cache: :messages_count
|
11
|
+
|
12
|
+
def as_json(options = {})
|
13
|
+
if options.empty?
|
14
|
+
options[:only] = %i[id created_at updated_at]
|
15
|
+
options[:methods] = %i[messages_count]
|
16
|
+
options[:include] = [messages: { only: %i[id role content created_at updated_at] }]
|
17
|
+
end
|
18
|
+
|
19
|
+
super(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def reply(options = {})
|
23
|
+
options = options.dup
|
24
|
+
llm = ActiveIntelligence::LLM::Config.new.adapter(options[:adapter])
|
25
|
+
prompt = options.delete(:prompt) || to_prompt(options.delete(:name))
|
26
|
+
|
27
|
+
reply = llm.reply(self, prompt, options)
|
28
|
+
return messages.create!(role: 'assistant', content: reply)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -5,16 +5,17 @@ module ActiveIntelligence
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
-
def from_llm(template = nil,
|
9
|
-
|
10
|
-
|
8
|
+
def from_llm(template = nil, options = {})
|
9
|
+
adapter = options[:adapter]
|
10
|
+
llm = ActiveIntelligence::LLM::Config.new.adapter(adapter)
|
11
|
+
return llm.generate(to_prompt(template, options))
|
11
12
|
end
|
12
13
|
|
13
|
-
def to_prompt(name = nil)
|
14
|
+
def to_prompt(name = nil, options = {})
|
14
15
|
template = self.class.name.pluralize.underscore
|
15
16
|
template = [template, name].join('/') if name
|
16
17
|
|
17
|
-
assigns = { self: self }
|
18
|
+
assigns = { self: self }.merge(options[:assigns] || {})
|
18
19
|
prompt = ActiveIntelligence::LLM::Prompt.new(template, assigns)
|
19
20
|
return prompt.render
|
20
21
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# SEE: https://www.toptal.com/ruby-on-rails/rails-service-objects-tutorial
|
4
|
+
|
5
|
+
module ActiveIntelligence
|
6
|
+
class ApplicationService
|
7
|
+
def self.call(*args, &block)
|
8
|
+
new(*args, &block).call
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(*_args, &_block); end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveIntelligence
|
4
|
+
class ChatREPLService < ApplicationService
|
5
|
+
# rubocop:disable Rails/Output
|
6
|
+
|
7
|
+
def initialize(chat)
|
8
|
+
super
|
9
|
+
|
10
|
+
@chat = chat
|
11
|
+
@counter = 1
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
header
|
16
|
+
help
|
17
|
+
history
|
18
|
+
loop { cycle || break }
|
19
|
+
end
|
20
|
+
|
21
|
+
def cycle
|
22
|
+
print prefix(:user)
|
23
|
+
input = $stdin.gets.chomp
|
24
|
+
case input
|
25
|
+
when 'h' then help
|
26
|
+
when 'p' then prompt
|
27
|
+
when 'q' then return false
|
28
|
+
else reply(input)
|
29
|
+
end
|
30
|
+
|
31
|
+
return true
|
32
|
+
end
|
33
|
+
|
34
|
+
def header
|
35
|
+
puts "Chat #{@chat.id}\n"
|
36
|
+
end
|
37
|
+
|
38
|
+
def help
|
39
|
+
puts <<~HELP
|
40
|
+
|
41
|
+
h - help
|
42
|
+
p - prompt
|
43
|
+
q - quit
|
44
|
+
HELP
|
45
|
+
end
|
46
|
+
|
47
|
+
def history
|
48
|
+
@chat.messages.order(:id).each do |message|
|
49
|
+
@counter += 1
|
50
|
+
puts [prefix(message.role), message.content].join
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def prefix(name)
|
55
|
+
"\n(#{name}:#{@counter})> "
|
56
|
+
end
|
57
|
+
|
58
|
+
def prompt
|
59
|
+
puts ["\n", @chat.to_prompt].join
|
60
|
+
end
|
61
|
+
|
62
|
+
def reply(input)
|
63
|
+
@chat.messages.create!(role: 'user', content: input)
|
64
|
+
|
65
|
+
@counter += 1
|
66
|
+
print prefix(:assistant)
|
67
|
+
puts @chat.reply.content
|
68
|
+
@counter += 1
|
69
|
+
end
|
70
|
+
|
71
|
+
# rubocop:enable Rails/Output
|
72
|
+
end
|
73
|
+
end
|
@@ -57,11 +57,12 @@ module ActiveIntelligence
|
|
57
57
|
|
58
58
|
def parameters(key, options)
|
59
59
|
now = Time.now.to_i
|
60
|
+
format = options.delete(:format) # TODO: This ain't good
|
60
61
|
|
61
62
|
parameters = {
|
62
63
|
transcription_job_name: "transcribe-#{now}",
|
63
64
|
language_code: settings[:language_code] || 'en-US',
|
64
|
-
media_format:
|
65
|
+
media_format: format || format(key),
|
65
66
|
media: { media_file_uri: s3_url(key) },
|
66
67
|
output_bucket_name: settings[:bucket],
|
67
68
|
output_key: s3_path("transcribe-#{now}.json")
|
@@ -7,13 +7,30 @@ module ActiveIntelligence
|
|
7
7
|
class OpenAIAdapter < Adapter
|
8
8
|
include ActiveIntelligence::Concerns::OpenAI
|
9
9
|
|
10
|
+
def chat(parameters)
|
11
|
+
response = client.chat(parameters:)
|
12
|
+
return response.dig('choices', 0, 'message', 'content')
|
13
|
+
end
|
14
|
+
|
10
15
|
def generate(prompt, _options = {})
|
11
16
|
parameters = default_parameters
|
12
17
|
parameters[:messages] = [{ role: 'user', content: prompt }]
|
13
18
|
|
14
|
-
|
19
|
+
return chat(parameters)
|
20
|
+
end
|
15
21
|
|
16
|
-
|
22
|
+
def reply(chat, prompt, options = {})
|
23
|
+
limit = options[:limit] || settings[:chat_message_limit] || 10
|
24
|
+
|
25
|
+
parameters = default_parameters
|
26
|
+
parameters[:messages] = [{ role: 'system', content: prompt }]
|
27
|
+
|
28
|
+
messages = chat.messages.order(created_at: :desc).limit(limit).reverse
|
29
|
+
messages.each do |message|
|
30
|
+
parameters[:messages] << { role: message.role, content: message.content }
|
31
|
+
end
|
32
|
+
|
33
|
+
return chat(parameters)
|
17
34
|
end
|
18
35
|
end
|
19
36
|
end
|
@@ -1,6 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
namespace :active_intelligence do
|
4
|
+
include ActiveIntelligence
|
5
|
+
|
6
|
+
desc 'Chat with the LLM'
|
7
|
+
task :chat, [:id] => :environment do |_t, args|
|
8
|
+
chat = args[:id].nil? ? Chat.create! : Chat.find(args[:id])
|
9
|
+
ChatREPLService.call(chat)
|
10
|
+
end
|
11
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_intelligence
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rich Humphrey
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-05-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -97,10 +97,16 @@ files:
|
|
97
97
|
- app/jobs/active_intelligence/application_job.rb
|
98
98
|
- app/mailers/active_intelligence/application_mailer.rb
|
99
99
|
- app/models/active_intelligence/application_record.rb
|
100
|
+
- app/models/active_intelligence/chat.rb
|
101
|
+
- app/models/active_intelligence/chat_message.rb
|
100
102
|
- app/models/concerns/active_intelligence/promptable.rb
|
103
|
+
- app/services/active_intelligence/application_service.rb
|
104
|
+
- app/services/active_intelligence/chat_repl_service.rb
|
101
105
|
- app/views/layouts/active_intelligence/application.html.erb
|
102
106
|
- config/initializers/inflections.rb
|
103
107
|
- config/routes.rb
|
108
|
+
- db/migrate/20240520181009_create_active_intelligence_chats.rb
|
109
|
+
- db/migrate/20240520185221_create_active_intelligence_chat_messages.rb
|
104
110
|
- lib/active_intelligence.rb
|
105
111
|
- lib/active_intelligence/adapter.rb
|
106
112
|
- lib/active_intelligence/asr/adapter.rb
|