Kaynağa Gözat

feature: Azure OpenAI image generation support

The image generation API used on Azure OpenAI requires to specify the API
version by appending an `api-version` query parameter to the endpoint URL.
Added the environment variable `IMAGES_OPENAI_API_VERSION` with
configuration functionality in the administration UI.
Andreas Fuerer 1 ay önce
ebeveyn
işleme
bc6afc9057

+ 6 - 0
backend/open_webui/config.py

@@ -3100,6 +3100,12 @@ IMAGES_OPENAI_API_BASE_URL = PersistentConfig(
     "image_generation.openai.api_base_url",
     os.getenv("IMAGES_OPENAI_API_BASE_URL", OPENAI_API_BASE_URL),
 )
+IMAGES_OPENAI_API_VERSION = PersistentConfig(
+    "IMAGES_OPENAI_API_VERSION",
+    "image_generation.openai.api_version",
+    os.getenv("IMAGES_OPENAI_API_VERSION", ""),
+)
+
 IMAGES_OPENAI_API_KEY = PersistentConfig(
     "IMAGES_OPENAI_API_KEY",
     "image_generation.openai.api_key",

+ 2 - 0
backend/open_webui/main.py

@@ -157,6 +157,7 @@ from open_webui.config import (
     IMAGE_SIZE,
     IMAGE_STEPS,
     IMAGES_OPENAI_API_BASE_URL,
+    IMAGES_OPENAI_API_VERSION,
     IMAGES_OPENAI_API_KEY,
     IMAGES_GEMINI_API_BASE_URL,
     IMAGES_GEMINI_API_KEY,
@@ -1019,6 +1020,7 @@ app.state.config.ENABLE_IMAGE_GENERATION = ENABLE_IMAGE_GENERATION
 app.state.config.ENABLE_IMAGE_PROMPT_GENERATION = ENABLE_IMAGE_PROMPT_GENERATION
 
 app.state.config.IMAGES_OPENAI_API_BASE_URL = IMAGES_OPENAI_API_BASE_URL
+app.state.config.IMAGES_OPENAI_API_VERSION = IMAGES_OPENAI_API_VERSION
 app.state.config.IMAGES_OPENAI_API_KEY = IMAGES_OPENAI_API_KEY
 
 app.state.config.IMAGES_GEMINI_API_BASE_URL = IMAGES_GEMINI_API_BASE_URL

+ 11 - 1
backend/open_webui/routers/images.py

@@ -48,6 +48,7 @@ async def get_config(request: Request, user=Depends(get_admin_user)):
         "prompt_generation": request.app.state.config.ENABLE_IMAGE_PROMPT_GENERATION,
         "openai": {
             "OPENAI_API_BASE_URL": request.app.state.config.IMAGES_OPENAI_API_BASE_URL,
+            "OPENAI_API_VERSION": request.app.state.config.IMAGES_OPENAI_API_VERSION,
             "OPENAI_API_KEY": request.app.state.config.IMAGES_OPENAI_API_KEY,
         },
         "automatic1111": {
@@ -72,6 +73,7 @@ async def get_config(request: Request, user=Depends(get_admin_user)):
 
 class OpenAIConfigForm(BaseModel):
     OPENAI_API_BASE_URL: str
+    OPENAI_API_VERSION: str
     OPENAI_API_KEY: str
 
 
@@ -119,6 +121,9 @@ async def update_config(
     request.app.state.config.IMAGES_OPENAI_API_BASE_URL = (
         form_data.openai.OPENAI_API_BASE_URL
     )
+    request.app.state.config.IMAGES_OPENAI_API_VERSION = (
+        form_data.openai.OPENAI_API_VERSION
+    )
     request.app.state.config.IMAGES_OPENAI_API_KEY = form_data.openai.OPENAI_API_KEY
 
     request.app.state.config.IMAGES_GEMINI_API_BASE_URL = (
@@ -165,6 +170,7 @@ async def update_config(
         "prompt_generation": request.app.state.config.ENABLE_IMAGE_PROMPT_GENERATION,
         "openai": {
             "OPENAI_API_BASE_URL": request.app.state.config.IMAGES_OPENAI_API_BASE_URL,
+            "OPENAI_API_VERSION": request.app.state.config.IMAGES_OPENAI_API_VERSION,
             "OPENAI_API_KEY": request.app.state.config.IMAGES_OPENAI_API_KEY,
         },
         "automatic1111": {
@@ -543,11 +549,15 @@ async def image_generations(
                     else {"response_format": "b64_json"}
                 ),
             }
+            
+            api_version_query_param = ""
+            if (request.app.state.config.IMAGES_OPENAI_API_VERSION):
+                api_version_query_param = f"?api-version={request.app.state.config.IMAGES_OPENAI_API_VERSION}"
 
             # Use asyncio.to_thread for the requests.post call
             r = await asyncio.to_thread(
                 requests.post,
-                url=f"{request.app.state.config.IMAGES_OPENAI_API_BASE_URL}/images/generations",
+                url=f"{request.app.state.config.IMAGES_OPENAI_API_BASE_URL}/images/generations{api_version_query_param}",
                 json=data,
                 headers=headers,
             )

+ 35 - 13
src/lib/components/admin/Settings/Images.svelte

@@ -599,20 +599,42 @@
 					{/if}
 				{:else if config?.engine === 'openai'}
 					<div>
-						<div class=" mb-1.5 text-sm font-medium">{$i18n.t('OpenAI API Config')}</div>
-
-						<div class="flex gap-2 mb-1">
-							<input
-								class="flex-1 w-full text-sm bg-transparent outline-hidden"
-								placeholder={$i18n.t('API Base URL')}
-								bind:value={config.openai.OPENAI_API_BASE_URL}
-								required
-							/>
+						<div class=" mb-2 text-sm font-medium">{$i18n.t('OpenAI API Config')}</div>
+						<div class="flex w-full">
+							<div class="flex-1 mr-2">
+								<input
+									class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
+									placeholder={$i18n.t('API Base URL')}
+									bind:value={config.openai.OPENAI_API_BASE_URL}
+									required
+								/>
+							</div>
+						</div>
+					</div>
 
-							<SensitiveInput
-								placeholder={$i18n.t('API Key')}
-								bind:value={config.openai.OPENAI_API_KEY}
-							/>
+					<div>
+						<div class=" mb-2 text-sm font-medium">{$i18n.t('API Key')}</div>
+						<div class="flex w-full">
+							<div class="flex-1 mr-2">
+								<SensitiveInput
+									placeholder={$i18n.t('API Key')}
+									bind:value={config.openai.OPENAI_API_KEY}
+									required
+								/>
+							</div>
+						</div>
+					</div>
+					
+					<div>
+						<div class=" mb-2 text-sm font-medium">{$i18n.t('API Version')}</div>
+						<div class="flex w-full">
+							<div class="flex-1 mr-2">
+								<input
+									class="w-full rounded-lg py-2 px-4 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden"
+									placeholder={$i18n.t('API Version')}
+									bind:value={config.openai.OPENAI_API_VERSION}
+								/>
+							</div>
 						</div>
 					</div>
 				{:else if config?.engine === 'gemini'}