Commit fc243982 authored by takatost's avatar takatost

add api extension to http request node convert

parent df66cd22
import concurrent import concurrent
import json
import logging import logging
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from typing import Optional from typing import Optional
...@@ -28,12 +27,6 @@ class ExternalDataFetchFeature: ...@@ -28,12 +27,6 @@ class ExternalDataFetchFeature:
:param query: the query :param query: the query
:return: the filled inputs :return: the filled inputs
""" """
# Group tools by type and config
grouped_tools = {}
for tool in external_data_tools:
tool_key = (tool.type, json.dumps(tool.config, sort_keys=True))
grouped_tools.setdefault(tool_key, []).append(tool)
results = {} results = {}
with ThreadPoolExecutor() as executor: with ThreadPoolExecutor() as executor:
futures = {} futures = {}
......
...@@ -11,6 +11,7 @@ from core.entities.application_entities import ( ...@@ -11,6 +11,7 @@ from core.entities.application_entities import (
PromptTemplateEntity, PromptTemplateEntity,
VariableEntity, VariableEntity,
) )
from core.helper import encrypter
from core.model_runtime.entities.llm_entities import LLMMode from core.model_runtime.entities.llm_entities import LLMMode
from core.model_runtime.utils import helper from core.model_runtime.utils import helper
from core.prompt.simple_prompt_transform import SimplePromptTransform from core.prompt.simple_prompt_transform import SimplePromptTransform
...@@ -18,6 +19,7 @@ from core.workflow.entities.NodeEntities import NodeType ...@@ -18,6 +19,7 @@ from core.workflow.entities.NodeEntities import NodeType
from core.workflow.nodes.end.entities import EndNodeOutputType from core.workflow.nodes.end.entities import EndNodeOutputType
from extensions.ext_database import db from extensions.ext_database import db
from models.account import Account from models.account import Account
from models.api_based_extension import APIBasedExtension, APIBasedExtensionPoint
from models.model import App, AppMode, ChatbotAppEngine from models.model import App, AppMode, ChatbotAppEngine
from models.workflow import Workflow, WorkflowType from models.workflow import Workflow, WorkflowType
...@@ -49,7 +51,7 @@ class WorkflowConverter: ...@@ -49,7 +51,7 @@ class WorkflowConverter:
# convert app model config # convert app model config
application_manager = ApplicationManager() application_manager = ApplicationManager()
application_manager.convert_from_app_model_config_dict( app_orchestration_config_entity = application_manager.convert_from_app_model_config_dict(
tenant_id=app_model.tenant_id, tenant_id=app_model.tenant_id,
app_model_config_dict=app_model_config.to_dict() app_model_config_dict=app_model_config.to_dict()
) )
...@@ -71,24 +73,27 @@ class WorkflowConverter: ...@@ -71,24 +73,27 @@ class WorkflowConverter:
# convert to start node # convert to start node
start_node = self._convert_to_start_node( start_node = self._convert_to_start_node(
variables=app_model_config.variables variables=app_orchestration_config_entity.variables
) )
graph['nodes'].append(start_node) graph['nodes'].append(start_node)
# convert to http request node # convert to http request node
if app_model_config.external_data_variables: if app_orchestration_config_entity.external_data_variables:
http_request_node = self._convert_to_http_request_node( http_request_nodes = self._convert_to_http_request_node(
external_data_variables=app_model_config.external_data_variables app_model=app_model,
variables=app_orchestration_config_entity.variables,
external_data_variables=app_orchestration_config_entity.external_data_variables
) )
for http_request_node in http_request_nodes:
graph = self._append_node(graph, http_request_node) graph = self._append_node(graph, http_request_node)
# convert to knowledge retrieval node # convert to knowledge retrieval node
if app_model_config.dataset: if app_orchestration_config_entity.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, new_app_mode=new_app_mode,
dataset_config=app_model_config.dataset dataset_config=app_orchestration_config_entity.dataset
) )
if knowledge_retrieval_node: if knowledge_retrieval_node:
...@@ -98,9 +103,9 @@ class WorkflowConverter: ...@@ -98,9 +103,9 @@ class WorkflowConverter:
llm_node = self._convert_to_llm_node( llm_node = self._convert_to_llm_node(
new_app_mode=new_app_mode, new_app_mode=new_app_mode,
graph=graph, graph=graph,
model_config=app_model_config.model_config, model_config=app_orchestration_config_entity.model_config,
prompt_template=app_model_config.prompt_template, prompt_template=app_orchestration_config_entity.prompt_template,
file_upload=app_model_config.file_upload file_upload=app_orchestration_config_entity.file_upload
) )
graph = self._append_node(graph, llm_node) graph = self._append_node(graph, llm_node)
...@@ -160,14 +165,130 @@ class WorkflowConverter: ...@@ -160,14 +165,130 @@ class WorkflowConverter:
} }
} }
def _convert_to_http_request_node(self, external_data_variables: list[ExternalDataVariableEntity]) -> dict: def _convert_to_http_request_node(self, app_model: App,
variables: list[VariableEntity],
external_data_variables: list[ExternalDataVariableEntity]) -> list[dict]:
""" """
Convert API Based Extension to HTTP Request Node Convert API Based Extension to HTTP Request Node
:param app_model: App instance
:param variables: list of variables
:param external_data_variables: list of external data variables :param external_data_variables: list of external data variables
:return: :return:
""" """
# TODO: implement index = 1
pass nodes = []
tenant_id = app_model.tenant_id
for external_data_variable in external_data_variables:
tool_type = external_data_variable.type
if tool_type != "api":
continue
tool_variable = external_data_variable.variable
tool_config = external_data_variable.config
# get params from config
api_based_extension_id = tool_config.get("api_based_extension_id")
# get api_based_extension
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("[External data tool] API query failed, variable: {}, "
"error: api_based_extension_id is invalid"
.format(tool_variable))
# decrypt api_key
api_key = encrypter.decrypt_token(
tenant_id=tenant_id,
token=api_based_extension.api_key
)
http_request_variables = []
inputs = {}
for v in variables:
http_request_variables.append({
"variable": v.variable,
"value_selector": ["start", v.variable]
})
inputs[v.variable] = '{{' + v.variable + '}}'
if app_model.mode == AppMode.CHAT.value:
http_request_variables.append({
"variable": "_query",
"value_selector": ["start", "sys.query"]
})
request_body = {
'point': APIBasedExtensionPoint.APP_EXTERNAL_DATA_TOOL_QUERY.value,
'params': {
'app_id': app_model.id,
'tool_variable': tool_variable,
'inputs': inputs,
'query': '{{_query}}' if app_model.mode == AppMode.CHAT.value else ''
}
}
request_body_json = json.dumps(request_body)
request_body_json = request_body_json.replace('\{\{', '{{').replace('\}\}', '}}')
http_request_node = {
"id": f"http-request-{index}",
"position": None,
"data": {
"title": f"HTTP REQUEST {api_based_extension.name}",
"type": NodeType.HTTP_REQUEST.value,
"variables": http_request_variables,
"method": "post",
"url": api_based_extension.api_endpoint,
"authorization": {
"type": "api-key",
"config": {
"type": "bearer",
"api_key": api_key
}
},
"headers": "",
"params": "",
"body": {
"type": "json",
"data": request_body_json
}
}
}
index += 1
nodes.append(http_request_node)
# append code node for response body parsing
code_node = {
"id": f"code-{index}",
"position": None,
"data": {
"title": f"Parse {api_based_extension.name} response",
"type": NodeType.CODE.value,
"variables": [{
"variable": "response_json",
"value_selector": [http_request_node['id'], "body"]
}],
"code_language": "python3",
"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": [
{
"variable": "result",
"variable_type": "string"
}
]
}
}
nodes.append(code_node)
return nodes
def _convert_to_knowledge_retrieval_node(self, new_app_mode: AppMode, dataset_config: DatasetEntity) \ def _convert_to_knowledge_retrieval_node(self, new_app_mode: AppMode, dataset_config: DatasetEntity) \
-> Optional[dict]: -> Optional[dict]:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment