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.

app.py 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. from collections.abc import Generator, Mapping
  2. from typing import Optional, Union
  3. from controllers.service_api.wraps import create_or_update_end_user_for_user_id
  4. from core.app.app_config.common.parameters_mapping import get_parameters_from_feature_dict
  5. from core.app.apps.advanced_chat.app_generator import AdvancedChatAppGenerator
  6. from core.app.apps.agent_chat.app_generator import AgentChatAppGenerator
  7. from core.app.apps.chat.app_generator import ChatAppGenerator
  8. from core.app.apps.completion.app_generator import CompletionAppGenerator
  9. from core.app.apps.workflow.app_generator import WorkflowAppGenerator
  10. from core.app.entities.app_invoke_entities import InvokeFrom
  11. from core.plugin.backwards_invocation.base import BaseBackwardsInvocation
  12. from extensions.ext_database import db
  13. from models.account import Account
  14. from models.model import App, AppMode, EndUser
  15. class PluginAppBackwardsInvocation(BaseBackwardsInvocation):
  16. @classmethod
  17. def fetch_app_info(cls, app_id: str, tenant_id: str) -> Mapping:
  18. """
  19. Fetch app info
  20. """
  21. app = cls._get_app(app_id, tenant_id)
  22. """Retrieve app parameters."""
  23. if app.mode in {AppMode.ADVANCED_CHAT.value, AppMode.WORKFLOW.value}:
  24. workflow = app.workflow
  25. if workflow is None:
  26. raise ValueError("unexpected app type")
  27. features_dict = workflow.features_dict
  28. user_input_form = workflow.user_input_form(to_old_structure=True)
  29. else:
  30. app_model_config = app.app_model_config
  31. if app_model_config is None:
  32. raise ValueError("unexpected app type")
  33. features_dict = app_model_config.to_dict()
  34. user_input_form = features_dict.get("user_input_form", [])
  35. return {
  36. "data": get_parameters_from_feature_dict(features_dict=features_dict, user_input_form=user_input_form),
  37. }
  38. @classmethod
  39. def invoke_app(
  40. cls,
  41. app_id: str,
  42. user_id: str,
  43. tenant_id: str,
  44. conversation_id: Optional[str],
  45. query: Optional[str],
  46. stream: bool,
  47. inputs: Mapping,
  48. files: list[dict],
  49. ) -> Generator[Mapping | str, None, None] | Mapping:
  50. """
  51. invoke app
  52. """
  53. app = cls._get_app(app_id, tenant_id)
  54. if not user_id:
  55. user = create_or_update_end_user_for_user_id(app)
  56. else:
  57. user = cls._get_user(user_id)
  58. conversation_id = conversation_id or ""
  59. if app.mode in {AppMode.ADVANCED_CHAT.value, AppMode.AGENT_CHAT.value, AppMode.CHAT.value}:
  60. if not query:
  61. raise ValueError("missing query")
  62. return cls.invoke_chat_app(app, user, conversation_id, query, stream, inputs, files)
  63. elif app.mode == AppMode.WORKFLOW:
  64. return cls.invoke_workflow_app(app, user, stream, inputs, files)
  65. elif app.mode == AppMode.COMPLETION:
  66. return cls.invoke_completion_app(app, user, stream, inputs, files)
  67. raise ValueError("unexpected app type")
  68. @classmethod
  69. def invoke_chat_app(
  70. cls,
  71. app: App,
  72. user: Account | EndUser,
  73. conversation_id: str,
  74. query: str,
  75. stream: bool,
  76. inputs: Mapping,
  77. files: list[dict],
  78. ) -> Generator[Mapping | str, None, None] | Mapping:
  79. """
  80. invoke chat app
  81. """
  82. if app.mode == AppMode.ADVANCED_CHAT.value:
  83. workflow = app.workflow
  84. if not workflow:
  85. raise ValueError("unexpected app type")
  86. return AdvancedChatAppGenerator().generate(
  87. app_model=app,
  88. workflow=workflow,
  89. user=user,
  90. args={
  91. "inputs": inputs,
  92. "query": query,
  93. "files": files,
  94. "conversation_id": conversation_id,
  95. },
  96. invoke_from=InvokeFrom.SERVICE_API,
  97. streaming=stream,
  98. )
  99. elif app.mode == AppMode.AGENT_CHAT.value:
  100. return AgentChatAppGenerator().generate(
  101. app_model=app,
  102. user=user,
  103. args={
  104. "inputs": inputs,
  105. "query": query,
  106. "files": files,
  107. "conversation_id": conversation_id,
  108. },
  109. invoke_from=InvokeFrom.SERVICE_API,
  110. streaming=stream,
  111. )
  112. elif app.mode == AppMode.CHAT.value:
  113. return ChatAppGenerator().generate(
  114. app_model=app,
  115. user=user,
  116. args={
  117. "inputs": inputs,
  118. "query": query,
  119. "files": files,
  120. "conversation_id": conversation_id,
  121. },
  122. invoke_from=InvokeFrom.SERVICE_API,
  123. streaming=stream,
  124. )
  125. else:
  126. raise ValueError("unexpected app type")
  127. @classmethod
  128. def invoke_workflow_app(
  129. cls,
  130. app: App,
  131. user: EndUser | Account,
  132. stream: bool,
  133. inputs: Mapping,
  134. files: list[dict],
  135. ) -> Generator[Mapping | str, None, None] | Mapping:
  136. """
  137. invoke workflow app
  138. """
  139. workflow = app.workflow
  140. if not workflow:
  141. raise ValueError("")
  142. return WorkflowAppGenerator().generate(
  143. app_model=app,
  144. workflow=workflow,
  145. user=user,
  146. args={"inputs": inputs, "files": files},
  147. invoke_from=InvokeFrom.SERVICE_API,
  148. streaming=stream,
  149. call_depth=1,
  150. workflow_thread_pool_id=None,
  151. )
  152. @classmethod
  153. def invoke_completion_app(
  154. cls,
  155. app: App,
  156. user: EndUser | Account,
  157. stream: bool,
  158. inputs: Mapping,
  159. files: list[dict],
  160. ) -> Generator[Mapping | str, None, None] | Mapping:
  161. """
  162. invoke completion app
  163. """
  164. return CompletionAppGenerator().generate(
  165. app_model=app,
  166. user=user,
  167. args={"inputs": inputs, "files": files},
  168. invoke_from=InvokeFrom.SERVICE_API,
  169. streaming=stream,
  170. )
  171. @classmethod
  172. def _get_user(cls, user_id: str) -> Union[EndUser, Account]:
  173. """
  174. get the user by user id
  175. """
  176. user = db.session.query(EndUser).filter(EndUser.id == user_id).first()
  177. if not user:
  178. user = db.session.query(Account).filter(Account.id == user_id).first()
  179. if not user:
  180. raise ValueError("user not found")
  181. return user
  182. @classmethod
  183. def _get_app(cls, app_id: str, tenant_id: str) -> App:
  184. """
  185. get app
  186. """
  187. try:
  188. app = db.session.query(App).filter(App.id == app_id).filter(App.tenant_id == tenant_id).first()
  189. except Exception:
  190. raise ValueError("app not found")
  191. if not app:
  192. raise ValueError("app not found")
  193. return app