bas 0.4.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/README.md +68 -147
  4. data/lib/bas/bot/base.rb +74 -0
  5. data/lib/bas/bot/compare_wip_limit_count.rb +92 -0
  6. data/lib/bas/bot/fetch_birthdays_from_notion.rb +128 -0
  7. data/lib/bas/bot/fetch_domains_wip_counts_from_notion.rb +121 -0
  8. data/lib/bas/bot/fetch_domains_wip_limit_from_notion.rb +134 -0
  9. data/lib/bas/bot/fetch_emails_from_imap.rb +99 -0
  10. data/lib/bas/bot/fetch_next_week_birthdays_from_notion.rb +142 -0
  11. data/lib/bas/bot/fetch_next_week_ptos_from_notion.rb +162 -0
  12. data/lib/bas/bot/fetch_ptos_from_notion.rb +138 -0
  13. data/lib/bas/bot/format_birthdays.rb +97 -0
  14. data/lib/bas/bot/format_emails.rb +124 -0
  15. data/lib/bas/bot/format_wip_limit_exceeded.rb +97 -0
  16. data/lib/bas/bot/garbage_collector.rb +85 -0
  17. data/lib/bas/bot/humanize_pto.rb +119 -0
  18. data/lib/bas/bot/notify_discord.rb +96 -0
  19. data/lib/bas/read/base.rb +10 -23
  20. data/lib/bas/read/default.rb +16 -0
  21. data/lib/bas/read/postgres.rb +44 -0
  22. data/lib/bas/read/types/response.rb +18 -0
  23. data/lib/bas/utils/discord/integration.rb +43 -0
  24. data/lib/bas/utils/exceptions/function_not_implemented.rb +16 -0
  25. data/lib/bas/utils/exceptions/invalid_process_response.rb +16 -0
  26. data/lib/bas/utils/imap/request.rb +76 -0
  27. data/lib/bas/utils/notion/request.rb +45 -0
  28. data/lib/bas/utils/openai/run_assistant.rb +99 -0
  29. data/lib/bas/utils/postgres/request.rb +50 -0
  30. data/lib/bas/version.rb +1 -1
  31. data/lib/bas/write/base.rb +12 -17
  32. data/lib/bas/write/postgres.rb +45 -0
  33. data/lib/bas/write/postgres_update.rb +49 -0
  34. data/lib/bas.rb +1 -3
  35. metadata +30 -67
  36. data/lib/bas/domain/birthday.rb +0 -25
  37. data/lib/bas/domain/email.rb +0 -34
  38. data/lib/bas/domain/exceptions/function_not_implemented.rb +0 -18
  39. data/lib/bas/domain/issue.rb +0 -22
  40. data/lib/bas/domain/notification.rb +0 -23
  41. data/lib/bas/domain/pto.rb +0 -69
  42. data/lib/bas/domain/work_items_limit.rb +0 -25
  43. data/lib/bas/formatter/base.rb +0 -53
  44. data/lib/bas/formatter/birthday.rb +0 -38
  45. data/lib/bas/formatter/exceptions/invalid_data.rb +0 -15
  46. data/lib/bas/formatter/notification.rb +0 -34
  47. data/lib/bas/formatter/pto.rb +0 -89
  48. data/lib/bas/formatter/support_emails.rb +0 -73
  49. data/lib/bas/formatter/types/response.rb +0 -16
  50. data/lib/bas/formatter/work_items_limit.rb +0 -68
  51. data/lib/bas/process/base.rb +0 -39
  52. data/lib/bas/process/discord/exceptions/invalid_webhook_token.rb +0 -16
  53. data/lib/bas/process/discord/implementation.rb +0 -71
  54. data/lib/bas/process/discord/types/response.rb +0 -22
  55. data/lib/bas/process/openai/base.rb +0 -72
  56. data/lib/bas/process/openai/helper.rb +0 -19
  57. data/lib/bas/process/openai/types/response.rb +0 -27
  58. data/lib/bas/process/openai/use_case/humanize_pto.rb +0 -53
  59. data/lib/bas/process/slack/exceptions/invalid_webhook_token.rb +0 -16
  60. data/lib/bas/process/slack/implementation.rb +0 -70
  61. data/lib/bas/process/slack/types/response.rb +0 -21
  62. data/lib/bas/process/types/response.rb +0 -16
  63. data/lib/bas/read/github/base.rb +0 -57
  64. data/lib/bas/read/github/types/response.rb +0 -27
  65. data/lib/bas/read/github/use_case/repo_issues.rb +0 -17
  66. data/lib/bas/read/imap/base.rb +0 -70
  67. data/lib/bas/read/imap/types/response.rb +0 -27
  68. data/lib/bas/read/imap/use_case/support_emails.rb +0 -26
  69. data/lib/bas/read/notion/base.rb +0 -52
  70. data/lib/bas/read/notion/exceptions/invalid_api_key.rb +0 -15
  71. data/lib/bas/read/notion/exceptions/invalid_database_id.rb +0 -15
  72. data/lib/bas/read/notion/helper.rb +0 -21
  73. data/lib/bas/read/notion/types/response.rb +0 -26
  74. data/lib/bas/read/notion/use_case/birthday_next_week.rb +0 -41
  75. data/lib/bas/read/notion/use_case/birthday_today.rb +0 -29
  76. data/lib/bas/read/notion/use_case/notification.rb +0 -28
  77. data/lib/bas/read/notion/use_case/pto_next_week.rb +0 -71
  78. data/lib/bas/read/notion/use_case/pto_today.rb +0 -30
  79. data/lib/bas/read/notion/use_case/work_items_limit.rb +0 -37
  80. data/lib/bas/read/postgres/base.rb +0 -46
  81. data/lib/bas/read/postgres/helper.rb +0 -16
  82. data/lib/bas/read/postgres/types/response.rb +0 -42
  83. data/lib/bas/read/postgres/use_case/pto_today.rb +0 -32
  84. data/lib/bas/serialize/base.rb +0 -30
  85. data/lib/bas/serialize/github/issues.rb +0 -57
  86. data/lib/bas/serialize/imap/support_emails.rb +0 -56
  87. data/lib/bas/serialize/notion/birthday_today.rb +0 -68
  88. data/lib/bas/serialize/notion/notification.rb +0 -56
  89. data/lib/bas/serialize/notion/pto_today.rb +0 -75
  90. data/lib/bas/serialize/notion/work_items_limit.rb +0 -65
  91. data/lib/bas/serialize/postgres/pto_today.rb +0 -47
  92. data/lib/bas/use_cases/types/config.rb +0 -20
  93. data/lib/bas/use_cases/use_case.rb +0 -42
  94. data/lib/bas/use_cases/use_cases.rb +0 -465
  95. data/lib/bas/write/logs/base.rb +0 -33
  96. data/lib/bas/write/logs/use_case/console_log.rb +0 -22
  97. data/lib/bas/write/notion/base.rb +0 -36
  98. data/lib/bas/write/notion/use_case/empty_notification.rb +0 -38
  99. data/lib/bas/write/notion/use_case/notification.rb +0 -38
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./base"
4
+ require_relative "../read/default"
5
+ require_relative "../utils/notion/request"
6
+ require_relative "../write/postgres"
7
+
8
+ module Bot
9
+ ##
10
+ # The Bot::FetchPtosFromNotion class serves as a bot implementation to read PTO's from a
11
+ # notion database and write them on a PostgresDB table with a specific format.
12
+ #
13
+ # <br>
14
+ # <b>Example</b>
15
+ #
16
+ # options = {
17
+ # process_options: {
18
+ # database_id: "notion database id",
19
+ # secret: "notion secret"
20
+ # },
21
+ # write_options: {
22
+ # connection: {
23
+ # host: "host",
24
+ # port: 5432,
25
+ # dbname: "bas",
26
+ # user: "postgres",
27
+ # password: "postgres"
28
+ # },
29
+ # db_table: "pto",
30
+ # tag: "FetchPtosFromNotion"
31
+ # }
32
+ # }
33
+ #
34
+ # bot = Bot::FetchPtosFromNotion.new(options)
35
+ # bot.execute
36
+ #
37
+ class FetchPtosFromNotion < Bot::Base
38
+ # Read function to execute the default Read component
39
+ #
40
+ def read
41
+ reader = Read::Default.new
42
+
43
+ reader.execute
44
+ end
45
+
46
+ # Process function to execute the Notion utility to fetch PTO's from the notion database
47
+ #
48
+ def process
49
+ response = Utils::Notion::Request.execute(params)
50
+
51
+ if response.code == 200
52
+ ptos_list = normalize_response(response.parsed_response["results"])
53
+
54
+ { success: { ptos: ptos_list } }
55
+ else
56
+ { error: { message: response.parsed_response, status_code: response.code } }
57
+ end
58
+ end
59
+
60
+ # Write function to execute the PostgresDB write component
61
+ #
62
+ def write
63
+ write = Write::Postgres.new(write_options, process_response)
64
+
65
+ write.execute
66
+ end
67
+
68
+ private
69
+
70
+ def params
71
+ {
72
+ endpoint: "databases/#{process_options[:database_id]}/query",
73
+ secret: process_options[:secret],
74
+ method: "post",
75
+ body:
76
+ }
77
+ end
78
+
79
+ def body
80
+ { filter: { "or": conditions } }
81
+ end
82
+
83
+ def conditions
84
+ [
85
+ today_condition,
86
+ { property: "StartDateTime", date: { this_week: {} } },
87
+ { property: "EndDateTime", date: { this_week: {} } },
88
+ { property: "StartDateTime", date: { next_week: {} } },
89
+ { property: "EndDateTime", date: { next_week: {} } }
90
+ ]
91
+ end
92
+
93
+ def today_condition
94
+ today = Time.now.utc.strftime("%F").to_s
95
+ {
96
+ "and": [
97
+ { property: "StartDateTime", date: { on_or_before: today } },
98
+ { property: "EndDateTime", date: { on_or_after: today } }
99
+ ]
100
+ }
101
+ end
102
+
103
+ def normalize_response(results)
104
+ return [] if results.nil?
105
+
106
+ results.map do |pto|
107
+ pto_fields = pto["properties"]
108
+
109
+ {
110
+ "Name" => extract_description_field_value(pto_fields["Description"]),
111
+ "StartDateTime" => extract_date_field_value(pto_fields["StartDateTime"]),
112
+ "EndDateTime" => extract_date_field_value(pto_fields["EndDateTime"])
113
+ }
114
+ end
115
+ end
116
+
117
+ def extract_description_field_value(data)
118
+ names = data["title"].map { |name| name["plain_text"] }
119
+
120
+ names.join(" ")
121
+ end
122
+
123
+ def extract_date_field_value(date)
124
+ {
125
+ from: extract_start_date(date),
126
+ to: extract_end_date(date)
127
+ }
128
+ end
129
+
130
+ def extract_start_date(data)
131
+ data["date"]["start"]
132
+ end
133
+
134
+ def extract_end_date(data)
135
+ data["date"]["end"]
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./base"
4
+ require_relative "../read/postgres"
5
+ require_relative "../write/postgres"
6
+
7
+ module Bot
8
+ ##
9
+ # The Bot::FormatBirthdays class serves as a bot implementation to read birthdays from a
10
+ # PostgresDB database, format them with a specific template, and write them on a PostgresDB
11
+ # table with a specific format.
12
+ #
13
+ # <br>
14
+ # <b>Example</b>
15
+ #
16
+ # options = {
17
+ # read_options: {
18
+ # connection: {
19
+ # host: "localhost",
20
+ # port: 5432,
21
+ # dbname: "bas",
22
+ # user: "postgres",
23
+ # password: "postgres"
24
+ # },
25
+ # db_table: "use_cases",
26
+ # tag: "FetchBirthdaysFromNotion"
27
+ # },
28
+ # process_options: {
29
+ # template: "birthday template message"
30
+ # },
31
+ # write_options: {
32
+ # connection: {
33
+ # host: "localhost",
34
+ # port: 5432,
35
+ # dbname: "bas",
36
+ # user: "postgres",
37
+ # password: "postgres"
38
+ # },
39
+ # db_table: "use_cases",
40
+ # tag: "FormatBirthdays"
41
+ # }
42
+ # }
43
+ #
44
+ # bot = Bot::FormatBirthdays.new(options)
45
+ # bot.execute
46
+ #
47
+ class FormatBirthdays < Bot::Base
48
+ BIRTHDAY_ATTRIBUTES = %w[name birthday_date].freeze
49
+
50
+ # read function to execute the PostgresDB Read component
51
+ #
52
+ def read
53
+ reader = Read::Postgres.new(read_options.merge(conditions))
54
+
55
+ reader.execute
56
+ end
57
+
58
+ # Process function to format the notification using a template
59
+ #
60
+ def process
61
+ return { success: { notification: "" } } if unprocessable_response
62
+
63
+ birthdays_list = read_response.data["birthdays"]
64
+
65
+ notification = birthdays_list.reduce("") do |payload, birthday|
66
+ "#{payload} #{build_template(BIRTHDAY_ATTRIBUTES, birthday)} \n"
67
+ end
68
+
69
+ { success: { notification: } }
70
+ end
71
+
72
+ # Write function to execute the PostgresDB write component
73
+ #
74
+ def write
75
+ write = Write::Postgres.new(write_options, process_response)
76
+
77
+ write.execute
78
+ end
79
+
80
+ private
81
+
82
+ def conditions
83
+ {
84
+ where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
85
+ params: [false, read_options[:tag], "unprocessed"]
86
+ }
87
+ end
88
+
89
+ def build_template(attributes, instance)
90
+ template = process_options[:template]
91
+
92
+ attributes.reduce(template) do |formated_template, attribute|
93
+ formated_template.gsub("<#{attribute}>", instance[attribute].to_s)
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./base"
4
+ require_relative "../read/postgres"
5
+ require_relative "../write/postgres"
6
+
7
+ module Bot
8
+ ##
9
+ # The Bot::FormatEmails class serves as a bot implementation to read emails from a
10
+ # PostgresDB database, format them with a specific template, and write them on a PostgresDB
11
+ # table with a specific format.
12
+ #
13
+ # <br>
14
+ # <b>Example</b>
15
+ #
16
+ # options = {
17
+ # read_options: {
18
+ # connection: {
19
+ # host: "localhost",
20
+ # port: 5432,
21
+ # dbname: "bas",
22
+ # user: "postgres",
23
+ # password: "postgres"
24
+ # },
25
+ # db_table: "use_cases",
26
+ # tag: "FetchEmailsFromImap"
27
+ # },
28
+ # process_options: {
29
+ # template: "emails template message"
30
+ # },
31
+ # write_options: {
32
+ # connection: {
33
+ # host: "localhost",
34
+ # port: 5432,
35
+ # dbname: "bas",
36
+ # user: "postgres",
37
+ # password: "postgres"
38
+ # },
39
+ # db_table: "use_cases",
40
+ # tag: "FormatEmails"
41
+ # }
42
+ # }
43
+ #
44
+ # bot = Bot::FormatEmails.new(options)
45
+ # bot.execute
46
+ #
47
+ class FormatEmails < Bot::Base
48
+ EMAIL_ATTRIBUTES = %w[subject sender date].freeze
49
+ DEFAULT_TIME_ZONE = "+00:00"
50
+
51
+ # read function to execute the PostgresDB Read component
52
+ #
53
+ def read
54
+ reader = Read::Postgres.new(read_options.merge(conditions))
55
+
56
+ reader.execute
57
+ end
58
+
59
+ # Process function to format the notification using a template
60
+ #
61
+ def process
62
+ return { success: { notification: "" } } if unprocessable_response
63
+
64
+ emails_list = read_response.data["emails"]
65
+
66
+ notification = process_emails(emails_list).reduce("") do |payload, email|
67
+ "#{payload} #{build_template(EMAIL_ATTRIBUTES, email)} \n"
68
+ end
69
+
70
+ { success: { notification: } }
71
+ end
72
+
73
+ # Write function to execute the PostgresDB write component
74
+ #
75
+ def write
76
+ write = Write::Postgres.new(write_options, process_response)
77
+
78
+ write.execute
79
+ end
80
+
81
+ private
82
+
83
+ def conditions
84
+ {
85
+ where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
86
+ params: [false, read_options[:tag], "unprocessed"]
87
+ }
88
+ end
89
+
90
+ def process_emails(emails)
91
+ emails.each do |email|
92
+ date = DateTime.parse(email["date"]).to_time
93
+ email["date"] = at_timezone(date)
94
+ end
95
+ emails.filter! { |email| email["date"] > time_window } unless process_options[:frequency].nil?
96
+
97
+ format_timestamp(emails)
98
+ end
99
+
100
+ def format_timestamp(emails)
101
+ emails.each { |email| email["date"] = email["date"].strftime("%F %r") }
102
+ end
103
+
104
+ def time_window
105
+ date_time = Time.now - (60 * 60 * process_options[:frequency])
106
+
107
+ at_timezone(date_time)
108
+ end
109
+
110
+ def at_timezone(date)
111
+ timezone = process_options[:timezone] || DEFAULT_TIME_ZONE
112
+
113
+ Time.at(date, in: timezone)
114
+ end
115
+
116
+ def build_template(attributes, instance)
117
+ template = process_options[:template]
118
+
119
+ attributes.reduce(template) do |formated_template, attribute|
120
+ formated_template.gsub("<#{attribute}>", instance[attribute].to_s)
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./base"
4
+ require_relative "../read/postgres"
5
+ require_relative "../write/postgres"
6
+
7
+ module Bot
8
+ ##
9
+ # The Bot::FormatWipLimitExceeded class serves as a bot implementation to read exceeded domain wip
10
+ # counts by limits from a PostgresDB database, format them with a specific template, and write them
11
+ # on a PostgresDB table with a specific format.
12
+ #
13
+ # <br>
14
+ # <b>Example</b>
15
+ #
16
+ # options = {
17
+ # read_options: {
18
+ # connection: {
19
+ # host: "localhost",
20
+ # port: 5432,
21
+ # dbname: "bas",
22
+ # user: "postgres",
23
+ # password: "postgres"
24
+ # },
25
+ # db_table: "use_cases",
26
+ # tag: "CompareWipLimitCount"
27
+ # },
28
+ # process_options: {
29
+ # template: "exceeded wip limit template message"
30
+ # },
31
+ # write_options: {
32
+ # connection: {
33
+ # host: "localhost",
34
+ # port: 5432,
35
+ # dbname: "bas",
36
+ # user: "postgres",
37
+ # password: "postgres"
38
+ # },
39
+ # db_table: "use_cases",
40
+ # tag: "FormatWipLimitExceeded"
41
+ # }
42
+ # }
43
+ #
44
+ # bot = Bot::FormatWipLimitExceeded.new(options)
45
+ # bot.execute
46
+ #
47
+ class FormatWipLimitExceeded < Bot::Base
48
+ WIP_LIMIT_ATTRIBUTES = %w[domain exceeded].freeze
49
+
50
+ # read function to execute the PostgresDB Read component
51
+ #
52
+ def read
53
+ reader = Read::Postgres.new(read_options.merge(conditions))
54
+
55
+ reader.execute
56
+ end
57
+
58
+ # Process function to format the notification using a template
59
+ #
60
+ def process
61
+ return { success: { notification: "" } } if unprocessable_response
62
+
63
+ exceedded_limits_list = read_response.data["exceeded_domain_count"]
64
+
65
+ notification = exceedded_limits_list.reduce("") do |payload, exceedded_limit|
66
+ "#{payload} #{build_template(WIP_LIMIT_ATTRIBUTES, exceedded_limit)} \n"
67
+ end
68
+
69
+ { success: { notification: } }
70
+ end
71
+
72
+ # Write function to execute the PostgresDB write component
73
+ #
74
+ def write
75
+ write = Write::Postgres.new(write_options, process_response)
76
+
77
+ write.execute
78
+ end
79
+
80
+ private
81
+
82
+ def conditions
83
+ {
84
+ where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
85
+ params: [false, read_options[:tag], "unprocessed"]
86
+ }
87
+ end
88
+
89
+ def build_template(attributes, instance)
90
+ template = process_options[:template]
91
+
92
+ attributes.reduce(template) do |formated_template, attribute|
93
+ formated_template.gsub("<#{attribute}>", instance[attribute].to_s)
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./base"
4
+ require_relative "../read/default"
5
+ require_relative "../write/postgres"
6
+
7
+ module Bot
8
+ ##
9
+ # The Bot::GarbageCollector class serves as a bot implementation to archive bot records from a
10
+ # PostgresDB database table and write a response on a PostgresDB table with a specific format.
11
+ #
12
+ # <br>
13
+ # <b>Example</b>
14
+ #
15
+ # options = {
16
+ # process_options: {
17
+ # connection: {
18
+ # host: "localhost",
19
+ # port: 5432,
20
+ # dbname: "bas",
21
+ # user: "postgres",
22
+ # password: "postgres"
23
+ # },
24
+ # db_table: "use_cases"
25
+ # },
26
+ # write_options: {
27
+ # connection: {
28
+ # host: "localhost",
29
+ # port: 5432,
30
+ # dbname: "bas",
31
+ # user: "postgres",
32
+ # password: "postgres"
33
+ # },
34
+ # db_table: "use_cases"
35
+ # }
36
+ # }
37
+ #
38
+ # bot = Bot::GarbageCollector.new(options)
39
+ # bot.execute
40
+ #
41
+ class GarbageCollector < Bot::Base
42
+ SUCCESS_STATUS = "PGRES_COMMAND_OK"
43
+
44
+ # Read function to execute the default Read component
45
+ #
46
+ def read
47
+ reader = Read::Default.new
48
+
49
+ reader.execute
50
+ end
51
+
52
+ # Process function to update records in a PostgresDB database table
53
+ #
54
+ def process
55
+ response = Utils::Postgres::Request.execute(params)
56
+
57
+ if response.res_status == SUCCESS_STATUS
58
+ { success: { archived: true } }
59
+ else
60
+ { error: { message: response.result_error_message, status_code: response.res_status } }
61
+ end
62
+ end
63
+
64
+ # Write function to execute the PostgresDB write component
65
+ #
66
+ def write
67
+ write = Write::Postgres.new(write_options, process_response)
68
+
69
+ write.execute
70
+ end
71
+
72
+ private
73
+
74
+ def params
75
+ {
76
+ connection: process_options[:connection],
77
+ query:
78
+ }
79
+ end
80
+
81
+ def query
82
+ "UPDATE #{process_options[:db_table]} SET archived=true WHERE archived=false"
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./base"
4
+ require_relative "../read/postgres"
5
+ require_relative "../write/postgres"
6
+ require_relative "../utils/openai/run_assistant"
7
+
8
+ module Bot
9
+ ##
10
+ # The Bot::HumanizePto class serves as a bot implementation to read PTO's from a
11
+ # PostgresDb table, format them using an OpenAI Assistant with the OpenAI API, and
12
+ # write the response as a notification on a PostgresDB table.
13
+ #
14
+ # <br>
15
+ # <b>Example</b>
16
+ #
17
+ # options = {
18
+ # read_options: {
19
+ # connection: {
20
+ # host: "host",
21
+ # port: 5432,
22
+ # dbname: "bas",
23
+ # user: "postgres",
24
+ # password: "postgres"
25
+ # },
26
+ # db_table: "pto",
27
+ # tag: "FetchPtosFromNotion"
28
+ # },
29
+ # process_options: {
30
+ # secret: "openai secret key",
31
+ # assistant_id: "assistant_id",
32
+ # prompt: "optional additional prompt"
33
+ # },
34
+ # write_options: {
35
+ # connection: {
36
+ # host: "host",
37
+ # port: 5432,
38
+ # dbname: "bas",
39
+ # user: "postgres",
40
+ # password: "postgres"
41
+ # },
42
+ # db_table: "pto",
43
+ # tag: "HumanizePto"
44
+ # }
45
+ # }
46
+ #
47
+ # bot = Bot::HumanizePto.new(options)
48
+ # bot.execute
49
+ #
50
+ class HumanizePto < Bot::Base
51
+ DEFAULT_PROMPT = "{data}"
52
+
53
+ # read function to execute the PostgresDB Read component
54
+ #
55
+ def read
56
+ reader = Read::Postgres.new(read_options.merge(conditions))
57
+
58
+ reader.execute
59
+ end
60
+
61
+ # process function to execute the OpenaAI utility to process the PTO's
62
+ #
63
+ def process
64
+ return { success: { notification: "" } } if unprocessable_response
65
+
66
+ response = Utils::OpenAI::RunAssitant.execute(params)
67
+
68
+ if response.code != 200 || (!response["status"].nil? && response["status"] != "completed")
69
+ return error_response(response)
70
+ end
71
+
72
+ sucess_response(response)
73
+ end
74
+
75
+ # write function to execute the PostgresDB write component
76
+ #
77
+ def write
78
+ write = Write::Postgres.new(write_options, process_response)
79
+
80
+ write.execute
81
+ end
82
+
83
+ private
84
+
85
+ def conditions
86
+ {
87
+ where: "archived=$1 AND tag=$2 AND stage=$3 ORDER BY inserted_at ASC",
88
+ params: [false, read_options[:tag], "unprocessed"]
89
+ }
90
+ end
91
+
92
+ def params
93
+ {
94
+ assistant_id: process_options[:assistant_id],
95
+ secret: process_options[:secret],
96
+ prompt: build_prompt
97
+ }
98
+ end
99
+
100
+ def build_prompt
101
+ prompt = process_options[:prompt] || DEFAULT_PROMPT
102
+ ptos_list = read_response.data["ptos"]
103
+
104
+ ptos_list_formatted_string = ptos_list.map do |pto|
105
+ "#{pto["Name"]} is PTO from StartDateTime: #{pto["StartDateTime"]} to EndDateTime: #{pto["EndDateTime"]}"
106
+ end.join("\n")
107
+
108
+ prompt.gsub("{data}", ptos_list_formatted_string)
109
+ end
110
+
111
+ def sucess_response(response)
112
+ { success: { notification: response.parsed_response["data"].first["content"].first["text"]["value"] } }
113
+ end
114
+
115
+ def error_response(response)
116
+ { error: { message: response.parsed_response, status_code: response.code } }
117
+ end
118
+ end
119
+ end