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

This commit is contained in:
Gabriel Luiz Freitas Almeida 2023-09-19 16:07:39 -03:00
commit f081a0079c
16 changed files with 274 additions and 179 deletions

View file

@ -55,7 +55,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,
@ -153,10 +153,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

@ -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

@ -359,11 +359,16 @@ export default function ParameterComponent({
field_name={name}
setNodeClass={(nodeClass) => {
data.node = nodeClass;
const clone = cloneDeep(data);
clone.node = nodeClass;
setData(clone);
}}
nodeClass={data.node}
disabled={disabled}
value={data.node?.template[name].value ?? ""}
onChange={handleOnNewValue}
onChange={(e) => {
handleOnNewValue(e);
}}
/>
</div>
) : left === true && type === "NestedDict" ? (

View file

@ -19,7 +19,9 @@ export default function InputListComponent({
}, [disabled]);
// @TODO Recursive Character Text Splitter - the value might be in string format, whereas the InputListComponent specifically requires an array format. To ensure smooth operation and prevent potential errors, it's crucial that we handle the conversion from a string to an array with the string as its element.
typeof value === "string" ? (value = [value]) : (value = value);
if (typeof value === "string") {
value = [value];
}
return (
<div

View file

@ -3,7 +3,7 @@ import { useEffect } from "react";
import { TypeModal } from "../../constants/enums";
import { postValidatePrompt } from "../../controllers/API";
import GenericModal from "../../modals/genericModal";
import { TextAreaComponentType } from "../../types/components";
import { PromptAreaComponentType } from "../../types/components";
import IconComponent from "../genericIconComponent";
export default function PromptAreaComponent({
@ -14,7 +14,7 @@ export default function PromptAreaComponent({
onChange,
disabled,
editNode = false,
}: TextAreaComponentType): JSX.Element {
}: PromptAreaComponentType) {
useEffect(() => {
if (disabled) {
onChange("");

View file

@ -1,3 +1,4 @@
import { InfinityIcon } from "lucide-react";
import { forwardRef } from "react";
export const GradientSparkles = forwardRef<
@ -14,26 +15,7 @@ export const GradientSparkles = forwardRef<
</linearGradient>
</defs>
</svg>
{/* this svg comes from the source code of lucide,
we do not use the import because it crashes the ui (why? no one knows...).
source code from the used svg:
https://github.com/lucide-icons/lucide/blob/a4076db69b52ff0debc383f76d4d671c3bad5345/icons/infinity.svg?short_path=f79de91
*/}
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
stroke="url(#grad1)"
ref={ref}
{...props}
>
<path d="M12 12c-2-2.67-4-4-6-4a4 4 0 1 0 0 8c2 0 4-1.33 6-4Zm0 0c2 2.67 4 4 6 4a4 4 0 0 0 0-8c-2 0-4 1.33-6 4Z" />
</svg>
<InfinityIcon stroke="url(#grad1)" ref={ref} {...props} />
</>
);
});

View file

@ -1,5 +1,12 @@
import { cloneDeep } from "lodash";
import { ReactNode, forwardRef, useContext, useEffect, useState } from "react";
import {
ReactNode,
forwardRef,
useContext,
useEffect,
useRef,
useState,
} from "react";
import CodeAreaComponent from "../../components/codeAreaComponent";
import DictComponent from "../../components/dictComponent";
import Dropdown from "../../components/dropdownComponent";
@ -51,37 +58,29 @@ const EditNodeModal = forwardRef(
ref
) => {
const [modalOpen, setModalOpen] = useState(false);
const [myData, setMyData] = useState(data);
const { setTabsState, tabId } = useContext(TabsContext);
const { reactFlowInstance } = useContext(typesContext);
const myData = useRef(data);
let disabled =
reactFlowInstance
?.getEdges()
.some((edge) => edge.targetHandle === data.id) ?? false;
function changeAdvanced(templateParam: string): void {
setMyData((old) => {
let newData = cloneDeep(old);
newData.node!.template[templateParam].advanced =
!newData.node!.template[templateParam].advanced;
return newData;
});
function changeAdvanced(n) {
let newData = cloneDeep(data);
newData.node!.template[n].advanced = !newData.node!.template[n].advanced;
myData.current = newData;
}
const handleOnNewValue = (
newValue: string | string[] | boolean,
name: string
) => {
setMyData((old) => {
let newData = cloneDeep(old);
newData.node!.template[name].value = newValue;
return newData;
});
const handleOnNewValue = (newValue: any, name) => {
let newData = cloneDeep(data);
newData.node!.template[name].value = newValue;
myData.current = newData;
};
useEffect(() => {
setMyData(data); // reset data to what it is on node when opening modal
myData.current = data;
}, [modalOpen]);
const [obj, setObj] = useState({
@ -104,9 +103,17 @@ const EditNodeModal = forwardRef(
] as Object[]);
return (
<BaseModal size="large-h-full" open={modalOpen} setOpen={setModalOpen}>
<BaseModal
size="large-h-full"
open={modalOpen}
setOpen={setModalOpen}
onChangeOpenModal={(open) => {
let newData = cloneDeep(data);
myData.current = newData;
}}
>
<BaseModal.Trigger>{children}</BaseModal.Trigger>
<BaseModal.Header description={myData.node?.description!}>
<BaseModal.Header description={myData.current.node?.description!}>
<span className="pr-2">{myData.type}</span>
<Badge variant="secondary">ID: {myData.id}</Badge>
</BaseModal.Header>
@ -141,58 +148,65 @@ const EditNodeModal = forwardRef(
</TableRow>
</TableHeader>
<TableBody className="p-0">
{Object.keys(myData.node!.template)
{Object.keys(myData.current.node!.template)
.filter(
(templateParam) =>
templateParam.charAt(0) !== "_" &&
myData.node?.template[templateParam].show &&
(myData.node.template[templateParam].type ===
"str" ||
myData.node.template[templateParam].type ===
"bool" ||
myData.node.template[templateParam].type ===
"float" ||
myData.node.template[templateParam].type ===
"code" ||
myData.node.template[templateParam].type ===
"prompt" ||
myData.node.template[templateParam].type ===
"file" ||
myData.node.template[templateParam].type ===
"int")
myData.current.node?.template[templateParam].show &&
(myData.current.node.template[templateParam]
.type === "str" ||
myData.current.node.template[templateParam]
.type === "bool" ||
myData.current.node.template[templateParam]
.type === "float" ||
myData.current.node.template[templateParam]
.type === "code" ||
myData.current.node.template[templateParam]
.type === "prompt" ||
myData.current.node.template[templateParam]
.type === "file" ||
myData.current.node.template[templateParam]
.type === "int")
)
.map((templateParam, index) => (
<TableRow key={index} className="h-10">
<TableCell className="truncate p-0 text-center text-sm text-foreground sm:px-3">
{myData.node?.template[templateParam].name
? myData.node.template[templateParam].name
: myData.node?.template[templateParam]
{myData.current.node?.template[templateParam].name
? myData.current.node.template[templateParam]
.name
: myData.current.node?.template[templateParam]
.display_name}
</TableCell>
<TableCell className="w-[300px] p-0 text-center text-xs text-foreground ">
{myData.node?.template[templateParam].type ===
"str" &&
!myData.node.template[templateParam].options ? (
{myData.current.node?.template[templateParam]
.type === "str" &&
!myData.current.node.template[templateParam]
.options ? (
<div className="mx-auto">
{myData.node.template[templateParam].list ? (
{myData.current.node.template[templateParam]
.list ? (
<InputListComponent
editNode={true}
disabled={disabled}
value={
!myData.node.template[templateParam]
.value ||
myData.node.template[templateParam]
.value === ""
!myData.current.node.template[
templateParam
].value ||
myData.current.node.template[
templateParam
].value === ""
? [""]
: myData.node.template[templateParam]
.value
: myData.current.node.template[
templateParam
].value
}
onChange={(value: string[]) => {
handleOnNewValue(value, templateParam);
}}
/>
) : myData.node?.template[templateParam]
.type === "NestedDict" ? (
) : myData.current.node?.template[
templateParam
].type === "NestedDict" ? (
<div className="mt-2 w-full">
<DictComponent
disabled={disabled}
@ -203,20 +217,23 @@ const EditNodeModal = forwardRef(
}}
/>
</div>
) : myData.node?.template[templateParam]
.type === "dict" ? (
) : myData.current.node?.template[
templateParam
].type === "dict" ? (
<div className="mt-2 w-full">
<KeypairListComponent
disabled={disabled}
editNode={false}
value={
myData.node.template[templateParam]
.value?.length === 0 ||
!myData.node.template[templateParam]
.value
myData.current.node.template[
templateParam
].value?.length === 0 ||
!myData.current.node.template[
templateParam
].value
? dictArr
: convertObjToArray(
myData.node.template[
myData.current.node.template[
templateParam
].value
)
@ -230,21 +247,23 @@ const EditNodeModal = forwardRef(
setDictArr(newValue);
} else {
setDictArr(newValue);
myData.node!.template[
myData.current.node!.template[
templateParam
].value = newValue;
}
}}
/>
</div>
) : myData.node.template[templateParam]
.multiline ? (
) : myData.current.node.template[
templateParam
].multiline ? (
<TextAreaComponent
disabled={disabled}
editNode={true}
value={
myData.node.template[templateParam]
.value ?? ""
myData.current.node.template[
templateParam
].value ?? ""
}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateParam);
@ -255,12 +274,14 @@ const EditNodeModal = forwardRef(
editNode={true}
disabled={disabled}
password={
myData.node.template[templateParam]
.password ?? false
myData.current.node.template[
templateParam
].password ?? false
}
value={
myData.node.template[templateParam]
.value ?? ""
myData.current.node.template[
templateParam
].value ?? ""
}
onChange={(value) => {
handleOnNewValue(value, templateParam);
@ -268,14 +289,16 @@ const EditNodeModal = forwardRef(
/>
)}
</div>
) : myData.node?.template[templateParam].type ===
"bool" ? (
) : myData.current.node?.template[templateParam]
.type === "bool" ? (
<div className="ml-auto">
{" "}
<ToggleShadComponent
disabled={disabled}
enabled={
myData.node.template[templateParam].value
myData.current.node.template[
templateParam
].value
}
setEnabled={(isEnabled) => {
handleOnNewValue(
@ -286,76 +309,84 @@ const EditNodeModal = forwardRef(
size="small"
/>
</div>
) : myData.node?.template[templateParam].type ===
"float" ? (
) : myData.current.node?.template[templateParam]
.type === "float" ? (
<div className="mx-auto">
<FloatComponent
disabled={disabled}
editNode={true}
value={
myData.node.template[templateParam]
.value ?? ""
myData.current.node.template[
templateParam
].value ?? ""
}
onChange={(value) => {
handleOnNewValue(value, templateParam);
}}
/>
</div>
) : myData.node?.template[templateParam].type ===
"str" &&
myData.node.template[templateParam].options ? (
) : myData.current.node?.template[templateParam]
.type === "str" &&
myData.current.node.template[templateParam]
.options ? (
<div className="mx-auto">
<Dropdown
numberOfOptions={nodeLength}
editNode={true}
options={
myData.node.template[templateParam]
.options
myData.current.node.template[
templateParam
].options
}
onSelect={(value) =>
handleOnNewValue(value, templateParam)
}
value={
myData.node.template[templateParam]
.value ?? "Choose an option"
myData.current.node.template[
templateParam
].value ?? "Choose an option"
}
></Dropdown>
</div>
) : myData.node?.template[templateParam].type ===
"int" ? (
) : myData.current.node?.template[templateParam]
.type === "int" ? (
<div className="mx-auto">
<IntComponent
disabled={disabled}
editNode={true}
value={
myData.node.template[templateParam]
.value ?? ""
myData.current.node.template[
templateParam
].value ?? ""
}
onChange={(value) => {
handleOnNewValue(value, templateParam);
}}
/>
</div>
) : myData.node?.template[templateParam].type ===
"file" ? (
) : myData.current.node?.template[templateParam]
.type === "file" ? (
<div className="mx-auto">
<InputFileComponent
editNode={true}
disabled={disabled}
value={
myData.node.template[templateParam]
.value ?? ""
myData.current.node.template[
templateParam
].value ?? ""
}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateParam);
}}
fileTypes={
myData.node.template[templateParam]
.fileTypes
myData.current.node.template[
templateParam
].fileTypes
}
suffixes={
myData.node.template[templateParam]
.suffixes
myData.current.node.template[
templateParam
].suffixes
}
onFileChange={(filePath: string) => {
data.node!.template[
@ -364,28 +395,29 @@ const EditNodeModal = forwardRef(
}}
></InputFileComponent>
</div>
) : myData.node?.template[templateParam].type ===
"prompt" ? (
) : myData.current.node?.template[templateParam]
.type === "prompt" ? (
<div className="mx-auto">
<PromptAreaComponent
field_name={templateParam}
editNode={true}
disabled={disabled}
nodeClass={myData.node}
nodeClass={myData.current.node}
setNodeClass={(nodeClass) => {
myData.node = nodeClass;
myData.current.node = nodeClass;
}}
value={
myData.node.template[templateParam]
.value ?? ""
myData.current.node.template[
templateParam
].value ?? ""
}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateParam);
}}
/>
</div>
) : myData.node?.template[templateParam].type ===
"code" ? (
) : myData.current.node?.template[templateParam]
.type === "code" ? (
<div className="mx-auto">
<CodeAreaComponent
dynamic={
@ -399,16 +431,17 @@ const EditNodeModal = forwardRef(
disabled={disabled}
editNode={true}
value={
myData.node.template[templateParam]
.value ?? ""
myData.current.node.template[
templateParam
].value ?? ""
}
onChange={(value: string | string[]) => {
handleOnNewValue(value, templateParam);
}}
/>
</div>
) : myData.node?.template[templateParam].type ===
"Any" ? (
) : myData.current.node?.template[templateParam]
.type === "Any" ? (
"-"
) : (
<div className="hidden"></div>
@ -418,8 +451,9 @@ const EditNodeModal = forwardRef(
<div className="items-center text-center">
<ToggleShadComponent
enabled={
!myData.node?.template[templateParam]
.advanced
!myData.current.node?.template[
templateParam
].advanced
}
setEnabled={(e) =>
changeAdvanced(templateParam)

View file

@ -1,4 +1,4 @@
import { ReactNode } from "react";
import { ReactNode, useEffect } from "react";
import React from "react";
import {
@ -68,12 +68,16 @@ interface BaseModalProps {
| "large-h-full"
| "small-h-full"
| "medium-h-full";
disable?: boolean;
onChangeOpenModal?: (open: boolean) => void;
}
function BaseModal({
open,
setOpen,
children,
size = "large",
onChangeOpenModal,
}: BaseModalProps) {
const headerChild = React.Children.toArray(children).find(
(child) => (child as React.ReactElement).type === Header
@ -127,6 +131,12 @@ function BaseModal({
break;
}
useEffect(() => {
if (onChangeOpenModal) {
onChangeOpenModal(open);
}
}, [open]);
//UPDATE COLORS AND STYLE CLASSSES
return (
<Dialog open={open} onOpenChange={setOpen}>

View file

@ -164,18 +164,18 @@ export default function CodeAreaModal({
</div>
<div
className={
"w-full transition-all delay-500 " +
(error?.detail.error !== undefined ? "h-2/6" : "h-0")
"whitespace-break-spaces transition-all delay-500" +
(error?.detail?.error !== undefined ? "h-2/6" : "h-0")
}
>
<div className="mt-1 h-full w-full overflow-y-auto overflow-x-clip text-left custom-scroll">
<div className="mt-1 h-full max-h-[10rem] w-full overflow-y-auto overflow-x-clip text-left custom-scroll">
<h1 className="text-lg text-destructive">
{error?.detail?.error}
</h1>
<div className="ml-2 w-full text-sm text-status-red word-break-break-word">
<pre className="w-full word-break-break-word">
<span className="w-full word-break-break-word">
{error?.detail?.traceback}
</pre>
</span>
</div>
</div>
</div>

View file

@ -122,9 +122,15 @@ export default function GenericModal({
function validatePrompt(closeModal: boolean): void {
//nodeClass is always null on tweaks
postValidatePrompt(field_name, inputValue, nodeClass!)
.then((apiReturn) => {
if (apiReturn.data) {
setValue(inputValue);
apiReturn.data.frontend_node["template"]["template"]["value"] =
inputValue;
setNodeClass!(apiReturn?.data?.frontend_node);
let inputVariables = apiReturn.data.input_variables ?? [];
if (inputVariables && inputVariables.length === 0) {
setIsEdit(true);
@ -164,7 +170,11 @@ export default function GenericModal({
const [modalOpen, setModalOpen] = useState(false);
return (
<BaseModal open={modalOpen} setOpen={setModalOpen}>
<BaseModal
onChangeOpenModal={(open) => {}}
open={modalOpen}
setOpen={setModalOpen}
>
<BaseModal.Trigger>{children}</BaseModal.Trigger>
<BaseModal.Header
description={(() => {
@ -291,9 +301,7 @@ export default function GenericModal({
setModalOpen(false);
break;
case TypeModal.PROMPT:
!inputValue || inputValue === ""
? setModalOpen(false)
: validatePrompt(false);
validatePrompt(false);
break;
default:

View file

@ -29,7 +29,6 @@ pre {
animation: slideUp 300ms ease-out;
}
.gradient-end {
animation: gradient-motion-end 3s infinite forwards;
}
@ -50,4 +49,22 @@ select:-webkit-autofill:focus {
-webkit-box-shadow: 0 0 0px 1000px #fff6d0 inset;
box-shadow: 0 0 0px 1000px #fff6d0 inset;
color: black;
}
}
.ace_scrollbar::-webkit-scrollbar {
height: 8px;
width: 8px;
}
.ace_scrollbar::-webkit-scrollbar-track {
background-color: #f1f1f1;
}
.ace_scrollbar::-webkit-scrollbar-thumb {
background-color: #ccc;
border-radius: 999px;
}
.ace_scrollbar::-webkit-scrollbar-thumb:hover {
background-color: #bbb;
border-radius: 999px;
}

View file

@ -79,6 +79,16 @@ export type TextAreaComponentType = {
editNode?: boolean;
};
export type PromptAreaComponentType = {
field_name?: string;
nodeClass?: APIClassType;
setNodeClass?: (value: APIClassType) => void;
disabled: boolean;
onChange: (value: string[] | string) => void;
value: string;
editNode?: boolean;
};
export type CodeAreaComponentType = {
disabled: boolean;
onChange: (value: string[] | string) => void;