@lobehub/chat 1.46.7 → 1.47.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/CHANGELOG.md +42 -0
- package/changelog/v1.json +14 -0
- package/package.json +2 -1
- package/src/app/(main)/discover/(detail)/provider/[slug]/features/ProviderConfig.tsx +2 -2
- package/src/app/(main)/settings/hooks/useCategory.tsx +3 -3
- package/src/app/(main)/settings/provider/(detail)/[id]/ClientMode.tsx +25 -0
- package/src/app/(main)/settings/provider/(detail)/[id]/page.tsx +2 -1
- package/src/app/(main)/settings/provider/ProviderMenu/SortProviderModal/index.tsx +0 -1
- package/src/database/client/migrations.json +11 -0
- package/src/database/repositories/tableViewer/index.test.ts +256 -0
- package/src/database/repositories/tableViewer/index.ts +251 -0
- package/src/database/server/models/aiProvider.ts +2 -2
- package/src/features/DevPanel/FloatPanel.tsx +136 -0
- package/src/features/DevPanel/PostgresViewer/DataTable/Table.tsx +157 -0
- package/src/features/DevPanel/PostgresViewer/DataTable/TableCell.tsx +34 -0
- package/src/features/DevPanel/PostgresViewer/DataTable/index.tsx +67 -0
- package/src/features/DevPanel/PostgresViewer/Schema.tsx +196 -0
- package/src/features/DevPanel/PostgresViewer/TableColumns.tsx +67 -0
- package/src/features/DevPanel/PostgresViewer/index.tsx +19 -0
- package/src/features/DevPanel/PostgresViewer/useTableColumns.ts +13 -0
- package/src/features/DevPanel/index.tsx +12 -0
- package/src/features/ModelSwitchPanel/index.tsx +4 -2
- package/src/hooks/useEnabledChatModels.ts +2 -2
- package/src/hooks/useModelContextWindowTokens.ts +2 -2
- package/src/hooks/useModelHasContextWindowToken.ts +2 -2
- package/src/hooks/useModelSupportToolUse.ts +2 -2
- package/src/hooks/useModelSupportVision.ts +2 -2
- package/src/layout/GlobalProvider/index.tsx +2 -2
- package/src/services/_auth.ts +2 -2
- package/src/services/aiModel/client.ts +60 -0
- package/src/services/aiModel/index.test.ts +10 -0
- package/src/services/aiModel/index.ts +5 -0
- package/src/services/aiModel/server.ts +47 -0
- package/src/services/aiModel/type.ts +30 -0
- package/src/services/aiProvider/client.ts +64 -0
- package/src/services/aiProvider/index.test.ts +10 -0
- package/src/services/aiProvider/index.ts +5 -0
- package/src/services/aiProvider/server.ts +43 -0
- package/src/services/aiProvider/type.ts +26 -0
- package/src/services/chat.ts +5 -5
- package/src/services/tableViewer/client.ts +16 -0
- package/src/services/tableViewer/index.ts +3 -0
- package/src/store/aiInfra/slices/aiProvider/action.ts +2 -2
- package/src/types/serverConfig.ts +6 -0
- package/src/types/tableViewer.ts +30 -0
- package/tests/utils.tsx +46 -0
- package/vercel.json +1 -1
- package/src/features/DebugUI/Content.tsx +0 -34
- package/src/features/DebugUI/index.tsx +0 -20
- package/src/services/aiModel.ts +0 -52
- package/src/services/aiProvider.ts +0 -47
@@ -0,0 +1,196 @@
|
|
1
|
+
import { Icon } from '@lobehub/ui';
|
2
|
+
import { createStyles } from 'antd-style';
|
3
|
+
import { ChevronDown, ChevronRight, Database, Table as TableIcon } from 'lucide-react';
|
4
|
+
import React, { useState } from 'react';
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
6
|
+
import useSWR from 'swr';
|
7
|
+
|
8
|
+
import { tableViewerService } from '@/services/tableViewer';
|
9
|
+
import { useGlobalStore } from '@/store/global';
|
10
|
+
import { systemStatusSelectors } from '@/store/global/selectors';
|
11
|
+
|
12
|
+
import TableColumns from './TableColumns';
|
13
|
+
|
14
|
+
// 样式定义
|
15
|
+
const useStyles = createStyles(({ token, css }) => ({
|
16
|
+
button: css`
|
17
|
+
cursor: pointer;
|
18
|
+
|
19
|
+
display: flex;
|
20
|
+
gap: 4px;
|
21
|
+
align-items: center;
|
22
|
+
|
23
|
+
padding-block: ${token.paddingXS}px;
|
24
|
+
padding-inline: ${token.padding}px;
|
25
|
+
border: none;
|
26
|
+
border-radius: ${token.borderRadius}px;
|
27
|
+
|
28
|
+
color: ${token.colorText};
|
29
|
+
|
30
|
+
background: ${token.colorFillSecondary};
|
31
|
+
|
32
|
+
transition: all ${token.motionDurationMid};
|
33
|
+
|
34
|
+
&:hover {
|
35
|
+
background: ${token.colorFillTertiary};
|
36
|
+
}
|
37
|
+
`,
|
38
|
+
count: css`
|
39
|
+
font-size: 12px;
|
40
|
+
color: ${token.colorTextTertiary};
|
41
|
+
`,
|
42
|
+
dataPanel: css`
|
43
|
+
overflow: hidden;
|
44
|
+
display: flex;
|
45
|
+
flex: 1;
|
46
|
+
flex-direction: column;
|
47
|
+
|
48
|
+
height: 100%;
|
49
|
+
|
50
|
+
background: ${token.colorBgContainer};
|
51
|
+
`,
|
52
|
+
schema: css`
|
53
|
+
font-family: ${token.fontFamilyCode};
|
54
|
+
font-size: 12px;
|
55
|
+
font-weight: normal;
|
56
|
+
color: ${token.colorTextTertiary};
|
57
|
+
`,
|
58
|
+
schemaHeader: css`
|
59
|
+
display: flex;
|
60
|
+
gap: 8px;
|
61
|
+
align-items: center;
|
62
|
+
|
63
|
+
padding-block: 12px;
|
64
|
+
padding-inline: 16px;
|
65
|
+
|
66
|
+
font-weight: ${token.fontWeightStrong};
|
67
|
+
color: ${token.colorText};
|
68
|
+
`,
|
69
|
+
schemaPanel: css`
|
70
|
+
overflow: scroll;
|
71
|
+
|
72
|
+
width: 280px;
|
73
|
+
height: 100%;
|
74
|
+
border-inline-end: 1px solid ${token.colorBorderSecondary};
|
75
|
+
|
76
|
+
background: ${token.colorBgContainer};
|
77
|
+
`,
|
78
|
+
selected: css`
|
79
|
+
background: ${token.colorFillSecondary};
|
80
|
+
`,
|
81
|
+
table: css`
|
82
|
+
overflow: hidden;
|
83
|
+
flex: 1;
|
84
|
+
|
85
|
+
table {
|
86
|
+
border-collapse: collapse;
|
87
|
+
width: 100%;
|
88
|
+
}
|
89
|
+
|
90
|
+
th {
|
91
|
+
position: sticky;
|
92
|
+
z-index: 1;
|
93
|
+
inset-block-start: 0;
|
94
|
+
|
95
|
+
padding: ${token.padding}px;
|
96
|
+
border-block-end: 1px solid ${token.colorBorderSecondary};
|
97
|
+
|
98
|
+
font-weight: ${token.fontWeightStrong};
|
99
|
+
text-align: start;
|
100
|
+
|
101
|
+
background: ${token.colorFillQuaternary};
|
102
|
+
}
|
103
|
+
|
104
|
+
td {
|
105
|
+
padding: ${token.padding}px;
|
106
|
+
border-block-end: 1px solid ${token.colorBorderSecondary};
|
107
|
+
transition: all ${token.motionDurationMid};
|
108
|
+
|
109
|
+
&:hover {
|
110
|
+
background: ${token.colorFillQuaternary};
|
111
|
+
}
|
112
|
+
}
|
113
|
+
`,
|
114
|
+
tableItem: css`
|
115
|
+
cursor: pointer;
|
116
|
+
|
117
|
+
display: flex;
|
118
|
+
gap: 8px;
|
119
|
+
align-items: center;
|
120
|
+
|
121
|
+
margin-inline: 8px;
|
122
|
+
padding: 8px;
|
123
|
+
border-radius: ${token.borderRadius}px;
|
124
|
+
|
125
|
+
color: ${token.colorText};
|
126
|
+
|
127
|
+
&:hover {
|
128
|
+
background: ${token.colorFillSecondary};
|
129
|
+
}
|
130
|
+
`,
|
131
|
+
}));
|
132
|
+
|
133
|
+
interface SchemaPanelProps {
|
134
|
+
onTableSelect: (tableName: string) => void;
|
135
|
+
selectedTable?: string;
|
136
|
+
}
|
137
|
+
const SchemaPanel = ({ onTableSelect, selectedTable }: SchemaPanelProps) => {
|
138
|
+
const { styles, cx } = useStyles();
|
139
|
+
const [expandedTables, setExpandedTables] = useState(new Set());
|
140
|
+
|
141
|
+
const isDBInited = useGlobalStore(systemStatusSelectors.isDBInited);
|
142
|
+
|
143
|
+
const { data, isLoading } = useSWR(isDBInited ? 'fetch-tables' : null, () =>
|
144
|
+
tableViewerService.getAllTables(),
|
145
|
+
);
|
146
|
+
|
147
|
+
const toggleTable = (tableName: string) => {
|
148
|
+
const newExpanded = new Set(expandedTables);
|
149
|
+
if (newExpanded.has(tableName)) {
|
150
|
+
newExpanded.delete(tableName);
|
151
|
+
} else {
|
152
|
+
newExpanded.add(tableName);
|
153
|
+
}
|
154
|
+
setExpandedTables(newExpanded);
|
155
|
+
};
|
156
|
+
|
157
|
+
return (
|
158
|
+
<div className={styles.schemaPanel}>
|
159
|
+
<div className={styles.schemaHeader}>
|
160
|
+
<Database size={16} />
|
161
|
+
<Flexbox align={'center'} horizontal justify={'space-between'}>
|
162
|
+
<span>Tables {data?.length}</span>
|
163
|
+
<span className={styles.schema}>public</span>
|
164
|
+
</Flexbox>
|
165
|
+
</div>
|
166
|
+
{isLoading ? (
|
167
|
+
<div>Loading...</div>
|
168
|
+
) : (
|
169
|
+
<Flexbox>
|
170
|
+
{data?.map((table) => (
|
171
|
+
<div key={table.name}>
|
172
|
+
<Flexbox
|
173
|
+
className={cx(styles.tableItem, selectedTable === table.name && styles.selected)}
|
174
|
+
horizontal
|
175
|
+
onClick={() => {
|
176
|
+
toggleTable(table.name);
|
177
|
+
onTableSelect(table.name);
|
178
|
+
}}
|
179
|
+
>
|
180
|
+
<Icon icon={expandedTables.has(table.name) ? ChevronDown : ChevronRight} />
|
181
|
+
<TableIcon size={16} />
|
182
|
+
<Flexbox align={'center'} horizontal justify={'space-between'}>
|
183
|
+
<span>{table.name}</span>
|
184
|
+
<span className={styles.count}>{table.count}</span>
|
185
|
+
</Flexbox>
|
186
|
+
</Flexbox>
|
187
|
+
{expandedTables.has(table.name) && <TableColumns tableName={table.name} />}
|
188
|
+
</div>
|
189
|
+
))}
|
190
|
+
</Flexbox>
|
191
|
+
)}
|
192
|
+
</div>
|
193
|
+
);
|
194
|
+
};
|
195
|
+
|
196
|
+
export default SchemaPanel;
|
@@ -0,0 +1,67 @@
|
|
1
|
+
import { Tag } from 'antd';
|
2
|
+
import { createStyles } from 'antd-style';
|
3
|
+
import React from 'react';
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
5
|
+
|
6
|
+
import { useTableColumns } from './useTableColumns';
|
7
|
+
|
8
|
+
const useStyles = createStyles(({ token, css }) => ({
|
9
|
+
container: css`
|
10
|
+
margin-inline: 40px 4px;
|
11
|
+
font-size: ${token.fontSizeSM}px;
|
12
|
+
color: ${token.colorTextSecondary};
|
13
|
+
`,
|
14
|
+
item: css`
|
15
|
+
padding-block: 4px;
|
16
|
+
padding-inline: 0;
|
17
|
+
font-family: ${token.fontFamilyCode};
|
18
|
+
`,
|
19
|
+
type: css`
|
20
|
+
font-size: 10px;
|
21
|
+
color: ${token.red9};
|
22
|
+
`,
|
23
|
+
}));
|
24
|
+
|
25
|
+
interface TableColumnsProps {
|
26
|
+
tableName: string;
|
27
|
+
}
|
28
|
+
|
29
|
+
const TableColumns = ({ tableName }: TableColumnsProps) => {
|
30
|
+
const { styles } = useStyles();
|
31
|
+
|
32
|
+
const { data, isLoading } = useTableColumns(tableName);
|
33
|
+
|
34
|
+
return (
|
35
|
+
<div className={styles.container}>
|
36
|
+
{isLoading ? (
|
37
|
+
<div>Loading...</div>
|
38
|
+
) : (
|
39
|
+
<Flexbox>
|
40
|
+
{data?.map((column) => (
|
41
|
+
<Flexbox
|
42
|
+
align={'center'}
|
43
|
+
className={styles.item}
|
44
|
+
horizontal
|
45
|
+
justify={'space-between'}
|
46
|
+
key={column.name}
|
47
|
+
>
|
48
|
+
<Flexbox>
|
49
|
+
<Flexbox>{column.name}</Flexbox>
|
50
|
+
<span className={styles.type}>{column.type}</span>
|
51
|
+
</Flexbox>
|
52
|
+
{column.isPrimaryKey && (
|
53
|
+
<div>
|
54
|
+
<Tag bordered={false} color={'cyan'}>
|
55
|
+
Primary
|
56
|
+
</Tag>
|
57
|
+
</div>
|
58
|
+
)}
|
59
|
+
</Flexbox>
|
60
|
+
))}
|
61
|
+
</Flexbox>
|
62
|
+
)}
|
63
|
+
</div>
|
64
|
+
);
|
65
|
+
};
|
66
|
+
|
67
|
+
export default TableColumns;
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import { Flexbox } from 'react-layout-kit';
|
3
|
+
|
4
|
+
import DataTable from './DataTable';
|
5
|
+
import SchemaPanel from './Schema';
|
6
|
+
|
7
|
+
// Main Database Panel Component
|
8
|
+
const DatabasePanel = () => {
|
9
|
+
const [selectedTable, setSelectedTable] = useState<string>('');
|
10
|
+
|
11
|
+
return (
|
12
|
+
<Flexbox height={'100%'} horizontal>
|
13
|
+
<SchemaPanel onTableSelect={setSelectedTable} selectedTable={selectedTable} />
|
14
|
+
<DataTable tableName={selectedTable} />
|
15
|
+
</Flexbox>
|
16
|
+
);
|
17
|
+
};
|
18
|
+
|
19
|
+
export default DatabasePanel;
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import useSWR from 'swr';
|
2
|
+
|
3
|
+
import { tableViewerService } from '@/services/tableViewer';
|
4
|
+
import { useGlobalStore } from '@/store/global';
|
5
|
+
import { systemStatusSelectors } from '@/store/global/selectors';
|
6
|
+
|
7
|
+
export const useTableColumns = (tableName?: string) => {
|
8
|
+
const isDBInited = useGlobalStore(systemStatusSelectors.isDBInited);
|
9
|
+
|
10
|
+
return useSWR(isDBInited && tableName ? ['fetch-table-columns', tableName] : null, ([, table]) =>
|
11
|
+
tableViewerService.getTableDetails(table),
|
12
|
+
);
|
13
|
+
};
|
@@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next';
|
|
9
9
|
import { Flexbox } from 'react-layout-kit';
|
10
10
|
|
11
11
|
import { ModelItemRender, ProviderItemRender } from '@/components/ModelSelect';
|
12
|
-
import {
|
12
|
+
import { isDeprecatedEdition } from '@/const/version';
|
13
13
|
import { useEnabledChatModels } from '@/hooks/useEnabledChatModels';
|
14
14
|
import { useIsMobile } from '@/hooks/useIsMobile';
|
15
15
|
import { useAgentStore } from '@/store/agent';
|
@@ -76,7 +76,9 @@ const ModelSwitchPanel = memo<PropsWithChildren>(({ children }) => {
|
|
76
76
|
</Flexbox>
|
77
77
|
),
|
78
78
|
onClick: () => {
|
79
|
-
router.push(
|
79
|
+
router.push(
|
80
|
+
isDeprecatedEdition ? '/settings/llm' : `/settings/provider/${provider.id}`,
|
81
|
+
);
|
80
82
|
},
|
81
83
|
},
|
82
84
|
];
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import isEqual from 'fast-deep-equal';
|
2
2
|
|
3
|
-
import {
|
3
|
+
import { isDeprecatedEdition } from '@/const/version';
|
4
4
|
import { useAiInfraStore } from '@/store/aiInfra';
|
5
5
|
import { useUserStore } from '@/store/user';
|
6
6
|
import { modelProviderSelectors } from '@/store/user/selectors';
|
@@ -10,7 +10,7 @@ export const useEnabledChatModels = (): EnabledProviderWithModels[] => {
|
|
10
10
|
const enabledList = useUserStore(modelProviderSelectors.modelProviderListForModelSelect, isEqual);
|
11
11
|
const enabledChatModelList = useAiInfraStore((s) => s.enabledChatModelList, isEqual);
|
12
12
|
|
13
|
-
if (
|
13
|
+
if (isDeprecatedEdition) {
|
14
14
|
return enabledList;
|
15
15
|
}
|
16
16
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import {
|
1
|
+
import { isDeprecatedEdition } from '@/const/version';
|
2
2
|
import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
|
3
3
|
import { useUserStore } from '@/store/user';
|
4
4
|
import { modelProviderSelectors } from '@/store/user/selectors';
|
@@ -8,7 +8,7 @@ export const useModelContextWindowTokens = (model: string, provider: string) =>
|
|
8
8
|
|
9
9
|
// TODO: remove this in V2.0
|
10
10
|
const oldValue = useUserStore(modelProviderSelectors.modelMaxToken(model));
|
11
|
-
if (
|
11
|
+
if (isDeprecatedEdition) return oldValue;
|
12
12
|
//
|
13
13
|
|
14
14
|
return newValue as number;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import {
|
1
|
+
import { isDeprecatedEdition } from '@/const/version';
|
2
2
|
import { useAgentStore } from '@/store/agent';
|
3
3
|
import { agentSelectors } from '@/store/agent/slices/chat';
|
4
4
|
import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
|
@@ -12,7 +12,7 @@ export const useModelHasContextWindowToken = () => {
|
|
12
12
|
|
13
13
|
// TODO: remove this in V2.0
|
14
14
|
const oldValue = useUserStore(modelProviderSelectors.isModelHasMaxToken(model));
|
15
|
-
if (
|
15
|
+
if (isDeprecatedEdition) return oldValue;
|
16
16
|
//
|
17
17
|
|
18
18
|
return newValue;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import {
|
1
|
+
import { isDeprecatedEdition } from '@/const/version';
|
2
2
|
import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
|
3
3
|
import { useUserStore } from '@/store/user';
|
4
4
|
import { modelProviderSelectors } from '@/store/user/selectors';
|
@@ -8,7 +8,7 @@ export const useModelSupportToolUse = (model: string, provider: string) => {
|
|
8
8
|
|
9
9
|
// TODO: remove this in V2.0
|
10
10
|
const oldValue = useUserStore(modelProviderSelectors.isModelEnabledFunctionCall(model));
|
11
|
-
if (
|
11
|
+
if (isDeprecatedEdition) return oldValue;
|
12
12
|
//
|
13
13
|
|
14
14
|
return newValue;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import {
|
1
|
+
import { isDeprecatedEdition } from '@/const/version';
|
2
2
|
import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
|
3
3
|
import { useUserStore } from '@/store/user';
|
4
4
|
import { modelProviderSelectors } from '@/store/user/selectors';
|
@@ -8,7 +8,7 @@ export const useModelSupportVision = (model: string, provider: string) => {
|
|
8
8
|
|
9
9
|
// TODO: remove this in V2.0
|
10
10
|
const oldValue = useUserStore(modelProviderSelectors.isModelEnabledVision(model));
|
11
|
-
if (
|
11
|
+
if (isDeprecatedEdition) return oldValue;
|
12
12
|
//
|
13
13
|
|
14
14
|
return newValue;
|
@@ -9,7 +9,7 @@ import {
|
|
9
9
|
LOBE_THEME_NEUTRAL_COLOR,
|
10
10
|
LOBE_THEME_PRIMARY_COLOR,
|
11
11
|
} from '@/const/theme';
|
12
|
-
import
|
12
|
+
import DevPanel from '@/features/DevPanel';
|
13
13
|
import { getServerGlobalConfig } from '@/server/globalConfig';
|
14
14
|
import { ServerConfigStoreProvider } from '@/store/serverConfig';
|
15
15
|
import { getAntdLocale, parseBrowserLanguage } from '@/utils/locale';
|
@@ -65,9 +65,9 @@ const GlobalLayout = async ({ children }: PropsWithChildren) => {
|
|
65
65
|
<Suspense>
|
66
66
|
<StoreInitialization />
|
67
67
|
<ReactScan />
|
68
|
+
{process.env.NODE_ENV === 'development' && <DevPanel />}
|
68
69
|
</Suspense>
|
69
70
|
</ServerConfigStoreProvider>
|
70
|
-
<DebugUI />
|
71
71
|
</AppTheme>
|
72
72
|
<AntdV5MonkeyPatch />
|
73
73
|
</Locale>
|
package/src/services/_auth.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { JWTPayload, LOBE_CHAT_AUTH_HEADER } from '@/const/auth';
|
2
|
-
import {
|
2
|
+
import { isDeprecatedEdition } from '@/const/version';
|
3
3
|
import { ModelProvider } from '@/libs/agent-runtime';
|
4
4
|
import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
|
5
5
|
import { useUserStore } from '@/store/user';
|
@@ -94,7 +94,7 @@ export const createPayloadWithKeyVaults = (provider: string) => {
|
|
94
94
|
let keyVaults = {};
|
95
95
|
|
96
96
|
// TODO: remove this condition in V2.0
|
97
|
-
if (
|
97
|
+
if (isDeprecatedEdition) {
|
98
98
|
keyVaults = keyVaultsConfigSelectors.getVaultByProvider(provider as any)(
|
99
99
|
useUserStore.getState(),
|
100
100
|
);
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import { clientDB } from '@/database/client/db';
|
2
|
+
import { AiInfraRepos } from '@/database/repositories/aiInfra';
|
3
|
+
import { AiModelModel } from '@/database/server/models/aiModel';
|
4
|
+
import { BaseClientService } from '@/services/baseClientService';
|
5
|
+
|
6
|
+
import { IAiModelService } from './type';
|
7
|
+
|
8
|
+
export class ClientService extends BaseClientService implements IAiModelService {
|
9
|
+
private get aiModel(): AiModelModel {
|
10
|
+
return new AiModelModel(clientDB as any, this.userId);
|
11
|
+
}
|
12
|
+
private get aiInfraRepos(): AiInfraRepos {
|
13
|
+
return new AiInfraRepos(clientDB as any, this.userId, {});
|
14
|
+
}
|
15
|
+
|
16
|
+
createAiModel: IAiModelService['createAiModel'] = async (params) => {
|
17
|
+
const data = await this.aiModel.create(params);
|
18
|
+
|
19
|
+
return data?.id;
|
20
|
+
};
|
21
|
+
|
22
|
+
getAiProviderModelList: IAiModelService['getAiProviderModelList'] = async (id) => {
|
23
|
+
return this.aiInfraRepos.getAiProviderModelList(id);
|
24
|
+
};
|
25
|
+
|
26
|
+
getAiModelById: IAiModelService['getAiModelById'] = async (id) => {
|
27
|
+
return this.aiModel.findById(id);
|
28
|
+
};
|
29
|
+
|
30
|
+
toggleModelEnabled: IAiModelService['toggleModelEnabled'] = async (params) => {
|
31
|
+
return this.aiModel.toggleModelEnabled(params);
|
32
|
+
};
|
33
|
+
|
34
|
+
updateAiModel: IAiModelService['updateAiModel'] = async (id, providerId, value) => {
|
35
|
+
return this.aiModel.update(id, providerId, value);
|
36
|
+
};
|
37
|
+
|
38
|
+
batchUpdateAiModels: IAiModelService['batchUpdateAiModels'] = async (id, models) => {
|
39
|
+
return this.aiModel.batchUpdateAiModels(id, models);
|
40
|
+
};
|
41
|
+
|
42
|
+
batchToggleAiModels: IAiModelService['batchToggleAiModels'] = async (id, models, enabled) => {
|
43
|
+
return this.aiModel.batchToggleAiModels(id, models, enabled);
|
44
|
+
};
|
45
|
+
|
46
|
+
clearRemoteModels: IAiModelService['clearRemoteModels'] = async (providerId) => {
|
47
|
+
return this.aiModel.clearRemoteModels(providerId);
|
48
|
+
};
|
49
|
+
|
50
|
+
updateAiModelOrder: IAiModelService['updateAiModelOrder'] = async (providerId, items) => {
|
51
|
+
return this.aiModel.updateModelsOrder(providerId, items);
|
52
|
+
};
|
53
|
+
|
54
|
+
deleteAiModel: IAiModelService['deleteAiModel'] = async (params: {
|
55
|
+
id: string;
|
56
|
+
providerId: string;
|
57
|
+
}) => {
|
58
|
+
return this.aiModel.delete(params.id, params.providerId);
|
59
|
+
};
|
60
|
+
}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import { lambdaClient } from '@/libs/trpc/client';
|
2
|
+
import { IAiModelService } from '@/services/aiModel/type';
|
3
|
+
|
4
|
+
export class ServerService implements IAiModelService {
|
5
|
+
createAiModel: IAiModelService['createAiModel'] = async (params) => {
|
6
|
+
return lambdaClient.aiModel.createAiModel.mutate(params);
|
7
|
+
};
|
8
|
+
|
9
|
+
getAiProviderModelList: IAiModelService['getAiProviderModelList'] = async (id) => {
|
10
|
+
return lambdaClient.aiModel.getAiProviderModelList.query({ id });
|
11
|
+
};
|
12
|
+
|
13
|
+
getAiModelById: IAiModelService['getAiModelById'] = async (id) => {
|
14
|
+
return lambdaClient.aiModel.getAiModelById.query({ id });
|
15
|
+
};
|
16
|
+
|
17
|
+
toggleModelEnabled: IAiModelService['toggleModelEnabled'] = async (params) => {
|
18
|
+
return lambdaClient.aiModel.toggleModelEnabled.mutate(params);
|
19
|
+
};
|
20
|
+
|
21
|
+
updateAiModel: IAiModelService['updateAiModel'] = async (id, providerId, value) => {
|
22
|
+
return lambdaClient.aiModel.updateAiModel.mutate({ id, providerId, value });
|
23
|
+
};
|
24
|
+
|
25
|
+
batchUpdateAiModels: IAiModelService['batchUpdateAiModels'] = async (id, models) => {
|
26
|
+
return lambdaClient.aiModel.batchUpdateAiModels.mutate({ id, models });
|
27
|
+
};
|
28
|
+
|
29
|
+
batchToggleAiModels: IAiModelService['batchToggleAiModels'] = async (id, models, enabled) => {
|
30
|
+
return lambdaClient.aiModel.batchToggleAiModels.mutate({ enabled, id, models });
|
31
|
+
};
|
32
|
+
|
33
|
+
clearRemoteModels: IAiModelService['clearRemoteModels'] = async (providerId) => {
|
34
|
+
return lambdaClient.aiModel.clearRemoteModels.mutate({ providerId });
|
35
|
+
};
|
36
|
+
|
37
|
+
updateAiModelOrder: IAiModelService['updateAiModelOrder'] = async (providerId, items) => {
|
38
|
+
return lambdaClient.aiModel.updateAiModelOrder.mutate({ providerId, sortMap: items });
|
39
|
+
};
|
40
|
+
|
41
|
+
deleteAiModel: IAiModelService['deleteAiModel'] = async (params: {
|
42
|
+
id: string;
|
43
|
+
providerId: string;
|
44
|
+
}) => {
|
45
|
+
return lambdaClient.aiModel.removeAiModel.mutate(params);
|
46
|
+
};
|
47
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
/* eslint-disable typescript-sort-keys/interface */
|
2
|
+
import {
|
3
|
+
AiModelSortMap,
|
4
|
+
AiProviderModelListItem,
|
5
|
+
CreateAiModelParams,
|
6
|
+
ToggleAiModelEnableParams,
|
7
|
+
UpdateAiModelParams,
|
8
|
+
} from '@/types/aiModel';
|
9
|
+
|
10
|
+
export interface IAiModelService {
|
11
|
+
createAiModel: (params: CreateAiModelParams) => Promise<any>;
|
12
|
+
|
13
|
+
getAiProviderModelList: (id: string) => Promise<AiProviderModelListItem[]>;
|
14
|
+
|
15
|
+
getAiModelById: (id: string) => Promise<any>;
|
16
|
+
|
17
|
+
toggleModelEnabled: (params: ToggleAiModelEnableParams) => Promise<any>;
|
18
|
+
|
19
|
+
updateAiModel: (id: string, providerId: string, value: UpdateAiModelParams) => Promise<any>;
|
20
|
+
|
21
|
+
batchUpdateAiModels: (id: string, models: AiProviderModelListItem[]) => Promise<any>;
|
22
|
+
|
23
|
+
batchToggleAiModels: (id: string, models: string[], enabled: boolean) => Promise<any>;
|
24
|
+
|
25
|
+
clearRemoteModels: (providerId: string) => Promise<any>;
|
26
|
+
|
27
|
+
updateAiModelOrder: (providerId: string, items: AiModelSortMap[]) => Promise<any>;
|
28
|
+
|
29
|
+
deleteAiModel: (params: { id: string; providerId: string }) => Promise<any>;
|
30
|
+
}
|
@@ -0,0 +1,64 @@
|
|
1
|
+
import { clientDB } from '@/database/client/db';
|
2
|
+
import { AiInfraRepos } from '@/database/repositories/aiInfra';
|
3
|
+
import { AiProviderModel } from '@/database/server/models/aiProvider';
|
4
|
+
import { BaseClientService } from '@/services/baseClientService';
|
5
|
+
|
6
|
+
import { IAiProviderService } from './type';
|
7
|
+
|
8
|
+
export class ClientService extends BaseClientService implements IAiProviderService {
|
9
|
+
private get aiProviderModel(): AiProviderModel {
|
10
|
+
return new AiProviderModel(clientDB as any, this.userId);
|
11
|
+
}
|
12
|
+
private get aiInfraRepos(): AiInfraRepos {
|
13
|
+
let config = {};
|
14
|
+
if (typeof window !== 'undefined') {
|
15
|
+
config = window.global_serverConfigStore.getState().serverConfig.aiProvider || {};
|
16
|
+
}
|
17
|
+
|
18
|
+
return new AiInfraRepos(clientDB as any, this.userId, config);
|
19
|
+
}
|
20
|
+
|
21
|
+
createAiProvider: IAiProviderService['createAiProvider'] = async (params) => {
|
22
|
+
const data = await this.aiProviderModel.create(params);
|
23
|
+
|
24
|
+
return data?.id;
|
25
|
+
};
|
26
|
+
|
27
|
+
getAiProviderById: IAiProviderService['getAiProviderById'] = async (id) => {
|
28
|
+
return this.aiProviderModel.getAiProviderById(id);
|
29
|
+
};
|
30
|
+
|
31
|
+
getAiProviderList: IAiProviderService['getAiProviderList'] = async () => {
|
32
|
+
return await this.aiInfraRepos.getAiProviderList();
|
33
|
+
};
|
34
|
+
|
35
|
+
getAiProviderRuntimeState: IAiProviderService['getAiProviderRuntimeState'] = async () => {
|
36
|
+
const runtimeConfig = await this.aiProviderModel.getAiProviderRuntimeConfig();
|
37
|
+
|
38
|
+
const enabledAiProviders = await this.aiInfraRepos.getUserEnabledProviderList();
|
39
|
+
|
40
|
+
const enabledAiModels = await this.aiInfraRepos.getEnabledModels();
|
41
|
+
|
42
|
+
return { enabledAiModels, enabledAiProviders, runtimeConfig };
|
43
|
+
};
|
44
|
+
|
45
|
+
toggleProviderEnabled: IAiProviderService['toggleProviderEnabled'] = async (id, enabled) => {
|
46
|
+
return this.aiProviderModel.toggleProviderEnabled(id, enabled);
|
47
|
+
};
|
48
|
+
|
49
|
+
updateAiProvider: IAiProviderService['updateAiProvider'] = async (id, value) => {
|
50
|
+
return this.aiProviderModel.update(id, value);
|
51
|
+
};
|
52
|
+
|
53
|
+
updateAiProviderConfig: IAiProviderService['updateAiProviderConfig'] = async (id, value) => {
|
54
|
+
return this.aiProviderModel.updateConfig(id, value);
|
55
|
+
};
|
56
|
+
|
57
|
+
updateAiProviderOrder: IAiProviderService['updateAiProviderOrder'] = async (items) => {
|
58
|
+
return this.aiProviderModel.updateOrder(items);
|
59
|
+
};
|
60
|
+
|
61
|
+
deleteAiProvider: IAiProviderService['deleteAiProvider'] = async (id) => {
|
62
|
+
return this.aiProviderModel.delete(id);
|
63
|
+
};
|
64
|
+
}
|