application_manager.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. import json
  2. import logging
  3. import threading
  4. import uuid
  5. from typing import Any, Generator, Optional, Tuple, Union, cast
  6. from core.app_runner.agent_app_runner import AgentApplicationRunner
  7. from core.app_runner.basic_app_runner import BasicApplicationRunner
  8. from core.app_runner.generate_task_pipeline import GenerateTaskPipeline
  9. from core.application_queue_manager import ApplicationQueueManager, ConversationTaskStoppedException, PublishFrom
  10. from core.entities.application_entities import (AdvancedChatPromptTemplateEntity,
  11. AdvancedCompletionPromptTemplateEntity, AgentEntity, AgentToolEntity,
  12. ApplicationGenerateEntity, AppOrchestrationConfigEntity, DatasetEntity,
  13. DatasetRetrieveConfigEntity, ExternalDataVariableEntity,
  14. FileUploadEntity, InvokeFrom, ModelConfigEntity, PromptTemplateEntity,
  15. SensitiveWordAvoidanceEntity)
  16. from core.entities.model_entities import ModelStatus
  17. from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError
  18. from core.file.file_obj import FileObj
  19. from core.model_runtime.entities.message_entities import PromptMessageRole
  20. from core.model_runtime.entities.model_entities import ModelType
  21. from core.model_runtime.errors.invoke import InvokeAuthorizationError, InvokeError
  22. from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel
  23. from core.prompt.prompt_template import PromptTemplateParser
  24. from core.provider_manager import ProviderManager
  25. from extensions.ext_database import db
  26. from flask import Flask, current_app
  27. from models.account import Account
  28. from models.model import App, Conversation, EndUser, Message, MessageFile
  29. from pydantic import ValidationError
  30. logger = logging.getLogger(__name__)
  31. class ApplicationManager:
  32. """
  33. This class is responsible for managing application
  34. """
  35. def generate(self, tenant_id: str,
  36. app_id: str,
  37. app_model_config_id: str,
  38. app_model_config_dict: dict,
  39. app_model_config_override: bool,
  40. user: Union[Account, EndUser],
  41. invoke_from: InvokeFrom,
  42. inputs: dict[str, str],
  43. query: Optional[str] = None,
  44. files: Optional[list[FileObj]] = None,
  45. conversation: Optional[Conversation] = None,
  46. stream: bool = False,
  47. extras: Optional[dict[str, Any]] = None) \
  48. -> Union[dict, Generator]:
  49. """
  50. Generate App response.
  51. :param tenant_id: workspace ID
  52. :param app_id: app ID
  53. :param app_model_config_id: app model config id
  54. :param app_model_config_dict: app model config dict
  55. :param app_model_config_override: app model config override
  56. :param user: account or end user
  57. :param invoke_from: invoke from source
  58. :param inputs: inputs
  59. :param query: query
  60. :param files: file obj list
  61. :param conversation: conversation
  62. :param stream: is stream
  63. :param extras: extras
  64. """
  65. # init task id
  66. task_id = str(uuid.uuid4())
  67. # init application generate entity
  68. application_generate_entity = ApplicationGenerateEntity(
  69. task_id=task_id,
  70. tenant_id=tenant_id,
  71. app_id=app_id,
  72. app_model_config_id=app_model_config_id,
  73. app_model_config_dict=app_model_config_dict,
  74. app_orchestration_config_entity=self._convert_from_app_model_config_dict(
  75. tenant_id=tenant_id,
  76. app_model_config_dict=app_model_config_dict
  77. ),
  78. app_model_config_override=app_model_config_override,
  79. conversation_id=conversation.id if conversation else None,
  80. inputs=conversation.inputs if conversation else inputs,
  81. query=query.replace('\x00', '') if query else None,
  82. files=files if files else [],
  83. user_id=user.id,
  84. stream=stream,
  85. invoke_from=invoke_from,
  86. extras=extras
  87. )
  88. # init generate records
  89. (
  90. conversation,
  91. message
  92. ) = self._init_generate_records(application_generate_entity)
  93. # init queue manager
  94. queue_manager = ApplicationQueueManager(
  95. task_id=application_generate_entity.task_id,
  96. user_id=application_generate_entity.user_id,
  97. invoke_from=application_generate_entity.invoke_from,
  98. conversation_id=conversation.id,
  99. app_mode=conversation.mode,
  100. message_id=message.id
  101. )
  102. # new thread
  103. worker_thread = threading.Thread(target=self._generate_worker, kwargs={
  104. 'flask_app': current_app._get_current_object(),
  105. 'application_generate_entity': application_generate_entity,
  106. 'queue_manager': queue_manager,
  107. 'conversation_id': conversation.id,
  108. 'message_id': message.id,
  109. })
  110. worker_thread.start()
  111. # return response or stream generator
  112. return self._handle_response(
  113. application_generate_entity=application_generate_entity,
  114. queue_manager=queue_manager,
  115. conversation=conversation,
  116. message=message,
  117. stream=stream
  118. )
  119. def _generate_worker(self, flask_app: Flask,
  120. application_generate_entity: ApplicationGenerateEntity,
  121. queue_manager: ApplicationQueueManager,
  122. conversation_id: str,
  123. message_id: str) -> None:
  124. """
  125. Generate worker in a new thread.
  126. :param flask_app: Flask app
  127. :param application_generate_entity: application generate entity
  128. :param queue_manager: queue manager
  129. :param conversation_id: conversation ID
  130. :param message_id: message ID
  131. :return:
  132. """
  133. with flask_app.app_context():
  134. try:
  135. # get conversation and message
  136. conversation = self._get_conversation(conversation_id)
  137. message = self._get_message(message_id)
  138. if application_generate_entity.app_orchestration_config_entity.agent:
  139. # agent app
  140. runner = AgentApplicationRunner()
  141. runner.run(
  142. application_generate_entity=application_generate_entity,
  143. queue_manager=queue_manager,
  144. conversation=conversation,
  145. message=message
  146. )
  147. else:
  148. # basic app
  149. runner = BasicApplicationRunner()
  150. runner.run(
  151. application_generate_entity=application_generate_entity,
  152. queue_manager=queue_manager,
  153. conversation=conversation,
  154. message=message
  155. )
  156. except ConversationTaskStoppedException:
  157. pass
  158. except InvokeAuthorizationError:
  159. queue_manager.publish_error(
  160. InvokeAuthorizationError('Incorrect API key provided'),
  161. PublishFrom.APPLICATION_MANAGER
  162. )
  163. except ValidationError as e:
  164. logger.exception("Validation Error when generating")
  165. queue_manager.publish_error(e, PublishFrom.APPLICATION_MANAGER)
  166. except (ValueError, InvokeError) as e:
  167. queue_manager.publish_error(e, PublishFrom.APPLICATION_MANAGER)
  168. except Exception as e:
  169. logger.exception("Unknown Error when generating")
  170. queue_manager.publish_error(e, PublishFrom.APPLICATION_MANAGER)
  171. finally:
  172. db.session.remove()
  173. def _handle_response(self, application_generate_entity: ApplicationGenerateEntity,
  174. queue_manager: ApplicationQueueManager,
  175. conversation: Conversation,
  176. message: Message,
  177. stream: bool = False) -> Union[dict, Generator]:
  178. """
  179. Handle response.
  180. :param application_generate_entity: application generate entity
  181. :param queue_manager: queue manager
  182. :param conversation: conversation
  183. :param message: message
  184. :param stream: is stream
  185. :return:
  186. """
  187. # init generate task pipeline
  188. generate_task_pipeline = GenerateTaskPipeline(
  189. application_generate_entity=application_generate_entity,
  190. queue_manager=queue_manager,
  191. conversation=conversation,
  192. message=message
  193. )
  194. try:
  195. return generate_task_pipeline.process(stream=stream)
  196. except ValueError as e:
  197. if e.args[0] == "I/O operation on closed file.": # ignore this error
  198. raise ConversationTaskStoppedException()
  199. else:
  200. logger.exception(e)
  201. raise e
  202. finally:
  203. db.session.remove()
  204. def _convert_from_app_model_config_dict(self, tenant_id: str, app_model_config_dict: dict) \
  205. -> AppOrchestrationConfigEntity:
  206. """
  207. Convert app model config dict to entity.
  208. :param tenant_id: tenant ID
  209. :param app_model_config_dict: app model config dict
  210. :raises ProviderTokenNotInitError: provider token not init error
  211. :return: app orchestration config entity
  212. """
  213. properties = {}
  214. copy_app_model_config_dict = app_model_config_dict.copy()
  215. provider_manager = ProviderManager()
  216. provider_model_bundle = provider_manager.get_provider_model_bundle(
  217. tenant_id=tenant_id,
  218. provider=copy_app_model_config_dict['model']['provider'],
  219. model_type=ModelType.LLM
  220. )
  221. provider_name = provider_model_bundle.configuration.provider.provider
  222. model_name = copy_app_model_config_dict['model']['name']
  223. model_type_instance = provider_model_bundle.model_type_instance
  224. model_type_instance = cast(LargeLanguageModel, model_type_instance)
  225. # check model credentials
  226. model_credentials = provider_model_bundle.configuration.get_current_credentials(
  227. model_type=ModelType.LLM,
  228. model=copy_app_model_config_dict['model']['name']
  229. )
  230. if model_credentials is None:
  231. raise ProviderTokenNotInitError(f"Model {model_name} credentials is not initialized.")
  232. # check model
  233. provider_model = provider_model_bundle.configuration.get_provider_model(
  234. model=copy_app_model_config_dict['model']['name'],
  235. model_type=ModelType.LLM
  236. )
  237. if provider_model is None:
  238. model_name = copy_app_model_config_dict['model']['name']
  239. raise ValueError(f"Model {model_name} not exist.")
  240. if provider_model.status == ModelStatus.NO_CONFIGURE:
  241. raise ProviderTokenNotInitError(f"Model {model_name} credentials is not initialized.")
  242. elif provider_model.status == ModelStatus.NO_PERMISSION:
  243. raise ModelCurrentlyNotSupportError(f"Dify Hosted OpenAI {model_name} currently not support.")
  244. elif provider_model.status == ModelStatus.QUOTA_EXCEEDED:
  245. raise QuotaExceededError(f"Model provider {provider_name} quota exceeded.")
  246. # model config
  247. completion_params = copy_app_model_config_dict['model'].get('completion_params')
  248. stop = []
  249. if 'stop' in completion_params:
  250. stop = completion_params['stop']
  251. del completion_params['stop']
  252. # get model mode
  253. model_mode = copy_app_model_config_dict['model'].get('mode')
  254. if not model_mode:
  255. mode_enum = model_type_instance.get_model_mode(
  256. model=copy_app_model_config_dict['model']['name'],
  257. credentials=model_credentials
  258. )
  259. model_mode = mode_enum.value
  260. model_schema = model_type_instance.get_model_schema(
  261. copy_app_model_config_dict['model']['name'],
  262. model_credentials
  263. )
  264. if not model_schema:
  265. raise ValueError(f"Model {model_name} not exist.")
  266. properties['model_config'] = ModelConfigEntity(
  267. provider=copy_app_model_config_dict['model']['provider'],
  268. model=copy_app_model_config_dict['model']['name'],
  269. model_schema=model_schema,
  270. mode=model_mode,
  271. provider_model_bundle=provider_model_bundle,
  272. credentials=model_credentials,
  273. parameters=completion_params,
  274. stop=stop,
  275. )
  276. # prompt template
  277. prompt_type = PromptTemplateEntity.PromptType.value_of(copy_app_model_config_dict['prompt_type'])
  278. if prompt_type == PromptTemplateEntity.PromptType.SIMPLE:
  279. simple_prompt_template = copy_app_model_config_dict.get("pre_prompt", "")
  280. properties['prompt_template'] = PromptTemplateEntity(
  281. prompt_type=prompt_type,
  282. simple_prompt_template=simple_prompt_template
  283. )
  284. else:
  285. advanced_chat_prompt_template = None
  286. chat_prompt_config = copy_app_model_config_dict.get("chat_prompt_config", {})
  287. if chat_prompt_config:
  288. chat_prompt_messages = []
  289. for message in chat_prompt_config.get("prompt", []):
  290. chat_prompt_messages.append({
  291. "text": message["text"],
  292. "role": PromptMessageRole.value_of(message["role"])
  293. })
  294. advanced_chat_prompt_template = AdvancedChatPromptTemplateEntity(
  295. messages=chat_prompt_messages
  296. )
  297. advanced_completion_prompt_template = None
  298. completion_prompt_config = copy_app_model_config_dict.get("completion_prompt_config", {})
  299. if completion_prompt_config:
  300. completion_prompt_template_params = {
  301. 'prompt': completion_prompt_config['prompt']['text'],
  302. }
  303. if 'conversation_histories_role' in completion_prompt_config:
  304. completion_prompt_template_params['role_prefix'] = {
  305. 'user': completion_prompt_config['conversation_histories_role']['user_prefix'],
  306. 'assistant': completion_prompt_config['conversation_histories_role']['assistant_prefix']
  307. }
  308. advanced_completion_prompt_template = AdvancedCompletionPromptTemplateEntity(
  309. **completion_prompt_template_params
  310. )
  311. properties['prompt_template'] = PromptTemplateEntity(
  312. prompt_type=prompt_type,
  313. advanced_chat_prompt_template=advanced_chat_prompt_template,
  314. advanced_completion_prompt_template=advanced_completion_prompt_template
  315. )
  316. # external data variables
  317. properties['external_data_variables'] = []
  318. external_data_tools = copy_app_model_config_dict.get('external_data_tools', [])
  319. for external_data_tool in external_data_tools:
  320. if 'enabled' not in external_data_tool or not external_data_tool['enabled']:
  321. continue
  322. properties['external_data_variables'].append(
  323. ExternalDataVariableEntity(
  324. variable=external_data_tool['variable'],
  325. type=external_data_tool['type'],
  326. config=external_data_tool['config']
  327. )
  328. )
  329. # show retrieve source
  330. show_retrieve_source = False
  331. retriever_resource_dict = copy_app_model_config_dict.get('retriever_resource')
  332. if retriever_resource_dict:
  333. if 'enabled' in retriever_resource_dict and retriever_resource_dict['enabled']:
  334. show_retrieve_source = True
  335. properties['show_retrieve_source'] = show_retrieve_source
  336. if 'agent_mode' in copy_app_model_config_dict and copy_app_model_config_dict['agent_mode'] \
  337. and 'enabled' in copy_app_model_config_dict['agent_mode'] and copy_app_model_config_dict['agent_mode'][
  338. 'enabled']:
  339. agent_dict = copy_app_model_config_dict.get('agent_mode')
  340. agent_strategy = agent_dict.get('strategy', 'router')
  341. if agent_strategy in ['router', 'react_router']:
  342. dataset_ids = []
  343. for tool in agent_dict.get('tools', []):
  344. key = list(tool.keys())[0]
  345. if key != 'dataset':
  346. continue
  347. tool_item = tool[key]
  348. if "enabled" not in tool_item or not tool_item["enabled"]:
  349. continue
  350. dataset_id = tool_item['id']
  351. dataset_ids.append(dataset_id)
  352. dataset_configs = copy_app_model_config_dict.get('dataset_configs', {'retrieval_model': 'single'})
  353. query_variable = copy_app_model_config_dict.get('dataset_query_variable')
  354. if dataset_configs['retrieval_model'] == 'single':
  355. properties['dataset'] = DatasetEntity(
  356. dataset_ids=dataset_ids,
  357. retrieve_config=DatasetRetrieveConfigEntity(
  358. query_variable=query_variable,
  359. retrieve_strategy=DatasetRetrieveConfigEntity.RetrieveStrategy.value_of(
  360. dataset_configs['retrieval_model']
  361. ),
  362. single_strategy=agent_strategy
  363. )
  364. )
  365. else:
  366. properties['dataset'] = DatasetEntity(
  367. dataset_ids=dataset_ids,
  368. retrieve_config=DatasetRetrieveConfigEntity(
  369. query_variable=query_variable,
  370. retrieve_strategy=DatasetRetrieveConfigEntity.RetrieveStrategy.value_of(
  371. dataset_configs['retrieval_model']
  372. ),
  373. top_k=dataset_configs.get('top_k'),
  374. score_threshold=dataset_configs.get('score_threshold'),
  375. reranking_model=dataset_configs.get('reranking_model')
  376. )
  377. )
  378. else:
  379. if agent_strategy == 'react':
  380. strategy = AgentEntity.Strategy.CHAIN_OF_THOUGHT
  381. else:
  382. strategy = AgentEntity.Strategy.FUNCTION_CALLING
  383. agent_tools = []
  384. for tool in agent_dict.get('tools', []):
  385. key = list(tool.keys())[0]
  386. tool_item = tool[key]
  387. agent_tool_properties = {
  388. "tool_id": key
  389. }
  390. if "enabled" not in tool_item or not tool_item["enabled"]:
  391. continue
  392. agent_tool_properties["config"] = tool_item
  393. agent_tools.append(AgentToolEntity(**agent_tool_properties))
  394. properties['agent'] = AgentEntity(
  395. provider=properties['model_config'].provider,
  396. model=properties['model_config'].model,
  397. strategy=strategy,
  398. tools=agent_tools
  399. )
  400. # file upload
  401. file_upload_dict = copy_app_model_config_dict.get('file_upload')
  402. if file_upload_dict:
  403. if 'image' in file_upload_dict and file_upload_dict['image']:
  404. if 'enabled' in file_upload_dict['image'] and file_upload_dict['image']['enabled']:
  405. properties['file_upload'] = FileUploadEntity(
  406. image_config={
  407. 'number_limits': file_upload_dict['image']['number_limits'],
  408. 'detail': file_upload_dict['image']['detail'],
  409. 'transfer_methods': file_upload_dict['image']['transfer_methods']
  410. }
  411. )
  412. # opening statement
  413. properties['opening_statement'] = copy_app_model_config_dict.get('opening_statement')
  414. # suggested questions after answer
  415. suggested_questions_after_answer_dict = copy_app_model_config_dict.get('suggested_questions_after_answer')
  416. if suggested_questions_after_answer_dict:
  417. if 'enabled' in suggested_questions_after_answer_dict and suggested_questions_after_answer_dict['enabled']:
  418. properties['suggested_questions_after_answer'] = True
  419. # more like this
  420. more_like_this_dict = copy_app_model_config_dict.get('more_like_this')
  421. if more_like_this_dict:
  422. if 'enabled' in more_like_this_dict and more_like_this_dict['enabled']:
  423. properties['more_like_this'] = True
  424. # speech to text
  425. speech_to_text_dict = copy_app_model_config_dict.get('speech_to_text')
  426. if speech_to_text_dict:
  427. if 'enabled' in speech_to_text_dict and speech_to_text_dict['enabled']:
  428. properties['speech_to_text'] = True
  429. # sensitive word avoidance
  430. sensitive_word_avoidance_dict = copy_app_model_config_dict.get('sensitive_word_avoidance')
  431. if sensitive_word_avoidance_dict:
  432. if 'enabled' in sensitive_word_avoidance_dict and sensitive_word_avoidance_dict['enabled']:
  433. properties['sensitive_word_avoidance'] = SensitiveWordAvoidanceEntity(
  434. type=sensitive_word_avoidance_dict.get('type'),
  435. config=sensitive_word_avoidance_dict.get('config'),
  436. )
  437. return AppOrchestrationConfigEntity(**properties)
  438. def _init_generate_records(self, application_generate_entity: ApplicationGenerateEntity) \
  439. -> Tuple[Conversation, Message]:
  440. """
  441. Initialize generate records
  442. :param application_generate_entity: application generate entity
  443. :return:
  444. """
  445. app_orchestration_config_entity = application_generate_entity.app_orchestration_config_entity
  446. model_type_instance = app_orchestration_config_entity.model_config.provider_model_bundle.model_type_instance
  447. model_type_instance = cast(LargeLanguageModel, model_type_instance)
  448. model_schema = model_type_instance.get_model_schema(
  449. model=app_orchestration_config_entity.model_config.model,
  450. credentials=app_orchestration_config_entity.model_config.credentials
  451. )
  452. app_record = (db.session.query(App)
  453. .filter(App.id == application_generate_entity.app_id).first())
  454. app_mode = app_record.mode
  455. # get from source
  456. end_user_id = None
  457. account_id = None
  458. if application_generate_entity.invoke_from in [InvokeFrom.WEB_APP, InvokeFrom.SERVICE_API]:
  459. from_source = 'api'
  460. end_user_id = application_generate_entity.user_id
  461. else:
  462. from_source = 'console'
  463. account_id = application_generate_entity.user_id
  464. override_model_configs = None
  465. if application_generate_entity.app_model_config_override:
  466. override_model_configs = application_generate_entity.app_model_config_dict
  467. introduction = ''
  468. if app_mode == 'chat':
  469. # get conversation introduction
  470. introduction = self._get_conversation_introduction(application_generate_entity)
  471. if not application_generate_entity.conversation_id:
  472. conversation = Conversation(
  473. app_id=app_record.id,
  474. app_model_config_id=application_generate_entity.app_model_config_id,
  475. model_provider=app_orchestration_config_entity.model_config.provider,
  476. model_id=app_orchestration_config_entity.model_config.model,
  477. override_model_configs=json.dumps(override_model_configs) if override_model_configs else None,
  478. mode=app_mode,
  479. name='New conversation',
  480. inputs=application_generate_entity.inputs,
  481. introduction=introduction,
  482. system_instruction="",
  483. system_instruction_tokens=0,
  484. status='normal',
  485. from_source=from_source,
  486. from_end_user_id=end_user_id,
  487. from_account_id=account_id,
  488. )
  489. db.session.add(conversation)
  490. db.session.commit()
  491. else:
  492. conversation = (
  493. db.session.query(Conversation)
  494. .filter(
  495. Conversation.id == application_generate_entity.conversation_id,
  496. Conversation.app_id == app_record.id
  497. ).first()
  498. )
  499. currency = model_schema.pricing.currency if model_schema.pricing else 'USD'
  500. message = Message(
  501. app_id=app_record.id,
  502. model_provider=app_orchestration_config_entity.model_config.provider,
  503. model_id=app_orchestration_config_entity.model_config.model,
  504. override_model_configs=json.dumps(override_model_configs) if override_model_configs else None,
  505. conversation_id=conversation.id,
  506. inputs=application_generate_entity.inputs,
  507. query=application_generate_entity.query or "",
  508. message="",
  509. message_tokens=0,
  510. message_unit_price=0,
  511. message_price_unit=0,
  512. answer="",
  513. answer_tokens=0,
  514. answer_unit_price=0,
  515. answer_price_unit=0,
  516. provider_response_latency=0,
  517. total_price=0,
  518. currency=currency,
  519. from_source=from_source,
  520. from_end_user_id=end_user_id,
  521. from_account_id=account_id,
  522. agent_based=app_orchestration_config_entity.agent is not None
  523. )
  524. db.session.add(message)
  525. db.session.commit()
  526. for file in application_generate_entity.files:
  527. message_file = MessageFile(
  528. message_id=message.id,
  529. type=file.type.value,
  530. transfer_method=file.transfer_method.value,
  531. url=file.url,
  532. upload_file_id=file.upload_file_id,
  533. created_by_role=('account' if account_id else 'end_user'),
  534. created_by=account_id or end_user_id,
  535. )
  536. db.session.add(message_file)
  537. db.session.commit()
  538. return conversation, message
  539. def _get_conversation_introduction(self, application_generate_entity: ApplicationGenerateEntity) -> str:
  540. """
  541. Get conversation introduction
  542. :param application_generate_entity: application generate entity
  543. :return: conversation introduction
  544. """
  545. app_orchestration_config_entity = application_generate_entity.app_orchestration_config_entity
  546. introduction = app_orchestration_config_entity.opening_statement
  547. if introduction:
  548. try:
  549. inputs = application_generate_entity.inputs
  550. prompt_template = PromptTemplateParser(template=introduction)
  551. prompt_inputs = {k: inputs[k] for k in prompt_template.variable_keys if k in inputs}
  552. introduction = prompt_template.format(prompt_inputs)
  553. except KeyError:
  554. pass
  555. return introduction
  556. def _get_conversation(self, conversation_id: str) -> Conversation:
  557. """
  558. Get conversation by conversation id
  559. :param conversation_id: conversation id
  560. :return: conversation
  561. """
  562. conversation = (
  563. db.session.query(Conversation)
  564. .filter(Conversation.id == conversation_id)
  565. .first()
  566. )
  567. return conversation
  568. def _get_message(self, message_id: str) -> Message:
  569. """
  570. Get message by message id
  571. :param message_id: message id
  572. :return: message
  573. """
  574. message = (
  575. db.session.query(Message)
  576. .filter(Message.id == message_id)
  577. .first()
  578. )
  579. return message