Added dropdown and global page
This commit is contained in:
parent
b57173dd76
commit
06f0e0e0f8
8 changed files with 118 additions and 215 deletions
BIN
langflow1.db
Normal file
BIN
langflow1.db
Normal file
Binary file not shown.
|
|
@ -8,7 +8,6 @@ from loguru import logger
|
|||
from langflow.api.v1.schemas import ChatMessage
|
||||
from langflow.interface.utils import try_setting_streaming_options
|
||||
from langflow.processing.base import get_result_and_steps
|
||||
from langflow.utils.chat import ChatDefinition
|
||||
|
||||
LANGCHAIN_RUNNABLES = (Chain, Runnable, AgentExecutor)
|
||||
|
||||
|
|
@ -40,20 +39,6 @@ async def process_graph(
|
|||
client_id=client_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:
|
||||
raise TypeError(f"Unknown type {type(build_result)}")
|
||||
logger.debug("Generated result and intermediate_steps")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
|
|
@ -314,9 +314,8 @@ export default function ParameterComponent({
|
|||
<>
|
||||
<div
|
||||
className={
|
||||
"w-full truncate text-sm" +
|
||||
(left ? "" : " text-end") +
|
||||
(info !== "" ? " flex items-center" : "")
|
||||
"w-full truncate text-sm flex items-center" +
|
||||
(left ? "" : " text-end")
|
||||
}
|
||||
>
|
||||
{proxy ? (
|
||||
|
|
@ -429,8 +428,7 @@ export default function ParameterComponent({
|
|||
newNode.data.node.template[name].load_from_db = true;
|
||||
return newNode;
|
||||
});
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
setNode(data.id, (oldNode) => {
|
||||
let newNode = cloneDeep(oldNode);
|
||||
newNode.data = {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import { Listbox, Transition } from "@headlessui/react";
|
||||
import * as Form from "@radix-ui/react-form";
|
||||
import { Fragment, useEffect, useRef, useState } from "react";
|
||||
import AddNewVariableButton from "../../pages/globalVariablesPage/components/addNewVariableButton";
|
||||
import { InputComponentType } from "../../types/components";
|
||||
import { handleKeyDown } from "../../utils/reactflowUtils";
|
||||
import { classNames } from "../../utils/utils";
|
||||
import { classNames, cn } from "../../utils/utils";
|
||||
import IconComponent from "../genericIconComponent";
|
||||
import { Input } from "../ui/input";
|
||||
import { Separator } from "../ui/separator";
|
||||
|
||||
export default function InputComponent({
|
||||
autoFocus = false,
|
||||
|
|
@ -26,7 +28,6 @@ export default function InputComponent({
|
|||
const [pwdVisible, setPwdVisible] = useState(false);
|
||||
const refInput = useRef<HTMLInputElement>(null);
|
||||
const [showOptions, setShowOptions] = useState<boolean>(false);
|
||||
const [filteredOpts, setFilteredValue] = useState<string[]>(options);
|
||||
|
||||
// Clear component state
|
||||
useEffect(() => {
|
||||
|
|
@ -35,13 +36,12 @@ export default function InputComponent({
|
|||
}
|
||||
}, [disabled]);
|
||||
|
||||
const filteredOptions = filteredOpts.filter((option) =>
|
||||
const filteredOptions = options.filter((option) =>
|
||||
option.toLowerCase().includes(value.toLowerCase())
|
||||
);
|
||||
|
||||
function onInputLostFocus(event): void {
|
||||
if (onBlur) onBlur(event);
|
||||
setShowOptions(false);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -107,103 +107,115 @@ export default function InputComponent({
|
|||
handleKeyDown(e, value, "");
|
||||
if (blurOnEnter && e.key === "Enter") refInput.current?.blur();
|
||||
}}
|
||||
onFocus={() => setShowOptions(true)}
|
||||
/>
|
||||
{
|
||||
/* options.length > 0 && filteredOptions.length > 0 */ true ? (
|
||||
<Listbox
|
||||
onChange={(val) => {
|
||||
onChange(val);
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<div className={"relative mt-1 "}>
|
||||
<Transition
|
||||
show={showOptions}
|
||||
as={Fragment}
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<Listbox.Options
|
||||
className={classNames(
|
||||
editNode
|
||||
? "dropdown-component-true-options nowheel custom-scroll"
|
||||
: "dropdown-component-false-options nowheel custom-scroll",
|
||||
false ? "mb-2 w-[250px]" : "absolute w-full"
|
||||
)}
|
||||
<Listbox
|
||||
onChange={(val) => {
|
||||
onChange(val);
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<div className={"relative mt-1 "}>
|
||||
<Transition
|
||||
show={showOptions}
|
||||
as={Fragment}
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<Listbox.Options
|
||||
className={classNames(
|
||||
editNode
|
||||
? "dropdown-component-true-options nowheel custom-scroll"
|
||||
: "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) => (
|
||||
<Listbox.Option
|
||||
key={id}
|
||||
className={({ active }) =>
|
||||
classNames(
|
||||
active ? " bg-accent" : "",
|
||||
editNode
|
||||
? "dropdown-component-false-option"
|
||||
: "dropdown-component-true-option",
|
||||
" hover:bg-accent"
|
||||
)
|
||||
}
|
||||
value={option}
|
||||
>
|
||||
{({ selected, active }) => (
|
||||
<>
|
||||
<span
|
||||
className={classNames(
|
||||
selected ? "font-semibold" : "font-normal",
|
||||
"block truncate "
|
||||
)}
|
||||
data-testid={`${option}-${id ?? ""}-option`}
|
||||
>
|
||||
{option}
|
||||
</span>
|
||||
{({ selected, active }) => (
|
||||
<>
|
||||
<span
|
||||
className={classNames(
|
||||
selected ? "font-semibold" : "font-normal",
|
||||
"block truncate "
|
||||
)}
|
||||
data-testid={`${option}-${id ?? ""}-option`}
|
||||
>
|
||||
{option}
|
||||
</span>
|
||||
|
||||
{selected ? (
|
||||
<span
|
||||
className={classNames(
|
||||
active ? "text-background " : "",
|
||||
"dropdown-component-choosal"
|
||||
)}
|
||||
>
|
||||
<IconComponent
|
||||
name="Check"
|
||||
className={
|
||||
active
|
||||
? "dropdown-component-check-icon"
|
||||
: "dropdown-component-check-icon"
|
||||
}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</Listbox.Option>
|
||||
))}
|
||||
</Listbox.Options>
|
||||
</Transition>
|
||||
</div>
|
||||
</>
|
||||
</Listbox>
|
||||
) : null
|
||||
}
|
||||
{selected ? (
|
||||
<span
|
||||
className={classNames(
|
||||
"dropdown-component-choosal"
|
||||
)}
|
||||
>
|
||||
<IconComponent
|
||||
name="Check"
|
||||
className={
|
||||
"dropdown-component-check-icon text-foreground"
|
||||
}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</Listbox.Option>
|
||||
))}
|
||||
</Listbox.Options>
|
||||
</Transition>
|
||||
</div>
|
||||
</>
|
||||
</Listbox>
|
||||
</>
|
||||
)}
|
||||
|
||||
{options.length > 0 && (
|
||||
<span
|
||||
className={
|
||||
password
|
||||
? "dropdown-component-arrow right-8"
|
||||
: "dropdown-component-arrow right-0"
|
||||
}
|
||||
className={cn(
|
||||
password ? "right-8" : "right-0",
|
||||
"absolute inset-y-0 flex items-center pr-2"
|
||||
)}
|
||||
>
|
||||
<IconComponent
|
||||
name="ChevronsUpDown"
|
||||
className="dropdown-component-arrow-color"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowOptions(!showOptions);
|
||||
}}
|
||||
className="text-muted-foreground hover:text-accent-foreground"
|
||||
>
|
||||
<IconComponent
|
||||
name="Globe"
|
||||
className="h-4 w-4"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
)}
|
||||
|
||||
|
|
@ -212,6 +224,7 @@ export default function InputComponent({
|
|||
type="button"
|
||||
tabIndex={-1}
|
||||
className={classNames(
|
||||
"mb-px",
|
||||
editNode
|
||||
? "input-component-true-button"
|
||||
: "input-component-false-button"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { useGlobalVariablesStore } from "../../../stores/globalVariables";
|
|||
|
||||
//TODO IMPLEMENT FORM LOGIC
|
||||
|
||||
export default function AddNewVariableButton(): JSX.Element {
|
||||
export default function AddNewVariableButton({children}): JSX.Element {
|
||||
const [key, setKey] = useState("");
|
||||
const [value, setValue] = useState("");
|
||||
const [provider, setProvider] = useState("");
|
||||
|
|
@ -33,25 +33,24 @@ export default function AddNewVariableButton(): JSX.Element {
|
|||
});
|
||||
}
|
||||
return (
|
||||
<BaseModal open={open} setOpen={setOpen} size="small">
|
||||
<BaseModal open={open} setOpen={setOpen} size="x-small">
|
||||
<BaseModal.Header
|
||||
description={"write a text variable to use anywhere on your flow"}
|
||||
>
|
||||
<span>Create a new Variable</span>
|
||||
</BaseModal.Header>
|
||||
<BaseModal.Trigger>
|
||||
<Button>Create a new variable</Button>
|
||||
{children}
|
||||
</BaseModal.Trigger>
|
||||
<BaseModal.Content>
|
||||
<div className="flex h-full w-full flex-col justify-around align-middle">
|
||||
<div className="h-1/2">
|
||||
<div className="flex gap-4 h-full w-full flex-col align-middle">
|
||||
<Label>Variable name </Label>
|
||||
<Input
|
||||
value={key}
|
||||
onChange={(e) => {
|
||||
setKey(e.target.value);
|
||||
}}
|
||||
placeholder="example name"
|
||||
placeholder="Insert a name for the variable..."
|
||||
></Input>
|
||||
<Label>Provider (optional) </Label>
|
||||
<InputComponent
|
||||
|
|
@ -61,19 +60,17 @@ export default function AddNewVariableButton(): JSX.Element {
|
|||
}}
|
||||
password={false}
|
||||
options={["OPENAI_API_KEY", "ANTHROPIC_API_KEY"]}
|
||||
placeholder="example provider"
|
||||
placeholder="Choose a provider between the environment variables..."
|
||||
></InputComponent>
|
||||
</div>
|
||||
<div className="h-1/2">
|
||||
<Label>Variable Value </Label>
|
||||
<Textarea
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
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>
|
||||
</BaseModal.Content>
|
||||
<BaseModal.Footer>
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import {
|
|||
GitBranchPlus,
|
||||
GitFork,
|
||||
GithubIcon,
|
||||
Globe,
|
||||
Group,
|
||||
Hammer,
|
||||
Heart,
|
||||
|
|
@ -326,6 +327,7 @@ export const nodeIconsLucide: iconsType = {
|
|||
Circle,
|
||||
Clipboard,
|
||||
Code2,
|
||||
Globe,
|
||||
Variable,
|
||||
Store,
|
||||
Download,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue