app_runner.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import logging
  2. from typing import cast
  3. from core.app.apps.base_app_queue_manager import AppQueueManager
  4. from core.app.apps.base_app_runner import AppRunner
  5. from core.app.apps.completion.app_config_manager import CompletionAppConfig
  6. from core.app.entities.app_invoke_entities import (
  7. CompletionAppGenerateEntity,
  8. )
  9. from core.callback_handler.index_tool_callback_handler import DatasetIndexToolCallbackHandler
  10. from core.model_manager import ModelInstance
  11. from core.model_runtime.entities.message_entities import ImagePromptMessageContent
  12. from core.moderation.base import ModerationError
  13. from core.rag.retrieval.dataset_retrieval import DatasetRetrieval
  14. from extensions.ext_database import db
  15. from models.model import App, Message
  16. logger = logging.getLogger(__name__)
  17. class CompletionAppRunner(AppRunner):
  18. """
  19. Completion Application Runner
  20. """
  21. def run(
  22. self, application_generate_entity: CompletionAppGenerateEntity, queue_manager: AppQueueManager, message: Message
  23. ) -> None:
  24. """
  25. Run application
  26. :param application_generate_entity: application generate entity
  27. :param queue_manager: application queue manager
  28. :param message: message
  29. :return:
  30. """
  31. app_config = application_generate_entity.app_config
  32. app_config = cast(CompletionAppConfig, app_config)
  33. app_record = db.session.query(App).where(App.id == app_config.app_id).first()
  34. if not app_record:
  35. raise ValueError("App not found")
  36. inputs = application_generate_entity.inputs
  37. query = application_generate_entity.query
  38. files = application_generate_entity.files
  39. image_detail_config = (
  40. application_generate_entity.file_upload_config.image_config.detail
  41. if (
  42. application_generate_entity.file_upload_config
  43. and application_generate_entity.file_upload_config.image_config
  44. )
  45. else None
  46. )
  47. image_detail_config = image_detail_config or ImagePromptMessageContent.DETAIL.LOW
  48. # organize all inputs and template to prompt messages
  49. # Include: prompt template, inputs, query(optional), files(optional)
  50. prompt_messages, stop = self.organize_prompt_messages(
  51. app_record=app_record,
  52. model_config=application_generate_entity.model_conf,
  53. prompt_template_entity=app_config.prompt_template,
  54. inputs=inputs,
  55. files=files,
  56. query=query,
  57. image_detail_config=image_detail_config,
  58. )
  59. # moderation
  60. try:
  61. # process sensitive_word_avoidance
  62. _, inputs, query = self.moderation_for_inputs(
  63. app_id=app_record.id,
  64. tenant_id=app_config.tenant_id,
  65. app_generate_entity=application_generate_entity,
  66. inputs=inputs,
  67. query=query or "",
  68. message_id=message.id,
  69. )
  70. except ModerationError as e:
  71. self.direct_output(
  72. queue_manager=queue_manager,
  73. app_generate_entity=application_generate_entity,
  74. prompt_messages=prompt_messages,
  75. text=str(e),
  76. stream=application_generate_entity.stream,
  77. )
  78. return
  79. # fill in variable inputs from external data tools if exists
  80. external_data_tools = app_config.external_data_variables
  81. if external_data_tools:
  82. inputs = self.fill_in_inputs_from_external_data_tools(
  83. tenant_id=app_record.tenant_id,
  84. app_id=app_record.id,
  85. external_data_tools=external_data_tools,
  86. inputs=inputs,
  87. query=query,
  88. )
  89. # get context from datasets
  90. context = None
  91. if app_config.dataset and app_config.dataset.dataset_ids:
  92. hit_callback = DatasetIndexToolCallbackHandler(
  93. queue_manager,
  94. app_record.id,
  95. message.id,
  96. application_generate_entity.user_id,
  97. application_generate_entity.invoke_from,
  98. )
  99. dataset_config = app_config.dataset
  100. if dataset_config and dataset_config.retrieve_config.query_variable:
  101. query = inputs.get(dataset_config.retrieve_config.query_variable, "")
  102. dataset_retrieval = DatasetRetrieval(application_generate_entity)
  103. context = dataset_retrieval.retrieve(
  104. app_id=app_record.id,
  105. user_id=application_generate_entity.user_id,
  106. tenant_id=app_record.tenant_id,
  107. model_config=application_generate_entity.model_conf,
  108. config=dataset_config,
  109. query=query or "",
  110. invoke_from=application_generate_entity.invoke_from,
  111. show_retrieve_source=app_config.additional_features.show_retrieve_source,
  112. hit_callback=hit_callback,
  113. message_id=message.id,
  114. inputs=inputs,
  115. )
  116. # reorganize all inputs and template to prompt messages
  117. # Include: prompt template, inputs, query(optional), files(optional)
  118. # memory(optional), external data, dataset context(optional)
  119. prompt_messages, stop = self.organize_prompt_messages(
  120. app_record=app_record,
  121. model_config=application_generate_entity.model_conf,
  122. prompt_template_entity=app_config.prompt_template,
  123. inputs=inputs,
  124. files=files,
  125. query=query,
  126. context=context,
  127. image_detail_config=image_detail_config,
  128. )
  129. # check hosting moderation
  130. hosting_moderation_result = self.check_hosting_moderation(
  131. application_generate_entity=application_generate_entity,
  132. queue_manager=queue_manager,
  133. prompt_messages=prompt_messages,
  134. )
  135. if hosting_moderation_result:
  136. return
  137. # Re-calculate the max tokens if sum(prompt_token + max_tokens) over model token limit
  138. self.recalc_llm_max_tokens(model_config=application_generate_entity.model_conf, prompt_messages=prompt_messages)
  139. # Invoke model
  140. model_instance = ModelInstance(
  141. provider_model_bundle=application_generate_entity.model_conf.provider_model_bundle,
  142. model=application_generate_entity.model_conf.model,
  143. )
  144. db.session.close()
  145. invoke_result = model_instance.invoke_llm(
  146. prompt_messages=prompt_messages,
  147. model_parameters=application_generate_entity.model_conf.parameters,
  148. stop=stop,
  149. stream=application_generate_entity.stream,
  150. user=application_generate_entity.user_id,
  151. )
  152. # handle invoke result
  153. self._handle_invoke_result(
  154. invoke_result=invoke_result, queue_manager=queue_manager, stream=application_generate_entity.stream
  155. )