Pārlūkot izejas kodu

feat: response watermark

Timothy Jaeryang Baek 4 mēneši atpakaļ
vecāks
revīzija
0a8cecfbfa

+ 7 - 0
backend/open_webui/config.py

@@ -1002,6 +1002,13 @@ PENDING_USER_OVERLAY_CONTENT = PersistentConfig(
 )
 
 
+RESPONSE_WATERMARK = PersistentConfig(
+    "RESPONSE_WATERMARK",
+    "ui.watermark",
+    os.environ.get("RESPONSE_WATERMARK", ""),
+)
+
+
 USER_PERMISSIONS_WORKSPACE_MODELS_ACCESS = (
     os.environ.get("USER_PERMISSIONS_WORKSPACE_MODELS_ACCESS", "False").lower()
     == "true"

+ 5 - 0
backend/open_webui/main.py

@@ -334,6 +334,7 @@ from open_webui.config import (
     DEFAULT_LOCALE,
     OAUTH_PROVIDERS,
     WEBUI_URL,
+    RESPONSE_WATERMARK,
     # Admin
     ENABLE_ADMIN_CHAT_ACCESS,
     ENABLE_ADMIN_EXPORT,
@@ -580,9 +581,12 @@ app.state.config.ADMIN_EMAIL = ADMIN_EMAIL
 app.state.config.DEFAULT_MODELS = DEFAULT_MODELS
 app.state.config.DEFAULT_PROMPT_SUGGESTIONS = DEFAULT_PROMPT_SUGGESTIONS
 app.state.config.DEFAULT_USER_ROLE = DEFAULT_USER_ROLE
+
 app.state.config.PENDING_USER_OVERLAY_CONTENT = PENDING_USER_OVERLAY_CONTENT
 app.state.config.PENDING_USER_OVERLAY_TITLE = PENDING_USER_OVERLAY_TITLE
 
+app.state.config.RESPONSE_WATERMARK = RESPONSE_WATERMARK
+
 app.state.config.USER_PERMISSIONS = USER_PERMISSIONS
 app.state.config.WEBHOOK_URL = WEBHOOK_URL
 app.state.config.BANNERS = WEBUI_BANNERS
@@ -1413,6 +1417,7 @@ async def get_app_config(request: Request):
                 "ui": {
                     "pending_user_overlay_title": app.state.config.PENDING_USER_OVERLAY_TITLE,
                     "pending_user_overlay_content": app.state.config.PENDING_USER_OVERLAY_CONTENT,
+                    "response_watermark": app.state.config.RESPONSE_WATERMARK,
                 },
                 "license_metadata": app.state.LICENSE_METADATA,
                 **(

+ 6 - 3
backend/open_webui/routers/auths.py

@@ -187,9 +187,7 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm):
     LDAP_USE_TLS = request.app.state.config.LDAP_USE_TLS
     LDAP_CA_CERT_FILE = request.app.state.config.LDAP_CA_CERT_FILE
     LDAP_VALIDATE_CERT = (
-        CERT_REQUIRED
-        if request.app.state.config.LDAP_VALIDATE_CERT
-        else CERT_NONE
+        CERT_REQUIRED if request.app.state.config.LDAP_VALIDATE_CERT else CERT_NONE
     )
     LDAP_CIPHERS = (
         request.app.state.config.LDAP_CIPHERS
@@ -703,6 +701,7 @@ async def get_admin_config(request: Request, user=Depends(get_admin_user)):
         "ENABLE_USER_WEBHOOKS": request.app.state.config.ENABLE_USER_WEBHOOKS,
         "PENDING_USER_OVERLAY_TITLE": request.app.state.config.PENDING_USER_OVERLAY_TITLE,
         "PENDING_USER_OVERLAY_CONTENT": request.app.state.config.PENDING_USER_OVERLAY_CONTENT,
+        "RESPONSE_WATERMARK": request.app.state.config.RESPONSE_WATERMARK,
     }
 
 
@@ -722,6 +721,7 @@ class AdminConfig(BaseModel):
     ENABLE_USER_WEBHOOKS: bool
     PENDING_USER_OVERLAY_TITLE: Optional[str] = None
     PENDING_USER_OVERLAY_CONTENT: Optional[str] = None
+    RESPONSE_WATERMARK: Optional[str] = None
 
 
 @router.post("/admin/config")
@@ -766,6 +766,8 @@ async def update_admin_config(
         form_data.PENDING_USER_OVERLAY_CONTENT
     )
 
+    request.app.state.config.RESPONSE_WATERMARK = form_data.RESPONSE_WATERMARK
+
     return {
         "SHOW_ADMIN_DETAILS": request.app.state.config.SHOW_ADMIN_DETAILS,
         "WEBUI_URL": request.app.state.config.WEBUI_URL,
@@ -782,6 +784,7 @@ async def update_admin_config(
         "ENABLE_USER_WEBHOOKS": request.app.state.config.ENABLE_USER_WEBHOOKS,
         "PENDING_USER_OVERLAY_TITLE": request.app.state.config.PENDING_USER_OVERLAY_TITLE,
         "PENDING_USER_OVERLAY_CONTENT": request.app.state.config.PENDING_USER_OVERLAY_CONTENT,
+        "RESPONSE_WATERMARK": request.app.state.config.RESPONSE_WATERMARK,
     }
 
 

+ 14 - 4
src/lib/components/admin/Settings/General.svelte

@@ -306,8 +306,8 @@
 						<Switch bind:state={adminConfig.SHOW_ADMIN_DETAILS} />
 					</div>
 
-					<div class="mb-3.5">
-						<div class=" self-center text-xs font-medium mb-1">
+					<div class="mb-2.5">
+						<div class=" self-center text-xs font-medium mb-2">
 							{$i18n.t('Pending User Overlay Title')}
 						</div>
 						<Textarea
@@ -319,8 +319,8 @@
 						/>
 					</div>
 
-					<div class="mb-3.5">
-						<div class=" self-center text-xs font-medium mb-1">
+					<div class="mb-2.5">
+						<div class=" self-center text-xs font-medium mb-2">
 							{$i18n.t('Pending User Overlay Content')}
 						</div>
 						<Textarea
@@ -658,6 +658,16 @@
 						<Switch bind:state={adminConfig.ENABLE_USER_WEBHOOKS} />
 					</div>
 
+					<div class="mb-2.5">
+						<div class=" self-center text-xs font-medium mb-2">
+							{$i18n.t('Response Watermark')}
+						</div>
+						<Textarea
+							placeholder={$i18n.t('Enter a watermark for the response. Leave empty for none.')}
+							bind:value={adminConfig.RESPONSE_WATERMARK}
+						/>
+					</div>
+
 					<div class="mb-2.5 w-full justify-between">
 						<div class="flex w-full justify-between">
 							<div class=" self-center text-xs font-medium">{$i18n.t('WebUI URL')}</div>

+ 4 - 0
src/lib/components/chat/Messages/ResponseMessage.svelte

@@ -157,6 +157,10 @@
 	const copyToClipboard = async (text) => {
 		text = removeAllDetails(text);
 
+		if (($config?.ui?.response_watermark ?? '').trim() !== '') {
+			text = `${text}\n\n${$config?.ui?.response_watermark}`;
+		}
+
 		const res = await _copyToClipboard(text, $settings?.copyFormatted ?? false);
 		if (res) {
 			toast.success($i18n.t('Copying to clipboard was successful!'));

+ 1 - 1
src/lib/components/common/Textarea.svelte

@@ -7,7 +7,7 @@
 	export let minSize = null;
 	export let required = false;
 	export let className =
-		'w-full rounded-lg px-3 py-2 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden  h-full';
+		'w-full rounded-lg px-3.5 py-2 text-sm bg-gray-50 dark:text-gray-300 dark:bg-gray-850 outline-hidden  h-full';
 
 	let textareaElement;
 

+ 2 - 2
src/lib/components/layout/Overlay/AccountPending.svelte

@@ -25,7 +25,7 @@
 					class="text-center dark:text-white text-2xl font-medium z-50"
 					style="white-space: pre-wrap;"
 				>
-					{#if $config?.ui?.pending_user_overlay_title && $config?.ui?.pending_user_overlay_title.trim() !== ''}
+					{#if ($config?.ui?.pending_user_overlay_title ?? '').trim() !== ''}
 						{$config.ui.pending_user_overlay_title}
 					{:else}
 						{$i18n.t('Account Activation Pending')}<br />
@@ -37,7 +37,7 @@
 					class=" mt-4 text-center text-sm dark:text-gray-200 w-full"
 					style="white-space: pre-wrap;"
 				>
-					{#if $config?.ui?.pending_user_overlay_content && $config?.ui?.pending_user_overlay_content.trim() !== ''}
+					{#if ($config?.ui?.pending_user_overlay_content ?? '').trim() !== ''}
 						{$config.ui.pending_user_overlay_content}
 					{:else}
 						{$i18n.t('Your account status is currently pending activation.')}{'\n'}{$i18n.t(