diff --git a/api/apps/kb_app.py b/api/apps/kb_app.py index f173b56a0..53e42303f 100644 --- a/api/apps/kb_app.py +++ b/api/apps/kb_app.py @@ -918,6 +918,6 @@ def check_embedding(): } if summary["avg_cos_sim"] > 0.9: return get_json_result(data={"summary": summary, "results": results}) - return get_json_result(code=RetCode.NOT_EFFECTIVE, message="failed", data={"summary": summary, "results": results}) + return get_json_result(code=RetCode.NOT_EFFECTIVE, message="Embedding model switch failed: the average similarity between old and new vectors is below 0.9, indicating incompatible vector spaces.", data={"summary": summary, "results": results}) diff --git a/common/data_source/blob_connector.py b/common/data_source/blob_connector.py index 0bec7cbe6..9e74a5394 100644 --- a/common/data_source/blob_connector.py +++ b/common/data_source/blob_connector.py @@ -87,6 +87,13 @@ class BlobStorageConnector(LoadConnector, PollConnector): ): raise ConnectorMissingCredentialError("Oracle Cloud Infrastructure") + elif self.bucket_type == BlobType.S3_COMPATIBLE: + if not all( + credentials.get(key) + for key in ["endpoint_url", "aws_access_key_id", "aws_secret_access_key"] + ): + raise ConnectorMissingCredentialError("S3 Compatible Storage") + else: raise ValueError(f"Unsupported bucket type: {self.bucket_type}") diff --git a/common/data_source/config.py b/common/data_source/config.py index 098b5fb54..0c038c6d7 100644 --- a/common/data_source/config.py +++ b/common/data_source/config.py @@ -32,6 +32,7 @@ class BlobType(str, Enum): R2 = "r2" GOOGLE_CLOUD_STORAGE = "google_cloud_storage" OCI_STORAGE = "oci_storage" + S3_COMPATIBLE = "s3_compatible" class DocumentSource(str, Enum): @@ -48,6 +49,7 @@ class DocumentSource(str, Enum): GMAIL = "gmail" DISCORD = "discord" MOODLE = "moodle" + S3_COMPATIBLE = "s3_compatible" class FileOrigin(str, Enum): diff --git a/common/data_source/utils.py b/common/data_source/utils.py index b42c3833b..c079b2b9a 100644 --- a/common/data_source/utils.py +++ b/common/data_source/utils.py @@ -311,6 +311,13 @@ def create_s3_client(bucket_type: BlobType, credentials: dict[str, Any], europea aws_secret_access_key=credentials["secret_access_key"], region_name=credentials["region"], ) + elif bucket_type == BlobType.S3_COMPATIBLE: + return boto3.client( + "s3", + endpoint_url=credentials["endpoint_url"], + aws_access_key_id=credentials["aws_access_key_id"], + aws_secret_access_key=credentials["aws_secret_access_key"], + ) else: raise ValueError(f"Unsupported bucket type: {bucket_type}") diff --git a/web/src/components/dynamic-form.tsx b/web/src/components/dynamic-form.tsx index a90afe287..5c78a1dcb 100644 --- a/web/src/components/dynamic-form.tsx +++ b/web/src/components/dynamic-form.tsx @@ -67,6 +67,7 @@ export interface FormFieldConfig { ) => string | boolean | Promise; dependencies?: string[]; schema?: ZodSchema; + shouldRender?: (formValues: any) => boolean; } // Component props interface @@ -654,6 +655,9 @@ const DynamicForm = { } }; + // Watch all form values to re-render when they change (for shouldRender checks) + const formValues = form.watch(); + return (
<> - {fields.map((field) => ( -
- {renderField(field)} -
- ))} + {fields.map((field) => { + const shouldShow = field.shouldRender + ? field.shouldRender(formValues) + : true; + return ( +
+ {renderField(field)} +
+ ); + })} {children}
diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 4889bfc96..48de4cbf9 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -705,6 +705,8 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s 'The base URL of your Confluence instance (e.g., https://your-domain.atlassian.net/wiki)', s3PrefixTip: `Specify the folder path within your S3 bucket to fetch files from. Example: general/v2/`, + S3CompatibleEndpointUrlTip: `Required for S3 compatible Storage Box. Specify the S3-compatible endpoint URL. +Example: https://fsn1.your-objectstorage.com`, addDataSourceModalTital: 'Create your {{name}} connector', deleteSourceModalTitle: 'Delete data source', deleteSourceModalContent: ` diff --git a/web/src/pages/agent/gobal-variable-sheet/hooks/use-form.tsx b/web/src/pages/agent/gobal-variable-sheet/hooks/use-form.tsx index cb38012f3..54d37957a 100644 --- a/web/src/pages/agent/gobal-variable-sheet/hooks/use-form.tsx +++ b/web/src/pages/agent/gobal-variable-sheet/hooks/use-form.tsx @@ -15,27 +15,30 @@ export const useHandleForm = () => { return value; } }; - const handleSubmit = useCallback(async (fieldValue: FieldValues) => { - const param = { - ...(data.dsl?.variables || {}), - [fieldValue.name]: { - ...fieldValue, - value: - fieldValue.type === TypesWithArray.Object || - fieldValue.type === TypesWithArray.ArrayObject - ? handleObjectData(fieldValue.value) - : fieldValue.value, - }, - } as Record; + const handleSubmit = useCallback( + async (fieldValue: FieldValues) => { + const param = { + ...(data.dsl?.variables || {}), + [fieldValue.name]: { + ...fieldValue, + value: + fieldValue.type === TypesWithArray.Object || + fieldValue.type === TypesWithArray.ArrayObject + ? handleObjectData(fieldValue.value) + : fieldValue.value, + }, + } as Record; - const res = await saveGraph(undefined, { - globalVariables: param, - }); + const res = await saveGraph(undefined, { + globalVariables: param, + }); - if (res.code === 0) { - refetch(); - } - }, []); + if (res.code === 0) { + refetch(); + } + }, + [data.dsl?.variables, refetch, saveGraph], + ); return { handleSubmit, loading }; }; diff --git a/web/src/pages/user-setting/data-source/contant.tsx b/web/src/pages/user-setting/data-source/contant.tsx index ce3be9778..29ddd219c 100644 --- a/web/src/pages/user-setting/data-source/contant.tsx +++ b/web/src/pages/user-setting/data-source/contant.tsx @@ -110,9 +110,21 @@ export const DataSourceFormFields = { { label: 'R2', value: 'r2' }, { label: 'Google Cloud Storage', value: 'google_cloud_storage' }, { label: 'OCI Storage', value: 'oci_storage' }, + { label: 'S3 Compatible', value: 's3_compatible' }, ], required: true, }, + { + label: 'Endpoint URL', + name: 'config.credentials.endpoint_url', + type: FormFieldType.Text, + required: false, + placeholder: 'https://fsn1.your-objectstorage.com', + tooltip: t('setting.S3CompatibleEndpointUrlTip'), + shouldRender: (formValues) => { + return formValues?.config?.bucket_type === 's3_compatible'; + }, + }, { label: 'Prefix', name: 'config.prefix', @@ -501,6 +513,7 @@ export const DataSourceFormDefaultValues = { credentials: { aws_access_key_id: '', aws_secret_access_key: '', + endpoint_url: '', }, }, },