@lobehub/chat 1.15.7 → 1.15.9
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/.i18nrc.js +0 -1
- package/CHANGELOG.md +50 -0
- package/README.md +6 -6
- package/README.zh-CN.md +6 -6
- package/locales/ar/knowledgeBase.json +1 -0
- package/locales/ar/ragEval.json +91 -0
- package/locales/bg-BG/knowledgeBase.json +1 -0
- package/locales/bg-BG/ragEval.json +91 -0
- package/locales/de-DE/knowledgeBase.json +1 -0
- package/locales/de-DE/ragEval.json +91 -0
- package/locales/en-US/knowledgeBase.json +1 -0
- package/locales/en-US/ragEval.json +91 -0
- package/locales/es-ES/knowledgeBase.json +1 -0
- package/locales/es-ES/ragEval.json +91 -0
- package/locales/fr-FR/knowledgeBase.json +1 -0
- package/locales/fr-FR/ragEval.json +91 -0
- package/locales/it-IT/knowledgeBase.json +1 -0
- package/locales/it-IT/ragEval.json +91 -0
- package/locales/ja-JP/knowledgeBase.json +1 -0
- package/locales/ja-JP/ragEval.json +91 -0
- package/locales/ko-KR/knowledgeBase.json +1 -0
- package/locales/ko-KR/ragEval.json +91 -0
- package/locales/nl-NL/knowledgeBase.json +1 -0
- package/locales/nl-NL/ragEval.json +91 -0
- package/locales/pl-PL/knowledgeBase.json +1 -0
- package/locales/pl-PL/ragEval.json +91 -0
- package/locales/pt-BR/knowledgeBase.json +1 -0
- package/locales/pt-BR/ragEval.json +91 -0
- package/locales/ru-RU/knowledgeBase.json +1 -0
- package/locales/ru-RU/ragEval.json +91 -0
- package/locales/tr-TR/knowledgeBase.json +1 -0
- package/locales/tr-TR/ragEval.json +91 -0
- package/locales/vi-VN/knowledgeBase.json +1 -0
- package/locales/vi-VN/ragEval.json +91 -0
- package/locales/zh-CN/knowledgeBase.json +1 -0
- package/locales/zh-CN/ragEval.json +91 -0
- package/locales/zh-TW/knowledgeBase.json +1 -0
- package/locales/zh-TW/ragEval.json +91 -0
- package/package.json +2 -1
- package/src/app/(main)/repos/[id]/@menu/Head/index.tsx +4 -13
- package/src/app/(main)/repos/[id]/@menu/Menu/index.tsx +30 -21
- package/src/app/(main)/repos/[id]/@menu/default.tsx +8 -2
- package/src/app/(main)/repos/[id]/evals/components/Container.tsx +25 -0
- package/src/app/(main)/repos/[id]/evals/components/Tabs.tsx +35 -0
- package/src/app/(main)/repos/[id]/evals/dataset/CreateDataset/CreateForm.tsx +72 -0
- package/src/app/(main)/repos/[id]/evals/dataset/CreateDataset/index.tsx +37 -0
- package/src/app/(main)/repos/[id]/evals/dataset/DatasetDetail/index.tsx +126 -0
- package/src/app/(main)/repos/[id]/evals/dataset/DatasetList/Item.tsx +59 -0
- package/src/app/(main)/repos/[id]/evals/dataset/DatasetList/index.tsx +32 -0
- package/src/app/(main)/repos/[id]/evals/dataset/EmptyGuide/index.tsx +33 -0
- package/src/app/(main)/repos/[id]/evals/dataset/page.tsx +47 -0
- package/src/app/(main)/repos/[id]/evals/evaluation/CreateEvaluation/CreateForm.tsx +93 -0
- package/src/app/(main)/repos/[id]/evals/evaluation/CreateEvaluation/index.tsx +28 -0
- package/src/app/(main)/repos/[id]/evals/evaluation/CreateEvaluation/useModal.tsx +39 -0
- package/src/app/(main)/repos/[id]/evals/evaluation/EmptyGuide/index.tsx +25 -0
- package/src/app/(main)/repos/[id]/evals/evaluation/EvaluationList/index.tsx +209 -0
- package/src/app/(main)/repos/[id]/evals/evaluation/page.tsx +32 -0
- package/src/app/(main)/repos/[id]/evals/layout.tsx +22 -0
- package/src/app/(main)/repos/[id]/evals/page.tsx +9 -0
- package/src/app/(main)/repos/[id]/evals/type.ts +5 -0
- package/src/app/(main)/repos/[id]/not-found.tsx +3 -0
- package/src/chains/answerWithContext.ts +6 -7
- package/src/components/FileIcon/index.tsx +2 -2
- package/src/config/featureFlags/schema.ts +3 -1
- package/src/database/server/migrations/0008_add_rag_evals.sql +120 -0
- package/src/database/server/migrations/meta/0008_snapshot.json +3463 -0
- package/src/database/server/migrations/meta/_journal.json +7 -0
- package/src/database/server/models/file.ts +11 -2
- package/src/database/server/models/ragEval/dataset.ts +59 -0
- package/src/database/server/models/ragEval/datasetRecord.ts +87 -0
- package/src/database/server/models/ragEval/evaluation.ts +96 -0
- package/src/database/server/models/ragEval/evaluationRecord.ts +64 -0
- package/src/database/server/models/ragEval/index.ts +4 -0
- package/src/database/server/schemas/lobechat/asyncTask.ts +24 -0
- package/src/database/server/schemas/lobechat/file.ts +2 -18
- package/src/database/server/schemas/lobechat/index.ts +2 -0
- package/src/database/server/schemas/lobechat/ragEvals.ts +105 -0
- package/src/database/server/schemas/lobechat/relations.ts +2 -1
- package/src/libs/agent-runtime/types/chat.ts +3 -0
- package/src/libs/agent-runtime/utils/openaiCompatibleFactory/index.ts +3 -1
- package/src/libs/langchain/loaders/index.ts +1 -1
- package/src/locales/default/index.ts +2 -0
- package/src/locales/default/knowledgeBase.ts +1 -0
- package/src/locales/default/ragEval.ts +93 -0
- package/src/server/modules/S3/index.ts +11 -0
- package/src/server/routers/async/index.ts +2 -0
- package/src/server/routers/async/ragEval.ts +138 -0
- package/src/server/routers/lambda/index.ts +2 -1
- package/src/server/routers/lambda/ragEval.ts +296 -0
- package/src/services/ragEval.ts +67 -0
- package/src/services/upload.ts +12 -5
- package/src/store/file/slices/upload/action.ts +8 -6
- package/src/store/knowledgeBase/initialState.ts +3 -1
- package/src/store/knowledgeBase/slices/ragEval/actions/dataset.ts +88 -0
- package/src/store/knowledgeBase/slices/ragEval/actions/evaluation.ts +62 -0
- package/src/store/knowledgeBase/slices/ragEval/actions/index.ts +20 -0
- package/src/store/knowledgeBase/slices/ragEval/index.ts +2 -0
- package/src/store/knowledgeBase/slices/ragEval/initialState.ts +7 -0
- package/src/store/knowledgeBase/store.ts +9 -3
- package/src/store/serverConfig/selectors.test.ts +1 -0
- package/src/types/eval/dataset.ts +47 -0
- package/src/types/eval/evaluation.ts +53 -0
- package/src/types/eval/index.ts +3 -0
- package/src/types/eval/ragas.ts +9 -0
- package/src/types/files/upload.ts +1 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Button } from 'antd';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
|
|
7
|
+
import { useCreateDatasetModal } from '../CreateEvaluation/useModal';
|
|
8
|
+
|
|
9
|
+
interface CreateEvaluationProps {
|
|
10
|
+
knowledgeBaseId: string;
|
|
11
|
+
onCreate?: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const CreateEvaluation = memo<CreateEvaluationProps>(({ knowledgeBaseId, onCreate }) => {
|
|
15
|
+
const { t } = useTranslation('ragEval');
|
|
16
|
+
const modal = useCreateDatasetModal();
|
|
17
|
+
return (
|
|
18
|
+
<Button
|
|
19
|
+
onClick={() => {
|
|
20
|
+
modal.open({ knowledgeBaseId, onCreate });
|
|
21
|
+
}}
|
|
22
|
+
type={'primary'}
|
|
23
|
+
>
|
|
24
|
+
{t('evaluation.addNewButton')}
|
|
25
|
+
</Button>
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
export default CreateEvaluation;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Icon } from '@lobehub/ui';
|
|
2
|
+
import { SheetIcon } from 'lucide-react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
|
5
|
+
|
|
6
|
+
import { createModal } from '@/components/FunctionModal';
|
|
7
|
+
|
|
8
|
+
import CreateForm from './CreateForm';
|
|
9
|
+
|
|
10
|
+
const Title = () => {
|
|
11
|
+
const { t } = useTranslation('ragEval');
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<Flexbox gap={8} horizontal>
|
|
15
|
+
<Icon icon={SheetIcon} />
|
|
16
|
+
{t('addDataset.title')}
|
|
17
|
+
</Flexbox>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
interface CreateDatasetModalProps {
|
|
22
|
+
knowledgeBaseId: string;
|
|
23
|
+
onCreate?: () => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const useCreateDatasetModal = createModal<CreateDatasetModalProps>((instance, params) => ({
|
|
27
|
+
content: (
|
|
28
|
+
<Flexbox paddingInline={16} style={{ marginBlock: 24 }}>
|
|
29
|
+
<CreateForm
|
|
30
|
+
knowledgeBaseId={params!.knowledgeBaseId}
|
|
31
|
+
onClose={() => {
|
|
32
|
+
instance.current?.destroy();
|
|
33
|
+
}}
|
|
34
|
+
onCreate={params?.onCreate}
|
|
35
|
+
/>
|
|
36
|
+
</Flexbox>
|
|
37
|
+
),
|
|
38
|
+
title: <Title />,
|
|
39
|
+
}));
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { Center, Flexbox } from 'react-layout-kit';
|
|
6
|
+
|
|
7
|
+
import CreateEvaluationButton from '../CreateEvaluation';
|
|
8
|
+
|
|
9
|
+
interface EmptyGuideProps {
|
|
10
|
+
knowledgeBaseId: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const EmptyGuide = memo<EmptyGuideProps>(({ knowledgeBaseId }) => {
|
|
14
|
+
const { t } = useTranslation('ragEval');
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<Center gap={24} height={'100%'} width={'100%'}>
|
|
18
|
+
<div>{t('evaluation.emptyGuide')}</div>
|
|
19
|
+
<Flexbox gap={8} horizontal>
|
|
20
|
+
<CreateEvaluationButton knowledgeBaseId={knowledgeBaseId} />
|
|
21
|
+
</Flexbox>
|
|
22
|
+
</Center>
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
export default EmptyGuide;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
|
|
4
|
+
import { ActionIcon, Icon } from '@lobehub/ui';
|
|
5
|
+
import { App, Button, ButtonProps, Typography } from 'antd';
|
|
6
|
+
import { createStyles } from 'antd-style';
|
|
7
|
+
import { DownloadIcon, PlayIcon, RotateCcwIcon, Trash2Icon } from 'lucide-react';
|
|
8
|
+
import { useRef, useState } from 'react';
|
|
9
|
+
import { useTranslation } from 'react-i18next';
|
|
10
|
+
import { Flexbox } from 'react-layout-kit';
|
|
11
|
+
|
|
12
|
+
import { ragEvalService } from '@/services/ragEval';
|
|
13
|
+
import { useKnowledgeBaseStore } from '@/store/knowledgeBase';
|
|
14
|
+
import { EvalEvaluationStatus, RAGEvalEvaluationItem } from '@/types/eval';
|
|
15
|
+
|
|
16
|
+
import CreateEvaluationButton from '../CreateEvaluation';
|
|
17
|
+
|
|
18
|
+
const createRequest = (knowledgeBaseId: string) => async () => {
|
|
19
|
+
const records = await ragEvalService.getEvaluationList(knowledgeBaseId);
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
data: records,
|
|
23
|
+
success: true,
|
|
24
|
+
total: records.length,
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const useStyles = createStyles(({ css }) => ({
|
|
29
|
+
icon: css`
|
|
30
|
+
min-width: 24px;
|
|
31
|
+
border-radius: 4px;
|
|
32
|
+
`,
|
|
33
|
+
title: css`
|
|
34
|
+
font-size: 16px;
|
|
35
|
+
`,
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
const EvaluationList = ({ knowledgeBaseId }: { knowledgeBaseId: string }) => {
|
|
39
|
+
const { t } = useTranslation(['ragEval', 'common']);
|
|
40
|
+
const { styles } = useStyles();
|
|
41
|
+
const [removeEvaluation, runEvaluation, checkEvaluationStatus] = useKnowledgeBaseStore((s) => [
|
|
42
|
+
s.removeEvaluation,
|
|
43
|
+
s.runEvaluation,
|
|
44
|
+
s.checkEvaluationStatus,
|
|
45
|
+
]);
|
|
46
|
+
const [isCheckingStatus, setCheckingStatus] = useState(false);
|
|
47
|
+
const { modal } = App.useApp();
|
|
48
|
+
const actionRef = useRef<ActionType>();
|
|
49
|
+
|
|
50
|
+
const columns: ProColumns<RAGEvalEvaluationItem>[] = [
|
|
51
|
+
{
|
|
52
|
+
dataIndex: 'name',
|
|
53
|
+
ellipsis: true,
|
|
54
|
+
title: t('evaluation.table.columns.name.title'),
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
dataIndex: ['dataset', 'id'],
|
|
58
|
+
render: (dom, entity) => {
|
|
59
|
+
return (
|
|
60
|
+
<Typography.Link
|
|
61
|
+
href={`/repos/${knowledgeBaseId}/evals/dataset?id=${entity.dataset.id}`}
|
|
62
|
+
style={{ color: 'initial' }}
|
|
63
|
+
target={'_blank'}
|
|
64
|
+
>
|
|
65
|
+
{entity.dataset.name}
|
|
66
|
+
</Typography.Link>
|
|
67
|
+
);
|
|
68
|
+
},
|
|
69
|
+
title: t('evaluation.table.columns.datasetId.title'),
|
|
70
|
+
width: 200,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
dataIndex: 'status',
|
|
74
|
+
title: t('evaluation.table.columns.status.title'),
|
|
75
|
+
valueEnum: {
|
|
76
|
+
[EvalEvaluationStatus.Error]: {
|
|
77
|
+
status: 'error',
|
|
78
|
+
text: t('evaluation.table.columns.status.error'),
|
|
79
|
+
},
|
|
80
|
+
[EvalEvaluationStatus.Processing]: {
|
|
81
|
+
status: 'processing',
|
|
82
|
+
text: t('evaluation.table.columns.status.processing'),
|
|
83
|
+
},
|
|
84
|
+
[EvalEvaluationStatus.Pending]: {
|
|
85
|
+
status: 'default',
|
|
86
|
+
text: t('evaluation.table.columns.status.pending'),
|
|
87
|
+
},
|
|
88
|
+
[EvalEvaluationStatus.Success]: {
|
|
89
|
+
status: 'success',
|
|
90
|
+
text: t('evaluation.table.columns.status.success'),
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
dataIndex: ['recordsStats', 'total'],
|
|
96
|
+
render: (dom, entity) => {
|
|
97
|
+
return entity.status === 'Pending'
|
|
98
|
+
? entity.recordsStats.total
|
|
99
|
+
: `${entity.recordsStats.success}/${entity.recordsStats.total}`;
|
|
100
|
+
},
|
|
101
|
+
title: t('evaluation.table.columns.records.title'),
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
dataIndex: 'actions',
|
|
105
|
+
render: (_, entity) => {
|
|
106
|
+
const actionsMap: Record<EvalEvaluationStatus, ButtonProps> = {
|
|
107
|
+
[EvalEvaluationStatus.Pending]: {
|
|
108
|
+
children: t('evaluation.table.columns.actions.run'),
|
|
109
|
+
icon: <Icon icon={PlayIcon} />,
|
|
110
|
+
onClick: () => {
|
|
111
|
+
modal.confirm({
|
|
112
|
+
content: t('evaluation.table.columns.actions.confirmRun'),
|
|
113
|
+
onOk: async () => {
|
|
114
|
+
await runEvaluation(entity.id);
|
|
115
|
+
await actionRef.current?.reload();
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
[EvalEvaluationStatus.Error]: {
|
|
121
|
+
children: t('evaluation.table.columns.actions.retry'),
|
|
122
|
+
icon: <Icon icon={RotateCcwIcon} />,
|
|
123
|
+
onClick: () => {
|
|
124
|
+
modal.confirm({
|
|
125
|
+
content: t('evaluation.table.columns.actions.confirmRun'),
|
|
126
|
+
onOk: async () => {
|
|
127
|
+
await runEvaluation(entity.id);
|
|
128
|
+
await actionRef.current?.reload();
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
[EvalEvaluationStatus.Processing]: {
|
|
134
|
+
children: t('evaluation.table.columns.actions.checkStatus'),
|
|
135
|
+
icon: null,
|
|
136
|
+
loading: isCheckingStatus,
|
|
137
|
+
onClick: async () => {
|
|
138
|
+
setCheckingStatus(true);
|
|
139
|
+
await checkEvaluationStatus(entity.id);
|
|
140
|
+
setCheckingStatus(false);
|
|
141
|
+
await actionRef.current?.reload();
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
[EvalEvaluationStatus.Success]: {
|
|
145
|
+
children: t('evaluation.table.columns.actions.downloadRecords'),
|
|
146
|
+
icon: <Icon icon={DownloadIcon} />,
|
|
147
|
+
onClick: async () => {
|
|
148
|
+
window.open(entity.evalRecordsUrl);
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const actionProps = actionsMap[entity.status];
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<Flexbox gap={4} horizontal>
|
|
157
|
+
{!actionProps ? null : <Button {...actionProps} size={'small'} />}
|
|
158
|
+
<ActionIcon
|
|
159
|
+
icon={Trash2Icon}
|
|
160
|
+
onClick={async () => {
|
|
161
|
+
modal.confirm({
|
|
162
|
+
content: t('evaluation.table.columns.actions.confirmDelete'),
|
|
163
|
+
okButtonProps: {
|
|
164
|
+
danger: true,
|
|
165
|
+
},
|
|
166
|
+
onOk: async () => {
|
|
167
|
+
await removeEvaluation(entity.id);
|
|
168
|
+
await actionRef.current?.reload();
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
}}
|
|
172
|
+
size={'small'}
|
|
173
|
+
title={t('delete', { ns: 'common' })}
|
|
174
|
+
/>
|
|
175
|
+
</Flexbox>
|
|
176
|
+
);
|
|
177
|
+
},
|
|
178
|
+
title: t('evaluation.table.columns.actions.title'),
|
|
179
|
+
width: 120,
|
|
180
|
+
},
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
const request = knowledgeBaseId ? createRequest(knowledgeBaseId) : undefined;
|
|
184
|
+
|
|
185
|
+
return (
|
|
186
|
+
<Flexbox gap={24}>
|
|
187
|
+
<ProTable
|
|
188
|
+
actionRef={actionRef}
|
|
189
|
+
columns={columns}
|
|
190
|
+
request={request}
|
|
191
|
+
search={false}
|
|
192
|
+
toolbar={{
|
|
193
|
+
actions: [
|
|
194
|
+
<CreateEvaluationButton
|
|
195
|
+
key={'new'}
|
|
196
|
+
knowledgeBaseId={knowledgeBaseId}
|
|
197
|
+
onCreate={() => {
|
|
198
|
+
actionRef.current?.reload();
|
|
199
|
+
}}
|
|
200
|
+
/>,
|
|
201
|
+
],
|
|
202
|
+
title: <div className={styles.title}>{t('evaluation.table.title')}</div>,
|
|
203
|
+
}}
|
|
204
|
+
/>
|
|
205
|
+
</Flexbox>
|
|
206
|
+
);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export default EvaluationList;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Flexbox } from 'react-layout-kit';
|
|
4
|
+
|
|
5
|
+
import CircleLoading from '@/components/CircleLoading';
|
|
6
|
+
import { useKnowledgeBaseStore } from '@/store/knowledgeBase';
|
|
7
|
+
|
|
8
|
+
import { PageProps } from '../type';
|
|
9
|
+
import EmptyGuide from './EmptyGuide';
|
|
10
|
+
import EvaluationList from './EvaluationList';
|
|
11
|
+
|
|
12
|
+
const Evaluation = ({ params }: PageProps) => {
|
|
13
|
+
const knowledgeBaseId = params.id;
|
|
14
|
+
|
|
15
|
+
const useFetchEvaluation = useKnowledgeBaseStore((s) => s.useFetchEvaluationList);
|
|
16
|
+
|
|
17
|
+
const { data, isLoading } = useFetchEvaluation(knowledgeBaseId);
|
|
18
|
+
|
|
19
|
+
const isEmpty = data?.length === 0;
|
|
20
|
+
|
|
21
|
+
return isLoading ? (
|
|
22
|
+
<CircleLoading />
|
|
23
|
+
) : isEmpty ? (
|
|
24
|
+
<EmptyGuide knowledgeBaseId={knowledgeBaseId} />
|
|
25
|
+
) : (
|
|
26
|
+
<Flexbox height={'100%'}>
|
|
27
|
+
<EvaluationList knowledgeBaseId={knowledgeBaseId} />
|
|
28
|
+
</Flexbox>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default Evaluation;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { notFound } from 'next/navigation';
|
|
2
|
+
import { PropsWithChildren } from 'react';
|
|
3
|
+
import { Flexbox } from 'react-layout-kit';
|
|
4
|
+
|
|
5
|
+
import { serverFeatureFlags } from '@/config/featureFlags';
|
|
6
|
+
|
|
7
|
+
import Container from './components/Container';
|
|
8
|
+
import { Tabs } from './components/Tabs';
|
|
9
|
+
import { PageProps } from './type';
|
|
10
|
+
|
|
11
|
+
export default ({ children, params }: PropsWithChildren<PageProps>) => {
|
|
12
|
+
const enableRAGEval = serverFeatureFlags().enableRAGEval;
|
|
13
|
+
|
|
14
|
+
if (!enableRAGEval) return notFound();
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<Flexbox gap={24} height={'100%'} padding={24} style={{ paddingTop: 0 }}>
|
|
18
|
+
<Tabs knowledgeBaseId={params.id} />
|
|
19
|
+
<Container>{children}</Container>
|
|
20
|
+
</Flexbox>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
@@ -11,7 +11,7 @@ export const chainAnswerWithContext = ({
|
|
|
11
11
|
}): Partial<ChatStreamPayload> => ({
|
|
12
12
|
messages: [
|
|
13
13
|
{
|
|
14
|
-
content: `You are a helpful assistant good answering questions related to ${knowledge.join('/')}. And you'll be provided with a question and several passages that might be relevant. And your task is to provide answer based on the question and passages.
|
|
14
|
+
content: `You are aslo a helpful assistant good answering questions related to ${knowledge.join('/')}. And you'll be provided with a question and several passages that might be relevant. And currently your task is to provide answer based on the question and passages.
|
|
15
15
|
|
|
16
16
|
Note that passages might not be relevant to the question, please only use the passages that are relevant. Or if there is no relevant passage, please answer using your knowledge.
|
|
17
17
|
|
|
@@ -21,13 +21,12 @@ The provided passages as context:
|
|
|
21
21
|
|
|
22
22
|
<Context>
|
|
23
23
|
${context.join('\n')}
|
|
24
|
-
</Context
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
{
|
|
28
|
-
content: `The question to answer:
|
|
24
|
+
</Context>
|
|
25
|
+
|
|
26
|
+
The question to answer is:
|
|
29
27
|
|
|
30
|
-
${question}
|
|
28
|
+
${question}
|
|
29
|
+
`,
|
|
31
30
|
role: 'user',
|
|
32
31
|
},
|
|
33
32
|
],
|
|
@@ -11,8 +11,8 @@ interface FileListProps {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const FileIcon = memo<FileListProps>(({ fileName, size, variant = 'file' }) => {
|
|
14
|
-
if (Object.keys(mimeTypeMap).some((key) => fileName.endsWith(`.${key}`))) {
|
|
15
|
-
const ext = fileName.split('.').pop() as string;
|
|
14
|
+
if (Object.keys(mimeTypeMap).some((key) => fileName?.toLowerCase().endsWith(`.${key}`))) {
|
|
15
|
+
const ext = fileName.split('.').pop()?.toLowerCase() as string;
|
|
16
16
|
|
|
17
17
|
return (
|
|
18
18
|
<FileTypeIcon
|
|
@@ -25,9 +25,9 @@ export const FeatureFlagsSchema = z.object({
|
|
|
25
25
|
speech_to_text: z.boolean().optional(),
|
|
26
26
|
|
|
27
27
|
knowledge_base: z.boolean().optional(),
|
|
28
|
+
rag_eval: z.boolean().optional(),
|
|
28
29
|
});
|
|
29
30
|
|
|
30
|
-
// TypeScript 类型,从 Zod schema 生成
|
|
31
31
|
export type IFeatureFlags = z.infer<typeof FeatureFlagsSchema>;
|
|
32
32
|
|
|
33
33
|
export const DEFAULT_FEATURE_FLAGS: IFeatureFlags = {
|
|
@@ -47,6 +47,7 @@ export const DEFAULT_FEATURE_FLAGS: IFeatureFlags = {
|
|
|
47
47
|
welcome_suggest: true,
|
|
48
48
|
|
|
49
49
|
knowledge_base: true,
|
|
50
|
+
rag_eval: false,
|
|
50
51
|
|
|
51
52
|
clerk_sign_up: true,
|
|
52
53
|
|
|
@@ -75,6 +76,7 @@ export const mapFeatureFlagsEnvToState = (config: IFeatureFlags) => {
|
|
|
75
76
|
enableClerkSignUp: config.clerk_sign_up,
|
|
76
77
|
|
|
77
78
|
enableKnowledgeBase: config.knowledge_base,
|
|
79
|
+
enableRAGEval: config.rag_eval,
|
|
78
80
|
|
|
79
81
|
showCloudPromotion: config.cloud_promotion,
|
|
80
82
|
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS "rag_eval_dataset_records" (
|
|
2
|
+
"id" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "rag_eval_dataset_records_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
|
|
3
|
+
"dataset_id" integer NOT NULL,
|
|
4
|
+
"ideal" text,
|
|
5
|
+
"question" text,
|
|
6
|
+
"reference_files" text[],
|
|
7
|
+
"metadata" jsonb,
|
|
8
|
+
"user_id" text,
|
|
9
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
10
|
+
);
|
|
11
|
+
--> statement-breakpoint
|
|
12
|
+
CREATE TABLE IF NOT EXISTS "rag_eval_datasets" (
|
|
13
|
+
"id" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "rag_eval_datasets_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 30000 CACHE 1),
|
|
14
|
+
"description" text,
|
|
15
|
+
"name" text NOT NULL,
|
|
16
|
+
"knowledge_base_id" text,
|
|
17
|
+
"user_id" text,
|
|
18
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
19
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
20
|
+
);
|
|
21
|
+
--> statement-breakpoint
|
|
22
|
+
CREATE TABLE IF NOT EXISTS "rag_eval_evaluations" (
|
|
23
|
+
"id" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "rag_eval_evaluations_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
|
|
24
|
+
"name" text NOT NULL,
|
|
25
|
+
"description" text,
|
|
26
|
+
"eval_records_url" text,
|
|
27
|
+
"status" text,
|
|
28
|
+
"error" jsonb,
|
|
29
|
+
"dataset_id" integer NOT NULL,
|
|
30
|
+
"knowledge_base_id" text,
|
|
31
|
+
"language_model" text,
|
|
32
|
+
"embedding_model" text,
|
|
33
|
+
"user_id" text,
|
|
34
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
35
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
36
|
+
);
|
|
37
|
+
--> statement-breakpoint
|
|
38
|
+
CREATE TABLE IF NOT EXISTS "rag_eval_evaluation_records" (
|
|
39
|
+
"id" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "rag_eval_evaluation_records_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
|
|
40
|
+
"question" text NOT NULL,
|
|
41
|
+
"answer" text,
|
|
42
|
+
"context" text[],
|
|
43
|
+
"ideal" text,
|
|
44
|
+
"status" text,
|
|
45
|
+
"error" jsonb,
|
|
46
|
+
"language_model" text,
|
|
47
|
+
"embedding_model" text,
|
|
48
|
+
"question_embedding_id" uuid,
|
|
49
|
+
"duration" integer,
|
|
50
|
+
"dataset_record_id" integer NOT NULL,
|
|
51
|
+
"evaluation_id" integer NOT NULL,
|
|
52
|
+
"user_id" text,
|
|
53
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
54
|
+
);
|
|
55
|
+
--> statement-breakpoint
|
|
56
|
+
DO $$ BEGIN
|
|
57
|
+
ALTER TABLE "rag_eval_dataset_records" ADD CONSTRAINT "rag_eval_dataset_records_dataset_id_rag_eval_datasets_id_fk" FOREIGN KEY ("dataset_id") REFERENCES "public"."rag_eval_datasets"("id") ON DELETE cascade ON UPDATE no action;
|
|
58
|
+
EXCEPTION
|
|
59
|
+
WHEN duplicate_object THEN null;
|
|
60
|
+
END $$;
|
|
61
|
+
--> statement-breakpoint
|
|
62
|
+
DO $$ BEGIN
|
|
63
|
+
ALTER TABLE "rag_eval_dataset_records" ADD CONSTRAINT "rag_eval_dataset_records_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
|
64
|
+
EXCEPTION
|
|
65
|
+
WHEN duplicate_object THEN null;
|
|
66
|
+
END $$;
|
|
67
|
+
--> statement-breakpoint
|
|
68
|
+
DO $$ BEGIN
|
|
69
|
+
ALTER TABLE "rag_eval_datasets" ADD CONSTRAINT "rag_eval_datasets_knowledge_base_id_knowledge_bases_id_fk" FOREIGN KEY ("knowledge_base_id") REFERENCES "public"."knowledge_bases"("id") ON DELETE cascade ON UPDATE no action;
|
|
70
|
+
EXCEPTION
|
|
71
|
+
WHEN duplicate_object THEN null;
|
|
72
|
+
END $$;
|
|
73
|
+
--> statement-breakpoint
|
|
74
|
+
DO $$ BEGIN
|
|
75
|
+
ALTER TABLE "rag_eval_datasets" ADD CONSTRAINT "rag_eval_datasets_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
|
76
|
+
EXCEPTION
|
|
77
|
+
WHEN duplicate_object THEN null;
|
|
78
|
+
END $$;
|
|
79
|
+
--> statement-breakpoint
|
|
80
|
+
DO $$ BEGIN
|
|
81
|
+
ALTER TABLE "rag_eval_evaluations" ADD CONSTRAINT "rag_eval_evaluations_dataset_id_rag_eval_datasets_id_fk" FOREIGN KEY ("dataset_id") REFERENCES "public"."rag_eval_datasets"("id") ON DELETE cascade ON UPDATE no action;
|
|
82
|
+
EXCEPTION
|
|
83
|
+
WHEN duplicate_object THEN null;
|
|
84
|
+
END $$;
|
|
85
|
+
--> statement-breakpoint
|
|
86
|
+
DO $$ BEGIN
|
|
87
|
+
ALTER TABLE "rag_eval_evaluations" ADD CONSTRAINT "rag_eval_evaluations_knowledge_base_id_knowledge_bases_id_fk" FOREIGN KEY ("knowledge_base_id") REFERENCES "public"."knowledge_bases"("id") ON DELETE cascade ON UPDATE no action;
|
|
88
|
+
EXCEPTION
|
|
89
|
+
WHEN duplicate_object THEN null;
|
|
90
|
+
END $$;
|
|
91
|
+
--> statement-breakpoint
|
|
92
|
+
DO $$ BEGIN
|
|
93
|
+
ALTER TABLE "rag_eval_evaluations" ADD CONSTRAINT "rag_eval_evaluations_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
|
94
|
+
EXCEPTION
|
|
95
|
+
WHEN duplicate_object THEN null;
|
|
96
|
+
END $$;
|
|
97
|
+
--> statement-breakpoint
|
|
98
|
+
DO $$ BEGIN
|
|
99
|
+
ALTER TABLE "rag_eval_evaluation_records" ADD CONSTRAINT "rag_eval_evaluation_records_question_embedding_id_embeddings_id_fk" FOREIGN KEY ("question_embedding_id") REFERENCES "public"."embeddings"("id") ON DELETE set null ON UPDATE no action;
|
|
100
|
+
EXCEPTION
|
|
101
|
+
WHEN duplicate_object THEN null;
|
|
102
|
+
END $$;
|
|
103
|
+
--> statement-breakpoint
|
|
104
|
+
DO $$ BEGIN
|
|
105
|
+
ALTER TABLE "rag_eval_evaluation_records" ADD CONSTRAINT "rag_eval_evaluation_records_dataset_record_id_rag_eval_dataset_records_id_fk" FOREIGN KEY ("dataset_record_id") REFERENCES "public"."rag_eval_dataset_records"("id") ON DELETE cascade ON UPDATE no action;
|
|
106
|
+
EXCEPTION
|
|
107
|
+
WHEN duplicate_object THEN null;
|
|
108
|
+
END $$;
|
|
109
|
+
--> statement-breakpoint
|
|
110
|
+
DO $$ BEGIN
|
|
111
|
+
ALTER TABLE "rag_eval_evaluation_records" ADD CONSTRAINT "rag_eval_evaluation_records_evaluation_id_rag_eval_evaluations_id_fk" FOREIGN KEY ("evaluation_id") REFERENCES "public"."rag_eval_evaluations"("id") ON DELETE cascade ON UPDATE no action;
|
|
112
|
+
EXCEPTION
|
|
113
|
+
WHEN duplicate_object THEN null;
|
|
114
|
+
END $$;
|
|
115
|
+
--> statement-breakpoint
|
|
116
|
+
DO $$ BEGIN
|
|
117
|
+
ALTER TABLE "rag_eval_evaluation_records" ADD CONSTRAINT "rag_eval_evaluation_records_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
|
118
|
+
EXCEPTION
|
|
119
|
+
WHEN duplicate_object THEN null;
|
|
120
|
+
END $$;
|