chatgpt_assistant 0.1.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/.env_sample +18 -0
- data/.rspec +3 -0
- data/.rubocop.yml +26 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/CONTRIBUTING.md +147 -0
- data/Dockerfile +15 -0
- data/Gemfile +47 -0
- data/Gemfile.lock +299 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +21 -0
- data/README.md +77 -0
- data/Rakefile +15 -0
- data/deploy.sh +10 -0
- data/deploy_and_build.sh +11 -0
- data/docker-compose.prod.yml +34 -0
- data/docker-compose.yml +34 -0
- data/exe/chatgpt_assistant +43 -0
- data/exe/chatgpt_bot +16 -0
- data/lib/bots/application_bot.rb +119 -0
- data/lib/bots/discord_bot.rb +304 -0
- data/lib/bots/telegram_bot.rb +279 -0
- data/lib/chatgpt_assistant/audio_recognition.rb +54 -0
- data/lib/chatgpt_assistant/audio_synthesis.rb +124 -0
- data/lib/chatgpt_assistant/chatter.rb +84 -0
- data/lib/chatgpt_assistant/chatter_logger.rb +18 -0
- data/lib/chatgpt_assistant/config.rb +59 -0
- data/lib/chatgpt_assistant/default_messages.rb +144 -0
- data/lib/chatgpt_assistant/migrations.rb +57 -0
- data/lib/chatgpt_assistant/models.rb +45 -0
- data/lib/chatgpt_assistant/version.rb +5 -0
- data/lib/chatgpt_assistant.rb +57 -0
- data/logs/.keep +0 -0
- data/sig/chatgpt_assistant.rbs +4 -0
- data/voice/.keep +0 -0
- metadata +87 -0
@@ -0,0 +1,279 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ChatgptAssistant
|
4
|
+
# This class is responsible for the telegram bot features
|
5
|
+
class TelegramBot < ApplicationBot
|
6
|
+
def start
|
7
|
+
start_log
|
8
|
+
bot.listen do |message|
|
9
|
+
@msg = message
|
10
|
+
next unless text_or_audio?
|
11
|
+
|
12
|
+
message_received_log
|
13
|
+
message_text_cases if msg.text.present?
|
14
|
+
message_audio_process if msg.audio.present? || msg.voice.present?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_accessor :msg
|
21
|
+
|
22
|
+
def message_text_cases
|
23
|
+
logger.log("MESSAGE TEXT: TRUE")
|
24
|
+
case msg.text
|
25
|
+
when "/start"
|
26
|
+
run_start
|
27
|
+
when "/help"
|
28
|
+
run_help
|
29
|
+
when "/list"
|
30
|
+
list_chats
|
31
|
+
when "/stop"
|
32
|
+
run_stop
|
33
|
+
when "/hist"
|
34
|
+
run_hist
|
35
|
+
when nil
|
36
|
+
run_nil_error
|
37
|
+
else
|
38
|
+
operations
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def message_audio_process
|
43
|
+
logger.log("MESSAGE AUDIO: TRUE")
|
44
|
+
return bot.api.send_message(chat_id: msg.chat.id, text: error_messages[:no_chat_selected]) if user.current_chat_id.nil? || user.current_chat_id.zero?
|
45
|
+
chat = Chat.find(user.current_chat_id)
|
46
|
+
message_create(transcribed_text, chat.id, "user")
|
47
|
+
text = chatter.chat(transcribed_text, chat.id)
|
48
|
+
voice = audio_synthesis.synthesize_text(text)
|
49
|
+
bot.api.send_message(chat_id: msg.chat.id, text: text)
|
50
|
+
bot.api.send_voice(chat_id: msg.chat.id, voice: Faraday::UploadIO.new(voice, "audio/mp3"))
|
51
|
+
delete_all_voice_files
|
52
|
+
end
|
53
|
+
|
54
|
+
def operations
|
55
|
+
return chatter_call unless actions?
|
56
|
+
return new_chat if msg.text.include?("new_chat/")
|
57
|
+
return select_chat if msg.text.include?("sl_chat/")
|
58
|
+
return login if msg.text.include?("login/")
|
59
|
+
return register if msg.text.include?("register/")
|
60
|
+
invalid_command_error_message
|
61
|
+
end
|
62
|
+
|
63
|
+
def login
|
64
|
+
user_info = msg.text.split("/").last
|
65
|
+
email, password = user_info.split(":")
|
66
|
+
case auth_usertelegram(email, password, msg.chat.id)
|
67
|
+
when "user not found"
|
68
|
+
user_not_found_error_message
|
69
|
+
when "wrong password"
|
70
|
+
wrong_password_error_message
|
71
|
+
when find_usertelegram(email)
|
72
|
+
user_logged_in_message
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def register
|
77
|
+
user_info = msg.text.split("/").last
|
78
|
+
email, password = user_info.split(":")
|
79
|
+
if telegram_user_create(msg.chat.id, email, password, msg.from.username || msg.from.first_name)
|
80
|
+
user_created_message
|
81
|
+
else
|
82
|
+
user_creation_error_message
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def audio
|
87
|
+
msg.audio || msg.voice
|
88
|
+
end
|
89
|
+
|
90
|
+
def audio_info
|
91
|
+
bot.api.get_file(file_id: audio.file_id)
|
92
|
+
end
|
93
|
+
|
94
|
+
def audio_url
|
95
|
+
"https://api.telegram.org/file/bot#{telegram_token}/#{audio_info["result"]["file_path"]}"
|
96
|
+
end
|
97
|
+
|
98
|
+
def transcribed_text
|
99
|
+
audio_recognition.transcribe_audio(audio_url)
|
100
|
+
end
|
101
|
+
|
102
|
+
def run_start
|
103
|
+
bot.api.send_message(chat_id: msg.chat.id, text: commom_messages[:start])
|
104
|
+
help_message = help_messages.join("\n").to_s
|
105
|
+
bot.api.send_message(chat_id: msg.chat.id, text: help_message)
|
106
|
+
bot.api.send_message(chat_id: msg.chat.id, text: commom_messages[:start_helper])
|
107
|
+
bot.api.send_message(chat_id: msg.chat.id, text: commom_messages[:start_sec_helper])
|
108
|
+
end
|
109
|
+
|
110
|
+
def run_hist
|
111
|
+
return not_logged_in_message unless user
|
112
|
+
|
113
|
+
chat = Chat.find(user.current_chat_id)
|
114
|
+
if chat
|
115
|
+
if chat.messages.count.zero?
|
116
|
+
return bot.api.send_message(chat_id: msg.chat.id,
|
117
|
+
text: error_messages[:no_messages_founded])
|
118
|
+
end
|
119
|
+
|
120
|
+
response = chat.messages.last(4).map do |mess|
|
121
|
+
"#{mess.role}: #{mess.content}\n at: #{mess.created_at}\n\n"
|
122
|
+
end.join
|
123
|
+
logger.log("HIST RESPONSE: #{response}")
|
124
|
+
bot.api.send_message(chat_id: msg.chat.id, text: response)
|
125
|
+
else
|
126
|
+
bot.api.send_message(chat_id: msg.chat.id, text: error_messages[:no_chat_selected])
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def select_chat
|
131
|
+
if user.nil?
|
132
|
+
not_logged_in_message
|
133
|
+
else
|
134
|
+
chat = Chat.find_by(user: user, title: msg.text.split("/").last)
|
135
|
+
if chat
|
136
|
+
user.update(current_chat_id: chat.id)
|
137
|
+
bot.api.send_message(chat_id: msg.chat.id, text: success_messages[:chat_selected])
|
138
|
+
else
|
139
|
+
chat_not_found_message
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def new_chat
|
145
|
+
user.nil? ? not_logged_in_message : create_chat
|
146
|
+
end
|
147
|
+
|
148
|
+
def create_chat
|
149
|
+
text = msg.text
|
150
|
+
title = text.split("/").last
|
151
|
+
chat = Chat.new(user_id: user.id, status: 0, title: title)
|
152
|
+
chat.save ? chat_created_message(chat) : chat_creation_failed_message
|
153
|
+
end
|
154
|
+
|
155
|
+
def list_chats
|
156
|
+
chats = Chat.where(user_id: User.find_by(telegram_id: msg.chat.id).id)
|
157
|
+
return bot.api.send_message(chat_id: msg.chat.id, text: error_messages[:no_chats_founded]) if chats.count.zero?
|
158
|
+
bot.api.send_message(chat_id: msg.chat.id,
|
159
|
+
text: commom_messages[:chats_list])
|
160
|
+
chats_str = ""
|
161
|
+
chats.each do |chat|
|
162
|
+
chats_str += "Chat #{chat.id} - #{chat.title}\n"
|
163
|
+
end
|
164
|
+
bot.api.send_message(chat_id: msg.chat.id, text: chats_str)
|
165
|
+
end
|
166
|
+
|
167
|
+
def chatter_call
|
168
|
+
user ? chat_if_exists : not_logged_in_message
|
169
|
+
end
|
170
|
+
|
171
|
+
def chat_if_exists
|
172
|
+
chat = Chat.find_by(user_id: user.id, id: user.current_chat_id)
|
173
|
+
chat ? chat_success(chat.id) : no_chat_selected
|
174
|
+
end
|
175
|
+
|
176
|
+
def chat_success(chat_id)
|
177
|
+
Message.create(chat_id: chat_id, content: msg.text, role: "user")
|
178
|
+
bot.api.send_message(chat_id: msg.chat.id, text: chatter.chat(msg.text, chat_id))
|
179
|
+
end
|
180
|
+
|
181
|
+
def run_help
|
182
|
+
help_messages.each do |message|
|
183
|
+
bot.api.send_message(chat_id: msg.chat.id, text: message)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def run_stop
|
188
|
+
bot.api.send_message(chat_id: msg.chat.id, text: commom_messages[:stop])
|
189
|
+
bot.api.leave_chat(chat_id: msg.chat.id)
|
190
|
+
end
|
191
|
+
|
192
|
+
def run_nil_error
|
193
|
+
bot.api.send_message(chat_id: msg.chat.id, text: error_messages[:nil])
|
194
|
+
end
|
195
|
+
|
196
|
+
def user_logged_message
|
197
|
+
user.update(telegram_id: msg.chat.id)
|
198
|
+
bot.api.send_message(chat_id: msg.chat.id, text: success_messages[:user_logged_in])
|
199
|
+
end
|
200
|
+
|
201
|
+
def invalid_command_error_message
|
202
|
+
bot.api.send_message(chat_id: msg.chat.id, text: error_messages[:invalid_command])
|
203
|
+
end
|
204
|
+
|
205
|
+
def wrong_password_error_message
|
206
|
+
bot.api.send_message(chat_id: msg.chat.id, text: error_messages[:password])
|
207
|
+
end
|
208
|
+
|
209
|
+
def user_not_found_error_message
|
210
|
+
bot.api.send_message(chat_id: msg.chat.id, text: error_messages[:user_not_found])
|
211
|
+
end
|
212
|
+
|
213
|
+
def not_logged_in_message
|
214
|
+
bot.api.send_message(chat_id: msg.chat.id, text: error_messages[:user_not_logged_in])
|
215
|
+
end
|
216
|
+
|
217
|
+
def user_created_message
|
218
|
+
bot.api.send_message(chat_id: msg.chat.id, text: success_messages[:user_created])
|
219
|
+
end
|
220
|
+
|
221
|
+
def user_creation_error_message
|
222
|
+
bot.api.send_message(chat_id: msg.chat.id, text: error_messages[:user_creation])
|
223
|
+
end
|
224
|
+
|
225
|
+
def chat_created_message(chat)
|
226
|
+
user.update(current_chat_id: chat.id)
|
227
|
+
bot.api.send_message(chat_id: msg.chat.id, text: success_messages[:chat_created])
|
228
|
+
end
|
229
|
+
|
230
|
+
def chat_creation_failed_message
|
231
|
+
bot.api.send_message(chat_id: msg.chat.id, text: error_messages[:chat_creation_failed])
|
232
|
+
end
|
233
|
+
|
234
|
+
def no_chat_selected
|
235
|
+
bot.api.send_message(chat_id: msg.chat.id,
|
236
|
+
text: error_messages[:no_chat_selected])
|
237
|
+
end
|
238
|
+
|
239
|
+
def chat_not_found_message
|
240
|
+
bot.api.send_message(chat_id: msg.chat.id, text: error_messages[:chat_not_found])
|
241
|
+
end
|
242
|
+
|
243
|
+
def start_log
|
244
|
+
logger.log("STARTING BOT AT #{Time.now}")
|
245
|
+
logger.log("ENVIRONMENT: #{@config.env_type}")
|
246
|
+
end
|
247
|
+
|
248
|
+
def error_log(err)
|
249
|
+
if err.message.to_s.include?("Bad Request: message is too long")
|
250
|
+
bot.api.send_message(chat_id: msg.chat.id, text: error_messages[:message_history_too_long])
|
251
|
+
else
|
252
|
+
bot.api.send_message(chat_id: msg.chat.id, text: error_messages[:something_went_wrong])
|
253
|
+
bot.api.send_message(chat_id: msg.chat.id, text: "ERROR: #{err.message}\n #{err.backtrace}")
|
254
|
+
end
|
255
|
+
logger.log("ERROR: #{err.message}\n #{err.backtrace}")
|
256
|
+
end
|
257
|
+
|
258
|
+
def message_received_log
|
259
|
+
logger.log("MESSAGE RECEIVED AT: #{Time.now}")
|
260
|
+
logger.log("MESSAGE FROM USER: #{msg.from.first_name} #{msg.from.last_name} - #{msg.from.username}")
|
261
|
+
end
|
262
|
+
|
263
|
+
def user
|
264
|
+
@user ||= User.find_by(telegram_id: msg.chat.id)
|
265
|
+
end
|
266
|
+
|
267
|
+
def bot
|
268
|
+
@bot ||= Telegram::Bot::Client.new(telegram_token)
|
269
|
+
end
|
270
|
+
|
271
|
+
def text_or_audio?
|
272
|
+
msg.respond_to?(:text) || msg.respond_to?(:audio) || msg.respond_to?(:voice)
|
273
|
+
end
|
274
|
+
|
275
|
+
def actions?
|
276
|
+
msg.text.include?("new_chat/") || msg.text.include?("sl_chat/") || msg.text.include?("login/") || msg.text.include?("register/")
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ChatgptAssistant
|
4
|
+
# This is the AudioRecognition class
|
5
|
+
class AudioRecognition
|
6
|
+
def initialize(openai_api_key)
|
7
|
+
@conn = Faraday.new(url: "https://api.openai.com/") do |faraday|
|
8
|
+
faraday.request :multipart
|
9
|
+
faraday.request :url_encoded
|
10
|
+
faraday.adapter Faraday.default_adapter
|
11
|
+
end
|
12
|
+
@logger = ChatterLogger.new
|
13
|
+
@openai_api_key = openai_api_key
|
14
|
+
end
|
15
|
+
|
16
|
+
def download_audio(audio_url)
|
17
|
+
logger.log("DOWNLOADING AUDIO FROM TELEGRAM")
|
18
|
+
@time = Time.now.to_i
|
19
|
+
audio_conn = Faraday.new(url: audio_url)
|
20
|
+
File.open("voice/audio-#{time}.oga", "wb") do |file|
|
21
|
+
file.write(audio_conn.get.body)
|
22
|
+
end
|
23
|
+
|
24
|
+
FFMPEG::Movie.new("voice/audio-#{time}.oga").transcode("voice/audio-#{time}.mp3")
|
25
|
+
File.delete("voice/audio-#{time}.oga")
|
26
|
+
end
|
27
|
+
|
28
|
+
def header
|
29
|
+
{
|
30
|
+
"Content-Type": "multipart/form-data",
|
31
|
+
"Authorization": "Bearer #{openai_api_key}"
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def payload
|
36
|
+
{
|
37
|
+
"file": Faraday::UploadIO.new("voice/audio-#{time}.mp3", "audio/mp3"),
|
38
|
+
"model": "whisper-1"
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def transcribe_audio(audio_url)
|
43
|
+
@audio_url = audio_url
|
44
|
+
download_audio(audio_url)
|
45
|
+
response = conn.post("v1/audio/transcriptions", payload, header)
|
46
|
+
logger.log("RESPONSE FROM OPENAI API AUDIO TRANSCRIPTION")
|
47
|
+
JSON.parse(response.body)["text"]
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
attr_reader :conn, :openai_api_key, :logger, :audio_url, :time, :ibm_api_key, :ibm_url
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ChatgptAssistant
|
4
|
+
# This class is responsible for synthesize text to speech
|
5
|
+
# This class can work with IBM Cloud or AWS Polly for synthesize text into speech
|
6
|
+
class AudioSynthesis
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
@openai_api_key = config.openai_api_key
|
10
|
+
@language = config.language
|
11
|
+
@conn = faraday_instance
|
12
|
+
@logger = ChatterLogger.new
|
13
|
+
classify_mode
|
14
|
+
end
|
15
|
+
|
16
|
+
def synthesize_text(text)
|
17
|
+
if ibm_mode?
|
18
|
+
synthesize_text_ibm(text)
|
19
|
+
elsif aws_mode?
|
20
|
+
synthesize_text_aws(text)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :openai_api_key, :ibm_api_key, :ibm_url, :aws_access_key_id, :aws_secret_access_key, :aws_region,
|
27
|
+
:config, :logger, :language, :voice
|
28
|
+
|
29
|
+
def faraday_instance
|
30
|
+
Faraday.new(url: "https://api.openai.com/") do |faraday|
|
31
|
+
faraday.request :multipart
|
32
|
+
faraday.request :url_encoded
|
33
|
+
faraday.adapter Faraday.default_adapter
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def classify_mode
|
38
|
+
if ibm_mode?
|
39
|
+
@ibm_api_key = config.ibm_api_key
|
40
|
+
@ibm_url = config.ibm_url
|
41
|
+
@voice = send("#{language}_ibm_voice")
|
42
|
+
elsif aws_mode?
|
43
|
+
@aws_access_key_id = config.aws_access_key_id
|
44
|
+
@aws_secret_access_key = config.aws_secret_access_key
|
45
|
+
@aws_region = config.aws_region
|
46
|
+
@voice = send("#{language}_aws_voice")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def synthesize_text_aws(text)
|
51
|
+
time = Time.now.to_i
|
52
|
+
logger.log("SYNTHESIZING TEXT WITH AWS POLLY")
|
53
|
+
@time = Time.now.to_i
|
54
|
+
polly_client = Aws::Polly::Client.new(
|
55
|
+
access_key_id: aws_access_key_id,
|
56
|
+
secret_access_key: aws_secret_access_key,
|
57
|
+
region: aws_region
|
58
|
+
)
|
59
|
+
response = polly_client.synthesize_speech(
|
60
|
+
output_format: "mp3",
|
61
|
+
text: text,
|
62
|
+
voice_id: voice,
|
63
|
+
engine: "neural"
|
64
|
+
)
|
65
|
+
|
66
|
+
File.open("voice/aws-#{time}.mp3", "wb") do |file|
|
67
|
+
file.write(response.audio_stream.read)
|
68
|
+
end
|
69
|
+
|
70
|
+
logger.log("SYNTHESIZED TEXT WITH AWS POLLY")
|
71
|
+
"voice/aws-#{time}.mp3"
|
72
|
+
end
|
73
|
+
|
74
|
+
def synthesize_text_ibm(text)
|
75
|
+
time = Time.now.to_i
|
76
|
+
logger.log("SYNTHESIZING TEXT WITH IBM WATSON")
|
77
|
+
authenticator = IBMWatson::Authenticators::IamAuthenticator.new(
|
78
|
+
apikey: ibm_api_key
|
79
|
+
)
|
80
|
+
|
81
|
+
text_to_speech = IBMWatson::TextToSpeechV1.new(
|
82
|
+
authenticator: authenticator
|
83
|
+
)
|
84
|
+
|
85
|
+
text_to_speech.service_url = ibm_url
|
86
|
+
|
87
|
+
audio_format = "audio/mp3"
|
88
|
+
audio = text_to_speech.synthesize(
|
89
|
+
text: text,
|
90
|
+
accept: audio_format,
|
91
|
+
voice: voice
|
92
|
+
).result
|
93
|
+
|
94
|
+
File.open("voice/ibm-#{time}.mp3", "wb") do |audio_file|
|
95
|
+
audio_file.write(audio)
|
96
|
+
end
|
97
|
+
"voice/ibm-#{time}.mp3"
|
98
|
+
end
|
99
|
+
|
100
|
+
def pt_aws_voice
|
101
|
+
"Vitoria"
|
102
|
+
end
|
103
|
+
|
104
|
+
def en_aws_voice
|
105
|
+
"Joanna"
|
106
|
+
end
|
107
|
+
|
108
|
+
def pt_ibm_voice
|
109
|
+
"pt-BR_IsabelaV3Voice"
|
110
|
+
end
|
111
|
+
|
112
|
+
def en_ibm_voice
|
113
|
+
"en-US_AllisonV3Voice"
|
114
|
+
end
|
115
|
+
|
116
|
+
def ibm_mode?
|
117
|
+
config.mode == "ibm"
|
118
|
+
end
|
119
|
+
|
120
|
+
def aws_mode?
|
121
|
+
config.mode == "aws"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "faraday"
|
4
|
+
require_relative "models"
|
5
|
+
require_relative "chatter_logger"
|
6
|
+
|
7
|
+
module ChatgptAssistant
|
8
|
+
# This is the Chat Ai class
|
9
|
+
class Chatter
|
10
|
+
def initialize(openai_api_key)
|
11
|
+
@openai_api_key = openai_api_key
|
12
|
+
@logger = ChatterLogger.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def chat(message, chat_id)
|
16
|
+
@chat_id = chat_id
|
17
|
+
@message = message
|
18
|
+
init_log
|
19
|
+
@response = request(message)
|
20
|
+
@json = JSON.parse(response.body)
|
21
|
+
logger.log("RESPONSE FROM OPENAI API: OK")
|
22
|
+
|
23
|
+
return error_log if response.status != 200
|
24
|
+
|
25
|
+
text = json["choices"][0]["message"]["content"]
|
26
|
+
|
27
|
+
Message.create(content: text, role: "assistant", chat_id: chat_id)
|
28
|
+
logger.log("MESSAGE SAVED IN DATABASE")
|
29
|
+
text
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :openai_api_key, :response, :message, :logger
|
35
|
+
attr_accessor :chat_id, :json
|
36
|
+
|
37
|
+
def init_log
|
38
|
+
logger.log("REQUESTING OPENAI API COMPLETION")
|
39
|
+
end
|
40
|
+
|
41
|
+
def error_log
|
42
|
+
logger.log("RESPONSE FROM OPENAI API ERROR")
|
43
|
+
logger.log("RESPONSE STATUS: #{response.status}")
|
44
|
+
"Algo deu errado, tente novamente mais tarde."
|
45
|
+
end
|
46
|
+
|
47
|
+
def header
|
48
|
+
{
|
49
|
+
"Content-Type": "application/json",
|
50
|
+
Authorization: "Bearer #{openai_api_key}"
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def connection
|
55
|
+
Faraday.new(url: "https://api.openai.com/") do |faraday|
|
56
|
+
faraday.request :url_encoded
|
57
|
+
faraday.adapter Faraday.default_adapter
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def request_params(message)
|
62
|
+
messages = Message.where(chat_id: chat_id).order(id: :asc).last(10)
|
63
|
+
if messages.empty?
|
64
|
+
ids = ["unknown"]
|
65
|
+
messages = [{ role: "user", content: message }]
|
66
|
+
else
|
67
|
+
ids = messages.map(&:id)
|
68
|
+
messages = messages.map { |mess| { role: mess.role, content: mess.content } }
|
69
|
+
end
|
70
|
+
logger.log("MESSAGES LOADED IN CONTEXT: #{messages.count}")
|
71
|
+
messages.each_with_index do |mess, index|
|
72
|
+
logger.log("MESSAGE ROLE: #{mess[:role]}, ID: #{ids[index]}")
|
73
|
+
end
|
74
|
+
{
|
75
|
+
model: "gpt-3.5-turbo",
|
76
|
+
messages: messages
|
77
|
+
}.to_json
|
78
|
+
end
|
79
|
+
|
80
|
+
def request(message)
|
81
|
+
connection.post("v1/chat/completions", request_params(message), header)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ChatgptAssistant
|
4
|
+
# This class is responsible for logging the messages
|
5
|
+
class ChatterLogger
|
6
|
+
def initialize
|
7
|
+
@file_name = "logs/telegram_chatgpt.log"
|
8
|
+
@log_file = File.open("logs/telegram_chatgpt.log", "a")
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :log_file
|
12
|
+
|
13
|
+
def log(message)
|
14
|
+
log_file.puts(message)
|
15
|
+
system "echo '#{message}'"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record"
|
4
|
+
require "active_model"
|
5
|
+
require_relative "migrations"
|
6
|
+
require "fileutils"
|
7
|
+
|
8
|
+
module ChatgptAssistant
|
9
|
+
# This class is responsible for the configuration of the Chatgpt Assistant
|
10
|
+
class Config
|
11
|
+
def initialize
|
12
|
+
@env_type = ENV["ENV_TYPE"]
|
13
|
+
@language = ENV["LANGUAGE"]
|
14
|
+
@mode = ENV["MODE"]
|
15
|
+
@database_host = ENV["POSTGRES_HOST"]
|
16
|
+
@database_name = ENV["POSTGRES_DB"]
|
17
|
+
@database_username = ENV["POSTGRES_USER"]
|
18
|
+
@database_password = ENV["POSTGRES_PASSWORD"]
|
19
|
+
@openai_api_key = ENV["OPENAI_API_KEY"]
|
20
|
+
@telegram_token = ENV["TELEGRAM_TOKEN"]
|
21
|
+
@discord_token = ENV["DISCORD_TOKEN"]
|
22
|
+
@discord_client_id = ENV["DISCORD_CLIENT_ID"]
|
23
|
+
@ibm_api_key = ENV["IBM_API_KEY"]
|
24
|
+
@ibm_url = ENV["IBM_URL"]
|
25
|
+
@aws_access_key_id = ENV["AWS_ACCESS_KEY_ID"]
|
26
|
+
@aws_secret_access_key = ENV["AWS_SECRET_ACCESS_KEY"]
|
27
|
+
@aws_region = ENV["AWS_REGION"]
|
28
|
+
@discord_prefix = ENV["DISCORD_PREFIX"]
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :openai_api_key, :telegram_token, :discord_token, :ibm_api_key, :ibm_url,
|
32
|
+
:aws_access_key_id, :aws_secret_access_key, :aws_region, :mode, :language,
|
33
|
+
:discord_client_id, :discord_public_key, :env_type, :discord_prefix
|
34
|
+
|
35
|
+
def db_connection
|
36
|
+
ActiveRecord::Base.establish_connection(
|
37
|
+
adapter: "postgresql",
|
38
|
+
host: database_host,
|
39
|
+
port: 5432,
|
40
|
+
database: database_name,
|
41
|
+
username: database_username,
|
42
|
+
password: database_password
|
43
|
+
)
|
44
|
+
ActiveRecord::Base.logger = Logger.new($stdout) if ENV["ENV_TYPE"] == "development"
|
45
|
+
end
|
46
|
+
|
47
|
+
def migrate
|
48
|
+
db_connection
|
49
|
+
ActiveRecord::Base.logger = Logger.new($stdout)
|
50
|
+
UserMigration.new.migrate(:up)
|
51
|
+
ChatMigration.new.migrate(:up)
|
52
|
+
MessageMigration.new.migrate(:up)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
attr_reader :database_host, :database_name, :database_username, :database_password
|
58
|
+
end
|
59
|
+
end
|