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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +34 -1
  3. data/img/chat_gpt_attach_image.png +0 -0
  4. data/lib/slack/smart-bot/ai/open_ai/models.rb +19 -10
  5. data/lib/slack/smart-bot/ai/open_ai/send_gpt_chat.rb +14 -10
  6. data/lib/slack/smart-bot/comm/dont_understand.rb +23 -6
  7. data/lib/slack/smart-bot/comm/get_user_info.rb +9 -10
  8. data/lib/slack/smart-bot/comm/respond.rb +56 -28
  9. data/lib/slack/smart-bot/comm/send_file.rb +17 -6
  10. data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat.rb +885 -129
  11. data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_add_collaborator.rb +3 -3
  12. data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_copy_session.rb +132 -15
  13. data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_delete_session.rb +1 -1
  14. data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_get_prompts.rb +50 -12
  15. data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_list_sessions.rb +99 -34
  16. data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_share_session.rb +12 -2
  17. data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_use_model.rb +36 -25
  18. data/lib/slack/smart-bot/commands/general/bot_help.rb +29 -24
  19. data/lib/slack/smart-bot/commands/general/poster.rb +0 -1
  20. data/lib/slack/smart-bot/commands/general/see_announcements.rb +1 -1
  21. data/lib/slack/smart-bot/commands/general/summarize.rb +22 -8
  22. data/lib/slack/smart-bot/commands/general_bot_commands.rb +156 -55
  23. data/lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb +13 -11
  24. data/lib/slack/smart-bot/commands/on_extended/bot_rules.rb +21 -17
  25. data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +2 -2
  26. data/lib/slack/smart-bot/commands.rb +19 -19
  27. data/lib/slack/smart-bot/process_first.rb +38 -35
  28. data/lib/slack/smart-bot/treat_message.rb +57 -56
  29. data/lib/slack/smart-bot/utils/download_http_content.rb +91 -0
  30. data/lib/slack/smart-bot/utils/get_authorizations.rb +41 -0
  31. data/lib/slack/smart-bot/utils/get_keywords.rb +33 -0
  32. data/lib/slack/smart-bot/utils/get_openai_sessions.rb +46 -6
  33. data/lib/slack/smart-bot/utils/get_teams.rb +9 -1
  34. data/lib/slack/smart-bot/utils/save_stats.rb +13 -5
  35. data/lib/slack/smart-bot/utils/transform_to_slack_markdown.rb +36 -0
  36. data/lib/slack/smart-bot/utils/update_openai_sessions.rb +9 -4
  37. data/lib/slack/smart-bot/utils.rb +48 -44
  38. data/lib/slack-smart-bot.rb +10 -10
  39. data/whats_new.txt +27 -1
  40. metadata +49 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2c3c10ede28d806c5c386904621b877fdc1077f84f758b5affde34b3160340bf
4
- data.tar.gz: 4db939606739e903c5d2916ea4d12409457eb3a62a8a740a0dec42f022f6bb70
3
+ metadata.gz: eae826f4dd78e2f74b1ce77cb89b8e2c42282bb242db0d42b469dfe8dac9c502
4
+ data.tar.gz: d9d7b750d738c58f37f9df9c0be19feee22aedb1c93c904e5b0e3f21b8b56c90
5
5
  SHA512:
6
- metadata.gz: d204840c2f03710234fcc7f959b85256065cc312784cd5bb0f3e40aced01301a0a695c35e66161091d0b88e11d2e57283e47782752543240fff1ed00cda7ad0d
7
- data.tar.gz: f06acd8003f313d2711710778e4a7119434d349107c4930e68800ef61620b367635ec047191061830711ee4c6eefbd5ade67eb06f320cdea2f249338cad22eb5
6
+ metadata.gz: 67e0ded851f65cdb368471b3b016e4da58c9e4d82dda0a4d7fb3d796079b5adc62021cd69f3e0f88b4dc8847e6248d3a95ea4de236628fb43242ac3bb438cb81
7
+ data.tar.gz: c804e0884ab1505b2024c2f7819060f2e149e3174dc2527fb65ac5e0f1a14e0ef6139021f6efc6e475385802a9bcf40d3c55ee76135c437571302274d7b31e0d
data/README.md CHANGED
@@ -44,6 +44,8 @@ slack-smart-bot has the ability to create bots on demand, set up shortcuts, exec
44
44
  * [OpenAI](#openai)
45
45
  + [OpenAI Set up](#openai-setup) (A)
46
46
  + [Chat GPT](#chatgpt)
47
+ + [Docs Folder for ChatGPT Sessions](#docs-folder-for-chatgpt-sessions) (A)
48
+ + [Restrict who has access to a specific model](#restrict-who-has-access-to-a-specific-model) (A)
47
49
  + [Image Generation](#image-generation)
48
50
  + [Image Variations](#image-variations)
49
51
  + [Image Editing](#image-editing)
@@ -859,7 +861,20 @@ To get all prompts from a specific session name use `chatGPT get SESSION_NAME`.
859
861
  To list all sessions you created use `chatGPT sessions`.
860
862
  When starting a new session, if you ask SmartBot to answer on a Thread by using !! or ^, then it won't be necessary to send ? before the prompt. In this case, every single message you send will be considered a prompt to be treated. After 30 minutes of inactivity, SmartBot will stop listening to the thread. You will need to continue the session after that. If you want to avoid a message to be treated then start it with a hyphen '-'.
861
863
  To add a collaborator when on a thread, you can use directly `add collaborator @USER`
862
- If you include in the prompt `!URL` then it will download and use the content of the URL as input for the prompt.
864
+ If you include in the prompt `!URL` then it will download and use the content of the URL as input for the prompt. If the URL is a Google Drive link, it will download the content of the file. PDF, DOCX and text files (txt, json, yaml...) are supported.
865
+ If you want to add static content to your session to be used: `add static content URL1 URL99`.
866
+ Add live content to your session by using `add live content URL1 URL99`. The content will be downloaded and added to your session every time you send a new prompt.
867
+ It is possible to specify authorizations tokens for any website you want to reach the content using ChatGPT command. When adding to your prompt `!URL` SmartBot will verify if the domain specified have set an authorization header and add it. To add personal authorization tokens you can do it calling on a DM the commands: `add personal settings authorizations.example.host example.com`, `add personal settings authorizations.example.authorization Xdddj33a_SDFBBBS33Ab`
868
+ Also you can add authorizations on a specific ChatGPT session: `add authorization HOST HEADER VALUE`, for example: `add authorization api.example.com Authorization Bearer 123456`. If you share this session as public or for a specific channel, users will be able to send prompts for that session using your authorizations but they won't be able to see the auth values or copy those auth to a new chatgpt session.
869
+ You can add messages from a channel to your session by using `add history #CHANNEL_NAME`.
870
+
871
+ If you want to delete the last ChatGPT response and send again last prompt, you can use `resend prompt`.
872
+ You can set the context of your ChatGPT session: `set context CONTEXT`. Example: `set context You are a funny comedian who tells dad jokes. The output should be in JSON format.`
873
+
874
+ Also if you are using a model that allows you to add images to your prompt (fex gpt-4o), you can attach any images.
875
+
876
+ <img src="img/chat_gpt_attach_image.png" width="500">
877
+
863
878
  When on a thread you can change the model to be used by sending `use model MODEL_NAME`. For a temporary session if you want to create the session with a specific model use `?? use model MODEL_NAME`. The model supplied can be a substring of the model name, SmartBot will try to find the model that matches the substring.
864
879
 
865
880
  <img src="img/chat_gpt_session.png" width="650">
@@ -873,9 +888,27 @@ To remove any shared session from the list, call `chatGPT stop sharing SESSION_N
873
888
  Play this video:
874
889
  [![SmartBot ChatGPT Share Sessions](https://img.youtube.com/vi/Mnve3tnEd-8/0.jpg)](https://www.youtube.com/watch?v=Mnve3tnEd-8)
875
890
 
891
+ It is possible to use a session that is public, private or shared with a channel as a temporary session: `?? use SESSION_NAME PROMPT`. For example: `?? use lunch What's for Thursday?`. This will create a temporary session using the session named as `lunch` and send the prompt `What's for Thursday?`
892
+
876
893
  You can also use ChatGPT when creating REPLs. During the REPL session you can ask *ChatGPT* about the code or any other question. Just start the message with `?` and the Smart Bot will ask ChatGPT and will post the answer. Example: `? How to create a new customer?`. If you send just the question mark without a prompt then ChatGPT will suggest next code line. Example: `?`
877
894
  To send the results of a *SmartBot command* as input for a *ChatGPT* session, use `COMMAND ?? PROMPT`. Example: `bot help ?? how can I use the time off commands`. If you are on a thread you can send more SmartBot commands to the same session by using `COMMAND ?? PROMPT`.
878
895
 
896
+ ##### Docs Folder for ChatGPT Sessions
897
+ > For admins
898
+
899
+ Doc folders can be added by admins for specific chatgpt sessions. SmartBot will filter those docs depending on the prompt and attach them along with the prompt.
900
+ Put all docs as text files on `./openai/TEAM_ID/USER_NAME/SESSION_NAME/docs_folder`.
901
+ For the documents to be filtered add them to `filter` subfolder under `docs_folder`.
902
+ For the documents to be added always to the prompts, add them to `include` subfolder under `docs_folder`.
903
+ Inside those subfolders you can organize the documents the way you want.
904
+
905
+ ##### Restrict who has access to a specific model
906
+ > For admins
907
+
908
+ You can add a file named restricted_models.yaml on ./openai folder supplying the models and users that will have access to specific models.
909
+ Example of content:
910
+ o1-mini: [rmario, peter]
911
+ o1-preview: [rmario]
879
912
 
880
913
  #### Image Generation
881
914
  > for all users
Binary file
@@ -1,26 +1,35 @@
1
1
  class SlackSmartBot
2
2
  module AI
3
3
  module OpenAI
4
- def self.models(open_ai_client, models_config, model='', return_response: false)
4
+ def self.models(open_ai_client, models_config, model = "", return_response: false)
5
5
  require "openai"
6
- require 'amazing_print'
6
+ require "amazing_print"
7
7
  user = Thread.current[:user]
8
- if model.empty? or model == 'chatgpt'
8
+ models = []
9
+ if model.empty? or model == "chatgpt"
9
10
  if open_ai_client.is_a?(NiceHttp) and models_config.url != ""
10
11
  resp = open_ai_client.get(models_config.url)
11
- models = resp.body.json(:model_name)
12
- models.select!{|i| i.include?('gpt-')} if model == 'chatgpt'
12
+ #save resp to a file
13
+ resp.body.json.data.each do |m|
14
+ if model.empty? or (model == "chatgpt" and
15
+ (m[:model_name].to_s.include?("gpt-") or (m.key?(:model_info) and m[:model_info][:mode].to_s == "chat")))
16
+ models << m[:model_name]
17
+ end
18
+ end
13
19
  elsif open_ai_client.is_a?(NiceHttp) #azure
20
+ #todo: consider filtering by model mode
14
21
  resp = open_ai_client.get("/openai/deployments?api-version=#{models_config.api_version}")
15
22
  models = resp.body.json(:id)
16
- models.select!{|i| i.include?('gpt-')} if model == 'chatgpt'
23
+ models.flatten!
24
+ models.select! { |i| i.include?("gpt-") } if model == "chatgpt"
17
25
  else
26
+ #todo: consider filtering by model mode
18
27
  response = open_ai_client.models.list
19
28
  models = []
20
29
  response.data.each do |model|
21
30
  models << model["id"]
22
31
  end
23
- models.select!{|i| i.include?('gpt-')} if model == 'chatgpt'
32
+ models.select! { |i| i.include?("gpt-") } if model == "chatgpt"
24
33
  end
25
34
  if return_response
26
35
  return models.uniq.sort
@@ -39,11 +48,11 @@ class SlackSmartBot
39
48
  end
40
49
  end
41
50
  if result.empty?
42
- response = {message: "Model not found"}
51
+ response = { message: "Model not found" }
43
52
  response_obj = response
44
53
  else
45
- response = {message: ''}
46
- result[:model_info].each do |k,v|
54
+ response = { message: "" }
55
+ result[:model_info].each do |k, v|
47
56
  response.message += "#{k}: #{v}\n"
48
57
  end
49
58
  response_obj = result[:model_info]
@@ -1,43 +1,47 @@
1
1
  class SlackSmartBot
2
2
  module AI
3
3
  module OpenAI
4
- def self.send_gpt_chat(open_ai_client, model, message, chat_gpt_config)
4
+ def self.send_gpt_chat(open_ai_client, model, messages, chat_gpt_config)
5
5
  require "openai"
6
- require 'nice_http'
6
+ require "nice_http"
7
7
  user = Thread.current[:user]
8
8
  if user.key?(:sso_user_name)
9
9
  user_name = user.sso_user_name
10
10
  else
11
11
  user_name = user.name
12
12
  end
13
+ if messages.is_a?(String)
14
+ messages = [{ role: "user", content: messages }]
15
+ end
13
16
  parameters = {
14
17
  model: model, # Required.
15
- messages: [{ role: "user", content: message }], # Required.
18
+ messages: messages,
16
19
  temperature: 0.7,
17
- user: user_name
20
+ user: user_name,
18
21
  }
22
+
19
23
  parameters.user = chat_gpt_config.fixed_user if chat_gpt_config.fixed_user.to_s != ""
20
24
  if open_ai_client.is_a?(NiceHttp)
21
25
  begin
22
26
  response = {}
23
27
  tries = 0
24
- while (!response.key?(:data) or response.data.nil? or response.data.empty? ) and tries < 10
28
+ while (!response.key?(:data) or response.data.nil? or response.data.empty?) and tries < 10
25
29
  begin
26
30
  request = {
27
31
  path: "/openai/deployments/#{model}/chat/completions?api-version=#{chat_gpt_config.api_version}",
28
- data: parameters
32
+ data: parameters,
29
33
  }
30
34
  response = open_ai_client.post(request)
31
35
  rescue Exception => exception
32
- response = {message: exception.message}.to_json
36
+ response = { message: exception.message }.to_json
33
37
  end
34
38
  tries += 1
35
39
  sleep 1 if !response.key?(:data) or response.data.nil? or response.data.empty? #wait a second before trying again
36
40
  end
37
- response.data = { message: ""}.to_json if !response.key?(:data) or response.data.nil? or response.data.empty?
41
+ response.data = { message: "" }.to_json if !response.key?(:data) or response.data.nil? or response.data.empty?
38
42
  response = response.data
39
43
  rescue Exception => exception
40
- response = {message: exception.message}.to_json
44
+ response = { message: exception.message }.to_json
41
45
  end
42
46
  else
43
47
  begin
@@ -49,7 +53,7 @@ class SlackSmartBot
49
53
  response.body.error.message += "\nThe user on Slack is: #{user.name}\nYou have to go to your Profile Slack Account on a browser. Then go to Settings.\nNow go to Username and click on expand, change the name to your SSO name and click on Save"
50
54
  end
51
55
  if response.nil?
52
- response = {message: e.message}
56
+ response = { message: e.message }
53
57
  else
54
58
  response = response.to_json
55
59
  end
@@ -1,5 +1,4 @@
1
1
  class SlackSmartBot
2
-
3
2
  def dont_understand(rules_file = nil, command = nil, user = nil, dest = nil, answer = ["what?", "huh?", "sorry?", "what do you mean?", "I don't understand"], channel_rules: config.channel, typem: nil)
4
3
  save_stats(:dont_understand)
5
4
  command = Thread.current[:command] if command.nil?
@@ -7,10 +6,10 @@ class SlackSmartBot
7
6
  dest = Thread.current[:dest] if dest.nil?
8
7
  rules_file = Thread.current[:rules_file] if rules_file.nil?
9
8
  typem = Thread.current[:typem] if typem.nil?
10
- if typem==:on_extended
9
+ if typem == :on_extended
11
10
  get_bots_created()
12
11
  end
13
- text = get_help(rules_file, dest, user, typem==:on_extended, true)
12
+ text = get_help(rules_file, dest, user, typem == :on_extended, true)
14
13
 
15
14
  ff = text.scan(/^\s*`\s*([^`]+)\s*`\s*$/i).flatten
16
15
  ff.delete("!THE_COMMAND")
@@ -41,7 +40,7 @@ class SlackSmartBot
41
40
  end
42
41
  res_final.flatten!
43
42
 
44
- if typem==:on_extended
43
+ if typem == :on_extended
45
44
  if @extended_from[@channels_name[dest]].size == 1
46
45
  respond "#{user.profile.display_name}, I don't understand.", dest
47
46
  end
@@ -49,8 +48,8 @@ class SlackSmartBot
49
48
  respond "Similar rules on : *#{channel_rules}*\n`#{res_final[0..4].join("`\n`")}`", dest
50
49
  end
51
50
  else
52
- message = ''
53
- message = "\nTake in consideration when on external calls, not all the commands are available." if typem==:on_call
51
+ message = ""
52
+ message = "\nTake in consideration when on external calls, not all the commands are available." if typem == :on_call
54
53
  if res_final.empty?
55
54
  resp = answer.sample
56
55
  respond "#{user.profile.display_name}, #{resp}#{message}", dest
@@ -58,5 +57,23 @@ class SlackSmartBot
58
57
  respond "#{user.profile.display_name}, I don't understand. Maybe you are trying to say:\n`#{res_final[0..4].join("`\n`")}`#{message}", dest
59
58
  end
60
59
  end
60
+
61
+ ai_conn, message = SlackSmartBot::AI::OpenAI.connect({}, config, {}, service: :chat_gpt)
62
+ if message.empty?
63
+ react :speech_balloon
64
+ chatgpt = ai_conn[Thread.current[:team_id_user]].chat_gpt
65
+ model = chatgpt.smartbot_model if model.nil?
66
+ prompt = "I sent this command to Slack SmartBot: `#{command}` and it seems that is wrong\n\n"
67
+ prompt += "These are the available SmartBot commands:\n#{text}\n\n"
68
+ prompt += "Please, can you suggest the command that I mean?\n"
69
+ prompt += "Return just like 5 lines of text max. If you supply a command do it like this: `the command`"
70
+ success, res = SlackSmartBot::AI::OpenAI.send_gpt_chat(chatgpt.client, model, prompt, chatgpt)
71
+ if success
72
+ response_message = "*ChatGPT*: Maybe you are trying to say:\n#{res.to_s.strip}\n\n"
73
+ response_message += "Remember you can always ask for help by calling `bot help ?? YOUR QUESTION`."
74
+ respond transform_to_slack_markdown(response_message), dest
75
+ end
76
+ unreact :speech_balloon
77
+ end
61
78
  end
62
79
  end
@@ -1,17 +1,16 @@
1
1
  class SlackSmartBot
2
-
3
2
  def get_user_info(user, is_bot: false)
4
3
  begin
5
- if user.to_s.length>0
6
- if user[0]=='@' #name
4
+ if user.to_s.length > 0
5
+ if user[0] == "@" #name
7
6
  user = user[1..-1]
8
7
  is_name = true
9
8
  else
10
9
  is_name = false
11
10
  end
12
11
  if user.match?(/^[A-Z0-9]{7,11}_/) #team_id_user_name
13
- team_id = user.split('_')[0]
14
- user = user.split('_')[1..-1].join('_')
12
+ team_id = user.split("_")[0]
13
+ user = user.split("_")[1..-1].join("_")
15
14
  else
16
15
  team_id = config.team_id
17
16
  end
@@ -19,20 +18,20 @@ class SlackSmartBot
19
18
  if client.web_client.users_info.key?(user.to_sym) #id
20
19
  client.web_client.users_info[user.to_sym]
21
20
  else #name
22
- client.web_client.users_info.select{|k, v| v[:user][:name] == user and v[:user][:team_id] == team_id}.values[-1]
21
+ client.web_client.users_info.select { |k, v| v[:user][:name] == user and v[:user][:team_id] == team_id }.values[-1]
23
22
  end
24
23
  else
25
24
  if is_bot
26
25
  @logger.info "Getting bot info for <#{user}>"
27
26
  begin
28
27
  result = client.web_client.bots_info(bot: user)
29
- rescue Exception => stack
30
- @logger.warn stack
28
+ rescue Exception => e
29
+ @logger.warn "Failed to get bot info for <#{user}>: #{e.message}"
31
30
  return nil
32
31
  end
33
32
  if !result.nil? and result.key?(:bot) and result[:bot].key?(:user_id)
34
- user = result[:bot][:user_id]
35
- is_name = false
33
+ user = result[:bot][:user_id]
34
+ is_name = false
36
35
  else
37
36
  return nil
38
37
  end
@@ -1,5 +1,5 @@
1
1
  class SlackSmartBot
2
- def respond(msg = "", dest = nil, unfurl_links: true, unfurl_media: true, thread_ts: "", web_client: true, blocks: [], dont_share: false, return_message: false, max_chars_per_message: 4000)
2
+ def respond(msg = "", dest = nil, unfurl_links: true, unfurl_media: true, thread_ts: "", web_client: true, blocks: [], dont_share: false, return_message: false, max_chars_per_message: 4000, split: true)
3
3
  result = true
4
4
  resp = nil
5
5
 
@@ -10,7 +10,7 @@ class SlackSmartBot
10
10
  if (msg.to_s != "" or !msg.to_s.match?(/^A\s*\z/) or !blocks.empty?) and Thread.current[:routine_type].to_s != "bgroutine"
11
11
  if !web_client.is_a?(TrueClass) and !web_client.is_a?(FalseClass)
12
12
  (!unfurl_links or !unfurl_media) ? web_client = true : web_client = false
13
- end
13
+ end
14
14
  begin
15
15
  msg = msg.to_s
16
16
  web_client = true if !blocks.empty?
@@ -38,7 +38,7 @@ class SlackSmartBot
38
38
 
39
39
  dest = @channels_id[dest] if @channels_id.key?(dest) #it is a name of channel
40
40
 
41
- on_thread ? txt_on_thread=":on_thread:" : txt_on_thread=''
41
+ on_thread ? txt_on_thread = ":on_thread:" : txt_on_thread = ""
42
42
 
43
43
  if blocks.empty?
44
44
  if !config.simulate #https://api.slack.com/docs/rate-limits
@@ -62,36 +62,40 @@ class SlackSmartBot
62
62
  num_chars_code = 0
63
63
  print_previous = false
64
64
  if in_a_code_block
65
- all_lines[i+1..-1].each do |l|
66
- num_chars_code += l.size
65
+ all_lines[i + 1..-1].each do |l|
66
+ num_chars_code += l.size + 1 # +1 for the \n
67
67
  break if l.match?(/^\s*```/)
68
68
  end
69
- if num_chars_code + (m + txt).size > max_chars_per_message
69
+ if (num_chars_code + (m + txt).size > max_chars_per_message) and txt != ""
70
70
  print_previous = true
71
- end
71
+ end
72
72
  end
73
- end
73
+ end
74
74
  if ((m + txt).size > max_chars_per_message and !in_a_code_block) or print_previous
75
75
  unless txt == ""
76
- txt[0] = '.' if txt.match?(/\A\s\s\s/) #first line of message in slack don't show spaces at the begining so we force it by changing first char
76
+ txt[0] = "." if txt.match?(/\A\s\s\s/) #first line of message in slack don't show spaces at the begining so we force it by changing first char
77
77
  if m.match?(/^\s*```\s*$/) and !in_a_code_block
78
78
  txt += (m + "\n")
79
79
  m = ""
80
80
  end
81
- t = txt.chars.each_slice(max_chars_per_message).map(&:join)
82
- msgs << t
81
+ if split
82
+ t = txt.chars.each_slice(max_chars_per_message).map(&:join) #jalsplit
83
+ msgs << t
84
+ else
85
+ msgs << txt #not necessary to split the message in smaller parts since we are sending it as a file now
86
+ end
83
87
  txt = ""
84
88
  print_previous = false if print_previous
85
89
  end
86
90
  end
87
91
  txt += (m + "\n")
88
- txt[0] = '.' if txt.match?(/\A\s\s\s/) #first line of message in slack don't show spaces at the begining so we force it by changing first char
92
+ txt[0] = "." if txt.match?(/\A\s\s\s/) #first line of message in slack don't show spaces at the begining so we force it by changing first char
89
93
  txt[0] = ". " if txt.match?(/\A\t/)
90
94
  end
91
95
  end
92
96
  msgs << txt
93
97
  msgs.flatten!
94
- msgs.delete_if{|e| e.match?(/\A\s*\z/)}
98
+ msgs.delete_if { |e| e.match?(/\A\s*\z/) }
95
99
  if dest.nil?
96
100
  if config[:simulate]
97
101
  open("#{config.path}/buffer_complete.log", "a") { |f|
@@ -100,19 +104,27 @@ class SlackSmartBot
100
104
  else
101
105
  if on_thread
102
106
  msgs.each do |msg|
103
- if web_client
104
- resp = client.web_client.chat_postMessage(channel: @channel_id, text: msg, as_user: true, unfurl_links: unfurl_links, unfurl_media: unfurl_media, thread_ts: thread_ts)
107
+ if msg.size > max_chars_per_message
108
+ resp = send_file(@channel_id, "", "", "", "", "text", content: msg)
105
109
  else
106
- resp = client.message(channel: @channel_id, text: msg, as_user: true, thread_ts: thread_ts, unfurl_links: unfurl_links, unfurl_media: unfurl_media)
110
+ if web_client
111
+ resp = client.web_client.chat_postMessage(channel: @channel_id, text: msg, as_user: true, unfurl_links: unfurl_links, unfurl_media: unfurl_media, thread_ts: thread_ts)
112
+ else
113
+ resp = client.message(channel: @channel_id, text: msg, as_user: true, thread_ts: thread_ts, unfurl_links: unfurl_links, unfurl_media: unfurl_media)
114
+ end
107
115
  end
108
116
  sleep wait
109
117
  end
110
118
  else
111
119
  msgs.each do |msg|
112
- if web_client
113
- resp = client.web_client.chat_postMessage(channel: @channel_id, text: msg, as_user: true, unfurl_links: unfurl_links, unfurl_media: unfurl_media)
120
+ if msg.size > max_chars_per_message
121
+ resp = send_file(@channel_id, "", "", "", "", "text", content: msg)
114
122
  else
115
- resp = client.message(channel: @channel_id, text: msg, as_user: true, unfurl_links: unfurl_links, unfurl_media: unfurl_media)
123
+ if web_client
124
+ resp = client.web_client.chat_postMessage(channel: @channel_id, text: msg, as_user: true, unfurl_links: unfurl_links, unfurl_media: unfurl_media)
125
+ else
126
+ resp = client.message(channel: @channel_id, text: msg, as_user: true, unfurl_links: unfurl_links, unfurl_media: unfurl_media)
127
+ end
116
128
  end
117
129
  sleep wait
118
130
  end
@@ -132,19 +144,27 @@ class SlackSmartBot
132
144
  else
133
145
  if on_thread
134
146
  msgs.each do |msg|
135
- if web_client
136
- resp = client.web_client.chat_postMessage(channel: dest, text: msg, as_user: true, unfurl_links: unfurl_links, unfurl_media: unfurl_media, thread_ts: thread_ts)
147
+ if msg.size > max_chars_per_message
148
+ resp = send_file(dest, "", "", "", "", "text", content: msg)
137
149
  else
138
- resp = client.message(channel: dest, text: msg, as_user: true, thread_ts: thread_ts, unfurl_links: unfurl_links, unfurl_media: unfurl_media)
150
+ if web_client
151
+ resp = client.web_client.chat_postMessage(channel: dest, text: msg, as_user: true, unfurl_links: unfurl_links, unfurl_media: unfurl_media, thread_ts: thread_ts)
152
+ else
153
+ resp = client.message(channel: dest, text: msg, as_user: true, thread_ts: thread_ts, unfurl_links: unfurl_links, unfurl_media: unfurl_media)
154
+ end
139
155
  end
140
156
  sleep wait
141
157
  end
142
158
  else
143
159
  msgs.each do |msg|
144
- if web_client
145
- resp = client.web_client.chat_postMessage(channel: dest, text: msg, as_user: true, unfurl_links: unfurl_links, unfurl_media: unfurl_media)
160
+ if msg.size > max_chars_per_message
161
+ resp = send_file(dest, "", "", "", "", "text", content: msg)
146
162
  else
147
- resp = client.message(channel: dest, text: msg, as_user: true, unfurl_links: unfurl_links, unfurl_media: unfurl_media)
163
+ if web_client
164
+ resp = client.web_client.chat_postMessage(channel: dest, text: msg, as_user: true, unfurl_links: unfurl_links, unfurl_media: unfurl_media)
165
+ else
166
+ resp = client.message(channel: dest, text: msg, as_user: true, unfurl_links: unfurl_links, unfurl_media: unfurl_media)
167
+ end
148
168
  end
149
169
  sleep wait
150
170
  end
@@ -158,14 +178,22 @@ class SlackSmartBot
158
178
  end
159
179
  elsif dest[0] == "D" or dest[0] == "U" or dest[0] == "W" # Direct message
160
180
  msgs.each do |msg|
161
- resp = send_msg_user(dest, msg, on_thread, unfurl_links: unfurl_links, unfurl_media: unfurl_media, thread_ts: thread_ts)
181
+ if msg.size > max_chars_per_message
182
+ resp = send_file(dest, "", "", "", "", "text", content: msg)
183
+ else
184
+ resp = send_msg_user(dest, msg, on_thread, unfurl_links: unfurl_links, unfurl_media: unfurl_media, thread_ts: thread_ts)
185
+ end
162
186
  sleep wait
163
187
  end
164
188
  elsif dest[0] == "@"
165
189
  begin
166
190
  user_info = @users.select { |u| u.id == dest[1..-1] or u.name == dest[1..-1] or (u.key?(:enterprise_user) and u.enterprise_user.id == dest[1..-1]) }[-1]
167
191
  msgs.each do |msg|
168
- resp = send_msg_user(user_info.id, msg, on_thread, unfurl_links: unfurl_links, unfurl_media: unfurl_media, thread_ts: thread_ts)
192
+ if msg.size > max_chars_per_message
193
+ resp = send_file(user_info.id, "", "", "", "", "text", content: msg)
194
+ else
195
+ resp = send_msg_user(user_info.id, msg, on_thread, unfurl_links: unfurl_links, unfurl_media: unfurl_media, thread_ts: thread_ts)
196
+ end
169
197
  sleep wait
170
198
  end
171
199
  rescue Exception => stack
@@ -190,7 +218,7 @@ class SlackSmartBot
190
218
  else
191
219
  if on_thread
192
220
  blocks.each_slice(40).to_a.each do |blockstmp|
193
- resp = client.web_client.chat_postMessage(channel: @channel_id, blocks: blockstmp, as_user: true, thread_ts: thread_ts)
221
+ resp = client.web_client.chat_postMessage(channel: @channel_id, blocks: blockstmp, as_user: true, thread_ts: thread_ts)
194
222
  sleep wait
195
223
  end
196
224
  else
@@ -5,10 +5,10 @@ class SlackSmartBot
5
5
  #send_file(dest, 'the message', "#{project_folder}/temp/example.jpeg", 'message to be sent', 'image/jpeg', "jpg")
6
6
  #send_file(dest, 'the message', "", 'message to be sent', 'text/plain', "ruby", content: "the content to be sent when no file supplied")
7
7
  #send_file(dest, 'the message', "myfile.rb", 'message to be sent', 'text/plain', "ruby", content: "the content to be sent when no file supplied")
8
- def send_file(to, msg, file, title, format, type = "text", content: '')
8
+ def send_file(to, msg, file, title, format, type = "text", content: "")
9
9
  unless config[:simulate]
10
10
  begin
11
- file = 'myfile' if file.to_s == '' and content!=''
11
+ file = "myfile" if file.to_s == "" and content != ""
12
12
  if to[0] == "U" or to[0] == "W" #user
13
13
  im = client.web_client.conversations_open(users: id_user)
14
14
  channel = im["channel"]["id"]
@@ -22,7 +22,7 @@ class SlackSmartBot
22
22
  ts = nil
23
23
  end
24
24
 
25
- if content.to_s == ''
25
+ if content.to_s == ""
26
26
  client.web_client.files_upload(
27
27
  channels: channel,
28
28
  as_user: true,
@@ -31,9 +31,21 @@ class SlackSmartBot
31
31
  filename: file,
32
32
  filetype: type,
33
33
  initial_comment: msg,
34
- thread_ts: ts
34
+ thread_ts: ts,
35
35
  )
36
36
  else
37
+ content.strip!
38
+ #if first line is ```TYPE, then set file_type to TYPE
39
+ if content[0..2] == "```"
40
+ type = content[3..-1].split("\n")[0]
41
+ content = content.split("\n")[1..-1].join("\n")
42
+ #remove the last line if it is ```
43
+ if content[-3..-1] == "```"
44
+ content = content[0..-4]
45
+ end
46
+ content.gsub!(/[\u0080-\uFFFF]/, "?") #replace all non-ascii characters with a question mark
47
+ end
48
+ type = "text" if type.to_s == ""
37
49
  client.web_client.files_upload(
38
50
  channels: channel,
39
51
  as_user: true,
@@ -42,7 +54,7 @@ class SlackSmartBot
42
54
  filename: file,
43
55
  filetype: type,
44
56
  initial_comment: msg,
45
- thread_ts: ts
57
+ thread_ts: ts,
46
58
  )
47
59
  end
48
60
  rescue Exception => stack
@@ -50,5 +62,4 @@ class SlackSmartBot
50
62
  end
51
63
  end
52
64
  end
53
-
54
65
  end