feat: global image compression

This commit is contained in:
Timothy Jaeryang Baek 2025-06-16 16:52:57 +04:00
parent 2949be4f27
commit 6c54ca552a
6 changed files with 142 additions and 15 deletions

View File

@ -2107,6 +2107,27 @@ RAG_FILE_MAX_SIZE = PersistentConfig(
),
)
FILE_IMAGE_COMPRESSION_WIDTH = PersistentConfig(
"FILE_IMAGE_COMPRESSION_WIDTH",
"file.image_compression_width",
(
int(os.environ.get("FILE_IMAGE_COMPRESSION_WIDTH"))
if os.environ.get("FILE_IMAGE_COMPRESSION_WIDTH")
else None
),
)
FILE_IMAGE_COMPRESSION_HEIGHT = PersistentConfig(
"FILE_IMAGE_COMPRESSION_HEIGHT",
"file.image_compression_height",
(
int(os.environ.get("FILE_IMAGE_COMPRESSION_HEIGHT"))
if os.environ.get("FILE_IMAGE_COMPRESSION_HEIGHT")
else None
),
)
RAG_ALLOWED_FILE_EXTENSIONS = PersistentConfig(
"RAG_ALLOWED_FILE_EXTENSIONS",
"rag.file.allowed_extensions",
@ -2909,7 +2930,13 @@ AUDIO_STT_MODEL = PersistentConfig(
AUDIO_STT_SUPPORTED_CONTENT_TYPES = PersistentConfig(
"AUDIO_STT_SUPPORTED_CONTENT_TYPES",
"audio.stt.supported_content_types",
os.getenv("AUDIO_STT_SUPPORTED_CONTENT_TYPES", "").split(","),
[
content_type.strip()
for content_type in os.environ.get(
"AUDIO_STT_SUPPORTED_CONTENT_TYPES", ""
).split(",")
if content_type.strip()
],
)
AUDIO_STT_AZURE_API_KEY = PersistentConfig(

View File

@ -211,6 +211,8 @@ from open_webui.config import (
RAG_ALLOWED_FILE_EXTENSIONS,
RAG_FILE_MAX_COUNT,
RAG_FILE_MAX_SIZE,
FILE_IMAGE_COMPRESSION_WIDTH,
FILE_IMAGE_COMPRESSION_HEIGHT,
RAG_OPENAI_API_BASE_URL,
RAG_OPENAI_API_KEY,
RAG_AZURE_OPENAI_BASE_URL,
@ -713,9 +715,13 @@ app.state.config.TOP_K = RAG_TOP_K
app.state.config.TOP_K_RERANKER = RAG_TOP_K_RERANKER
app.state.config.RELEVANCE_THRESHOLD = RAG_RELEVANCE_THRESHOLD
app.state.config.HYBRID_BM25_WEIGHT = RAG_HYBRID_BM25_WEIGHT
app.state.config.ALLOWED_FILE_EXTENSIONS = RAG_ALLOWED_FILE_EXTENSIONS
app.state.config.FILE_MAX_SIZE = RAG_FILE_MAX_SIZE
app.state.config.FILE_MAX_COUNT = RAG_FILE_MAX_COUNT
app.state.config.FILE_IMAGE_COMPRESSION_WIDTH = FILE_IMAGE_COMPRESSION_WIDTH
app.state.config.FILE_IMAGE_COMPRESSION_HEIGHT = FILE_IMAGE_COMPRESSION_HEIGHT
app.state.config.RAG_FULL_CONTEXT = RAG_FULL_CONTEXT
@ -1558,6 +1564,10 @@ async def get_app_config(request: Request):
"file": {
"max_size": app.state.config.FILE_MAX_SIZE,
"max_count": app.state.config.FILE_MAX_COUNT,
"image_compression": {
"width": app.state.config.FILE_IMAGE_COMPRESSION_WIDTH,
"height": app.state.config.FILE_IMAGE_COMPRESSION_HEIGHT,
},
},
"permissions": {**app.state.config.USER_PERMISSIONS},
"google_drive": {

View File

@ -432,6 +432,8 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)):
# File upload settings
"FILE_MAX_SIZE": request.app.state.config.FILE_MAX_SIZE,
"FILE_MAX_COUNT": request.app.state.config.FILE_MAX_COUNT,
"FILE_IMAGE_COMPRESSION_WIDTH": request.app.state.config.FILE_IMAGE_COMPRESSION_WIDTH,
"FILE_IMAGE_COMPRESSION_HEIGHT": request.app.state.config.FILE_IMAGE_COMPRESSION_HEIGHT,
"ALLOWED_FILE_EXTENSIONS": request.app.state.config.ALLOWED_FILE_EXTENSIONS,
# Integration settings
"ENABLE_GOOGLE_DRIVE_INTEGRATION": request.app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION,
@ -599,6 +601,8 @@ class ConfigForm(BaseModel):
# File upload settings
FILE_MAX_SIZE: Optional[int] = None
FILE_MAX_COUNT: Optional[int] = None
FILE_IMAGE_COMPRESSION_WIDTH: Optional[int] = None
FILE_IMAGE_COMPRESSION_HEIGHT: Optional[int] = None
ALLOWED_FILE_EXTENSIONS: Optional[List[str]] = None
# Integration settings
@ -847,15 +851,13 @@ async def update_rag_config(
)
# File upload settings
request.app.state.config.FILE_MAX_SIZE = (
form_data.FILE_MAX_SIZE
if form_data.FILE_MAX_SIZE is not None
else request.app.state.config.FILE_MAX_SIZE
request.app.state.config.FILE_MAX_SIZE = form_data.FILE_MAX_SIZE
request.app.state.config.FILE_MAX_COUNT = form_data.FILE_MAX_COUNT
request.app.state.config.FILE_IMAGE_COMPRESSION_WIDTH = (
form_data.FILE_IMAGE_COMPRESSION_WIDTH
)
request.app.state.config.FILE_MAX_COUNT = (
form_data.FILE_MAX_COUNT
if form_data.FILE_MAX_COUNT is not None
else request.app.state.config.FILE_MAX_COUNT
request.app.state.config.FILE_IMAGE_COMPRESSION_HEIGHT = (
form_data.FILE_IMAGE_COMPRESSION_HEIGHT
)
request.app.state.config.ALLOWED_FILE_EXTENSIONS = (
form_data.ALLOWED_FILE_EXTENSIONS
@ -1025,6 +1027,8 @@ async def update_rag_config(
# File upload settings
"FILE_MAX_SIZE": request.app.state.config.FILE_MAX_SIZE,
"FILE_MAX_COUNT": request.app.state.config.FILE_MAX_COUNT,
"FILE_IMAGE_COMPRESSION_WIDTH": request.app.state.config.FILE_IMAGE_COMPRESSION_WIDTH,
"FILE_IMAGE_COMPRESSION_HEIGHT": request.app.state.config.FILE_IMAGE_COMPRESSION_HEIGHT,
"ALLOWED_FILE_EXTENSIONS": request.app.state.config.ALLOWED_FILE_EXTENSIONS,
# Integration settings
"ENABLE_GOOGLE_DRIVE_INTEGRATION": request.app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION,

View File

@ -1144,6 +1144,50 @@
</Tooltip>
</div>
</div>
<div class=" mb-2.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">{$i18n.t('Image Compression Width')}</div>
<div class="flex items-center relative">
<Tooltip
content={$i18n.t(
'The width in pixels to compress images to. Leave empty for no compression.'
)}
placement="top-start"
>
<input
class="flex-1 w-full text-sm bg-transparent outline-hidden"
type="number"
placeholder={$i18n.t('Leave empty for no compression')}
bind:value={RAGConfig.FILE_IMAGE_COMPRESSION_WIDTH}
autocomplete="off"
min="0"
/>
</Tooltip>
</div>
</div>
<div class=" mb-2.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">
{$i18n.t('Image Compression Height')}
</div>
<div class="flex items-center relative">
<Tooltip
content={$i18n.t(
'The height in pixels to compress images to. Leave empty for no compression.'
)}
placement="top-start"
>
<input
class="flex-1 w-full text-sm bg-transparent outline-hidden"
type="number"
placeholder={$i18n.t('Leave empty for no compression')}
bind:value={RAGConfig.FILE_IMAGE_COMPRESSION_HEIGHT}
autocomplete="off"
min="0"
/>
</Tooltip>
</div>
</div>
</div>
<div class="mb-3">

View File

@ -110,9 +110,30 @@
reader.onload = async (event) => {
let imageUrl = event.target.result;
if (
($settings?.imageCompression ?? false) ||
($config?.file?.image_compression?.width ?? null) ||
($config?.file?.image_compression?.height ?? null)
) {
let width = null;
let height = null;
if ($settings?.imageCompression ?? false) {
const width = $settings?.imageCompressionSize?.width ?? null;
const height = $settings?.imageCompressionSize?.height ?? null;
width = $settings?.imageCompressionSize?.width ?? null;
height = $settings?.imageCompressionSize?.height ?? null;
}
if (
($config?.file?.image_compression?.width ?? null) ||
($config?.file?.image_compression?.height ?? null)
) {
if (width > ($config?.file?.image_compression?.width ?? null)) {
width = $config?.file?.image_compression?.width ?? null;
}
if (height > ($config?.file?.image_compression?.height ?? null)) {
height = $config?.file?.image_compression?.height ?? null;
}
}
if (width || height) {
imageUrl = await compressImage(imageUrl, width, height);

View File

@ -355,9 +355,30 @@
reader.onload = async (event) => {
let imageUrl = event.target.result;
if (
($settings?.imageCompression ?? false) ||
($config?.file?.image_compression?.width ?? null) ||
($config?.file?.image_compression?.height ?? null)
) {
let width = null;
let height = null;
if ($settings?.imageCompression ?? false) {
const width = $settings?.imageCompressionSize?.width ?? null;
const height = $settings?.imageCompressionSize?.height ?? null;
width = $settings?.imageCompressionSize?.width ?? null;
height = $settings?.imageCompressionSize?.height ?? null;
}
if (
($config?.file?.image_compression?.width ?? null) ||
($config?.file?.image_compression?.height ?? null)
) {
if (width > ($config?.file?.image_compression?.width ?? null)) {
width = $config?.file?.image_compression?.width ?? null;
}
if (height > ($config?.file?.image_compression?.height ?? null)) {
height = $config?.file?.image_compression?.height ?? null;
}
}
if (width || height) {
imageUrl = await compressImage(imageUrl, width, height);