You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(llm): consolidate Azure-OpenAI key resolution across 4 call sites
Pre-fix, the Azure-OpenAI provider in rag/llm had 4 unfixed call sites
with 3 different patterns for parsing the key:
- chat (chat_model.py:1649-1651): bare json.loads(key).get(...) with
no try/except; crashes with JSONDecodeError on a plain Portal API
key (the most common user mistake) and AttributeError on any JSON
non-object input.
- vision / CV (cv_model.py:380): local helper with silent fallback
for non-object JSON, silently using the raw key string.
- embed (embedding_model.py:325): identical local helper, a duplicate
copy of the CV one.
- seq2txt (sequence2txt_model.py:386): raw key passed straight to
AzureOpenAI; a JSON string was used as the api_key and the call
silently failed at the API with a 401.
Unify all 4 through a single _resolve_azure_credentials helper in
rag/llm/key_utils.py that follows the same pattern as the other 5
helpers in the JSON-decode family (Bedrock, BaiduYiyan, VolcEngine,
OpenRouter, GoogleCV):
1. Accepts a dict (returned verbatim) or a JSON-string-encoded dict.
2. On non-JSON input, raises a clear ModelException (retryable=False)
naming the required fields and pointing at conf/models/azure.json,
instead of letting json.loads bubble up as JSONDecodeError.
3. On a JSON top-level type that is not a dict (list, string,
number, bool, null), raises the same clear ModelException instead
of calling .get('api_key') on the value and getting AttributeError.
Returns (api_key, api_version) where api_version defaults to
'2024-02-01' and api_key defaults to '' if missing.
The two duplicate _resolve_azure_credentials definitions in
cv_model.py and embedding_model.py are removed in favor of the
shared helper.
Fixesinfiniflow#17675. Supersedes the partial infiniflow#17215 (which only touched the
chat branch and used a silent-fallback helper).
"""Parse an Azure-OpenAI ``key`` and return ``(api_key, api_version)``.
39
+
40
+
The Azure-OpenAI provider requires a JSON object key with at least
41
+
``api_key``; ``api_version`` defaults to ``"2024-02-01"`` if missing.
42
+
See ``conf/llm_factories.json`` for the factory entry and
43
+
``conf/models/azure.json`` for the model class.
44
+
45
+
On non-JSON input -- for example a user pasting a plain Azure API
46
+
key like ``"abc...123"`` from the Azure Portal -- we raise a clear
47
+
:class:`ModelException` pointing at the required schema, instead of
48
+
letting ``json.loads`` bubble up as ``json.decoder.JSONDecodeError:
49
+
Expecting value: line 1 column 1 (char 0)`` from inside ``rag/llm``
50
+
internals. Mirrors the fix shape of ``_resolve_bedrock_credentials``
51
+
for #17373 and the Azure fix for #17204 / #17215.
52
+
53
+
On a JSON top-level type that is not a dict (e.g. a list, string, or
54
+
number), we also raise the same clear error rather than calling
55
+
``.get("api_key")`` on the value and getting an ``AttributeError``.
56
+
57
+
Returns ``(api_key, api_version)``. Both default to ``""`` and
58
+
``"2024-02-01"`` respectively if missing from a valid dict.
59
+
"""
60
+
ifisinstance(key, dict):
61
+
payload=key
62
+
elifisinstance(key, str):
63
+
try:
64
+
payload=json.loads(key)
65
+
except (json.JSONDecodeError, TypeError):
66
+
logging.warning(
67
+
"Azure-OpenAI key is not valid JSON; expected a JSON object with 'api_key' (and optionally 'api_version') (see conf/models/azure.json).",
68
+
)
69
+
raiseModelException(
70
+
'Azure-OpenAI requires a JSON key with at least \'api_key\'. Example: {"api_key": "...", "api_version": "2024-02-01"}. See conf/models/azure.json for the model class.',
71
+
retryable=False,
72
+
)
73
+
else:
74
+
logging.warning(
75
+
"Azure-OpenAI key is not a string or dict (got %s); expected a JSON object with 'api_key' (and optionally 'api_version').",
76
+
type(key).__name__,
77
+
)
78
+
raiseModelException(
79
+
f"Azure-OpenAI requires a JSON key, got {type(key).__name__}. See conf/models/azure.json for the model class.",
80
+
retryable=False,
81
+
)
82
+
83
+
ifnotisinstance(payload, dict):
84
+
logging.warning(
85
+
"Azure-OpenAI key parsed as JSON but is not a dict (got %s).",
86
+
type(payload).__name__,
87
+
)
88
+
raiseModelException(
89
+
f"Azure-OpenAI key must be a JSON object, got {type(payload).__name__}. See conf/models/azure.json for the model class.",
0 commit comments