forked from open-webui/open-webui
		
	feat: image size param
This commit is contained in:
		
							parent
							
								
									0d99c292f6
								
							
						
					
					
						commit
						7ec4c07bf9
					
				
					 4 changed files with 125 additions and 6 deletions
				
			
		|  | @ -1,4 +1,4 @@ | ||||||
| import os | import re | ||||||
| import requests | import requests | ||||||
| from fastapi import ( | from fastapi import ( | ||||||
|     FastAPI, |     FastAPI, | ||||||
|  | @ -34,6 +34,7 @@ app.add_middleware( | ||||||
| 
 | 
 | ||||||
| app.state.AUTOMATIC1111_BASE_URL = AUTOMATIC1111_BASE_URL | app.state.AUTOMATIC1111_BASE_URL = AUTOMATIC1111_BASE_URL | ||||||
| app.state.ENABLED = app.state.AUTOMATIC1111_BASE_URL != "" | app.state.ENABLED = app.state.AUTOMATIC1111_BASE_URL != "" | ||||||
|  | app.state.IMAGE_SIZE = "512x512" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @app.get("/enabled", response_model=bool) | @app.get("/enabled", response_model=bool) | ||||||
|  | @ -74,6 +75,33 @@ async def update_openai_url(form_data: UrlUpdateForm, user=Depends(get_admin_use | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class ImageSizeUpdateForm(BaseModel): | ||||||
|  |     size: str | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @app.get("/size") | ||||||
|  | async def get_image_size(user=Depends(get_admin_user)): | ||||||
|  |     return {"IMAGE_SIZE": app.state.IMAGE_SIZE} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @app.post("/size/update") | ||||||
|  | async def update_image_size( | ||||||
|  |     form_data: ImageSizeUpdateForm, user=Depends(get_admin_user) | ||||||
|  | ): | ||||||
|  |     pattern = r"^\d+x\d+$"  # Regular expression pattern | ||||||
|  |     if re.match(pattern, form_data.size): | ||||||
|  |         app.state.IMAGE_SIZE = form_data.size | ||||||
|  |         return { | ||||||
|  |             "IMAGE_SIZE": app.state.IMAGE_SIZE, | ||||||
|  |             "status": True, | ||||||
|  |         } | ||||||
|  |     else: | ||||||
|  |         raise HTTPException( | ||||||
|  |             status_code=400, | ||||||
|  |             detail=ERROR_MESSAGES.INCORRECT_FORMAT("  (e.g., 512x512)."), | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| @app.get("/models") | @app.get("/models") | ||||||
| def get_models(user=Depends(get_current_user)): | def get_models(user=Depends(get_current_user)): | ||||||
|     try: |     try: | ||||||
|  | @ -140,7 +168,7 @@ def generate_image( | ||||||
|         if form_data.model: |         if form_data.model: | ||||||
|             set_model_handler(form_data.model) |             set_model_handler(form_data.model) | ||||||
| 
 | 
 | ||||||
|         width, height = tuple(map(int, form_data.size.split("x"))) |         width, height = tuple(map(int, app.state.IMAGE_SIZE.split("x"))) | ||||||
| 
 | 
 | ||||||
|         data = { |         data = { | ||||||
|             "prompt": form_data.prompt, |             "prompt": form_data.prompt, | ||||||
|  |  | ||||||
|  | @ -44,3 +44,6 @@ class ERROR_MESSAGES(str, Enum): | ||||||
|     MALICIOUS = "Unusual activities detected, please try again in a few minutes." |     MALICIOUS = "Unusual activities detected, please try again in a few minutes." | ||||||
| 
 | 
 | ||||||
|     PANDOC_NOT_INSTALLED = "Pandoc is not installed on the server. Please contact your administrator for assistance." |     PANDOC_NOT_INSTALLED = "Pandoc is not installed on the server. Please contact your administrator for assistance." | ||||||
|  |     INCORRECT_FORMAT = ( | ||||||
|  |         lambda err="": f"Invalid format. Please use the correct format{err if err else ''}" | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  | @ -131,6 +131,73 @@ export const updateAUTOMATIC1111Url = async (token: string = '', url: string) => | ||||||
| 	return res.AUTOMATIC1111_BASE_URL; | 	return res.AUTOMATIC1111_BASE_URL; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | export const getImageSize = async (token: string = '') => { | ||||||
|  | 	let error = null; | ||||||
|  | 
 | ||||||
|  | 	const res = await fetch(`${IMAGES_API_BASE_URL}/size`, { | ||||||
|  | 		method: 'GET', | ||||||
|  | 		headers: { | ||||||
|  | 			Accept: 'application/json', | ||||||
|  | 			'Content-Type': 'application/json', | ||||||
|  | 			...(token && { authorization: `Bearer ${token}` }) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | 		.then(async (res) => { | ||||||
|  | 			if (!res.ok) throw await res.json(); | ||||||
|  | 			return res.json(); | ||||||
|  | 		}) | ||||||
|  | 		.catch((err) => { | ||||||
|  | 			console.log(err); | ||||||
|  | 			if ('detail' in err) { | ||||||
|  | 				error = err.detail; | ||||||
|  | 			} else { | ||||||
|  | 				error = 'Server connection failed'; | ||||||
|  | 			} | ||||||
|  | 			return null; | ||||||
|  | 		}); | ||||||
|  | 
 | ||||||
|  | 	if (error) { | ||||||
|  | 		throw error; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return res.IMAGE_SIZE; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export const updateImageSize = async (token: string = '', size: string) => { | ||||||
|  | 	let error = null; | ||||||
|  | 
 | ||||||
|  | 	const res = await fetch(`${IMAGES_API_BASE_URL}/size/update`, { | ||||||
|  | 		method: 'POST', | ||||||
|  | 		headers: { | ||||||
|  | 			Accept: 'application/json', | ||||||
|  | 			'Content-Type': 'application/json', | ||||||
|  | 			...(token && { authorization: `Bearer ${token}` }) | ||||||
|  | 		}, | ||||||
|  | 		body: JSON.stringify({ | ||||||
|  | 			size: size | ||||||
|  | 		}) | ||||||
|  | 	}) | ||||||
|  | 		.then(async (res) => { | ||||||
|  | 			if (!res.ok) throw await res.json(); | ||||||
|  | 			return res.json(); | ||||||
|  | 		}) | ||||||
|  | 		.catch((err) => { | ||||||
|  | 			console.log(err); | ||||||
|  | 			if ('detail' in err) { | ||||||
|  | 				error = err.detail; | ||||||
|  | 			} else { | ||||||
|  | 				error = 'Server connection failed'; | ||||||
|  | 			} | ||||||
|  | 			return null; | ||||||
|  | 		}); | ||||||
|  | 
 | ||||||
|  | 	if (error) { | ||||||
|  | 		throw error; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return res.IMAGE_SIZE; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| export const getDiffusionModels = async (token: string = '') => { | export const getDiffusionModels = async (token: string = '') => { | ||||||
| 	let error = null; | 	let error = null; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,9 +8,11 @@ | ||||||
| 		getDefaultDiffusionModel, | 		getDefaultDiffusionModel, | ||||||
| 		getDiffusionModels, | 		getDiffusionModels, | ||||||
| 		getImageGenerationEnabledStatus, | 		getImageGenerationEnabledStatus, | ||||||
|  | 		getImageSize, | ||||||
| 		toggleImageGenerationEnabledStatus, | 		toggleImageGenerationEnabledStatus, | ||||||
| 		updateAUTOMATIC1111Url, | 		updateAUTOMATIC1111Url, | ||||||
| 		updateDefaultDiffusionModel | 		updateDefaultDiffusionModel, | ||||||
|  | 		updateImageSize | ||||||
| 	} from '$lib/apis/images'; | 	} from '$lib/apis/images'; | ||||||
| 	import { getBackendConfig } from '$lib/apis'; | 	import { getBackendConfig } from '$lib/apis'; | ||||||
| 	const dispatch = createEventDispatcher(); | 	const dispatch = createEventDispatcher(); | ||||||
|  | @ -25,6 +27,8 @@ | ||||||
| 	let selectedModel = ''; | 	let selectedModel = ''; | ||||||
| 	let models = []; | 	let models = []; | ||||||
| 
 | 
 | ||||||
|  | 	let imageSize = ''; | ||||||
|  | 
 | ||||||
| 	const getModels = async () => { | 	const getModels = async () => { | ||||||
| 		models = await getDiffusionModels(localStorage.token).catch((error) => { | 		models = await getDiffusionModels(localStorage.token).catch((error) => { | ||||||
| 			toast.error(error); | 			toast.error(error); | ||||||
|  | @ -53,7 +57,6 @@ | ||||||
| 			AUTOMATIC1111_BASE_URL = await getAUTOMATIC1111Url(localStorage.token); | 			AUTOMATIC1111_BASE_URL = await getAUTOMATIC1111Url(localStorage.token); | ||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
| 
 |  | ||||||
| 	const toggleImageGeneration = async () => { | 	const toggleImageGeneration = async () => { | ||||||
| 		if (AUTOMATIC1111_BASE_URL) { | 		if (AUTOMATIC1111_BASE_URL) { | ||||||
| 			enableImageGeneration = await toggleImageGenerationEnabledStatus(localStorage.token).catch( | 			enableImageGeneration = await toggleImageGenerationEnabledStatus(localStorage.token).catch( | ||||||
|  | @ -79,6 +82,7 @@ | ||||||
| 			AUTOMATIC1111_BASE_URL = await getAUTOMATIC1111Url(localStorage.token); | 			AUTOMATIC1111_BASE_URL = await getAUTOMATIC1111Url(localStorage.token); | ||||||
| 
 | 
 | ||||||
| 			if (enableImageGeneration && AUTOMATIC1111_BASE_URL) { | 			if (enableImageGeneration && AUTOMATIC1111_BASE_URL) { | ||||||
|  | 				imageSize = await getImageSize(localStorage.token); | ||||||
| 				getModels(); | 				getModels(); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | @ -89,13 +93,17 @@ | ||||||
| 	class="flex flex-col h-full justify-between space-y-3 text-sm" | 	class="flex flex-col h-full justify-between space-y-3 text-sm" | ||||||
| 	on:submit|preventDefault={async () => { | 	on:submit|preventDefault={async () => { | ||||||
| 		loading = true; | 		loading = true; | ||||||
| 		const res = await updateDefaultDiffusionModel(localStorage.token, selectedModel); | 		await updateDefaultDiffusionModel(localStorage.token, selectedModel); | ||||||
|  | 		await updateImageSize(localStorage.token, imageSize).catch((error) => { | ||||||
|  | 			toast.error(error); | ||||||
|  | 			return null; | ||||||
|  | 		}); | ||||||
| 
 | 
 | ||||||
| 		dispatch('save'); | 		dispatch('save'); | ||||||
| 		loading = false; | 		loading = false; | ||||||
| 	}} | 	}} | ||||||
| > | > | ||||||
| 	<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80"> | 	<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[21rem]"> | ||||||
| 		<div> | 		<div> | ||||||
| 			<div class=" mb-1 text-sm font-medium">Image Settings</div> | 			<div class=" mb-1 text-sm font-medium">Image Settings</div> | ||||||
| 
 | 
 | ||||||
|  | @ -168,6 +176,19 @@ | ||||||
| 		{#if enableImageGeneration} | 		{#if enableImageGeneration} | ||||||
| 			<hr class=" dark:border-gray-700" /> | 			<hr class=" dark:border-gray-700" /> | ||||||
| 
 | 
 | ||||||
|  | 			<div> | ||||||
|  | 				<div class=" mb-2.5 text-sm font-medium">Set Image Size</div> | ||||||
|  | 				<div class="flex w-full"> | ||||||
|  | 					<div class="flex-1 mr-2"> | ||||||
|  | 						<input | ||||||
|  | 							class="w-full rounded py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none" | ||||||
|  | 							placeholder="Enter Image Size (e.g. 512x512)" | ||||||
|  | 							bind:value={imageSize} | ||||||
|  | 						/> | ||||||
|  | 					</div> | ||||||
|  | 				</div> | ||||||
|  | 			</div> | ||||||
|  | 
 | ||||||
| 			<div> | 			<div> | ||||||
| 				<div class=" mb-2.5 text-sm font-medium">Set default model</div> | 				<div class=" mb-2.5 text-sm font-medium">Set default model</div> | ||||||
| 				<div class="flex w-full"> | 				<div class="flex w-full"> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Timothy J. Baek
						Timothy J. Baek