fix: run_flow_from_json circular dependency (#2485)
* fix: run_flow_from_json circular dependency * fix: run_flow_from_json circular dependency * fix: run_flow_from_json circular dependency * fix mypy * fix mypy * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
e244157be6
commit
fb29b248be
2 changed files with 115 additions and 116 deletions
|
|
@ -50,116 +50,3 @@ class PromptValidationResponse(BaseModel):
|
||||||
input_variables: list
|
input_variables: list
|
||||||
# object return for tweak call
|
# object return for tweak call
|
||||||
frontend_node: Optional[FrontendNodeRequest] = None
|
frontend_node: Optional[FrontendNodeRequest] = None
|
||||||
|
|
||||||
|
|
||||||
INVALID_CHARACTERS = {
|
|
||||||
" ",
|
|
||||||
",",
|
|
||||||
".",
|
|
||||||
":",
|
|
||||||
";",
|
|
||||||
"!",
|
|
||||||
"?",
|
|
||||||
"/",
|
|
||||||
"\\",
|
|
||||||
"(",
|
|
||||||
")",
|
|
||||||
"[",
|
|
||||||
"]",
|
|
||||||
}
|
|
||||||
|
|
||||||
INVALID_NAMES = {
|
|
||||||
"input_variables",
|
|
||||||
"output_parser",
|
|
||||||
"partial_variables",
|
|
||||||
"template",
|
|
||||||
"template_format",
|
|
||||||
"validate_template",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def is_json_like(var):
|
|
||||||
if var.startswith("{{") and var.endswith("}}"):
|
|
||||||
# If it is a double brance variable
|
|
||||||
# we don't want to validate any of its content
|
|
||||||
return True
|
|
||||||
# the above doesn't work on all cases because the json string can be multiline
|
|
||||||
# or indented which can add \n or spaces at the start or end of the string
|
|
||||||
# test_case_3 new_var == '\n{{\n "test": "hello",\n "text": "world"\n}}\n'
|
|
||||||
# what we can do is to remove the \n and spaces from the start and end of the string
|
|
||||||
# and then check if the string starts with {{ and ends with }}
|
|
||||||
var = var.strip()
|
|
||||||
var = var.replace("\n", "")
|
|
||||||
var = var.replace(" ", "")
|
|
||||||
# Now it should be a valid json string
|
|
||||||
return var.startswith("{{") and var.endswith("}}")
|
|
||||||
|
|
||||||
|
|
||||||
def fix_variable(var, invalid_chars, wrong_variables):
|
|
||||||
if not var:
|
|
||||||
return var, invalid_chars, wrong_variables
|
|
||||||
new_var = var
|
|
||||||
|
|
||||||
# Handle variables starting with a number
|
|
||||||
if var[0].isdigit():
|
|
||||||
invalid_chars.append(var[0])
|
|
||||||
new_var, invalid_chars, wrong_variables = fix_variable(var[1:], invalid_chars, wrong_variables)
|
|
||||||
|
|
||||||
# Temporarily replace {{ and }} to avoid treating them as invalid
|
|
||||||
new_var = new_var.replace("{{", "ᴛᴇᴍᴘᴏᴘᴇɴ").replace("}}", "ᴛᴇᴍᴘᴄʟᴏsᴇ")
|
|
||||||
|
|
||||||
# Remove invalid characters
|
|
||||||
for char in new_var:
|
|
||||||
if char in INVALID_CHARACTERS:
|
|
||||||
invalid_chars.append(char)
|
|
||||||
new_var = new_var.replace(char, "")
|
|
||||||
if var not in wrong_variables: # Avoid duplicating entries
|
|
||||||
wrong_variables.append(var)
|
|
||||||
|
|
||||||
# Restore {{ and }}
|
|
||||||
new_var = new_var.replace("ᴛᴇᴍᴘᴏᴘᴇɴ", "{{").replace("ᴛᴇᴍᴘᴄʟᴏsᴇ", "}}")
|
|
||||||
|
|
||||||
return new_var, invalid_chars, wrong_variables
|
|
||||||
|
|
||||||
|
|
||||||
def check_variable(var, invalid_chars, wrong_variables, empty_variables):
|
|
||||||
if any(char in invalid_chars for char in var):
|
|
||||||
wrong_variables.append(var)
|
|
||||||
elif var == "":
|
|
||||||
empty_variables.append(var)
|
|
||||||
return wrong_variables, empty_variables
|
|
||||||
|
|
||||||
|
|
||||||
def check_for_errors(input_variables, fixed_variables, wrong_variables, empty_variables):
|
|
||||||
if any(var for var in input_variables if var not in fixed_variables):
|
|
||||||
error_message = (
|
|
||||||
f"Error: Input variables contain invalid characters or formats. \n"
|
|
||||||
f"Invalid variables: {', '.join(wrong_variables)}.\n"
|
|
||||||
f"Empty variables: {', '.join(empty_variables)}. \n"
|
|
||||||
f"Fixed variables: {', '.join(fixed_variables)}."
|
|
||||||
)
|
|
||||||
raise ValueError(error_message)
|
|
||||||
|
|
||||||
|
|
||||||
def check_input_variables(input_variables):
|
|
||||||
invalid_chars = []
|
|
||||||
fixed_variables = []
|
|
||||||
wrong_variables = []
|
|
||||||
empty_variables = []
|
|
||||||
variables_to_check = []
|
|
||||||
|
|
||||||
for var in input_variables:
|
|
||||||
# First, let's check if the variable is a JSON string
|
|
||||||
# because if it is, it won't be considered a variable
|
|
||||||
# and we don't need to validate it
|
|
||||||
if is_json_like(var):
|
|
||||||
continue
|
|
||||||
|
|
||||||
new_var, wrong_variables, empty_variables = fix_variable(var, invalid_chars, wrong_variables)
|
|
||||||
wrong_variables, empty_variables = check_variable(var, INVALID_CHARACTERS, wrong_variables, empty_variables)
|
|
||||||
fixed_variables.append(new_var)
|
|
||||||
variables_to_check.append(var)
|
|
||||||
|
|
||||||
check_for_errors(variables_to_check, fixed_variables, wrong_variables, empty_variables)
|
|
||||||
|
|
||||||
return fixed_variables
|
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,129 @@ from fastapi import HTTPException
|
||||||
from langchain_core.prompts import PromptTemplate
|
from langchain_core.prompts import PromptTemplate
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from langflow.api.v1.base import INVALID_NAMES, check_input_variables
|
|
||||||
from langflow.interface.utils import extract_input_variables_from_prompt
|
from langflow.interface.utils import extract_input_variables_from_prompt
|
||||||
from langflow.template.field.prompt import DefaultPromptField
|
from langflow.template.field.prompt import DefaultPromptField
|
||||||
|
|
||||||
|
|
||||||
|
_INVALID_CHARACTERS = {
|
||||||
|
" ",
|
||||||
|
",",
|
||||||
|
".",
|
||||||
|
":",
|
||||||
|
";",
|
||||||
|
"!",
|
||||||
|
"?",
|
||||||
|
"/",
|
||||||
|
"\\",
|
||||||
|
"(",
|
||||||
|
")",
|
||||||
|
"[",
|
||||||
|
"]",
|
||||||
|
}
|
||||||
|
|
||||||
|
_INVALID_NAMES = {
|
||||||
|
"input_variables",
|
||||||
|
"output_parser",
|
||||||
|
"partial_variables",
|
||||||
|
"template",
|
||||||
|
"template_format",
|
||||||
|
"validate_template",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _is_json_like(var):
|
||||||
|
if var.startswith("{{") and var.endswith("}}"):
|
||||||
|
# If it is a double brance variable
|
||||||
|
# we don't want to validate any of its content
|
||||||
|
return True
|
||||||
|
# the above doesn't work on all cases because the json string can be multiline
|
||||||
|
# or indented which can add \n or spaces at the start or end of the string
|
||||||
|
# test_case_3 new_var == '\n{{\n "test": "hello",\n "text": "world"\n}}\n'
|
||||||
|
# what we can do is to remove the \n and spaces from the start and end of the string
|
||||||
|
# and then check if the string starts with {{ and ends with }}
|
||||||
|
var = var.strip()
|
||||||
|
var = var.replace("\n", "")
|
||||||
|
var = var.replace(" ", "")
|
||||||
|
# Now it should be a valid json string
|
||||||
|
return var.startswith("{{") and var.endswith("}}")
|
||||||
|
|
||||||
|
|
||||||
|
def _fix_variable(var, invalid_chars, wrong_variables):
|
||||||
|
if not var:
|
||||||
|
return var, invalid_chars, wrong_variables
|
||||||
|
new_var = var
|
||||||
|
|
||||||
|
# Handle variables starting with a number
|
||||||
|
if var[0].isdigit():
|
||||||
|
invalid_chars.append(var[0])
|
||||||
|
new_var, invalid_chars, wrong_variables = _fix_variable(var[1:], invalid_chars, wrong_variables)
|
||||||
|
|
||||||
|
# Temporarily replace {{ and }} to avoid treating them as invalid
|
||||||
|
new_var = new_var.replace("{{", "ᴛᴇᴍᴘᴏᴘᴇɴ").replace("}}", "ᴛᴇᴍᴘᴄʟᴏsᴇ")
|
||||||
|
|
||||||
|
# Remove invalid characters
|
||||||
|
for char in new_var:
|
||||||
|
if char in _INVALID_CHARACTERS:
|
||||||
|
invalid_chars.append(char)
|
||||||
|
new_var = new_var.replace(char, "")
|
||||||
|
if var not in wrong_variables: # Avoid duplicating entries
|
||||||
|
wrong_variables.append(var)
|
||||||
|
|
||||||
|
# Restore {{ and }}
|
||||||
|
new_var = new_var.replace("ᴛᴇᴍᴘᴏᴘᴇɴ", "{{").replace("ᴛᴇᴍᴘᴄʟᴏsᴇ", "}}")
|
||||||
|
|
||||||
|
return new_var, invalid_chars, wrong_variables
|
||||||
|
|
||||||
|
|
||||||
|
def _check_variable(var, invalid_chars, wrong_variables, empty_variables):
|
||||||
|
if any(char in invalid_chars for char in var):
|
||||||
|
wrong_variables.append(var)
|
||||||
|
elif var == "":
|
||||||
|
empty_variables.append(var)
|
||||||
|
return wrong_variables, empty_variables
|
||||||
|
|
||||||
|
|
||||||
|
def _check_for_errors(input_variables, fixed_variables, wrong_variables, empty_variables):
|
||||||
|
if any(var for var in input_variables if var not in fixed_variables):
|
||||||
|
error_message = (
|
||||||
|
f"Error: Input variables contain invalid characters or formats. \n"
|
||||||
|
f"Invalid variables: {', '.join(wrong_variables)}.\n"
|
||||||
|
f"Empty variables: {', '.join(empty_variables)}. \n"
|
||||||
|
f"Fixed variables: {', '.join(fixed_variables)}."
|
||||||
|
)
|
||||||
|
raise ValueError(error_message)
|
||||||
|
|
||||||
|
|
||||||
|
def _check_input_variables(input_variables):
|
||||||
|
invalid_chars = []
|
||||||
|
fixed_variables = []
|
||||||
|
wrong_variables = []
|
||||||
|
empty_variables = []
|
||||||
|
variables_to_check = []
|
||||||
|
|
||||||
|
for var in input_variables:
|
||||||
|
# First, let's check if the variable is a JSON string
|
||||||
|
# because if it is, it won't be considered a variable
|
||||||
|
# and we don't need to validate it
|
||||||
|
if _is_json_like(var):
|
||||||
|
continue
|
||||||
|
|
||||||
|
new_var, wrong_variables, empty_variables = _fix_variable(var, invalid_chars, wrong_variables)
|
||||||
|
wrong_variables, empty_variables = _check_variable(var, _INVALID_CHARACTERS, wrong_variables, empty_variables)
|
||||||
|
fixed_variables.append(new_var)
|
||||||
|
variables_to_check.append(var)
|
||||||
|
|
||||||
|
_check_for_errors(variables_to_check, fixed_variables, wrong_variables, empty_variables)
|
||||||
|
|
||||||
|
return fixed_variables
|
||||||
|
|
||||||
|
|
||||||
def validate_prompt(prompt_template: str, silent_errors: bool = False) -> list[str]:
|
def validate_prompt(prompt_template: str, silent_errors: bool = False) -> list[str]:
|
||||||
input_variables = extract_input_variables_from_prompt(prompt_template)
|
input_variables = extract_input_variables_from_prompt(prompt_template)
|
||||||
|
|
||||||
# Check if there are invalid characters in the input_variables
|
# Check if there are invalid characters in the input_variables
|
||||||
input_variables = check_input_variables(input_variables)
|
input_variables = _check_input_variables(input_variables)
|
||||||
if any(var in INVALID_NAMES for var in input_variables):
|
if any(var in _INVALID_NAMES for var in input_variables):
|
||||||
raise ValueError(f"Invalid input variables. None of the variables can be named {', '.join(input_variables)}. ")
|
raise ValueError(f"Invalid input variables. None of the variables can be named {', '.join(input_variables)}. ")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue