@lobehub/chat 1.81.2 → 1.81.4
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/CHANGELOG.md +59 -0
- package/changelog/v1.json +21 -0
- package/locales/ar/common.json +2 -0
- package/locales/ar/electron.json +32 -0
- package/locales/ar/models.json +126 -3
- package/locales/ar/plugin.json +1 -0
- package/locales/ar/tool.json +25 -0
- package/locales/bg-BG/common.json +2 -0
- package/locales/bg-BG/electron.json +32 -0
- package/locales/bg-BG/models.json +126 -3
- package/locales/bg-BG/plugin.json +1 -0
- package/locales/bg-BG/tool.json +25 -0
- package/locales/de-DE/common.json +2 -0
- package/locales/de-DE/electron.json +32 -0
- package/locales/de-DE/models.json +126 -3
- package/locales/de-DE/plugin.json +1 -0
- package/locales/de-DE/tool.json +25 -0
- package/locales/en-US/common.json +2 -0
- package/locales/en-US/electron.json +32 -0
- package/locales/en-US/models.json +126 -3
- package/locales/en-US/plugin.json +1 -0
- package/locales/en-US/tool.json +25 -0
- package/locales/es-ES/common.json +2 -0
- package/locales/es-ES/electron.json +32 -0
- package/locales/es-ES/models.json +126 -3
- package/locales/es-ES/plugin.json +1 -0
- package/locales/es-ES/tool.json +25 -0
- package/locales/fa-IR/common.json +2 -0
- package/locales/fa-IR/electron.json +32 -0
- package/locales/fa-IR/models.json +126 -3
- package/locales/fa-IR/plugin.json +1 -0
- package/locales/fa-IR/tool.json +25 -0
- package/locales/fr-FR/common.json +2 -0
- package/locales/fr-FR/electron.json +32 -0
- package/locales/fr-FR/models.json +126 -3
- package/locales/fr-FR/plugin.json +1 -0
- package/locales/fr-FR/tool.json +25 -0
- package/locales/it-IT/common.json +2 -0
- package/locales/it-IT/electron.json +32 -0
- package/locales/it-IT/models.json +126 -3
- package/locales/it-IT/plugin.json +1 -0
- package/locales/it-IT/tool.json +25 -0
- package/locales/ja-JP/common.json +2 -0
- package/locales/ja-JP/electron.json +32 -0
- package/locales/ja-JP/models.json +126 -3
- package/locales/ja-JP/plugin.json +1 -0
- package/locales/ja-JP/tool.json +25 -0
- package/locales/ko-KR/common.json +2 -0
- package/locales/ko-KR/electron.json +32 -0
- package/locales/ko-KR/models.json +126 -3
- package/locales/ko-KR/plugin.json +1 -0
- package/locales/ko-KR/tool.json +25 -0
- package/locales/nl-NL/common.json +2 -0
- package/locales/nl-NL/electron.json +32 -0
- package/locales/nl-NL/models.json +126 -3
- package/locales/nl-NL/plugin.json +1 -0
- package/locales/nl-NL/tool.json +25 -0
- package/locales/pl-PL/common.json +2 -0
- package/locales/pl-PL/electron.json +32 -0
- package/locales/pl-PL/models.json +126 -3
- package/locales/pl-PL/plugin.json +1 -0
- package/locales/pl-PL/tool.json +25 -0
- package/locales/pt-BR/common.json +2 -0
- package/locales/pt-BR/electron.json +32 -0
- package/locales/pt-BR/models.json +126 -3
- package/locales/pt-BR/plugin.json +1 -0
- package/locales/pt-BR/tool.json +25 -0
- package/locales/ru-RU/common.json +2 -0
- package/locales/ru-RU/electron.json +32 -0
- package/locales/ru-RU/models.json +126 -3
- package/locales/ru-RU/plugin.json +1 -0
- package/locales/ru-RU/tool.json +25 -0
- package/locales/tr-TR/common.json +2 -0
- package/locales/tr-TR/electron.json +32 -0
- package/locales/tr-TR/models.json +126 -3
- package/locales/tr-TR/plugin.json +1 -0
- package/locales/tr-TR/tool.json +25 -0
- package/locales/vi-VN/common.json +2 -0
- package/locales/vi-VN/electron.json +32 -0
- package/locales/vi-VN/models.json +126 -3
- package/locales/vi-VN/plugin.json +1 -0
- package/locales/vi-VN/tool.json +25 -0
- package/locales/zh-CN/common.json +2 -0
- package/locales/zh-CN/electron.json +32 -0
- package/locales/zh-CN/models.json +131 -8
- package/locales/zh-CN/plugin.json +1 -0
- package/locales/zh-CN/tool.json +25 -0
- package/locales/zh-TW/common.json +2 -0
- package/locales/zh-TW/electron.json +32 -0
- package/locales/zh-TW/models.json +126 -3
- package/locales/zh-TW/plugin.json +1 -0
- package/locales/zh-TW/tool.json +25 -0
- package/package.json +3 -2
- package/packages/electron-client-ipc/src/events/index.ts +5 -5
- package/packages/electron-client-ipc/src/events/localFile.ts +22 -0
- package/packages/electron-client-ipc/src/events/{file.ts → upload.ts} +1 -1
- package/packages/electron-client-ipc/src/types/index.ts +2 -1
- package/packages/electron-client-ipc/src/types/localFile.ts +52 -0
- package/scripts/prebuild.mts +5 -1
- package/src/app/(backend)/trpc/desktop/[trpc]/route.ts +26 -0
- package/src/config/aiModels/cloudflare.ts +41 -37
- package/src/config/aiModels/github.ts +90 -0
- package/src/config/aiModels/google.ts +25 -0
- package/src/features/Conversation/Messages/Assistant/Tool/Render/Arguments/ObjectEntity.tsx +81 -0
- package/src/features/Conversation/Messages/Assistant/Tool/Render/Arguments/ValueCell.tsx +43 -0
- package/src/features/Conversation/Messages/Assistant/Tool/Render/Arguments/index.tsx +120 -0
- package/src/features/Conversation/Messages/Assistant/Tool/Render/CustomRender.tsx +75 -2
- package/src/features/Conversation/Messages/Assistant/Tool/Render/KeyValueEditor.tsx +214 -0
- package/src/features/User/UserPanel/useMenu.tsx +8 -1
- package/src/libs/agent-runtime/google/index.ts +3 -0
- package/src/libs/trpc/client/desktop.ts +14 -0
- package/src/locales/default/common.ts +2 -0
- package/src/locales/default/electron.ts +34 -0
- package/src/locales/default/index.ts +2 -0
- package/src/locales/default/tool.ts +25 -0
- package/src/server/routers/desktop/index.ts +9 -0
- package/src/server/routers/desktop/pgTable.ts +43 -0
- package/src/services/electron/autoUpdate.ts +17 -0
- package/src/services/electron/file.ts +31 -0
- package/src/services/electron/localFileService.ts +39 -0
- package/src/services/electron/remoteServer.ts +40 -0
- package/src/store/chat/index.ts +1 -1
- package/src/store/chat/slices/builtinTool/actions/index.ts +3 -1
- package/src/store/chat/slices/builtinTool/actions/localFile.ts +129 -0
- package/src/store/chat/slices/builtinTool/initialState.ts +2 -0
- package/src/store/chat/slices/builtinTool/selectors.ts +2 -0
- package/src/store/chat/slices/plugin/action.ts +3 -3
- package/src/store/chat/store.ts +2 -0
- package/src/store/electron/actions/sync.ts +117 -0
- package/src/store/electron/index.ts +1 -0
- package/src/store/electron/initialState.ts +18 -0
- package/src/store/electron/selectors/index.ts +1 -0
- package/src/store/electron/selectors/sync.ts +9 -0
- package/src/store/electron/store.ts +29 -0
- package/src/tools/index.ts +8 -0
- package/src/tools/local-files/Render/ListFiles/Result.tsx +42 -0
- package/src/tools/local-files/Render/ListFiles/index.tsx +68 -0
- package/src/tools/local-files/Render/ReadLocalFile/ReadFileSkeleton.tsx +50 -0
- package/src/tools/local-files/Render/ReadLocalFile/ReadFileView.tsx +197 -0
- package/src/tools/local-files/Render/ReadLocalFile/index.tsx +31 -0
- package/src/tools/local-files/Render/ReadLocalFile/style.ts +37 -0
- package/src/tools/local-files/Render/SearchFiles/Result.tsx +42 -0
- package/src/tools/local-files/Render/SearchFiles/SearchQuery/SearchView.tsx +77 -0
- package/src/tools/local-files/Render/SearchFiles/SearchQuery/index.tsx +72 -0
- package/src/tools/local-files/Render/SearchFiles/index.tsx +32 -0
- package/src/tools/local-files/Render/index.tsx +36 -0
- package/src/tools/local-files/components/FileItem.tsx +117 -0
- package/src/tools/local-files/index.ts +149 -0
- package/src/tools/local-files/systemRole.ts +46 -0
- package/src/tools/local-files/type.ts +33 -0
- package/src/tools/renders.ts +3 -0
- package/packages/electron-client-ipc/src/events/search.ts +0 -4
- package/src/features/Conversation/Messages/Assistant/Tool/Render/Arguments.tsx +0 -165
- /package/packages/electron-client-ipc/src/types/{file.ts → upload.ts} +0 -0
@@ -0,0 +1,214 @@
|
|
1
|
+
import { ActionIcon, Icon } from '@lobehub/ui';
|
2
|
+
import { App, Button, Form, FormInstance, Input } from 'antd';
|
3
|
+
import { createStyles } from 'antd-style';
|
4
|
+
import { LucidePlus, LucideTrash } from 'lucide-react';
|
5
|
+
import { memo, useEffect, useRef, useState } from 'react';
|
6
|
+
import { useTranslation } from 'react-i18next';
|
7
|
+
import { Flexbox } from 'react-layout-kit';
|
8
|
+
|
9
|
+
const useStyles = createStyles(({ css, token }) => ({
|
10
|
+
form: css`
|
11
|
+
position: relative;
|
12
|
+
|
13
|
+
width: 100%;
|
14
|
+
min-width: 600px;
|
15
|
+
padding-block: 8px;
|
16
|
+
padding-inline: 12px;
|
17
|
+
border: 1px solid ${token.colorBorder};
|
18
|
+
border-radius: ${token.borderRadiusLG}px;
|
19
|
+
`,
|
20
|
+
formItem: css`
|
21
|
+
margin-block-end: 4px !important;
|
22
|
+
`,
|
23
|
+
input: css`
|
24
|
+
font-family: ${token.fontFamilyCode};
|
25
|
+
font-size: 12px;
|
26
|
+
`,
|
27
|
+
row: css`
|
28
|
+
position: relative;
|
29
|
+
`,
|
30
|
+
title: css`
|
31
|
+
color: ${token.colorTextTertiary};
|
32
|
+
`,
|
33
|
+
}));
|
34
|
+
|
35
|
+
interface KeyValueItem {
|
36
|
+
id: string;
|
37
|
+
key?: string;
|
38
|
+
value?: string;
|
39
|
+
}
|
40
|
+
|
41
|
+
interface KeyValueEditorProps {
|
42
|
+
initialValue?: Record<string, any>;
|
43
|
+
onCancel?: () => void;
|
44
|
+
onFinish?: (value: Record<string, any>) => Promise<void>;
|
45
|
+
}
|
46
|
+
|
47
|
+
const recordToFormList = (record: Record<string, any>): KeyValueItem[] =>
|
48
|
+
Object.entries(record)
|
49
|
+
.map(([key, val], index) => ({
|
50
|
+
id: `${key}-${index}`,
|
51
|
+
key,
|
52
|
+
value: typeof val === 'string' ? val : JSON.stringify(val),
|
53
|
+
}))
|
54
|
+
.filter((item) => item.key);
|
55
|
+
|
56
|
+
const formListToRecord = (list: KeyValueItem[]): Record<string, any> => {
|
57
|
+
const record: Record<string, any> = {};
|
58
|
+
list.forEach((item) => {
|
59
|
+
if (item.key) {
|
60
|
+
try {
|
61
|
+
record[item.key] = JSON.parse(item.value || '""');
|
62
|
+
} catch {
|
63
|
+
record[item.key] = item.value || '';
|
64
|
+
}
|
65
|
+
}
|
66
|
+
});
|
67
|
+
return record;
|
68
|
+
};
|
69
|
+
|
70
|
+
const KeyValueEditor = memo<KeyValueEditorProps>(({ initialValue = {}, onFinish, onCancel }) => {
|
71
|
+
const { styles } = useStyles();
|
72
|
+
const { t } = useTranslation(['tool', 'common']);
|
73
|
+
const [form] = Form.useForm();
|
74
|
+
const { message } = App.useApp();
|
75
|
+
const formRef = useRef<FormInstance>(null);
|
76
|
+
|
77
|
+
useEffect(() => {
|
78
|
+
form.setFieldsValue({ items: recordToFormList(initialValue) });
|
79
|
+
}, [initialValue, form]);
|
80
|
+
|
81
|
+
const [updating, setUpdating] = useState(false);
|
82
|
+
const handleFinish = async () => {
|
83
|
+
setUpdating(true);
|
84
|
+
try {
|
85
|
+
await form.validateFields();
|
86
|
+
const values = form.getFieldsValue();
|
87
|
+
const record = formListToRecord(values.items || []);
|
88
|
+
await onFinish?.(record);
|
89
|
+
} catch (errorInfo) {
|
90
|
+
console.error('Validation Failed:', errorInfo);
|
91
|
+
message.error(t('updateArgs.formValidationFailed') || 'Please check the form for errors.');
|
92
|
+
}
|
93
|
+
setUpdating(false);
|
94
|
+
};
|
95
|
+
|
96
|
+
const handleCancel = () => {
|
97
|
+
onCancel?.();
|
98
|
+
};
|
99
|
+
|
100
|
+
const validateKeys = (_: any, item: KeyValueItem, items: KeyValueItem[]) => {
|
101
|
+
if (!item?.key) {
|
102
|
+
return Promise.resolve();
|
103
|
+
}
|
104
|
+
const keys = items.map((i) => i?.key).filter(Boolean);
|
105
|
+
if (keys.filter((k) => k === item.key).length > 1) {
|
106
|
+
return Promise.reject(new Error(t('updateArgs.duplicateKeyError')));
|
107
|
+
}
|
108
|
+
|
109
|
+
return Promise.resolve();
|
110
|
+
};
|
111
|
+
|
112
|
+
return (
|
113
|
+
<Form
|
114
|
+
autoComplete="off"
|
115
|
+
className={styles.form}
|
116
|
+
form={form}
|
117
|
+
initialValues={{ items: recordToFormList(initialValue) }}
|
118
|
+
ref={formRef}
|
119
|
+
>
|
120
|
+
<Flexbox className={styles.title} gap={8} horizontal>
|
121
|
+
<Flexbox flex={1}>key</Flexbox>
|
122
|
+
<Flexbox flex={4}>value</Flexbox>
|
123
|
+
</Flexbox>
|
124
|
+
<Form.List name="items">
|
125
|
+
{(fields, { add, remove }) => (
|
126
|
+
<Flexbox width={'100%'}>
|
127
|
+
{fields.map(({ key, name, ...restField }, index) => (
|
128
|
+
<Flexbox
|
129
|
+
align="center"
|
130
|
+
className={styles.row}
|
131
|
+
gap={8}
|
132
|
+
horizontal
|
133
|
+
key={key}
|
134
|
+
width={'100%'}
|
135
|
+
>
|
136
|
+
<Form.Item
|
137
|
+
{...restField}
|
138
|
+
className={styles.formItem}
|
139
|
+
name={[name, 'key']}
|
140
|
+
rules={[
|
141
|
+
{ message: t('updateArgs.keyRequired'), required: true },
|
142
|
+
{
|
143
|
+
validator: (rule) =>
|
144
|
+
validateKeys(
|
145
|
+
rule,
|
146
|
+
form.getFieldValue(['items', index]),
|
147
|
+
form.getFieldValue('items'),
|
148
|
+
),
|
149
|
+
},
|
150
|
+
]}
|
151
|
+
style={{ flex: 1 }}
|
152
|
+
validateTrigger={['onChange', 'onBlur']}
|
153
|
+
>
|
154
|
+
<Input
|
155
|
+
allowClear
|
156
|
+
className={styles.input}
|
157
|
+
placeholder={t('updateArgs.form.key')}
|
158
|
+
variant={'filled'}
|
159
|
+
/>
|
160
|
+
</Form.Item>
|
161
|
+
<Form.Item
|
162
|
+
{...restField}
|
163
|
+
className={styles.formItem}
|
164
|
+
name={[name, 'value']}
|
165
|
+
style={{ flex: 4 }}
|
166
|
+
>
|
167
|
+
<Input
|
168
|
+
allowClear
|
169
|
+
className={styles.input}
|
170
|
+
placeholder={t('updateArgs.form.value')}
|
171
|
+
variant={'filled'}
|
172
|
+
/>
|
173
|
+
</Form.Item>
|
174
|
+
<ActionIcon
|
175
|
+
icon={LucideTrash}
|
176
|
+
onClick={() => remove(name)}
|
177
|
+
size={'small'}
|
178
|
+
style={{
|
179
|
+
marginBottom: 6,
|
180
|
+
}}
|
181
|
+
title={t('delete', { ns: 'common' })}
|
182
|
+
/>
|
183
|
+
</Flexbox>
|
184
|
+
))}
|
185
|
+
<Form.Item style={{ marginBottom: 0, marginTop: 8 }}>
|
186
|
+
<Flexbox gap={8} horizontal justify={'space-between'}>
|
187
|
+
<Button
|
188
|
+
color={'default'}
|
189
|
+
icon={<Icon icon={LucidePlus} />}
|
190
|
+
onClick={() => add({ id: `new-${Date.now()}`, key: '', value: '' })}
|
191
|
+
size={'small'}
|
192
|
+
variant="filled"
|
193
|
+
>
|
194
|
+
{t('updateArgs.form.add')}
|
195
|
+
</Button>
|
196
|
+
|
197
|
+
<Flexbox gap={8} horizontal>
|
198
|
+
<Button onClick={handleCancel} size={'small'}>
|
199
|
+
{t('cancel', { ns: 'common' })}
|
200
|
+
</Button>
|
201
|
+
<Button loading={updating} onClick={handleFinish} size={'small'} type={'primary'}>
|
202
|
+
{t('save', { ns: 'common' })}
|
203
|
+
</Button>
|
204
|
+
</Flexbox>
|
205
|
+
</Flexbox>
|
206
|
+
</Form.Item>
|
207
|
+
</Flexbox>
|
208
|
+
)}
|
209
|
+
</Form.List>
|
210
|
+
</Form>
|
211
|
+
);
|
212
|
+
});
|
213
|
+
|
214
|
+
export default KeyValueEditor;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { DiscordIcon, Icon } from '@lobehub/ui';
|
1
|
+
import { DiscordIcon, Hotkey, Icon } from '@lobehub/ui';
|
2
2
|
import { Badge } from 'antd';
|
3
3
|
import { ItemType } from 'antd/es/menu/interface';
|
4
4
|
import {
|
@@ -22,6 +22,7 @@ import { Flexbox } from 'react-layout-kit';
|
|
22
22
|
import type { MenuProps } from '@/components/Menu';
|
23
23
|
import { enableAuth } from '@/const/auth';
|
24
24
|
import { LOBE_CHAT_CLOUD } from '@/const/branding';
|
25
|
+
import { DEFAULT_HOTKEY_CONFIG } from '@/const/settings';
|
25
26
|
import {
|
26
27
|
DISCORD,
|
27
28
|
DOCUMENTS_REFER_URL,
|
@@ -31,6 +32,7 @@ import {
|
|
31
32
|
UTM_SOURCE,
|
32
33
|
mailTo,
|
33
34
|
} from '@/const/url';
|
35
|
+
import { isDesktop } from '@/const/version';
|
34
36
|
import DataImporter from '@/features/DataImporter';
|
35
37
|
import { usePWAInstall } from '@/hooks/usePWAInstall';
|
36
38
|
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
@@ -81,6 +83,11 @@ export const useMenu = () => {
|
|
81
83
|
|
82
84
|
const settings: MenuProps['items'] = [
|
83
85
|
{
|
86
|
+
extra: isDesktop ? (
|
87
|
+
<div>
|
88
|
+
<Hotkey keys={DEFAULT_HOTKEY_CONFIG.openSettings} />
|
89
|
+
</div>
|
90
|
+
) : undefined,
|
84
91
|
icon: <Icon icon={Settings2} />,
|
85
92
|
key: 'setting',
|
86
93
|
label: (
|
@@ -368,6 +368,9 @@ export class LobeGoogleAI implements LobeRuntimeAI {
|
|
368
368
|
payload?: ChatStreamPayload,
|
369
369
|
): GoogleFunctionCallTool[] | undefined {
|
370
370
|
// 目前 Tools (例如 googleSearch) 无法与其他 FunctionCall 同时使用
|
371
|
+
if (payload?.messages?.some(m => m.tool_calls?.length)) {
|
372
|
+
return; // 若历史消息中已有 function calling,则不再注入任何 Tools
|
373
|
+
}
|
371
374
|
if (payload?.enabledSearch) {
|
372
375
|
return [{ googleSearch: {} } as GoogleSearchRetrievalTool];
|
373
376
|
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { createTRPCClient, httpBatchLink } from '@trpc/client';
|
2
|
+
import superjson from 'superjson';
|
3
|
+
|
4
|
+
import type { DesktopRouter } from '@/server/routers/desktop';
|
5
|
+
|
6
|
+
export const desktopClient = createTRPCClient<DesktopRouter>({
|
7
|
+
links: [
|
8
|
+
httpBatchLink({
|
9
|
+
maxURLLength: 2083,
|
10
|
+
transformer: superjson,
|
11
|
+
url: '/trpc/desktop',
|
12
|
+
}),
|
13
|
+
],
|
14
|
+
});
|
@@ -0,0 +1,34 @@
|
|
1
|
+
const electron = {
|
2
|
+
remoteServer: {
|
3
|
+
authError: '授权失败: {{error}}',
|
4
|
+
authPending: '请在浏览器中完成授权',
|
5
|
+
configDesc: '连接到远程LobeChat服务器,启用数据同步',
|
6
|
+
configError: '配置出错',
|
7
|
+
configTitle: '配置云同步',
|
8
|
+
connect: '连接并授权',
|
9
|
+
connected: '已连接',
|
10
|
+
disconnect: '断开连接',
|
11
|
+
disconnectError: '断开连接失败',
|
12
|
+
disconnected: '未连接',
|
13
|
+
fetchError: '获取配置失败',
|
14
|
+
invalidUrl: '请输入有效的URL地址',
|
15
|
+
serverUrl: '服务器地址',
|
16
|
+
statusConnected: '已连接',
|
17
|
+
statusDisconnected: '未连接',
|
18
|
+
urlRequired: '请输入服务器地址',
|
19
|
+
},
|
20
|
+
updater: {
|
21
|
+
downloadingUpdate: '正在下载更新',
|
22
|
+
downloadingUpdateDesc: '更新正在下载中,请稍候...',
|
23
|
+
later: '稍后更新',
|
24
|
+
newVersionAvailable: '新版本可用',
|
25
|
+
newVersionAvailableDesc: '发现新版本 {{version}},是否立即下载?',
|
26
|
+
restartAndInstall: '重启并安装',
|
27
|
+
updateError: '更新错误',
|
28
|
+
updateReady: '更新已就绪',
|
29
|
+
updateReadyDesc: 'Lobe Chat {{version}} 已下载完成,重启应用后即可完成安装。',
|
30
|
+
upgradeNow: '立即更新',
|
31
|
+
},
|
32
|
+
};
|
33
|
+
|
34
|
+
export default electron;
|
@@ -5,6 +5,7 @@ import clerk from './clerk';
|
|
5
5
|
import common from './common';
|
6
6
|
import components from './components';
|
7
7
|
import discover from './discover';
|
8
|
+
import electron from './electron';
|
8
9
|
import error from './error';
|
9
10
|
import file from './file';
|
10
11
|
import hotkey from './hotkey';
|
@@ -32,6 +33,7 @@ const resources = {
|
|
32
33
|
common,
|
33
34
|
components,
|
34
35
|
discover,
|
36
|
+
electron,
|
35
37
|
error,
|
36
38
|
file,
|
37
39
|
hotkey,
|
@@ -7,6 +7,20 @@ export default {
|
|
7
7
|
images: '图片:',
|
8
8
|
prompt: '提示词',
|
9
9
|
},
|
10
|
+
localFiles: {
|
11
|
+
file: '文件',
|
12
|
+
folder: '文件夹',
|
13
|
+
open: '打开',
|
14
|
+
openFile: '打开文件',
|
15
|
+
openFolder: '打开文件夹',
|
16
|
+
read: {
|
17
|
+
more: '查看更多',
|
18
|
+
},
|
19
|
+
readFile: '读取文件',
|
20
|
+
readFileError: '读取文件失败,请检查文件路径是否正确',
|
21
|
+
readFiles: '读取文件',
|
22
|
+
readFilesError: '读取文件失败,请检查文件路径是否正确',
|
23
|
+
},
|
10
24
|
search: {
|
11
25
|
createNewSearch: '创建新的搜索记录',
|
12
26
|
emptyResult: '没有搜索到结果,请修改关键词后重试',
|
@@ -54,4 +68,15 @@ export default {
|
|
54
68
|
summaryTooltip: '总结当前内容',
|
55
69
|
viewMoreResults: '查看更多 {{results}} 个结果',
|
56
70
|
},
|
71
|
+
updateArgs: {
|
72
|
+
duplicateKeyError: '字段键必须唯一',
|
73
|
+
form: {
|
74
|
+
add: '添加一项',
|
75
|
+
key: '字段键',
|
76
|
+
value: '字段值',
|
77
|
+
},
|
78
|
+
formValidationFailed: '表单验证失败,请检查参数格式',
|
79
|
+
keyRequired: '字段键不能为空',
|
80
|
+
stringifyError: '无法序列化参数,请检查参数格式',
|
81
|
+
},
|
57
82
|
};
|
@@ -0,0 +1,43 @@
|
|
1
|
+
import { z } from 'zod';
|
2
|
+
|
3
|
+
import { DESKTOP_USER_ID } from '@/const/desktop';
|
4
|
+
import { TableViewerRepo } from '@/database/repositories/tableViewer';
|
5
|
+
import { publicProcedure, router } from '@/libs/trpc/lambda';
|
6
|
+
import { serverDatabase } from '@/libs/trpc/lambda/middleware';
|
7
|
+
|
8
|
+
const pgTableProcedure = publicProcedure.use(serverDatabase).use(async ({ ctx, next }) => {
|
9
|
+
return next({
|
10
|
+
ctx: {
|
11
|
+
tableViewerRepo: new TableViewerRepo(ctx.serverDB, DESKTOP_USER_ID),
|
12
|
+
},
|
13
|
+
});
|
14
|
+
});
|
15
|
+
|
16
|
+
export const pgTableRouter = router({
|
17
|
+
getAllTables: pgTableProcedure.query(async ({ ctx }) => {
|
18
|
+
return ctx.tableViewerRepo.getAllTables();
|
19
|
+
}),
|
20
|
+
getTableData: pgTableProcedure
|
21
|
+
.input(
|
22
|
+
z.object({
|
23
|
+
page: z.number(),
|
24
|
+
pageSize: z.number(),
|
25
|
+
tableName: z.string(),
|
26
|
+
}),
|
27
|
+
)
|
28
|
+
.query(async ({ input, ctx }) => {
|
29
|
+
return ctx.tableViewerRepo.getTableData(input.tableName, {
|
30
|
+
page: input.page,
|
31
|
+
pageSize: input.pageSize,
|
32
|
+
});
|
33
|
+
}),
|
34
|
+
getTableDetails: pgTableProcedure
|
35
|
+
.input(
|
36
|
+
z.object({
|
37
|
+
tableName: z.string(),
|
38
|
+
}),
|
39
|
+
)
|
40
|
+
.query(async ({ input, ctx }) => {
|
41
|
+
return ctx.tableViewerRepo.getTableDetails(input.tableName);
|
42
|
+
}),
|
43
|
+
});
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { dispatch } from '@lobechat/electron-client-ipc';
|
2
|
+
|
3
|
+
class AutoUpdateService {
|
4
|
+
checkUpdate = async () => {
|
5
|
+
return dispatch('checkUpdate');
|
6
|
+
};
|
7
|
+
|
8
|
+
installNow = async () => {
|
9
|
+
return dispatch('installNow');
|
10
|
+
};
|
11
|
+
|
12
|
+
installLater = async () => {
|
13
|
+
return dispatch('installLater');
|
14
|
+
};
|
15
|
+
}
|
16
|
+
|
17
|
+
export const autoUpdateService = new AutoUpdateService();
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import { dispatch } from '@lobechat/electron-client-ipc';
|
2
|
+
|
3
|
+
import { FileMetadata } from '@/types/files';
|
4
|
+
|
5
|
+
/**
|
6
|
+
* 桌面应用文件API客户端服务
|
7
|
+
*/
|
8
|
+
class DesktopFileAPI {
|
9
|
+
/**
|
10
|
+
* 上传文件到桌面应用
|
11
|
+
* @param file 文件对象
|
12
|
+
* @param hash 文件哈希
|
13
|
+
* @returns 上传结果
|
14
|
+
*/
|
15
|
+
async uploadFile(
|
16
|
+
file: File,
|
17
|
+
hash: string,
|
18
|
+
): Promise<{ metadata: FileMetadata; success: boolean }> {
|
19
|
+
const arrayBuffer = await file.arrayBuffer();
|
20
|
+
|
21
|
+
return dispatch('createFile', {
|
22
|
+
content: arrayBuffer,
|
23
|
+
filename: file.name,
|
24
|
+
hash,
|
25
|
+
path: file.name,
|
26
|
+
type: file.type,
|
27
|
+
});
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
export const desktopFileAPI = new DesktopFileAPI();
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import {
|
2
|
+
ListLocalFileParams,
|
3
|
+
LocalFileItem,
|
4
|
+
LocalReadFileParams,
|
5
|
+
LocalReadFileResult,
|
6
|
+
LocalReadFilesParams,
|
7
|
+
LocalSearchFilesParams,
|
8
|
+
OpenLocalFileParams,
|
9
|
+
OpenLocalFolderParams,
|
10
|
+
dispatch,
|
11
|
+
} from '@lobechat/electron-client-ipc';
|
12
|
+
|
13
|
+
class LocalFileService {
|
14
|
+
async listLocalFiles(params: ListLocalFileParams): Promise<LocalFileItem[]> {
|
15
|
+
return dispatch('listLocalFiles', params);
|
16
|
+
}
|
17
|
+
|
18
|
+
async readLocalFile(params: LocalReadFileParams): Promise<LocalReadFileResult> {
|
19
|
+
return dispatch('readLocalFile', params);
|
20
|
+
}
|
21
|
+
|
22
|
+
async readLocalFiles(params: LocalReadFilesParams): Promise<LocalReadFileResult[]> {
|
23
|
+
return dispatch('readLocalFiles', params);
|
24
|
+
}
|
25
|
+
|
26
|
+
async searchLocalFiles(params: LocalSearchFilesParams): Promise<LocalFileItem[]> {
|
27
|
+
return dispatch('searchLocalFiles', params);
|
28
|
+
}
|
29
|
+
|
30
|
+
async openLocalFile(params: OpenLocalFileParams) {
|
31
|
+
return dispatch('openLocalFile', params);
|
32
|
+
}
|
33
|
+
|
34
|
+
async openLocalFolder(params: OpenLocalFolderParams) {
|
35
|
+
return dispatch('openLocalFolder', params);
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
export const localFileService = new LocalFileService();
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import { RemoteServerConfig, dispatch } from '@lobechat/electron-client-ipc';
|
2
|
+
|
3
|
+
class RemoteServerService {
|
4
|
+
/**
|
5
|
+
* 获取远程服务器配置
|
6
|
+
*/
|
7
|
+
getRemoteServerConfig = async () => {
|
8
|
+
return dispatch('getRemoteServerConfig');
|
9
|
+
};
|
10
|
+
|
11
|
+
/**
|
12
|
+
* 设置远程服务器配置
|
13
|
+
*/
|
14
|
+
setRemoteServerConfig = async (config: RemoteServerConfig) => {
|
15
|
+
return dispatch('setRemoteServerConfig', config);
|
16
|
+
};
|
17
|
+
|
18
|
+
/**
|
19
|
+
* 清除远程服务器配置
|
20
|
+
*/
|
21
|
+
clearRemoteServerConfig = async () => {
|
22
|
+
return dispatch('clearRemoteServerConfig');
|
23
|
+
};
|
24
|
+
|
25
|
+
/**
|
26
|
+
* 请求授权
|
27
|
+
*/
|
28
|
+
requestAuthorization = async (serverUrl: string) => {
|
29
|
+
return dispatch('requestAuthorization', serverUrl);
|
30
|
+
};
|
31
|
+
|
32
|
+
/**
|
33
|
+
* 刷新访问令牌
|
34
|
+
*/
|
35
|
+
refreshAccessToken = async () => {
|
36
|
+
return dispatch('refreshAccessToken');
|
37
|
+
};
|
38
|
+
}
|
39
|
+
|
40
|
+
export const remoteServerService = new RemoteServerService();
|
package/src/store/chat/index.ts
CHANGED
@@ -3,9 +3,10 @@ import { StateCreator } from 'zustand/vanilla';
|
|
3
3
|
import { ChatStore } from '@/store/chat/store';
|
4
4
|
|
5
5
|
import { ChatDallEAction, dalleSlice } from './dalle';
|
6
|
+
import { LocalFileAction, localFileSlice } from './localFile';
|
6
7
|
import { SearchAction, searchSlice } from './search';
|
7
8
|
|
8
|
-
export interface ChatBuiltinToolAction extends ChatDallEAction, SearchAction {}
|
9
|
+
export interface ChatBuiltinToolAction extends ChatDallEAction, SearchAction, LocalFileAction {}
|
9
10
|
|
10
11
|
export const chatToolSlice: StateCreator<
|
11
12
|
ChatStore,
|
@@ -15,4 +16,5 @@ export const chatToolSlice: StateCreator<
|
|
15
16
|
> = (...params) => ({
|
16
17
|
...dalleSlice(...params),
|
17
18
|
...searchSlice(...params),
|
19
|
+
...localFileSlice(...params),
|
18
20
|
});
|