fix: fix airplane mode for AI usage and qwen 3.6 one-shot parsing
This commit is contained in:
@@ -111,6 +111,19 @@ defmodule BDS.AI do
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
True when the airplane (local) endpoint has both a URL and a model
|
||||
configured, so gated AI features can run against the local model.
|
||||
"""
|
||||
@spec airplane_endpoint_configured?() :: boolean()
|
||||
def airplane_endpoint_configured? do
|
||||
present_setting?(get_setting("ai.airplane.url")) and
|
||||
present_setting?(get_setting("ai.airplane.model"))
|
||||
end
|
||||
|
||||
defp present_setting?(value) when is_binary(value), do: String.trim(value) != ""
|
||||
defp present_setting?(_value), do: false
|
||||
|
||||
@spec put_model_preference(atom(), String.t()) ::
|
||||
:ok | {:error, :unknown_model_preference | term()}
|
||||
def put_model_preference(key, model) when is_atom(key) and is_binary(model) do
|
||||
|
||||
@@ -4,6 +4,7 @@ defmodule BDS.AI.OneShot do
|
||||
require Logger
|
||||
|
||||
alias BDS.AI.Chat
|
||||
alias BDS.AI.JsonContent
|
||||
alias BDS.AI.OpenAICompatibleRuntime
|
||||
alias BDS.AI.Runtime
|
||||
alias BDS.Media.Media
|
||||
@@ -213,7 +214,9 @@ defmodule BDS.AI.OneShot do
|
||||
messages: [
|
||||
%{
|
||||
"role" => "system",
|
||||
"content" => one_shot_system_prompt(operation, language, source_language)
|
||||
"content" =>
|
||||
one_shot_system_prompt(operation, language, source_language) <>
|
||||
" Output raw JSON only, without markdown code fences."
|
||||
},
|
||||
%{
|
||||
"role" => "user",
|
||||
@@ -351,11 +354,11 @@ defmodule BDS.AI.OneShot do
|
||||
defp extract_json_response(%{json: json}) when is_map(json), do: {:ok, json}
|
||||
|
||||
defp extract_json_response(%{content: content}) when is_binary(content) do
|
||||
case Jason.decode(content) do
|
||||
{:ok, json} when is_map(json) ->
|
||||
case JsonContent.decode(content) do
|
||||
json when is_map(json) ->
|
||||
{:ok, json}
|
||||
|
||||
_other ->
|
||||
nil ->
|
||||
Logger.error(
|
||||
"AI extract_json_response failed to parse content as JSON. Content: #{String.slice(content, 0, 1000)}"
|
||||
)
|
||||
|
||||
@@ -182,14 +182,7 @@ defmodule BDS.AI.OpenAICompatibleRuntime do
|
||||
end
|
||||
end
|
||||
|
||||
defp decode_json_content(nil), do: nil
|
||||
|
||||
defp decode_json_content(content) when is_binary(content) do
|
||||
case Jason.decode(content) do
|
||||
{:ok, decoded} when is_map(decoded) -> decoded
|
||||
_other -> nil
|
||||
end
|
||||
end
|
||||
defp decode_json_content(content), do: BDS.AI.JsonContent.decode(content)
|
||||
|
||||
defp completions_url(url) do
|
||||
cond do
|
||||
|
||||
@@ -414,7 +414,7 @@ defmodule BDS.Desktop.ShellLive do
|
||||
do: OverlayManager.handle_event("overlay_lightbox_next", params, socket, overlay_callbacks())
|
||||
|
||||
def handle_event("add_gallery_images", %{"post-id" => post_id}, socket) do
|
||||
if socket.assigns.offline_mode do
|
||||
if socket.assigns.offline_mode and not AI.airplane_endpoint_configured?() do
|
||||
{:noreply,
|
||||
append_output_entry(
|
||||
socket,
|
||||
|
||||
@@ -230,7 +230,7 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do
|
||||
not is_nil(socket.assigns.request) ->
|
||||
build_data(socket)
|
||||
|
||||
socket.assigns.offline_mode ->
|
||||
socket.assigns.offline_mode and not AI.airplane_endpoint_configured?() ->
|
||||
Notify.output(
|
||||
dgettext("ui", "Chat"),
|
||||
dgettext("ui", "Automatic AI actions stay gated by airplane mode."),
|
||||
@@ -239,7 +239,7 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do
|
||||
|
||||
build_data(socket)
|
||||
|
||||
ModelSelection.needs_api_key?(false) ->
|
||||
ModelSelection.needs_api_key?(socket.assigns.offline_mode) ->
|
||||
build_data(socket)
|
||||
|
||||
true ->
|
||||
|
||||
@@ -434,7 +434,7 @@ defmodule BDS.Desktop.ShellLive.ImportEditor do
|
||||
socket =
|
||||
with %{} = definition <- ImportDefinitions.get_definition(definition_id),
|
||||
%{} = report <- ImportDefinitions.decode_analysis_result(definition) do
|
||||
if socket.assigns.offline_mode? do
|
||||
if socket.assigns.offline_mode? and not AI.airplane_endpoint_configured?() do
|
||||
notify_output(
|
||||
dgettext("ui", "Import"),
|
||||
BDS.Gettext.lgettext(
|
||||
|
||||
@@ -82,7 +82,7 @@ defmodule BDS.Desktop.ShellLive.ImportEditor.TaxonomyEditing do
|
||||
%{} = definition <- ImportDefinitions.get_definition(definition_id),
|
||||
%{} = report <- ImportDefinitions.decode_analysis_result(definition) do
|
||||
cond do
|
||||
socket.assigns.offline_mode ->
|
||||
socket.assigns.offline_mode and not AI.airplane_endpoint_configured?() ->
|
||||
socket
|
||||
|> append_output.(
|
||||
dgettext("ui", "Import"),
|
||||
|
||||
@@ -153,7 +153,7 @@ defmodule BDS.Desktop.ShellLive.MediaEditor do
|
||||
end
|
||||
|
||||
def handle_event("detect_media_editor_language", _params, socket) do
|
||||
if socket.assigns.offline_mode do
|
||||
if socket.assigns.offline_mode and not AI.airplane_endpoint_configured?() do
|
||||
notify_output(
|
||||
socket,
|
||||
dgettext("ui", "Detect Language"),
|
||||
@@ -346,7 +346,7 @@ defmodule BDS.Desktop.ShellLive.MediaEditor do
|
||||
def handle_event("refresh_media_translation", %{"language" => language}, socket) do
|
||||
media = socket.assigns.media
|
||||
|
||||
if socket.assigns.offline_mode do
|
||||
if socket.assigns.offline_mode and not AI.airplane_endpoint_configured?() do
|
||||
notify_output(
|
||||
socket,
|
||||
dgettext("ui", "Translate"),
|
||||
@@ -539,7 +539,7 @@ defmodule BDS.Desktop.ShellLive.MediaEditor do
|
||||
end
|
||||
|
||||
defp do_translate(socket, language) do
|
||||
if socket.assigns.offline_mode do
|
||||
if socket.assigns.offline_mode and not AI.airplane_endpoint_configured?() do
|
||||
notify_output(
|
||||
socket,
|
||||
dgettext("ui", "Translate"),
|
||||
|
||||
@@ -66,7 +66,7 @@ defmodule BDS.Desktop.ShellLive.OverlayManager do
|
||||
|
||||
socket =
|
||||
if kind == "ai_suggestions" and not is_nil(overlay) do
|
||||
if socket.assigns.offline_mode do
|
||||
if socket.assigns.offline_mode and not AI.airplane_endpoint_configured?() do
|
||||
callbacks.append_output.(
|
||||
socket,
|
||||
dgettext("ui", "AI Suggestions"),
|
||||
|
||||
@@ -707,7 +707,7 @@ defmodule BDS.Desktop.ShellLive.PostEditor do
|
||||
end
|
||||
|
||||
defp do_detect_language(socket) do
|
||||
if Map.get(socket.assigns, :offline_mode, true) do
|
||||
if Map.get(socket.assigns, :offline_mode, true) and not AI.airplane_endpoint_configured?() do
|
||||
notify_output(
|
||||
socket,
|
||||
dgettext("ui", "Detect Language"),
|
||||
@@ -756,7 +756,7 @@ defmodule BDS.Desktop.ShellLive.PostEditor do
|
||||
end
|
||||
|
||||
defp do_translate(socket, language) do
|
||||
if Map.get(socket.assigns, :offline_mode, true) do
|
||||
if Map.get(socket.assigns, :offline_mode, true) and not AI.airplane_endpoint_configured?() do
|
||||
notify_output(
|
||||
socket,
|
||||
dgettext("ui", "Translate"),
|
||||
|
||||
Reference in New Issue
Block a user