diff --git a/backend/open_webui/models/users.py b/backend/open_webui/models/users.py index 5b6c27214..bceb72572 100644 --- a/backend/open_webui/models/users.py +++ b/backend/open_webui/models/users.py @@ -168,6 +168,18 @@ class UsersTable: except Exception: return None + def get_user_webhook_url_by_id(self, id: str) -> Optional[str]: + try: + with get_db() as db: + user = db.query(User).filter_by(id=id).first() + return ( + user.settings.get("ui", {}) + .get("notifications", {}) + .get("webhook_url", None) + ) + except Exception: + return None + def update_user_role_by_id(self, id: str, role: str) -> Optional[UserModel]: try: with get_db() as db: diff --git a/backend/open_webui/socket/main.py b/backend/open_webui/socket/main.py index f336030d3..aaf44e2cb 100644 --- a/backend/open_webui/socket/main.py +++ b/backend/open_webui/socket/main.py @@ -249,3 +249,9 @@ def get_event_call(request_info): return response return __event_call__ + + +def get_user_id_from_session_pool(sid): + print("get_user_id_from_session_pool", sid) + print(SESSION_POOL.get(sid)) + return SESSION_POOL.get(sid) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 472f4ecf0..0ea10ebf5 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -18,15 +18,18 @@ from starlette.responses import Response, StreamingResponse from open_webui.models.chats import Chats +from open_webui.models.users import Users from open_webui.socket.main import ( get_event_call, get_event_emitter, + get_user_id_from_session_pool, ) from open_webui.routers.tasks import ( generate_queries, generate_title, generate_chat_tags, ) +from open_webui.utils.webhook import post_webhook from open_webui.models.users import UserModel @@ -55,7 +58,12 @@ from open_webui.utils.plugin import load_function_module_by_id from open_webui.tasks import create_task from open_webui.config import DEFAULT_TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE -from open_webui.env import SRC_LOG_LEVELS, GLOBAL_LOG_LEVEL, BYPASS_MODEL_ACCESS_CONTROL +from open_webui.env import ( + SRC_LOG_LEVELS, + GLOBAL_LOG_LEVEL, + BYPASS_MODEL_ACCESS_CONTROL, + WEBUI_URL, +) from open_webui.constants import TASKS @@ -593,6 +601,25 @@ async def process_chat_response(request, response, user, events, metadata, tasks if done: data = {"done": True, "content": content, "title": title} + + if ( + get_user_id_from_session_pool(metadata["session_id"]) + is None + ): + webhook_url = Users.get_user_webhook_url_by_id(user.id) + print(f"webhook_url: {webhook_url}") + if webhook_url: + post_webhook( + webhook_url, + f"{title} - {WEBUI_URL}/{metadata['chat_id']}\n\n{content}", + { + "action": "chat", + "message": content, + "title": title, + "url": f"{WEBUI_URL}/{metadata['chat_id']}", + }, + ) + else: continue diff --git a/backend/open_webui/utils/webhook.py b/backend/open_webui/utils/webhook.py index 234209884..e6e10884a 100644 --- a/backend/open_webui/utils/webhook.py +++ b/backend/open_webui/utils/webhook.py @@ -11,6 +11,7 @@ log.setLevel(SRC_LOG_LEVELS["WEBHOOK"]) def post_webhook(url: str, message: str, event_data: dict) -> bool: try: + log.debug(f"post_webhook: {url}, {message}, {event_data}") payload = {} # Slack and Google Chat Webhooks diff --git a/src/lib/components/chat/Settings/Account.svelte b/src/lib/components/chat/Settings/Account.svelte index 70c53977e..fd14e696a 100644 --- a/src/lib/components/chat/Settings/Account.svelte +++ b/src/lib/components/chat/Settings/Account.svelte @@ -2,7 +2,7 @@ import { toast } from 'svelte-sonner'; import { onMount, getContext } from 'svelte'; - import { user, config } from '$lib/stores'; + import { user, config, settings } from '$lib/stores'; import { updateUserProfile, createAPIKey, getAPIKey } from '$lib/apis/auths'; import UpdatePassword from './Account/UpdatePassword.svelte'; @@ -16,10 +16,12 @@ const i18n = getContext('i18n'); export let saveHandler: Function; + export let saveSettings: Function; let profileImageUrl = ''; let name = ''; + let webhookUrl = ''; let showAPIKeys = false; let JWTTokenCopied = false; @@ -35,6 +37,15 @@ } } + if (webhookUrl !== $settings?.notifications?.webhook_url) { + saveSettings({ + notifications: { + ...$settings.notifications, + webhook_url: webhookUrl + } + }); + } + const updatedUser = await updateUserProfile(localStorage.token, name, profileImageUrl).catch( (error) => { toast.error(error); @@ -60,6 +71,7 @@ onMount(async () => { name = $user.name; profileImageUrl = $user.profile_image_url; + webhookUrl = $settings?.notifications?.webhook_url ?? ''; APIKey = await getAPIKey(localStorage.token).catch((error) => { console.log(error); @@ -226,6 +238,22 @@ + +
+
+
{$i18n.t('Notification Webhook')}
+ +
+ +
+
+
diff --git a/src/lib/components/chat/Settings/Account/UpdatePassword.svelte b/src/lib/components/chat/Settings/Account/UpdatePassword.svelte index 175ee61eb..eec899002 100644 --- a/src/lib/components/chat/Settings/Account/UpdatePassword.svelte +++ b/src/lib/components/chat/Settings/Account/UpdatePassword.svelte @@ -60,9 +60,10 @@
@@ -74,9 +75,10 @@
@@ -88,9 +90,10 @@
@@ -100,7 +103,7 @@
diff --git a/src/lib/components/chat/SettingsModal.svelte b/src/lib/components/chat/SettingsModal.svelte index 2c381a62f..62f6d016f 100644 --- a/src/lib/components/chat/SettingsModal.svelte +++ b/src/lib/components/chat/SettingsModal.svelte @@ -637,6 +637,7 @@ {:else if selectedTab === 'account'} { toast.success($i18n.t('Settings saved successfully!')); }}