Merge branch 'dev' into feat/slack-directory-loader
This commit is contained in:
commit
8db30348d8
30 changed files with 494 additions and 404 deletions
4
Makefile
4
Makefile
|
|
@ -5,6 +5,10 @@ all: help
|
||||||
init:
|
init:
|
||||||
@echo 'Installing pre-commit hooks'
|
@echo 'Installing pre-commit hooks'
|
||||||
git config core.hooksPath .githooks
|
git config core.hooksPath .githooks
|
||||||
|
@echo 'Installing backend dependencies'
|
||||||
|
make install_backend
|
||||||
|
@echo 'Installing frontend dependencies'
|
||||||
|
make install_frontend
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
poetry run pytest --cov \
|
poetry run pytest --cov \
|
||||||
|
|
|
||||||
377
poetry.lock
generated
377
poetry.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -22,22 +22,22 @@ langflow = "langflow.__main__:main"
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = ">=3.9,<3.12"
|
python = ">=3.9,<3.12"
|
||||||
fastapi = "^0.92.0"
|
fastapi = "^0.95.0"
|
||||||
uvicorn = "^0.20.0"
|
uvicorn = "^0.20.0"
|
||||||
beautifulsoup4 = "^4.11.2"
|
beautifulsoup4 = "^4.11.2"
|
||||||
google-search-results = "^2.4.1"
|
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.176"
|
langchain = "^0.0.184"
|
||||||
openai = "^0.27.2"
|
openai = "^0.27.7"
|
||||||
types-pyyaml = "^6.0.12.8"
|
types-pyyaml = "^6.0.12.8"
|
||||||
dill = "^0.3.6"
|
dill = "^0.3.6"
|
||||||
pandas = "^1.5.3"
|
pandas = "^1.5.3"
|
||||||
chromadb = "^0.3.21"
|
chromadb = "^0.3.21"
|
||||||
huggingface-hub = "^0.13.3"
|
huggingface-hub = "^0.13.3"
|
||||||
rich = "^13.3.3"
|
rich = "^13.3.3"
|
||||||
llama-cpp-python = "0.1.50"
|
llama-cpp-python = "^0.1.50"
|
||||||
networkx = "^3.1"
|
networkx = "^3.1"
|
||||||
unstructured = "^0.5.11"
|
unstructured = "^0.5.11"
|
||||||
pypdf = "^3.7.1"
|
pypdf = "^3.7.1"
|
||||||
|
|
@ -49,12 +49,15 @@ 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]
|
||||||
black = "^23.1.0"
|
black = "^23.1.0"
|
||||||
|
|
|
||||||
2
src/backend/langflow/cache/base.py
vendored
2
src/backend/langflow/cache/base.py
vendored
|
|
@ -120,7 +120,7 @@ def save_binary_file(content: str, file_name: str, accepted_types: list[str]) ->
|
||||||
|
|
||||||
# Get the destination folder
|
# Get the destination folder
|
||||||
cache_path = Path(tempfile.gettempdir()) / PREFIX
|
cache_path = Path(tempfile.gettempdir()) / PREFIX
|
||||||
if content is None:
|
if not content:
|
||||||
raise ValueError("Please, reload the file in the loader.")
|
raise ValueError("Please, reload the file in the loader.")
|
||||||
data = content.split(",")[1]
|
data = content.split(",")[1]
|
||||||
decoded_bytes = base64.b64decode(data)
|
decoded_bytes = base64.b64decode(data)
|
||||||
|
|
|
||||||
|
|
@ -43,16 +43,19 @@ documentloaders:
|
||||||
- GitbookLoader
|
- GitbookLoader
|
||||||
- ReadTheDocsLoader
|
- ReadTheDocsLoader
|
||||||
- SlackDirectoryLoader
|
- SlackDirectoryLoader
|
||||||
|
- 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
|
||||||
|
|
@ -63,6 +66,9 @@ prompts:
|
||||||
- ZeroShotPrompt
|
- ZeroShotPrompt
|
||||||
textsplitters:
|
textsplitters:
|
||||||
- CharacterTextSplitter
|
- CharacterTextSplitter
|
||||||
|
- RecursiveCharacterTextSplitter
|
||||||
|
- LatexTextSplitter
|
||||||
|
- PythonCodeTextSplitter
|
||||||
toolkits:
|
toolkits:
|
||||||
- OpenAPIToolkit
|
- OpenAPIToolkit
|
||||||
- JsonToolkit
|
- JsonToolkit
|
||||||
|
|
@ -114,7 +120,7 @@ vectorstores:
|
||||||
- Qdrant
|
- Qdrant
|
||||||
- Weaviate
|
- Weaviate
|
||||||
wrappers:
|
wrappers:
|
||||||
- RequestsWrapper # Wait more tests
|
- RequestsWrapper
|
||||||
# - ChatPromptTemplate
|
# - ChatPromptTemplate
|
||||||
# - SystemMessagePromptTemplate
|
# - SystemMessagePromptTemplate
|
||||||
# - HumanMessagePromptTemplate
|
# - HumanMessagePromptTemplate
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,8 @@ 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
|
||||||
|
if not isinstance(signature, FrontendNode):
|
||||||
fields = [
|
fields = [
|
||||||
TemplateField(
|
TemplateField(
|
||||||
name=key,
|
name=key,
|
||||||
|
|
@ -74,9 +73,13 @@ class LangChainTypeCreator(BaseModel, ABC):
|
||||||
if key != "_type"
|
if key != "_type"
|
||||||
]
|
]
|
||||||
template = Template(type_name=name, fields=fields)
|
template = Template(type_name=name, fields=fields)
|
||||||
return self.frontend_node_class(
|
signature = self.frontend_node_class(
|
||||||
template=template,
|
template=template,
|
||||||
description=signature.get("description", ""),
|
description=signature.get("description", ""),
|
||||||
base_classes=signature["base_classes"],
|
base_classes=signature["base_classes"],
|
||||||
name=name,
|
name=name,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
signature.add_extra_fields()
|
||||||
|
|
||||||
|
return signature
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ class DocumentLoaderCreator(LangChainTypeCreator):
|
||||||
"value": "",
|
"value": "",
|
||||||
"display_name": "Web Page",
|
"display_name": "Web Page",
|
||||||
}
|
}
|
||||||
elif name in {"ReadTheDocsLoader"}:
|
elif name in {"ReadTheDocsLoader", "NotionDirectoryLoader"}:
|
||||||
signature["template"]["path"] = {
|
signature["template"]["path"] = {
|
||||||
"type": "str",
|
"type": "str",
|
||||||
"required": True,
|
"required": True,
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ def try_setting_streaming_options(langchain_object, websocket):
|
||||||
langchain_object.llm_chain, "llm"
|
langchain_object.llm_chain, "llm"
|
||||||
):
|
):
|
||||||
llm = langchain_object.llm_chain.llm
|
llm = langchain_object.llm_chain.llm
|
||||||
if isinstance(llm, BaseLanguageModel):
|
if isinstance(llm, BaseLanguageModel) and hasattr(llm, "streaming"):
|
||||||
llm.streaming = bool(hasattr(llm, "streaming"))
|
llm.streaming = True
|
||||||
|
|
||||||
return langchain_object
|
return langchain_object
|
||||||
|
|
|
||||||
|
|
@ -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."""
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,22 @@ class EmbeddingFrontendNode(FrontendNode):
|
||||||
field.display_name = "Jina API URL"
|
field.display_name = "Jina API URL"
|
||||||
field.password = False
|
field.password = False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def format_openai_fields(field: TemplateField):
|
||||||
|
if "openai" in field.name:
|
||||||
|
field.show = True
|
||||||
|
field.advanced = True
|
||||||
|
split_name = field.name.split("_")
|
||||||
|
title_name = " ".join([s.capitalize() for s in split_name])
|
||||||
|
field.display_name = title_name.replace("Openai", "OpenAI").replace(
|
||||||
|
"Api", "API"
|
||||||
|
)
|
||||||
|
|
||||||
|
if "api_key" in field.name:
|
||||||
|
field.password = True
|
||||||
|
field.show = True
|
||||||
|
field.advanced = False
|
||||||
|
|
||||||
@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)
|
||||||
|
|
@ -30,9 +46,6 @@ class EmbeddingFrontendNode(FrontendNode):
|
||||||
if field.name == "headers":
|
if field.name == "headers":
|
||||||
field.show = False
|
field.show = False
|
||||||
|
|
||||||
if "openai" in field.name:
|
|
||||||
field.show = True
|
|
||||||
field.advanced = "api_key" not in field.name
|
|
||||||
|
|
||||||
# Format Jina fields
|
# Format Jina fields
|
||||||
EmbeddingFrontendNode.format_jina_fields(field)
|
EmbeddingFrontendNode.format_jina_fields(field)
|
||||||
|
EmbeddingFrontendNode.format_openai_fields(field)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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) => {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,23 @@
|
||||||
import {
|
import {
|
||||||
BugAntIcon,
|
BugAntIcon,
|
||||||
CheckCircleIcon,
|
|
||||||
Cog6ToothIcon,
|
Cog6ToothIcon,
|
||||||
EllipsisHorizontalCircleIcon,
|
|
||||||
ExclamationCircleIcon,
|
|
||||||
InformationCircleIcon,
|
InformationCircleIcon,
|
||||||
TrashIcon,
|
TrashIcon,
|
||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
import { classNames, nodeColors, nodeIcons, toNormalCase } from "../../utils";
|
|
||||||
|
import {
|
||||||
|
CheckCircleIcon,
|
||||||
|
EllipsisHorizontalCircleIcon,
|
||||||
|
ExclamationCircleIcon,
|
||||||
|
} from "@heroicons/react/24/solid";
|
||||||
|
|
||||||
|
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";
|
||||||
|
|
@ -101,7 +111,9 @@ export default function GenericNode({
|
||||||
color: nodeColors[types[data.type]] ?? nodeColors.unknown,
|
color: nodeColors[types[data.type]] ?? nodeColors.unknown,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<Tooltip title={data.type} placement="top">
|
||||||
<div className="ml-2 truncate">{data.type}</div>
|
<div className="ml-2 truncate">{data.type}</div>
|
||||||
|
</Tooltip>
|
||||||
<div>
|
<div>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
|
|
@ -170,7 +182,7 @@ export default function GenericNode({
|
||||||
)
|
)
|
||||||
? ""
|
? ""
|
||||||
: "hidden",
|
: "hidden",
|
||||||
"w-6 h-6 dark:text-gray-300 hover:animate-spin"
|
"w-6 h-6 dark:text-gray-300 hover:animate-spin-once"
|
||||||
)}
|
)}
|
||||||
></Cog6ToothIcon>
|
></Cog6ToothIcon>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -225,8 +237,8 @@ export default function GenericNode({
|
||||||
data.node.template[t].display_name
|
data.node.template[t].display_name
|
||||||
? data.node.template[t].display_name
|
? data.node.template[t].display_name
|
||||||
: data.node.template[t].name
|
: data.node.template[t].name
|
||||||
? toNormalCase(data.node.template[t].name)
|
? toTitleCase(data.node.template[t].name)
|
||||||
: toNormalCase(t)
|
: toTitleCase(t)
|
||||||
}
|
}
|
||||||
name={t}
|
name={t}
|
||||||
tooltipTitle={
|
tooltipTitle={
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,12 @@ export default function ChatTrigger({ open, setOpen }) {
|
||||||
>
|
>
|
||||||
<div className="absolute bottom-4 right-3">
|
<div className="absolute bottom-4 right-3">
|
||||||
<div
|
<div
|
||||||
// style={{ backgroundColor: nodeColors["chat"] }}
|
className="border flex justify-center align-center py-1 px-3 w-12 h-12 rounded-full bg-gradient-to-r from-blue-500 via-blue-600 to-blue-700 dark:border-gray-600 cursor-pointer"
|
||||||
className="border flex justify-center align-center py-1 px-3 w-12 h-12 rounded-full bg-gradient-to-r from-blue-500 via-blue-600 to-blue-700 dark:border-gray-600"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<button>
|
||||||
<div className="flex gap-3 items-center">
|
<div className="flex gap-3 items-center">
|
||||||
<ChatBubbleBottomCenterTextIcon
|
<ChatBubbleBottomCenterTextIcon
|
||||||
className="h-6 w-6 mt-1"
|
className="h-6 w-6 mt-1"
|
||||||
|
|
|
||||||
|
|
@ -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,12 +29,18 @@ 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" : "",
|
||||||
password && !pwdVisible && myValue !== "" ? "password" : ""
|
password && !pwdVisible && myValue !== "" ? "password" : ""
|
||||||
)}
|
)}
|
||||||
placeholder="Type a text"
|
placeholder="Type something..."
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setMyValue(e.target.value);
|
setMyValue(e.target.value);
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ export default function InputListComponent({
|
||||||
"block w-full form-input rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
|
"block w-full form-input rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
|
||||||
(disabled ? " bg-gray-200" : "")
|
(disabled ? " bg-gray-200" : "")
|
||||||
}
|
}
|
||||||
placeholder="Type a text"
|
placeholder="Type something..."
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setInputList((old) => {
|
setInputList((old) => {
|
||||||
let newInputList = _.cloneDeep(old);
|
let newInputList = _.cloneDeep(old);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import CodeAreaModal from "../../modals/codeAreaModal";
|
||||||
import TextAreaModal from "../../modals/textAreaModal";
|
import TextAreaModal from "../../modals/textAreaModal";
|
||||||
import { TextAreaComponentType } from "../../types/components";
|
import { TextAreaComponentType } from "../../types/components";
|
||||||
import GenericModal from "../../modals/genericModal";
|
import GenericModal from "../../modals/genericModal";
|
||||||
|
import { TypeModal } from "../../utils";
|
||||||
|
|
||||||
export default function PromptAreaComponent({
|
export default function PromptAreaComponent({
|
||||||
value,
|
value,
|
||||||
|
|
@ -30,6 +31,7 @@ export default function PromptAreaComponent({
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openPopUp(
|
openPopUp(
|
||||||
<GenericModal
|
<GenericModal
|
||||||
|
type={TypeModal.PROMPT}
|
||||||
value={myValue}
|
value={myValue}
|
||||||
buttonText="Check & Save"
|
buttonText="Check & Save"
|
||||||
modalTitle="Edit Prompt"
|
modalTitle="Edit Prompt"
|
||||||
|
|
@ -51,6 +53,7 @@ export default function PromptAreaComponent({
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openPopUp(
|
openPopUp(
|
||||||
<GenericModal
|
<GenericModal
|
||||||
|
type={TypeModal.PROMPT}
|
||||||
value={myValue}
|
value={myValue}
|
||||||
buttonText="Check & Save"
|
buttonText="Check & Save"
|
||||||
modalTitle="Edit Prompt"
|
modalTitle="Edit Prompt"
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { useContext, useEffect, useState } from "react";
|
||||||
import { PopUpContext } from "../../contexts/popUpContext";
|
import { PopUpContext } from "../../contexts/popUpContext";
|
||||||
import { TextAreaComponentType } from "../../types/components";
|
import { TextAreaComponentType } from "../../types/components";
|
||||||
import GenericModal from "../../modals/genericModal";
|
import GenericModal from "../../modals/genericModal";
|
||||||
|
import { TypeModal } from "../../utils";
|
||||||
|
|
||||||
export default function TextAreaComponent({
|
export default function TextAreaComponent({
|
||||||
value,
|
value,
|
||||||
|
|
@ -24,6 +25,7 @@ export default function TextAreaComponent({
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openPopUp(
|
openPopUp(
|
||||||
<GenericModal
|
<GenericModal
|
||||||
|
type={TypeModal.TEXT}
|
||||||
buttonText="Finishing Editing"
|
buttonText="Finishing Editing"
|
||||||
modalTitle="Edit Text"
|
modalTitle="Edit Text"
|
||||||
value={myValue}
|
value={myValue}
|
||||||
|
|
@ -45,6 +47,7 @@ export default function TextAreaComponent({
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openPopUp(
|
openPopUp(
|
||||||
<GenericModal
|
<GenericModal
|
||||||
|
type={TypeModal.TEXT}
|
||||||
buttonText="Finishing Editing"
|
buttonText="Finishing Editing"
|
||||||
modalTitle="Edit Text"
|
modalTitle="Edit Text"
|
||||||
value={myValue}
|
value={myValue}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,8 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
||||||
console.log(node.data.node.template[key].type);
|
console.log(node.data.node.template[key].type);
|
||||||
if (node.data.node.template[key].type === "file") {
|
if (node.data.node.template[key].type === "file") {
|
||||||
console.log(node.data.node.template[key]);
|
console.log(node.data.node.template[key]);
|
||||||
node.data.node.template[key].content = "";
|
// ! Commenting this out for now, as it is causing issues with the file upload
|
||||||
|
// node.data.node.template[key].content = "";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -86,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"
|
||||||
|
|
@ -275,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
|
||||||
|
|
|
||||||
|
|
@ -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 && (
|
||||||
|
|
|
||||||
|
|
@ -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 } 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(
|
||||||
|
|
@ -103,8 +122,8 @@ export default function NodeModal({ data }: { data: NodeDataType }) {
|
||||||
data.node.template[t].display_name
|
data.node.template[t].display_name
|
||||||
? data.node.template[t].display_name
|
? data.node.template[t].display_name
|
||||||
: data.node.template[t].name
|
: data.node.template[t].name
|
||||||
? toNormalCase(data.node.template[t].name)
|
? toTitleCase(data.node.template[t].name)
|
||||||
: toNormalCase(t)
|
: toTitleCase(t)
|
||||||
}
|
}
|
||||||
required={data.node.template[t].required}
|
required={data.node.template[t].required}
|
||||||
id={
|
id={
|
||||||
|
|
@ -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}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
|
||||||
|
|
@ -5,19 +5,23 @@ import { PopUpContext } from "../../contexts/popUpContext";
|
||||||
import { darkContext } from "../../contexts/darkContext";
|
import { darkContext } from "../../contexts/darkContext";
|
||||||
import { checkPrompt } from "../../controllers/API";
|
import { checkPrompt } from "../../controllers/API";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
|
import { TypeModal } from "../../utils";
|
||||||
export default function PromptAreaModal({
|
export default function PromptAreaModal({
|
||||||
value,
|
value,
|
||||||
setValue,
|
setValue,
|
||||||
buttonText,
|
buttonText,
|
||||||
modalTitle,
|
modalTitle,
|
||||||
|
type,
|
||||||
}: {
|
}: {
|
||||||
setValue: (value: string) => void;
|
setValue: (value: string) => void;
|
||||||
value: string;
|
value: string;
|
||||||
buttonText: string;
|
buttonText: string;
|
||||||
modalTitle: string;
|
modalTitle: string;
|
||||||
|
type: number;
|
||||||
}) {
|
}) {
|
||||||
const [myButtonText, setmyButtonText] = useState(buttonText);
|
const [myButtonText] = useState(buttonText);
|
||||||
const [myModalTitle, setMyModalTitle] = useState(modalTitle);
|
const [myModalTitle] = useState(modalTitle);
|
||||||
|
const [myModalType] = useState(type);
|
||||||
const [open, setOpen] = useState(true);
|
const [open, setOpen] = useState(true);
|
||||||
const [myValue, setMyValue] = useState(value);
|
const [myValue, setMyValue] = useState(value);
|
||||||
const { dark } = useContext(darkContext);
|
const { dark } = useContext(darkContext);
|
||||||
|
|
@ -114,6 +118,11 @@ export default function PromptAreaModal({
|
||||||
type="button"
|
type="button"
|
||||||
className="inline-flex w-full justify-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-base font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 sm:ml-3 sm:w-auto sm:text-sm"
|
className="inline-flex w-full justify-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-base font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 sm:ml-3 sm:w-auto sm:text-sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
switch (myModalType) {
|
||||||
|
case 1:
|
||||||
|
setModalOpen(false);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
checkPrompt(myValue)
|
checkPrompt(myValue)
|
||||||
.then((apiReturn) => {
|
.then((apiReturn) => {
|
||||||
if (apiReturn.data) {
|
if (apiReturn.data) {
|
||||||
|
|
@ -133,7 +142,8 @@ export default function PromptAreaModal({
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setErrorData({
|
setErrorData({
|
||||||
title: "Something went wrong, please try again",
|
title:
|
||||||
|
"Something went wrong, please try again",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -144,6 +154,11 @@ export default function PromptAreaModal({
|
||||||
list: [error.response.data.detail],
|
list: [error.response.data.detail],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{myButtonText}
|
{myButtonText}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { nodeColors, nodeIcons, nodeNames } from "../../../../utils";
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useContext, useEffect, useState } from "react";
|
||||||
import { typesContext } from "../../../../contexts/typesContext";
|
import { typesContext } from "../../../../contexts/typesContext";
|
||||||
import { APIClassType, APIObjectType } from "../../../../types/api";
|
import { APIClassType, APIObjectType } from "../../../../types/api";
|
||||||
|
import Tooltip from "../../../../components/TooltipComponent";
|
||||||
|
|
||||||
export default function ExtraSidebar() {
|
export default function ExtraSidebar() {
|
||||||
const { data } = useContext(typesContext);
|
const { data } = useContext(typesContext);
|
||||||
|
|
@ -33,6 +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">
|
||||||
<div key={k}>
|
<div key={k}>
|
||||||
<div
|
<div
|
||||||
draggable
|
draggable
|
||||||
|
|
@ -55,6 +57,7 @@ export default function ExtraSidebar() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</Tooltip>
|
||||||
))}
|
))}
|
||||||
{Object.keys(data[d]).length === 0 && (
|
{Object.keys(data[d]).length === 0 && (
|
||||||
<div className="text-gray-400 text-center">Coming soon</div>
|
<div className="text-gray-400 text-center">Coming soon</div>
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,19 @@ import { Connection, Edge, Node, ReactFlowInstance } from "reactflow";
|
||||||
import { FlowType } from "./types/flow";
|
import { FlowType } from "./types/flow";
|
||||||
import { APITemplateType, TemplateVariableType } from "./types/api";
|
import { APITemplateType, TemplateVariableType } from "./types/api";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
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 {
|
||||||
|
TEXT = 1,
|
||||||
|
PROMPT = 2,
|
||||||
|
}
|
||||||
|
|
||||||
export const textColors = {
|
export const textColors = {
|
||||||
white: "text-white",
|
white: "text-white",
|
||||||
red: "text-red-700",
|
red: "text-red-700",
|
||||||
|
|
@ -492,3 +500,64 @@ export const programmingLanguages: languageMap = {
|
||||||
css: ".css",
|
css: ".css",
|
||||||
// add more file extensions here, make sure the key is same as language prop in CodeBlock.tsx component
|
// add more file extensions here, make sure the key is same as language prop in CodeBlock.tsx component
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function toTitleCase(str: string) {
|
||||||
|
let result = str
|
||||||
|
.split("_")
|
||||||
|
.map((word, index) => {
|
||||||
|
if (index === 0) {
|
||||||
|
return checkUpperWords(
|
||||||
|
word[0].toUpperCase() + word.slice(1).toLowerCase()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return checkUpperWords(word.toLowerCase());
|
||||||
|
})
|
||||||
|
.join(" ");
|
||||||
|
|
||||||
|
return result
|
||||||
|
.split("-")
|
||||||
|
.map((word, index) => {
|
||||||
|
if (index === 0) {
|
||||||
|
return checkUpperWords(
|
||||||
|
word[0].toUpperCase() + word.slice(1).toLowerCase()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return checkUpperWords(word.toLowerCase());
|
||||||
|
})
|
||||||
|
.join(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
export const upperCaseWords: string[] = ["llm", "uri"];
|
||||||
|
export function checkUpperWords(str: string) {
|
||||||
|
const words = str.split(" ").map((word) => {
|
||||||
|
return upperCaseWords.includes(word.toLowerCase())
|
||||||
|
? word.toUpperCase()
|
||||||
|
: word[0].toUpperCase() + word.slice(1).toLowerCase();
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ module.exports = {
|
||||||
|
|
||||||
animation: {
|
animation: {
|
||||||
"pulse-green": "pulseGreen 1s linear",
|
"pulse-green": "pulseGreen 1s linear",
|
||||||
|
'spin-once': 'spin 1s linear 0.7'
|
||||||
},
|
},
|
||||||
keyframes: {
|
keyframes: {
|
||||||
pulseGreen: {
|
pulseGreen: {
|
||||||
|
|
|
||||||
59
tests/test_embeddings_template.py
Normal file
59
tests/test_embeddings_template.py
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
from langflow.template.field.base import TemplateField
|
||||||
|
from langflow.template.frontend_node.embeddings import EmbeddingFrontendNode
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_jina_fields():
|
||||||
|
field = TemplateField(name="jina")
|
||||||
|
EmbeddingFrontendNode.format_jina_fields(field)
|
||||||
|
assert field.show is True
|
||||||
|
assert field.advanced is False
|
||||||
|
|
||||||
|
field = TemplateField(name="auth")
|
||||||
|
EmbeddingFrontendNode.format_jina_fields(field)
|
||||||
|
assert field.password is True
|
||||||
|
assert field.show is True
|
||||||
|
assert field.advanced is False
|
||||||
|
|
||||||
|
field = TemplateField(name="jina_api_url")
|
||||||
|
EmbeddingFrontendNode.format_jina_fields(field)
|
||||||
|
assert field.show is True
|
||||||
|
assert field.advanced is True
|
||||||
|
assert field.display_name == "Jina API URL"
|
||||||
|
assert field.password is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_openai_fields():
|
||||||
|
field = TemplateField(name="openai")
|
||||||
|
EmbeddingFrontendNode.format_openai_fields(field)
|
||||||
|
assert field.show is True
|
||||||
|
assert field.advanced is True
|
||||||
|
assert field.display_name == "OpenAI"
|
||||||
|
|
||||||
|
field = TemplateField(name="openai_api_key")
|
||||||
|
EmbeddingFrontendNode.format_openai_fields(field)
|
||||||
|
assert field.password is True
|
||||||
|
assert field.show is True
|
||||||
|
assert field.advanced is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_field():
|
||||||
|
field = TemplateField(name="headers")
|
||||||
|
EmbeddingFrontendNode.format_field(field)
|
||||||
|
assert field.show is False
|
||||||
|
|
||||||
|
field = TemplateField(name="jina")
|
||||||
|
EmbeddingFrontendNode.format_field(field)
|
||||||
|
assert field.advanced is False
|
||||||
|
assert field.show is True
|
||||||
|
|
||||||
|
field = TemplateField(name="openai")
|
||||||
|
EmbeddingFrontendNode.format_field(field)
|
||||||
|
assert field.advanced is True
|
||||||
|
assert field.show is True
|
||||||
|
assert field.display_name == "OpenAI"
|
||||||
|
|
||||||
|
field = TemplateField(name="test_field", required=True)
|
||||||
|
EmbeddingFrontendNode.format_field(field)
|
||||||
|
assert field.advanced is False
|
||||||
|
assert field.show is True
|
||||||
|
assert field.required is True
|
||||||
Loading…
Add table
Add a link
Reference in a new issue