mirror of
https://github.com/labring/FastGPT.git
synced 2026-05-05 01:02:59 +08:00
feat: custom domain (#6067)
* perf: faq * index * delete dataset * delete dataset * perf: delete dataset * init * fix: faq * doc * fix: share link auth (#6063) * standard plan add custom domain config (#6061) * standard plan add custom domain config * bill detail modal * perf: vector count api * feat: custom domain & wecom bot SaaS integration (#6047) * feat: custom Domain type define * feat: custom domain * feat: wecom custom domain * chore: i18n * chore: i18n; team auth * feat: wecom multi-model message support * chore: wecom edit modal * chore(doc): custom domain && wecom bot * fix: type * fix: type * fix: file detect * feat: fe * fix: img name * fix: test * compress img * rename * editor initial status * fix: chat url * perf: s3 upload by buffer * img * refresh * fix: custom domain selector (#6069) * empty tip * perf: s3 init * sort provider * fix: extend * perf: extract filename --------- Co-authored-by: Roy <whoeverimf5@gmail.com> Co-authored-by: heheer <heheer@sealos.io> Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
This commit is contained in:
@@ -126,7 +126,6 @@ const AppSchema = new Schema(
|
||||
}
|
||||
);
|
||||
|
||||
AppSchema.index({ type: 1 });
|
||||
AppSchema.index({ teamId: 1, updateTime: -1 });
|
||||
AppSchema.index({ teamId: 1, type: 1 });
|
||||
AppSchema.index(
|
||||
@@ -137,5 +136,7 @@ AppSchema.index(
|
||||
}
|
||||
}
|
||||
);
|
||||
// Admin count
|
||||
AppSchema.index({ type: 1 });
|
||||
|
||||
export const MongoApp = getMongoModel<AppType>(AppCollectionName, AppSchema);
|
||||
|
||||
@@ -96,40 +96,20 @@ export async function delDatasetRelevantData({
|
||||
datasetId: { $in: datasetIds }
|
||||
});
|
||||
|
||||
// Delete dataset_data_texts in batches by datasetId
|
||||
for (const datasetId of datasetIds) {
|
||||
// Delete dataset_data_texts in batches by datasetId
|
||||
await MongoDatasetDataText.deleteMany({
|
||||
teamId,
|
||||
datasetId
|
||||
}).maxTimeMS(300000); // Reduce timeout for single batch
|
||||
}
|
||||
// Delete dataset_datas in batches by datasetId
|
||||
for (const datasetId of datasetIds) {
|
||||
await MongoDatasetData.deleteMany({
|
||||
teamId,
|
||||
datasetId
|
||||
}).maxTimeMS(300000);
|
||||
}
|
||||
|
||||
await delCollectionRelatedSource({ collections });
|
||||
// Delete vector data
|
||||
await deleteDatasetDataVector({ teamId, datasetIds });
|
||||
|
||||
// Delete dataset_data_texts in batches by datasetId
|
||||
for (const datasetId of datasetIds) {
|
||||
await MongoDatasetDataText.deleteMany({
|
||||
teamId,
|
||||
datasetId
|
||||
}).maxTimeMS(300000); // Reduce timeout for single batch
|
||||
}
|
||||
// Delete dataset_datas in batches by datasetId
|
||||
for (const datasetId of datasetIds) {
|
||||
// Delete dataset_datas in batches by datasetId
|
||||
await MongoDatasetData.deleteMany({
|
||||
teamId,
|
||||
datasetId
|
||||
}).maxTimeMS(300000);
|
||||
}
|
||||
|
||||
// Delete source: 兼容旧版的图片
|
||||
await delCollectionRelatedSource({ collections });
|
||||
// Delete vector data
|
||||
await deleteDatasetDataVector({ teamId, datasetIds });
|
||||
|
||||
@@ -148,7 +148,7 @@ const DatasetSchema = new Schema({
|
||||
|
||||
try {
|
||||
DatasetSchema.index({ teamId: 1 });
|
||||
DatasetSchema.index({ type: 1 });
|
||||
DatasetSchema.index({ type: 1 }); // Admin count
|
||||
DatasetSchema.index({ deleteTime: 1 }); // 添加软删除字段索引
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
@@ -179,13 +179,13 @@ export const getFileContentFromLinks = async ({
|
||||
sourceId: url,
|
||||
customPdfParse
|
||||
});
|
||||
if (rawTextBuffer) {
|
||||
return formatResponseObject({
|
||||
filename: rawTextBuffer.filename || url,
|
||||
url,
|
||||
content: rawTextBuffer.text
|
||||
});
|
||||
}
|
||||
// if (rawTextBuffer) {
|
||||
// return formatResponseObject({
|
||||
// filename: rawTextBuffer.filename || url,
|
||||
// url,
|
||||
// content: rawTextBuffer.text
|
||||
// });
|
||||
// }
|
||||
|
||||
try {
|
||||
if (isInternalAddress(url)) {
|
||||
@@ -207,23 +207,39 @@ export const getFileContentFromLinks = async ({
|
||||
|
||||
// Get file name
|
||||
const { filename, extension, imageParsePrefix } = (() => {
|
||||
const contentDisposition = response.headers['content-disposition'];
|
||||
if (contentDisposition) {
|
||||
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
|
||||
const matches = filenameRegex.exec(contentDisposition);
|
||||
if (matches != null && matches[1]) {
|
||||
const filename = decodeURIComponent(matches[1].replace(/['"]/g, ''));
|
||||
return {
|
||||
filename,
|
||||
extension: path.extname(filename).replace('.', ''),
|
||||
imageParsePrefix: `` // TODO: 需要根据是否是聊天对话里面的外部链接来决定
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (isChatExternalUrl) {
|
||||
const filename = urlObj.pathname.split('/').pop() || 'file';
|
||||
const contentDisposition = response.headers['content-disposition'] || '';
|
||||
|
||||
// Priority: filename* (RFC 5987, UTF-8 encoded) > filename (traditional)
|
||||
const extractFilename = (contentDisposition: string): string => {
|
||||
// Try RFC 5987 filename* first (e.g., filename*=UTF-8''encoded-name)
|
||||
const filenameStarRegex = /filename\*=([^']*)'([^']*)'([^;\n]*)/i;
|
||||
const starMatches = filenameStarRegex.exec(contentDisposition);
|
||||
if (starMatches && starMatches[3]) {
|
||||
const charset = starMatches[1].toLowerCase();
|
||||
const encodedFilename = starMatches[3];
|
||||
// Decode percent-encoded UTF-8 filename
|
||||
try {
|
||||
return decodeURIComponent(encodedFilename);
|
||||
} catch (error) {
|
||||
addLog.warn('Failed to decode filename*', { encodedFilename, error });
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to traditional filename parameter
|
||||
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/i;
|
||||
const matches = filenameRegex.exec(contentDisposition);
|
||||
if (matches && matches[1]) {
|
||||
return matches[1].replace(/['"]/g, '');
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
const matchFilename = extractFilename(contentDisposition);
|
||||
const filename = matchFilename || urlObj.pathname.split('/').pop() || 'file';
|
||||
const extension = path.extname(filename).replace('.', '');
|
||||
|
||||
return {
|
||||
filename,
|
||||
extension,
|
||||
|
||||
Reference in New Issue
Block a user