Skip to content

Commit 2261af9

Browse files
author
dreamer6680
committed
support feishuPrivateDataset
1 parent 4376de6 commit 2261af9

File tree

42 files changed

+694
-68
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+694
-68
lines changed

packages/global/common/system/types/index.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ export type FastGPTFeConfigsType = {
7373
show_dataset_enhance?: boolean;
7474
show_batch_eval?: boolean;
7575

76+
feishu_auth_robot_client_id?: string;
77+
feishu_auth_robot_client_secret?: string;
78+
7679
concatMd?: string;
7780
docUrl?: string;
7881
openAPIDocUrl?: string;

packages/global/core/dataset/api.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export type DatasetUpdateBody = {
2828
yuqueServer?: DatasetSchemaType['yuqueServer'];
2929
feishuShareServer?: DatasetSchemaType['feishuShareServer'];
3030
feishuKnowledgeServer?: DatasetSchemaType['feishuKnowledgeServer'];
31+
feishuPrivateServer?: DatasetSchemaType['feishuPrivateServer'];
3132
chunkSettings?: DatasetSchemaType['chunkSettings'];
3233

3334
// sync schedule

packages/global/core/dataset/apiDataset.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ export type FeishuKnowledgeServer = {
2828
basePath?: string;
2929
};
3030

31+
export type FeishuPrivateServer = {
32+
user_access_token: string;
33+
refresh_token: string;
34+
outdate_time: number;
35+
basePath?: string;
36+
};
37+
3138
export type YuqueServer = {
3239
userId: string;
3340
token?: string;

packages/global/core/dataset/constants.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export enum DatasetTypeEnum {
99
apiDataset = 'apiDataset',
1010
feishuShare = 'feishuShare',
1111
feishuKnowledge = 'feishuKnowledge',
12+
feishuPrivate = 'feishuPrivate',
1213
yuque = 'yuque'
1314
}
1415
export const DatasetTypeMap = {
@@ -47,6 +48,11 @@ export const DatasetTypeMap = {
4748
label: i18nT('dataset:feishu_knowledge_dataset'),
4849
collectionLabel: i18nT('common:File')
4950
},
51+
[DatasetTypeEnum.feishuPrivate]: {
52+
icon: 'core/dataset/feishuPrivateDatasetOutline',
53+
label: i18nT('dataset:feishu_private_dataset'),
54+
collectionLabel: i18nT('common:File')
55+
},
5056
[DatasetTypeEnum.yuque]: {
5157
icon: 'core/dataset/yuqueDatasetOutline',
5258
label: i18nT('dataset:yuque_dataset'),

packages/global/core/dataset/type.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ import type {
1717
APIFileServer,
1818
FeishuShareServer,
1919
YuqueServer,
20-
FeishuKnowledgeServer
20+
FeishuKnowledgeServer,
21+
FeishuPrivateServer
2122
} from './apiDataset';
2223
import type { SourceMemberType } from 'support/user/type';
2324
import type { DatasetDataIndexTypeEnum } from './data/constants';
@@ -81,6 +82,7 @@ export type DatasetSchemaType = {
8182
feishuShareServer?: FeishuShareServer;
8283
yuqueServer?: YuqueServer;
8384
feishuKnowledgeServer?: FeishuKnowledgeServer;
85+
feishuPrivateServer?: FeishuPrivateServer;
8486

8587
// abandon
8688
autoSync?: boolean;

packages/service/common/api/type.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ApiDatasetDetailResponse } from '@fastgpt/global/core/dataset/apiDataset';
2-
import { FeishuServer, YuqueServer } from '@fastgpt/global/core/dataset/apiDataset';
2+
import { FeishuShareServer, YuqueServer } from '@fastgpt/global/core/dataset/apiDataset';
33
import type {
44
DeepRagSearchProps,
55
SearchDatasetDataResponse

packages/service/core/dataset/apiDataset/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,24 @@ import type {
22
APIFileServer,
33
YuqueServer,
44
FeishuShareServer,
5-
FeishuKnowledgeServer
5+
FeishuKnowledgeServer,
6+
FeishuPrivateServer
67
} from '@fastgpt/global/core/dataset/apiDataset';
78
import { useApiDatasetRequest } from './api';
89
import { useYuqueDatasetRequest } from '../yuqueDataset/api';
910
import { useFeishuShareDatasetRequest } from '../feishuShareDataset/api';
1011
import { useFeishuKnowledgeDatasetRequest } from '../feishuKnowledgeDataset/api';
12+
import { useFeishuPrivateDatasetRequest } from '../feishuPrivateDataset/api';
1113

1214
export const getApiDatasetRequest = async (data: {
1315
apiServer?: APIFileServer;
1416
yuqueServer?: YuqueServer;
1517
feishuShareServer?: FeishuShareServer;
1618
feishuKnowledgeServer?: FeishuKnowledgeServer;
19+
feishuPrivateServer?: FeishuPrivateServer;
1720
}) => {
18-
const { apiServer, yuqueServer, feishuShareServer, feishuKnowledgeServer } = data;
21+
const { apiServer, yuqueServer, feishuShareServer, feishuKnowledgeServer, feishuPrivateServer } =
22+
data;
1923

2024
if (apiServer) {
2125
return useApiDatasetRequest({ apiServer });
@@ -29,5 +33,8 @@ export const getApiDatasetRequest = async (data: {
2933
if (feishuKnowledgeServer) {
3034
return useFeishuKnowledgeDatasetRequest({ feishuKnowledgeServer });
3135
}
36+
if (feishuPrivateServer) {
37+
return useFeishuPrivateDatasetRequest({ feishuPrivateServer });
38+
}
3239
return Promise.reject('Can not find api dataset server');
3340
};

packages/service/core/dataset/collection/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ export const syncCollection = async (collection: CollectionWithDatasetType) => {
162162
apiServer: dataset.apiServer,
163163
feishuShareServer: dataset.feishuShareServer,
164164
feishuKnowledgeServer: dataset.feishuKnowledgeServer,
165+
feishuPrivateServer: dataset.feishuPrivateServer,
165166
yuqueServer: dataset.yuqueServer
166167
};
167168
})();
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
import type {
2+
APIFileItem,
3+
ApiFileReadContentResponse,
4+
ApiDatasetDetailResponse,
5+
FeishuPrivateServer
6+
} from '@fastgpt/global/core/dataset/apiDataset';
7+
import { type ParentIdType } from '@fastgpt/global/common/parentFolder/type';
8+
import axios, { type Method } from 'axios';
9+
import { addLog } from '../../../common/system/log';
10+
import { preLoadWorker } from 'worker/preload';
11+
12+
type ResponseDataType = {
13+
success: boolean;
14+
message: string;
15+
data: any;
16+
};
17+
18+
type FeishuFileListResponse = {
19+
files: {
20+
token: string;
21+
parent_token: string;
22+
name: string;
23+
type: string;
24+
modified_time: number;
25+
created_time: number;
26+
url: string;
27+
owner_id: string;
28+
shortcut_info?: {
29+
target_token: string;
30+
target_type: string;
31+
};
32+
}[];
33+
has_more: boolean;
34+
next_page_token: string;
35+
};
36+
37+
type FeishuFileDetailResponse = {
38+
code: number;
39+
msg: string;
40+
data: {
41+
name: string;
42+
parentId: string;
43+
};
44+
};
45+
46+
const feishuBaseUrl = process.env.FEISHU_BASE_URL || 'https://open.feishu.cn';
47+
48+
export const useFeishuPrivateDatasetRequest = ({
49+
feishuPrivateServer
50+
}: {
51+
feishuPrivateServer: FeishuPrivateServer;
52+
}) => {
53+
const instance = axios.create({
54+
baseURL: feishuBaseUrl,
55+
timeout: 60000
56+
});
57+
58+
instance.defaults.headers.common['Authorization'] =
59+
`Bearer ${feishuPrivateServer.user_access_token}`;
60+
instance.defaults.headers.common['Content-Type'] = 'application/json; charset=utf-8';
61+
62+
/**
63+
* 响应数据检查
64+
*/
65+
const checkRes = (data: ResponseDataType) => {
66+
if (data === undefined) {
67+
addLog.info('yuque dataset data is empty');
68+
return Promise.reject('服务器异常');
69+
}
70+
return data.data;
71+
};
72+
const responseError = (err: any) => {
73+
console.log('error->', '请求错误', err);
74+
75+
if (!err) {
76+
return Promise.reject({ message: '未知错误' });
77+
}
78+
if (typeof err === 'string') {
79+
return Promise.reject({ message: err });
80+
}
81+
if (typeof err.message === 'string') {
82+
return Promise.reject({ message: err.message });
83+
}
84+
if (typeof err.data === 'string') {
85+
return Promise.reject({ message: err.data });
86+
}
87+
if (err?.response?.data) {
88+
return Promise.reject(err?.response?.data);
89+
}
90+
return Promise.reject(err);
91+
};
92+
93+
const request = <T>(url: string, data: any, method: Method): Promise<T> => {
94+
/* 去空 */
95+
for (const key in data) {
96+
if (data[key] === undefined) {
97+
delete data[key];
98+
}
99+
}
100+
101+
return instance
102+
.request({
103+
url,
104+
method,
105+
data: ['POST', 'PUT'].includes(method) ? data : undefined,
106+
params: !['POST', 'PUT'].includes(method) ? data : undefined
107+
})
108+
.then((res) => checkRes(res.data))
109+
.catch((err) => responseError(err));
110+
};
111+
112+
const listFiles = async ({ parentId }: { parentId?: ParentIdType }): Promise<APIFileItem[]> => {
113+
const fetchFiles = async (
114+
pageToken?: string,
115+
parentId?: ParentIdType
116+
): Promise<FeishuFileListResponse['files']> => {
117+
const data = await request<FeishuFileListResponse>(
118+
`/open-apis/drive/v1/files`,
119+
{
120+
page_size: 200,
121+
page_token: pageToken,
122+
folder_token: parentId ? parentId : undefined
123+
},
124+
'GET'
125+
);
126+
if (data.has_more) {
127+
const nextFiles = await fetchFiles(data.next_page_token);
128+
return [...data.files, ...nextFiles];
129+
}
130+
131+
return data.files;
132+
};
133+
const parent = parentId?.split('-')[1];
134+
135+
const allFiles = await fetchFiles(undefined, parent);
136+
137+
return allFiles
138+
.filter((file) => {
139+
if (file.type === 'shortcut') {
140+
return (
141+
file.shortcut_info?.target_type === 'docx' ||
142+
file.shortcut_info?.target_type === 'folder'
143+
);
144+
}
145+
return file.type === 'folder' || file.type === 'docx';
146+
})
147+
.map((file) => ({
148+
id:
149+
file.type === 'shortcut'
150+
? file.parent_token + '-' + file.shortcut_info!.target_token
151+
: file.parent_token + '-' + file.token,
152+
parentId: parentId,
153+
name: file.name,
154+
type: file.type === 'folder' ? ('folder' as const) : ('file' as const),
155+
hasChild: file.type === 'folder',
156+
updateTime: new Date(file.modified_time * 1000),
157+
createTime: new Date(file.created_time * 1000)
158+
}));
159+
};
160+
161+
const getFileContent = async ({
162+
apiFileId
163+
}: {
164+
apiFileId: string;
165+
}): Promise<ApiFileReadContentResponse> => {
166+
const fileId = apiFileId.split('-')[1];
167+
const [{ content }, { document }] = await Promise.all([
168+
request<{ content: string }>(`/open-apis/docx/v1/documents/${fileId}/raw_content`, {}, 'GET'),
169+
request<{ document: { title: string } }>(`/open-apis/docx/v1/documents/${fileId}`, {}, 'GET')
170+
]);
171+
172+
return {
173+
title: document?.title,
174+
rawText: content
175+
};
176+
};
177+
178+
const getFilePreviewUrl = async ({ apiFileId }: { apiFileId: string }): Promise<string> => {
179+
const fileId = apiFileId.split('-')[1];
180+
const { metas } = await request<{ metas: { url: string }[] }>(
181+
`/open-apis/drive/v1/metas/batch_query`,
182+
{
183+
request_docs: [
184+
{
185+
doc_token: fileId,
186+
doc_type: 'docx'
187+
}
188+
],
189+
with_url: true
190+
},
191+
'POST'
192+
);
193+
194+
return metas[0].url;
195+
};
196+
197+
const getFileDetail = async ({
198+
apiFileId
199+
}: {
200+
apiFileId: string;
201+
}): Promise<ApiDatasetDetailResponse> => {
202+
const parentId = apiFileId.split('-')[0];
203+
const fileId = apiFileId.split('-')[1];
204+
205+
const fileDetail = await request<FeishuFileDetailResponse['data']>(
206+
`/open-apis/drive/explorer/v2/folder/${fileId}/meta`,
207+
{},
208+
'GET'
209+
);
210+
console.log('fileDetail', fileDetail);
211+
if (!fileDetail) {
212+
return {
213+
name: '',
214+
parentId: null,
215+
id: apiFileId
216+
};
217+
}
218+
219+
return {
220+
name: fileDetail?.name,
221+
parentId: null,
222+
id: apiFileId
223+
};
224+
};
225+
226+
return {
227+
getFileContent,
228+
listFiles,
229+
getFilePreviewUrl,
230+
getFileDetail
231+
};
232+
};

0 commit comments

Comments
 (0)