Skip to content

Commit 99f3c55

Browse files
authored
feat: support Azure v1 endpoint format (/openai/v1) (open-webui#23484)
Azure offers two URL formats: the legacy deployment-based format (/openai/deployments/{model}/...) and the newer v1 format (/openai/v1/...) where the model stays in the payload body and no api-version query parameter is needed. Previously, the code always ran convert_to_azure_payload which rewrites the URL to the deployment format, causing 404 errors for users with v1-style base URLs. Now, when the base URL contains '/openai/v1', we skip deployment URL construction and route directly. Applied consistently across all three Azure routing paths: generate_chat_completion, /responses proxy, and generic proxy.
1 parent e7e006e commit 99f3c55

1 file changed

Lines changed: 38 additions & 20 deletions

File tree

backend/open_webui/routers/openai.py

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,21 +1131,31 @@ async def generate_chat_completion(
11311131
is_responses = api_config.get('api_type') == 'responses'
11321132

11331133
if api_config.get('azure', False):
1134-
api_version = api_config.get('api_version', '2023-03-15-preview')
1135-
request_url, payload = convert_to_azure_payload(url, payload, api_version)
1136-
11371134
# Only set api-key header if not using Azure Entra ID authentication
11381135
auth_type = api_config.get('auth_type', 'bearer')
11391136
if auth_type not in ('azure_ad', 'microsoft_entra_id'):
11401137
headers['api-key'] = key
11411138

1142-
headers['api-version'] = api_version
1139+
# Azure v1 format: base URL already ends with /openai/v1,
1140+
# model stays in the payload, no deployment URL rewriting.
1141+
is_azure_v1 = bool(re.search(r'/openai/v1(?:/|$)', url))
11431142

1144-
if is_responses:
1145-
payload = convert_to_responses_payload(payload)
1146-
request_url = f'{request_url}/responses?api-version={api_version}'
1143+
if is_azure_v1:
1144+
if is_responses:
1145+
payload = convert_to_responses_payload(payload)
1146+
request_url = f'{url.rstrip("/")}/responses'
1147+
else:
1148+
request_url = f'{url.rstrip("/")}/chat/completions'
11471149
else:
1148-
request_url = f'{request_url}/chat/completions?api-version={api_version}'
1150+
api_version = api_config.get('api_version', '2023-03-15-preview')
1151+
request_url, payload = convert_to_azure_payload(url, payload, api_version)
1152+
headers['api-version'] = api_version
1153+
1154+
if is_responses:
1155+
payload = convert_to_responses_payload(payload)
1156+
request_url = f'{request_url}/responses?api-version={api_version}'
1157+
else:
1158+
request_url = f'{request_url}/chat/completions?api-version={api_version}'
11491159
else:
11501160
if is_responses:
11511161
payload = convert_to_responses_payload(payload)
@@ -1357,16 +1367,19 @@ async def responses(
13571367
headers, cookies = await get_headers_and_cookies(request, url, key, api_config, user=user)
13581368

13591369
if api_config.get('azure', False):
1360-
api_version = api_config.get('api_version', '2023-03-15-preview')
1361-
13621370
auth_type = api_config.get('auth_type', 'bearer')
13631371
if auth_type not in ('azure_ad', 'microsoft_entra_id'):
13641372
headers['api-key'] = key
13651373

1366-
headers['api-version'] = api_version
1374+
is_azure_v1 = bool(re.search(r'/openai/v1(?:/|$)', url))
13671375

1368-
model = payload.get('model', '')
1369-
request_url = f'{url}/openai/deployments/{model}/responses?api-version={api_version}'
1376+
if is_azure_v1:
1377+
request_url = f'{url.rstrip("/")}/responses'
1378+
else:
1379+
api_version = api_config.get('api_version', '2023-03-15-preview')
1380+
headers['api-version'] = api_version
1381+
model = payload.get('model', '')
1382+
request_url = f'{url}/openai/deployments/{model}/responses?api-version={api_version}'
13701383
else:
13711384
request_url = f'{url}/responses'
13721385

@@ -1459,20 +1472,25 @@ async def proxy(path: str, request: Request, user=Depends(get_verified_user)):
14591472
headers, cookies = await get_headers_and_cookies(request, url, key, api_config, user=user)
14601473

14611474
if api_config.get('azure', False):
1462-
api_version = api_config.get('api_version', '2023-03-15-preview')
1463-
14641475
# Only set api-key header if not using Azure Entra ID authentication
14651476
auth_type = api_config.get('auth_type', 'bearer')
14661477
if auth_type not in ('azure_ad', 'microsoft_entra_id'):
14671478
headers['api-key'] = key
14681479

1469-
headers['api-version'] = api_version
1480+
is_azure_v1 = bool(re.search(r'/openai/v1(?:/|$)', url))
14701481

1471-
payload = json.loads(body)
1472-
url, payload = convert_to_azure_payload(url, payload, api_version)
1473-
body = json.dumps(payload).encode()
1482+
if is_azure_v1:
1483+
qs = request.url.query
1484+
request_url = f'{url.rstrip("/")}/{path}' + (f'?{qs}' if qs else '')
1485+
else:
1486+
api_version = api_config.get('api_version', '2023-03-15-preview')
1487+
headers['api-version'] = api_version
1488+
1489+
payload = json.loads(body)
1490+
url, payload = convert_to_azure_payload(url, payload, api_version)
1491+
body = json.dumps(payload).encode()
14741492

1475-
request_url = f'{url}/{path}?api-version={api_version}'
1493+
request_url = f'{url}/{path}?api-version={api_version}'
14761494
else:
14771495
request_url = f'{url}/{path}'
14781496

0 commit comments

Comments
 (0)