chatgpt_assistant 0.1.4 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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