Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

app_generate_service.py 9.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. from collections.abc import Generator, Mapping
  2. from typing import Any, Union
  3. from openai._exceptions import RateLimitError
  4. from configs import dify_config
  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.app.features.rate_limiting import RateLimit
  12. from libs.helper import RateLimiter
  13. from models.model import Account, App, AppMode, EndUser
  14. from models.workflow import Workflow
  15. from services.billing_service import BillingService
  16. from services.errors.llm import InvokeRateLimitError
  17. from services.workflow_service import WorkflowService
  18. class AppGenerateService:
  19. system_rate_limiter = RateLimiter("app_daily_rate_limiter", dify_config.APP_DAILY_RATE_LIMIT, 86400)
  20. @classmethod
  21. def generate(
  22. cls,
  23. app_model: App,
  24. user: Union[Account, EndUser],
  25. args: Mapping[str, Any],
  26. invoke_from: InvokeFrom,
  27. streaming: bool = True,
  28. ):
  29. """
  30. App Content Generate
  31. :param app_model: app model
  32. :param user: user
  33. :param args: args
  34. :param invoke_from: invoke from
  35. :param streaming: streaming
  36. :return:
  37. """
  38. # system level rate limiter
  39. if dify_config.BILLING_ENABLED:
  40. # check if it's free plan
  41. limit_info = BillingService.get_info(app_model.tenant_id)
  42. if limit_info["subscription"]["plan"] == "sandbox":
  43. if cls.system_rate_limiter.is_rate_limited(app_model.tenant_id):
  44. raise InvokeRateLimitError(
  45. "Rate limit exceeded, please upgrade your plan "
  46. f"or your RPD was {dify_config.APP_DAILY_RATE_LIMIT} requests/day"
  47. )
  48. cls.system_rate_limiter.increment_rate_limit(app_model.tenant_id)
  49. # app level rate limiter
  50. max_active_request = AppGenerateService._get_max_active_requests(app_model)
  51. rate_limit = RateLimit(app_model.id, max_active_request)
  52. request_id = RateLimit.gen_request_key()
  53. try:
  54. request_id = rate_limit.enter(request_id)
  55. if app_model.mode == AppMode.COMPLETION.value:
  56. return rate_limit.generate(
  57. CompletionAppGenerator.convert_to_event_stream(
  58. CompletionAppGenerator().generate(
  59. app_model=app_model, user=user, args=args, invoke_from=invoke_from, streaming=streaming
  60. ),
  61. ),
  62. request_id=request_id,
  63. )
  64. elif app_model.mode == AppMode.AGENT_CHAT.value or app_model.is_agent:
  65. return rate_limit.generate(
  66. AgentChatAppGenerator.convert_to_event_stream(
  67. AgentChatAppGenerator().generate(
  68. app_model=app_model, user=user, args=args, invoke_from=invoke_from, streaming=streaming
  69. ),
  70. ),
  71. request_id,
  72. )
  73. elif app_model.mode == AppMode.CHAT.value:
  74. return rate_limit.generate(
  75. ChatAppGenerator.convert_to_event_stream(
  76. ChatAppGenerator().generate(
  77. app_model=app_model, user=user, args=args, invoke_from=invoke_from, streaming=streaming
  78. ),
  79. ),
  80. request_id=request_id,
  81. )
  82. elif app_model.mode == AppMode.ADVANCED_CHAT.value:
  83. workflow = cls._get_workflow(app_model, invoke_from)
  84. return rate_limit.generate(
  85. AdvancedChatAppGenerator.convert_to_event_stream(
  86. AdvancedChatAppGenerator().generate(
  87. app_model=app_model,
  88. workflow=workflow,
  89. user=user,
  90. args=args,
  91. invoke_from=invoke_from,
  92. streaming=streaming,
  93. ),
  94. ),
  95. request_id=request_id,
  96. )
  97. elif app_model.mode == AppMode.WORKFLOW.value:
  98. workflow = cls._get_workflow(app_model, invoke_from)
  99. return rate_limit.generate(
  100. WorkflowAppGenerator.convert_to_event_stream(
  101. WorkflowAppGenerator().generate(
  102. app_model=app_model,
  103. workflow=workflow,
  104. user=user,
  105. args=args,
  106. invoke_from=invoke_from,
  107. streaming=streaming,
  108. call_depth=0,
  109. workflow_thread_pool_id=None,
  110. ),
  111. ),
  112. request_id,
  113. )
  114. else:
  115. raise ValueError(f"Invalid app mode {app_model.mode}")
  116. except RateLimitError as e:
  117. raise InvokeRateLimitError(str(e))
  118. except Exception:
  119. rate_limit.exit(request_id)
  120. raise
  121. finally:
  122. if not streaming:
  123. rate_limit.exit(request_id)
  124. @staticmethod
  125. def _get_max_active_requests(app: App) -> int:
  126. """
  127. Get the maximum number of active requests allowed for an app.
  128. Returns the smaller value between app's custom limit and global config limit.
  129. A value of 0 means infinite (no limit).
  130. Args:
  131. app: The App model instance
  132. Returns:
  133. The maximum number of active requests allowed
  134. """
  135. app_limit = app.max_active_requests or 0
  136. config_limit = dify_config.APP_MAX_ACTIVE_REQUESTS
  137. # Filter out infinite (0) values and return the minimum, or 0 if both are infinite
  138. limits = [limit for limit in [app_limit, config_limit] if limit > 0]
  139. return min(limits) if limits else 0
  140. @classmethod
  141. def generate_single_iteration(cls, app_model: App, user: Account, node_id: str, args: Any, streaming: bool = True):
  142. if app_model.mode == AppMode.ADVANCED_CHAT.value:
  143. workflow = cls._get_workflow(app_model, InvokeFrom.DEBUGGER)
  144. return AdvancedChatAppGenerator.convert_to_event_stream(
  145. AdvancedChatAppGenerator().single_iteration_generate(
  146. app_model=app_model, workflow=workflow, node_id=node_id, user=user, args=args, streaming=streaming
  147. )
  148. )
  149. elif app_model.mode == AppMode.WORKFLOW.value:
  150. workflow = cls._get_workflow(app_model, InvokeFrom.DEBUGGER)
  151. return AdvancedChatAppGenerator.convert_to_event_stream(
  152. WorkflowAppGenerator().single_iteration_generate(
  153. app_model=app_model, workflow=workflow, node_id=node_id, user=user, args=args, streaming=streaming
  154. )
  155. )
  156. else:
  157. raise ValueError(f"Invalid app mode {app_model.mode}")
  158. @classmethod
  159. def generate_single_loop(cls, app_model: App, user: Account, node_id: str, args: Any, streaming: bool = True):
  160. if app_model.mode == AppMode.ADVANCED_CHAT.value:
  161. workflow = cls._get_workflow(app_model, InvokeFrom.DEBUGGER)
  162. return AdvancedChatAppGenerator.convert_to_event_stream(
  163. AdvancedChatAppGenerator().single_loop_generate(
  164. app_model=app_model, workflow=workflow, node_id=node_id, user=user, args=args, streaming=streaming
  165. )
  166. )
  167. elif app_model.mode == AppMode.WORKFLOW.value:
  168. workflow = cls._get_workflow(app_model, InvokeFrom.DEBUGGER)
  169. return AdvancedChatAppGenerator.convert_to_event_stream(
  170. WorkflowAppGenerator().single_loop_generate(
  171. app_model=app_model, workflow=workflow, node_id=node_id, user=user, args=args, streaming=streaming
  172. )
  173. )
  174. else:
  175. raise ValueError(f"Invalid app mode {app_model.mode}")
  176. @classmethod
  177. def generate_more_like_this(
  178. cls,
  179. app_model: App,
  180. user: Union[Account, EndUser],
  181. message_id: str,
  182. invoke_from: InvokeFrom,
  183. streaming: bool = True,
  184. ) -> Union[Mapping, Generator]:
  185. """
  186. Generate more like this
  187. :param app_model: app model
  188. :param user: user
  189. :param message_id: message id
  190. :param invoke_from: invoke from
  191. :param streaming: streaming
  192. :return:
  193. """
  194. return CompletionAppGenerator().generate_more_like_this(
  195. app_model=app_model, message_id=message_id, user=user, invoke_from=invoke_from, stream=streaming
  196. )
  197. @classmethod
  198. def _get_workflow(cls, app_model: App, invoke_from: InvokeFrom) -> Workflow:
  199. """
  200. Get workflow
  201. :param app_model: app model
  202. :param invoke_from: invoke from
  203. :return:
  204. """
  205. workflow_service = WorkflowService()
  206. if invoke_from == InvokeFrom.DEBUGGER:
  207. # fetch draft workflow by app_model
  208. workflow = workflow_service.get_draft_workflow(app_model=app_model)
  209. if not workflow:
  210. raise ValueError("Workflow not initialized")
  211. else:
  212. # fetch published workflow by app_model
  213. workflow = workflow_service.get_published_workflow(app_model=app_model)
  214. if not workflow:
  215. raise ValueError("Workflow not published")
  216. return workflow