@lobehub/chat 1.103.2 → 1.104.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules/code-review.mdc +2 -0
- package/.cursor/rules/typescript.mdc +3 -1
- package/CHANGELOG.md +50 -0
- package/apps/desktop/src/main/controllers/BrowserWindowsCtr.ts +1 -1
- package/apps/desktop/src/main/controllers/ShortcutCtr.ts +9 -1
- package/apps/desktop/src/main/controllers/TrayMenuCtr.ts +1 -5
- package/apps/desktop/src/main/controllers/__tests__/ShortcutCtr.test.ts +14 -11
- package/apps/desktop/src/main/core/ui/ShortcutManager.ts +71 -5
- package/apps/desktop/src/main/shortcuts/config.ts +4 -2
- package/changelog/v1.json +18 -0
- package/locales/ar/hotkey.json +10 -4
- package/locales/ar/setting.json +12 -1
- package/locales/bg-BG/hotkey.json +10 -4
- package/locales/bg-BG/setting.json +12 -1
- package/locales/de-DE/hotkey.json +10 -4
- package/locales/de-DE/setting.json +12 -1
- package/locales/en-US/hotkey.json +10 -4
- package/locales/en-US/setting.json +12 -1
- package/locales/es-ES/hotkey.json +10 -4
- package/locales/es-ES/setting.json +12 -1
- package/locales/fa-IR/hotkey.json +10 -4
- package/locales/fa-IR/setting.json +12 -1
- package/locales/fr-FR/hotkey.json +10 -4
- package/locales/fr-FR/setting.json +12 -1
- package/locales/it-IT/hotkey.json +10 -4
- package/locales/it-IT/setting.json +12 -1
- package/locales/ja-JP/hotkey.json +10 -4
- package/locales/ja-JP/setting.json +12 -1
- package/locales/ko-KR/hotkey.json +10 -4
- package/locales/ko-KR/setting.json +12 -1
- package/locales/nl-NL/hotkey.json +10 -4
- package/locales/nl-NL/setting.json +12 -1
- package/locales/pl-PL/hotkey.json +10 -4
- package/locales/pl-PL/setting.json +12 -1
- package/locales/pt-BR/hotkey.json +10 -4
- package/locales/pt-BR/setting.json +12 -1
- package/locales/ru-RU/hotkey.json +10 -4
- package/locales/ru-RU/setting.json +12 -1
- package/locales/tr-TR/hotkey.json +10 -4
- package/locales/tr-TR/setting.json +12 -1
- package/locales/vi-VN/hotkey.json +10 -4
- package/locales/vi-VN/setting.json +12 -1
- package/locales/zh-CN/hotkey.json +10 -4
- package/locales/zh-CN/setting.json +12 -1
- package/locales/zh-TW/hotkey.json +10 -4
- package/locales/zh-TW/setting.json +12 -1
- package/package.json +1 -1
- package/packages/electron-client-ipc/src/events/shortcut.ts +3 -1
- package/packages/electron-client-ipc/src/types/shortcut.ts +11 -0
- package/src/app/[variants]/(main)/image/features/GenerationFeed/BatchItem.tsx +6 -1
- package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/ErrorState.tsx +3 -2
- package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/LoadingState.tsx +27 -24
- package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/SuccessState.tsx +14 -3
- package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/index.tsx +4 -7
- package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/types.ts +3 -0
- package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/utils.test.ts +600 -0
- package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/utils.ts +126 -7
- package/src/app/[variants]/(main)/settings/hotkey/features/Conversation.tsx +3 -11
- package/src/app/[variants]/(main)/settings/hotkey/features/Desktop.tsx +92 -0
- package/src/app/[variants]/(main)/settings/hotkey/features/Essential.tsx +3 -11
- package/src/app/[variants]/(main)/settings/hotkey/page.tsx +3 -0
- package/src/const/desktop.ts +9 -0
- package/src/const/hotkeys.ts +20 -16
- package/src/const/imageGeneration.ts +18 -0
- package/src/features/User/UserPanel/useMenu.tsx +2 -2
- package/src/libs/model-runtime/utils/openaiCompatibleFactory/index.test.ts +3 -0
- package/src/libs/model-runtime/utils/openaiCompatibleFactory/index.ts +7 -5
- package/src/libs/model-runtime/utils/streams/openai/openai.ts +8 -4
- package/src/libs/model-runtime/utils/usageConverter.test.ts +45 -1
- package/src/libs/model-runtime/utils/usageConverter.ts +6 -2
- package/src/locales/default/hotkey.ts +13 -5
- package/src/locales/default/setting.ts +11 -0
- package/src/server/services/generation/index.test.ts +848 -0
- package/src/server/services/generation/index.ts +90 -69
- package/src/services/electron/settings.ts +19 -1
- package/src/store/electron/actions/settings.ts +42 -1
- package/src/store/electron/initialState.ts +9 -1
- package/src/store/electron/selectors/__tests__/desktopState.test.ts +6 -17
- package/src/store/electron/selectors/hotkey.ts +11 -0
- package/src/store/electron/selectors/index.ts +1 -0
- package/src/types/hotkey.ts +18 -4
- package/src/utils/number.test.ts +101 -1
- package/src/utils/number.ts +42 -0
@@ -45,14 +45,25 @@
|
|
45
45
|
},
|
46
46
|
"hotkey": {
|
47
47
|
"conflicts": "与现有快捷键冲突",
|
48
|
+
"errors": {
|
49
|
+
"CONFLICT": "快捷键冲突:该快捷键已被其他功能占用",
|
50
|
+
"INVALID_FORMAT": "快捷键格式无效:请使用正确的格式(如 CommandOrControl+E)",
|
51
|
+
"INVALID_ID": "无效的快捷键ID",
|
52
|
+
"NO_MODIFIER": "快捷键必须包含修饰键(Ctrl、Alt、Shift等)",
|
53
|
+
"SYSTEM_OCCUPIED": "快捷键已被系统或其他应用程序占用",
|
54
|
+
"UNKNOWN": "更新失败:未知错误"
|
55
|
+
},
|
48
56
|
"group": {
|
49
57
|
"conversation": "会话",
|
58
|
+
"desktop": "桌面端",
|
50
59
|
"essential": "基础"
|
51
60
|
},
|
52
61
|
"invalidCombination": "快捷键需要至少包含一个修饰键 (Ctrl, Alt, Shift) 和一个常规键",
|
53
62
|
"record": "按下按键以录制快捷键",
|
54
63
|
"reset": "重置为默认快捷键",
|
55
|
-
"title": "快捷键"
|
64
|
+
"title": "快捷键",
|
65
|
+
"updateError": "快捷键更新失败:网络或系统错误",
|
66
|
+
"updateSuccess": "快捷键更新成功"
|
56
67
|
},
|
57
68
|
"llm": {
|
58
69
|
"aesGcm": "您的秘钥与代理地址等将使用 <1>AES-GCM</1> 加密算法进行加密",
|
@@ -7,6 +7,16 @@
|
|
7
7
|
"desc": "清空當前會話的消息和上傳的檔案",
|
8
8
|
"title": "清空會話消息"
|
9
9
|
},
|
10
|
+
"desktop": {
|
11
|
+
"openSettings": {
|
12
|
+
"desc": "打開應用設定頁面",
|
13
|
+
"title": "應用設定"
|
14
|
+
},
|
15
|
+
"showApp": {
|
16
|
+
"desc": "全域快速鍵顯示或隱藏主視窗",
|
17
|
+
"title": "顯示/隱藏主視窗"
|
18
|
+
}
|
19
|
+
},
|
10
20
|
"editMessage": {
|
11
21
|
"desc": "通過按住 Alt 並雙擊消息進入編輯模式",
|
12
22
|
"title": "編輯消息"
|
@@ -19,10 +29,6 @@
|
|
19
29
|
"desc": "查看所有快捷鍵的使用說明",
|
20
30
|
"title": "打開快捷鍵幫助"
|
21
31
|
},
|
22
|
-
"openSettings": {
|
23
|
-
"desc": "打開應用設定頁面",
|
24
|
-
"title": "應用設定"
|
25
|
-
},
|
26
32
|
"regenerateMessage": {
|
27
33
|
"desc": "重新生成最後一條消息",
|
28
34
|
"title": "重新生成消息"
|
@@ -45,14 +45,25 @@
|
|
45
45
|
},
|
46
46
|
"hotkey": {
|
47
47
|
"conflicts": "與現有快捷鍵衝突",
|
48
|
+
"errors": {
|
49
|
+
"CONFLICT": "快速鍵衝突:該快速鍵已被其他功能佔用",
|
50
|
+
"INVALID_FORMAT": "快速鍵格式無效:請使用正確的格式(如 CommandOrControl+E)",
|
51
|
+
"INVALID_ID": "無效的快速鍵ID",
|
52
|
+
"NO_MODIFIER": "快速鍵必須包含修飾鍵(Ctrl、Alt、Shift等)",
|
53
|
+
"SYSTEM_OCCUPIED": "快速鍵已被系統或其他應用程式佔用",
|
54
|
+
"UNKNOWN": "更新失敗:未知錯誤"
|
55
|
+
},
|
48
56
|
"group": {
|
49
57
|
"conversation": "對話",
|
58
|
+
"desktop": "桌面端",
|
50
59
|
"essential": "基本"
|
51
60
|
},
|
52
61
|
"invalidCombination": "快捷鍵需要至少包含一個修飾鍵 (Ctrl, Alt, Shift) 和一個常規鍵",
|
53
62
|
"record": "按下按鍵以錄製快捷鍵",
|
54
63
|
"reset": "重置為預設快捷鍵",
|
55
|
-
"title": "快速鍵"
|
64
|
+
"title": "快速鍵",
|
65
|
+
"updateError": "快速鍵更新失敗:網路或系統錯誤",
|
66
|
+
"updateSuccess": "快速鍵更新成功"
|
56
67
|
},
|
57
68
|
"llm": {
|
58
69
|
"aesGcm": "您的金鑰與代理地址等將使用 <1>AES-GCM</1> 加密演算法進行加密",
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@lobehub/chat",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.104.1",
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
5
5
|
"keywords": [
|
6
6
|
"framework",
|
@@ -1,4 +1,6 @@
|
|
1
|
+
import { ShortcutUpdateResult } from '../types';
|
2
|
+
|
1
3
|
export interface ShortcutDispatchEvents {
|
2
4
|
getShortcutsConfig: () => Record<string, string>;
|
3
|
-
updateShortcutConfig: (
|
5
|
+
updateShortcutConfig: (params: { accelerator: string; id: string }) => ShortcutUpdateResult;
|
4
6
|
}
|
@@ -9,3 +9,14 @@ export interface ShortcutConfig {
|
|
9
9
|
id: string;
|
10
10
|
}
|
11
11
|
export type ShortcutActionType = Record<string, any>;
|
12
|
+
|
13
|
+
export interface ShortcutUpdateResult {
|
14
|
+
errorType?:
|
15
|
+
| 'INVALID_ID'
|
16
|
+
| 'INVALID_FORMAT'
|
17
|
+
| 'NO_MODIFIER'
|
18
|
+
| 'CONFLICT'
|
19
|
+
| 'SYSTEM_OCCUPIED'
|
20
|
+
| 'UNKNOWN';
|
21
|
+
success: boolean;
|
22
|
+
}
|
@@ -20,6 +20,7 @@ import { AsyncTaskErrorType } from '@/types/asyncTask';
|
|
20
20
|
import { GenerationBatch } from '@/types/generation';
|
21
21
|
|
22
22
|
import { GenerationItem } from './GenerationItem';
|
23
|
+
import { DEFAULT_MAX_ITEM_WIDTH } from './GenerationItem/utils';
|
23
24
|
import { ReferenceImages } from './ReferenceImages';
|
24
25
|
|
25
26
|
const useStyles = createStyles(({ cx, css, token }) => ({
|
@@ -182,7 +183,11 @@ export const GenerationBatchItem = memo<GenerationBatchItemProps>(({ batch }) =>
|
|
182
183
|
{promptAndMetadata}
|
183
184
|
</>
|
184
185
|
)}
|
185
|
-
<Grid
|
186
|
+
<Grid
|
187
|
+
maxItemWidth={DEFAULT_MAX_ITEM_WIDTH}
|
188
|
+
ref={imageGridRef}
|
189
|
+
rows={batch.generations.length}
|
190
|
+
>
|
186
191
|
{batch.generations.map((generation) => (
|
187
192
|
<GenerationItem
|
188
193
|
generation={generation}
|
package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/ErrorState.tsx
CHANGED
@@ -9,10 +9,11 @@ import { Center } from 'react-layout-kit';
|
|
9
9
|
import { ActionButtons } from './ActionButtons';
|
10
10
|
import { useStyles } from './styles';
|
11
11
|
import { ErrorStateProps } from './types';
|
12
|
+
import { getThumbnailMaxWidth } from './utils';
|
12
13
|
|
13
14
|
// 错误状态组件
|
14
15
|
export const ErrorState = memo<ErrorStateProps>(
|
15
|
-
({ generation, aspectRatio, onDelete, onCopyError }) => {
|
16
|
+
({ generation, generationBatch, aspectRatio, onDelete, onCopyError }) => {
|
16
17
|
const { styles, theme } = useStyles();
|
17
18
|
const { t } = useTranslation('image');
|
18
19
|
|
@@ -32,7 +33,7 @@ export const ErrorState = memo<ErrorStateProps>(
|
|
32
33
|
style={{
|
33
34
|
aspectRatio,
|
34
35
|
cursor: 'pointer',
|
35
|
-
maxWidth: generation
|
36
|
+
maxWidth: getThumbnailMaxWidth(generation, generationBatch),
|
36
37
|
}}
|
37
38
|
variant={'filled'}
|
38
39
|
>
|
package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/LoadingState.tsx
CHANGED
@@ -12,33 +12,36 @@ import { ActionButtons } from './ActionButtons';
|
|
12
12
|
import { ElapsedTime } from './ElapsedTime';
|
13
13
|
import { useStyles } from './styles';
|
14
14
|
import { LoadingStateProps } from './types';
|
15
|
+
import { getThumbnailMaxWidth } from './utils';
|
15
16
|
|
16
17
|
// 加载状态组件
|
17
|
-
export const LoadingState = memo<LoadingStateProps>(
|
18
|
-
|
18
|
+
export const LoadingState = memo<LoadingStateProps>(
|
19
|
+
({ generation, generationBatch, aspectRatio, onDelete }) => {
|
20
|
+
const { styles } = useStyles();
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
const isGenerating =
|
23
|
+
generation.task.status === AsyncTaskStatus.Processing ||
|
24
|
+
generation.task.status === AsyncTaskStatus.Pending;
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
}
|
26
|
+
return (
|
27
|
+
<Block
|
28
|
+
align={'center'}
|
29
|
+
className={styles.placeholderContainer}
|
30
|
+
justify={'center'}
|
31
|
+
style={{
|
32
|
+
aspectRatio,
|
33
|
+
maxWidth: getThumbnailMaxWidth(generation, generationBatch),
|
34
|
+
}}
|
35
|
+
variant={'filled'}
|
36
|
+
>
|
37
|
+
<Center gap={8}>
|
38
|
+
<Spin indicator={<LoadingOutlined spin />} />
|
39
|
+
<ElapsedTime generationId={generation.id} isActive={isGenerating} />
|
40
|
+
</Center>
|
41
|
+
<ActionButtons onDelete={onDelete} />
|
42
|
+
</Block>
|
43
|
+
);
|
44
|
+
},
|
45
|
+
);
|
43
46
|
|
44
47
|
LoadingState.displayName = 'LoadingState';
|
package/src/app/[variants]/(main)/image/features/GenerationFeed/GenerationItem/SuccessState.tsx
CHANGED
@@ -8,10 +8,20 @@ import ImageItem from '@/components/ImageItem';
|
|
8
8
|
import { ActionButtons } from './ActionButtons';
|
9
9
|
import { useStyles } from './styles';
|
10
10
|
import { SuccessStateProps } from './types';
|
11
|
+
import { getThumbnailMaxWidth } from './utils';
|
11
12
|
|
12
13
|
// 成功状态组件
|
13
14
|
export const SuccessState = memo<SuccessStateProps>(
|
14
|
-
({
|
15
|
+
({
|
16
|
+
generation,
|
17
|
+
generationBatch,
|
18
|
+
prompt,
|
19
|
+
aspectRatio,
|
20
|
+
onDelete,
|
21
|
+
onDownload,
|
22
|
+
onCopySeed,
|
23
|
+
seedTooltip,
|
24
|
+
}) => {
|
15
25
|
const { styles } = useStyles();
|
16
26
|
|
17
27
|
return (
|
@@ -21,7 +31,7 @@ export const SuccessState = memo<SuccessStateProps>(
|
|
21
31
|
justify={'center'}
|
22
32
|
style={{
|
23
33
|
aspectRatio,
|
24
|
-
maxWidth: generation
|
34
|
+
maxWidth: getThumbnailMaxWidth(generation, generationBatch),
|
25
35
|
}}
|
26
36
|
variant={'filled'}
|
27
37
|
>
|
@@ -31,7 +41,8 @@ export const SuccessState = memo<SuccessStateProps>(
|
|
31
41
|
src: generation.asset!.url,
|
32
42
|
}}
|
33
43
|
style={{ height: '100%', width: '100%' }}
|
34
|
-
|
44
|
+
// Thumbnail quality is too bad
|
45
|
+
url={generation.asset!.url}
|
35
46
|
/>
|
36
47
|
<ActionButtons
|
37
48
|
onCopySeed={onCopySeed}
|
@@ -37,13 +37,7 @@ export const GenerationItem = memo<GenerationItemProps>(
|
|
37
37
|
const shouldPoll = !isFinalized;
|
38
38
|
useCheckGenerationStatus(generation.id, generation.task.id, activeTopicId!, shouldPoll);
|
39
39
|
|
40
|
-
const aspectRatio = getAspectRatio(
|
41
|
-
generation.asset ?? {
|
42
|
-
height: generationBatch.config?.height,
|
43
|
-
type: 'image',
|
44
|
-
width: generationBatch.config?.width,
|
45
|
-
},
|
46
|
-
);
|
40
|
+
const aspectRatio = getAspectRatio(generation, generationBatch);
|
47
41
|
|
48
42
|
// 事件处理函数
|
49
43
|
const handleDeleteGeneration = async () => {
|
@@ -120,6 +114,7 @@ export const GenerationItem = memo<GenerationItemProps>(
|
|
120
114
|
<SuccessState
|
121
115
|
aspectRatio={aspectRatio}
|
122
116
|
generation={generation}
|
117
|
+
generationBatch={generationBatch}
|
123
118
|
onCopySeed={handleCopySeed}
|
124
119
|
onDelete={handleDeleteGeneration}
|
125
120
|
onDownload={handleDownloadImage}
|
@@ -134,6 +129,7 @@ export const GenerationItem = memo<GenerationItemProps>(
|
|
134
129
|
<ErrorState
|
135
130
|
aspectRatio={aspectRatio}
|
136
131
|
generation={generation}
|
132
|
+
generationBatch={generationBatch}
|
137
133
|
onCopyError={handleCopyError}
|
138
134
|
onDelete={handleDeleteGeneration}
|
139
135
|
/>
|
@@ -145,6 +141,7 @@ export const GenerationItem = memo<GenerationItemProps>(
|
|
145
141
|
<LoadingState
|
146
142
|
aspectRatio={aspectRatio}
|
147
143
|
generation={generation}
|
144
|
+
generationBatch={generationBatch}
|
148
145
|
onDelete={handleDeleteGeneration}
|
149
146
|
/>
|
150
147
|
);
|
@@ -18,6 +18,7 @@ export interface ActionButtonsProps {
|
|
18
18
|
export interface SuccessStateProps {
|
19
19
|
aspectRatio: string;
|
20
20
|
generation: Generation;
|
21
|
+
generationBatch: GenerationBatch;
|
21
22
|
onCopySeed?: () => void;
|
22
23
|
onDelete: () => void;
|
23
24
|
onDownload: () => void;
|
@@ -28,6 +29,7 @@ export interface SuccessStateProps {
|
|
28
29
|
export interface ErrorStateProps {
|
29
30
|
aspectRatio: string;
|
30
31
|
generation: Generation;
|
32
|
+
generationBatch: GenerationBatch;
|
31
33
|
onCopyError: () => void;
|
32
34
|
onDelete: () => void;
|
33
35
|
}
|
@@ -35,5 +37,6 @@ export interface ErrorStateProps {
|
|
35
37
|
export interface LoadingStateProps {
|
36
38
|
aspectRatio: string;
|
37
39
|
generation: Generation;
|
40
|
+
generationBatch: GenerationBatch;
|
38
41
|
onDelete: () => void;
|
39
42
|
}
|