diff --git a/src/main/services/NotificationService.ts b/src/main/services/NotificationService.ts
index e06036b523..5ba0d82ce4 100644
--- a/src/main/services/NotificationService.ts
+++ b/src/main/services/NotificationService.ts
@@ -1,8 +1,6 @@
import { BrowserWindow, Notification as ElectronNotification } from 'electron'
import { Notification } from 'src/renderer/src/types/notification'
-import icon from '../../../build/icon.png?asset'
-
class NotificationService {
private window: BrowserWindow
@@ -15,8 +13,7 @@ class NotificationService {
// 使用 Electron Notification API
const electronNotification = new ElectronNotification({
title: notification.title,
- body: notification.message,
- icon: icon
+ body: notification.message
})
electronNotification.on('click', () => {
diff --git a/src/renderer/src/hooks/useUpdateHandler.ts b/src/renderer/src/hooks/useUpdateHandler.ts
index fe4d8f631c..4724ddd688 100644
--- a/src/renderer/src/hooks/useUpdateHandler.ts
+++ b/src/renderer/src/hooks/useUpdateHandler.ts
@@ -31,7 +31,8 @@ export default function useUpdateHandler() {
title: t('button.update_available'),
message: t('button.update_available', { version: releaseInfo.version }),
timestamp: Date.now(),
- source: 'update'
+ source: 'update',
+ channel: 'system'
})
dispatch(
setUpdateState({
diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json
index e24f0c0eaa..301f97505f 100644
--- a/src/renderer/src/i18n/locales/en-us.json
+++ b/src/renderer/src/i18n/locales/en-us.json
@@ -906,7 +906,8 @@
"notification": {
"assistant": "Assistant Response",
"knowledge.error": "{{error}}",
- "knowledge.success": "Successfully added {{type}} to the knowledge base"
+ "knowledge.success": "Successfully added {{type}} to the knowledge base",
+ "tip": "If the response is successful, then only messages exceeding 30 seconds will trigger a reminder"
},
"ollama": {
"keep_alive_time.description": "The time in minutes to keep the connection alive, default is 5 minutes.",
diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json
index 76ba1c3daa..13f55bac96 100644
--- a/src/renderer/src/i18n/locales/ja-jp.json
+++ b/src/renderer/src/i18n/locales/ja-jp.json
@@ -906,7 +906,8 @@
"notification": {
"assistant": "助手回應",
"knowledge.error": "{{error}}",
- "knowledge.success": "ナレッジベースに{{type}}を正常に追加しました"
+ "knowledge.success": "ナレッジベースに{{type}}を正常に追加しました",
+ "tip": "応答が成功した場合、30秒を超えるメッセージのみに通知を行います"
},
"ollama": {
"keep_alive_time.description": "モデルがメモリに保持される時間(デフォルト:5分)",
diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json
index 9dbe4698e4..a59b9d6581 100644
--- a/src/renderer/src/i18n/locales/ru-ru.json
+++ b/src/renderer/src/i18n/locales/ru-ru.json
@@ -906,7 +906,8 @@
"notification": {
"assistant": "Ответ ассистента",
"knowledge.error": "{{error}}",
- "knowledge.success": "Успешно добавлено {{type}} в базу знаний"
+ "knowledge.success": "Успешно добавлено {{type}} в базу знаний",
+ "tip": "Если ответ успешен, уведомление выдается только по сообщениям, превышающим 30 секунд"
},
"ollama": {
"keep_alive_time.description": "Время в минутах, в течение которого модель остается активной, по умолчанию 5 минут.",
diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json
index 5c636eb8bf..52fea95ad0 100644
--- a/src/renderer/src/i18n/locales/zh-cn.json
+++ b/src/renderer/src/i18n/locales/zh-cn.json
@@ -906,7 +906,8 @@
"notification": {
"assistant": "助手响应",
"knowledge.error": "{{error}}",
- "knowledge.success": "成功添加 {{type}} 到知识库"
+ "knowledge.success": "成功添加 {{type}} 到知识库",
+ "tip": "如果响应成功,则只针对超过30秒的消息进行提醒"
},
"ollama": {
"keep_alive_time.description": "对话后模型在内存中保持的时间(默认:5 分钟)",
diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json
index af1b21fe23..21c937d2d5 100644
--- a/src/renderer/src/i18n/locales/zh-tw.json
+++ b/src/renderer/src/i18n/locales/zh-tw.json
@@ -906,7 +906,8 @@
"notification": {
"assistant": "助手回應",
"knowledge.error": "無法將 {{type}} 加入知識庫: {{error}}",
- "knowledge.success": "成功將 {{type}} 新增至知識庫"
+ "knowledge.success": "成功將 {{type}} 新增至知識庫",
+ "tip": "如果回應成功,則只針對超過30秒的訊息發出提醒"
},
"ollama": {
"keep_alive_time.description": "對話後模型在記憶體中保持的時間(預設為 5 分鐘)",
diff --git a/src/renderer/src/pages/settings/GeneralSettings.tsx b/src/renderer/src/pages/settings/GeneralSettings.tsx
index 9e47317a55..b9f55cc604 100644
--- a/src/renderer/src/pages/settings/GeneralSettings.tsx
+++ b/src/renderer/src/pages/settings/GeneralSettings.tsx
@@ -1,3 +1,4 @@
+import { InfoCircleOutlined } from '@ant-design/icons'
import Selector from '@renderer/components/Selector'
import { useTheme } from '@renderer/context/ThemeProvider'
import { useSettings } from '@renderer/hooks/useSettings'
@@ -16,7 +17,7 @@ import { LanguageVarious } from '@renderer/types'
import { NotificationSource } from '@renderer/types/notification'
import { isValidProxyUrl } from '@renderer/utils'
import { defaultLanguage } from '@shared/config/constant'
-import { Flex, Input, Switch } from 'antd'
+import { Flex, Input, Switch, Tooltip } from 'antd'
import { FC, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'
@@ -261,7 +262,12 @@ const GeneralSettings: FC = () => {
{t('settings.notification.title')}
- {t('settings.notification.assistant')}
+
+ {t('settings.notification.assistant')}
+
+
+
+
handleNotificationChange('assistant', v)} />
diff --git a/src/renderer/src/services/BackupService.ts b/src/renderer/src/services/BackupService.ts
index 9e594f85c2..74cd253679 100644
--- a/src/renderer/src/services/BackupService.ts
+++ b/src/renderer/src/services/BackupService.ts
@@ -94,7 +94,8 @@ export async function restore() {
message: i18n.t('message.restore.success'),
silent: false,
timestamp: Date.now(),
- source: 'backup'
+ source: 'backup',
+ channel: 'system'
})
} catch (error) {
Logger.error('[Backup] restore: Error restoring backup file:', error)
@@ -129,6 +130,8 @@ export async function reset() {
// 备份到 webdav
/**
+ * @param showMessage
+ * @param customFileName
* @param autoBackupProcess
* if call in auto backup process, not show any message, any error will be thrown
*/
@@ -189,7 +192,8 @@ export async function backupToWebdav({
message: i18n.t('message.backup.success'),
silent: false,
timestamp: Date.now(),
- source: 'backup'
+ source: 'backup',
+ channel: 'system'
})
showMessage && window.message.success({ content: i18n.t('message.backup.success'), key: 'backup' })
@@ -258,7 +262,8 @@ export async function backupToWebdav({
message: error.message,
silent: false,
timestamp: Date.now(),
- source: 'backup'
+ source: 'backup',
+ channel: 'system'
})
store.dispatch(setWebDAVSyncState({ lastSyncError: error.message }))
showMessage && window.message.error({ content: i18n.t('message.backup.failed'), key: 'backup' })
@@ -354,7 +359,8 @@ export async function backupToS3({
message: i18n.t('message.backup.success'),
silent: false,
timestamp: Date.now(),
- source: 'backup'
+ source: 'backup',
+ channel: 'system'
})
showMessage && window.message.success({ content: i18n.t('message.backup.success'), key: 'backup' })
@@ -407,7 +413,8 @@ export async function backupToS3({
message: error.message,
silent: false,
timestamp: Date.now(),
- source: 'backup'
+ source: 'backup',
+ channel: 'system'
})
store.dispatch(setS3SyncState({ lastSyncError: error.message }))
console.error('[Backup] backupToS3: Error uploading file to S3:', error)
@@ -935,7 +942,8 @@ export async function backupToLocal({
message: i18n.t('message.backup.success'),
silent: false,
timestamp: Date.now(),
- source: 'backup'
+ source: 'backup',
+ channel: 'system'
})
}
diff --git a/src/renderer/src/store/thunk/__tests__/streamCallback.integration.test.ts b/src/renderer/src/store/thunk/__tests__/streamCallback.integration.test.ts
index 15a86ce64d..da07cc3b34 100644
--- a/src/renderer/src/store/thunk/__tests__/streamCallback.integration.test.ts
+++ b/src/renderer/src/store/thunk/__tests__/streamCallback.integration.test.ts
@@ -142,7 +142,8 @@ vi.mock('@renderer/services/EventService', () => ({
}))
vi.mock('@renderer/utils/window', () => ({
- isOnHomePage: vi.fn(() => true)
+ isOnHomePage: vi.fn(() => true),
+ isFocused: vi.fn(() => true)
}))
vi.mock('@renderer/hooks/useTopic', () => ({
@@ -231,11 +232,10 @@ const reducer = combineReducers({
})
const createMockStore = () => {
- const store = configureStore({
+ return configureStore({
reducer: reducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: false })
})
- return store
}
// Helper function to simulate processing chunks through the stream processor
diff --git a/src/renderer/src/store/thunk/messageThunk.ts b/src/renderer/src/store/thunk/messageThunk.ts
index 5aba6499d9..7fe4b303e5 100644
--- a/src/renderer/src/store/thunk/messageThunk.ts
+++ b/src/renderer/src/store/thunk/messageThunk.ts
@@ -42,9 +42,8 @@ import {
resetAssistantMessage
} from '@renderer/utils/messageUtils/create'
import { findMainTextBlocks, getMainTextContent } from '@renderer/utils/messageUtils/find'
-import { getTopicQueue } from '@renderer/utils/queue'
-import { waitForTopicQueue } from '@renderer/utils/queue'
-import { isOnHomePage } from '@renderer/utils/window'
+import { getTopicQueue, waitForTopicQueue } from '@renderer/utils/queue'
+import { isFocused, isOnHomePage } from '@renderer/utils/window'
import { t } from 'i18next'
import { isEmpty, throttle } from 'lodash'
import { LRUCache } from 'lru-cache'
@@ -719,7 +718,8 @@ export const streamCallback = (
status: error.status || error.code,
requestId: error.request_id
}
- if (!isOnHomePage()) {
+ const msgDuration = Date.now() - startTime
+ if ((!isOnHomePage() && msgDuration > 30 * 1000) || (!isFocused() && msgDuration > 30 * 1000)) {
await notificationService.send({
id: uuid(),
type: 'error',
@@ -789,10 +789,9 @@ export const streamCallback = (
smartBlockUpdate(possibleBlockId, changes, lastBlockType!, true)
}
- const endTime = Date.now()
- const duration = endTime - startTime
const content = getMainTextContent(finalAssistantMsg)
- if (!isOnHomePage() && duration > 60 * 1000) {
+ const msgDuration = Date.now() - startTime
+ if ((!isOnHomePage() && msgDuration > 30 * 1000) || (!isFocused() && msgDuration > 30 * 1000)) {
await notificationService.send({
id: uuid(),
type: 'success',
@@ -800,7 +799,8 @@ export const streamCallback = (
message: content.length > 50 ? content.slice(0, 47) + '...' : content,
silent: false,
timestamp: Date.now(),
- source: 'assistant'
+ source: 'assistant',
+ channel: 'system'
})
}
@@ -813,8 +813,7 @@ export const streamCallback = (
response?.usage?.prompt_tokens === 0 ||
response?.usage?.completion_tokens === 0)
) {
- const usage = await estimateMessagesUsage({ assistant, messages: finalContextWithAssistant })
- response.usage = usage
+ response.usage = await estimateMessagesUsage({ assistant, messages: finalContextWithAssistant })
}
// dispatch(newMessagesActions.setTopicLoading({ topicId, loading: false }))
}