diff --git a/document/content/docs/upgrading/4-14/4144.mdx b/document/content/docs/upgrading/4-14/4144.mdx index b33db70cf..a131f498d 100644 --- a/document/content/docs/upgrading/4-14/4144.mdx +++ b/document/content/docs/upgrading/4-14/4144.mdx @@ -31,6 +31,7 @@ curl --location --request POST 'https://{{host}}/api/admin/initv4144' \ 5. 新版订阅套餐逻辑。 6. 支持配置对话文件白名单。 7. S3 支持 pathStyle 配置。 +8. 支持通过 Sealos 来进行多租户自定义域名配置。 ## ⚙️ 优化 diff --git a/document/data/doc-last-modified.json b/document/data/doc-last-modified.json index 16a9e93d2..86afd48fd 100644 --- a/document/data/doc-last-modified.json +++ b/document/data/doc-last-modified.json @@ -199,6 +199,6 @@ "document/content/docs/use-cases/external-integration/feishu.mdx": "2025-07-24T14:23:04+08:00", "document/content/docs/use-cases/external-integration/official_account.mdx": "2025-08-05T23:20:39+08:00", "document/content/docs/use-cases/external-integration/openapi.mdx": "2025-09-29T11:34:11+08:00", - "document/content/docs/use-cases/external-integration/wecom.mdx": "2025-12-09T18:14:22+08:00", + "document/content/docs/use-cases/external-integration/wecom.mdx": "2025-12-09T20:03:29+08:00", "document/content/docs/use-cases/index.mdx": "2025-07-24T14:23:04+08:00" } \ No newline at end of file diff --git a/packages/global/common/file/tools.ts b/packages/global/common/file/tools.ts index ca31c2c50..7f2cb981e 100644 --- a/packages/global/common/file/tools.ts +++ b/packages/global/common/file/tools.ts @@ -1,5 +1,5 @@ import { detect } from 'jschardet'; -import { documentFileType } from './constants'; +import { imageFileType } from './constants'; import { ChatFileTypeEnum } from '../../core/chat/constants'; import { type UserChatItemFileItemType } from '../../core/chat/type'; import * as fs from 'fs'; @@ -66,18 +66,17 @@ export const parseUrlToFileType = (url: string): UserChatItemFileItemType | unde })(); const extension = filename?.split('.').pop()?.toLowerCase() || ''; - // If it's a document type, return as file, otherwise treat as image - if (extension && documentFileType.includes(extension)) { + if (extension && imageFileType.includes(extension)) { + // Default to file type for non-extension files return { - type: ChatFileTypeEnum.file, + type: ChatFileTypeEnum.image, name: filename || 'null', url }; } - - // Default to file type for non-extension files + // If it's a document type, return as file, otherwise treat as image return { - type: ChatFileTypeEnum.image, + type: ChatFileTypeEnum.file, name: filename || 'null', url }; diff --git a/packages/service/common/s3/buckets/base.ts b/packages/service/common/s3/buckets/base.ts index 3242e3a70..ddebe451c 100644 --- a/packages/service/common/s3/buckets/base.ts +++ b/packages/service/common/s3/buckets/base.ts @@ -62,7 +62,9 @@ export class S3BaseBucket { await this.options.afterInit?.(); console.log(`S3 init success: ${this.name}`); }; - init(); + if (this.options.init) { + init(); + } } get name(): string { diff --git a/packages/service/common/s3/constants.ts b/packages/service/common/s3/constants.ts index 7b9b7c5bd..65be2f896 100644 --- a/packages/service/common/s3/constants.ts +++ b/packages/service/common/s3/constants.ts @@ -28,6 +28,7 @@ export const Mimes = { export const defaultS3Options: { externalBaseURL?: string; afterInit?: () => Promise | void; + init?: boolean; } & ClientOptions = { useSSL: process.env.S3_USE_SSL === 'true', endPoint: process.env.S3_ENDPOINT || 'localhost', diff --git a/packages/service/common/s3/index.ts b/packages/service/common/s3/index.ts index 6e6729efd..012d31bf3 100644 --- a/packages/service/common/s3/index.ts +++ b/packages/service/common/s3/index.ts @@ -4,8 +4,8 @@ import { addLog } from '../system/log'; import { startS3DelWorker } from './mq'; export function initS3Buckets() { - const publicBucket = new S3PublicBucket(); - const privateBucket = new S3PrivateBucket(); + const publicBucket = new S3PublicBucket({ init: true }); + const privateBucket = new S3PrivateBucket({ init: true }); global.s3BucketMap = { [publicBucket.name]: publicBucket, diff --git a/packages/service/common/s3/sources/avatar.ts b/packages/service/common/s3/sources/avatar.ts index bfa179e32..6661d504e 100644 --- a/packages/service/common/s3/sources/avatar.ts +++ b/packages/service/common/s3/sources/avatar.ts @@ -7,16 +7,11 @@ import { getFileS3Key } from '../utils'; class S3AvatarSource { private bucket: S3PublicBucket; - private static instance: S3AvatarSource; constructor() { this.bucket = new S3PublicBucket(); } - static getInstance() { - return (this.instance ??= new S3AvatarSource()); - } - get prefix(): string { return imageBaseUrl; } @@ -89,5 +84,13 @@ class S3AvatarSource { } export function getS3AvatarSource() { - return S3AvatarSource.getInstance(); + if (global.avatarBucket) { + return global.avatarBucket; + } + global.avatarBucket = new S3AvatarSource(); + return global.avatarBucket; +} + +declare global { + var avatarBucket: S3AvatarSource; } diff --git a/packages/service/common/s3/sources/chat/index.ts b/packages/service/common/s3/sources/chat/index.ts index 5c86bad86..22463baf2 100644 --- a/packages/service/common/s3/sources/chat/index.ts +++ b/packages/service/common/s3/sources/chat/index.ts @@ -16,16 +16,11 @@ import { getFileS3Key } from '../../utils'; export class S3ChatSource { private bucket: S3PrivateBucket; - private static instance: S3ChatSource; constructor() { this.bucket = new S3PrivateBucket(); } - static getInstance() { - return (this.instance ??= new S3ChatSource()); - } - static parseChatUrl(url: string | URL) { try { const parseUrl = new URL(url); @@ -131,5 +126,13 @@ export class S3ChatSource { } export function getS3ChatSource() { - return S3ChatSource.getInstance(); + if (global.chatBucket) { + return global.chatBucket; + } + global.chatBucket = new S3ChatSource(); + return global.chatBucket; +} + +declare global { + var chatBucket: S3ChatSource; } diff --git a/packages/service/common/s3/sources/dataset/index.ts b/packages/service/common/s3/sources/dataset/index.ts index e8367b769..2acd2cd7e 100644 --- a/packages/service/common/s3/sources/dataset/index.ts +++ b/packages/service/common/s3/sources/dataset/index.ts @@ -29,16 +29,11 @@ import { S3Error } from 'minio'; export class S3DatasetSource { public bucket: S3PrivateBucket; - private static instance: S3DatasetSource; constructor() { this.bucket = new S3PrivateBucket(); } - static getInstance() { - return (this.instance ??= new S3DatasetSource()); - } - // 下载链接 async createGetDatasetFileURL(params: CreateGetDatasetFileURLParams) { const { key, expiredHours, external } = CreateGetDatasetFileURLParamsSchema.parse(params); @@ -260,5 +255,13 @@ export class S3DatasetSource { } export function getS3DatasetSource() { - return S3DatasetSource.getInstance(); + if (global.datasetBucket) { + return global.datasetBucket; + } + global.datasetBucket = new S3DatasetSource(); + return global.datasetBucket; +} + +declare global { + var datasetBucket: S3DatasetSource; } diff --git a/packages/service/core/workflow/dispatch/tools/readFiles.ts b/packages/service/core/workflow/dispatch/tools/readFiles.ts index 62f79911d..565d27a94 100644 --- a/packages/service/core/workflow/dispatch/tools/readFiles.ts +++ b/packages/service/core/workflow/dispatch/tools/readFiles.ts @@ -207,23 +207,18 @@ export const getFileContentFromLinks = async ({ // Get file name const { filename, extension, imageParsePrefix } = (() => { - const contentDisposition = response.headers['content-disposition']; - if (contentDisposition) { + if (isChatExternalUrl) { + const contentDisposition = response.headers['content-disposition'] || ''; 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: 需要根据是否是聊天对话里面的外部链接来决定 - }; - } - } + const matchFilename = + matches != null && matches[1] ? matches[1].replace(/['"]/g, '') : ''; - if (isChatExternalUrl) { - const filename = urlObj.pathname.split('/').pop() || 'file'; + const filename = decodeURIComponent( + matchFilename || urlObj.pathname.split('/').pop() || 'file' + ); const extension = path.extname(filename).replace('.', ''); + return { filename, extension,