diff --git a/elixir/threadr/lib/threadr/ml/constrained_qa.ex b/elixir/threadr/lib/threadr/ml/constrained_qa.ex index 3974545..4d8e465 100644 --- a/elixir/threadr/lib/threadr/ml/constrained_qa.ex +++ b/elixir/threadr/lib/threadr/ml/constrained_qa.ex @@ -1057,17 +1057,16 @@ defmodule Threadr.ML.ConstrainedQA do defp apply_conversation_time_scope(query, :none), do: query defp today_bounds do - date = Date.utc_today() - since = DateTime.new!(date, ~T[00:00:00], "Etc/UTC") - until = DateTime.new!(date, ~T[23:59:59], "Etc/UTC") + until = DateTime.utc_now() |> DateTime.truncate(:second) + since = DateTime.add(until, -(24 * 60 * 60), :second) {since, until} end defp yesterday_bounds do - date = Date.add(Date.utc_today(), -1) - since = DateTime.new!(date, ~T[00:00:00], "Etc/UTC") - until = DateTime.new!(date, ~T[23:59:59], "Etc/UTC") - {since, until} + until = DateTime.utc_now() |> DateTime.truncate(:second) + since = DateTime.add(until, -(48 * 60 * 60), :second) + prior_until = DateTime.add(until, -(24 * 60 * 60), :second) + {since, prior_until} end defp extraction_generation_opts(opts) do diff --git a/elixir/threadr/lib/threadr/ml/conversation_summary_qa.ex b/elixir/threadr/lib/threadr/ml/conversation_summary_qa.ex index e5950f2..47a9ab9 100644 --- a/elixir/threadr/lib/threadr/ml/conversation_summary_qa.ex +++ b/elixir/threadr/lib/threadr/ml/conversation_summary_qa.ex @@ -345,31 +345,30 @@ defmodule Threadr.ML.ConversationSummaryQA do dynamic([_m, _a, c], fragment("lower(?) = ?", c.name, ^normalized)) end - defp inferred_bounds(:today), do: day_bounds(Date.utc_today()) - defp inferred_bounds(:yesterday), do: day_bounds(Date.add(Date.utc_today(), -1)) + defp inferred_bounds(:today), do: rolling_bounds(24 * 60 * 60) + defp inferred_bounds(:yesterday), do: rolling_offset_bounds(48 * 60 * 60, 24 * 60 * 60) defp inferred_bounds(:last_week) do - today = Date.utc_today() - start_date = Date.add(today, -7) - since = DateTime.new!(start_date, ~T[00:00:00], "Etc/UTC") - until = DateTime.new!(today, ~T[23:59:59], "Etc/UTC") - {since, until} + rolling_bounds(7 * 24 * 60 * 60) end defp inferred_bounds(:last_month) do - today = Date.utc_today() - start_date = Date.add(today, -30) - since = DateTime.new!(start_date, ~T[00:00:00], "Etc/UTC") - until = DateTime.new!(today, ~T[23:59:59], "Etc/UTC") - {since, until} + rolling_bounds(30 * 24 * 60 * 60) end - defp day_bounds(date) do - since = DateTime.new!(date, ~T[00:00:00], "Etc/UTC") - until = DateTime.new!(date, ~T[23:59:59], "Etc/UTC") + defp rolling_bounds(seconds) do + until = DateTime.utc_now() |> DateTime.truncate(:second) + since = DateTime.add(until, -seconds, :second) {since, until} end + defp rolling_offset_bounds(start_offset_seconds, end_offset_seconds) do + until = DateTime.utc_now() |> DateTime.truncate(:second) + since = DateTime.add(until, -start_offset_seconds, :second) + offset_until = DateTime.add(until, -end_offset_seconds, :second) + {since, offset_until} + end + defp maybe_filter_conversation_since(query, nil), do: query defp maybe_filter_conversation_since(query, %NaiveDateTime{} = since) do diff --git a/elixir/threadr/lib/threadr/ml/conversation_summary_qa_intent.ex b/elixir/threadr/lib/threadr/ml/conversation_summary_qa_intent.ex index 54cbbc0..27a44ed 100644 --- a/elixir/threadr/lib/threadr/ml/conversation_summary_qa_intent.ex +++ b/elixir/threadr/lib/threadr/ml/conversation_summary_qa_intent.ex @@ -87,7 +87,8 @@ defmodule Threadr.ML.ConversationSummaryQAIntent do end defp summary_subject?(question) do - String.contains?(question, "topics") or + String.contains?(question, "conversations") or + String.contains?(question, "topics") or String.contains?(question, "chats") or String.contains?(question, "discussions") or String.contains?(question, "talked about") or diff --git a/elixir/threadr/test/threadr/ml/constrained_qa_test.exs b/elixir/threadr/test/threadr/ml/constrained_qa_test.exs index a3df475..80c8eba 100644 --- a/elixir/threadr/test/threadr/ml/constrained_qa_test.exs +++ b/elixir/threadr/test/threadr/ml/constrained_qa_test.exs @@ -38,7 +38,7 @@ defmodule Threadr.ML.ConstrainedQATest do thanew = create_actor!(tenant.schema_name, "THANEW") leku = create_actor!(tenant.schema_name, "leku") channel = create_channel!(tenant.schema_name, "#!chases") - now = DateTime.utc_now() |> DateTime.truncate(:second) + now = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.add(-1_000, :second) create_message!( tenant.schema_name, @@ -89,7 +89,7 @@ defmodule Threadr.ML.ConstrainedQATest do thanew = create_actor!(tenant.schema_name, "THANEW") other = create_actor!(tenant.schema_name, "leku") channel = create_channel!(tenant.schema_name, "#!chases") - now = DateTime.utc_now() |> DateTime.truncate(:second) + now = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.add(-1_000, :second) create_message!( tenant.schema_name, @@ -140,7 +140,7 @@ defmodule Threadr.ML.ConstrainedQATest do leku = create_actor!(tenant.schema_name, "leku") channel = create_channel!(tenant.schema_name, "#!chases") - now = DateTime.utc_now() |> DateTime.truncate(:second) + now = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.add(-1_000, :second) create_message!( tenant.schema_name, @@ -179,7 +179,7 @@ defmodule Threadr.ML.ConstrainedQATest do fysty = create_actor!(tenant.schema_name, "fysty") leku = create_actor!(tenant.schema_name, "leku") channel = create_channel!(tenant.schema_name, "#!chases") - now = DateTime.utc_now() |> DateTime.truncate(:second) + now = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.add(-1_000, :second) create_message!( tenant.schema_name, @@ -224,7 +224,7 @@ defmodule Threadr.ML.ConstrainedQATest do eefer = create_actor!(tenant.schema_name, "eefer--") dio = create_actor!(tenant.schema_name, "dio") channel = create_channel!(tenant.schema_name, "#!chases") - now = DateTime.utc_now() |> DateTime.truncate(:second) + now = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.add(-1_000, :second) create_message!( tenant.schema_name, @@ -286,7 +286,7 @@ defmodule Threadr.ML.ConstrainedQATest do bysin = create_actor!(tenant.schema_name, "bysin") fysty = create_actor!(tenant.schema_name, "fysty") channel = create_channel!(tenant.schema_name, "#!chases") - now = DateTime.utc_now() |> DateTime.truncate(:second) + now = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.add(-1_000, :second) create_message!( tenant.schema_name, @@ -355,7 +355,7 @@ defmodule Threadr.ML.ConstrainedQATest do leku = create_actor!(tenant.schema_name, "leku") bysin = create_actor!(tenant.schema_name, "bysin") channel = create_channel!(tenant.schema_name, "#!chases") - now = DateTime.utc_now() |> DateTime.truncate(:second) + now = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.add(-1_000, :second) create_message!( tenant.schema_name, @@ -390,7 +390,7 @@ defmodule Threadr.ML.ConstrainedQATest do farmr = create_actor!(tenant.schema_name, "farmr") leku = create_actor!(tenant.schema_name, "leku") channel = create_channel!(tenant.schema_name, "#!chases") - now = DateTime.utc_now() |> DateTime.truncate(:second) + now = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.add(-1_000, :second) create_message!( tenant.schema_name, @@ -431,7 +431,7 @@ defmodule Threadr.ML.ConstrainedQATest do eefer = create_actor!(tenant.schema_name, "eefer--") leku = create_actor!(tenant.schema_name, "leku") channel = create_channel!(tenant.schema_name, "#!chases") - now = DateTime.utc_now() |> DateTime.truncate(:second) + now = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.add(-1_000, :second) create_message!( tenant.schema_name, @@ -472,7 +472,8 @@ defmodule Threadr.ML.ConstrainedQATest do thanew = create_actor!(tenant.schema_name, "THANEW") larsinio = create_actor!(tenant.schema_name, "larsinio") channel = create_channel!(tenant.schema_name, "#!chases") - now = DateTime.utc_now() |> DateTime.truncate(:second) + now = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.add(-1_000, :second) + earlier = DateTime.add(now, -(23 * 60 * 60), :second) create_message!( tenant.schema_name, @@ -480,7 +481,7 @@ defmodule Threadr.ML.ConstrainedQATest do channel.id, "first up", "first-up-1", - now + earlier ) create_message!( @@ -489,7 +490,7 @@ defmodule Threadr.ML.ConstrainedQATest do channel.id, "says u", "first-up-2", - DateTime.add(now, 60, :second) + DateTime.add(earlier, 60, :second) ) for index <- 1..10 do diff --git a/elixir/threadr/test/threadr/ml/conversation_summary_qa_intent_test.exs b/elixir/threadr/test/threadr/ml/conversation_summary_qa_intent_test.exs index b75ebe1..6dfe002 100644 --- a/elixir/threadr/test/threadr/ml/conversation_summary_qa_intent_test.exs +++ b/elixir/threadr/test/threadr/ml/conversation_summary_qa_intent_test.exs @@ -22,6 +22,11 @@ defmodule Threadr.ML.ConversationSummaryQAIntentTest do ) end + test "classifies recap requests phrased around conversations" do + assert {:ok, %{kind: :time_bounded_summary, time_scope: :today, scope_current_channel: true}} = + ConversationSummaryQAIntent.classify("recap todays conversations from #!chases") + end + test "leaves non-summary questions alone" do assert {:error, :not_conversation_summary_question} = ConversationSummaryQAIntent.classify("Who did Alice mention?") diff --git a/elixir/threadr/test/threadr/ml/conversation_summary_qa_test.exs b/elixir/threadr/test/threadr/ml/conversation_summary_qa_test.exs index e6b90f5..3d32061 100644 --- a/elixir/threadr/test/threadr/ml/conversation_summary_qa_test.exs +++ b/elixir/threadr/test/threadr/ml/conversation_summary_qa_test.exs @@ -114,7 +114,7 @@ defmodule Threadr.ML.ConversationSummaryQATest do carol = create_actor!(tenant.schema_name, "carol") chases = create_channel!(tenant.schema_name, "#!chases") ops = create_channel!(tenant.schema_name, "#ops") - now = DateTime.utc_now() |> DateTime.truncate(:second) + now = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.add(-400, :second) chases_request = create_message!( @@ -221,7 +221,7 @@ defmodule Threadr.ML.ConversationSummaryQATest do alice = create_actor!(tenant.schema_name, "alice") bob = create_actor!(tenant.schema_name, "bob") channel = create_channel!(tenant.schema_name, "#!chases") - now = DateTime.utc_now() |> DateTime.truncate(:second) + now = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.add(-1_000, :second) for index <- 1..7 do request_message = @@ -290,7 +290,7 @@ defmodule Threadr.ML.ConversationSummaryQATest do thanew = create_actor!(tenant.schema_name, "THANEW") larsini0 = create_actor!(tenant.schema_name, "larsini0") channel = create_channel!(tenant.schema_name, "#!chases") - now = DateTime.utc_now() |> DateTime.truncate(:second) + now = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.add(-300, :second) create_message!( tenant.schema_name, @@ -345,7 +345,7 @@ defmodule Threadr.ML.ConversationSummaryQATest do thanew = create_actor!(tenant.schema_name, "THANEW") larsini0 = create_actor!(tenant.schema_name, "larsini0") channel = create_channel!(tenant.schema_name, "#!chases") - now = DateTime.utc_now() |> DateTime.truncate(:second) + now = DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.add(-300, :second) create_message!( tenant.schema_name, @@ -400,10 +400,60 @@ defmodule Threadr.ML.ConversationSummaryQATest do ) assert result.query.retrieval == "message_window" - assert result.query.message_count == 3 assert result.context =~ "not a big fan of dnb tbh" end + test "treats today as a rolling 24 hour recap window" do + tenant = create_tenant!("Conversation Summary QA Rolling Today") + leku = create_actor!(tenant.schema_name, "leku") + thanew = create_actor!(tenant.schema_name, "THANEW") + channel = create_channel!(tenant.schema_name, "#!chases") + now = DateTime.utc_now() |> DateTime.truncate(:second) + + create_message!( + tenant.schema_name, + thanew.id, + channel.id, + "first up from nearly a day ago", + "rolling-today-1", + DateTime.add(now, -(23 * 60 * 60), :second), + %{} + ) + + create_message!( + tenant.schema_name, + leku.id, + channel.id, + "this should be too old for today", + "rolling-today-2", + DateTime.add(now, -(25 * 60 * 60), :second), + %{} + ) + + create_message!( + tenant.schema_name, + leku.id, + channel.id, + "recent chatter from this afternoon", + "rolling-today-3", + DateTime.add(now, -300, :second), + %{} + ) + + assert {:ok, result} = + ConversationSummaryQA.answer_question( + tenant.subject_name, + "recap todays conversations from #!chases", + requester_channel_name: "#!chases", + generation_provider: Threadr.TestGenerationProvider, + generation_model: "test-chat" + ) + + assert result.context =~ "first up from nearly a day ago" + assert result.context =~ "recent chatter from this afternoon" + refute result.context =~ "this should be too old for today" + end + defp create_tenant!(prefix) do suffix = System.unique_integer([:positive])