slack-smart-bot 1.15.0 → 1.15.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +34 -1
- data/img/chat_gpt_attach_image.png +0 -0
- data/lib/slack/smart-bot/ai/open_ai/models.rb +19 -10
- data/lib/slack/smart-bot/ai/open_ai/send_gpt_chat.rb +14 -10
- data/lib/slack/smart-bot/comm/dont_understand.rb +23 -6
- data/lib/slack/smart-bot/comm/get_user_info.rb +9 -10
- data/lib/slack/smart-bot/comm/respond.rb +56 -28
- data/lib/slack/smart-bot/comm/send_file.rb +17 -6
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat.rb +885 -129
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_add_collaborator.rb +3 -3
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_copy_session.rb +132 -15
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_delete_session.rb +1 -1
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_get_prompts.rb +50 -12
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_list_sessions.rb +99 -34
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_share_session.rb +12 -2
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_use_model.rb +36 -25
- data/lib/slack/smart-bot/commands/general/bot_help.rb +29 -24
- data/lib/slack/smart-bot/commands/general/poster.rb +0 -1
- data/lib/slack/smart-bot/commands/general/see_announcements.rb +1 -1
- data/lib/slack/smart-bot/commands/general/summarize.rb +22 -8
- data/lib/slack/smart-bot/commands/general_bot_commands.rb +156 -55
- data/lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb +13 -11
- data/lib/slack/smart-bot/commands/on_extended/bot_rules.rb +21 -17
- data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +2 -2
- data/lib/slack/smart-bot/commands.rb +19 -19
- data/lib/slack/smart-bot/process_first.rb +38 -35
- data/lib/slack/smart-bot/treat_message.rb +57 -56
- data/lib/slack/smart-bot/utils/download_http_content.rb +91 -0
- data/lib/slack/smart-bot/utils/get_authorizations.rb +41 -0
- data/lib/slack/smart-bot/utils/get_keywords.rb +33 -0
- data/lib/slack/smart-bot/utils/get_openai_sessions.rb +46 -6
- data/lib/slack/smart-bot/utils/get_teams.rb +9 -1
- data/lib/slack/smart-bot/utils/save_stats.rb +13 -5
- data/lib/slack/smart-bot/utils/transform_to_slack_markdown.rb +36 -0
- data/lib/slack/smart-bot/utils/update_openai_sessions.rb +9 -4
- data/lib/slack/smart-bot/utils.rb +48 -44
- data/lib/slack-smart-bot.rb +10 -10
- data/whats_new.txt +27 -1
- metadata +49 -8
@@ -3,41 +3,74 @@ class SlackSmartBot
|
|
3
3
|
module General
|
4
4
|
module AI
|
5
5
|
module OpenAI
|
6
|
-
def open_ai_chat(message, delete_history, type, model:
|
6
|
+
def open_ai_chat(message, delete_history, type, model: "", tag: "", description: "", files: [])
|
7
|
+
message.strip!
|
7
8
|
get_personal_settings()
|
8
9
|
user = Thread.current[:user].dup
|
9
10
|
user_name = user.name
|
10
11
|
team_id = user.team_id
|
11
12
|
team_id_user = Thread.current[:team_id_user]
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
success = true
|
14
|
+
if !defined?(@chat_gpt_default_model)
|
15
|
+
#config.ai.open_ai.chat_gpt.model
|
16
|
+
if config.key?(:ai) and config[:ai].key?(:open_ai) and config[:ai][:open_ai].key?(:chat_gpt) and
|
17
|
+
config[:ai][:open_ai][:chat_gpt].key?(:model)
|
18
|
+
@chat_gpt_default_model = config[:ai][:open_ai][:chat_gpt][:model]
|
19
|
+
else
|
20
|
+
@chat_gpt_default_model = ""
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if model != "" and !@open_ai_models.include?(model)
|
25
|
+
open_ai_models("", just_models: true) if @open_ai_models.empty?
|
26
|
+
model_selected = @open_ai_models.select { |m| m.include?(model) }
|
15
27
|
model = model_selected[0] if model_selected.size == 1
|
16
28
|
end
|
17
29
|
|
18
30
|
@active_chat_gpt_sessions[team_id_user] ||= {}
|
19
31
|
if delete_history
|
20
|
-
@active_chat_gpt_sessions[team_id_user][Thread.current[:dest]] =
|
21
|
-
session_name =
|
32
|
+
@active_chat_gpt_sessions[team_id_user][Thread.current[:dest]] = ""
|
33
|
+
session_name = ""
|
22
34
|
end
|
23
|
-
|
24
|
-
if @active_chat_gpt_sessions[team_id_user].key?(Thread.current[:thread_ts]) and Thread.current[:thread_ts]!='' #added and Thread.current[:thread_ts]!='' for testing when SIMULATE==true and not in a thread
|
35
|
+
if @active_chat_gpt_sessions[team_id_user].key?(Thread.current[:thread_ts]) and Thread.current[:thread_ts] != "" #added and Thread.current[:thread_ts]!='' for testing when SIMULATE==true and not in a thread
|
25
36
|
session_name = @active_chat_gpt_sessions[team_id_user][Thread.current[:thread_ts]]
|
26
37
|
elsif @active_chat_gpt_sessions[team_id_user].key?(Thread.current[:dest])
|
27
|
-
|
38
|
+
if type == :temporary
|
39
|
+
session_name = ""
|
40
|
+
@active_chat_gpt_sessions[team_id_user][Thread.current[:dest]] = ""
|
41
|
+
else
|
42
|
+
#:continue_session
|
43
|
+
session_name = @active_chat_gpt_sessions[team_id_user][Thread.current[:dest]]
|
44
|
+
end
|
28
45
|
else
|
29
|
-
session_name =
|
30
|
-
@active_chat_gpt_sessions[team_id_user][Thread.current[:dest]] =
|
46
|
+
session_name = ""
|
47
|
+
@active_chat_gpt_sessions[team_id_user][Thread.current[:dest]] = ""
|
31
48
|
end
|
32
|
-
if
|
49
|
+
if @open_ai.key?(team_id_user) and @open_ai[team_id_user].key?(:chat_gpt) and @open_ai[team_id_user][:chat_gpt].key?(:sessions) and
|
50
|
+
@open_ai[team_id_user][:chat_gpt][:sessions].key?(session_name) and @open_ai[team_id_user][:chat_gpt][:sessions][session_name].key?(:collaborators)
|
51
|
+
collaborators_saved = @open_ai[team_id_user][:chat_gpt][:sessions][session_name][:collaborators]
|
52
|
+
else
|
53
|
+
collaborators_saved = []
|
54
|
+
end
|
55
|
+
|
56
|
+
if type == :start or type == :continue or type == :clean
|
33
57
|
session_name = message
|
58
|
+
|
34
59
|
@active_chat_gpt_sessions[team_id_user] ||= {}
|
35
60
|
@active_chat_gpt_sessions[team_id_user][Thread.current[:thread_ts]] = session_name
|
36
|
-
|
61
|
+
@active_chat_gpt_sessions[team_id_user][Thread.current[:dest]] = session_name
|
62
|
+
message = ""
|
37
63
|
get_openai_sessions(session_name)
|
38
64
|
@open_ai[team_id_user] ||= {}
|
39
65
|
@open_ai[team_id_user][:chat_gpt] ||= {}
|
40
66
|
@open_ai[team_id_user][:chat_gpt][:sessions] ||= {}
|
67
|
+
|
68
|
+
if !@open_ai[team_id_user][:chat_gpt][:sessions].key?(session_name) and
|
69
|
+
(type == :continue or type == :clean)
|
70
|
+
respond "*ChatGPT*: I'm sorry, but I couldn't find a session named *#{session_name}*."
|
71
|
+
return
|
72
|
+
end
|
73
|
+
|
41
74
|
if !@open_ai[team_id_user][:chat_gpt][:sessions].key?(session_name)
|
42
75
|
@open_ai[team_id_user][:chat_gpt][:sessions][session_name] = {
|
43
76
|
team_creator: team_id,
|
@@ -47,33 +80,111 @@ class SlackSmartBot
|
|
47
80
|
collaborators: [],
|
48
81
|
num_prompts: 0,
|
49
82
|
model: model,
|
50
|
-
copy_of_session:
|
51
|
-
copy_of_team:
|
52
|
-
copy_of_user:
|
83
|
+
copy_of_session: "",
|
84
|
+
copy_of_team: "",
|
85
|
+
copy_of_user: "",
|
53
86
|
users_copying: [],
|
87
|
+
temp_copies: 0,
|
88
|
+
own_temp_copies: 0,
|
54
89
|
public: false,
|
55
90
|
shared: [],
|
56
91
|
description: description,
|
57
|
-
tag: tag.downcase
|
92
|
+
tag: tag.downcase,
|
93
|
+
live_content: [],
|
94
|
+
static_content: [],
|
95
|
+
authorizations: {},
|
58
96
|
}
|
59
|
-
else # type == :continue or loading
|
60
|
-
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:model] = model if model !=
|
97
|
+
else # type == :continue or loading or clean
|
98
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:model] = model if model != ""
|
61
99
|
num_prompts = @open_ai[team_id_user][:chat_gpt][:sessions][session_name][:num_prompts]
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
100
|
+
unless type == :clean
|
101
|
+
collaborators_txt = ""
|
102
|
+
if @open_ai[team_id_user][:chat_gpt][:sessions][session_name][:collaborators].size > 0
|
103
|
+
collaborators = @open_ai[team_id_user][:chat_gpt][:sessions][session_name][:collaborators].map do |team_user|
|
104
|
+
team_user.split("_")[1..-1].join("_")
|
105
|
+
end
|
106
|
+
collaborators_txt = ":busts_in_silhouette: Collaborators: `#{collaborators.join("`, `")}`\n"
|
107
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:collaborators].each do |team_id_user_collaborator|
|
108
|
+
@chat_gpt_collaborating[team_id_user_collaborator] ||= {}
|
109
|
+
@chat_gpt_collaborating[team_id_user_collaborator][Thread.current[:thread_ts]] ||= { team_creator: team_id, user_creator: user.name, session_name: session_name }
|
110
|
+
@listening[team_id_user_collaborator] ||= {}
|
111
|
+
@listening[team_id_user_collaborator][Thread.current[:thread_ts]] = Time.now
|
112
|
+
end
|
113
|
+
end
|
114
|
+
if num_prompts > 0
|
115
|
+
respond "*ChatGPT*: I just loaded *#{session_name}*.\n#{collaborators_txt}There are *#{num_prompts} prompts* in this session.\nThis was the *last prompt* from the session:\n"
|
116
|
+
else
|
117
|
+
respond "*ChatGPT*: I just loaded *#{session_name}*.\n#{collaborators_txt}There are *no prompts* in this session."
|
118
|
+
end
|
119
|
+
content = @ai_gpt[team_id_user][session_name]
|
120
|
+
index_last_prompt = content.rindex { |c| c[:role] == "user" and c[:content].size == 1 and c[:content][0][:type] == "text" }
|
121
|
+
index_last_context = content.rindex { |c| c[:role] == "system" and c[:content].size == 1 and c[:content][0][:type] == "text" }
|
122
|
+
if index_last_context
|
123
|
+
last_context = "\n:robot_face: *User>* #{content[index_last_context][:content][0][:text]}\n"
|
124
|
+
else
|
125
|
+
last_context = ""
|
126
|
+
end
|
127
|
+
if !@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:live_content].nil? and
|
128
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:live_content].size > 0
|
129
|
+
live_content = "\n:globe_with_meridians: *Live content*:\n\t\t - `#{@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:live_content].join("`\n\t\t - `")}`"
|
130
|
+
else
|
131
|
+
live_content = ""
|
132
|
+
end
|
133
|
+
if !@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:static_content].nil? and
|
134
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:static_content].size > 0
|
135
|
+
static_content = "\n:pushpin: *Static content*:\n\t\t - `#{@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:static_content].join("`\n\t\t - `")}`"
|
136
|
+
if Thread.current[:dest][0] != "D"
|
137
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:static_content].each do |cont|
|
138
|
+
channel_hist = cont.scan(/\AHistory of <#(\w+)>\Z/im).flatten[0]
|
139
|
+
if channel_hist != Thread.current[:dest]
|
140
|
+
respond ":information_source: I'm sorry this session is trying to load the history of <##{channel_hist}>, but you can only load the history of the channel where you are currently talking or in a DM with me."
|
141
|
+
return
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
else
|
146
|
+
static_content = ""
|
147
|
+
end
|
148
|
+
|
149
|
+
#authorizations
|
150
|
+
if !@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:authorizations].nil? and
|
151
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:authorizations].size > 0
|
152
|
+
auth = "\n:lock: *Authorizations:*\n"
|
153
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:authorizations].each do |host, header|
|
154
|
+
auth += "\t\t - `#{host}`: `#{header.keys.join("`, `")}`\n"
|
155
|
+
end
|
156
|
+
else
|
157
|
+
auth = ""
|
158
|
+
end
|
159
|
+
if index_last_prompt.nil?
|
160
|
+
respond "#{last_context}No prompts found.\n#{live_content}#{static_content}#{auth}" unless delete_history
|
161
|
+
else
|
162
|
+
last_prompt = ""
|
163
|
+
content[index_last_prompt..-1].each do |c|
|
164
|
+
if c[:role] == "user" and c[:content].size == 1 and c[:content][0][:type] == "text"
|
165
|
+
if c[:content][0].key?(:clean_text)
|
166
|
+
if @open_ai[team_id_user][:chat_gpt][:sessions][session_name][:static_content].nil? or
|
167
|
+
!@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:static_content].include?(c[:content][0][:clean_text])
|
168
|
+
last_prompt += ":runner: *User>* #{transform_to_slack_markdown(c[:content][0][:clean_text])}\n"
|
169
|
+
end
|
170
|
+
else
|
171
|
+
last_prompt += ":runner: *User>* #{transform_to_slack_markdown(c[:content][0][:text])}\n"
|
172
|
+
end
|
173
|
+
elsif c[:role] == "user" and c[:content].size == 1 and c[:content][0][:type] != "text"
|
174
|
+
last_prompt += ":runner: *User>* Attached file type #{c[:content][0][:type]}\n"
|
175
|
+
elsif c[:role] == "assistant" and c[:content].size == 1 and c[:content][0][:type] == "text"
|
176
|
+
last_prompt += ":speech_balloon: *ChatGPT>* #{transform_to_slack_markdown(c[:content][0][:text])}\n"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
respond last_prompt + last_context + live_content + static_content + auth
|
180
|
+
end
|
70
181
|
end
|
71
182
|
end
|
72
183
|
if Thread.current[:on_thread] and
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
184
|
+
(Thread.current[:thread_ts] == Thread.current[:ts] or
|
185
|
+
(@open_ai[team_id_user][:chat_gpt][:sessions].key?(session_name) and
|
186
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name].key?(:thread_ts) and
|
187
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:thread_ts].include?(Thread.current[:thread_ts])))
|
77
188
|
react :running, Thread.current[:thread_ts]
|
78
189
|
@listening[team_id_user] ||= {}
|
79
190
|
@listening[team_id_user][Thread.current[:thread_ts]] = Time.now
|
@@ -84,20 +195,19 @@ class SlackSmartBot
|
|
84
195
|
else
|
85
196
|
@active_chat_gpt_sessions[team_id_user][Thread.current[:dest]] = session_name
|
86
197
|
end
|
87
|
-
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:description] = description if description !=
|
88
|
-
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:tag] = tag.downcase if tag !=
|
89
|
-
open_ai_chat_use_model(model, dont_save_stats: true) if model !=
|
198
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:description] = description if description != ""
|
199
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:tag] = tag.downcase if tag != ""
|
200
|
+
open_ai_chat_use_model(model, dont_save_stats: true) if model != ""
|
90
201
|
elsif type == :temporary and
|
91
|
-
|
92
|
-
|
202
|
+
(!@chat_gpt_collaborating.key?(team_id_user) or !@chat_gpt_collaborating[team_id_user].key?(Thread.current[:thread_ts]))
|
93
203
|
@open_ai[team_id_user] ||= {}
|
94
204
|
@open_ai[team_id_user][:chat_gpt] ||= {}
|
95
205
|
@open_ai[team_id_user][:chat_gpt][:sessions] ||= {}
|
96
206
|
|
97
207
|
if Thread.current[:on_thread] and
|
98
|
-
|
208
|
+
(Thread.current[:thread_ts] == Thread.current[:ts] or
|
99
209
|
(@open_ai[team_id_user][:chat_gpt][:sessions].key?("") and @open_ai[team_id_user][:chat_gpt][:sessions][""].key?(:thread_ts) and
|
100
|
-
|
210
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][""][:thread_ts].include?(Thread.current[:thread_ts])))
|
101
211
|
@listening[team_id_user] ||= {}
|
102
212
|
@listening[team_id_user][Thread.current[:thread_ts]] = Time.now
|
103
213
|
@listening[:threads][Thread.current[:thread_ts]] = Thread.current[:dest]
|
@@ -109,6 +219,19 @@ class SlackSmartBot
|
|
109
219
|
@active_chat_gpt_sessions[team_id_user][Thread.current[:thread_ts]] ||= ""
|
110
220
|
end
|
111
221
|
end
|
222
|
+
if delete_history and type != :clean and @open_ai.key?(team_id_user) and @open_ai[team_id_user].key?(:chat_gpt) and @open_ai[team_id_user][:chat_gpt].key?(:sessions) and
|
223
|
+
@open_ai[team_id_user][:chat_gpt][:sessions].key?(session_name)
|
224
|
+
if session_name == "" and type == :temporary
|
225
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:collaborators] = []
|
226
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:num_prompts] = 0
|
227
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:copy_of_session] = ""
|
228
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:copy_of_team] = ""
|
229
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:copy_of_user] = ""
|
230
|
+
end
|
231
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:live_content] = []
|
232
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:static_content] = []
|
233
|
+
@open_ai[team_id_user][:chat_gpt][:sessions][session_name][:authorizations] = {}
|
234
|
+
end
|
112
235
|
|
113
236
|
#for collaborators
|
114
237
|
if @chat_gpt_collaborating.key?(team_id_user) and @chat_gpt_collaborating[team_id_user].key?(Thread.current[:thread_ts])
|
@@ -123,33 +246,72 @@ class SlackSmartBot
|
|
123
246
|
end
|
124
247
|
team_id_user_creator = team_creator + "_" + user_creator
|
125
248
|
unless type != :temporary and
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
249
|
+
(!@open_ai.key?(team_id_user_creator) or !@open_ai[team_id_user_creator].key?(:chat_gpt) or !@open_ai[team_id_user_creator][:chat_gpt].key?(:sessions) or
|
250
|
+
!@open_ai[team_id_user_creator][:chat_gpt][:sessions].key?(session_name) or
|
251
|
+
(@open_ai[team_id_user_creator][:chat_gpt][:sessions].key?(session_name) and !collaborator and user_creator != user.name))
|
252
|
+
subtype = ""
|
253
|
+
if type == :clean
|
254
|
+
save_stats(:open_ai_chat_clean_session)
|
255
|
+
elsif message.match?(/\A\s*set\s+context\s+(.+)\s*\Z/i)
|
256
|
+
subtype = :set_context
|
257
|
+
save_stats(:open_ai_chat_set_context)
|
258
|
+
elsif message.match(/\A\s*add\s+live\s+(resource|content|feed|doc)s?\s+(.+)\s*\Z/im)
|
259
|
+
subtype = :add_live_content
|
260
|
+
save_stats(:open_ai_chat_add_live_content)
|
261
|
+
elsif message.match(/\A\s*add\s+(static\s+)?(resource|content|doc)s?\s+(.+)\s*\Z/im)
|
262
|
+
subtype = :add_static_content
|
263
|
+
save_stats(:open_ai_chat_add_static_content)
|
264
|
+
elsif message.match(/\A\s*add\s+history\s+(channel\s+)?<#(\w+)\|.*>\s*\Z/im)
|
265
|
+
subtype = :add_history_channel
|
266
|
+
save_stats(:open_ai_chat_add_history_channel)
|
267
|
+
elsif message.match(/\A\s*delete\s+live\s+(resource|content|feed|doc)s?\s+(.+)\s*\Z/im)
|
268
|
+
subtype = :delete_live_content
|
269
|
+
save_stats(:open_ai_chat_delete_live_content)
|
270
|
+
elsif message.match(/\A\s*delete\s+(static\s+)?(resource|content|doc)s?\s+(.+)\s*\Z/im)
|
271
|
+
subtype = :delete_static_content
|
272
|
+
save_stats(:open_ai_chat_delete_static_content)
|
273
|
+
elsif message.match(/\A\s*delete\s+history\s+(channel\s+)?<#(\w+)\|.*>\s*\Z/im)
|
274
|
+
subtype = :delete_history_channel
|
275
|
+
save_stats(:open_ai_chat_delete_history_channel)
|
276
|
+
elsif message.match(/\A\s*add\s+authorization\s+([^\s]+)\s+([^\s]+)\s+(.+)\s*\Z/im)
|
277
|
+
subtype = :add_authorization
|
278
|
+
save_stats(:open_ai_chat_add_authorization)
|
279
|
+
elsif message.match(/\A\s*delete\s+authorization\s+([^\s]+)\s+([^\s]+)\s*\Z/im)
|
280
|
+
subtype = :delete_authorization
|
281
|
+
save_stats(:open_ai_chat_delete_authorization)
|
282
|
+
else
|
283
|
+
save_stats(__method__)
|
284
|
+
end
|
285
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:last_activity] = Time.now.strftime("%Y-%m-%d %H:%M:%S") unless session_name == ""
|
131
286
|
@ai_open_ai, message_connect = SlackSmartBot::AI::OpenAI.connect(@ai_open_ai, config, @personal_settings, reconnect: delete_history, service: :chat_gpt)
|
132
287
|
|
133
288
|
respond message_connect if message_connect
|
134
289
|
if !@ai_open_ai[team_id_user_creator].nil? and !@ai_open_ai[team_id_user_creator][:chat_gpt][:client].nil?
|
135
290
|
@ai_gpt[team_id_user_creator] ||= {}
|
136
291
|
@ai_gpt[team_id_user_creator][session_name] ||= []
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
if delete_history and session_name ==
|
143
|
-
|
144
|
-
|
145
|
-
|
292
|
+
if delete_history or !@open_ai.key?(team_id_user_creator) or !@open_ai[team_id_user_creator].key?(:chat_gpt) or
|
293
|
+
!@open_ai[team_id_user_creator][:chat_gpt].key?(:sessions) or
|
294
|
+
!@open_ai[team_id_user_creator][:chat_gpt][:sessions].key?(session_name) or
|
295
|
+
!@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name].key?(:model) or
|
296
|
+
!@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name].key?(:num_prompts)
|
297
|
+
if delete_history and session_name == "" && @open_ai.key?(team_id_user_creator) && @open_ai[team_id_user_creator].key?(:chat_gpt) &&
|
298
|
+
@open_ai[team_id_user_creator][:chat_gpt].key?(:sessions) && @open_ai[team_id_user_creator][:chat_gpt][:sessions].key?("") &&
|
299
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][""].key?(:thread_ts)
|
146
300
|
@open_ai[team_id_user_creator][:chat_gpt][:sessions][""][:thread_ts].each do |thread_ts|
|
147
301
|
if thread_ts != Thread.current[:thread_ts] && @listening[:threads].key?(thread_ts)
|
148
302
|
unreact :running, thread_ts, channel: @listening[:threads][thread_ts]
|
149
|
-
message_chatgpt = "I'm sorry, but I'm no longer listening to this thread since you started a new temporary session."
|
303
|
+
message_chatgpt = ":information_source: I'm sorry, but I'm no longer listening to this thread since you started a new temporary session."
|
150
304
|
respond message_chatgpt, @listening[:threads][thread_ts], thread_ts: thread_ts
|
151
305
|
@listening[team_id_user_creator].delete(thread_ts)
|
152
306
|
@listening[:threads].delete(thread_ts)
|
307
|
+
collaborators_saved.each do |team_id_user_collaborator|
|
308
|
+
if @listening.key?(team_id_user_collaborator)
|
309
|
+
@listening[team_id_user_collaborator].delete(thread_ts)
|
310
|
+
end
|
311
|
+
if @chat_gpt_collaborating.key?(team_id_user_collaborator) && @chat_gpt_collaborating[team_id_user_collaborator].key?(thread_ts)
|
312
|
+
@chat_gpt_collaborating[team_id_user_collaborator].delete(thread_ts)
|
313
|
+
end
|
314
|
+
end
|
153
315
|
end
|
154
316
|
end
|
155
317
|
end
|
@@ -162,117 +324,711 @@ class SlackSmartBot
|
|
162
324
|
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:num_prompts] = 0
|
163
325
|
end
|
164
326
|
|
165
|
-
if message == "" and session_name ==
|
327
|
+
if message == "" and session_name == "" # ?? is called
|
166
328
|
@ai_gpt[team_id_user_creator][session_name] = []
|
167
329
|
respond "*ChatGPT*: Let's start a new temporary conversation. Ask me anything."
|
168
|
-
open_ai_chat_use_model(model, dont_save_stats: true) if model !=
|
330
|
+
open_ai_chat_use_model(model, dont_save_stats: true) if model != ""
|
331
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:live_content] = []
|
332
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:static_content] = []
|
333
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:authorizations] = {}
|
169
334
|
else
|
335
|
+
treated = false
|
170
336
|
react :speech_balloon
|
171
337
|
begin
|
172
338
|
urls_messages = []
|
173
339
|
get_openai_sessions(session_name, team_id: team_creator, user_name: user_creator)
|
174
|
-
|
340
|
+
if delete_history
|
341
|
+
prompts = []
|
342
|
+
if type == :temporary
|
343
|
+
@ai_gpt[team_id_user_creator][session_name] = []
|
344
|
+
else
|
345
|
+
#remove all prompts that are not static content or context
|
346
|
+
@ai_gpt[team_id_user_creator][session_name].each do |c|
|
347
|
+
if (c[:role] == "user" and c[:content].size == 1 and c[:content][0][:type] == "text" and c[:content][0].key?(:clean_text) and
|
348
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:static_content].include?(c[:content][0][:clean_text])) or
|
349
|
+
c[:role] == "system"
|
350
|
+
prompts << c
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
@ai_gpt[team_id_user_creator][session_name] = prompts
|
355
|
+
end
|
356
|
+
|
175
357
|
if @open_ai.key?(team_id_user_creator) and @open_ai[team_id_user_creator].key?(:chat_gpt) and @open_ai[team_id_user_creator][:chat_gpt].key?(:sessions) and
|
176
|
-
|
177
|
-
if model ==
|
358
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions].key?(session_name) and @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name].key?(:model)
|
359
|
+
if model == ""
|
178
360
|
model = @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:model].to_s
|
179
361
|
else
|
180
362
|
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:model] = model
|
181
363
|
end
|
182
364
|
else
|
183
|
-
model =
|
365
|
+
model = ""
|
184
366
|
end
|
185
367
|
model = @ai_open_ai[team_id_user_creator].chat_gpt.model if model.empty?
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
368
|
+
max_num_tokens = 8000 #default in case no model is found
|
369
|
+
@open_ai_model_info ||= {}
|
370
|
+
if !@open_ai_model_info.key?(model)
|
371
|
+
ai_models_conn, message_conn = SlackSmartBot::AI::OpenAI.connect({}, config, {}, service: :models)
|
372
|
+
models = ai_models_conn[team_id_user_creator].models
|
373
|
+
unless models.nil? or models.client.nil? or message_conn.to_s != ""
|
374
|
+
@open_ai_model_info[model] ||= SlackSmartBot::AI::OpenAI.models(models.client, models, model, return_response: true)
|
193
375
|
end
|
376
|
+
end
|
377
|
+
if @open_ai_model_info.key?(model) and @open_ai_model_info[model].key?(:max_input_tokens)
|
378
|
+
max_num_tokens = @open_ai_model_info[model][:max_input_tokens].to_i
|
379
|
+
elsif @open_ai_model_info.key?(model) and @open_ai_model_info[model].key?(:max_tokens)
|
380
|
+
max_num_tokens = @open_ai_model_info[model][:max_tokens].to_i
|
381
|
+
end
|
194
382
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
383
|
+
if message.match?(/\A\s*resend\s+prompt\s*\z/i) and !@ai_gpt[team_id_user_creator][session_name].empty?
|
384
|
+
files_attached = []
|
385
|
+
system_prompt = @ai_gpt[team_id_user_creator][session_name].pop if @ai_gpt[team_id_user_creator][session_name].last[:role] == "system"
|
386
|
+
@ai_gpt[team_id_user_creator][session_name].pop if @ai_gpt[team_id_user_creator][session_name].last[:role] == "assistant"
|
387
|
+
while @ai_gpt[team_id_user_creator][session_name].last[:role] == "user" and
|
388
|
+
@ai_gpt[team_id_user_creator][session_name].last[:content].first[:type] == "image_url"
|
389
|
+
files_attached << @ai_gpt[team_id_user_creator][session_name].last[:content].first
|
390
|
+
@ai_gpt[team_id_user_creator][session_name].pop
|
391
|
+
end
|
392
|
+
if @ai_gpt[team_id_user_creator][session_name].last[:role] == "user" and
|
393
|
+
@ai_gpt[team_id_user_creator][session_name].last[:content].first[:type] == "text"
|
394
|
+
last_prompt = @ai_gpt[team_id_user_creator][session_name].pop
|
395
|
+
if last_prompt[:content].first.key?(:clean_text) and
|
396
|
+
(@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:static_content].nil? or
|
397
|
+
!@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:static_content].include?(last_prompt[:content].first[:clean_text]))
|
398
|
+
message = last_prompt[:content].first[:clean_text]
|
399
|
+
else
|
400
|
+
message = last_prompt[:content].first[:text]
|
401
|
+
end
|
402
|
+
respond ":information_source: Last ChatGPT response was removed from history.\nPrompt resent: `#{message}`"
|
403
|
+
end
|
404
|
+
elsif subtype == :set_context
|
405
|
+
context = message.match(/\A\s*set\s+context\s+(.+)\s*\Z/i)[1]
|
406
|
+
@ai_gpt[team_id_user_creator][session_name] << { role: "system", content: [{ type: "text", text: context }] }
|
407
|
+
respond ":information_source: Context set to: `#{context}`"
|
408
|
+
treated = true
|
409
|
+
elsif message.match(/\A\s*add\s+live\s+(resource|content|feed|doc)s?\s+(.+)\s*\Z/im)
|
410
|
+
opts = $2.to_s
|
411
|
+
opts.gsub!("!http", "http")
|
412
|
+
urls = opts.scan(/https?:\/\/[^\s\/$.?#].[^\s]*/)
|
413
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:live_content] ||= []
|
414
|
+
copy_of_user = @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_user]
|
415
|
+
if copy_of_user.to_s != "" and copy_of_user != user_name
|
416
|
+
#check if host of url is in authorizations of the user orig of the session
|
417
|
+
team_id_user_orig = @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_team] + "_" +
|
418
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_user]
|
419
|
+
copy_of_session = @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_session]
|
420
|
+
auth_user_orig = @open_ai[team_id_user_orig][:chat_gpt][:sessions][copy_of_session][:authorizations]
|
421
|
+
not_allowed = []
|
422
|
+
#if the host is on auth of the user orig, then it is not allwed for other users to add it
|
423
|
+
urls.each do |url|
|
424
|
+
host = URI.parse(url).host
|
425
|
+
if auth_user_orig.key?(host)
|
426
|
+
not_allowed << url
|
427
|
+
end
|
428
|
+
end
|
429
|
+
if not_allowed.size > 0
|
430
|
+
respond ":warning: You are not allowed to add the following URLs because they are part of the authorizations of the user that created the session:\n\t\t - `#{not_allowed.join("`\n\t\t - `")}`"
|
431
|
+
urls -= not_allowed
|
432
|
+
end
|
433
|
+
end
|
434
|
+
if urls.size > 0
|
435
|
+
urls.each do |url|
|
436
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:live_content] << url
|
437
|
+
end
|
438
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:live_content].uniq!
|
439
|
+
respond ":globe_with_meridians: Live content added:\n\t\t - `#{urls.join("`\n\t\t - `")}`\nEvery time you send a new prompt, it will use the latest version of the resource.\nCall `delete live content URL1 URL99` to remove them."
|
440
|
+
end
|
441
|
+
treated = true
|
442
|
+
elsif message.match(/\A\s*add\s+(static\s+)?(resource|content|doc)s?\s+(.+)\s*\Z/im)
|
443
|
+
opts = $3.to_s
|
444
|
+
opts.gsub!("!http", "http")
|
445
|
+
urls = opts.scan(/https?:\/\/[^\s\/$.?#].[^\s]*/)
|
446
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:static_content] ||= []
|
447
|
+
copy_of_user = @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_user]
|
448
|
+
if copy_of_user.to_s != "" and copy_of_user != user_name
|
449
|
+
#check if host of url is in authorizations of the user orig of the session
|
450
|
+
team_id_user_orig = @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_team] + "_" +
|
451
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_user]
|
452
|
+
copy_of_session = @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_session]
|
453
|
+
auth_user_orig = @open_ai[team_id_user_orig][:chat_gpt][:sessions][copy_of_session][:authorizations]
|
454
|
+
not_allowed = []
|
455
|
+
#if the host is on auth of the user orig, then it is not allwed for other users to add it
|
456
|
+
urls.each do |url|
|
457
|
+
host = URI.parse(url).host
|
458
|
+
if auth_user_orig.key?(host)
|
459
|
+
not_allowed << url
|
460
|
+
end
|
461
|
+
end
|
462
|
+
if not_allowed.size > 0
|
463
|
+
respond ":warning: You are not allowed to add the following URLs because they are part of the authorizations of the user that created the session:\n\t\t - `#{not_allowed.join("`\n\t\t - `")}`"
|
464
|
+
urls -= not_allowed
|
465
|
+
end
|
466
|
+
end
|
467
|
+
if urls.size > 0
|
468
|
+
authorizations = get_authorizations(session_name, team_id_user_creator)
|
469
|
+
threads = []
|
470
|
+
urls.uniq.each do |url|
|
471
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:static_content] << url
|
472
|
+
threads << Thread.new do
|
473
|
+
text, url_message = download_http_content(url, authorizations, team_id_user_creator, session_name)
|
474
|
+
@ai_gpt[team_id_user_creator][session_name] << { role: "user", content: [{ type: "text", text: text, clean_text: url }] }
|
475
|
+
end
|
476
|
+
end
|
477
|
+
threads.each(&:join)
|
203
478
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
479
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:static_content].uniq!
|
480
|
+
update_openai_sessions(session_name, team_id: team_creator, user_name: user_creator) unless session_name == ""
|
481
|
+
respond ":pushpin: Static content added:\n\t\t - `#{urls.join("`\n\t\t - `")}`\nCall `delete static content URL1 URL99` to remove them."
|
482
|
+
end
|
483
|
+
treated = true
|
484
|
+
elsif message.match(/\A\s*add\s+history\s+(channel\s+)?<#(\w+)\|.*>\s*\Z/im)
|
485
|
+
channel_history = $2.to_s
|
486
|
+
#check if the user is on the channel or on a DM with the bot
|
487
|
+
if Thread.current[:dest][0] == "D" or Thread.current[:dest] == channel_history
|
488
|
+
members_channel_history = get_channel_members(channel_history)
|
489
|
+
#check if SmartBot and The granular smartbot are members of the channel
|
490
|
+
if members_channel_history.include?(config.nick_id) and members_channel_history.include?(config.nick_id_granular)
|
491
|
+
if Thread.current[:dest][0] == "D"
|
492
|
+
#Check if the user is a member of the Channel
|
493
|
+
if !members_channel_history.include?(user.id)
|
494
|
+
respond ":warning: You are not a member of the channel <##{channel_history}>."
|
495
|
+
end
|
496
|
+
end
|
497
|
+
#get the history of the channel
|
498
|
+
@history_still_running ||= false
|
499
|
+
if @history_still_running
|
500
|
+
respond "Due to Slack API rate limit, when getting history of a channel this command is limited. Waiting for other command to finish."
|
501
|
+
num_times = 0
|
502
|
+
while @history_still_running and num_times < 30
|
503
|
+
num_times += 1
|
504
|
+
sleep 1
|
505
|
+
end
|
506
|
+
if @history_still_running
|
507
|
+
respond "Sorry, Another command is still running after 30 seconds. Please try again later."
|
508
|
+
end
|
509
|
+
end
|
510
|
+
unless @history_still_running
|
511
|
+
@history_still_running = true
|
512
|
+
#from 6 months ago
|
513
|
+
from = Time.now - 60 * 60 * 24 * 180
|
514
|
+
to = Time.now
|
515
|
+
respond "Adding the history of the channel from #{from.strftime("%Y-%m-%d")}. Take in consideration that this could take a while."
|
516
|
+
hist = []
|
517
|
+
num_times = 0
|
518
|
+
while hist.empty? and num_times < 6
|
519
|
+
client_granular.conversations_history(channel: channel_history, limit: 1000, oldest: from.to_f, latest: to.to_f) do |response|
|
520
|
+
hist << response.messages
|
521
|
+
end
|
522
|
+
hist.flatten!
|
523
|
+
num_times += 1
|
524
|
+
if hist.empty?
|
525
|
+
if num_times == 1
|
526
|
+
respond "It seems like the history of the channel is empty. It could be the Slack API rate limit. I'll try again for one minute."
|
208
527
|
end
|
528
|
+
sleep 10
|
209
529
|
end
|
210
530
|
end
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
531
|
+
messages = {} # store the messages by year/month
|
532
|
+
act_users = {}
|
533
|
+
act_threads = {}
|
534
|
+
#from the past 6 months
|
535
|
+
hist.each do |hist_message|
|
536
|
+
if Time.at(hist_message.ts.to_f) >= from
|
537
|
+
year_month = Time.at(hist_message.ts.to_f).strftime("%Y-%m")
|
538
|
+
messages[year_month] ||= []
|
539
|
+
if hist_message.key?("thread_ts")
|
540
|
+
thread_ts_message = hist_message.thread_ts
|
541
|
+
replies = client_granular.conversations_replies(channel: channel_history, ts: thread_ts_message) #jal, latest: last_msg.ts)
|
542
|
+
sleep 0.5 #to avoid rate limit Tier 3 (50 requests per minute)
|
543
|
+
messages_replies = ["Thread Started about last message:"]
|
544
|
+
act_threads[hist_message.ts] = replies.messages.size
|
545
|
+
replies.messages.each_with_index do |msgrepl, i|
|
546
|
+
act_users[msgrepl.user] ||= 0
|
547
|
+
act_users[msgrepl.user] += 1
|
548
|
+
messages_replies << "<@#{msgrepl.user}> (#{Time.at(msgrepl.ts.to_f)}) wrote:> #{msgrepl.text}" if i > 0
|
549
|
+
end
|
550
|
+
messages_replies << "Thread ended."
|
551
|
+
messages[year_month] += messages_replies.reverse # the order on repls is from older to newer
|
216
552
|
end
|
553
|
+
act_users[hist_message.user] ||= 0
|
554
|
+
act_users[hist_message.user] += 1
|
555
|
+
url_to_message = "https://#{client.team.domain}.slack.com/archives/#{channel_history}/#{hist_message.ts}"
|
556
|
+
messages[year_month] << "<@#{hist_message.user}> (#{Time.at(hist_message.ts.to_f)}) (link to the message: #{url_to_message}) wrote:> #{hist_message.text}"
|
217
557
|
end
|
218
558
|
end
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
559
|
+
@history_still_running = false
|
560
|
+
messages.each do |year_month, msgs|
|
561
|
+
messages[year_month] = msgs.reverse # the order on history is from newer to older
|
562
|
+
end
|
563
|
+
if messages.empty?
|
564
|
+
#last 6 months
|
565
|
+
message_history = ":warning: No messages found on the channel <##{channel_history}> from the past 6 months."
|
566
|
+
message_history += "\n\nIt could be the Slack API rate limit. Please try again in a while."
|
567
|
+
respond message_history
|
568
|
+
else
|
569
|
+
#sort by year/month from older to newer
|
570
|
+
messages = messages.sort_by { |k, v| k }.to_h
|
571
|
+
#check num_tokens don't exceed max_num_tokens
|
572
|
+
#remove messages if it exceeds from the oldest to the newest
|
573
|
+
num_tokens = 0
|
574
|
+
prompts_check = @ai_gpt[team_id_user_creator][session_name].deep_copy
|
575
|
+
prompts_check_text = prompts_check.map { |c| c[:content].map { |cont| cont[:text] }.join("\n") }.join("\n")
|
576
|
+
enc = Tiktoken.encoding_for_model("gpt-4") #jal todo: fixed value since version 0.0.8 and 0.0.9 failed to install on SmartBot VM. Revert when fixed.
|
577
|
+
text_to_check = nil
|
578
|
+
num_tokens = 0
|
579
|
+
removed_months = []
|
580
|
+
while text_to_check.nil? or num_tokens > (max_num_tokens - 1000)
|
581
|
+
if num_tokens > (max_num_tokens - 1000)
|
582
|
+
removed_months << messages.keys.first
|
583
|
+
messages.shift
|
584
|
+
end
|
585
|
+
text_to_check = messages.values.flatten.join("\n") + prompts_check_text
|
586
|
+
num_tokens = enc.encode(text_to_check.to_s).length
|
587
|
+
end
|
588
|
+
if messages.empty?
|
589
|
+
message_history = ":warning: The history of the channel exceeds the limit of tokens allowed."
|
590
|
+
if removed_months.size > 0
|
591
|
+
message_history += "\n\n:The following months were removed because the total number of ChatGPT tokens exceeded the limit of the model:\n\t\t - `#{removed_months.join("`\n\t\t - `")}`"
|
592
|
+
end
|
593
|
+
else
|
594
|
+
history_text = "This is the history of conversations on the Slack channel <##{channel_history}>:\n\n#{messages.values.flatten.join("\n")}"
|
595
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:static_content] ||= []
|
596
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:static_content] << "History of <##{channel_history}>"
|
597
|
+
@ai_gpt[team_id_user_creator][session_name] << { role: "user", content: [{ type: "text", text: history_text, clean_text: "History of <##{channel_history}>" }] }
|
598
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:static_content].uniq!
|
599
|
+
update_openai_sessions(session_name, team_id: team_creator, user_name: user_creator) unless session_name == ""
|
600
|
+
message_history = ":scroll: History of the channel <##{channel_history}> from the past 6 months added to the session.\nCall `delete history <##{channel_history}>` to delete it."
|
601
|
+
if removed_months.size > 0
|
602
|
+
message_history += "\n\n:warning: The following months were removed because the total number of tokens exceeded the limit:\n\t\t - `#{removed_months.join("`\n\t\t - `")}`"
|
224
603
|
end
|
604
|
+
message_history += "\n\nThe history of that channel will be used as part of the prompts for the next responses."
|
605
|
+
# specify month and year
|
606
|
+
message_history += "\n\nThe first message added is from #{messages.keys.first}."
|
607
|
+
message_history += "\n\t\tTotal number of messages added: #{messages.values.flatten.size - act_threads.size}."
|
608
|
+
message_history += "\n\t\tNumber of threads added: #{act_threads.size}."
|
609
|
+
message_history += "\n\t\tNumber of messages on threads added: #{act_threads.values.sum}." unless removed_months.size > 0
|
610
|
+
respond message_history
|
225
611
|
end
|
226
612
|
end
|
613
|
+
end
|
614
|
+
else
|
615
|
+
respond ":warning: <@#{config.nick_id}> and <@#{config.nick_id_granular}> need to be members of the channel <##{channel_history}> to be able to add its history. Please add them to the channel and try again."
|
616
|
+
end
|
617
|
+
else
|
618
|
+
respond ":warning: You can only add the history of a Slack channel where you are or on a DM with me."
|
619
|
+
end
|
227
620
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
621
|
+
treated = true
|
622
|
+
elsif message.match(/\A\s*delete\s+live\s+(resource|content|feed|doc)s?\s+(.+)\s*\Z/im)
|
623
|
+
opts = $2.to_s
|
624
|
+
opts.gsub!("!http", "http")
|
625
|
+
urls = opts.scan(/https?:\/\/[^\s\/$.?#].[^\s]*/)
|
626
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:live_content] ||= []
|
627
|
+
not_found = []
|
628
|
+
urls.each do |url|
|
629
|
+
unless @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:live_content].delete(url)
|
630
|
+
not_found << url
|
631
|
+
end
|
632
|
+
end
|
633
|
+
message_live_content = []
|
634
|
+
message_live_content << "Live content removed: `#{(urls - not_found).join("`, `")}`." if (urls - not_found).size > 0
|
635
|
+
message_live_content << "Not found: `#{not_found.join("`, `")}`." if not_found.size > 0
|
636
|
+
respond ":globe_with_meridians: #{message_live_content.join("\n")}"
|
637
|
+
treated = true
|
638
|
+
elsif message.match(/\A\s*delete\s+(static\s+)?(resource|content|doc)s?\s+(.+)\s*\Z/im)
|
639
|
+
opts = $3.to_s
|
640
|
+
opts.gsub!("!http", "http")
|
641
|
+
urls = opts.scan(/https?:\/\/[^\s\/$.?#].[^\s]*/)
|
642
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:static_content] ||= []
|
643
|
+
not_found = []
|
644
|
+
urls.each do |url|
|
645
|
+
unless @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:static_content].delete(url)
|
646
|
+
not_found << url
|
647
|
+
end
|
648
|
+
@ai_gpt[team_id_user_creator][session_name].each do |prompt|
|
649
|
+
prompt[:content].each do |content|
|
650
|
+
if content[:type] == "text" and content[:clean_text] == url
|
651
|
+
@ai_gpt[team_id_user_creator][session_name].delete(prompt)
|
652
|
+
end
|
653
|
+
end
|
654
|
+
end
|
655
|
+
end
|
656
|
+
update_openai_sessions(session_name, team_id: team_creator, user_name: user_creator) unless session_name == ""
|
657
|
+
message_static_content = []
|
658
|
+
message_static_content << "Static content removed: `#{(urls - not_found).join("`, `")}`." if (urls - not_found).size > 0
|
659
|
+
message_static_content << "Not found: `#{not_found.join("`, `")}`." if not_found.size > 0
|
660
|
+
respond ":pushpin: #{message_static_content.join("\n")}"
|
661
|
+
treated = true
|
662
|
+
elsif message.match(/\A\s*delete\s+history\s+(channel\s+)?<#(\w+)\|.*>\s*\Z/im)
|
663
|
+
channel_history = $2.to_s
|
664
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:static_content] ||= []
|
665
|
+
@ai_gpt[team_id_user_creator][session_name].each do |prompt|
|
666
|
+
prompt[:content].each do |content|
|
667
|
+
if content[:type] == "text" and content[:clean_text] == "History of <##{channel_history}>"
|
668
|
+
@ai_gpt[team_id_user_creator][session_name].delete(prompt)
|
669
|
+
end
|
670
|
+
end
|
243
671
|
end
|
672
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:static_content].delete_if { |url| url == "History of <##{channel_history}>" }
|
673
|
+
update_openai_sessions(session_name, team_id: team_creator, user_name: user_creator) unless session_name == ""
|
674
|
+
respond ":scroll: History of the channel <##{channel_history}> removed from the session."
|
675
|
+
treated = true
|
244
676
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
677
|
+
#add authorization HOST HEADER VALUE
|
678
|
+
#for example: add authorization api.example.com Authorization Bearer 123456
|
679
|
+
elsif message.match(/\A\s*add\s+authorization\s+([^\s]+)\s+([^\s]+)\s+(.+)\s*\Z/im)
|
680
|
+
host = $1.to_s
|
681
|
+
header = $2.to_s
|
682
|
+
value = $3.to_s
|
683
|
+
#remove http:// or https:// from host
|
684
|
+
host.gsub!(/\Ahttps?:\/\//, "")
|
685
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:authorizations] ||= {}
|
686
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:authorizations][host] ||= {}
|
687
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:authorizations][host][header] = value
|
688
|
+
message_sec = [":key: Authorization header added: `#{header}` for host `#{host}`."]
|
689
|
+
message_sec << "Call `delete authorization HOST HEADER` to remove it."
|
690
|
+
message_sec << "This authorization will be used only for this session."
|
691
|
+
unless type == :temporary
|
692
|
+
message_sec << "If you share this session, they will be able to use the authorization but will not be able to see the authorization value."
|
693
|
+
end
|
694
|
+
respond message_sec.join("\n")
|
695
|
+
treated = true
|
696
|
+
#delete authorization HOST HEADER
|
697
|
+
#for example: delete authorization api.example.com Authorization
|
698
|
+
elsif message.match(/\A\s*delete\s+authorization\s+([^\s]+)\s+([^\s]+)\s*\Z/im)
|
699
|
+
host = $1.to_s
|
700
|
+
header = $2.to_s
|
701
|
+
host.gsub!(/\Ahttps?:\/\//, "")
|
702
|
+
if @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:authorizations].nil? or
|
703
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:authorizations][host].nil? or
|
704
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:authorizations][host][header].nil?
|
705
|
+
respond ":key: Authorization header not found: `#{header}` for host `#{host}`."
|
706
|
+
else
|
707
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:authorizations] ||= {}
|
708
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:authorizations][host] ||= {}
|
709
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:authorizations][host].delete(header)
|
710
|
+
respond ":key: Authorization header deleted: `#{header}` for host `#{host}`."
|
252
711
|
end
|
712
|
+
treated = true
|
253
713
|
end
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
714
|
+
unless treated
|
715
|
+
num_folder_docs = 0
|
716
|
+
if message == ""
|
717
|
+
res = ""
|
718
|
+
prompts ||= []
|
719
|
+
else
|
720
|
+
restricted = false
|
721
|
+
files_attached ||= []
|
722
|
+
if !files.nil?
|
723
|
+
files.each do |file|
|
724
|
+
http2 = NiceHttp.new(host: "https://files.slack.com", headers: { "Authorization" => "Bearer #{config.token}" })
|
725
|
+
res = http2.get(file.url_private_download)
|
726
|
+
#identify the type of file. In case of image identify the type and encode it to base64
|
727
|
+
if res[:'content-type'].to_s.include?("image")
|
728
|
+
require "base64"
|
729
|
+
image_type = res[:'content-type'].split("/")[1]
|
730
|
+
data = "data:image/#{image_type};base64,#{Base64.strict_encode64(res.body)}"
|
731
|
+
files_attached << { type: "image_url", image_url: { url: data } }
|
732
|
+
else
|
733
|
+
message = "#{message}\n\n#{res.data}"
|
734
|
+
end
|
735
|
+
http2.close
|
736
|
+
end
|
737
|
+
end
|
738
|
+
|
739
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:num_prompts] += 1
|
740
|
+
urls = message.scan(/!(https?:\/\/[\S]+)/).flatten
|
741
|
+
if urls.size > 0 and @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_user] != user_name
|
742
|
+
#check if host of url is in authorizations of the user orig of the session
|
743
|
+
team_id_user_orig = @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_team] + "_" +
|
744
|
+
@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_user]
|
745
|
+
copy_of_session = @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_session]
|
746
|
+
if @open_ai.key?(team_id_user_orig) and @open_ai[team_id_user_orig].key?(:chat_gpt) and
|
747
|
+
@open_ai[team_id_user_orig][:chat_gpt].key?(:sessions) and @open_ai[team_id_user_orig][:chat_gpt][:sessions].key?(copy_of_session) and
|
748
|
+
!@open_ai[team_id_user_orig][:chat_gpt][:sessions][copy_of_session].key?(:authorizations)
|
749
|
+
auth_user_orig = @open_ai[team_id_user_orig][:chat_gpt][:sessions][copy_of_session][:authorizations]
|
750
|
+
else
|
751
|
+
auth_user_orig = {}
|
752
|
+
end
|
753
|
+
not_allowed = []
|
754
|
+
#if the host is on auth of the user orig, then it is not allwed for other users to add it
|
755
|
+
urls.each do |url|
|
756
|
+
host = URI.parse(url).host
|
757
|
+
if auth_user_orig.key?(host)
|
758
|
+
not_allowed << url
|
759
|
+
end
|
760
|
+
end
|
761
|
+
if not_allowed.size > 0
|
762
|
+
respond ":warning: You are not allowed to add the following URLs because they are part of the authorizations of the user that created the session:\n\t\t - `#{not_allowed.join("`\n\t\t - `")}`"
|
763
|
+
urls -= not_allowed
|
764
|
+
end
|
765
|
+
end
|
766
|
+
|
767
|
+
if !@open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:live_content].nil?
|
768
|
+
urls += @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:live_content]
|
769
|
+
end
|
770
|
+
#get a copy of message
|
771
|
+
clean_message = message.dup
|
772
|
+
authorizations = get_authorizations(session_name, team_id_user_creator)
|
773
|
+
#download the content of the urls simultaneously on threads
|
774
|
+
threads = []
|
775
|
+
texts = []
|
776
|
+
urls.uniq.each do |url|
|
777
|
+
threads << Thread.new do
|
778
|
+
text, url_message = download_http_content(url, authorizations, team_id_user_creator, session_name)
|
779
|
+
urls_messages << url_message if url_message != ""
|
780
|
+
texts << text
|
781
|
+
end
|
782
|
+
end
|
783
|
+
threads.each(&:join)
|
784
|
+
urls.uniq.each do |url|
|
785
|
+
message.gsub!("!#{url}", "")
|
786
|
+
end
|
787
|
+
texts.each do |text|
|
788
|
+
message += "\n #{text}\n"
|
789
|
+
end
|
790
|
+
|
791
|
+
if urls.empty?
|
792
|
+
@ai_gpt[team_id_user_creator][session_name] << { role: "user", content: [{ type: "text", text: message }] }
|
793
|
+
else
|
794
|
+
@ai_gpt[team_id_user_creator][session_name] << { role: "user", content: [{ type: "text", text: message, clean_text: clean_message }] }
|
795
|
+
end
|
796
|
+
files_attached.each do |file|
|
797
|
+
@ai_gpt[team_id_user_creator][session_name] << { role: "user", content: [file] }
|
798
|
+
end
|
799
|
+
prompts = @ai_gpt[team_id_user_creator][session_name].deep_copy
|
800
|
+
prompts.each do |prompt|
|
801
|
+
prompt[:content].each do |content|
|
802
|
+
content.delete(:clean_text)
|
803
|
+
end
|
804
|
+
end
|
805
|
+
if @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_session] == ""
|
806
|
+
path_to_session_folder = "#{config.path}/openai/#{team_creator}/#{user_creator}/#{session_name}"
|
807
|
+
term_to_avoid = session_name
|
808
|
+
else
|
809
|
+
copy_of_team = @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_team]
|
810
|
+
copy_of_user = @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_user]
|
811
|
+
term_to_avoid = @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_session]
|
812
|
+
path_to_session_folder = "#{config.path}/openai/#{copy_of_team}/#{copy_of_user}/"
|
813
|
+
path_to_session_folder += @open_ai[team_id_user_creator][:chat_gpt][:sessions][session_name][:copy_of_session].to_s
|
814
|
+
end
|
815
|
+
|
816
|
+
if Dir.exist?(path_to_session_folder)
|
817
|
+
#read the content of chatgpt_prompts.json and add it to the prompts at the beginning
|
818
|
+
if !File.exist?("#{path_to_session_folder}/chatgpt_prompts.json")
|
819
|
+
# Get the content of all files in all folders and subfolders and add it to the chatgpt_prompts.json file
|
820
|
+
docs_folder_prompts = []
|
821
|
+
#enc = Tiktoken.encoding_for_model(model)
|
822
|
+
enc = Tiktoken.encoding_for_model("gpt-4") #jal todo: fixed value since version 0.0.8 and 0.0.9 failed to install on SmartBot VM. Revert when fixed.
|
823
|
+
# all files in the docs_folder should be in text format
|
824
|
+
# first all files on 'include' folder then all files on 'filter' folder
|
825
|
+
["#{path_to_session_folder}/docs_folder/include/**/*", "#{path_to_session_folder}/docs_folder/filter/**/*"].each do |folder|
|
826
|
+
Dir.glob(folder).each do |file|
|
827
|
+
next if File.directory?(file)
|
828
|
+
file_content = File.read(file)
|
829
|
+
num_tokens = enc.encode(file_content.to_s).length
|
830
|
+
docs_folder_prompts << {
|
831
|
+
role: "user",
|
832
|
+
content: [
|
833
|
+
{ type: "text", text: file_content, include_file: file.include?("/docs_folder/include/"), num_tokens: num_tokens, clean_text: file },
|
834
|
+
],
|
835
|
+
}
|
836
|
+
end
|
837
|
+
end
|
838
|
+
File.open("#{path_to_session_folder}/chatgpt_prompts.json", "w") do |f|
|
839
|
+
f.write(docs_folder_prompts.to_json)
|
840
|
+
end
|
841
|
+
end
|
842
|
+
if File.exist?("#{path_to_session_folder}/chatgpt_prompts.json")
|
843
|
+
# Extract all sentences from the prompts not including the system prompts or the user prompts that are images or responses from chatGPT
|
844
|
+
all_sentences = ""
|
845
|
+
prompts.each do |prompt|
|
846
|
+
if prompt[:role] == "user" and prompt[:content].size == 1 and prompt[:content][0][:type] == "text"
|
847
|
+
all_sentences += prompt[:content][0][:text] + " "
|
848
|
+
end
|
849
|
+
end
|
850
|
+
list_avoid = ["use", "set", "bash", term_to_avoid]
|
851
|
+
keywords = get_keywords(all_sentences, list_avoid: list_avoid)
|
852
|
+
|
853
|
+
# Read the JSON file
|
854
|
+
file_content = File.read("#{path_to_session_folder}/chatgpt_prompts.json")
|
855
|
+
json_data = JSON.parse(file_content, symbolize_names: true)
|
856
|
+
|
857
|
+
#remove keyword if keyword is in more than 50% of the documents
|
858
|
+
keywords_num_docs = {}
|
859
|
+
keywords.delete_if do |k|
|
860
|
+
num_found = 0
|
861
|
+
#check if the keyword is in the text field but not in the clean_text field (file name)
|
862
|
+
json_data.each do |entry|
|
863
|
+
num_found += 1 if entry[:content][0][:text].match?(/#{k}/i) and !entry[:content][0][:clean_text].to_s.match?(/#{k}/i)
|
864
|
+
end
|
865
|
+
keywords_num_docs[k] = num_found
|
866
|
+
num_found > (json_data.size / 2)
|
867
|
+
end
|
868
|
+
|
869
|
+
# Filter the JSON data to include only entries with keywords in the text field.
|
870
|
+
# Order the entries by the number of keywords found in the text field.
|
871
|
+
data_num_keywords = {}
|
872
|
+
json_data.each do |entry|
|
873
|
+
num_found = 0
|
874
|
+
total_occurrences = 0
|
875
|
+
keywords.each do |k|
|
876
|
+
num_found += 1 if entry[:content][0][:text].match?(/#{k}/i)
|
877
|
+
total_occurrences += entry[:content][0][:text].scan(/#{k}/i).size
|
878
|
+
end
|
879
|
+
entry[:content][0][:total_occurrences] = total_occurrences
|
880
|
+
data_num_keywords[num_found] ||= []
|
881
|
+
data_num_keywords[num_found] << entry
|
882
|
+
end
|
883
|
+
#delete all entries that have no keywords
|
884
|
+
data_num_keywords.delete(0)
|
885
|
+
#sort the data_num_keywords by the number of keywords found in the text field. From the highest to the lowest
|
886
|
+
data_num_keywords = data_num_keywords.sort_by { |k, v| k }.reverse.to_h
|
887
|
+
#sort by the total_occurrences descending
|
888
|
+
data_num_keywords.each do |k, v|
|
889
|
+
v.sort_by! { |entry| entry[:content][0][:total_occurrences] }.reverse!
|
890
|
+
end
|
891
|
+
#remove occurences of 1 keyword if 10 or more documents have been found with more than 1 keyword
|
892
|
+
if data_num_keywords.values.flatten.uniq.size > (json_data.size / 2) and data_num_keywords.keys.size > 1 and
|
893
|
+
data_num_keywords.key?(1) and (data_num_keywords.values.flatten.uniq.size - data_num_keywords[1].size) >= 10
|
894
|
+
|
895
|
+
#remove data_num_keywords for entries that have less than 2 keywords found
|
896
|
+
data_num_keywords.delete(1)
|
897
|
+
end
|
898
|
+
|
899
|
+
#flatten the data_num_keywords
|
900
|
+
filtered_data = data_num_keywords.values.flatten.uniq
|
901
|
+
|
902
|
+
#add all the entries that have the include_file set to true
|
903
|
+
json_data.each do |entry|
|
904
|
+
if entry[:content][0][:include_file]
|
905
|
+
filtered_data << entry
|
906
|
+
end
|
907
|
+
end
|
908
|
+
|
909
|
+
# put on top of the filtered_data the entries that have the include_file set to true
|
910
|
+
filtered_data.sort_by! { |entry| entry[:content][0][:include_file] ? 0 : 1 }
|
911
|
+
|
912
|
+
#remove key "include_file" and total_occurrences from filtered_data
|
913
|
+
filtered_data.each do |entry|
|
914
|
+
entry[:content].each do |content_block|
|
915
|
+
content_block.delete(:include_file)
|
916
|
+
content_block.delete(:total_occurrences)
|
917
|
+
end
|
918
|
+
end
|
919
|
+
filtered_data.uniq!
|
920
|
+
|
921
|
+
#enc = Tiktoken.encoding_for_model(model)
|
922
|
+
enc = Tiktoken.encoding_for_model("gpt-4") #jal todo: fixed value since version 0.0.8 and 0.0.9 failed to install on SmartBot VM. Revert when fixed.
|
923
|
+
prompts_orig = prompts.deep_copy
|
924
|
+
prompts = filtered_data + prompts
|
925
|
+
#content = (prompts || []).map do |entry|
|
926
|
+
# (entry[:content] || []).map { |content_block| content_block[:text] }
|
927
|
+
#end.flatten
|
928
|
+
content = ""
|
929
|
+
prompts.each do |prompt|
|
930
|
+
content += prompt[:content][0][:text] if prompt.key?(:content) and prompt[:content][0].key?(:text)
|
931
|
+
end
|
932
|
+
|
933
|
+
num_tokens = enc.encode(content.to_s).length
|
934
|
+
|
935
|
+
respond ":information_source: The number of tokens in the prompt including all filtered docs is *#{num_tokens}*.\n\tWe will remove docs to ensure we don't reach the max num of allowed tokens for this ChatGPT model." if num_tokens > max_num_tokens
|
936
|
+
if num_tokens > (max_num_tokens - 1000) #since the number of tokens is not exact, we allow 1000 tokens less
|
937
|
+
#remove filtered_data one by one from the end until the number of tokens is less than max_num_tokens
|
938
|
+
while num_tokens > (max_num_tokens - 1000) and filtered_data.size > 0
|
939
|
+
filtered_data.pop
|
940
|
+
prompts = filtered_data + prompts_orig
|
941
|
+
content = ""
|
942
|
+
num_tokens = 0
|
943
|
+
prompts.each do |prompt|
|
944
|
+
if prompt[:content][0].key?(:num_tokens) and prompt[:content][0][:num_tokens] > 0
|
945
|
+
num_tokens += prompt[:content][0][:num_tokens]
|
946
|
+
else
|
947
|
+
if prompt.key?(:content) and prompt[:content][0].key?(:text)
|
948
|
+
content += prompt[:content][0][:text]
|
949
|
+
end
|
950
|
+
end
|
951
|
+
end
|
952
|
+
num_tokens += enc.encode(content.to_s).length if content != ""
|
953
|
+
end
|
954
|
+
end
|
955
|
+
num_folder_docs = filtered_data.size
|
956
|
+
end
|
957
|
+
#delete num_tokens from content
|
958
|
+
prompts.each do |entry|
|
959
|
+
entry[:content].each do |content_block|
|
960
|
+
content_block.delete(:num_tokens)
|
961
|
+
end
|
962
|
+
end
|
963
|
+
end
|
964
|
+
if @chat_gpt_default_model != model and File.exist?("#{config.path}/openai/restricted_models.yaml")
|
965
|
+
restricted_models = YAML.load_file("#{config.path}/openai/restricted_models.yaml")
|
966
|
+
if restricted_models.key?(model) and !restricted_models[model].include?(team_id_user_creator) and !restricted_models[model].include?(user_creator)
|
967
|
+
respond "You don't have access to this model: #{model}. You can request access to an admin user."
|
968
|
+
restricted = true
|
969
|
+
end
|
970
|
+
end
|
971
|
+
if !restricted
|
972
|
+
success, res = SlackSmartBot::AI::OpenAI.send_gpt_chat(@ai_open_ai[team_id_user_creator][:chat_gpt][:client], model, prompts, @ai_open_ai[team_id_user_creator].chat_gpt)
|
973
|
+
if success
|
974
|
+
@ai_gpt[team_id_user_creator][session_name] << { role: "assistant", content: [{ type: "text", text: res }] }
|
975
|
+
@ai_gpt[team_id_user_creator][session_name] << system_prompt if system_prompt
|
976
|
+
end
|
977
|
+
end
|
259
978
|
end
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
979
|
+
unless restricted
|
980
|
+
#enc = Tiktoken.encoding_for_model(model)
|
981
|
+
enc = Tiktoken.encoding_for_model("gpt-4") #jal todo: fixed value since version 0.0.8 and 0.0.9 failed to install on SmartBot VM. Revert when fixed.
|
982
|
+
content = ""
|
983
|
+
prompts.each do |prompt|
|
984
|
+
content += prompt[:content][0][:text] if prompt.key?(:content) and prompt[:content][0].key?(:text)
|
985
|
+
end
|
986
|
+
|
987
|
+
num_tokens = enc.encode(content.to_s).length
|
988
|
+
|
989
|
+
if num_tokens > max_num_tokens and type != :clean
|
990
|
+
message_max_tokens = ":warning: The total number of tokens in the prompt is #{num_tokens}, which is greater than the maximum number of tokens allowed for the model (#{max_num_tokens})."
|
991
|
+
message_max_tokens += "\nTry to be more concrete writing your prompt. The number of docs attached according to your prompt was #{num_folder_docs}\n" if num_folder_docs > 0
|
992
|
+
respond message_max_tokens
|
993
|
+
end
|
994
|
+
|
995
|
+
if session_name == ""
|
996
|
+
temp_session_name = @ai_gpt[team_id_user_creator][""].first.content.first.text.to_s[0..35] #jal
|
997
|
+
res_slack_mkd = transform_to_slack_markdown(res.to_s.strip)
|
998
|
+
if num_folder_docs > 0
|
999
|
+
docs_message = "\n:notebook_with_decorative_cover: *#{num_folder_docs} documents* were added for this prompt (keywords: _#{keywords.sort[0..9].join(", ")}#{" ..." if keywords.size > 10}_)\n\n"
|
1000
|
+
else
|
1001
|
+
docs_message = ""
|
1002
|
+
end
|
1003
|
+
obj_id = @ai_gpt[team_id_user_creator][""].first.object_id
|
1004
|
+
respond "*ChatGPT* Temporary session: _<#{temp_session_name.gsub("\n", " ").gsub("`", " ")}...>_ (#{obj_id}) model: #{model} num_tokens: #{num_tokens}#{docs_message}\n#{res_slack_mkd}", split: false
|
1005
|
+
if res.to_s.strip == ""
|
1006
|
+
respond "It seems like GPT is not responding. Please try again later or use another model, as it might be overloaded."
|
1007
|
+
end
|
1008
|
+
#to avoid logging the prompt or the response
|
1009
|
+
if config.encrypt
|
1010
|
+
Thread.current[:encrypted] ||= []
|
1011
|
+
Thread.current[:encrypted] << message
|
1012
|
+
end
|
1013
|
+
elsif res.to_s.strip == ""
|
1014
|
+
res = "\nAll prompts were removed from session." if delete_history
|
1015
|
+
respond "*ChatGPT* Session _<#{session_name}>_ model: #{model}#{res}"
|
1016
|
+
respond "It seems like GPT is not responding. Please try again later or use another model, as it might be overloaded." if message != ""
|
1017
|
+
else
|
1018
|
+
res_slack_mkd = transform_to_slack_markdown(res.to_s.strip)
|
1019
|
+
if num_folder_docs > 0
|
1020
|
+
docs_message = "\n:open_file_folder: #{num_folder_docs} documents from the folder were added to the prompts."
|
1021
|
+
else
|
1022
|
+
docs_message = ""
|
1023
|
+
end
|
1024
|
+
respond "*ChatGPT* Session _<#{session_name}>_ model: #{model} num_tokens: #{num_tokens}#{docs_message}\n#{res_slack_mkd}", split: false
|
1025
|
+
end
|
1026
|
+
if urls_messages.size > 0
|
1027
|
+
respond urls_messages.join("\n")
|
1028
|
+
end
|
264
1029
|
end
|
265
|
-
elsif res.to_s.strip == ''
|
266
|
-
res = "\nAll prompts were removed from session." if delete_history
|
267
|
-
respond "*ChatGPT* Session _<#{session_name}>_ model: #{model}#{res}"
|
268
|
-
respond "It seems like GPT is not responding. Please try again later or use another model, as it might be overloaded." if message != ''
|
269
|
-
else
|
270
|
-
respond "*ChatGPT* Session _<#{session_name}>_ model: #{model}\n#{res.to_s.strip}"
|
271
|
-
end
|
272
|
-
if urls_messages.size > 0
|
273
|
-
respond urls_messages.join("\n")
|
274
1030
|
end
|
275
|
-
update_openai_sessions(session_name, team_id: team_creator, user_name: user_creator) unless session_name ==
|
1031
|
+
update_openai_sessions(session_name, team_id: team_creator, user_name: user_creator) unless session_name == "" or !success or restricted
|
276
1032
|
rescue => exception
|
277
1033
|
respond "*ChatGPT*: Sorry, I'm having some problems. OpenAI probably is not available. Please try again later."
|
278
1034
|
@logger.warn exception
|