Pārlūkot izejas kodu

feat: add latest version

Yeuoly 6 mēneši atpakaļ
vecāks
revīzija
5f61aa85db

+ 14 - 0
api/core/helper/marketplace.py

@@ -1,7 +1,11 @@
+from collections.abc import Sequence
+
+import requests
 from yarl import URL
 
 from configs import dify_config
 from core.helper.download import download_with_size_limit
+from core.plugin.entities.marketplace import MarketplacePluginDeclaration
 
 
 def get_plugin_pkg_url(plugin_unique_identifier: str):
@@ -13,3 +17,13 @@ def get_plugin_pkg_url(plugin_unique_identifier: str):
 def download_plugin_pkg(plugin_unique_identifier: str):
     url = str(get_plugin_pkg_url(plugin_unique_identifier))
     return download_with_size_limit(url, dify_config.PLUGIN_MAX_PACKAGE_SIZE)
+
+
+def batch_fetch_plugin_manifests(plugin_ids: list[str]) -> Sequence[MarketplacePluginDeclaration]:
+    if len(plugin_ids) == 0:
+        return []
+
+    url = str(URL(str(dify_config.MARKETPLACE_API_URL)) / "api/v1/plugins/batch")
+    response = requests.get(url, json={"plugin_ids": plugin_ids})
+    response.raise_for_status()
+    return [MarketplacePluginDeclaration(**plugin) for plugin in response.json()["plugins"]]

+ 34 - 0
api/core/plugin/entities/marketplace.py

@@ -0,0 +1,34 @@
+from typing import Optional
+
+from pydantic import BaseModel, Field
+
+from core.model_runtime.entities.provider_entities import ProviderEntity
+from core.plugin.entities.endpoint import EndpointProviderDeclaration
+from core.plugin.entities.plugin import PluginResourceRequirements
+from core.tools.entities.common_entities import I18nObject
+from core.tools.entities.tool_entities import ToolProviderEntity
+
+
+class MarketplacePluginDeclaration(BaseModel):
+    name: str = Field(..., description="Unique identifier for the plugin within the marketplace")
+    org: str = Field(..., description="Organization or developer responsible for creating and maintaining the plugin")
+    plugin_id: str = Field(..., description="Globally unique identifier for the plugin across all marketplaces")
+    icon: str = Field(..., description="URL or path to the plugin's visual representation")
+    label: I18nObject = Field(..., description="Localized display name for the plugin in different languages")
+    brief: I18nObject = Field(..., description="Short, localized description of the plugin's functionality")
+    resource: PluginResourceRequirements = Field(
+        ..., description="Specification of computational resources needed to run the plugin"
+    )
+    endpoint: Optional[EndpointProviderDeclaration] = Field(
+        None, description="Configuration for the plugin's API endpoint, if applicable"
+    )
+    model: Optional[ProviderEntity] = Field(None, description="Details of the AI model used by the plugin, if any")
+    tool: Optional[ToolProviderEntity] = Field(
+        None, description="Information about the tool functionality provided by the plugin, if any"
+    )
+    latest_version: str = Field(
+        ..., description="Most recent version number of the plugin available in the marketplace"
+    )
+    latest_package_identifier: str = Field(
+        ..., description="Unique identifier for the latest package release of the plugin"
+    )

+ 1 - 0
api/core/plugin/entities/plugin.py

@@ -105,6 +105,7 @@ class PluginEntity(BasePluginEntity):
     endpoints_active: int
     runtime_type: str
     version: str
+    latest_version: Optional[str] = None
     source: PluginInstallationSource
     meta: Mapping[str, Any]
 

+ 11 - 1
api/services/plugin/plugin_service.py

@@ -2,6 +2,7 @@ from collections.abc import Sequence
 from mimetypes import guess_type
 
 from configs import dify_config
+from core.helper import marketplace
 from core.helper.download import download_with_size_limit
 from core.helper.marketplace import download_plugin_pkg
 from core.plugin.entities.plugin import PluginDeclaration, PluginEntity, PluginInstallationSource
@@ -26,7 +27,16 @@ class PluginService:
         list all plugins of the tenant
         """
         manager = PluginInstallationManager()
-        return manager.list_plugins(tenant_id)
+        plugins = manager.list_plugins(tenant_id)
+        plugin_ids = [plugin.plugin_id for plugin in plugins if plugin.source == PluginInstallationSource.Marketplace]
+        manifests = {manifest.plugin_id: manifest for manifest in marketplace.batch_fetch_plugin_manifests(plugin_ids)}
+        for plugin in plugins:
+            if plugin.source == PluginInstallationSource.Marketplace:
+                if plugin.plugin_id in manifests:
+                    # set latest_version
+                    plugin.latest_version = manifests[plugin.plugin_id].latest_version
+
+        return plugins
 
     @staticmethod
     def get_asset(tenant_id: str, asset_file: str) -> tuple[bytes, str]: