Merge remote-tracking branch 'origin/dev' into add_cli_options_superuser

This commit is contained in:
Gabriel Luiz Freitas Almeida 2023-09-20 16:16:52 -03:00
commit 7733904378
52 changed files with 1055 additions and 526 deletions

View file

@ -56,7 +56,7 @@ def display_results(results):
def update_settings(
config: str,
cache: str,
cache: Optional[str] = None,
dev: bool = False,
remove_api_keys: bool = False,
components_path: Optional[Path] = None,
@ -154,10 +154,10 @@ def run(
log_file: Path = typer.Option(
"logs/langflow.log", help="Path to the log file.", envvar="LANGFLOW_LOG_FILE"
),
cache: str = typer.Option(
cache: Optional[str] = typer.Option(
envvar="LANGFLOW_LANGCHAIN_CACHE",
help="Type of cache to use. (InMemoryCache, SQLiteCache)",
default="SQLiteCache",
default=None,
),
jcloud: bool = typer.Option(False, help="Deploy on Jina AI Cloud"),
dev: bool = typer.Option(False, help="Run in development mode (may contain bugs)"),

View file

@ -58,6 +58,16 @@ def post_validate_prompt(prompt_request: ValidatePromptRequest):
def get_old_custom_fields(prompt_request):
try:
if (
len(prompt_request.frontend_node.custom_fields) == 1
and prompt_request.name == ""
):
# If there is only one custom field and the name is empty string
# then we are dealing with the first prompt request after the node was created
prompt_request.name = list(
prompt_request.frontend_node.custom_fields.keys()
)[0]
old_custom_fields = prompt_request.frontend_node.custom_fields[
prompt_request.name
].copy()

View file

@ -16,17 +16,14 @@ class PromptRunner(CustomComponent):
"info": "Make sure the prompt has all variables filled.",
},
"code": {"show": False},
"inputs": {"field_type": "code"},
}
def build(
self,
llm: BaseLLM,
prompt: PromptTemplate,
self, llm: BaseLLM, prompt: PromptTemplate, inputs: dict = {}
) -> Document:
chain = prompt | llm
# The input is an empty dict because the prompt is already filled
result = chain.invoke({})
result = chain.invoke(input=inputs)
if hasattr(result, "content"):
result = result.content
self.repr_value = result

View file

@ -14,7 +14,7 @@ class MetalRetrieverComponent(CustomComponent):
"api_key": {"display_name": "API Key", "password": True},
"client_id": {"display_name": "Client ID", "password": True},
"index_id": {"display_name": "Index ID"},
"params": {"display_name": "Parameters", "field_type": "code"},
"params": {"display_name": "Parameters"},
"code": {"show": False},
}

View file

@ -19,7 +19,6 @@ class GetRequest(CustomComponent):
},
"headers": {
"display_name": "Headers",
"field_type": "code",
"info": "The headers to send with the request.",
},
"code": {"show": False},

View file

@ -15,7 +15,6 @@ class PostRequest(CustomComponent):
"url": {"display_name": "URL", "info": "The URL to make the request to."},
"headers": {
"display_name": "Headers",
"field_type": "code",
"info": "The headers to send with the request.",
},
"code": {"show": False},

View file

@ -15,7 +15,7 @@ class UpdateRequest(CustomComponent):
"url": {"display_name": "URL", "info": "The URL to make the request to."},
"headers": {
"display_name": "Headers",
"field_type": "code",
"field_type": "NestedDict",
"info": "The headers to send with the request.",
},
"code": {"show": False},

View file

@ -0,0 +1,3 @@
from .base import NestedDict
__all__ = ["NestedDict"]

View file

@ -0,0 +1,4 @@
from typing import Union, Dict
# Type alias for more complex dicts
NestedDict = Dict[str, Union[str, Dict]]

View file

@ -122,6 +122,19 @@ class Vertex:
except Exception as exc:
logger.debug(f"Error parsing code: {exc}")
params[key] = value.get("value")
elif value.get("type") in ["dict", "NestedDict"]:
# When dict comes from the frontend it comes as a
# list of dicts, so we need to convert it to a dict
# before passing it to the build method
_value = value.get("value")
if isinstance(_value, list):
params[key] = {
k: v
for item in value.get("value", [])
for k, v in item.items()
}
elif isinstance(_value, dict):
params[key] = _value
else:
params[key] = value.get("value")

View file

@ -58,8 +58,12 @@ def get_memory_key(langchain_object):
"chat_history": "history",
"history": "chat_history",
}
memory_key = langchain_object.memory.memory_key
return mem_key_dict.get(memory_key)
# Check if memory_key attribute exists
if hasattr(langchain_object.memory, "memory_key"):
memory_key = langchain_object.memory.memory_key
return mem_key_dict.get(memory_key)
else:
return None # or some other default value or action
def update_memory_keys(langchain_object, possible_new_mem_key):

View file

@ -290,31 +290,42 @@ def add_base_classes(frontend_node, return_types: List[str]):
def build_langchain_template_custom_component(custom_component: CustomComponent):
"""Build a custom component template for the langchain"""
logger.debug("Building custom component template")
frontend_node = build_frontend_node(custom_component)
try:
logger.debug("Building custom component template")
frontend_node = build_frontend_node(custom_component)
if frontend_node is None:
return None
logger.debug("Built base frontend node")
template_config = custom_component.build_template_config
if frontend_node is None:
return None
logger.debug("Built base frontend node")
template_config = custom_component.build_template_config
update_attributes(frontend_node, template_config)
logger.debug("Updated attributes")
field_config = build_field_config(custom_component)
logger.debug("Built field config")
add_extra_fields(
frontend_node, field_config, custom_component.get_function_entrypoint_args
)
logger.debug("Added extra fields")
frontend_node = add_code_field(
frontend_node, custom_component.code, field_config.get("code", {})
)
logger.debug("Added code field")
add_base_classes(
frontend_node, custom_component.get_function_entrypoint_return_type
)
logger.debug("Added base classes")
return frontend_node
update_attributes(frontend_node, template_config)
logger.debug("Updated attributes")
field_config = build_field_config(custom_component)
logger.debug("Built field config")
add_extra_fields(
frontend_node, field_config, custom_component.get_function_entrypoint_args
)
logger.debug("Added extra fields")
frontend_node = add_code_field(
frontend_node, custom_component.code, field_config.get("code", {})
)
logger.debug("Added code field")
add_base_classes(
frontend_node, custom_component.get_function_entrypoint_return_type
)
logger.debug("Added base classes")
return frontend_node
except Exception as exc:
raise HTTPException(
status_code=400,
detail={
"error": (
"Invalid type convertion. Please check your code and try again."
),
"traceback": traceback.format_exc(),
},
) from exc
def load_files_from_path(path: str):

View file

@ -77,9 +77,16 @@ def set_langchain_cache(settings):
import langchain
from langflow.interface.importing.utils import import_class
cache_type = os.getenv("LANGFLOW_LANGCHAIN_CACHE")
cache_class = import_class(f"langchain.cache.{cache_type or settings.CACHE}")
if cache_type := os.getenv("LANGFLOW_LANGCHAIN_CACHE"):
try:
cache_class = import_class(
f"langchain.cache.{cache_type or settings.CACHE}"
)
logger.debug(f"Setting up LLM caching with {cache_class.__name__}")
langchain.llm_cache = cache_class()
logger.info(f"LLM caching setup with {cache_class.__name__}")
logger.debug(f"Setting up LLM caching with {cache_class.__name__}")
langchain.llm_cache = cache_class()
logger.info(f"LLM caching setup with {cache_class.__name__}")
except ImportError:
logger.warning(f"Could not import {cache_type}. ")
else:
logger.info("No LLM cache set.")

View file

@ -146,9 +146,8 @@ def generate_result(langchain_object: Union[Chain, VectorStore], inputs: dict):
elif isinstance(langchain_object, Document):
result = langchain_object.dict()
else:
raise ValueError(
f"Unknown langchain_object type: {type(langchain_object).__name__}"
)
logger.warning(f"Unknown langchain_object type: {type(langchain_object)}")
result = langchain_object
return result

View file

@ -37,7 +37,7 @@ class Settings(BaseSettings):
DEV: bool = False
DATABASE_URL: Optional[str] = None
CACHE: str = "InMemoryCache"
CACHE: Optional[str] = None
REMOVE_API_KEYS: bool = False
COMPONENTS_PATH: List[str] = []

View file

@ -140,13 +140,16 @@ class FrontendNode(BaseModel):
@staticmethod
def handle_dict_type(field: TemplateField, _type: str) -> str:
"""Handles 'dict' type by replacing it with 'code' or 'file' based on the field name."""
if "dict" in _type.lower():
if field.name == "dict_":
field.field_type = "file"
field.suffixes = [".json", ".yaml", ".yml"]
field.file_types = ["json", "yaml", "yml"]
else:
field.field_type = "code"
if "dict" in _type.lower() and field.name == "dict_":
field.field_type = "file"
field.suffixes = [".json", ".yaml", ".yml"]
field.file_types = ["json", "yaml", "yml"]
elif (
_type.startswith("Dict")
or _type.startswith("Mapping")
or _type.startswith("dict")
):
field.field_type = "dict"
return _type
@staticmethod
@ -240,20 +243,6 @@ class FrontendNode(BaseModel):
"description",
}
@staticmethod
def replace_dict_with_code_or_file(
field: TemplateField, _type: str, key: str
) -> str:
"""Replaces 'dict' type with 'code' or 'file'."""
if "dict" in _type.lower():
if key == "dict_":
field.field_type = "file"
field.suffixes = [".json", ".yaml", ".yml"]
field.file_types = ["json", "yaml", "yml"]
else:
field.field_type = "code"
return field.field_type
@staticmethod
def set_field_default_value(field: TemplateField, value: dict, key: str) -> None:
"""Sets the field value with the default value if present."""

View file

@ -170,11 +170,11 @@ class DocumentLoaderFrontNode(FrontendNode):
# add a metadata field of type dict
self.template.add_field(
TemplateField(
field_type="code",
field_type="dict",
required=True,
show=True,
name="metadata",
value="{}",
value={},
display_name="Metadata",
multiline=False,
)

View file

@ -89,7 +89,7 @@ class EmbeddingFrontendNode(FrontendNode):
if field.name == "headers":
field.show = False
if field.name == "model_kwargs":
field.field_type = "code"
field.field_type = "dict"
field.advanced = True
field.show = True
elif field.name in [

View file

@ -153,10 +153,13 @@ class DictCodeFileFormatter(FieldFormatter):
key = field.name
value = field.to_dict()
_type = value["type"]
if "dict" in _type.lower():
if key == "dict_":
field.field_type = "file"
field.suffixes = [".json", ".yaml", ".yml"]
field.file_types = ["json", "yaml", "yml"]
else:
field.field_type = "code"
if "dict" in _type.lower() and key == "dict_":
field.field_type = "file"
field.suffixes = [".json", ".yaml", ".yml"]
field.file_types = ["json", "yaml", "yml"]
elif (
_type.startswith("Dict")
or _type.startswith("Mapping")
or _type.startswith("dict")
):
field.field_type = "dict"

View file

@ -131,7 +131,7 @@ class LLMFrontendNode(FrontendNode):
if display_name := display_names_dict.get(field.name):
field.display_name = display_name
if field.name == "model_kwargs":
field.field_type = "code"
field.field_type = "dict"
field.advanced = True
field.show = True
elif field.name in [

View file

@ -15,6 +15,7 @@ from langflow.template.template.base import Template
class PromptFrontendNode(FrontendNode):
@staticmethod
def format_field(field: TemplateField, name: Optional[str] = None) -> None:
FrontendNode.format_field(field, name)
# if field.field_type == "StringPromptTemplate"
# change it to str
PROMPT_FIELDS = [

View file

@ -21,5 +21,4 @@ class UtilitiesFrontendNode(FrontendNode):
field.field_type = "str"
if isinstance(field.value, dict):
field.field_type = "code"
field.value = orjson_dumps(field.value)

View file

@ -56,7 +56,7 @@ class VectorStoreFrontendNode(FrontendNode):
# Add search_kwargs field
extra_field = TemplateField(
name="search_kwargs",
field_type="code",
field_type="NestedDict",
required=False,
placeholder="",
show=True,

View file

@ -48,4 +48,14 @@ def python_function(text: str) -> str:
return text
"""
DIRECT_TYPES = ["str", "bool", "code", "int", "float", "Any", "prompt"]
DIRECT_TYPES = [
"str",
"bool",
"dict",
"int",
"float",
"Any",
"prompt",
"code",
"NestedDict",
]

View file

@ -276,8 +276,6 @@ def format_dict(
value["password"] = is_password_field(key)
value["multiline"] = is_multiline_field(key)
replace_dict_type_with_code(value)
if key == "dict_":
set_dict_file_attributes(value)
@ -407,14 +405,6 @@ def is_multiline_field(key: str) -> bool:
}
def replace_dict_type_with_code(value: Dict[str, Any]) -> None:
"""
Replaces the type value with 'code' if the type is a dict.
"""
if "dict" in value["type"].lower():
value["type"] = "code"
def set_dict_file_attributes(value: Dict[str, Any]) -> None:
"""
Sets the file attributes for the 'dict_' key.