-
Notifications
You must be signed in to change notification settings - Fork 438
/
api.rb
191 lines (151 loc) · 5.26 KB
/
api.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# frozen_string_literal: true
module MessageApis::OpenAi
class Api < MessageApis::BasePackage
include MessageApis::Helpers
BASE_URL = "https://api.openai.com"
PROVIDER = "openai"
attr_accessor :url, :api_secret, :conn
def initialize(config:)
@api_secret = config["api_secret"]
@url = "#{BASE_URL}/v1/chat/completions"
@conn = Faraday.new(
request: {
params_encoder: Faraday::FlatParamsEncoder
}
)
self
end
def authorize!
@conn.request :authorization, :Bearer, @api_secret
end
def trigger(event)
subject = event.eventable
action = event.action
Rails.logger.info "EVENTTTT: #{action}"
case action
# when "visitors.convert" then notify_new_lead(subject)
when "conversation.user.first.comment" then notify_added(subject)
# when "conversations.added" then notify_added(subject)
end
end
def notify_added(conversation)
authorize!
# TODO: handle this only on UI ?
# add an option on app parent definition to add this by default??
# message = conversation.messages.where.not(
# authorable_type: "Agent"
# ).last
# participant = conversation.main_participant
# conversation.conversation_channels.create({
# provider: 'open_ai',
# provider_channel_id: conversation.id
# })
end
def locked_for_channel?(conversation, part)
if part.authorable.is_a?(Agent) && !part.authorable.bot?
conversation.conversation_channels.find_by({
provider: "open_ai",
provider_channel_id: conversation.id
}).destroy
# assign and return , bot conversation over
# conversation.assign_user(part.authorable)
true
end
end
def notify_message(conversation:, part:, channel:)
gpt_channel = conversation.conversation_channels.find_by(provider: "open_ai")
return if gpt_channel.blank?
return unless part.messageable.is_a?(ConversationPartContent)
return true if locked_for_channel?(conversation, part)
return if part.conversation_part_channel_sources.where(provider: "open_ai").any?
Rails.logger.info "NOTIFY MESSAGE OPEN AI #{part.id}"
unless part.authorable.is_a?(Agent)
previous = previous_messages(conversation, part)
parsed_content = part&.message&.parsed_content
human_input = parsed_content["blocks"]
human_input = human_input&.map do |o|
o["text"]
end&.join(" ")
messages = previous << { role: "user", content: human_input }
Rails.cache.write("/conversation/#{conversation.key}/openai", messages)
Rails.logger.info "PROMPT: #{messages}"
gpt_result = get_gpt_response(gpt_channel.data["prompt"], messages, part.authorable.id.to_s)
Rails.logger.info(gpt_result)
text = begin
gpt_result["choices"].first["message"]["content"]
rescue StandardError
nil
end
return if text.nil?
blocks = {
blocks: [
serialized_block(text)
].flatten.compact
}.to_json
add_message(
conversation: conversation,
from: conversation.app.agents.bots.first,
text: text,
blocks: blocks,
message_id: gpt_result[:id]
)
end
end
def previous_messages(conversation, part)
Rails.cache.fetch("/conversation/#{conversation.key}/openai", expires_in: 1.hour) do
messages = conversation.messages.where(
messageable_type: "ConversationPartContent"
).where.not(id: part.id)
.order("id")
messages.map do |m|
{
"content" => m.message.text_from_serialized,
"role" => m.authorable_type == "Agent" ? "assistant" : "user"
}
end
end
end
def add_message(conversation:, from:, text:, blocks:, message_id:)
# TODO: serialize message
conversation.transaction do
conversation.add_message(
from: from,
message: {
html_content: text,
serialized_content: blocks
},
provider: "open_ai",
message_source_id: message_id,
check_assignment_rules: true
)
end
end
def post_data(url, data)
authorize!
@conn.post do |req|
req.url url
req.headers["Content-Type"] = "application/json; charset=utf-8"
req.body = data.to_json
end
end
def get_gpt_response(prompt, data, user_key)
system_prompt = { role: "system", content: prompt }
messages = []
messages << system_prompt
messages << data
message_data = {
model: "gpt-3.5-turbo",
messages: messages.flatten,
user: user_key
}
Rails.logger.debug message_data
JSON.parse(post_data(@url, message_data).body)
end
def process_event(params, package)
# todo, here we can do so many things like make a pause and
# analize conversation subject or classyficators
end
# for display in replied message
def self.display_data(data); end
end
end