| App Convert to Workflow Mode | App Convert to Workflow Mode | ||||
| """ | """ | ||||
| def convert_to_workflow(self, app_model: App, | |||||
| account: Account, | |||||
| name: str, | |||||
| icon_type: str, | |||||
| icon: str, | |||||
| icon_background: str) -> App: | |||||
| def convert_to_workflow( | |||||
| self, app_model: App, account: Account, name: str, icon_type: str, icon: str, icon_background: str | |||||
| ): | |||||
| """ | """ | ||||
| Convert app to workflow | Convert app to workflow | ||||
| :return: new App instance | :return: new App instance | ||||
| """ | """ | ||||
| # convert app model config | # convert app model config | ||||
| if not app_model.app_model_config: | |||||
| raise ValueError("App model config is required") | |||||
| workflow = self.convert_app_model_config_to_workflow( | workflow = self.convert_app_model_config_to_workflow( | ||||
| app_model=app_model, | |||||
| app_model_config=app_model.app_model_config, | |||||
| account_id=account.id | |||||
| app_model=app_model, app_model_config=app_model.app_model_config, account_id=account.id | |||||
| ) | ) | ||||
| # create new app | # create new app | ||||
| new_app = App() | new_app = App() | ||||
| new_app.tenant_id = app_model.tenant_id | new_app.tenant_id = app_model.tenant_id | ||||
| new_app.name = name if name else app_model.name + '(workflow)' | |||||
| new_app.mode = AppMode.ADVANCED_CHAT.value \ | |||||
| if app_model.mode == AppMode.CHAT.value else AppMode.WORKFLOW.value | |||||
| new_app.name = name if name else app_model.name + "(workflow)" | |||||
| new_app.mode = AppMode.ADVANCED_CHAT.value if app_model.mode == AppMode.CHAT.value else AppMode.WORKFLOW.value | |||||
| new_app.icon_type = icon_type if icon_type else app_model.icon_type | new_app.icon_type = icon_type if icon_type else app_model.icon_type | ||||
| new_app.icon = icon if icon else app_model.icon | new_app.icon = icon if icon else app_model.icon | ||||
| new_app.icon_background = icon_background if icon_background else app_model.icon_background | new_app.icon_background = icon_background if icon_background else app_model.icon_background | ||||
| return new_app | return new_app | ||||
| def convert_app_model_config_to_workflow(self, app_model: App, | |||||
| app_model_config: AppModelConfig, | |||||
| account_id: str) -> Workflow: | |||||
| def convert_app_model_config_to_workflow(self, app_model: App, app_model_config: AppModelConfig, account_id: str): | |||||
| """ | """ | ||||
| Convert app model config to workflow mode | Convert app model config to workflow mode | ||||
| :param app_model: App instance | :param app_model: App instance | ||||
| :param app_model_config: AppModelConfig instance | :param app_model_config: AppModelConfig instance | ||||
| :param account_id: Account ID | :param account_id: Account ID | ||||
| :return: | |||||
| """ | """ | ||||
| # get new app mode | # get new app mode | ||||
| new_app_mode = self._get_new_app_mode(app_model) | new_app_mode = self._get_new_app_mode(app_model) | ||||
| # convert app model config | # convert app model config | ||||
| app_config = self._convert_to_app_config( | |||||
| app_model=app_model, | |||||
| app_model_config=app_model_config | |||||
| ) | |||||
| app_config = self._convert_to_app_config(app_model=app_model, app_model_config=app_model_config) | |||||
| # init workflow graph | # init workflow graph | ||||
| graph = { | |||||
| "nodes": [], | |||||
| "edges": [] | |||||
| } | |||||
| graph = {"nodes": [], "edges": []} | |||||
| # Convert list: | # Convert list: | ||||
| # - variables -> start | # - variables -> start | ||||
| # - show_retrieve_source -> knowledge-retrieval | # - show_retrieve_source -> knowledge-retrieval | ||||
| # convert to start node | # convert to start node | ||||
| start_node = self._convert_to_start_node( | |||||
| variables=app_config.variables | |||||
| ) | |||||
| start_node = self._convert_to_start_node(variables=app_config.variables) | |||||
| graph['nodes'].append(start_node) | |||||
| graph["nodes"].append(start_node) | |||||
| # convert to http request node | # convert to http request node | ||||
| external_data_variable_node_mapping = {} | external_data_variable_node_mapping = {} | ||||
| http_request_nodes, external_data_variable_node_mapping = self._convert_to_http_request_node( | http_request_nodes, external_data_variable_node_mapping = self._convert_to_http_request_node( | ||||
| app_model=app_model, | app_model=app_model, | ||||
| variables=app_config.variables, | variables=app_config.variables, | ||||
| external_data_variables=app_config.external_data_variables | |||||
| external_data_variables=app_config.external_data_variables, | |||||
| ) | ) | ||||
| for http_request_node in http_request_nodes: | for http_request_node in http_request_nodes: | ||||
| # convert to knowledge retrieval node | # convert to knowledge retrieval node | ||||
| if app_config.dataset: | if app_config.dataset: | ||||
| knowledge_retrieval_node = self._convert_to_knowledge_retrieval_node( | knowledge_retrieval_node = self._convert_to_knowledge_retrieval_node( | ||||
| new_app_mode=new_app_mode, | |||||
| dataset_config=app_config.dataset, | |||||
| model_config=app_config.model | |||||
| new_app_mode=new_app_mode, dataset_config=app_config.dataset, model_config=app_config.model | |||||
| ) | ) | ||||
| if knowledge_retrieval_node: | if knowledge_retrieval_node: | ||||
| model_config=app_config.model, | model_config=app_config.model, | ||||
| prompt_template=app_config.prompt_template, | prompt_template=app_config.prompt_template, | ||||
| file_upload=app_config.additional_features.file_upload, | file_upload=app_config.additional_features.file_upload, | ||||
| external_data_variable_node_mapping=external_data_variable_node_mapping | |||||
| external_data_variable_node_mapping=external_data_variable_node_mapping, | |||||
| ) | ) | ||||
| graph = self._append_node(graph, llm_node) | graph = self._append_node(graph, llm_node) | ||||
| tenant_id=app_model.tenant_id, | tenant_id=app_model.tenant_id, | ||||
| app_id=app_model.id, | app_id=app_model.id, | ||||
| type=WorkflowType.from_app_mode(new_app_mode).value, | type=WorkflowType.from_app_mode(new_app_mode).value, | ||||
| version='draft', | |||||
| version="draft", | |||||
| graph=json.dumps(graph), | graph=json.dumps(graph), | ||||
| features=json.dumps(features), | features=json.dumps(features), | ||||
| created_by=account_id, | created_by=account_id, | ||||
| return workflow | return workflow | ||||
| def _convert_to_app_config(self, app_model: App, | |||||
| app_model_config: AppModelConfig) -> EasyUIBasedAppConfig: | |||||
| def _convert_to_app_config(self, app_model: App, app_model_config: AppModelConfig) -> EasyUIBasedAppConfig: | |||||
| app_mode = AppMode.value_of(app_model.mode) | app_mode = AppMode.value_of(app_model.mode) | ||||
| if app_mode == AppMode.AGENT_CHAT or app_model.is_agent: | if app_mode == AppMode.AGENT_CHAT or app_model.is_agent: | ||||
| app_model.mode = AppMode.AGENT_CHAT.value | app_model.mode = AppMode.AGENT_CHAT.value | ||||
| app_config = AgentChatAppConfigManager.get_app_config( | app_config = AgentChatAppConfigManager.get_app_config( | ||||
| app_model=app_model, | |||||
| app_model_config=app_model_config | |||||
| app_model=app_model, app_model_config=app_model_config | |||||
| ) | ) | ||||
| elif app_mode == AppMode.CHAT: | elif app_mode == AppMode.CHAT: | ||||
| app_config = ChatAppConfigManager.get_app_config( | |||||
| app_model=app_model, | |||||
| app_model_config=app_model_config | |||||
| ) | |||||
| app_config = ChatAppConfigManager.get_app_config(app_model=app_model, app_model_config=app_model_config) | |||||
| elif app_mode == AppMode.COMPLETION: | elif app_mode == AppMode.COMPLETION: | ||||
| app_config = CompletionAppConfigManager.get_app_config( | app_config = CompletionAppConfigManager.get_app_config( | ||||
| app_model=app_model, | |||||
| app_model_config=app_model_config | |||||
| app_model=app_model, app_model_config=app_model_config | |||||
| ) | ) | ||||
| else: | else: | ||||
| raise ValueError("Invalid app mode") | raise ValueError("Invalid app mode") | ||||
| "data": { | "data": { | ||||
| "title": "START", | "title": "START", | ||||
| "type": NodeType.START.value, | "type": NodeType.START.value, | ||||
| "variables": [jsonable_encoder(v) for v in variables] | |||||
| } | |||||
| "variables": [jsonable_encoder(v) for v in variables], | |||||
| }, | |||||
| } | } | ||||
| def _convert_to_http_request_node(self, app_model: App, | |||||
| variables: list[VariableEntity], | |||||
| external_data_variables: list[ExternalDataVariableEntity]) \ | |||||
| -> tuple[list[dict], dict[str, str]]: | |||||
| def _convert_to_http_request_node( | |||||
| self, app_model: App, variables: list[VariableEntity], external_data_variables: list[ExternalDataVariableEntity] | |||||
| ) -> tuple[list[dict], dict[str, str]]: | |||||
| """ | """ | ||||
| Convert API Based Extension to HTTP Request Node | Convert API Based Extension to HTTP Request Node | ||||
| :param app_model: App instance | :param app_model: App instance | ||||
| # get params from config | # get params from config | ||||
| api_based_extension_id = tool_config.get("api_based_extension_id") | api_based_extension_id = tool_config.get("api_based_extension_id") | ||||
| if not api_based_extension_id: | |||||
| continue | |||||
| # get api_based_extension | # get api_based_extension | ||||
| api_based_extension = self._get_api_based_extension( | api_based_extension = self._get_api_based_extension( | ||||
| tenant_id=tenant_id, | |||||
| api_based_extension_id=api_based_extension_id | |||||
| tenant_id=tenant_id, api_based_extension_id=api_based_extension_id | |||||
| ) | ) | ||||
| if not api_based_extension: | |||||
| raise ValueError("[External data tool] API query failed, variable: {}, " | |||||
| "error: api_based_extension_id is invalid" | |||||
| .format(tool_variable)) | |||||
| # decrypt api_key | # decrypt api_key | ||||
| api_key = encrypter.decrypt_token( | |||||
| tenant_id=tenant_id, | |||||
| token=api_based_extension.api_key | |||||
| ) | |||||
| api_key = encrypter.decrypt_token(tenant_id=tenant_id, token=api_based_extension.api_key) | |||||
| inputs = {} | inputs = {} | ||||
| for v in variables: | for v in variables: | ||||
| inputs[v.variable] = '{{#start.' + v.variable + '#}}' | |||||
| inputs[v.variable] = "{{#start." + v.variable + "#}}" | |||||
| request_body = { | request_body = { | ||||
| 'point': APIBasedExtensionPoint.APP_EXTERNAL_DATA_TOOL_QUERY.value, | |||||
| 'params': { | |||||
| 'app_id': app_model.id, | |||||
| 'tool_variable': tool_variable, | |||||
| 'inputs': inputs, | |||||
| 'query': '{{#sys.query#}}' if app_model.mode == AppMode.CHAT.value else '' | |||||
| } | |||||
| "point": APIBasedExtensionPoint.APP_EXTERNAL_DATA_TOOL_QUERY.value, | |||||
| "params": { | |||||
| "app_id": app_model.id, | |||||
| "tool_variable": tool_variable, | |||||
| "inputs": inputs, | |||||
| "query": "{{#sys.query#}}" if app_model.mode == AppMode.CHAT.value else "", | |||||
| }, | |||||
| } | } | ||||
| request_body_json = json.dumps(request_body) | request_body_json = json.dumps(request_body) | ||||
| request_body_json = request_body_json.replace(r'\{\{', '{{').replace(r'\}\}', '}}') | |||||
| request_body_json = request_body_json.replace(r"\{\{", "{{").replace(r"\}\}", "}}") | |||||
| http_request_node = { | http_request_node = { | ||||
| "id": f"http_request_{index}", | "id": f"http_request_{index}", | ||||
| "type": NodeType.HTTP_REQUEST.value, | "type": NodeType.HTTP_REQUEST.value, | ||||
| "method": "post", | "method": "post", | ||||
| "url": api_based_extension.api_endpoint, | "url": api_based_extension.api_endpoint, | ||||
| "authorization": { | |||||
| "type": "api-key", | |||||
| "config": { | |||||
| "type": "bearer", | |||||
| "api_key": api_key | |||||
| } | |||||
| }, | |||||
| "authorization": {"type": "api-key", "config": {"type": "bearer", "api_key": api_key}}, | |||||
| "headers": "", | "headers": "", | ||||
| "params": "", | "params": "", | ||||
| "body": { | |||||
| "type": "json", | |||||
| "data": request_body_json | |||||
| } | |||||
| } | |||||
| "body": {"type": "json", "data": request_body_json}, | |||||
| }, | |||||
| } | } | ||||
| nodes.append(http_request_node) | nodes.append(http_request_node) | ||||
| "data": { | "data": { | ||||
| "title": f"Parse {api_based_extension.name} Response", | "title": f"Parse {api_based_extension.name} Response", | ||||
| "type": NodeType.CODE.value, | "type": NodeType.CODE.value, | ||||
| "variables": [{ | |||||
| "variable": "response_json", | |||||
| "value_selector": [http_request_node['id'], "body"] | |||||
| }], | |||||
| "variables": [{"variable": "response_json", "value_selector": [http_request_node["id"], "body"]}], | |||||
| "code_language": "python3", | "code_language": "python3", | ||||
| "code": "import json\n\ndef main(response_json: str) -> str:\n response_body = json.loads(" | "code": "import json\n\ndef main(response_json: str) -> str:\n response_body = json.loads(" | ||||
| "response_json)\n return {\n \"result\": response_body[\"result\"]\n }", | |||||
| "outputs": { | |||||
| "result": { | |||||
| "type": "string" | |||||
| } | |||||
| } | |||||
| } | |||||
| 'response_json)\n return {\n "result": response_body["result"]\n }', | |||||
| "outputs": {"result": {"type": "string"}}, | |||||
| }, | |||||
| } | } | ||||
| nodes.append(code_node) | nodes.append(code_node) | ||||
| external_data_variable_node_mapping[external_data_variable.variable] = code_node['id'] | |||||
| external_data_variable_node_mapping[external_data_variable.variable] = code_node["id"] | |||||
| index += 1 | index += 1 | ||||
| return nodes, external_data_variable_node_mapping | return nodes, external_data_variable_node_mapping | ||||
| def _convert_to_knowledge_retrieval_node(self, new_app_mode: AppMode, | |||||
| dataset_config: DatasetEntity, | |||||
| model_config: ModelConfigEntity) \ | |||||
| -> Optional[dict]: | |||||
| def _convert_to_knowledge_retrieval_node( | |||||
| self, new_app_mode: AppMode, dataset_config: DatasetEntity, model_config: ModelConfigEntity | |||||
| ) -> Optional[dict]: | |||||
| """ | """ | ||||
| Convert datasets to Knowledge Retrieval Node | Convert datasets to Knowledge Retrieval Node | ||||
| :param new_app_mode: new app mode | :param new_app_mode: new app mode | ||||
| "completion_params": { | "completion_params": { | ||||
| **model_config.parameters, | **model_config.parameters, | ||||
| "stop": model_config.stop, | "stop": model_config.stop, | ||||
| } | |||||
| }, | |||||
| } | } | ||||
| } | } | ||||
| if retrieve_config.retrieve_strategy == DatasetRetrieveConfigEntity.RetrieveStrategy.SINGLE | if retrieve_config.retrieve_strategy == DatasetRetrieveConfigEntity.RetrieveStrategy.SINGLE | ||||
| "multiple_retrieval_config": { | "multiple_retrieval_config": { | ||||
| "top_k": retrieve_config.top_k, | "top_k": retrieve_config.top_k, | ||||
| "score_threshold": retrieve_config.score_threshold, | "score_threshold": retrieve_config.score_threshold, | ||||
| "reranking_model": retrieve_config.reranking_model | |||||
| "reranking_model": retrieve_config.reranking_model, | |||||
| } | } | ||||
| if retrieve_config.retrieve_strategy == DatasetRetrieveConfigEntity.RetrieveStrategy.MULTIPLE | if retrieve_config.retrieve_strategy == DatasetRetrieveConfigEntity.RetrieveStrategy.MULTIPLE | ||||
| else None, | else None, | ||||
| } | |||||
| }, | |||||
| } | } | ||||
| def _convert_to_llm_node(self, original_app_mode: AppMode, | |||||
| new_app_mode: AppMode, | |||||
| graph: dict, | |||||
| model_config: ModelConfigEntity, | |||||
| prompt_template: PromptTemplateEntity, | |||||
| file_upload: Optional[FileExtraConfig] = None, | |||||
| external_data_variable_node_mapping: dict[str, str] = None) -> dict: | |||||
| def _convert_to_llm_node( | |||||
| self, | |||||
| original_app_mode: AppMode, | |||||
| new_app_mode: AppMode, | |||||
| graph: dict, | |||||
| model_config: ModelConfigEntity, | |||||
| prompt_template: PromptTemplateEntity, | |||||
| file_upload: Optional[FileExtraConfig] = None, | |||||
| external_data_variable_node_mapping: dict[str, str] | None = None, | |||||
| ) -> dict: | |||||
| """ | """ | ||||
| Convert to LLM Node | Convert to LLM Node | ||||
| :param original_app_mode: original app mode | :param original_app_mode: original app mode | ||||
| :param external_data_variable_node_mapping: external data variable node mapping | :param external_data_variable_node_mapping: external data variable node mapping | ||||
| """ | """ | ||||
| # fetch start and knowledge retrieval node | # fetch start and knowledge retrieval node | ||||
| start_node = next(filter(lambda n: n['data']['type'] == NodeType.START.value, graph['nodes'])) | |||||
| knowledge_retrieval_node = next(filter( | |||||
| lambda n: n['data']['type'] == NodeType.KNOWLEDGE_RETRIEVAL.value, | |||||
| graph['nodes'] | |||||
| ), None) | |||||
| start_node = next(filter(lambda n: n["data"]["type"] == NodeType.START.value, graph["nodes"])) | |||||
| knowledge_retrieval_node = next( | |||||
| filter(lambda n: n["data"]["type"] == NodeType.KNOWLEDGE_RETRIEVAL.value, graph["nodes"]), None | |||||
| ) | |||||
| role_prefix = None | role_prefix = None | ||||
| # Chat Model | # Chat Model | ||||
| if model_config.mode == LLMMode.CHAT.value: | if model_config.mode == LLMMode.CHAT.value: | ||||
| if prompt_template.prompt_type == PromptTemplateEntity.PromptType.SIMPLE: | if prompt_template.prompt_type == PromptTemplateEntity.PromptType.SIMPLE: | ||||
| if not prompt_template.simple_prompt_template: | |||||
| raise ValueError("Simple prompt template is required") | |||||
| # get prompt template | # get prompt template | ||||
| prompt_transform = SimplePromptTransform() | prompt_transform = SimplePromptTransform() | ||||
| prompt_template_config = prompt_transform.get_prompt_template( | prompt_template_config = prompt_transform.get_prompt_template( | ||||
| model=model_config.model, | model=model_config.model, | ||||
| pre_prompt=prompt_template.simple_prompt_template, | pre_prompt=prompt_template.simple_prompt_template, | ||||
| has_context=knowledge_retrieval_node is not None, | has_context=knowledge_retrieval_node is not None, | ||||
| query_in_prompt=False | |||||
| query_in_prompt=False, | |||||
| ) | ) | ||||
| template = prompt_template_config['prompt_template'].template | |||||
| template = prompt_template_config["prompt_template"].template | |||||
| if not template: | if not template: | ||||
| prompts = [] | prompts = [] | ||||
| else: | else: | ||||
| template = self._replace_template_variables( | template = self._replace_template_variables( | ||||
| template, | |||||
| start_node['data']['variables'], | |||||
| external_data_variable_node_mapping | |||||
| template, start_node["data"]["variables"], external_data_variable_node_mapping | |||||
| ) | ) | ||||
| prompts = [ | |||||
| { | |||||
| "role": 'user', | |||||
| "text": template | |||||
| } | |||||
| ] | |||||
| prompts = [{"role": "user", "text": template}] | |||||
| else: | else: | ||||
| advanced_chat_prompt_template = prompt_template.advanced_chat_prompt_template | advanced_chat_prompt_template = prompt_template.advanced_chat_prompt_template | ||||
| prompts = [] | prompts = [] | ||||
| for m in advanced_chat_prompt_template.messages: | |||||
| if advanced_chat_prompt_template: | |||||
| if advanced_chat_prompt_template: | |||||
| for m in advanced_chat_prompt_template.messages: | |||||
| text = m.text | text = m.text | ||||
| text = self._replace_template_variables( | text = self._replace_template_variables( | ||||
| text, | |||||
| start_node['data']['variables'], | |||||
| external_data_variable_node_mapping | |||||
| text, start_node["data"]["variables"], external_data_variable_node_mapping | |||||
| ) | ) | ||||
| prompts.append({ | |||||
| "role": m.role.value, | |||||
| "text": text | |||||
| }) | |||||
| prompts.append({"role": m.role.value, "text": text}) | |||||
| # Completion Model | # Completion Model | ||||
| else: | else: | ||||
| if prompt_template.prompt_type == PromptTemplateEntity.PromptType.SIMPLE: | if prompt_template.prompt_type == PromptTemplateEntity.PromptType.SIMPLE: | ||||
| if not prompt_template.simple_prompt_template: | |||||
| raise ValueError("Simple prompt template is required") | |||||
| # get prompt template | # get prompt template | ||||
| prompt_transform = SimplePromptTransform() | prompt_transform = SimplePromptTransform() | ||||
| prompt_template_config = prompt_transform.get_prompt_template( | prompt_template_config = prompt_transform.get_prompt_template( | ||||
| model=model_config.model, | model=model_config.model, | ||||
| pre_prompt=prompt_template.simple_prompt_template, | pre_prompt=prompt_template.simple_prompt_template, | ||||
| has_context=knowledge_retrieval_node is not None, | has_context=knowledge_retrieval_node is not None, | ||||
| query_in_prompt=False | |||||
| query_in_prompt=False, | |||||
| ) | ) | ||||
| template = prompt_template_config['prompt_template'].template | |||||
| template = prompt_template_config["prompt_template"].template | |||||
| template = self._replace_template_variables( | template = self._replace_template_variables( | ||||
| template, | |||||
| start_node['data']['variables'], | |||||
| external_data_variable_node_mapping | |||||
| template=template, | |||||
| variables=start_node["data"]["variables"], | |||||
| external_data_variable_node_mapping=external_data_variable_node_mapping, | |||||
| ) | ) | ||||
| prompts = { | |||||
| "text": template | |||||
| } | |||||
| prompts = {"text": template} | |||||
| prompt_rules = prompt_template_config['prompt_rules'] | |||||
| prompt_rules = prompt_template_config["prompt_rules"] | |||||
| role_prefix = { | role_prefix = { | ||||
| "user": prompt_rules.get('human_prefix', 'Human'), | |||||
| "assistant": prompt_rules.get('assistant_prefix', 'Assistant') | |||||
| "user": prompt_rules.get("human_prefix", "Human"), | |||||
| "assistant": prompt_rules.get("assistant_prefix", "Assistant"), | |||||
| } | } | ||||
| else: | else: | ||||
| advanced_completion_prompt_template = prompt_template.advanced_completion_prompt_template | advanced_completion_prompt_template = prompt_template.advanced_completion_prompt_template | ||||
| if advanced_completion_prompt_template: | if advanced_completion_prompt_template: | ||||
| text = advanced_completion_prompt_template.prompt | text = advanced_completion_prompt_template.prompt | ||||
| text = self._replace_template_variables( | text = self._replace_template_variables( | ||||
| text, | |||||
| start_node['data']['variables'], | |||||
| external_data_variable_node_mapping | |||||
| template=text, | |||||
| variables=start_node["data"]["variables"], | |||||
| external_data_variable_node_mapping=external_data_variable_node_mapping, | |||||
| ) | ) | ||||
| else: | else: | ||||
| text = "" | text = "" | ||||
| text = text.replace('{{#query#}}', '{{#sys.query#}}') | |||||
| text = text.replace("{{#query#}}", "{{#sys.query#}}") | |||||
| prompts = { | prompts = { | ||||
| "text": text, | "text": text, | ||||
| } | } | ||||
| if advanced_completion_prompt_template.role_prefix: | |||||
| if advanced_completion_prompt_template and advanced_completion_prompt_template.role_prefix: | |||||
| role_prefix = { | role_prefix = { | ||||
| "user": advanced_completion_prompt_template.role_prefix.user, | "user": advanced_completion_prompt_template.role_prefix.user, | ||||
| "assistant": advanced_completion_prompt_template.role_prefix.assistant | |||||
| "assistant": advanced_completion_prompt_template.role_prefix.assistant, | |||||
| } | } | ||||
| memory = None | memory = None | ||||
| if new_app_mode == AppMode.ADVANCED_CHAT: | if new_app_mode == AppMode.ADVANCED_CHAT: | ||||
| memory = { | |||||
| "role_prefix": role_prefix, | |||||
| "window": { | |||||
| "enabled": False | |||||
| } | |||||
| } | |||||
| memory = {"role_prefix": role_prefix, "window": {"enabled": False}} | |||||
| completion_params = model_config.parameters | completion_params = model_config.parameters | ||||
| completion_params.update({"stop": model_config.stop}) | completion_params.update({"stop": model_config.stop}) | ||||
| "provider": model_config.provider, | "provider": model_config.provider, | ||||
| "name": model_config.model, | "name": model_config.model, | ||||
| "mode": model_config.mode, | "mode": model_config.mode, | ||||
| "completion_params": completion_params | |||||
| "completion_params": completion_params, | |||||
| }, | }, | ||||
| "prompt_template": prompts, | "prompt_template": prompts, | ||||
| "memory": memory, | "memory": memory, | ||||
| "context": { | "context": { | ||||
| "enabled": knowledge_retrieval_node is not None, | "enabled": knowledge_retrieval_node is not None, | ||||
| "variable_selector": ["knowledge_retrieval", "result"] | "variable_selector": ["knowledge_retrieval", "result"] | ||||
| if knowledge_retrieval_node is not None else None | |||||
| if knowledge_retrieval_node is not None | |||||
| else None, | |||||
| }, | }, | ||||
| "vision": { | "vision": { | ||||
| "enabled": file_upload is not None, | "enabled": file_upload is not None, | ||||
| "variable_selector": ["sys", "files"] if file_upload is not None else None, | "variable_selector": ["sys", "files"] if file_upload is not None else None, | ||||
| "configs": { | |||||
| "detail": file_upload.image_config['detail'] | |||||
| } if file_upload is not None else None | |||||
| } | |||||
| } | |||||
| "configs": {"detail": file_upload.image_config["detail"]} | |||||
| if file_upload is not None and file_upload.image_config is not None | |||||
| else None, | |||||
| }, | |||||
| }, | |||||
| } | } | ||||
| def _replace_template_variables(self, template: str, | |||||
| variables: list[dict], | |||||
| external_data_variable_node_mapping: dict[str, str] = None) -> str: | |||||
| def _replace_template_variables( | |||||
| self, template: str, variables: list[dict], external_data_variable_node_mapping: dict[str, str] | None = None | |||||
| ) -> str: | |||||
| """ | """ | ||||
| Replace Template Variables | Replace Template Variables | ||||
| :param template: template | :param template: template | ||||
| :return: | :return: | ||||
| """ | """ | ||||
| for v in variables: | for v in variables: | ||||
| template = template.replace('{{' + v['variable'] + '}}', '{{#start.' + v['variable'] + '#}}') | |||||
| template = template.replace("{{" + v["variable"] + "}}", "{{#start." + v["variable"] + "#}}") | |||||
| if external_data_variable_node_mapping: | if external_data_variable_node_mapping: | ||||
| for variable, code_node_id in external_data_variable_node_mapping.items(): | for variable, code_node_id in external_data_variable_node_mapping.items(): | ||||
| template = template.replace('{{' + variable + '}}', | |||||
| '{{#' + code_node_id + '.result#}}') | |||||
| template = template.replace("{{" + variable + "}}", "{{#" + code_node_id + ".result#}}") | |||||
| return template | return template | ||||
| "data": { | "data": { | ||||
| "title": "END", | "title": "END", | ||||
| "type": NodeType.END.value, | "type": NodeType.END.value, | ||||
| "outputs": [{ | |||||
| "variable": "result", | |||||
| "value_selector": ["llm", "text"] | |||||
| }] | |||||
| } | |||||
| "outputs": [{"variable": "result", "value_selector": ["llm", "text"]}], | |||||
| }, | |||||
| } | } | ||||
| def _convert_to_answer_node(self) -> dict: | def _convert_to_answer_node(self) -> dict: | ||||
| return { | return { | ||||
| "id": "answer", | "id": "answer", | ||||
| "position": None, | "position": None, | ||||
| "data": { | |||||
| "title": "ANSWER", | |||||
| "type": NodeType.ANSWER.value, | |||||
| "answer": "{{#llm.text#}}" | |||||
| } | |||||
| "data": {"title": "ANSWER", "type": NodeType.ANSWER.value, "answer": "{{#llm.text#}}"}, | |||||
| } | } | ||||
| def _create_edge(self, source: str, target: str) -> dict: | def _create_edge(self, source: str, target: str) -> dict: | ||||
| :param target: target node id | :param target: target node id | ||||
| :return: | :return: | ||||
| """ | """ | ||||
| return { | |||||
| "id": f"{source}-{target}", | |||||
| "source": source, | |||||
| "target": target | |||||
| } | |||||
| return {"id": f"{source}-{target}", "source": source, "target": target} | |||||
| def _append_node(self, graph: dict, node: dict) -> dict: | def _append_node(self, graph: dict, node: dict) -> dict: | ||||
| """ | """ | ||||
| :param node: Node to append | :param node: Node to append | ||||
| :return: | :return: | ||||
| """ | """ | ||||
| previous_node = graph['nodes'][-1] | |||||
| graph['nodes'].append(node) | |||||
| graph['edges'].append(self._create_edge(previous_node['id'], node['id'])) | |||||
| previous_node = graph["nodes"][-1] | |||||
| graph["nodes"].append(node) | |||||
| graph["edges"].append(self._create_edge(previous_node["id"], node["id"])) | |||||
| return graph | return graph | ||||
| def _get_new_app_mode(self, app_model: App) -> AppMode: | def _get_new_app_mode(self, app_model: App) -> AppMode: | ||||
| else: | else: | ||||
| return AppMode.ADVANCED_CHAT | return AppMode.ADVANCED_CHAT | ||||
| def _get_api_based_extension(self, tenant_id: str, api_based_extension_id: str) -> APIBasedExtension: | |||||
| def _get_api_based_extension(self, tenant_id: str, api_based_extension_id: str): | |||||
| """ | """ | ||||
| Get API Based Extension | Get API Based Extension | ||||
| :param tenant_id: tenant id | :param tenant_id: tenant id | ||||
| :param api_based_extension_id: api based extension id | :param api_based_extension_id: api based extension id | ||||
| :return: | :return: | ||||
| """ | """ | ||||
| return db.session.query(APIBasedExtension).filter( | |||||
| APIBasedExtension.tenant_id == tenant_id, | |||||
| APIBasedExtension.id == api_based_extension_id | |||||
| ).first() | |||||
| api_based_extension = ( | |||||
| db.session.query(APIBasedExtension) | |||||
| .filter(APIBasedExtension.tenant_id == tenant_id, APIBasedExtension.id == api_based_extension_id) | |||||
| .first() | |||||
| ) | |||||
| if not api_based_extension: | |||||
| raise ValueError(f"API Based Extension not found, id: {api_based_extension_id}") | |||||
| return api_based_extension |