diff --git a/app/jobs/magellan_rag_query_job.rb b/app/jobs/magellan_rag_query_job.rb index 5e81179..031e5df 100644 --- a/app/jobs/magellan_rag_query_job.rb +++ b/app/jobs/magellan_rag_query_job.rb @@ -129,11 +129,26 @@ def perform(params) user: message.user ) - posted_message = Utils.post_message( - channel: message.conversation.slack_id, - thread_ts: message.slack_thread_ts, - **post_params - ) + begin + posted_message = Utils.post_message( + channel: message.conversation.slack_id, + thread_ts: message.slack_thread_ts, + **post_params + ) + rescue Exception => err + logger.warn "Error occurred on post_message: #{err.full_message(highlight: false)}" + + post_params = format_simple_rag_response( + answer, + user: message.user + ) + + posted_message = Utils.post_message( + channel: message.conversation.slack_id, + thread_ts: message.slack_thread_ts, + **post_params + ) + end logger.info posted_message.inspect unless posted_message.ok @@ -172,6 +187,20 @@ def perform(params) {"answer" => s} end + private def format_simple_rag_response(answer, user:) + answer = rewrite_markdown_link(answer) + text = "<@#{user.slack_id}> 回答は次のとおりです。\n\n#{answer}" + response = SlackBot.format_chat_gpt_response(text) + feedback_block = response[:blocks].pop + response[:blocks] << { "type": "divider" } + response[:blocks] << feedback_block + response + end + + private def rewrite_markdown_link(s) + s.gsub(/\[(.+?)\]\((.+?)\)/) { "<#{$2}|#{$1}>" } + end + private def format_rag_response(answer, user:) answer_blocks = format_answer_blocks(answer, user) text = "#{answer_blocks[0][:text][:text]}\n\n#{answer}" diff --git a/test/integration/slack_events/rag_test.rb b/test/integration/slack_events/rag_test.rb index 964eaea..d3f3343 100644 --- a/test/integration/slack_events/rag_test.rb +++ b/test/integration/slack_events/rag_test.rb @@ -206,6 +206,144 @@ class SlackEventsRagTest < ActionDispatch::IntegrationTest end + test "the case of invalid blocks error" do + slack_ts = Time.now.to_f.to_s + channel = conversations(:magellan_rag) + user = users(:one) + query_body = "ZZZ" + query = "<@TEST_BOT_ID> #{query_body}" + + any_instance_of(SlackBot::Application) do |klass| + stub(klass).magellan_rag_channel? do |ch| + ch.slack_id == channel.slack_id + end + end + + stub_slack_api(:post, "chat.postMessage").to_return( + body: { "ok" => false, "error" => "invalid_blocks" }.to_json + ).then.to_return( + body: { "ok" => true, "ts" => Time.now.to_f.to_s }.to_json + ) + + # Check the case when missing reactions:write scope + stub_slack_api(:post, "reactions.add").to_return { raise Slack::Web::Api::Errors::MissingScope, "missing_scope" } + stub_slack_api(:post, "reactions.remove").to_return { raise Slack::Web::Api::Errors::MissingScope, "missing_scope" } + + assert Message.find_by(conversation: channel, user: user, slack_ts: slack_ts).blank? + + assert_enqueued_with(job: MagellanRagQueryJob) do + params = { + type: "event_callback", + event: { + type: "app_mention", + text: query, + channel: channel.slack_id, + user: user.slack_id, + ts: slack_ts + } + } + request_body = ActionDispatch::RequestEncoder.encoder(:json).encode_params(params) + timestamp = slack_ts.to_i + headers = { + "X-Slack-Request-Timestamp": timestamp, + "X-Slack-Signature": compute_request_signature(timestamp, request_body) + } + + post "/slack/events", params:, headers:, as: :json + end + + message = Message.find_by!(conversation: channel, user: user, slack_ts: slack_ts) + assert_equal([ + query_body, + slack_ts, + ], + [ + message.text, + message.slack_thread_ts, + ]) + + mock(Utils::MagellanRAG).endpoint do + "http://report-rag-api.test" + end + + rag_answer = <<~END_ANSWER + 花王株式会社_エッセンシャルの事例では、TVCMの残存週が他社(11週)と比べて13週と長いと報告されています。 + 詳細は以下のファイルで確認できます。 + - ファイル名: 【花王様】エッセンシャル_初回レポート報告_20221125.pdf + - ファイルのURL: [こちら](https://drive.google.com/file/d/1MB_IerrxHZ_Dn3ziT7vPixaOF_ng84D3/preview?authuser=0) + - 該当部分: 「15秒・30秒・60秒ともに他施策と比べて効率は良好。残存週は他社(11週)と比べて、13週と長い。」 + + 花王株式会社_ブランド横断の事例では、TVCMの残存週が業界傾向値(11週)と比べて13週と長いと報告されています。 + 詳細は以下のファイルで確認できます。 + - ファイル名: 【花王様】横断レポート_20230116.pdf + - ファイルのURL: [こちら](https://drive.google.com/file/d/1_t9ldOf-KcHxtC2fUS3sqCEJm8HwxMmU/preview?authuser=0) + - 該当部分: 「残存週は業界傾向値(11週)と比べて、13週と長い。」 + END_ANSWER + rag_response = {"answer": rag_answer} + + stub_request( + :get, "http://report-rag-api.test/generate_answer" + ).with( + query: {"query" => "ZZZ"} + ).to_return_json( + status: 200, + body: rag_response + ) + + expected_answer = <<~END_ANSWER + 花王株式会社_エッセンシャルの事例では、TVCMの残存週が他社(11週)と比べて13週と長いと報告されています。 + 詳細は以下のファイルで確認できます。 + - ファイル名: 【花王様】エッセンシャル_初回レポート報告_20221125.pdf + - ファイルのURL: + - 該当部分: 「15秒・30秒・60秒ともに他施策と比べて効率は良好。残存週は他社(11週)と比べて、13週と長い。」 + + 花王株式会社_ブランド横断の事例では、TVCMの残存週が業界傾向値(11週)と比べて13週と長いと報告されています。 + 詳細は以下のファイルで確認できます。 + - ファイル名: 【花王様】横断レポート_20230116.pdf + - ファイルのURL: + - 該当部分: 「残存週は業界傾向値(11週)と比べて、13週と長い。」 + END_ANSWER + expected_response = "<@#{user.slack_id}> 回答は次のとおりです。\n\n#{expected_answer}" + expected_answer_blocks = [ + { + "type" => "section", + "text" => { + "type" => "mrkdwn", + "text" => "<@#{user.slack_id}> 回答は次のとおりです。\n\n#{expected_answer}" + } + }, + {"type" => "divider"}, + ] + + perform_enqueued_jobs + + assert_response :success + + actual_body = nil + assert_slack_api_called(:post, "chat.postMessage", times: 2) do |request| + actual_body = decode_slack_client_request_body(request.body) + end + + query = Query.find_by!(message: message) + assert_kind_of Hash, query.body + response = Response.find_by!(query: query) + assert_kind_of Hash, response.body + + assert_equal( + { + "blocks" => [ + *expected_answer_blocks, + feedback_action_block + ], + "channel" => channel.slack_id, + "text" => expected_response, + "thread_ts" => slack_ts, + }, + actual_body + ) + end + + test "app_mention event from a channel for Magellan RAG with --retrieval option" do skip "TODO" slack_ts = Time.now.to_f.to_s diff --git a/test/jobs/magellan_rag_query_job_test.rb b/test/jobs/magellan_rag_query_job_test.rb index b56bf93..7245f08 100644 --- a/test/jobs/magellan_rag_query_job_test.rb +++ b/test/jobs/magellan_rag_query_job_test.rb @@ -118,4 +118,14 @@ class MagellanRagQueryJobTest < ActiveSupport::TestCase actual_body ) end + + test "query = 成果最大化シミュレーションを実施した事例を教えてください" do + skip "TODO" + message = messages(:report_query_one) + channel = message.conversation + user = message.user + + rag_answer = JSON.load(fixture_file_path("rag_answer-002.json").read)["answer"] + # p rag_answer + end end