You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import logging
  2. from typing import Any
  3. from pydantic.fields import FieldInfo
  4. from pydantic_settings import BaseSettings, PydanticBaseSettingsSource, SettingsConfigDict
  5. from .deploy import DeploymentConfig
  6. from .enterprise import EnterpriseFeatureConfig
  7. from .extra import ExtraServiceConfig
  8. from .feature import FeatureConfig
  9. from .middleware import MiddlewareConfig
  10. from .observability import ObservabilityConfig
  11. from .packaging import PackagingInfo
  12. from .remote_settings_sources import RemoteSettingsSource, RemoteSettingsSourceConfig, RemoteSettingsSourceName
  13. from .remote_settings_sources.apollo import ApolloSettingsSource
  14. logger = logging.getLogger(__name__)
  15. class RemoteSettingsSourceFactory(PydanticBaseSettingsSource):
  16. def __init__(self, settings_cls: type[BaseSettings]):
  17. super().__init__(settings_cls)
  18. def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]:
  19. raise NotImplementedError
  20. def __call__(self) -> dict[str, Any]:
  21. current_state = self.current_state
  22. remote_source_name = current_state.get("REMOTE_SETTINGS_SOURCE_NAME")
  23. if not remote_source_name:
  24. return {}
  25. remote_source: RemoteSettingsSource | None = None
  26. match remote_source_name:
  27. case RemoteSettingsSourceName.APOLLO:
  28. remote_source = ApolloSettingsSource(current_state)
  29. case _:
  30. logger.warning(f"Unsupported remote source: {remote_source_name}")
  31. return {}
  32. d: dict[str, Any] = {}
  33. for field_name, field in self.settings_cls.model_fields.items():
  34. field_value, field_key, value_is_complex = remote_source.get_field_value(field, field_name)
  35. field_value = remote_source.prepare_field_value(field_name, field, field_value, value_is_complex)
  36. if field_value is not None:
  37. d[field_key] = field_value
  38. return d
  39. class DifyConfig(
  40. # Packaging info
  41. PackagingInfo,
  42. # Deployment configs
  43. DeploymentConfig,
  44. # Feature configs
  45. FeatureConfig,
  46. # Middleware configs
  47. MiddlewareConfig,
  48. # Extra service configs
  49. ExtraServiceConfig,
  50. # Observability configs
  51. ObservabilityConfig,
  52. # Remote source configs
  53. RemoteSettingsSourceConfig,
  54. # Enterprise feature configs
  55. # **Before using, please contact business@dify.ai by email to inquire about licensing matters.**
  56. EnterpriseFeatureConfig,
  57. ):
  58. model_config = SettingsConfigDict(
  59. # read from dotenv format config file
  60. env_file=".env",
  61. env_file_encoding="utf-8",
  62. # ignore extra attributes
  63. extra="ignore",
  64. )
  65. # Before adding any config,
  66. # please consider to arrange it in the proper config group of existed or added
  67. # for better readability and maintainability.
  68. # Thanks for your concentration and consideration.
  69. @classmethod
  70. def settings_customise_sources(
  71. cls,
  72. settings_cls: type[BaseSettings],
  73. init_settings: PydanticBaseSettingsSource,
  74. env_settings: PydanticBaseSettingsSource,
  75. dotenv_settings: PydanticBaseSettingsSource,
  76. file_secret_settings: PydanticBaseSettingsSource,
  77. ) -> tuple[PydanticBaseSettingsSource, ...]:
  78. return (
  79. init_settings,
  80. env_settings,
  81. RemoteSettingsSourceFactory(settings_cls),
  82. dotenv_settings,
  83. file_secret_settings,
  84. )