您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

4 个月前
6 个月前
5 个月前
5 个月前
4 个月前
5 个月前
6 个月前
5 个月前
6 个月前
5 个月前
6 个月前
5 个月前
5 个月前
6 个月前
5 个月前
3 个月前
3 个月前
3 个月前
5 个月前
6 个月前
5 个月前
5 个月前
6 个月前
6 个月前
6 个月前
6 个月前
5 个月前
6 个月前
5 个月前
5 个月前
4 个月前
6 个月前
4 个月前
6 个月前
4 个月前
6 个月前
5 个月前
6 个月前
5 个月前
5 个月前
6 个月前
6 个月前
5 个月前
5 个月前
5 个月前
6 个月前
4 个月前
6 个月前
6 个月前
5 个月前
6 个月前
5 个月前
6 个月前
6 个月前
5 个月前
6 个月前
5 个月前
6 个月前
5 个月前
5 个月前
5 个月前
5 个月前
5 个月前
5 个月前
4 个月前
5 个月前
5 个月前
5 个月前
5 个月前
5 个月前
5 个月前
5 个月前
3 个月前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. from collections.abc import Generator, Mapping
  2. from typing import Any
  3. from core.datasource.entities.datasource_entities import (
  4. DatasourceMessage,
  5. GetOnlineDocumentPageContentRequest,
  6. OnlineDocumentPagesMessage,
  7. OnlineDriveBrowseFilesRequest,
  8. OnlineDriveBrowseFilesResponse,
  9. OnlineDriveDownloadFileRequest,
  10. WebsiteCrawlMessage,
  11. )
  12. from core.plugin.entities.plugin_daemon import (
  13. PluginBasicBooleanResponse,
  14. PluginDatasourceProviderEntity,
  15. )
  16. from core.plugin.impl.base import BasePluginClient
  17. from core.schemas.resolver import resolve_dify_schema_refs
  18. from models.provider_ids import DatasourceProviderID, GenericProviderID
  19. from services.tools.tools_transform_service import ToolTransformService
  20. class PluginDatasourceManager(BasePluginClient):
  21. def fetch_datasource_providers(self, tenant_id: str) -> list[PluginDatasourceProviderEntity]:
  22. """
  23. Fetch datasource providers for the given tenant.
  24. """
  25. def transformer(json_response: dict[str, Any]) -> dict:
  26. if json_response.get("data"):
  27. for provider in json_response.get("data", []):
  28. declaration = provider.get("declaration", {}) or {}
  29. provider_name = declaration.get("identity", {}).get("name")
  30. for datasource in declaration.get("datasources", []):
  31. datasource["identity"]["provider"] = provider_name
  32. # resolve refs
  33. if datasource.get("output_schema"):
  34. datasource["output_schema"] = resolve_dify_schema_refs(datasource["output_schema"])
  35. return json_response
  36. response = self._request_with_plugin_daemon_response(
  37. "GET",
  38. f"plugin/{tenant_id}/management/datasources",
  39. list[PluginDatasourceProviderEntity],
  40. params={"page": 1, "page_size": 256},
  41. transformer=transformer,
  42. )
  43. local_file_datasource_provider = PluginDatasourceProviderEntity(**self._get_local_file_datasource_provider())
  44. for provider in response:
  45. ToolTransformService.repack_provider(tenant_id=tenant_id, provider=provider)
  46. all_response = [local_file_datasource_provider] + response
  47. for provider in all_response:
  48. provider.declaration.identity.name = f"{provider.plugin_id}/{provider.declaration.identity.name}"
  49. # override the provider name for each tool to plugin_id/provider_name
  50. for tool in provider.declaration.datasources:
  51. tool.identity.provider = provider.declaration.identity.name
  52. return all_response
  53. def fetch_installed_datasource_providers(self, tenant_id: str) -> list[PluginDatasourceProviderEntity]:
  54. """
  55. Fetch datasource providers for the given tenant.
  56. """
  57. def transformer(json_response: dict[str, Any]) -> dict:
  58. if json_response.get("data"):
  59. for provider in json_response.get("data", []):
  60. declaration = provider.get("declaration", {}) or {}
  61. provider_name = declaration.get("identity", {}).get("name")
  62. for datasource in declaration.get("datasources", []):
  63. datasource["identity"]["provider"] = provider_name
  64. # resolve refs
  65. if datasource.get("output_schema"):
  66. datasource["output_schema"] = resolve_dify_schema_refs(datasource["output_schema"])
  67. return json_response
  68. response = self._request_with_plugin_daemon_response(
  69. "GET",
  70. f"plugin/{tenant_id}/management/datasources",
  71. list[PluginDatasourceProviderEntity],
  72. params={"page": 1, "page_size": 256},
  73. transformer=transformer,
  74. )
  75. for provider in response:
  76. ToolTransformService.repack_provider(tenant_id=tenant_id, provider=provider)
  77. for provider in response:
  78. provider.declaration.identity.name = f"{provider.plugin_id}/{provider.declaration.identity.name}"
  79. # override the provider name for each tool to plugin_id/provider_name
  80. for tool in provider.declaration.datasources:
  81. tool.identity.provider = provider.declaration.identity.name
  82. return response
  83. def fetch_datasource_provider(self, tenant_id: str, provider_id: str) -> PluginDatasourceProviderEntity:
  84. """
  85. Fetch datasource provider for the given tenant and plugin.
  86. """
  87. if provider_id == "langgenius/file/file":
  88. return PluginDatasourceProviderEntity(**self._get_local_file_datasource_provider())
  89. tool_provider_id = DatasourceProviderID(provider_id)
  90. def transformer(json_response: dict[str, Any]) -> dict:
  91. data = json_response.get("data")
  92. if data:
  93. for datasource in data.get("declaration", {}).get("datasources", []):
  94. datasource["identity"]["provider"] = tool_provider_id.provider_name
  95. if datasource.get("output_schema"):
  96. datasource["output_schema"] = resolve_dify_schema_refs(datasource["output_schema"])
  97. return json_response
  98. response = self._request_with_plugin_daemon_response(
  99. "GET",
  100. f"plugin/{tenant_id}/management/datasource",
  101. PluginDatasourceProviderEntity,
  102. params={"provider": tool_provider_id.provider_name, "plugin_id": tool_provider_id.plugin_id},
  103. transformer=transformer,
  104. )
  105. response.declaration.identity.name = f"{response.plugin_id}/{response.declaration.identity.name}"
  106. # override the provider name for each tool to plugin_id/provider_name
  107. for datasource in response.declaration.datasources:
  108. datasource.identity.provider = response.declaration.identity.name
  109. return response
  110. def get_website_crawl(
  111. self,
  112. tenant_id: str,
  113. user_id: str,
  114. datasource_provider: str,
  115. datasource_name: str,
  116. credentials: dict[str, Any],
  117. datasource_parameters: Mapping[str, Any],
  118. provider_type: str,
  119. ) -> Generator[WebsiteCrawlMessage, None, None]:
  120. """
  121. Invoke the datasource with the given tenant, user, plugin, provider, name, credentials and parameters.
  122. """
  123. datasource_provider_id = GenericProviderID(datasource_provider)
  124. return self._request_with_plugin_daemon_response_stream(
  125. "POST",
  126. f"plugin/{tenant_id}/dispatch/datasource/get_website_crawl",
  127. WebsiteCrawlMessage,
  128. data={
  129. "user_id": user_id,
  130. "data": {
  131. "provider": datasource_provider_id.provider_name,
  132. "datasource": datasource_name,
  133. "credentials": credentials,
  134. "datasource_parameters": datasource_parameters,
  135. },
  136. },
  137. headers={
  138. "X-Plugin-ID": datasource_provider_id.plugin_id,
  139. "Content-Type": "application/json",
  140. },
  141. )
  142. def get_online_document_pages(
  143. self,
  144. tenant_id: str,
  145. user_id: str,
  146. datasource_provider: str,
  147. datasource_name: str,
  148. credentials: dict[str, Any],
  149. datasource_parameters: Mapping[str, Any],
  150. provider_type: str,
  151. ) -> Generator[OnlineDocumentPagesMessage, None, None]:
  152. """
  153. Invoke the datasource with the given tenant, user, plugin, provider, name, credentials and parameters.
  154. """
  155. datasource_provider_id = GenericProviderID(datasource_provider)
  156. return self._request_with_plugin_daemon_response_stream(
  157. "POST",
  158. f"plugin/{tenant_id}/dispatch/datasource/get_online_document_pages",
  159. OnlineDocumentPagesMessage,
  160. data={
  161. "user_id": user_id,
  162. "data": {
  163. "provider": datasource_provider_id.provider_name,
  164. "datasource": datasource_name,
  165. "credentials": credentials,
  166. "datasource_parameters": datasource_parameters,
  167. },
  168. },
  169. headers={
  170. "X-Plugin-ID": datasource_provider_id.plugin_id,
  171. "Content-Type": "application/json",
  172. },
  173. )
  174. def get_online_document_page_content(
  175. self,
  176. tenant_id: str,
  177. user_id: str,
  178. datasource_provider: str,
  179. datasource_name: str,
  180. credentials: dict[str, Any],
  181. datasource_parameters: GetOnlineDocumentPageContentRequest,
  182. provider_type: str,
  183. ) -> Generator[DatasourceMessage, None, None]:
  184. """
  185. Invoke the datasource with the given tenant, user, plugin, provider, name, credentials and parameters.
  186. """
  187. datasource_provider_id = GenericProviderID(datasource_provider)
  188. return self._request_with_plugin_daemon_response_stream(
  189. "POST",
  190. f"plugin/{tenant_id}/dispatch/datasource/get_online_document_page_content",
  191. DatasourceMessage,
  192. data={
  193. "user_id": user_id,
  194. "data": {
  195. "provider": datasource_provider_id.provider_name,
  196. "datasource": datasource_name,
  197. "credentials": credentials,
  198. "page": datasource_parameters.model_dump(),
  199. },
  200. },
  201. headers={
  202. "X-Plugin-ID": datasource_provider_id.plugin_id,
  203. "Content-Type": "application/json",
  204. },
  205. )
  206. def online_drive_browse_files(
  207. self,
  208. tenant_id: str,
  209. user_id: str,
  210. datasource_provider: str,
  211. datasource_name: str,
  212. credentials: dict[str, Any],
  213. request: OnlineDriveBrowseFilesRequest,
  214. provider_type: str,
  215. ) -> Generator[OnlineDriveBrowseFilesResponse, None, None]:
  216. """
  217. Invoke the datasource with the given tenant, user, plugin, provider, name, credentials and parameters.
  218. """
  219. datasource_provider_id = GenericProviderID(datasource_provider)
  220. response = self._request_with_plugin_daemon_response_stream(
  221. "POST",
  222. f"plugin/{tenant_id}/dispatch/datasource/online_drive_browse_files",
  223. OnlineDriveBrowseFilesResponse,
  224. data={
  225. "user_id": user_id,
  226. "data": {
  227. "provider": datasource_provider_id.provider_name,
  228. "datasource": datasource_name,
  229. "credentials": credentials,
  230. "request": request.model_dump(),
  231. },
  232. },
  233. headers={
  234. "X-Plugin-ID": datasource_provider_id.plugin_id,
  235. "Content-Type": "application/json",
  236. },
  237. )
  238. yield from response
  239. def online_drive_download_file(
  240. self,
  241. tenant_id: str,
  242. user_id: str,
  243. datasource_provider: str,
  244. datasource_name: str,
  245. credentials: dict[str, Any],
  246. request: OnlineDriveDownloadFileRequest,
  247. provider_type: str,
  248. ) -> Generator[DatasourceMessage, None, None]:
  249. """
  250. Invoke the datasource with the given tenant, user, plugin, provider, name, credentials and parameters.
  251. """
  252. datasource_provider_id = GenericProviderID(datasource_provider)
  253. response = self._request_with_plugin_daemon_response_stream(
  254. "POST",
  255. f"plugin/{tenant_id}/dispatch/datasource/online_drive_download_file",
  256. DatasourceMessage,
  257. data={
  258. "user_id": user_id,
  259. "data": {
  260. "provider": datasource_provider_id.provider_name,
  261. "datasource": datasource_name,
  262. "credentials": credentials,
  263. "request": request.model_dump(),
  264. },
  265. },
  266. headers={
  267. "X-Plugin-ID": datasource_provider_id.plugin_id,
  268. "Content-Type": "application/json",
  269. },
  270. )
  271. yield from response
  272. def validate_provider_credentials(
  273. self, tenant_id: str, user_id: str, provider: str, plugin_id: str, credentials: dict[str, Any]
  274. ) -> bool:
  275. """
  276. validate the credentials of the provider
  277. """
  278. # datasource_provider_id = GenericProviderID(provider_id)
  279. response = self._request_with_plugin_daemon_response_stream(
  280. "POST",
  281. f"plugin/{tenant_id}/dispatch/datasource/validate_credentials",
  282. PluginBasicBooleanResponse,
  283. data={
  284. "user_id": user_id,
  285. "data": {
  286. "provider": provider,
  287. "credentials": credentials,
  288. },
  289. },
  290. headers={
  291. "X-Plugin-ID": plugin_id,
  292. "Content-Type": "application/json",
  293. },
  294. )
  295. for resp in response:
  296. return resp.result
  297. return False
  298. def _get_local_file_datasource_provider(self) -> dict[str, Any]:
  299. return {
  300. "id": "langgenius/file/file",
  301. "plugin_id": "langgenius/file",
  302. "provider": "file",
  303. "plugin_unique_identifier": "langgenius/file:0.0.1@dify",
  304. "declaration": {
  305. "identity": {
  306. "author": "langgenius",
  307. "name": "file",
  308. "label": {"zh_Hans": "File", "en_US": "File", "pt_BR": "File", "ja_JP": "File"},
  309. "icon": "https://assets.dify.ai/images/File%20Upload.svg",
  310. "description": {"zh_Hans": "File", "en_US": "File", "pt_BR": "File", "ja_JP": "File"},
  311. },
  312. "credentials_schema": [],
  313. "provider_type": "local_file",
  314. "datasources": [
  315. {
  316. "identity": {
  317. "author": "langgenius",
  318. "name": "upload-file",
  319. "provider": "file",
  320. "label": {"zh_Hans": "File", "en_US": "File", "pt_BR": "File", "ja_JP": "File"},
  321. },
  322. "parameters": [],
  323. "description": {"zh_Hans": "File", "en_US": "File", "pt_BR": "File", "ja_JP": "File"},
  324. }
  325. ],
  326. },
  327. }