fix: more refactorings for cleaning code
This commit is contained in:
@@ -9,6 +9,7 @@ defmodule BDS.AI.Chat do
|
||||
alias BDS.AI.CatalogProvider
|
||||
alias BDS.AI.ChatConversation
|
||||
alias BDS.AI.ChatMessage
|
||||
alias BDS.AI.ChatTitleGenerator
|
||||
alias BDS.AI.ChatTools
|
||||
alias BDS.AI.InFlight
|
||||
alias BDS.AI.OpenAICompatibleRuntime
|
||||
@@ -24,8 +25,6 @@ defmodule BDS.AI.Chat do
|
||||
|
||||
@default_system_prompt "You are the bDS AI backend. Be precise, prefer structured JSON when asked, and avoid inventing blog facts."
|
||||
@default_max_output_tokens 16_384
|
||||
@title_max_output_tokens 256
|
||||
@chat_title_max_length 30
|
||||
@chat_max_tool_rounds 10
|
||||
@chat_await_timeout_margin_ms 5_000
|
||||
@default_context_window 128_000
|
||||
@@ -34,7 +33,7 @@ defmodule BDS.AI.Chat do
|
||||
def start_chat(attrs \\ %{}) when is_map(attrs) do
|
||||
now = Persistence.now_ms()
|
||||
model = MapUtils.attr(attrs, :model)
|
||||
title = MapUtils.attr(attrs, :title) || generated_chat_title(model)
|
||||
title = MapUtils.attr(attrs, :title) || ChatTitleGenerator.generated_chat_title(model)
|
||||
|
||||
%ChatConversation{}
|
||||
|> ChatConversation.changeset(%{
|
||||
@@ -430,11 +429,11 @@ defmodule BDS.AI.Chat do
|
||||
conversation = Repo.get!(ChatConversation, conversation_id)
|
||||
|
||||
cond do
|
||||
chat_user_message_count(conversation_id) < 1 ->
|
||||
ChatTitleGenerator.chat_user_message_count(conversation_id) < 1 ->
|
||||
Logger.debug("Chat title generation skipped reason=:no_user_messages")
|
||||
{:ok, reply}
|
||||
|
||||
not generated_chat_title?(conversation.title, conversation.model) ->
|
||||
not ChatTitleGenerator.generated_chat_title?(conversation.title, conversation.model) ->
|
||||
Logger.debug(
|
||||
"Chat title generation skipped reason=:conversation_already_titled title=#{inspect(conversation.title)}"
|
||||
)
|
||||
@@ -444,7 +443,7 @@ defmodule BDS.AI.Chat do
|
||||
true ->
|
||||
Logger.debug("Chat title generation requested conversation_id=#{conversation_id}")
|
||||
|
||||
case generate_chat_title(user_content, opts) do
|
||||
case ChatTitleGenerator.generate_chat_title(user_content, opts) do
|
||||
{:ok, title} when is_binary(title) and title != "" ->
|
||||
now = Persistence.now_ms()
|
||||
|
||||
@@ -465,87 +464,6 @@ defmodule BDS.AI.Chat do
|
||||
end
|
||||
end
|
||||
|
||||
defp generate_chat_title(user_content, opts) when is_binary(user_content) do
|
||||
runtime = Keyword.get(opts, :runtime, OpenAICompatibleRuntime)
|
||||
|
||||
with {:ok, endpoint, model, mode} <- Runtime.resolve_target(:chat_title, opts),
|
||||
:ok <- Runtime.validate_target(:chat_title, model, mode),
|
||||
request <- build_chat_title_request(user_content, model),
|
||||
{:ok, response} <-
|
||||
runtime.generate(Runtime.endpoint_with_model(endpoint, model), request, opts) do
|
||||
title = sanitize_chat_title(Map.get(response, :content))
|
||||
|
||||
if title == "" do
|
||||
Logger.warning("Chat title generation returned an empty title",
|
||||
model: model,
|
||||
content: inspect(Map.get(response, :content)),
|
||||
usage: inspect(Map.get(response, :usage))
|
||||
)
|
||||
end
|
||||
|
||||
{:ok, title}
|
||||
else
|
||||
{:error, reason} = error ->
|
||||
Logger.warning("Chat title generation failed", reason: inspect(reason))
|
||||
error
|
||||
|
||||
other ->
|
||||
Logger.warning("Chat title generation failed", reason: inspect(other))
|
||||
other
|
||||
end
|
||||
end
|
||||
|
||||
defp build_chat_title_request(user_content, model) do
|
||||
%{
|
||||
operation: :chat_title,
|
||||
model: model,
|
||||
max_output_tokens: @title_max_output_tokens,
|
||||
messages: [
|
||||
%{
|
||||
"role" => "system",
|
||||
"content" =>
|
||||
"Generate an ultra-short title (2-3 words, max 25 characters) for this conversation. Focus ONLY on the topic. Ignore any capability disclaimers. Do not include reasoning. Output ONLY the title text."
|
||||
},
|
||||
%{"role" => "user", "content" => "Topic: #{String.slice(user_content, 0, 100)}"}
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
defp sanitize_chat_title(title) when is_binary(title) do
|
||||
title =
|
||||
title
|
||||
|> String.trim()
|
||||
|> String.trim_leading("\"")
|
||||
|> String.trim_leading("'")
|
||||
|> String.trim_trailing("\"")
|
||||
|> String.trim_trailing("'")
|
||||
|> String.trim_trailing(".")
|
||||
|> String.trim_trailing("!")
|
||||
|> String.trim_trailing("?")
|
||||
|
||||
if String.length(title) > @chat_title_max_length do
|
||||
String.slice(title, 0, @chat_title_max_length - 3) <> "..."
|
||||
else
|
||||
title
|
||||
end
|
||||
end
|
||||
|
||||
defp sanitize_chat_title(_title), do: ""
|
||||
|
||||
defp chat_user_message_count(conversation_id) do
|
||||
Repo.aggregate(
|
||||
from(message in ChatMessage,
|
||||
where: message.conversation_id == ^conversation_id and message.role == :user
|
||||
),
|
||||
:count,
|
||||
:id
|
||||
)
|
||||
end
|
||||
|
||||
defp generated_chat_title?(title, model) do
|
||||
title in [generated_chat_title(nil), generated_chat_title(model)]
|
||||
end
|
||||
|
||||
defp chat_round(
|
||||
_conversation,
|
||||
_messages,
|
||||
@@ -882,9 +800,6 @@ defmodule BDS.AI.Chat do
|
||||
)
|
||||
end
|
||||
|
||||
defp generated_chat_title(nil), do: "New Chat"
|
||||
defp generated_chat_title(model), do: "Chat with #{model}"
|
||||
|
||||
defp load_chat_messages(conversation_id) do
|
||||
Repo.all(
|
||||
from message in ChatMessage,
|
||||
|
||||
Reference in New Issue
Block a user