Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

dependencies_analysis.py 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import re
  2. from configs import dify_config
  3. from core.helper import marketplace
  4. from core.plugin.entities.plugin import PluginDependency, PluginInstallationSource
  5. from core.plugin.impl.plugin import PluginInstaller
  6. from models.provider_ids import ModelProviderID, ToolProviderID
  7. # Compile regex pattern for version extraction at module level for better performance
  8. _VERSION_REGEX = re.compile(r":(?P<version>[0-9]+(?:\.[0-9]+){2}(?:[+-][0-9A-Za-z.-]+)?)(?:@|$)")
  9. class DependenciesAnalysisService:
  10. @classmethod
  11. def analyze_tool_dependency(cls, tool_id: str) -> str:
  12. """
  13. Analyze the dependency of a tool.
  14. Convert the tool id to the plugin_id
  15. """
  16. try:
  17. return ToolProviderID(tool_id).plugin_id
  18. except Exception as e:
  19. raise e
  20. @classmethod
  21. def analyze_model_provider_dependency(cls, model_provider_id: str) -> str:
  22. """
  23. Analyze the dependency of a model provider.
  24. Convert the model provider id to the plugin_id
  25. """
  26. try:
  27. return ModelProviderID(model_provider_id).plugin_id
  28. except Exception as e:
  29. raise e
  30. @classmethod
  31. def get_leaked_dependencies(cls, tenant_id: str, dependencies: list[PluginDependency]) -> list[PluginDependency]:
  32. """
  33. Check dependencies, returns the leaked dependencies in current workspace
  34. """
  35. required_plugin_unique_identifiers = []
  36. for dependency in dependencies:
  37. required_plugin_unique_identifiers.append(dependency.value.plugin_unique_identifier)
  38. manager = PluginInstaller()
  39. # get leaked dependencies
  40. missing_plugins = manager.fetch_missing_dependencies(tenant_id, required_plugin_unique_identifiers)
  41. missing_plugin_unique_identifiers = {plugin.plugin_unique_identifier: plugin for plugin in missing_plugins}
  42. leaked_dependencies = []
  43. for dependency in dependencies:
  44. unique_identifier = dependency.value.plugin_unique_identifier
  45. if unique_identifier in missing_plugin_unique_identifiers:
  46. # Extract version for Marketplace dependencies
  47. if dependency.type == PluginDependency.Type.Marketplace:
  48. version_match = _VERSION_REGEX.search(unique_identifier)
  49. if version_match:
  50. dependency.value.version = version_match.group("version")
  51. # Create and append the dependency (same for all types)
  52. leaked_dependencies.append(
  53. PluginDependency(
  54. type=dependency.type,
  55. value=dependency.value,
  56. current_identifier=missing_plugin_unique_identifiers[unique_identifier].current_identifier,
  57. )
  58. )
  59. return leaked_dependencies
  60. @classmethod
  61. def generate_dependencies(cls, tenant_id: str, dependencies: list[str]) -> list[PluginDependency]:
  62. """
  63. Generate dependencies through the list of plugin ids
  64. """
  65. dependencies = list(set(dependencies))
  66. manager = PluginInstaller()
  67. plugins = manager.fetch_plugin_installation_by_ids(tenant_id, dependencies)
  68. result = []
  69. for plugin in plugins:
  70. if plugin.source == PluginInstallationSource.Github:
  71. result.append(
  72. PluginDependency(
  73. type=PluginDependency.Type.Github,
  74. value=PluginDependency.Github(
  75. repo=plugin.meta["repo"],
  76. version=plugin.meta["version"],
  77. package=plugin.meta["package"],
  78. github_plugin_unique_identifier=plugin.plugin_unique_identifier,
  79. ),
  80. )
  81. )
  82. elif plugin.source == PluginInstallationSource.Marketplace:
  83. result.append(
  84. PluginDependency(
  85. type=PluginDependency.Type.Marketplace,
  86. value=PluginDependency.Marketplace(
  87. marketplace_plugin_unique_identifier=plugin.plugin_unique_identifier
  88. ),
  89. )
  90. )
  91. elif plugin.source == PluginInstallationSource.Package:
  92. result.append(
  93. PluginDependency(
  94. type=PluginDependency.Type.Package,
  95. value=PluginDependency.Package(plugin_unique_identifier=plugin.plugin_unique_identifier),
  96. )
  97. )
  98. elif plugin.source == PluginInstallationSource.Remote:
  99. raise ValueError(
  100. f"You used a remote plugin: {plugin.plugin_unique_identifier} in the app, please remove it first"
  101. " if you want to export the DSL."
  102. )
  103. else:
  104. raise ValueError(f"Unknown plugin source: {plugin.source}")
  105. return result
  106. @classmethod
  107. def generate_latest_dependencies(cls, dependencies: list[str]) -> list[PluginDependency]:
  108. """
  109. Generate the latest version of dependencies
  110. """
  111. dependencies = list(set(dependencies))
  112. if not dify_config.MARKETPLACE_ENABLED:
  113. return []
  114. deps = marketplace.batch_fetch_plugin_manifests(dependencies)
  115. return [
  116. PluginDependency(
  117. type=PluginDependency.Type.Marketplace,
  118. value=PluginDependency.Marketplace(marketplace_plugin_unique_identifier=dep.latest_package_identifier),
  119. )
  120. for dep in deps
  121. ]