forked from open-webui/open-webui
		
	Merge pull request #888 from jmfirth/feature/img-gen-steps-setting
Add steps setting for image generation
This commit is contained in:
		
						commit
						92ec0d90e1
					
				
					 4 changed files with 119 additions and 2 deletions
				
			
		|  | @ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | ||||||
| 
 | 
 | ||||||
| - **Built-in LiteLLM Proxy**: Open WebUI now ships with LiteLLM Proxy. | - **Built-in LiteLLM Proxy**: Open WebUI now ships with LiteLLM Proxy. | ||||||
| - **Image Generation Enhancements**: Advanced Settings + Image Preview Feature. | - **Image Generation Enhancements**: Advanced Settings + Image Preview Feature. | ||||||
|  |   - Allows setting number of steps for image generation; defaults to a1111 default value. | ||||||
| 
 | 
 | ||||||
| ### Fixed | ### Fixed | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -35,6 +35,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.state.IMAGE_SIZE = "512x512" | ||||||
|  | app.state.IMAGE_STEPS = 50 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @app.get("/enabled", response_model=bool) | @app.get("/enabled", response_model=bool) | ||||||
|  | @ -102,6 +103,32 @@ async def update_image_size( | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class ImageStepsUpdateForm(BaseModel): | ||||||
|  |     steps: int | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @app.get("/steps") | ||||||
|  | async def get_image_size(user=Depends(get_admin_user)): | ||||||
|  |     return {"IMAGE_STEPS": app.state.IMAGE_STEPS} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @app.post("/steps/update") | ||||||
|  | async def update_image_size( | ||||||
|  |     form_data: ImageStepsUpdateForm, user=Depends(get_admin_user) | ||||||
|  | ): | ||||||
|  |     if form_data.steps >= 0: | ||||||
|  |         app.state.IMAGE_STEPS = form_data.steps | ||||||
|  |         return { | ||||||
|  |             "IMAGE_STEPS": app.state.IMAGE_STEPS, | ||||||
|  |             "status": True, | ||||||
|  |         } | ||||||
|  |     else: | ||||||
|  |         raise HTTPException( | ||||||
|  |             status_code=400, | ||||||
|  |             detail=ERROR_MESSAGES.INCORRECT_FORMAT("  (e.g., 50)."), | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| @app.get("/models") | @app.get("/models") | ||||||
| def get_models(user=Depends(get_current_user)): | def get_models(user=Depends(get_current_user)): | ||||||
|     try: |     try: | ||||||
|  | @ -179,6 +206,9 @@ def generate_image( | ||||||
|             "height": height, |             "height": height, | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         if app.state.IMAGE_STEPS != None: | ||||||
|  |             data["steps"] = app.state.IMAGE_STEPS | ||||||
|  | 
 | ||||||
|         if form_data.negative_prompt != None: |         if form_data.negative_prompt != None: | ||||||
|             data["negative_prompt"] = form_data.negative_prompt |             data["negative_prompt"] = form_data.negative_prompt | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -198,6 +198,71 @@ export const updateImageSize = async (token: string = '', size: string) => { | ||||||
| 	return res.IMAGE_SIZE; | 	return res.IMAGE_SIZE; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | export const getImageSteps = async (token: string = '') => { | ||||||
|  | 	let error = null; | ||||||
|  | 
 | ||||||
|  | 	const res = await fetch(`${IMAGES_API_BASE_URL}/steps`, { | ||||||
|  | 		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_STEPS; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export const updateImageSteps = async (token: string = '', steps: number) => { | ||||||
|  | 	let error = null; | ||||||
|  | 
 | ||||||
|  | 	const res = await fetch(`${IMAGES_API_BASE_URL}/steps/update`, { | ||||||
|  | 		method: 'POST', | ||||||
|  | 		headers: { | ||||||
|  | 			Accept: 'application/json', | ||||||
|  | 			'Content-Type': 'application/json', | ||||||
|  | 			...(token && { authorization: `Bearer ${token}` }) | ||||||
|  | 		}, | ||||||
|  | 		body: JSON.stringify({ steps }) | ||||||
|  | 	}) | ||||||
|  | 		.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_STEPS; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| export const getDiffusionModels = async (token: string = '') => { | export const getDiffusionModels = async (token: string = '') => { | ||||||
| 	let error = null; | 	let error = null; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -12,7 +12,9 @@ | ||||||
| 		toggleImageGenerationEnabledStatus, | 		toggleImageGenerationEnabledStatus, | ||||||
| 		updateAUTOMATIC1111Url, | 		updateAUTOMATIC1111Url, | ||||||
| 		updateDefaultDiffusionModel, | 		updateDefaultDiffusionModel, | ||||||
| 		updateImageSize | 		updateImageSize, | ||||||
|  | 		getImageSteps, | ||||||
|  | 		updateImageSteps | ||||||
| 	} from '$lib/apis/images'; | 	} from '$lib/apis/images'; | ||||||
| 	import { getBackendConfig } from '$lib/apis'; | 	import { getBackendConfig } from '$lib/apis'; | ||||||
| 	const dispatch = createEventDispatcher(); | 	const dispatch = createEventDispatcher(); | ||||||
|  | @ -21,13 +23,14 @@ | ||||||
| 
 | 
 | ||||||
| 	let loading = false; | 	let loading = false; | ||||||
| 
 | 
 | ||||||
| 	let enableImageGeneration = true; | 	let enableImageGeneration = false; | ||||||
| 	let AUTOMATIC1111_BASE_URL = ''; | 	let AUTOMATIC1111_BASE_URL = ''; | ||||||
| 
 | 
 | ||||||
| 	let selectedModel = ''; | 	let selectedModel = ''; | ||||||
| 	let models = []; | 	let models = []; | ||||||
| 
 | 
 | ||||||
| 	let imageSize = ''; | 	let imageSize = ''; | ||||||
|  | 	let steps = 50; | ||||||
| 
 | 
 | ||||||
| 	const getModels = async () => { | 	const getModels = async () => { | ||||||
| 		models = await getDiffusionModels(localStorage.token).catch((error) => { | 		models = await getDiffusionModels(localStorage.token).catch((error) => { | ||||||
|  | @ -85,6 +88,7 @@ | ||||||
| 
 | 
 | ||||||
| 			if (enableImageGeneration && AUTOMATIC1111_BASE_URL) { | 			if (enableImageGeneration && AUTOMATIC1111_BASE_URL) { | ||||||
| 				imageSize = await getImageSize(localStorage.token); | 				imageSize = await getImageSize(localStorage.token); | ||||||
|  | 				steps = await getImageSteps(localStorage.token); | ||||||
| 				getModels(); | 				getModels(); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | @ -100,6 +104,10 @@ | ||||||
| 			toast.error(error); | 			toast.error(error); | ||||||
| 			return null; | 			return null; | ||||||
| 		}); | 		}); | ||||||
|  | 		await updateImageSteps(localStorage.token, steps).catch((error) => { | ||||||
|  | 			toast.error(error); | ||||||
|  | 			return null; | ||||||
|  | 		}); | ||||||
| 
 | 
 | ||||||
| 		dispatch('save'); | 		dispatch('save'); | ||||||
| 		loading = false; | 		loading = false; | ||||||
|  | @ -212,6 +220,19 @@ | ||||||
| 					</div> | 					</div> | ||||||
| 				</div> | 				</div> | ||||||
| 			</div> | 			</div> | ||||||
|  | 
 | ||||||
|  | 			<div> | ||||||
|  | 				<div class=" mb-2.5 text-sm font-medium">Set Steps</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 Number of Steps (e.g. 50)" | ||||||
|  | 							bind:value={steps} | ||||||
|  | 						/> | ||||||
|  | 					</div> | ||||||
|  | 				</div> | ||||||
|  | 			</div> | ||||||
| 		{/if} | 		{/if} | ||||||
| 	</div> | 	</div> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Timothy Jaeryang Baek
						Timothy Jaeryang Baek