chatgpt_assistant 0.1.4 → 0.1.6

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.env_sample +1 -1
  3. data/.rubocop.yml +3 -3
  4. data/Gemfile +19 -5
  5. data/Gemfile.lock +64 -50
  6. data/README.md +14 -13
  7. data/Rakefile +2 -0
  8. data/docker-compose.prod.yml +1 -1
  9. data/docker-compose.yml +18 -0
  10. data/exe/chatgpt_bot +3 -0
  11. data/lib/bots/application_bot.rb +15 -5
  12. data/lib/bots/discord_bot.rb +42 -15
  13. data/lib/bots/helpers/authentication_helper.rb +7 -6
  14. data/lib/bots/helpers/discord_helper.rb +29 -7
  15. data/lib/bots/helpers/discord_voice_helper.rb +1 -1
  16. data/lib/bots/helpers/messenger_helper.rb +35 -36
  17. data/lib/bots/helpers/search_helper.rb +3 -3
  18. data/lib/bots/helpers/telegram_helper.rb +19 -35
  19. data/lib/bots/helpers/telegram_voice_helper.rb +33 -0
  20. data/lib/bots/helpers/validation_helper.rb +9 -0
  21. data/lib/bots/helpers/visit_helper.rb +4 -0
  22. data/lib/bots/jobs/new_chat_job.rb +17 -0
  23. data/lib/bots/jobs/register_job.rb +16 -0
  24. data/lib/bots/jobs/voice_connect_job.rb +14 -0
  25. data/lib/bots/services/new_chat_service.rb +34 -0
  26. data/lib/bots/services/register_service.rb +36 -0
  27. data/lib/bots/services/voice_connect_service.rb +29 -0
  28. data/lib/bots/telegram_bot.rb +72 -54
  29. data/lib/chatgpt_assistant/chatter.rb +17 -6
  30. data/lib/chatgpt_assistant/config.rb +23 -3
  31. data/lib/chatgpt_assistant/default_messages.rb +72 -30
  32. data/lib/chatgpt_assistant/error.rb +219 -0
  33. data/lib/chatgpt_assistant/migrations.rb +3 -30
  34. data/lib/chatgpt_assistant/models.rb +24 -29
  35. data/lib/chatgpt_assistant/sidekiq.rb +7 -0
  36. data/lib/chatgpt_assistant/sidekiq.yml +10 -0
  37. data/lib/chatgpt_assistant/version.rb +1 -1
  38. data/lib/chatgpt_assistant.rb +4 -12
  39. data/prompts-data/awesome-en-prompts.csv +164 -0
  40. data/prompts-data/awesome-pt-prompts.csv +164 -0
  41. metadata +15 -4
  42. data/lib/bots/helpers/logger_action_helper.rb +0 -14
@@ -1,14 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "helpers/telegram_helper"
4
+ require_relative "helpers/telegram_voice_helper"
4
5
 
5
6
  module ChatgptAssistant
6
7
  # This class is responsible for the telegram bot features
7
8
  class TelegramBot < ApplicationBot
8
9
  def start
9
10
  bot.listen do |message|
10
- next if message.chat.type != "private" # disable group and channel messages, we will enable it later
11
-
12
11
  @msg = message
13
12
  @visitor = telegram_visited?(@msg.chat.id)
14
13
  next unless telegram_text_or_audio?
@@ -24,6 +23,7 @@ module ChatgptAssistant
24
23
  private
25
24
 
26
25
  include TelegramHelper
26
+ include TelegramVoiceHelper
27
27
 
28
28
  attr_accessor :msg, :visitor, :chat, :chat_id
29
29
 
@@ -40,123 +40,141 @@ module ChatgptAssistant
40
40
  when "/stop"
41
41
  stop_event
42
42
  when nil
43
- nil_event
43
+ raise NilError
44
44
  else
45
45
  action_events
46
46
  end
47
+ rescue NilError => e
48
+ send_message e.message, msg.chat.id
47
49
  end
48
50
 
49
51
  def start_event
50
- register_visitor_action("start", visitor.id) unless visitor.tel_user
51
- register_user_action("start", visitor.tel_user.id) if visitor.tel_user
52
52
  telegram_send_start_message
53
53
  end
54
54
 
55
55
  def help_event
56
- register_visitor_action("help", visitor.id) unless visitor.tel_user
57
- register_user_action("help", visitor.tel_user.id) if visitor.tel_user
58
56
  help_messages.each { |m| send_message m, msg.chat.id }
59
57
  end
60
58
 
61
59
  def hist_event
62
- return not_logged_in_message unless user
63
- return no_chat_selected_message unless user.current_chat
64
- return no_messages_founded_message if user.current_chat.messages.count.zero?
60
+ raise UserNotLoggedInError if user.nil?
61
+ raise NoChatSelectedError if user.current_chat.nil?
62
+ raise NoMessagesFoundedError if user.current_chat.messages.count.zero?
65
63
 
66
- register_user_action("hist", user.id)
67
- telegram_user_history.each do |m|
64
+ user.chat_history.each do |m|
68
65
  send_message m, msg.chat.id
69
66
  end
67
+ rescue NoChatSelectedError, UserNotLoggedInError, NoMessagesFoundedError => e
68
+ send_message e.message, msg.chat.id
70
69
  end
71
70
 
72
71
  def list_event
73
- return unless valid_for_list_action?
72
+ raise UserNotLoggedInError if user.nil?
73
+ raise NoChatsFoundedError if user.chats.count.zero?
74
74
 
75
- register_user_action("list", user.id)
76
- send_message commom_messages[:chat_list], msg.chat.id
75
+ send_message common_messages[:chat_list], msg.chat.id
77
76
  chats_str = ""
78
77
  user.chats.each_with_index { |c, i| chats_str += "Chat #{i + 1} - #{c.title}\n" }
79
78
  send_message chats_str, msg.chat.id
79
+ rescue NoChatsFoundedError, UserNotLoggedInError => e
80
+ send_message e.message, msg.chat.id
80
81
  end
81
82
 
82
83
  def action_events
83
- return login_event if msg.text.include?("login/")
84
- return register_event if msg.text.include?("register/")
84
+ return auth_events if auth_event?
85
85
  return new_chat_event if msg.text.include?("new_chat/")
86
86
  return select_chat_event if msg.text.include?("sl_chat/")
87
87
  return telegram_chat_event unless telegram_actions?
88
88
 
89
- invalid_command_error_message
89
+ raise InvalidCommandError
90
+ rescue InvalidCommandError => e
91
+ send_message e.message, msg.chat.id
92
+ end
93
+
94
+ def auth_event?
95
+ msg.text.include?("login/") || msg.text.include?("register/") || msg.text.include?("sign_out/")
96
+ end
97
+
98
+ def auth_events
99
+ return login_event if msg.text.include?("login/")
100
+ return register_event if msg.text.include?("register/")
101
+ return sign_out_event if msg.text.include?("sign_out/")
90
102
  end
91
103
 
92
104
  def login_event
93
- register_visitor_action("login", visitor.id) unless visitor.tel_user
105
+ raise UserLoggedInError if user
106
+
94
107
  user_info = msg.text.split("/").last
95
108
  email, password = user_info.split(":")
96
109
  case telegram_user_auth(email, password, msg.chat.id)
97
110
  when "user not found"
98
- user_not_found_error_message
111
+ raise UserNotFoundError
99
112
  when "wrong password"
100
- wrong_password_error_message
113
+ raise WrongPasswordError
101
114
  when email
102
115
  user_logged_in_message
103
116
  end
117
+ rescue UserNotFoundError, WrongPasswordError, UserLoggedInError => e
118
+ send_message e.message, msg.chat.id
104
119
  end
105
120
 
106
121
  def register_event
107
- register_visitor_action("register", visitor.id)
108
122
  user_info = msg.text.split("/").last
123
+ raise NoRegisterInfoError if user_info.nil?
124
+ raise UserLoggedInError if user
125
+
109
126
  email, password = user_info.split(":")
110
- registered_email = telegram_user_create visitor.id, email, password
111
- registered_email == email ? user_created_message : user_creation_error_message
127
+ raise NoRegisterInfoError if email.nil? || password.nil?
128
+
129
+ RegisterJob.perform_async(email, password, visitor.telegram_id)
130
+ rescue NoRegisterInfoError, UserLoggedInError => e
131
+ send_message e.message, msg.chat.id
132
+ end
133
+
134
+ def sign_out_event
135
+ raise UserNotLoggedInError if user.nil?
136
+
137
+ user.update(telegram_id: nil)
138
+ send_message success_messages[:user_logged_out], msg.chat.id
139
+ rescue UserNotLoggedInError => e
140
+ send_message e.message, msg.chat.id
112
141
  end
113
142
 
114
143
  def new_chat_event
115
- return not_logged_in_message unless user
144
+ raise UserNotLoggedInError if user.nil?
116
145
 
117
- register_user_action("new_chat", user.id)
118
- telegram_create_chat
146
+ NewChatJob.perform_async(msg.text.split("/").last, user.id, msg.chat.id)
147
+ rescue UserNotLoggedInError => e
148
+ send_message e.message, msg.chat.id
119
149
  end
120
150
 
121
151
  def select_chat_event
122
- return not_logged_in_message unless user
152
+ raise UserNotLoggedInError if user.nil?
123
153
 
124
- register_user_action("select_chat", user.id)
125
154
  title = msg.text.split("/").last
126
155
  chat = user.chat_by_title(title)
127
- return chat_not_found_message unless chat
156
+ raise ChatNotFoundError if chat.nil?
128
157
 
129
- user.update(current_chat_id: chat.id)
130
- send_message success_messages[:chat_selected], msg.chat.id
131
- end
158
+ raise ChatNotFoundError unless user.update(current_chat_id: chat.id)
132
159
 
133
- def stop_event
134
- register_event_action("stop", visitor.id) unless visitor.tel_user
135
- register_user_action("stop", visitor.tel_user.id) if visitor.tel_user
136
- send_message commom_messages[:stop], msg.chat.id
137
- bot.api.leave_chat(chat_id: msg.chat.id)
138
- end
139
-
140
- def nil_event
141
- register_event_action("nil", visitor.id) unless visitor.tel_user
142
- register_user_action("nil", visitor.tel_user.id) if visitor.tel_user
143
- send_message error_messages[:nil], msg.chat.id
160
+ send_message success_messages[:chat_selected], msg.chat.id
161
+ rescue UserNotLoggedInError, ChatNotFoundError => e
162
+ send_message e.message, msg.chat.id
144
163
  end
145
164
 
146
165
  def audio_event
147
- return not_logged_in_message unless user
148
- return no_chat_selected_message if user.current_chat_id.nil?
166
+ raise UserNotLoggedInError if user.nil?
167
+ raise NoChatSelectedError if user.current_chat.nil?
149
168
 
150
- register_user_action("audio", user.id)
151
169
  user_audio = transcribe_file(telegram_audio_url)
152
170
  message = Message.new(content: user_audio[:text], chat_id: user.current_chat_id, role: "user")
153
- if message.save
154
- ai_response = telegram_process_ai_voice(user_audio[:file])
155
- telegram_send_voice_message(voice: ai_response[:voice], text: ai_response[:text])
156
- delete_file ai_response[:voice]
157
- else
158
- send_message error_messages[:message_creation_error], msg.chat.id
159
- end
171
+ raise MessageNotSavedError unless message.save
172
+
173
+ ai_response = telegram_process_ai_voice(user_audio[:file])
174
+ telegram_send_voice_message(voice: ai_response[:voice], text: ai_response[:text])
175
+ delete_file ai_response[:voice]
176
+ rescue UserNotLoggedInError, NoChatSelectedError, MessageNotSavedError => e
177
+ send_message e.message, msg.chat.id
160
178
  end
161
179
  end
162
180
  end
@@ -10,27 +10,36 @@ module ChatgptAssistant
10
10
  @openai_api_key = openai_api_key
11
11
  end
12
12
 
13
- def chat(message, chat_id)
13
+ def chat(message, chat_id, error_message)
14
+ @error_message = error_message
14
15
  @chat_id = chat_id
15
16
  @message = message
16
17
  @response = request(message)
17
18
  @json = JSON.parse(response.body)
18
19
 
19
- return error_log if response.status != 200
20
+ return no_response_error if json["choices"].empty?
21
+ return bot_offline_error if response.status != 200
20
22
 
21
23
  text = json["choices"][0]["message"]["content"]
22
24
 
23
25
  Message.create(content: text, role: "assistant", chat_id: chat_id)
24
26
  text
27
+ rescue StandardError => e
28
+ Error.create(message: e.message, backtrace: e.backtrace)
29
+ error_message
25
30
  end
26
31
 
27
32
  private
28
33
 
29
34
  attr_reader :openai_api_key, :response, :message
30
- attr_accessor :chat_id, :json
35
+ attr_accessor :chat_id, :json, :error_message
31
36
 
32
- def error_log
33
- "Algo deu errado, tente novamente mais tarde." # TODO: use a DefaultMessage object
37
+ def no_response_error
38
+ "I'm sorry, I didn't understand you. Please, try again."
39
+ end
40
+
41
+ def bot_offline_error
42
+ "I'm sorry, I'm offline. Please, try again later."
34
43
  end
35
44
 
36
45
  def header
@@ -59,7 +68,9 @@ module ChatgptAssistant
59
68
  end
60
69
  {
61
70
  model: "gpt-3.5-turbo",
62
- messages: messages
71
+ messages: messages,
72
+ max_tokens: 1000,
73
+ temperature: 0.1
63
74
  }.to_json
64
75
  end
65
76
 
@@ -44,13 +44,27 @@ module ChatgptAssistant
44
44
  ActiveRecord::Base.logger = Logger.new($stdout) if ENV["ENV_TYPE"] == "development"
45
45
  end
46
46
 
47
+ def create_db
48
+ db_connection
49
+ return if database_exists?
50
+
51
+ ActiveRecord::Base.establish_connection(
52
+ adapter: "postgresql",
53
+ host: database_host,
54
+ port: 5432,
55
+ database: "postgres",
56
+ username: database_username,
57
+ password: database_password
58
+ )
59
+ ActiveRecord::Base.logger = Logger.new($stdout) if ENV["ENV_TYPE"] == "development"
60
+ ActiveRecord::Base.connection.create_database(database_name)
61
+ end
62
+
47
63
  def migrate
48
64
  db_connection
49
- ActiveRecord::Base.logger = Logger.new($stdout)
65
+ ActiveRecord::Base.logger = Logger.new($stdout) if ENV["ENV_TYPE"] == "development"
50
66
  VisitorMigration.new.migrate(:up)
51
- VisitorActionsMigration.new.migrate(:up)
52
67
  UserMigration.new.migrate(:up)
53
- UserActionsMigration.new.migrate(:up)
54
68
  ChatMigration.new.migrate(:up)
55
69
  MessageMigration.new.migrate(:up)
56
70
  ErrorMigration.new.migrate(:up)
@@ -59,5 +73,11 @@ module ChatgptAssistant
59
73
  private
60
74
 
61
75
  attr_reader :database_host, :database_name, :database_username, :database_password
76
+
77
+ def database_exists?
78
+ ActiveRecord::Base.connection
79
+ rescue ActiveRecord::NoDatabaseError
80
+ false
81
+ end
62
82
  end
63
83
  end
@@ -3,15 +3,15 @@
3
3
  module ChatgptAssistant
4
4
  # This class is responsible for storing the default messages
5
5
  class DefaultMessages
6
- def initialize(language = "en")
6
+ def initialize(language = "en", _discord_prefix = "!")
7
7
  @language = language
8
8
  load_message_context
9
9
  end
10
10
 
11
- attr_reader :language, :commom_messages, :success_messages, :error_messages, :help_messages
11
+ attr_reader :language, :common_messages, :success_messages, :error_messages, :help_messages
12
12
 
13
13
  def load_message_context
14
- @commom_messages = send("commom_messages_#{language}")
14
+ @common_messages = send("common_messages_#{language}")
15
15
  @success_messages = send("success_messages_#{language}")
16
16
  @error_messages = send("error_messages_#{language}")
17
17
  @help_messages = send("help_messages_#{language}")
@@ -19,7 +19,7 @@ module ChatgptAssistant
19
19
 
20
20
  private
21
21
 
22
- def commom_messages_pt
22
+ def common_messages_pt
23
23
  {
24
24
  start: "Olá, eu sou o Chatgpt Assistant, um chatbot que usa a API da OpenAI para responder suas perguntas no Telegram e Discord.",
25
25
  stop: "Até mais!",
@@ -42,6 +42,7 @@ module ChatgptAssistant
42
42
  chat_created: "Chat criado com sucesso!",
43
43
  chat_selected: "Chat selecionado com sucesso!",
44
44
  user_logged_in: "Login realizado com sucesso!",
45
+ user_logged_out: "Logout realizado com sucesso!",
45
46
  voice_channel_connected: "O bot entrou no canal de voz com sucesso!"
46
47
  }
47
48
  end
@@ -49,26 +50,34 @@ module ChatgptAssistant
49
50
  def error_messages_pt
50
51
  {
51
52
  nil: "Não entendi o que você disse. Tente novamente",
52
- email: "O email que você digitou não é válido. Tente novamente",
53
- password: "A senha que você digitou não é válida. Tente novamente",
53
+ wrong_email: "O email que você digitou não é válido. Tente novamente",
54
54
  wrong_password: "A senha que você digitou não é válida. Tente novamente",
55
- user: "O usuário que você digitou não existe. Tente novamente",
56
- user_creation: "Erro ao criar usuário. Tente novamente",
55
+
57
56
  user_already_exists: "O usuário que você digitou já existe. Tente novamente",
58
- chat_creation: "Erro ao criar chat. Tente novamente",
59
- no_messages_founded: "Nenhuma mensagem encontrada",
57
+ chat_already_exists: "Você possui um chat com este titulo. Tente novamente",
58
+
59
+ no_register_info: "Você não digitou o email e a senha. Tente novamente",
60
+ sign_up_error: "Erro ao criar usuário. Tente novamente",
61
+ chat_not_created_error: "Erro ao criar chat. Tente novamente",
62
+ message_not_created_error: "Erro ao criar mensagem. Tente novamente",
60
63
  no_chat_selected: "Nenhum chat selecionado",
61
- chat_not_found: "Chat não encontrado",
64
+
65
+ no_messages_founded: "Nenhuma mensagem encontrada",
62
66
  no_chats_founded: "Nenhum chat encontrado",
67
+ chat_not_found: "Chat não encontrado",
68
+ user_not_found: "O usuário que você digitou não existe. Tente novamente",
69
+ user_not_registered: "O usuário não está registrado no sistema",
70
+ user_logged_in: "Usuário está logado no sistema, faça logout para continuar",
63
71
  user_not_logged_in: "Usuário não logado",
64
- user_not_found: "Usuário não encontrado",
65
- something_went_wrong: "Algo deu errado. Tente novamente mais tarde.",
66
- message_history_too_long: "O histórico mensagem é muito longo.",
67
- text_length: "O texto de resposta é muito longo. Tente diminuir a quantidade de respostas na mesma mensagem.",
72
+
68
73
  user_not_in_voice_channel: "Você não está em um canal de voz.",
69
74
  bot_not_in_voice_channel: "O bot não está em um canal de voz.",
75
+
76
+ message_history_too_long: "O histórico mensagem é muito longo.",
77
+ text_length_too_long: "O texto de resposta é muito longo. Tente diminuir a quantidade de respostas na mesma mensagem.",
78
+
70
79
  invalid_command: "Comando inválido. Tente novamente.",
71
- message_creation_error: "Erro ao criar mensagem. Tente novamente."
80
+ something_went_wrong: "Algo deu errado. Tente novamente mais tarde."
72
81
  }
73
82
  end
74
83
 
@@ -83,7 +92,18 @@ module ChatgptAssistant
83
92
  "Para ver esta mensagem novamente, digite /help"]
84
93
  end
85
94
 
86
- def commom_messages_en
95
+ def help_message_discord_pt
96
+ ["Para começar a conversar comigo, digite #{discord_prefix}start",
97
+ "Para parar de conversar comigo, digite #{discord_prefix}stop",
98
+ "Para se registrar no sistema, digite #{discord_prefix}register email:senha (a senha deve ser um numero de 4 digitos ex: 1234)",
99
+ "Para fazer login no sistema, digite #{discord_prefix}login email:senha (a senha deve ser um numero de 4 digitos ex: 1234)",
100
+ "Para criar um novo chat, digite #{discord_prefix}new_chat nome do chat",
101
+ "Para selecionar um chat, digite #{discord_prefix}sl_chat nome do chat",
102
+ "Para listar os chats que você criou, digite #{discord_prefix}list",
103
+ "Para ver esta mensagem novamente, digite #{discord_prefix}help"]
104
+ end
105
+
106
+ def common_messages_en
87
107
  {
88
108
  start: "Hello, I'm the Chatgpt Assistant, a chatbot that uses the OpenAI API to answer your questions on Telegram and Discord.",
89
109
  stop: "See you later!",
@@ -105,32 +125,43 @@ module ChatgptAssistant
105
125
  user_created: "User created successfully!",
106
126
  chat_created: "Chat created successfully!",
107
127
  chat_selected: "Chat selected successfully!",
108
- user_logged_in: "Login successfully!"
128
+ user_logged_in: "Login successfully!",
129
+ user_logged_out: "Logout successfully!",
130
+ voice_channel_connected: "The bot entered the voice channel successfully!"
109
131
  }
110
132
  end
111
133
 
112
134
  def error_messages_en
113
135
  {
114
- nil: "I didn't understand what you said. Try again",
115
- email: "The email you typed is not valid. Try again",
116
- password: "The password you typed is not valid. Try again",
136
+ nil: "I don't understand what you said. Try again",
137
+ wrong_email: "The email you typed is not valid. Try again",
117
138
  wrong_password: "The password you typed is not valid. Try again",
118
- user: "The user you typed does not exist. Try again",
119
- user_creation: "Error creating user. Try again",
120
- chat_creation: "Error creating chat. Try again",
121
- no_messages_founded: "No messages found",
139
+
140
+ user_already_exists: "The user you typed already exists. Try again",
141
+ chat_already_exists: "You already have a chat with this title. Try again",
142
+
143
+ no_register_info: "You did not type the email and password. Try again",
144
+ sign_up_error: "Error creating user. Try again",
145
+ chat_not_created_error: "Error creating chat. Try again",
146
+ message_not_created_error: "Error creating message. Try again",
122
147
  no_chat_selected: "No chat selected",
148
+
149
+ no_messages_founded: "No messages found",
123
150
  no_chats_founded: "No chats found",
124
151
  chat_not_found: "Chat not found",
152
+ user_not_found: "The user you typed does not exist. Try again",
153
+ user_not_registered: "The user is not registered in the system",
154
+ user_logged_in: "User is logged in the system, do logout to continue",
125
155
  user_not_logged_in: "User not logged in",
126
- user_not_found: "User not found",
127
- something_went_wrong: "Something went wrong. Try again later.",
128
- message_history_too_long: "The message history is too long.",
129
- text_length: "The response text is too long. Try to reduce the number of answers in the same message.",
156
+
130
157
  user_not_in_voice_channel: "You are not in a voice channel.",
131
158
  bot_not_in_voice_channel: "The bot is not in a voice channel.",
159
+
160
+ message_history_too_long: "The message history is too long.",
161
+ text_length_too_long: "The response text is too long. Try to reduce the number of responses in the same message.",
162
+
132
163
  invalid_command: "Invalid command. Try again.",
133
- message_creation_error: "Error creating message. Try again."
164
+ something_went_wrong: "Something went wrong. Try again later."
134
165
  }
135
166
  end
136
167
 
@@ -144,5 +175,16 @@ module ChatgptAssistant
144
175
  "To list the chats you created, type /list",
145
176
  "To see this message again, type /help"]
146
177
  end
178
+
179
+ def help_message_discord_en
180
+ ["To start talking to me, type #{discord_prefix}start",
181
+ "To stop talking to me, type #{discord_prefix}stop",
182
+ "To register in the system, type #{discord_prefix}register email:password (the password must be a 4 digit number ex: 1234)",
183
+ "To log in to the system, type #{discord_prefix}login email:password (the password must be a 4 digit number ex: 1234)",
184
+ "To create a new chat, type #{discord_prefix}new_chat chat name",
185
+ "To select a chat, type #{discord_prefix}sl_chat chat name",
186
+ "To list the chats you created, type #{discord_prefix}list",
187
+ "To see this message again, type #{discord_prefix}help"]
188
+ end
147
189
  end
148
190
  end