chatgpt_assistant 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 JesusGautamah
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # ChatGPT Assistant
2
+
3
+ This Ruby gem provides an easy way to initialize a client for Telegram and Discord bots using the ChatGPT API, audio transcription, IBM Cloud Text to Speech, and AWS Polly, creating an assistant that can answer questions in text and voice and have a conversation with the user.
4
+
5
+ ## Requirements
6
+
7
+ - Ruby > 2.6.0
8
+ - Docker
9
+ - Docker Compose
10
+
11
+ ## Installation
12
+
13
+ To install the gem, run:
14
+
15
+ ```bash
16
+ gem install chatgpt_assistant
17
+ ```
18
+
19
+ Then, edit the .env_sample file to include the necessary credentials and rename it to .env. Run bundle install to install the necessary dependencies.
20
+
21
+ Remember to edit docker-compose.prod.yml when deploying to production.
22
+
23
+ Alternatively, you can clone/fork this repo to use it as you wish.
24
+
25
+ ### Installation as a gem example
26
+
27
+ ```bash
28
+ gem install chatgpt_assistant
29
+ chatgpt_assistant PATH_TO_FOLDER
30
+ cd PATH_TO_FOLDER
31
+ cp .env_sample .env
32
+ bundle install
33
+ ```
34
+
35
+ ## Installation as a repo
36
+ Run in your terminal:
37
+ ```bash
38
+ git clone https://github.com/JesusGautamah/chatgpt_assistant.git
39
+ cd chatgpt_assistant
40
+ cp .env_sample .env
41
+ bundle install
42
+ ```
43
+
44
+ Make sure to run bundle before using the Lucy Dockerunner rake tasks.
45
+
46
+ ## Usage
47
+
48
+ You can start the Docker Compose services required for the gem using the rake tasks provided by the Lucy Dockerunner gem. These tasks include compose:up, compose:down, compose:status, compose:shell, compose:restart, and others listed previously.
49
+
50
+ For example, to start the services, run:
51
+
52
+ ```ruby
53
+ rake compose:up
54
+ ```
55
+
56
+
57
+ To stop the services, run:
58
+
59
+ ```ruby
60
+ rake compose:down
61
+ ```
62
+
63
+ After starting the Docker Compose services, you can use the features of the gem to create a chat assistant that responds to questions in both text and voice using the services mentioned above.
64
+
65
+ ## More commands at https://github.com/JesusGautamah/lucy_dockerunner
66
+
67
+ ## Contributing
68
+
69
+ Bug reports and pull requests are welcome on GitHub at https://github.com/JesusGautamah/chatgpt_assistant. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/JesusGautamah/chatgpt_assistant/blob/master/CODE_OF_CONDUCT.md).
70
+
71
+ ## License
72
+
73
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
74
+
75
+ ## Code of Conduct
76
+
77
+ Everyone interacting in the ChatgptAssistant project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/JesusGautamah/chatgpt_assistant/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+ require "lucy_dockerunner"
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ require "rubocop/rake_task"
10
+
11
+ RuboCop::RakeTask.new
12
+
13
+ task default: %i[spec rubocop]
14
+
15
+ LucyDockerunner.load_tasks
data/deploy.sh ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin bash
2
+
3
+ # This script is used to deploy the application to the server
4
+
5
+ echo "Deploying the application to the server..."
6
+ cd chatgpt_assistant
7
+ git pull
8
+ sudo docker compose up -d
9
+ sudo docker compose restart
10
+ echo "Deployed the application to the server"
@@ -0,0 +1,11 @@
1
+ #!/usr/bin bash
2
+
3
+ # This script is used to deploy the application to the server
4
+
5
+ echo "Deploying the application to the server..."
6
+ cd chatgpt_assistant
7
+ git pull
8
+ sudo docker compose build
9
+ sudo docker compose up -d
10
+ sudo docker compose restart
11
+ echo "Deployed the application to the server"
@@ -0,0 +1,34 @@
1
+ version: "3.3"
2
+ services:
3
+ db:
4
+ image: postgres:12.2
5
+ ports:
6
+ - "5432:5432"
7
+ volumes:
8
+ - ./db_data:/var/lib/postgresql/data
9
+ env_file:
10
+ - .env
11
+ telegram:
12
+ build: .
13
+ command: bash -c "exe/chatgpt_bot telegram"
14
+ volumes:
15
+ - .:/chatgpt_assistant
16
+ environment:
17
+ POSTGRES_HOST: db
18
+ env_file:
19
+ - .env
20
+ depends_on:
21
+ - db
22
+ discord:
23
+ build: .
24
+ command: bash -c "exe/chatgpt_bot discord"
25
+ volumes:
26
+ - .:/chatgpt_assistant
27
+ environment:
28
+ POSTGRES_HOST: db
29
+ env_file:
30
+ - .env
31
+ depends_on:
32
+ - db
33
+ volumes:
34
+ postgres:
@@ -0,0 +1,34 @@
1
+ version: "3.3"
2
+ services:
3
+ db:
4
+ image: postgres:12.2
5
+ ports:
6
+ - "5432:5432"
7
+ volumes:
8
+ - ./db_data:/var/lib/postgresql/data
9
+ env_file:
10
+ - .env
11
+ telegram:
12
+ build: .
13
+ command: bash -c "exe/chatgpt_bot telegram"
14
+ volumes:
15
+ - .:/chatgpt_assistant
16
+ environment:
17
+ POSTGRES_HOST: db
18
+ env_file:
19
+ - .env
20
+ depends_on:
21
+ - db
22
+ discord:
23
+ build: .
24
+ command: bash -c "exe/chatgpt_bot discord"
25
+ volumes:
26
+ - .:/chatgpt_assistant
27
+ environment:
28
+ POSTGRES_HOST: db
29
+ env_file:
30
+ - .env
31
+ depends_on:
32
+ - db
33
+ volumes:
34
+ postgres:
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ path = ARGV[0]
5
+ raise "Please specify the path to copy files to" if path.nil?
6
+
7
+ puts "Creating new chatgpt assistant at #{path}"
8
+
9
+ `mkdir -p #{path}`
10
+
11
+ raise "Path must be empty" unless Dir.empty?(path)
12
+
13
+ gem_dir = Gem::Specification.find_by_name("chatgpt_assistant").gem_dir
14
+
15
+ `cp -r #{gem_dir}/lib #{path}`
16
+
17
+ `mkdir -p #{path}/exe`
18
+
19
+ `cp #{gem_dir}/exe/chatgpt_bot #{path}/exe`
20
+
21
+ `mkdir -p #{path}/logs`
22
+
23
+ `mkdir -p #{path}/voice`
24
+
25
+ %w[Gemfile Gemfile.lock README.md Rakefile .env_sample .rubocop.yml .rspec].each do |file|
26
+ `cp #{gem_dir}/#{file} #{path}`
27
+ end
28
+
29
+ %w[docker-compose.yml docker-compose.prod.yml Dockerfile LICENSE LICENSE.txt].each do |file|
30
+ `cp #{gem_dir}/#{file} #{path}`
31
+ end
32
+
33
+ %w[/.bundle/ /.yardoc /_yardoc/ /coverage/ /doc/ /pkg/ /spec/reports/ /tmp/ /db_data /db_data/*
34
+ .rspec_status .env /logs/telegram_chatgpt.log /voice/audio* /voice/ibm* /voice/polly* /voice/aws*].each do |file_to_ignore|
35
+ `echo "#{file_to_ignore}" >> #{path}/.gitignore`
36
+ end
37
+
38
+ `cd #{path} && git init`
39
+
40
+ puts "Done! Now you can run 'cd #{path} && bundle install'"
41
+ puts "Build the docker image with 'rake compose:build'"
42
+ puts "Run the bot with 'rake compose:up'"
43
+ puts "For more information, see the README.md file"
data/exe/chatgpt_bot ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../lib/chatgpt_assistant"
5
+
6
+ puts "Starting Chatgpt Assistant"
7
+ puts "Bot Type: #{ARGV[0]}"
8
+ puts "Mode: #{ENV["MODE"]}"
9
+ case ARGV[0]
10
+ when "telegram"
11
+ ChatgptAssistant::Main.new("telegram").start
12
+ when "discord"
13
+ ChatgptAssistant::Main.new("discord").start
14
+ when "migrate"
15
+ ChatgptAssistant::Config.new.migrate
16
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChatgptAssistant
4
+ # This class is responsible to contain the shared variables between the bot classes
5
+ class ApplicationBot
6
+ def initialize(config)
7
+ @config = config
8
+ default_msg = DefaultMessages.new(@config.language)
9
+ @logger = ChatterLogger.new
10
+ @openai_api_key = @config.openai_api_key
11
+ @telegram_token = @config.telegram_token
12
+ @discord_token = @config.discord_token
13
+ @discord_client_id = @config.discord_client_id
14
+ @discord_prefix = @config.discord_prefix
15
+ @database = @config.db_connection
16
+ @mode = @config.mode
17
+ @commom_messages = default_msg.commom_messages
18
+ @error_messages = default_msg.error_messages
19
+ @success_messages = default_msg.success_messages
20
+ @help_messages = default_msg.help_messages
21
+ end
22
+
23
+ def chatter
24
+ @chatter ||= Chatter.new(openai_api_key)
25
+ end
26
+
27
+ def audio_recognition
28
+ @audio_recognition ||= AudioRecognition.new(openai_api_key)
29
+ end
30
+
31
+ def audio_synthesis
32
+ @audio_synthesis ||= AudioSynthesis.new(config)
33
+ end
34
+
35
+ def message_create(message, chat_id, role)
36
+ Message.create(content: message, chat_id: chat_id, role: role)
37
+ end
38
+
39
+ def find_useremail(email)
40
+ User.find_by(email: email)
41
+ end
42
+
43
+ def find_userdiscord(discord_id)
44
+ User.find_by(discord_id: discord_id)
45
+ end
46
+
47
+ def find_usertelegram(telegram_id)
48
+ User.find_by(telegram_id: telegram_id)
49
+ end
50
+
51
+ def valid_password?(user, password)
52
+ return false if password.nil?
53
+
54
+ salt = user.password_salt
55
+ password_hash = user.password_hash
56
+
57
+ BCrypt::Engine.hash_secret(password, salt) == password_hash
58
+ end
59
+
60
+ def auth_userdiscord(email, password, discord_id)
61
+ user = find_useremail(email)
62
+ return "user not found" unless user
63
+ return "wrong password" if password.nil?
64
+
65
+ valid_password?(user, password) ? user_disc_access(discord_id, user.email) : "wrong password"
66
+ end
67
+
68
+ def user_disc_access(discord_id, user_email)
69
+ last_access = find_userdiscord(discord_id)
70
+ new_access = find_useremail(user_email)
71
+ last_acess.update(discord_id: nil) if last_access && (last_access != new_access)
72
+ new_access.update(discord_id: discord_id)
73
+ new_access
74
+ end
75
+
76
+ def discord_user_create(discord_id, email, password, name)
77
+ user = User.new(discord_id: discord_id, email: email, password_hash: password, name: name)
78
+ last_access = find_userdiscord(discord_id)
79
+ last_access&.update(discord_id: nil)
80
+ user.save
81
+ end
82
+
83
+ def auth_usertelegram(email, password, telegram_id)
84
+ user = find_useremail(email)
85
+ return "user not found" unless user
86
+ return "wrong password" if password.nil?
87
+
88
+ valid_password?(user, password) ? user_tele_access(telegram_id, user.email) : "wrong password"
89
+ end
90
+
91
+ def user_tele_access(telegram_id, user_email)
92
+ last_access = find_usertelegram(telegram_id)
93
+ new_access = find_useremail(user_email)
94
+ last_acess.update(telegram_id: nil) if last_access && (last_access != new_access)
95
+ new_access.update(telegram_id: telegram_id)
96
+ new_access
97
+ end
98
+
99
+ def telegram_user_create(telegram_id, email, password, name)
100
+ user = User.new(telegram_id: telegram_id, email: email, password_hash: password, name: name)
101
+ last_access = find_usertelegram(telegram_id)
102
+ last_access&.update(telegram_id: nil)
103
+ user.save
104
+ end
105
+
106
+ def delete_all_voice_files
107
+ Dir.glob("voice/*").each do |file|
108
+ next if [".keep", "voice/.keep"].include?(file)
109
+
110
+ File.delete(file)
111
+ end
112
+ end
113
+
114
+ attr_reader :openai_api_key, :telegram_token, :database, :default_msg,
115
+ :logger, :mode, :config, :discord_token, :discord_client_id,
116
+ :discord_prefix, :commom_messages, :error_messages, :success_messages,
117
+ :help_messages
118
+ end
119
+ end
@@ -0,0 +1,304 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ChatgptAssistant
4
+ # This class is responsible to handle the discord bot
5
+ class DiscordBot < ApplicationBot
6
+ def start
7
+ start_logs
8
+ start_event
9
+ login_event
10
+ register_event
11
+ list_event
12
+ hist_event
13
+ help_event
14
+ new_chat_event
15
+ sl_chat_event
16
+ ask_event
17
+ voice_connect_event
18
+ disconnect_event
19
+ speak_event
20
+ bot_init
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :message
26
+ attr_accessor :evnt, :user, :chats, :chat
27
+
28
+ def bot
29
+ @bot ||= Discordrb::Commands::CommandBot.new(
30
+ token: discord_token,
31
+ client_id: discord_client_id,
32
+ prefix: discord_prefix
33
+ )
34
+ end
35
+
36
+ def start_logs
37
+ logger.log("Starting Discord bot")
38
+ logger.log("Discord Prefix: #{discord_prefix}")
39
+ end
40
+
41
+ def start_event
42
+ bot.command :start do |event|
43
+ @evnt = event
44
+ @user = event.user
45
+ start_action
46
+ end
47
+ logger.log("Start Event Configured")
48
+ end
49
+
50
+ def start_action
51
+ logger.log("USER: #{user.username} - #{user.id}\n MESSAGE: #{event.message.content}")
52
+ evnt.respond commom_messages[:start]
53
+ evnt.respond commom_messages[:start_helper].gsub("register/", "gpt!register ")
54
+ evnt.respond commom_messages[:start_sec_helper].gsub("login/", "gpt!login ")
55
+ end
56
+
57
+ def login_event
58
+ bot.command :login do |event|
59
+ @message = event.message.content.split(" ")[1]
60
+ @evnt = event
61
+ message.nil? ? event.respond(commom_messages[:login]) : login_action
62
+ end
63
+ logger.log("Login Event Configured")
64
+ end
65
+
66
+ def login_action
67
+ user_email = message.split(":")[0]
68
+ user_password = message.split(":")[1]
69
+ case auth_userdiscord(user_email, user_password, evnt.user.id)
70
+ when "user not found"
71
+ logger.log("User not found: #{user_email}")
72
+ evnt.respond error_messages[:user_not_found]
73
+ when "wrong password"
74
+ logger.log("Wrong password: #{user_email}")
75
+ evnt.respond error_messages[:wrong_password]
76
+ when find_useremail(user_email)
77
+ logger.log("User logged in: #{user_email}")
78
+ evnt.respond success_messages[:user_logged_in]
79
+ end
80
+ end
81
+
82
+ def register_event
83
+ bot.command :register do |event|
84
+ @message = event.message.content.split(" ")[1]
85
+ @evnt = event
86
+ message.nil? ? event.respond(commom_messages[:register]): register_action
87
+ end
88
+ logger.log("Register Event Configured")
89
+ end
90
+
91
+ def register_action
92
+ user_email = message.split(":")[0]
93
+ user_password = message.split(":")[1]
94
+ find_useremail(user_email).nil? ? create_user_action(user_email, user_password) : evnt.respond(error_messages[:user_already_exists])
95
+ end
96
+
97
+ def create_user_action(mail, pass)
98
+ logger.log("Creating user #{mail}")
99
+ id = evnt.user.id
100
+ name = evnt.user.username
101
+ discord_user_create(id, mail, pass, name) ? evnt.respond(success_messages[:user_created]) : evnt.respond(error_messages[:user_not_created])
102
+ end
103
+
104
+ def list_event
105
+ bot.command :list do |event|
106
+ @evnt = event
107
+ @user = User.find_by(discord_id: event.user.id)
108
+ event.respond error_messages[:user_not_logged_in] if user.nil?
109
+
110
+ @chats = Chat.where(user_id: user.id) if user
111
+ event.respond error_messages[:chat_not_found] if chats.empty? && user
112
+
113
+ list_action if user && !chats.empty?
114
+ end
115
+ logger.log("List Event Configured")
116
+ end
117
+
118
+ def list_action
119
+ chats_title = chats.map(&:title)
120
+ evnt.respond commom_messages[:chat_list]
121
+ evnt.respond chats_title.join("\n")
122
+ end
123
+
124
+ def hist_event
125
+ bot.command :hist do |event|
126
+ @evnt = event
127
+ @user = User.find_by(discord_id: event.user.id)
128
+ event.respond error_messages[:user_not_logged_in] if user.nil?
129
+ title = event.message.content.split(" ")[1 .. -1].join(" ")
130
+ @chat = Chat.find_by(user_id: user.id, title: title) if user
131
+ event.respond error_messages[:chat_not_found] if chat.nil? && user
132
+ hist_action if user && chat
133
+ end
134
+ logger.log("Hist Event Configured")
135
+ end
136
+
137
+ def hist_action
138
+ messages = Message.where(chat_id: chat.id).order(:created_at)
139
+ messages.each do |message|
140
+ evnt.respond "#{message.role} - #{message.content}\n#{message.created_at.strftime("%d/%m/%Y %H:%M")}"
141
+ end
142
+ "This is the end of the chat history"
143
+ end
144
+
145
+ def help_event
146
+ bot.command :help do |event|
147
+ @evnt = event
148
+ help_action
149
+ end
150
+ logger.log("Help Event Configured")
151
+ end
152
+
153
+ def help_action
154
+ message = help_messages.join("\n").gsub(" /", " gpt!")
155
+ .gsub("register/", "gpt!register ")
156
+ .gsub("login/", "gpt!login ")
157
+ .gsub("new_chat/", "gpt!new_chat/")
158
+ .gsub("sl_chat/", "gpt!sl_chat/")
159
+ evnt.respond message
160
+ end
161
+
162
+ def new_chat_event
163
+ bot.command :new_chat do |event|
164
+ @evnt = event
165
+ @user = User.find_by(discord_id: event.user.id)
166
+ event.respond error_messages[:user_not_logged_in] if user.nil?
167
+ create_chat_action if user
168
+ end
169
+ logger.log("New Chat Event Configured")
170
+ end
171
+
172
+ def create_chat_action
173
+ chat_title = event.message.content.split(" ")[1..].join(" ")
174
+ chat = Chat.new(user_id: user.id, title: chat_title, status: 0)
175
+ chat.save ? respond_with_success : evnt.respond(error_messages[:chat_creation])
176
+ end
177
+
178
+ def respond_with_success
179
+ user.update(current_chat_id: chat.id)
180
+ evnt.respond success_messages[:chat_created]
181
+ end
182
+
183
+ def sl_chat_event
184
+ bot.command :sl_chat do |event|
185
+ @evnt = event
186
+ chat_to_select = event.message.content.split(" ")[1..].join(" ")
187
+
188
+ @user = User.find_by(discord_id: event.user.id)
189
+ event.respond error_messages[:user_not_logged_in] if user.nil?
190
+
191
+ sl_chat_action(chat_to_select) if user
192
+ end
193
+ logger.log("SL Chat Event Configured")
194
+ end
195
+
196
+ def sl_chat_action(chat_to_select)
197
+ @chat = Chat.find_by(title: chat_to_select, user_id: user.id)
198
+ evnt.respond error_messages[:chat_not_found] if chat.nil?
199
+ user.update(current_chat_id: chat.id) if chat
200
+ evnt.respond success_messages[:chat_selected] if chat
201
+ end
202
+
203
+ def ask_event
204
+ bot.command :ask do |event|
205
+ @evnt = event
206
+ @message = event.message.content.split(" ")[1..].join(" ")
207
+ @user = User.find_by(discord_id: event.user.id)
208
+ event.respond error_messages[:user_not_logged_in] if user.nil?
209
+ ask_action if user
210
+ end
211
+ logger.log("Ask Event Configured")
212
+ end
213
+
214
+ def ask_action
215
+ @chat = Chat.where(id: user.current_chat_id).last
216
+ evnt.respond error_messages[:chat_not_found] if chat.nil?
217
+ @message = Message.new(chat_id: chat.id, content: message, role: "user") if chat
218
+ (message.save ? answer_action : evnt.respond(error_messages[:message_not_saved])) if chat
219
+ end
220
+
221
+ def answer_action
222
+ response = chatter.chat(message.content, chat.id)
223
+ evnt.respond response
224
+ end
225
+
226
+ def voice_connect_event
227
+ bot.command :connect do |event|
228
+ @evnt = event
229
+ @user = User.find_by(discord_id: event.user.id)
230
+ @chat = Chat.where(id: user.current_chat_id).last
231
+ event.respond error_messages[:user_not_logged_in] if user.nil?
232
+ event.respond error_messages[:chat_not_found] if user && chat.nil?
233
+ event.respond error_messages[:user_not_in_voice_channel] if event.user.voice_channel.nil? && user
234
+ event.respond error_messages[:bot_already_connected] if event.voice && user
235
+ bot.voice_connect(event.user.voice_channel) if bot_disconnected?
236
+ "Connected to voice channel" if bot_connected?
237
+ end
238
+ logger.log("Voice Connect Event Configured")
239
+ end
240
+
241
+ def bot_disconnected?
242
+ user && evnt.user.voice_channel && !evnt.voice && !chat.nil?
243
+ end
244
+
245
+ def bot_connected?
246
+ user && evnt.user.voice_channel && evnt.voice && !chat.nil?
247
+ end
248
+
249
+ def disconnect_event
250
+ bot.command :disconnect do |event|
251
+ @evnt = event
252
+ @user = User.find_by(discord_id: event.user.id)
253
+ event.respond error_messages[:user_not_logged_in] if user.nil?
254
+ event.respond error_messages[:user_not_in_voice_channel] if event.user.voice_channel.nil? && user
255
+ event.respond error_messages[:user_not_connected] if !event.voice && user
256
+ disconnect_action if user && event.user.voice_channel && event.voice
257
+ end
258
+ logger.log("Disconnect Event Configured")
259
+ end
260
+
261
+ def disconnect_action
262
+ logger.log("Disconnecting from voice channel: #{evnt.user.voice_channel.name}")
263
+ bot.voice_destroy(event.user.voice_channel)
264
+ logger.log("Disconnected from voice channel: #{evnt.user.voice_channel.name}")
265
+ "Disconnected from voice channel"
266
+ end
267
+
268
+ def speak_event
269
+ bot.command :speak do |event|
270
+ @evnt = event
271
+ @message = event.message.content.split(" ")[1..].join(" ")
272
+ @user = User.find_by(discord_id: event.user.id)
273
+ @chat = Chat.where(id: user.current_chat_id).last
274
+ event.respond error_messages[:user_not_logged_in] if user.nil?
275
+ event.respond error_messages[:user_not_in_voice_channel] if event.user.voice_channel.nil? && user
276
+ event.respond error_messages[:bot_not_in_voice_channel] if !event.voice && user
277
+ event.respond error_messages[:chat_not_found] if user && event.user.voice_channel && event.voice && chat.nil?
278
+ ask_to_speak_action if user && event.user.voice_channel && event.voice && !chat.nil?
279
+ end
280
+ end
281
+
282
+ def ask_to_speak_action
283
+ Message.create(chat_id: chat.id, content: message, role: "user")
284
+ response = chatter.chat(message, chat.id)
285
+ audio_path = audio_synthesis.synthesize_text(response)
286
+ speak_answer_action(audio_path, response)
287
+ end
288
+
289
+ def speak_answer_action(audio_path, response)
290
+ evnt.respond response
291
+ evnt.voice.play_file(audio_path)
292
+ delete_all_voice_files
293
+ "OK"
294
+ end
295
+
296
+ def bot_init
297
+ logger.log("Discord bot started")
298
+ at_exit { bot.stop }
299
+ bot.run
300
+ rescue StandardError
301
+ start
302
+ end
303
+ end
304
+ end