From d46eb6e5286eeffbdc5358dfb2802d77541064cf Mon Sep 17 00:00:00 2001 From: Aleksey Sabilin Date: Fri, 21 Aug 2026 21:32:13 +0300 Subject: [PATCH] =?UTF-8?q?fix(stt):=20xAI=20400=20=D0=BF=D1=80=D0=B8=20fo?= =?UTF-8?q?rmat=3Dtrue=20=D0=B1=D0=B5=D0=B7=20language=20=E2=80=94=20?= =?UTF-8?q?=D1=83=D0=B1=D0=B8=D1=80=D0=B0=D0=B5=D0=BC=20=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=B5=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Smoke на IFT: xAI отвечает 400 "Field 'language' is required when 'format' is true" → бэк маппит в 502 upstream_error. Проверено curl: без поля format эндпоинт /v1/stt работает (200), язык определяется автоматически. Убрано поле format из multipart xAI-адаптера, eunit обновлён (полный прогон: 1211 тестов зелёные). Refs EventHub/EventHubBack#79 --- src/logic/logic_ai_transcribe.erl | 5 +++-- test/unit/logic_ai_transcribe_tests.erl | 7 ++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/logic/logic_ai_transcribe.erl b/src/logic/logic_ai_transcribe.erl index e5c95da..96b0a46 100644 --- a/src/logic/logic_ai_transcribe.erl +++ b/src/logic/logic_ai_transcribe.erl @@ -125,8 +125,9 @@ env_int(Name, Default) -> %%%=================================================================== call_provider(xai, Url, Key, Audio, CType) -> - %% xAI: multipart; опциональные поля до поля file, file — последним. - Body = build_multipart([{<<"format">>, <<"true">>}], Audio, <<"voice.dat">>, CType), + %% xAI: multipart без опциональных полей — язык определяется авто + %% (format=true требует явный language и отключает автоопределение). + Body = build_multipart([], Audio, <<"voice.dat">>, CType), post_and_parse(xai, Url, Key, Body); call_provider(openai, Url, Key, Audio, CType) -> Model = case env_bin("STT_MODEL") of diff --git a/test/unit/logic_ai_transcribe_tests.erl b/test/unit/logic_ai_transcribe_tests.erl index f64f96c..31a9637 100644 --- a/test/unit/logic_ai_transcribe_tests.erl +++ b/test/unit/logic_ai_transcribe_tests.erl @@ -56,13 +56,10 @@ test_xai_success() -> ?assertEqual(?XAI_URL, Url), ?assertEqual([{"authorization", "Bearer test-key"}], Headers), ?assertMatch("multipart/form-data; boundary=" ++ _, ContentType), - ?assertMatch({_, _}, binary:match(Body, <<"name=\"format\"">>)), ?assertMatch({_, _}, binary:match(Body, <<"name=\"file\"">>)), ?assertMatch({_, _}, binary:match(Body, <<"audio-bytes">>)), - %% Поле file — последнее (требование xAI). - {PosFormat, _} = binary:match(Body, <<"name=\"format\"">>), - {PosFile, _} = binary:match(Body, <<"name=\"file\"">>), - ?assert(PosFormat < PosFile). + %% Без поля format — язык определяется авто (format=true требует language). + ?assertEqual(nomatch, binary:match(Body, <<"name=\"format\"">>)). test_openai_adapter() -> os:putenv("STT_PROVIDER", "openai"),