Added dropdown and global page

This commit is contained in:
Lucas Oliveira 2024-03-18 13:12:31 +01:00
commit 06f0e0e0f8
8 changed files with 118 additions and 215 deletions

BIN
langflow1.db Normal file

Binary file not shown.

View file

@ -8,7 +8,6 @@ from loguru import logger
from langflow.api.v1.schemas import ChatMessage from langflow.api.v1.schemas import ChatMessage
from langflow.interface.utils import try_setting_streaming_options from langflow.interface.utils import try_setting_streaming_options
from langflow.processing.base import get_result_and_steps from langflow.processing.base import get_result_and_steps
from langflow.utils.chat import ChatDefinition
LANGCHAIN_RUNNABLES = (Chain, Runnable, AgentExecutor) LANGCHAIN_RUNNABLES = (Chain, Runnable, AgentExecutor)
@ -40,20 +39,6 @@ async def process_graph(
client_id=client_id, client_id=client_id,
session_id=session_id, session_id=session_id,
) )
elif isinstance(build_result, ChatDefinition):
raw_output = await run_build_result(
build_result,
chat_inputs,
client_id=client_id,
session_id=session_id,
)
if isinstance(raw_output, dict):
if not build_result.output_key:
raise ValueError("No output key provided to ChatDefinition when returning a dict.")
result = raw_output[build_result.output_key]
else:
result = raw_output
intermediate_steps = []
else: else:
raise TypeError(f"Unknown type {type(build_result)}") raise TypeError(f"Unknown type {type(build_result)}")
logger.debug("Generated result and intermediate_steps") logger.debug("Generated result and intermediate_steps")

View file

@ -1,34 +0,0 @@
from typing import Any, Callable, Optional, Union
from langchain_core.prompts import PromptTemplate as LCPromptTemplate
from langflow.utils.prompt import GenericPromptTemplate
from llama_index.prompts import PromptTemplate as LIPromptTemplate
PromptTemplate = Union[LCPromptTemplate, LIPromptTemplate]
class ChatDefinition:
def __init__(
self,
func: Callable,
inputs: list[str],
output_key: Optional[str] = None,
prompt_template: Optional[PromptTemplate] = None,
):
self.func = func
self.input_keys = inputs
self.output_key = output_key
self.prompt_template = prompt_template
@classmethod
def from_prompt_template(cls, prompt_template: PromptTemplate, func: Callable, output_key: Optional[str] = None):
prompt = GenericPromptTemplate(prompt_template)
return cls(
func=func,
inputs=prompt.input_keys,
output_key=output_key,
prompt_template=prompt_template,
)
def __call__(self, inputs: dict, callbacks: Optional[Any] = None) -> dict:
return self.func(inputs, callbacks)

View file

@ -1,58 +0,0 @@
from typing import Any, Union
from langchain_core.prompts import PromptTemplate as LCPromptTemplate
from llama_index.prompts import PromptTemplate as LIPromptTemplate
PromptTemplateTypes = Union[LCPromptTemplate, LIPromptTemplate]
class GenericPromptTemplate:
def __init__(self, prompt_template: PromptTemplateTypes):
object.__setattr__(self, "prompt_template", prompt_template)
@property
def input_keys(self):
prompt_template = object.__getattribute__(self, "prompt_template")
if isinstance(prompt_template, LCPromptTemplate):
return prompt_template.input_variables
elif isinstance(prompt_template, LIPromptTemplate):
return prompt_template.template_vars
else:
raise TypeError(f"Unknown prompt template type {type(prompt_template)}")
def to_lc_prompt(self):
prompt_template = object.__getattribute__(self, "prompt_template")
if isinstance(prompt_template, LCPromptTemplate):
return prompt_template
elif isinstance(prompt_template, LIPromptTemplate):
return LCPromptTemplate.from_template(prompt_template.get_template())
else:
raise TypeError(f"Unknown prompt template type {type(prompt_template)}")
def to_li_prompt(self):
prompt_template = object.__getattribute__(self, "prompt_template")
if isinstance(prompt_template, LIPromptTemplate):
return prompt_template
elif isinstance(prompt_template, LCPromptTemplate):
return LIPromptTemplate(template=prompt_template.template)
else:
raise TypeError(f"Unknown prompt template type {type(prompt_template)}")
def __or__(self, other):
prompt_template = object.__getattribute__(self, "prompt_template")
if isinstance(prompt_template, LIPromptTemplate):
return self.to_lc_prompt() | other
else:
raise TypeError(f"Unknown prompt template type {type(other)}")
def __getattribute__(self, name: str) -> Any:
if name in {
"input_keys",
"to_lc_prompt",
"to_li_prompt",
"__or__",
"prompt_template",
}:
return object.__getattribute__(self, name)
prompt_template = object.__getattribute__(self, "prompt_template")
return getattr(prompt_template, name)

View file

@ -314,9 +314,8 @@ export default function ParameterComponent({
<> <>
<div <div
className={ className={
"w-full truncate text-sm" + "w-full truncate text-sm flex items-center" +
(left ? "" : " text-end") + (left ? "" : " text-end")
(info !== "" ? " flex items-center" : "")
} }
> >
{proxy ? ( {proxy ? (
@ -429,8 +428,7 @@ export default function ParameterComponent({
newNode.data.node.template[name].load_from_db = true; newNode.data.node.template[name].load_from_db = true;
return newNode; return newNode;
}); });
} } else {
else{
setNode(data.id, (oldNode) => { setNode(data.id, (oldNode) => {
let newNode = cloneDeep(oldNode); let newNode = cloneDeep(oldNode);
newNode.data = { newNode.data = {

View file

@ -1,11 +1,13 @@
import { Listbox, Transition } from "@headlessui/react"; import { Listbox, Transition } from "@headlessui/react";
import * as Form from "@radix-ui/react-form"; import * as Form from "@radix-ui/react-form";
import { Fragment, useEffect, useRef, useState } from "react"; import { Fragment, useEffect, useRef, useState } from "react";
import AddNewVariableButton from "../../pages/globalVariablesPage/components/addNewVariableButton";
import { InputComponentType } from "../../types/components"; import { InputComponentType } from "../../types/components";
import { handleKeyDown } from "../../utils/reactflowUtils"; import { handleKeyDown } from "../../utils/reactflowUtils";
import { classNames } from "../../utils/utils"; import { classNames, cn } from "../../utils/utils";
import IconComponent from "../genericIconComponent"; import IconComponent from "../genericIconComponent";
import { Input } from "../ui/input"; import { Input } from "../ui/input";
import { Separator } from "../ui/separator";
export default function InputComponent({ export default function InputComponent({
autoFocus = false, autoFocus = false,
@ -26,7 +28,6 @@ export default function InputComponent({
const [pwdVisible, setPwdVisible] = useState(false); const [pwdVisible, setPwdVisible] = useState(false);
const refInput = useRef<HTMLInputElement>(null); const refInput = useRef<HTMLInputElement>(null);
const [showOptions, setShowOptions] = useState<boolean>(false); const [showOptions, setShowOptions] = useState<boolean>(false);
const [filteredOpts, setFilteredValue] = useState<string[]>(options);
// Clear component state // Clear component state
useEffect(() => { useEffect(() => {
@ -35,13 +36,12 @@ export default function InputComponent({
} }
}, [disabled]); }, [disabled]);
const filteredOptions = filteredOpts.filter((option) => const filteredOptions = options.filter((option) =>
option.toLowerCase().includes(value.toLowerCase()) option.toLowerCase().includes(value.toLowerCase())
); );
function onInputLostFocus(event): void { function onInputLostFocus(event): void {
if (onBlur) onBlur(event); if (onBlur) onBlur(event);
setShowOptions(false);
} }
return ( return (
@ -107,103 +107,115 @@ export default function InputComponent({
handleKeyDown(e, value, ""); handleKeyDown(e, value, "");
if (blurOnEnter && e.key === "Enter") refInput.current?.blur(); if (blurOnEnter && e.key === "Enter") refInput.current?.blur();
}} }}
onFocus={() => setShowOptions(true)}
/> />
{ <Listbox
/* options.length > 0 && filteredOptions.length > 0 */ true ? ( onChange={(val) => {
<Listbox onChange(val);
onChange={(val) => { }}
onChange(val); >
}} <>
> <div className={"relative mt-1 "}>
<> <Transition
<div className={"relative mt-1 "}> show={showOptions}
<Transition as={Fragment}
show={showOptions} leave="transition ease-in duration-100"
as={Fragment} leaveFrom="opacity-100"
leave="transition ease-in duration-100" leaveTo="opacity-0"
leaveFrom="opacity-100" >
leaveTo="opacity-0" <Listbox.Options
> className={classNames(
<Listbox.Options editNode
className={classNames( ? "dropdown-component-true-options nowheel custom-scroll"
editNode : "dropdown-component-false-options nowheel custom-scroll",
? "dropdown-component-true-options nowheel custom-scroll" false ? "mb-2 w-[250px]" : "absolute w-full"
: "dropdown-component-false-options nowheel custom-scroll", )}
false ? "mb-2 w-[250px]" : "absolute w-full" >
)} <div className="flex items-center justify-between px-4 pb-3 pt-2 font-semibold">
<div className="flex items-center gap-2">
<IconComponent name="Globe" className="h-4 w-4" />
Global Variables
</div>
<div>
<AddNewVariableButton>
<button className="text-muted-foreground hover:text-accent-foreground">
<IconComponent name="Plus" className="h-5 w-5" />
</button>
</AddNewVariableButton>
</div>
</div>
<Separator />
{filteredOptions.map((option, id) => (
<Listbox.Option
key={id}
className={({ active }) =>
classNames(
active ? " bg-accent" : "",
editNode
? "dropdown-component-false-option"
: "dropdown-component-true-option",
" hover:bg-accent"
)
}
value={option}
> >
{filteredOptions.map((option, id) => ( {({ selected, active }) => (
<Listbox.Option <>
key={id} <span
className={({ active }) => className={classNames(
classNames( selected ? "font-semibold" : "font-normal",
active ? " bg-accent" : "", "block truncate "
editNode )}
? "dropdown-component-false-option" data-testid={`${option}-${id ?? ""}-option`}
: "dropdown-component-true-option", >
" hover:bg-accent" {option}
) </span>
}
value={option}
>
{({ selected, active }) => (
<>
<span
className={classNames(
selected ? "font-semibold" : "font-normal",
"block truncate "
)}
data-testid={`${option}-${id ?? ""}-option`}
>
{option}
</span>
{selected ? ( {selected ? (
<span <span
className={classNames( className={classNames(
active ? "text-background " : "", "dropdown-component-choosal"
"dropdown-component-choosal" )}
)} >
> <IconComponent
<IconComponent name="Check"
name="Check" className={
className={ "dropdown-component-check-icon text-foreground"
active }
? "dropdown-component-check-icon" aria-hidden="true"
: "dropdown-component-check-icon" />
} </span>
aria-hidden="true" ) : null}
/> </>
</span> )}
) : null} </Listbox.Option>
</> ))}
)} </Listbox.Options>
</Listbox.Option> </Transition>
))} </div>
</Listbox.Options> </>
</Transition> </Listbox>
</div>
</>
</Listbox>
) : null
}
</> </>
)} )}
{options.length > 0 && ( {options.length > 0 && (
<span <span
className={ className={cn(
password password ? "right-8" : "right-0",
? "dropdown-component-arrow right-8" "absolute inset-y-0 flex items-center pr-2"
: "dropdown-component-arrow right-0" )}
}
> >
<IconComponent <button
name="ChevronsUpDown" onClick={() => {
className="dropdown-component-arrow-color" setShowOptions(!showOptions);
aria-hidden="true" }}
/> className="text-muted-foreground hover:text-accent-foreground"
>
<IconComponent
name="Globe"
className="h-4 w-4"
aria-hidden="true"
/>
</button>
</span> </span>
)} )}
@ -212,6 +224,7 @@ export default function InputComponent({
type="button" type="button"
tabIndex={-1} tabIndex={-1}
className={classNames( className={classNames(
"mb-px",
editNode editNode
? "input-component-true-button" ? "input-component-true-button"
: "input-component-false-button" : "input-component-false-button"

View file

@ -10,7 +10,7 @@ import { useGlobalVariablesStore } from "../../../stores/globalVariables";
//TODO IMPLEMENT FORM LOGIC //TODO IMPLEMENT FORM LOGIC
export default function AddNewVariableButton(): JSX.Element { export default function AddNewVariableButton({children}): JSX.Element {
const [key, setKey] = useState(""); const [key, setKey] = useState("");
const [value, setValue] = useState(""); const [value, setValue] = useState("");
const [provider, setProvider] = useState(""); const [provider, setProvider] = useState("");
@ -33,25 +33,24 @@ export default function AddNewVariableButton(): JSX.Element {
}); });
} }
return ( return (
<BaseModal open={open} setOpen={setOpen} size="small"> <BaseModal open={open} setOpen={setOpen} size="x-small">
<BaseModal.Header <BaseModal.Header
description={"write a text variable to use anywhere on your flow"} description={"write a text variable to use anywhere on your flow"}
> >
<span>Create a new Variable</span> <span>Create a new Variable</span>
</BaseModal.Header> </BaseModal.Header>
<BaseModal.Trigger> <BaseModal.Trigger>
<Button>Create a new variable</Button> {children}
</BaseModal.Trigger> </BaseModal.Trigger>
<BaseModal.Content> <BaseModal.Content>
<div className="flex h-full w-full flex-col justify-around align-middle"> <div className="flex gap-4 h-full w-full flex-col align-middle">
<div className="h-1/2">
<Label>Variable name </Label> <Label>Variable name </Label>
<Input <Input
value={key} value={key}
onChange={(e) => { onChange={(e) => {
setKey(e.target.value); setKey(e.target.value);
}} }}
placeholder="example name" placeholder="Insert a name for the variable..."
></Input> ></Input>
<Label>Provider (optional) </Label> <Label>Provider (optional) </Label>
<InputComponent <InputComponent
@ -61,19 +60,17 @@ export default function AddNewVariableButton(): JSX.Element {
}} }}
password={false} password={false}
options={["OPENAI_API_KEY", "ANTHROPIC_API_KEY"]} options={["OPENAI_API_KEY", "ANTHROPIC_API_KEY"]}
placeholder="example provider" placeholder="Choose a provider between the environment variables..."
></InputComponent> ></InputComponent>
</div>
<div className="h-1/2">
<Label>Variable Value </Label> <Label>Variable Value </Label>
<Textarea <Textarea
value={value} value={value}
onChange={(e) => { onChange={(e) => {
setValue(e.target.value); setValue(e.target.value);
}} }}
className="h-4/6 w-full resize-none custom-scroll" placeholder="Insert a value for the variable..."
className="w-full resize-none custom-scroll"
/> />
</div>
</div> </div>
</BaseModal.Content> </BaseModal.Content>
<BaseModal.Footer> <BaseModal.Footer>

View file

@ -40,6 +40,7 @@ import {
GitBranchPlus, GitBranchPlus,
GitFork, GitFork,
GithubIcon, GithubIcon,
Globe,
Group, Group,
Hammer, Hammer,
Heart, Heart,
@ -326,6 +327,7 @@ export const nodeIconsLucide: iconsType = {
Circle, Circle,
Clipboard, Clipboard,
Code2, Code2,
Globe,
Variable, Variable,
Store, Store,
Download, Download,