Merge branch 'dev' into new_icons

This commit is contained in:
anovazzi1 2023-05-29 19:10:50 -03:00 • committed by GitHub
commit 3e3fff7dd1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 295 additions and 347 deletions

316
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -29,7 +29,7 @@ google-search-results = "^2.4.1"
google-api-python-client = "^2.79.0" google-api-python-client = "^2.79.0"
typer = "^0.7.0" typer = "^0.7.0"
gunicorn = "^20.1.0" gunicorn = "^20.1.0"
langchain = "^0.0.183" langchain = "^0.0.184"
openai = "^0.27.7" openai = "^0.27.7"
types-pyyaml = "^6.0.12.8" types-pyyaml = "^6.0.12.8"
dill = "^0.3.6" dill = "^0.3.6"
@ -49,12 +49,14 @@ psycopg2-binary = "^2.9.6"
pyarrow = "^11.0.0" pyarrow = "^11.0.0"
tiktoken = "^0.3.3" tiktoken = "^0.3.3"
wikipedia = "^1.4.0" wikipedia = "^1.4.0"
langchain-serve = { version = "^0.0.33", optional = true } langchain-serve = { version = "^0.0.38", optional = true }
qdrant-client = "^1.2.0" qdrant-client = "^1.2.0"
websockets = "^11.0.3" websockets = "^11.0.3"
weaviate-client = "^3.19.2" weaviate-client = "^3.19.2"
jina = "3.15.2" jina = "3.15.2"
sentence-transformers = "^2.2.2" sentence-transformers = "^2.2.2"
ctransformers = "^0.2.2"
cohere = "^4.6.0"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]

View file

@ -42,17 +42,20 @@ documentloaders:
- IMSDbLoader - IMSDbLoader
- GitbookLoader - GitbookLoader
- ReadTheDocsLoader - ReadTheDocsLoader
- SlackDirectoryLoader
- NotionDirectoryLoader - NotionDirectoryLoader
embeddings: embeddings:
- OpenAIEmbeddings - OpenAIEmbeddings
- HuggingFaceEmbeddings - HuggingFaceEmbeddings
- CohereEmbeddings
llms: llms:
- OpenAI - OpenAI
# - AzureOpenAI # - AzureOpenAI
- ChatOpenAI - ChatOpenAI
- HuggingFaceHub - HuggingFaceHub
- LlamaCpp - LlamaCpp
- CTransformers
- Cohere
memories: memories:
- ConversationBufferMemory - ConversationBufferMemory
- ConversationSummaryMemory - ConversationSummaryMemory
@ -117,7 +120,7 @@ vectorstores:
- Qdrant - Qdrant
- Weaviate - Weaviate
wrappers: wrappers:
- RequestsWrapper # Wait more tests - RequestsWrapper
# - ChatPromptTemplate # - ChatPromptTemplate
# - SystemMessagePromptTemplate # - SystemMessagePromptTemplate
# - HumanMessagePromptTemplate # - HumanMessagePromptTemplate

View file

@ -53,30 +53,33 @@ class LangChainTypeCreator(BaseModel, ABC):
signature = self.get_signature(name) signature = self.get_signature(name)
if signature is None: if signature is None:
logger.error(f"Node {name} not loaded") logger.error(f"Node {name} not loaded")
return None
if isinstance(signature, FrontendNode):
return signature return signature
fields = [ if not isinstance(signature, FrontendNode):
TemplateField( fields = [
name=key, TemplateField(
field_type=value["type"], name=key,
required=value.get("required", False), field_type=value["type"],
placeholder=value.get("placeholder", ""), required=value.get("required", False),
is_list=value.get("list", False), placeholder=value.get("placeholder", ""),
show=value.get("show", True), is_list=value.get("list", False),
multiline=value.get("multiline", False), show=value.get("show", True),
value=value.get("value", None), multiline=value.get("multiline", False),
suffixes=value.get("suffixes", []), value=value.get("value", None),
file_types=value.get("fileTypes", []), suffixes=value.get("suffixes", []),
content=value.get("content", None), file_types=value.get("fileTypes", []),
content=value.get("content", None),
)
for key, value in signature["template"].items()
if key != "_type"
]
template = Template(type_name=name, fields=fields)
signature = self.frontend_node_class(
template=template,
description=signature.get("description", ""),
base_classes=signature["base_classes"],
name=name,
) )
for key, value in signature["template"].items()
if key != "_type" signature.add_extra_fields()
]
template = Template(type_name=name, fields=fields) return signature
return self.frontend_node_class(
template=template,
description=signature.get("description", ""),
base_classes=signature["base_classes"],
name=name,
)

View file

@ -89,6 +89,9 @@ class DocumentLoaderCreator(LangChainTypeCreator):
"UnstructuredWordDocumentLoader": build_file_path_template( "UnstructuredWordDocumentLoader": build_file_path_template(
suffixes=[".docx", ".doc"], fileTypes=["docx", "doc"] suffixes=[".docx", ".doc"], fileTypes=["docx", "doc"]
), ),
"SlackDirectoryLoader": build_file_path_template(
suffixes=[".zip"], fileTypes=["zip"]
),
} }
if name in file_path_templates: if name in file_path_templates:

View file

@ -24,6 +24,9 @@ class FrontendNode(BaseModel):
} }
} }
def add_extra_fields(self) -> None:
pass
@staticmethod @staticmethod
def format_field(field: TemplateField, name: Optional[str] = None) -> None: def format_field(field: TemplateField, name: Optional[str] = None) -> None:
"""Formats a given field based on its attributes and value.""" """Formats a given field based on its attributes and value."""

View file

@ -43,7 +43,7 @@ class LLMFrontendNode(FrontendNode):
field.field_type = "code" field.field_type = "code"
field.advanced = True field.advanced = True
field.show = True field.show = True
elif field.name in ["model_name", "temperature"]: elif field.name in ["model_name", "temperature", "model_file", "model_type"]:
field.advanced = False field.advanced = False
field.show = True field.show = True

View file

@ -5,6 +5,21 @@ from langflow.template.frontend_node.base import FrontendNode
class VectorStoreFrontendNode(FrontendNode): class VectorStoreFrontendNode(FrontendNode):
def add_extra_fields(self) -> None:
if self.template.type_name == "Weaviate":
extra_field = TemplateField(
name="weaviate_url",
field_type="str",
required=True,
placeholder="http://localhost:8080",
show=True,
advanced=False,
multiline=False,
value="http://localhost:8080",
)
self.template.add_field(extra_field)
@staticmethod @staticmethod
def format_field(field: TemplateField, name: Optional[str] = None) -> None: def format_field(field: TemplateField, name: Optional[str] = None) -> None:
FrontendNode.format_field(field, name) FrontendNode.format_field(field, name)

View file

@ -23,3 +23,6 @@ class Template(BaseModel):
result = {field.name: field.to_dict() for field in self.fields} result = {field.name: field.to_dict() for field in self.fields}
result["_type"] = self.type_name # type: ignore result["_type"] = self.type_name # type: ignore
return result return result
def add_field(self, field: TemplateField) -> None:
self.fields.append(field)

View file

@ -119,6 +119,7 @@ export default function ParameterComponent({
) : ( ) : (
<InputComponent <InputComponent
disabled={disabled} disabled={disabled}
disableCopyPaste={true}
password={data.node.template[name].password ?? false} password={data.node.template[name].password ?? false}
value={data.node.template[name].value ?? ""} value={data.node.template[name].value ?? ""}
onChange={(t) => { onChange={(t) => {

View file

@ -11,7 +11,13 @@ import {
ExclamationCircleIcon, ExclamationCircleIcon,
} from "@heroicons/react/24/solid"; } from "@heroicons/react/24/solid";
import { classNames, nodeColors, nodeIcons, toNormalCase, toTitleCase } from "../../utils"; import {
classNames,
nodeColors,
nodeIcons,
toNormalCase,
toTitleCase,
} from "../../utils";
import ParameterComponent from "./components/parameterComponent"; import ParameterComponent from "./components/parameterComponent";
import { typesContext } from "../../contexts/typesContext"; import { typesContext } from "../../contexts/typesContext";
import { useContext, useState, useEffect, useRef, Fragment } from "react"; import { useContext, useState, useEffect, useRef, Fragment } from "react";
@ -107,7 +113,7 @@ export default function GenericNode({
}} }}
/> />
<Tooltip title={data.type} placement="top"> <Tooltip title={data.type} placement="top">
<div className="ml-2 truncate">{data.type}</div> <div className="ml-2 truncate">{data.type}</div>
</Tooltip> </Tooltip>
<div> <div>
<Tooltip <Tooltip

View file

@ -6,11 +6,13 @@ import { TabsContext } from "../../contexts/tabsContext";
export default function InputComponent({ export default function InputComponent({
value, value,
onChange, onChange,
disableCopyPaste = false,
disabled, disabled,
password, password,
}: InputComponentType) { }: InputComponentType) {
const [myValue, setMyValue] = useState(value ?? ""); const [myValue, setMyValue] = useState(value ?? "");
const [pwdVisible, setPwdVisible] = useState(false); const [pwdVisible, setPwdVisible] = useState(false);
const { setDisableCopyPaste } = useContext(TabsContext);
useEffect(() => { useEffect(() => {
if (disabled) { if (disabled) {
setMyValue(""); setMyValue("");
@ -27,6 +29,12 @@ export default function InputComponent({
> >
<input <input
value={myValue} value={myValue}
onFocus={() => {
if (disableCopyPaste) setDisableCopyPaste(true);
}}
onBlur={() => {
if (disableCopyPaste) setDisableCopyPaste(false);
}}
className={classNames( className={classNames(
"block w-full pr-12 form-input dark:bg-gray-900 dark:border-gray-600 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm", "block w-full pr-12 form-input dark:bg-gray-900 dark:border-gray-600 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm",
disabled ? " bg-gray-200 dark:bg-gray-700" : "", disabled ? " bg-gray-200 dark:bg-gray-700" : "",

View file

@ -87,6 +87,19 @@ export function TabsProvider({ children }: { children: ReactNode }) {
cookieObject.flows.forEach((flow) => { cookieObject.flows.forEach((flow) => {
flow.data.nodes.forEach((node) => { flow.data.nodes.forEach((node) => {
if (Object.keys(templates[node.data.type]["template"]).length > 0) { if (Object.keys(templates[node.data.type]["template"]).length > 0) {
node.data.node.base_classes =
templates[node.data.type]["base_classes"];
flow.data.edges.forEach((edge) => {
if (edge.source === node.id) {
edge.sourceHandle = edge.sourceHandle
.split("|")
.slice(0, 2)
.concat(templates[node.data.type]["base_classes"])
.join("|");
}
});
node.data.node.description =
templates[node.data.type]["description"];
node.data.node.template = updateTemplate( node.data.node.template = updateTemplate(
templates[node.data.type][ templates[node.data.type][
"template" "template"
@ -276,6 +289,18 @@ export function TabsProvider({ children }: { children: ReactNode }) {
if (data) { if (data) {
data.nodes.forEach((node) => { data.nodes.forEach((node) => {
if (Object.keys(templates[node.data.type]["template"]).length > 0) { if (Object.keys(templates[node.data.type]["template"]).length > 0) {
node.data.node.base_classes =
templates[node.data.type]["base_classes"];
flow.data.edges.forEach((edge) => {
if (edge.source === node.id) {
edge.sourceHandle = edge.sourceHandle
.split("|")
.slice(0, 2)
.concat(templates[node.data.type]["base_classes"])
.join("|");
}
});
node.data.node.description = templates[node.data.type]["description"];
node.data.node.template = updateTemplate( node.data.node.template = updateTemplate(
templates[node.data.type]["template"] as unknown as APITemplateType, templates[node.data.type]["template"] as unknown as APITemplateType,
node.data.node.template as APITemplateType node.data.node.template as APITemplateType

View file

@ -12,7 +12,15 @@ import PromptAreaComponent from "../../../../components/promptComponent";
import CodeAreaComponent from "../../../../components/codeAreaComponent"; import CodeAreaComponent from "../../../../components/codeAreaComponent";
import { classNames } from "../../../../utils"; import { classNames } from "../../../../utils";
export default function ModalField({ data, title, required, id, name, type }) { export default function ModalField({
data,
title,
required,
id,
name,
type,
index,
}) {
const { save } = useContext(TabsContext); const { save } = useContext(TabsContext);
const [enabled, setEnabled] = useState( const [enabled, setEnabled] = useState(
data.node.template[name]?.value ?? false data.node.template[name]?.value ?? false
@ -30,7 +38,17 @@ export default function ModalField({ data, title, required, id, name, type }) {
<div <div
className={classNames( className={classNames(
"flex flex-row w-full items-center justify-between", "flex flex-row w-full items-center justify-between",
display ? "" : "hidden" display ? "" : "hidden",
Object.keys(data.node.template).filter(
(t) =>
t.charAt(0) !== "_" &&
data.node.template[t].advanced &&
data.node.template[t].show
).length -
1 ===
index
? "pb-4"
: ""
)} )}
> >
{display && ( {display && (

View file

@ -3,7 +3,14 @@ import { XMarkIcon } from "@heroicons/react/24/outline";
import { Fragment, useContext, useRef, useState } from "react"; import { Fragment, useContext, useRef, useState } from "react";
import { PopUpContext } from "../../contexts/popUpContext"; import { PopUpContext } from "../../contexts/popUpContext";
import { NodeDataType } from "../../types/flow"; import { NodeDataType } from "../../types/flow";
import { nodeColors, nodeIcons, toNormalCase, toTitleCase } from "../../utils"; import {
classNames,
limitScrollFieldsModal,
nodeColors,
nodeIcons,
toNormalCase,
toTitleCase,
} from "../../utils";
import { typesContext } from "../../contexts/typesContext"; import { typesContext } from "../../contexts/typesContext";
import ModalField from "./components/ModalField"; import ModalField from "./components/ModalField";
@ -84,8 +91,20 @@ export default function NodeModal({ data }: { data: NodeDataType }) {
</div> </div>
</div> </div>
<div className="h-full w-full bg-gray-200 dark:bg-gray-900 p-4 gap-4 flex flex-row justify-center items-center"> <div className="h-full w-full bg-gray-200 dark:bg-gray-900 p-4 gap-4 flex flex-row justify-center items-center">
<div className="flex h-full w-full"> <div className="flex w-full h-[445px]">
<div className="overflow-hidden px-4 sm:p-4 w-full rounded-lg bg-white dark:bg-gray-800 shadow"> <div
className={classNames(
"px-4 sm:p-4 w-full rounded-lg bg-white dark:bg-gray-800 shadow",
Object.keys(data.node.template).filter(
(t) =>
t.charAt(0) !== "_" &&
data.node.template[t].advanced &&
data.node.template[t].show
).length > limitScrollFieldsModal
? "overflow-scroll overflow-x-hidden custom-scroll"
: "overflow-hidden"
)}
>
<div className="flex flex-col h-full gap-5"> <div className="flex flex-col h-full gap-5">
{Object.keys(data.node.template) {Object.keys(data.node.template)
.filter( .filter(
@ -116,6 +135,7 @@ export default function NodeModal({ data }: { data: NodeDataType }) {
} }
name={t} name={t}
type={data.node.template[t].type} type={data.node.template[t].type}
index={idx}
/> />
); );
})} })}

View file

@ -11,7 +11,7 @@ export default function PromptAreaModal({
setValue, setValue,
buttonText, buttonText,
modalTitle, modalTitle,
type type,
}: { }: {
setValue: (value: string) => void; setValue: (value: string) => void;
value: string; value: string;
@ -121,40 +121,41 @@ export default function PromptAreaModal({
switch (myModalType) { switch (myModalType) {
case 1: case 1:
setModalOpen(false); setModalOpen(false);
break; break;
case 2: case 2:
checkPrompt(myValue) checkPrompt(myValue)
.then((apiReturn) => { .then((apiReturn) => {
if (apiReturn.data) { if (apiReturn.data) {
let inputVariables = let inputVariables =
apiReturn.data.input_variables; apiReturn.data.input_variables;
if (inputVariables.length === 0) { if (inputVariables.length === 0) {
setErrorData({
title:
"The template you are attempting to use does not contain any variables for data entry.",
});
} else {
setSuccessData({
title: "Prompt is ready",
});
setModalOpen(false);
setValue(myValue);
}
} else {
setErrorData({ setErrorData({
title: title:
"The template you are attempting to use does not contain any variables for data entry.", "Something went wrong, please try again",
}); });
} else {
setSuccessData({
title: "Prompt is ready",
});
setModalOpen(false);
setValue(myValue);
} }
} else { })
setErrorData({ .catch((error) => {
title: "Something went wrong, please try again", return setErrorData({
title:
"There is something wrong with this prompt, please review it",
list: [error.response.data.detail],
}); });
}
})
.catch((error) => {
return setErrorData({
title:
"There is something wrong with this prompt, please review it",
list: [error.response.data.detail],
}); });
}); break;
break;
default: default:
break; break;
} }

View file

@ -34,7 +34,7 @@ export default function ExtraSidebar() {
{Object.keys(data[d]) {Object.keys(data[d])
.sort() .sort()
.map((t: string, k) => ( .map((t: string, k) => (
<Tooltip title={t.length > 21 ? t : ''} placement="right"> <Tooltip title={t.length > 21 ? t : ""} placement="right">
<div key={k}> <div key={k}>
<div <div
draggable draggable

View file

@ -317,10 +317,8 @@ export default function FlowPage({ flow }: { flow: FlowType }) {
onPaneClick={() => { onPaneClick={() => {
setDisableCopyPaste(false); setDisableCopyPaste(false);
}} }}
onNodeClick={() => {
setDisableCopyPaste(true);
}}
onPaneMouseLeave={() => { onPaneMouseLeave={() => {
console.log("saiu o mouse");
setDisableCopyPaste(true); setDisableCopyPaste(true);
}} }}
onNodesChange={onNodesChange} onNodesChange={onNodesChange}

View file

@ -10,6 +10,7 @@ export type InputComponentType = {
disabled?: boolean; disabled?: boolean;
onChange: (value: string) => void; onChange: (value: string) => void;
password: boolean; password: boolean;
disableCopyPaste?: boolean;
}; };
export type ToggleComponentType = { export type ToggleComponentType = {
enabled: boolean; enabled: boolean;

View file

@ -21,14 +21,17 @@ import { FlowType } from "./types/flow";
import { APITemplateType, TemplateVariableType } from "./types/api"; import { APITemplateType, TemplateVariableType } from "./types/api";
import _ from "lodash"; import _ from "lodash";
import { ChromaIcon } from "./icons"; import { ChromaIcon } from "./icons";
import { v4 as uuidv4 } from "uuid";
export function classNames(...classes: Array<string>) { export function classNames(...classes: Array<string>) {
return classes.filter(Boolean).join(" "); return classes.filter(Boolean).join(" ");
} }
export const limitScrollFieldsModal = 7;
export enum TypeModal { export enum TypeModal {
TEXT = 1, TEXT = 1,
PROMPT = 2 PROMPT = 2,
} }
export const textColors = { export const textColors = {
@ -501,33 +504,62 @@ export const programmingLanguages: languageMap = {
}; };
export function toTitleCase(str: string) { export function toTitleCase(str: string) {
let result = str let result = str
.split("_") .split("_")
.map((word, index) => { .map((word, index) => {
if (index === 0) { if (index === 0) {
return checkUpperWords(
word[0].toUpperCase() + word.slice(1).toLowerCase()
);
}
return checkUpperWords(word.toLowerCase());
})
.join(" ");
return checkUpperWords(word[0].toUpperCase() + word.slice(1).toLowerCase()); return result
} .split("-")
return checkUpperWords(word.toLowerCase()); .map((word, index) => {
}) if (index === 0) {
.join(" "); return checkUpperWords(
word[0].toUpperCase() + word.slice(1).toLowerCase()
return result );
.split("-") }
.map((word, index) => { return checkUpperWords(word.toLowerCase());
if (index === 0) { })
return checkUpperWords(word[0].toUpperCase() + word.slice(1).toLowerCase()); .join(" ");
}
return checkUpperWords(word.toLowerCase());
})
.join(" ");
} }
export const upperCaseWords: string[] = ["llm", "uri"]; export const upperCaseWords: string[] = ["llm", "uri"];
export function checkUpperWords(str: string) { export function checkUpperWords(str: string) {
const words = str.split(' ').map((word) => { const words = str.split(" ").map((word) => {
return upperCaseWords.includes(word.toLowerCase()) ? word.toUpperCase() : word[0].toUpperCase() + word.slice(1).toLowerCase(); return upperCaseWords.includes(word.toLowerCase())
? word.toUpperCase()
: word[0].toUpperCase() + word.slice(1).toLowerCase();
}); });
return words.join(' '); return words.join(" ");
} }
export function updateIds(newFLow: FlowType, baseFlow: FlowType) {
newFLow.data.nodes.forEach((node) => {
while (baseFlow.data.nodes.some((n) => n.id === node.id)) {
const newId = uuidv4();
newFLow.data.edges.forEach((edge) => {
if (edge.source === node.id) {
edge.source = newId;
}
if (edge.target === node.id) {
edge.target = newId;
}
const index = edge.id.split("|").findIndex((e) => e === node.id);
if (index != -1) {
let tempList = edge.id.split("|");
tempList[index] = newId;
edge.id = tempList.concat(newId).join("|");
}
node.id = newId;
});
}
});
return newFLow;
}