app_runner.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. import logging
  2. from typing import cast
  3. from core.app.apps.base_app_queue_manager import AppQueueManager, PublishFrom
  4. from core.app.apps.base_app_runner import AppRunner
  5. from core.app.apps.chat.app_config_manager import ChatAppConfig
  6. from core.app.entities.app_invoke_entities import (
  7. ChatAppGenerateEntity,
  8. )
  9. from core.app.entities.queue_entities import QueueAnnotationReplyEvent
  10. from core.callback_handler.index_tool_callback_handler import DatasetIndexToolCallbackHandler
  11. from core.memory.token_buffer_memory import TokenBufferMemory
  12. from core.model_manager import ModelInstance
  13. from core.moderation.base import ModerationException
  14. from core.rag.retrieval.dataset_retrieval import DatasetRetrieval
  15. from extensions.ext_database import db
  16. from models.model import App, Conversation, Message
  17. logger = logging.getLogger(__name__)
  18. class ChatAppRunner(AppRunner):
  19. """
  20. Chat Application Runner
  21. """
  22. def run(self, application_generate_entity: ChatAppGenerateEntity,
  23. queue_manager: AppQueueManager,
  24. conversation: Conversation,
  25. message: Message) -> None:
  26. """
  27. Run application
  28. :param application_generate_entity: application generate entity
  29. :param queue_manager: application queue manager
  30. :param conversation: conversation
  31. :param message: message
  32. :return:
  33. """
  34. app_config = application_generate_entity.app_config
  35. app_config = cast(ChatAppConfig, app_config)
  36. app_record = db.session.query(App).filter(App.id == app_config.app_id).first()
  37. if not app_record:
  38. raise ValueError("App not found")
  39. inputs = application_generate_entity.inputs
  40. query = application_generate_entity.query
  41. files = application_generate_entity.files
  42. # Pre-calculate the number of tokens of the prompt messages,
  43. # and return the rest number of tokens by model context token size limit and max token size limit.
  44. # If the rest number of tokens is not enough, raise exception.
  45. # Include: prompt template, inputs, query(optional), files(optional)
  46. # Not Include: memory, external data, dataset context
  47. self.get_pre_calculate_rest_tokens(
  48. app_record=app_record,
  49. model_config=application_generate_entity.model_config,
  50. prompt_template_entity=app_config.prompt_template,
  51. inputs=inputs,
  52. files=files,
  53. query=query
  54. )
  55. memory = None
  56. if application_generate_entity.conversation_id:
  57. # get memory of conversation (read-only)
  58. model_instance = ModelInstance(
  59. provider_model_bundle=application_generate_entity.model_config.provider_model_bundle,
  60. model=application_generate_entity.model_config.model
  61. )
  62. memory = TokenBufferMemory(
  63. conversation=conversation,
  64. model_instance=model_instance
  65. )
  66. # organize all inputs and template to prompt messages
  67. # Include: prompt template, inputs, query(optional), files(optional)
  68. # memory(optional)
  69. prompt_messages, stop = self.organize_prompt_messages(
  70. app_record=app_record,
  71. model_config=application_generate_entity.model_config,
  72. prompt_template_entity=app_config.prompt_template,
  73. inputs=inputs,
  74. files=files,
  75. query=query,
  76. memory=memory
  77. )
  78. # moderation
  79. try:
  80. # process sensitive_word_avoidance
  81. _, inputs, query = self.moderation_for_inputs(
  82. app_id=app_record.id,
  83. tenant_id=app_config.tenant_id,
  84. app_generate_entity=application_generate_entity,
  85. inputs=inputs,
  86. query=query,
  87. )
  88. except ModerationException as e:
  89. self.direct_output(
  90. queue_manager=queue_manager,
  91. app_generate_entity=application_generate_entity,
  92. prompt_messages=prompt_messages,
  93. text=str(e),
  94. stream=application_generate_entity.stream
  95. )
  96. return
  97. if query:
  98. # annotation reply
  99. annotation_reply = self.query_app_annotations_to_reply(
  100. app_record=app_record,
  101. message=message,
  102. query=query,
  103. user_id=application_generate_entity.user_id,
  104. invoke_from=application_generate_entity.invoke_from
  105. )
  106. if annotation_reply:
  107. queue_manager.publish(
  108. QueueAnnotationReplyEvent(message_annotation_id=annotation_reply.id),
  109. PublishFrom.APPLICATION_MANAGER
  110. )
  111. self.direct_output(
  112. queue_manager=queue_manager,
  113. app_generate_entity=application_generate_entity,
  114. prompt_messages=prompt_messages,
  115. text=annotation_reply.content,
  116. stream=application_generate_entity.stream
  117. )
  118. return
  119. # fill in variable inputs from external data tools if exists
  120. external_data_tools = app_config.external_data_variables
  121. if external_data_tools:
  122. inputs = self.fill_in_inputs_from_external_data_tools(
  123. tenant_id=app_record.tenant_id,
  124. app_id=app_record.id,
  125. external_data_tools=external_data_tools,
  126. inputs=inputs,
  127. query=query
  128. )
  129. # get context from datasets
  130. context = None
  131. if app_config.dataset and app_config.dataset.dataset_ids:
  132. hit_callback = DatasetIndexToolCallbackHandler(
  133. queue_manager,
  134. app_record.id,
  135. message.id,
  136. application_generate_entity.user_id,
  137. application_generate_entity.invoke_from
  138. )
  139. dataset_retrieval = DatasetRetrieval()
  140. context = dataset_retrieval.retrieve(
  141. app_id=app_record.id,
  142. user_id=application_generate_entity.user_id,
  143. tenant_id=app_record.tenant_id,
  144. model_config=application_generate_entity.model_config,
  145. config=app_config.dataset,
  146. query=query,
  147. invoke_from=application_generate_entity.invoke_from,
  148. show_retrieve_source=app_config.additional_features.show_retrieve_source,
  149. hit_callback=hit_callback,
  150. memory=memory
  151. )
  152. # reorganize all inputs and template to prompt messages
  153. # Include: prompt template, inputs, query(optional), files(optional)
  154. # memory(optional), external data, dataset context(optional)
  155. prompt_messages, stop = self.organize_prompt_messages(
  156. app_record=app_record,
  157. model_config=application_generate_entity.model_config,
  158. prompt_template_entity=app_config.prompt_template,
  159. inputs=inputs,
  160. files=files,
  161. query=query,
  162. context=context,
  163. memory=memory
  164. )
  165. # check hosting moderation
  166. hosting_moderation_result = self.check_hosting_moderation(
  167. application_generate_entity=application_generate_entity,
  168. queue_manager=queue_manager,
  169. prompt_messages=prompt_messages
  170. )
  171. if hosting_moderation_result:
  172. return
  173. # Re-calculate the max tokens if sum(prompt_token + max_tokens) over model token limit
  174. self.recalc_llm_max_tokens(
  175. model_config=application_generate_entity.model_config,
  176. prompt_messages=prompt_messages
  177. )
  178. # Invoke model
  179. model_instance = ModelInstance(
  180. provider_model_bundle=application_generate_entity.model_config.provider_model_bundle,
  181. model=application_generate_entity.model_config.model
  182. )
  183. db.session.close()
  184. invoke_result = model_instance.invoke_llm(
  185. prompt_messages=prompt_messages,
  186. model_parameters=application_generate_entity.model_config.parameters,
  187. stop=stop,
  188. stream=application_generate_entity.stream,
  189. user=application_generate_entity.user_id,
  190. )
  191. # handle invoke result
  192. self._handle_invoke_result(
  193. invoke_result=invoke_result,
  194. queue_manager=queue_manager,
  195. stream=application_generate_entity.stream
  196. )