feat: template transform

This commit is contained in:
Yeuoly
2024-03-09 22:49:53 +08:00
committed by takatost
parent 3d5f9b5a1e
commit 2895c3bc8c
10 changed files with 114 additions and 9 deletions

View File

@ -1,70 +0,0 @@
from os import environ
from httpx import post
from pydantic import BaseModel
from yarl import URL
from core.workflow.nodes.code.python_template import PythonTemplateTransformer
# Code Executor
CODE_EXECUTION_ENDPOINT = environ.get('CODE_EXECUTION_ENDPOINT', '')
CODE_EXECUTION_API_KEY = environ.get('CODE_EXECUTION_API_KEY', '')
class CodeExecutionException(Exception):
pass
class CodeExecutionResponse(BaseModel):
class Data(BaseModel):
stdout: str
stderr: str
code: int
message: str
data: Data
class CodeExecutor:
@classmethod
def execute_code(cls, language: str, code: str, inputs: dict) -> dict:
"""
Execute code
:param language: code language
:param code: code
:param inputs: inputs
:return:
"""
runner = PythonTemplateTransformer.transform_caller(code, inputs)
url = URL(CODE_EXECUTION_ENDPOINT) / 'v1' / 'sandbox' / 'run'
headers = {
'X-Api-Key': CODE_EXECUTION_API_KEY
}
data = {
'language': language,
'code': runner,
}
try:
response = post(str(url), json=data, headers=headers)
if response.status_code == 503:
raise CodeExecutionException('Code execution service is unavailable')
elif response.status_code != 200:
raise Exception('Failed to execute code')
except CodeExecutionException as e:
raise e
except Exception:
raise CodeExecutionException('Failed to execute code')
try:
response = response.json()
except:
raise CodeExecutionException('Failed to parse response')
response = CodeExecutionResponse(**response)
if response.code != 0:
raise CodeExecutionException(response.message)
if response.data.stderr:
raise CodeExecutionException(response.data.stderr)
return PythonTemplateTransformer.transform_response(response.data.stdout)

View File

@ -1,9 +1,9 @@
from typing import Optional, Union, cast
from core.helper.code_executor.code_executor import CodeExecutionException, CodeExecutor
from core.workflow.entities.node_entities import NodeRunResult, NodeType
from core.workflow.entities.variable_pool import VariablePool
from core.workflow.nodes.base_node import BaseNode
from core.workflow.nodes.code.code_executor import CodeExecutionException, CodeExecutor
from core.workflow.nodes.code.entities import CodeNodeData
from models.workflow import WorkflowNodeExecutionStatus

View File

@ -16,6 +16,6 @@ class CodeNodeData(BaseNodeData):
variables: list[VariableSelector]
answer: str
code_language: str
code_language: Literal['python3', 'javascript']
code: str
outputs: dict[str, Output]

View File

@ -1,55 +0,0 @@
import json
import re
PYTHON_RUNNER = """# declare main function here
{{code}}
# execute main function, and return the result
# inputs is a dict, and it
output = main(**{{inputs}})
# convert output to json and print
result = '''
<<RESULT>>
{output}
<<RESULT>>
'''
print(result)
"""
class PythonTemplateTransformer:
@classmethod
def transform_caller(cls, code: str, inputs: dict) -> str:
"""
Transform code to python runner
:param code: code
:param inputs: inputs
:return:
"""
# transform inputs to json string
inputs_str = json.dumps(inputs, indent=4)
# replace code and inputs
runner = PYTHON_RUNNER.replace('{{code}}', code)
runner = runner.replace('{{inputs}}', inputs_str)
return runner
@classmethod
def transform_response(cls, response: str) -> dict:
"""
Transform response to dict
:param response: response
:return:
"""
# extract result
result = re.search(r'<<RESULT>>(.*)<<RESULT>>', response, re.DOTALL)
if not result:
raise ValueError('Failed to parse result')
result = result.group(1)
return json.loads(result)