| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 | import osfrom typing import Any, Literal, Optionalfrom urllib.parse import quote_plusfrom pydantic import Field, NonNegativeInt, PositiveFloat, PositiveInt, computed_fieldfrom pydantic_settings import BaseSettingsfrom .cache.redis_config import RedisConfigfrom .storage.aliyun_oss_storage_config import AliyunOSSStorageConfigfrom .storage.amazon_s3_storage_config import S3StorageConfigfrom .storage.azure_blob_storage_config import AzureBlobStorageConfigfrom .storage.baidu_obs_storage_config import BaiduOBSStorageConfigfrom .storage.google_cloud_storage_config import GoogleCloudStorageConfigfrom .storage.huawei_obs_storage_config import HuaweiCloudOBSStorageConfigfrom .storage.oci_storage_config import OCIStorageConfigfrom .storage.opendal_storage_config import OpenDALStorageConfigfrom .storage.supabase_storage_config import SupabaseStorageConfigfrom .storage.tencent_cos_storage_config import TencentCloudCOSStorageConfigfrom .storage.volcengine_tos_storage_config import VolcengineTOSStorageConfigfrom .vdb.analyticdb_config import AnalyticdbConfigfrom .vdb.baidu_vector_config import BaiduVectorDBConfigfrom .vdb.chroma_config import ChromaConfigfrom .vdb.couchbase_config import CouchbaseConfigfrom .vdb.elasticsearch_config import ElasticsearchConfigfrom .vdb.lindorm_config import LindormConfigfrom .vdb.milvus_config import MilvusConfigfrom .vdb.myscale_config import MyScaleConfigfrom .vdb.oceanbase_config import OceanBaseVectorConfigfrom .vdb.opengauss_config import OpenGaussConfigfrom .vdb.opensearch_config import OpenSearchConfigfrom .vdb.oracle_config import OracleConfigfrom .vdb.pgvector_config import PGVectorConfigfrom .vdb.pgvectors_config import PGVectoRSConfigfrom .vdb.qdrant_config import QdrantConfigfrom .vdb.relyt_config import RelytConfigfrom .vdb.tencent_vector_config import TencentVectorDBConfigfrom .vdb.tidb_on_qdrant_config import TidbOnQdrantConfigfrom .vdb.tidb_vector_config import TiDBVectorConfigfrom .vdb.upstash_config import UpstashConfigfrom .vdb.vikingdb_config import VikingDBConfigfrom .vdb.weaviate_config import WeaviateConfigclass StorageConfig(BaseSettings):    STORAGE_TYPE: Literal[        "opendal",        "s3",        "aliyun-oss",        "azure-blob",        "baidu-obs",        "google-storage",        "huawei-obs",        "oci-storage",        "tencent-cos",        "volcengine-tos",        "supabase",        "local",    ] = Field(        description="Type of storage to use."        " Options: 'opendal', '(deprecated) local', 's3', 'aliyun-oss', 'azure-blob', 'baidu-obs', 'google-storage', "        "'huawei-obs', 'oci-storage', 'tencent-cos', 'volcengine-tos', 'supabase'. Default is 'opendal'.",        default="opendal",    )    STORAGE_LOCAL_PATH: str = Field(        description="Path for local storage when STORAGE_TYPE is set to 'local'.",        default="storage",        deprecated=True,    )class VectorStoreConfig(BaseSettings):    VECTOR_STORE: Optional[str] = Field(        description="Type of vector store to use for efficient similarity search."        " Set to None if not using a vector store.",        default=None,    )    VECTOR_STORE_WHITELIST_ENABLE: Optional[bool] = Field(        description="Enable whitelist for vector store.",        default=False,    )class KeywordStoreConfig(BaseSettings):    KEYWORD_STORE: str = Field(        description="Method for keyword extraction and storage."        " Default is 'jieba', a Chinese text segmentation library.",        default="jieba",    )class DatabaseConfig(BaseSettings):    DB_HOST: str = Field(        description="Hostname or IP address of the database server.",        default="localhost",    )    DB_PORT: PositiveInt = Field(        description="Port number for database connection.",        default=5432,    )    DB_USERNAME: str = Field(        description="Username for database authentication.",        default="postgres",    )    DB_PASSWORD: str = Field(        description="Password for database authentication.",        default="",    )    DB_DATABASE: str = Field(        description="Name of the database to connect to.",        default="dify",    )    DB_CHARSET: str = Field(        description="Character set for database connection.",        default="",    )    DB_EXTRAS: str = Field(        description="Additional database connection parameters. Example: 'keepalives_idle=60&keepalives=1'",        default="",    )    SQLALCHEMY_DATABASE_URI_SCHEME: str = Field(        description="Database URI scheme for SQLAlchemy connection.",        default="postgresql",    )    @computed_field    def SQLALCHEMY_DATABASE_URI(self) -> str:        db_extras = (            f"{self.DB_EXTRAS}&client_encoding={self.DB_CHARSET}" if self.DB_CHARSET else self.DB_EXTRAS        ).strip("&")        db_extras = f"?{db_extras}" if db_extras else ""        return (            f"{self.SQLALCHEMY_DATABASE_URI_SCHEME}://"            f"{quote_plus(self.DB_USERNAME)}:{quote_plus(self.DB_PASSWORD)}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_DATABASE}"            f"{db_extras}"        )    SQLALCHEMY_POOL_SIZE: NonNegativeInt = Field(        description="Maximum number of database connections in the pool.",        default=30,    )    SQLALCHEMY_MAX_OVERFLOW: NonNegativeInt = Field(        description="Maximum number of connections that can be created beyond the pool_size.",        default=10,    )    SQLALCHEMY_POOL_RECYCLE: NonNegativeInt = Field(        description="Number of seconds after which a connection is automatically recycled.",        default=3600,    )    SQLALCHEMY_POOL_PRE_PING: bool = Field(        description="If True, enables connection pool pre-ping feature to check connections.",        default=False,    )    SQLALCHEMY_ECHO: bool | str = Field(        description="If True, SQLAlchemy will log all SQL statements.",        default=False,    )    RETRIEVAL_SERVICE_EXECUTORS: NonNegativeInt = Field(        description="Number of processes for the retrieval service, default to CPU cores.",        default=os.cpu_count(),    )    @computed_field    def SQLALCHEMY_ENGINE_OPTIONS(self) -> dict[str, Any]:        return {            "pool_size": self.SQLALCHEMY_POOL_SIZE,            "max_overflow": self.SQLALCHEMY_MAX_OVERFLOW,            "pool_recycle": self.SQLALCHEMY_POOL_RECYCLE,            "pool_pre_ping": self.SQLALCHEMY_POOL_PRE_PING,            "connect_args": {"options": "-c timezone=UTC"},        }class CeleryConfig(DatabaseConfig):    CELERY_BACKEND: str = Field(        description="Backend for Celery task results. Options: 'database', 'redis'.",        default="database",    )    CELERY_BROKER_URL: Optional[str] = Field(        description="URL of the message broker for Celery tasks.",        default=None,    )    CELERY_USE_SENTINEL: Optional[bool] = Field(        description="Whether to use Redis Sentinel for high availability.",        default=False,    )    CELERY_SENTINEL_MASTER_NAME: Optional[str] = Field(        description="Name of the Redis Sentinel master.",        default=None,    )    CELERY_SENTINEL_SOCKET_TIMEOUT: Optional[PositiveFloat] = Field(        description="Timeout for Redis Sentinel socket operations in seconds.",        default=0.1,    )    @computed_field    def CELERY_RESULT_BACKEND(self) -> str | None:        return (            "db+{}".format(self.SQLALCHEMY_DATABASE_URI)            if self.CELERY_BACKEND == "database"            else self.CELERY_BROKER_URL        )    @property    def BROKER_USE_SSL(self) -> bool:        return self.CELERY_BROKER_URL.startswith("rediss://") if self.CELERY_BROKER_URL else Falseclass InternalTestConfig(BaseSettings):    """    Configuration settings for Internal Test    """    AWS_SECRET_ACCESS_KEY: Optional[str] = Field(        description="Internal test AWS secret access key",        default=None,    )    AWS_ACCESS_KEY_ID: Optional[str] = Field(        description="Internal test AWS access key ID",        default=None,    )class MiddlewareConfig(    # place the configs in alphabet order    CeleryConfig,    DatabaseConfig,    KeywordStoreConfig,    RedisConfig,    # configs of storage and storage providers    StorageConfig,    AliyunOSSStorageConfig,    AzureBlobStorageConfig,    BaiduOBSStorageConfig,    GoogleCloudStorageConfig,    HuaweiCloudOBSStorageConfig,    OCIStorageConfig,    OpenDALStorageConfig,    S3StorageConfig,    SupabaseStorageConfig,    TencentCloudCOSStorageConfig,    VolcengineTOSStorageConfig,    # configs of vdb and vdb providers    VectorStoreConfig,    AnalyticdbConfig,    ChromaConfig,    MilvusConfig,    MyScaleConfig,    OpenSearchConfig,    OracleConfig,    PGVectorConfig,    PGVectoRSConfig,    QdrantConfig,    RelytConfig,    TencentVectorDBConfig,    TiDBVectorConfig,    WeaviateConfig,    ElasticsearchConfig,    CouchbaseConfig,    InternalTestConfig,    VikingDBConfig,    UpstashConfig,    TidbOnQdrantConfig,    LindormConfig,    OceanBaseVectorConfig,    BaiduVectorDBConfig,    OpenGaussConfig,):    pass
 |