merge fix
This commit is contained in:
commit
3a612c874c
89 changed files with 1296 additions and 1059 deletions
|
|
@ -26,13 +26,13 @@ def upgrade() -> None:
|
|||
flow_constraints = inspector.get_unique_constraints("flow")
|
||||
user_constraints = inspector.get_unique_constraints("user")
|
||||
try:
|
||||
if not any(constraint["name"] == "uq_apikey_id" for constraint in api_key_constraints):
|
||||
if not any(constraint["column_names"] == ["id"] for constraint in api_key_constraints):
|
||||
with op.batch_alter_table("apikey", schema=None) as batch_op:
|
||||
batch_op.create_unique_constraint("uq_apikey_id", ["id"])
|
||||
if not any(constraint["name"] == "uq_flow_id" for constraint in flow_constraints):
|
||||
if not any(constraint["column_names"] == ["id"] for constraint in flow_constraints):
|
||||
with op.batch_alter_table("flow", schema=None) as batch_op:
|
||||
batch_op.create_unique_constraint("uq_flow_id", ["id"])
|
||||
if not any(constraint["name"] == "uq_user_id" for constraint in user_constraints):
|
||||
if not any(constraint["column_names"] == ["id"] for constraint in user_constraints):
|
||||
with op.batch_alter_table("user", schema=None) as batch_op:
|
||||
batch_op.create_unique_constraint("uq_user_id", ["id"])
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import warnings
|
|||
from typing import Optional, Union
|
||||
|
||||
from langflow.field_typing import Text
|
||||
from langflow.helpers.record import records_to_text
|
||||
from langflow.interface.custom.custom_component import CustomComponent
|
||||
from langflow.memory import add_messages
|
||||
from langflow.schema import Record
|
||||
|
|
@ -21,6 +22,7 @@ class ChatComponent(CustomComponent):
|
|||
"sender": {
|
||||
"options": ["Machine", "User"],
|
||||
"display_name": "Sender Type",
|
||||
"advanced": True,
|
||||
},
|
||||
"sender_name": {"display_name": "Sender Name"},
|
||||
"session_id": {
|
||||
|
|
@ -31,6 +33,13 @@ class ChatComponent(CustomComponent):
|
|||
"return_record": {
|
||||
"display_name": "Return Record",
|
||||
"info": "Return the message as a record containing the sender, sender_name, and session_id.",
|
||||
"advanced": True,
|
||||
},
|
||||
"record_template": {
|
||||
"display_name": "Record Template",
|
||||
"multiline": True,
|
||||
"info": "In case of Message being a Record, this template will be used to convert it to text.",
|
||||
"advanced": True,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -74,9 +83,10 @@ class ChatComponent(CustomComponent):
|
|||
self,
|
||||
sender: Optional[str] = "User",
|
||||
sender_name: Optional[str] = "User",
|
||||
input_value: Optional[str] = None,
|
||||
input_value: Optional[Union[str, Record]] = None,
|
||||
session_id: Optional[str] = None,
|
||||
return_record: Optional[bool] = False,
|
||||
record_template: Optional[str] = "Text: {text}\nData: {data}",
|
||||
) -> Union[Text, Record]:
|
||||
input_value_record: Optional[Record] = None
|
||||
if return_record:
|
||||
|
|
@ -94,6 +104,8 @@ class ChatComponent(CustomComponent):
|
|||
"session_id": session_id,
|
||||
},
|
||||
)
|
||||
elif isinstance(input_value, Record):
|
||||
input_value = records_to_text(template=record_template, records=input_value)
|
||||
if not input_value:
|
||||
input_value = ""
|
||||
if return_record and input_value_record:
|
||||
|
|
|
|||
|
|
@ -1,18 +1,28 @@
|
|||
from typing import Optional
|
||||
from typing import Optional, Union
|
||||
|
||||
from langflow.field_typing import Text
|
||||
from langflow.helpers.record import records_to_text
|
||||
from langflow.interface.custom.custom_component import CustomComponent
|
||||
from langflow.schema.schema import Record
|
||||
|
||||
|
||||
class TextComponent(CustomComponent):
|
||||
display_name = "Text Component"
|
||||
description = "Used to pass text to the next component."
|
||||
|
||||
field_config = {
|
||||
"input_value": {"display_name": "Value", "multiline": True},
|
||||
}
|
||||
def build_config(self):
|
||||
return {
|
||||
"input_value": {"display_name": "Value", "input_types": ["Record"], "info": "Text or Record to be passed."},
|
||||
"record_template": {"display_name": "Record Template", "multiline": True},
|
||||
}
|
||||
|
||||
def build(self, input_value: Optional[str] = "") -> Text:
|
||||
def build(
|
||||
self,
|
||||
input_value: Optional[Union[Text, Record]] = "",
|
||||
record_template: Optional[str] = "Text: {text}\nData: {data}",
|
||||
) -> Text:
|
||||
if isinstance(input_value, Record):
|
||||
input_value = records_to_text(template=record_template, records=input_value)
|
||||
self.status = input_value
|
||||
if not input_value:
|
||||
input_value = ""
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
__all__ = [
|
||||
"agents",
|
||||
"chains",
|
||||
"data",
|
||||
"documentloaders",
|
||||
"embeddings",
|
||||
"experimental",
|
||||
"helpers",
|
||||
"inputs",
|
||||
"memories",
|
||||
"model_specs",
|
||||
"models",
|
||||
"outputs",
|
||||
"retrievers",
|
||||
"textsplitters",
|
||||
"toolkits",
|
||||
"tools",
|
||||
"vectorsearch",
|
||||
"vectorstores",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from .OpenAIConversationalAgent import ConversationalAgent
|
|||
from .SQLAgent import SQLAgentComponent
|
||||
from .VectorStoreAgent import VectorStoreAgentComponent
|
||||
from .VectorStoreRouterAgent import VectorStoreRouterAgentComponent
|
||||
from .XMLAgent import XMLAgentComponent
|
||||
|
||||
__all__ = [
|
||||
"AgentInitializerComponent",
|
||||
|
|
@ -14,4 +15,5 @@ __all__ = [
|
|||
"SQLAgentComponent",
|
||||
"VectorStoreAgentComponent",
|
||||
"VectorStoreRouterAgentComponent",
|
||||
"XMLAgentComponent",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ from langflow.schema import Record
|
|||
|
||||
class APIRequest(CustomComponent):
|
||||
display_name: str = "API Request"
|
||||
description: str = "Make an HTTP request to the given URL."
|
||||
description: str = "Make HTTP requests given one or more URLs."
|
||||
output_types: list[str] = ["Record"]
|
||||
documentation: str = "https://docs.langflow.org/components/utilities#api-request"
|
||||
field_config = {
|
||||
"urls": {"display_name": "URLs", "info": "The URLs to make the request to."},
|
||||
"urls": {"display_name": "URLs", "info": "URLs to make requests to."},
|
||||
"method": {
|
||||
"display_name": "Method",
|
||||
"info": "The HTTP method to use.",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from langflow.schema import Record
|
|||
|
||||
class DirectoryComponent(CustomComponent):
|
||||
display_name = "Directory"
|
||||
description = "Load Text Files from a Directory and Convert Them to Records."
|
||||
description = "Recursively load files from a directory."
|
||||
|
||||
def build_config(self) -> Dict[str, Any]:
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
from typing import Any, Dict, List
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict
|
||||
|
||||
from langflow.base.data.utils import TEXT_FILE_TYPES, parse_text_file_to_record
|
||||
from langflow.interface.custom.custom_component import CustomComponent
|
||||
|
|
@ -7,12 +8,12 @@ from langflow.schema import Record
|
|||
|
||||
class FileComponent(CustomComponent):
|
||||
display_name = "Files"
|
||||
description = "Read Text Files"
|
||||
description = "A generic file loader."
|
||||
|
||||
def build_config(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"paths": {
|
||||
"display_name": "Paths",
|
||||
"path": {
|
||||
"display_name": "Path",
|
||||
"field_type": "file",
|
||||
"file_types": TEXT_FILE_TYPES,
|
||||
"info": f"Supported file types: {', '.join(TEXT_FILE_TYPES)}",
|
||||
|
|
@ -26,7 +27,8 @@ class FileComponent(CustomComponent):
|
|||
|
||||
def load_file(self, path: str, silent_errors: bool = False) -> Record:
|
||||
resolved_path = self.resolve_path(path)
|
||||
extension = resolved_path.split(".")[-1]
|
||||
path_obj = Path(resolved_path)
|
||||
extension = path_obj.suffix[1:].lower()
|
||||
if extension == "doc":
|
||||
raise ValueError("doc files are not supported. Please save as .docx")
|
||||
if extension not in TEXT_FILE_TYPES:
|
||||
|
|
@ -37,9 +39,9 @@ class FileComponent(CustomComponent):
|
|||
|
||||
def build(
|
||||
self,
|
||||
paths: List[str],
|
||||
path: str,
|
||||
silent_errors: bool = False,
|
||||
) -> List[Record]:
|
||||
records = [self.load_file(path, silent_errors) for path in paths]
|
||||
self.status = records
|
||||
return records
|
||||
) -> Record:
|
||||
record = self.load_file(path, silent_errors)
|
||||
self.status = record
|
||||
return record
|
||||
|
|
|
|||
|
|
@ -1,117 +0,0 @@
|
|||
from typing import List
|
||||
|
||||
from langflow.interface.custom.custom_component import CustomComponent
|
||||
from langflow.schema import Record
|
||||
from langflow.utils.constants import LOADERS_INFO
|
||||
|
||||
|
||||
class FileLoaderComponent(CustomComponent):
|
||||
display_name: str = "File Loader"
|
||||
description: str = "Generic File Loader"
|
||||
|
||||
def build_config(self):
|
||||
loader_options = ["Automatic"] + [loader_info["name"] for loader_info in LOADERS_INFO]
|
||||
|
||||
file_types = []
|
||||
suffixes = []
|
||||
|
||||
for loader_info in LOADERS_INFO:
|
||||
if "allowedTypes" in loader_info:
|
||||
file_types.extend(loader_info["allowedTypes"])
|
||||
suffixes.extend([f".{ext}" for ext in loader_info["allowedTypes"]])
|
||||
|
||||
return {
|
||||
"file_path": {
|
||||
"display_name": "File Path",
|
||||
"required": True,
|
||||
"field_type": "file",
|
||||
"file_types": [
|
||||
"json",
|
||||
"txt",
|
||||
"csv",
|
||||
"jsonl",
|
||||
"html",
|
||||
"htm",
|
||||
"conllu",
|
||||
"enex",
|
||||
"msg",
|
||||
"pdf",
|
||||
"srt",
|
||||
"eml",
|
||||
"md",
|
||||
"mdx",
|
||||
"pptx",
|
||||
"docx",
|
||||
],
|
||||
"suffixes": [
|
||||
".json",
|
||||
".txt",
|
||||
".csv",
|
||||
".jsonl",
|
||||
".html",
|
||||
".htm",
|
||||
".conllu",
|
||||
".enex",
|
||||
".msg",
|
||||
".pdf",
|
||||
".srt",
|
||||
".eml",
|
||||
".md",
|
||||
".mdx",
|
||||
".pptx",
|
||||
".docx",
|
||||
],
|
||||
# "file_types" : file_types,
|
||||
# "suffixes": suffixes,
|
||||
},
|
||||
"loader": {
|
||||
"display_name": "Loader",
|
||||
"is_list": True,
|
||||
"required": True,
|
||||
"options": loader_options,
|
||||
"value": "Automatic",
|
||||
},
|
||||
"code": {"show": False},
|
||||
}
|
||||
|
||||
def build(self, file_path: str, loader: str) -> List[Record]:
|
||||
file_type = file_path.split(".")[-1]
|
||||
|
||||
# Map the loader to the correct loader class
|
||||
selected_loader_info = None
|
||||
for loader_info in LOADERS_INFO:
|
||||
if loader_info["name"] == loader:
|
||||
selected_loader_info = loader_info
|
||||
break
|
||||
|
||||
if selected_loader_info is None and loader != "Automatic":
|
||||
raise ValueError(f"Loader {loader} not found in the loader info list")
|
||||
|
||||
if loader == "Automatic":
|
||||
# Determine the loader based on the file type
|
||||
default_loader_info = None
|
||||
for info in LOADERS_INFO:
|
||||
if "defaultFor" in info and file_type in info["defaultFor"]:
|
||||
default_loader_info = info
|
||||
break
|
||||
|
||||
if default_loader_info is None:
|
||||
raise ValueError(f"No default loader found for file type: {file_type}")
|
||||
|
||||
selected_loader_info = default_loader_info
|
||||
if isinstance(selected_loader_info, dict):
|
||||
loader_import: str = selected_loader_info["import"]
|
||||
else:
|
||||
raise ValueError(f"Loader info for {loader} is not a dict\nLoader info:\n{selected_loader_info}")
|
||||
module_name, class_name = loader_import.rsplit(".", 1)
|
||||
|
||||
try:
|
||||
# Import the loader class
|
||||
loader_module = __import__(module_name, fromlist=[class_name])
|
||||
loader_instance = getattr(loader_module, class_name)
|
||||
except ImportError as e:
|
||||
raise ValueError(f"Loader {loader} could not be imported\nLoader info:\n{selected_loader_info}") from e
|
||||
|
||||
result = loader_instance(file_path=file_path)
|
||||
docs = result.load()
|
||||
return self.to_records(docs)
|
||||
|
|
@ -8,7 +8,7 @@ from langflow.schema import Record
|
|||
|
||||
class URLComponent(CustomComponent):
|
||||
display_name = "URL"
|
||||
description = "Load URLs and convert them to records."
|
||||
description = "Fetch text content given one or more URLs."
|
||||
|
||||
def build_config(self) -> Dict[str, Any]:
|
||||
return {
|
||||
|
|
@ -22,4 +22,5 @@ class URLComponent(CustomComponent):
|
|||
loader = WebBaseLoader(web_paths=urls)
|
||||
docs = loader.load()
|
||||
records = self.to_records(docs)
|
||||
self.status = records
|
||||
return records
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from .APIRequest import APIRequest
|
||||
from .Directory import DirectoryComponent
|
||||
from .File import FileComponent
|
||||
from .FileLoader import FileLoaderComponent
|
||||
|
||||
from .URL import URLComponent
|
||||
|
||||
__all__ = ["APIRequest", "DirectoryComponent", "FileComponent", "FileLoaderComponent", "URLComponent"]
|
||||
__all__ = ["APIRequest", "DirectoryComponent", "FileComponent", "URLComponent"]
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from typing import Optional
|
|||
|
||||
from langchain_community.embeddings.cohere import CohereEmbeddings
|
||||
|
||||
from langflow.interface.custom.custom_component import CustomComponent
|
||||
from langflow.custom import CustomComponent
|
||||
|
||||
|
||||
class CohereEmbeddingsComponent(CustomComponent):
|
||||
|
|
|
|||
|
|
@ -1,23 +1,27 @@
|
|||
from .ClearMessageHistory import ClearMessageHistoryComponent
|
||||
from .ExtractDataFromRecord import ExtractKeyFromRecordComponent
|
||||
from .Listen import ListenComponent
|
||||
from .FlowTool import FlowToolComponent
|
||||
from .ListFlows import ListFlowsComponent
|
||||
from .Listen import ListenComponent
|
||||
from .MergeRecords import MergeRecordsComponent
|
||||
from .Notify import NotifyComponent
|
||||
from .PythonFunction import PythonFunctionComponent
|
||||
from .RunFlow import RunFlowComponent
|
||||
from .RunnableExecutor import RunnableExecComponent
|
||||
from .SQLExecutor import SQLExecutorComponent
|
||||
from .SubFlow import SubFlowComponent
|
||||
|
||||
__all__ = [
|
||||
"ClearMessageHistoryComponent",
|
||||
"ExtractKeyFromRecordComponent",
|
||||
"ListenComponent",
|
||||
"FlowToolComponent",
|
||||
"ListFlowsComponent",
|
||||
"ListenComponent",
|
||||
"MergeRecordsComponent",
|
||||
"MessageHistoryComponent",
|
||||
"NotifyComponent",
|
||||
"PythonFunctionComponent",
|
||||
"RunFlowComponent",
|
||||
"RunnableExecComponent",
|
||||
"SQLExecutorComponent",
|
||||
"TextToRecordComponent",
|
||||
"SubFlowComponent",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@ from langflow.interface.custom.custom_component import CustomComponent
|
|||
from langflow.schema import Record
|
||||
|
||||
|
||||
class TextToRecordComponent(CustomComponent):
|
||||
display_name = "Text to Record"
|
||||
description = "A component to create a record from Text."
|
||||
class CreateRecordComponent(CustomComponent):
|
||||
display_name = "Create Record"
|
||||
description = "A component to create a record."
|
||||
beta: bool = True
|
||||
|
||||
def build_config(self):
|
||||
return {
|
||||
"data": {
|
||||
"display_name": "Data",
|
||||
"info": "The data to convert to a record.",
|
||||
"info": "Data to contruct the record.",
|
||||
"input_types": ["Text"],
|
||||
}
|
||||
}
|
||||
|
|
@ -7,8 +7,8 @@ from langflow.schema import Record
|
|||
|
||||
|
||||
class DocumentToRecordComponent(CustomComponent):
|
||||
display_name = "Documents to Records"
|
||||
description = "Convert documents to records."
|
||||
display_name = "Documents To Records"
|
||||
description = "Convert LangChain Documents into Records."
|
||||
|
||||
field_config = {
|
||||
"documents": {"display_name": "Documents"},
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from langflow.interface.custom.custom_component import CustomComponent
|
|||
|
||||
class UUIDGeneratorComponent(CustomComponent):
|
||||
documentation: str = "http://docs.langflow.org/components/custom"
|
||||
display_name = "Unique ID Generator"
|
||||
display_name = "ID Generator"
|
||||
description = "Generates a unique ID."
|
||||
|
||||
def update_build_config(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from langflow.schema import Record
|
|||
|
||||
class MessageHistoryComponent(CustomComponent):
|
||||
display_name = "Message History"
|
||||
description = "Used to retrieve stored messages."
|
||||
description = "Used to retrieve stored chat messages."
|
||||
beta: bool = True
|
||||
|
||||
def build_config(self):
|
||||
|
|
@ -30,7 +30,7 @@ class MessageHistoryComponent(CustomComponent):
|
|||
|
||||
def build(
|
||||
self,
|
||||
sender: Optional[str] = None,
|
||||
sender: Optional[str] = "Machine",
|
||||
sender_name: Optional[str] = None,
|
||||
session_id: Optional[str] = None,
|
||||
n_messages: int = 5,
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ from langflow.interface.custom.custom_component import CustomComponent
|
|||
from langflow.schema import Record
|
||||
|
||||
|
||||
class RecordsAsTextComponent(CustomComponent):
|
||||
display_name = "Records to Text"
|
||||
description = "Converts Records into single piece of text using a template."
|
||||
class RecordsToTextComponent(CustomComponent):
|
||||
display_name = "Records To Text"
|
||||
description = "Convert Records into plain text using a pre-defined template."
|
||||
|
||||
def build_config(self):
|
||||
return {
|
||||
|
|
@ -4,7 +4,7 @@ from langflow.schema import Record
|
|||
|
||||
class UpdateRecordComponent(CustomComponent):
|
||||
display_name = "Update Record"
|
||||
description = "Updates a record with new data."
|
||||
description = "Updates a Record with new data. Akin to a Python dictionary update."
|
||||
|
||||
def build_config(self):
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ from .CustomComponent import Component
|
|||
from .DocumentToRecord import DocumentToRecordComponent
|
||||
from .IDGenerator import UUIDGeneratorComponent
|
||||
from .MessageHistory import MessageHistoryComponent
|
||||
from .PythonFunction import PythonFunctionComponent
|
||||
from .RecordsAsText import RecordsAsTextComponent
|
||||
from .TextToRecord import TextToRecordComponent
|
||||
from .UpdateRecord import UpdateRecordComponent
|
||||
|
||||
|
|
@ -13,7 +11,7 @@ __all__ = [
|
|||
"DocumentToRecordComponent",
|
||||
"UUIDGeneratorComponent",
|
||||
"PythonFunctionComponent",
|
||||
"RecordsAsTextComponent",
|
||||
"RecordsToTextComponent",
|
||||
"TextToRecordComponent",
|
||||
"MessageHistoryComponent",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from langflow.schema import Record
|
|||
|
||||
class ChatInput(ChatComponent):
|
||||
display_name = "Chat Input"
|
||||
description = "Used to get user input from the chat."
|
||||
description = "Capture user inputs from the chat interface."
|
||||
icon = "ChatInput"
|
||||
|
||||
def build(
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
import ast
|
||||
import json
|
||||
|
||||
from langflow.custom import CustomComponent
|
||||
from langflow.schema import Record
|
||||
|
||||
|
||||
class JSONInputComponent(CustomComponent):
|
||||
display_name = "JSON Input"
|
||||
description = "Load a JSON object as input."
|
||||
|
||||
def build_config(self):
|
||||
return {
|
||||
"json_str": {
|
||||
"display_name": "JSON String",
|
||||
"multiline": True,
|
||||
"info": "The JSON string to load.",
|
||||
}
|
||||
}
|
||||
|
||||
def build(self, json_str: str) -> Record:
|
||||
try:
|
||||
data = json.loads(json_str)
|
||||
except json.JSONDecodeError:
|
||||
try:
|
||||
data = ast.literal_eval(json_str)
|
||||
except (SyntaxError, ValueError):
|
||||
raise ValueError("Invalid JSON string.")
|
||||
record = Record(data=data)
|
||||
return record
|
||||
|
|
@ -6,7 +6,7 @@ from langflow.interface.custom.custom_component import CustomComponent
|
|||
|
||||
class PromptComponent(CustomComponent):
|
||||
display_name: str = "Prompt"
|
||||
description: str = "A component for creating prompts using templates"
|
||||
description: str = "A component for creating prompt templates using dynamic variables."
|
||||
icon = "terminal-square"
|
||||
|
||||
def build_config(self):
|
||||
|
|
|
|||
|
|
@ -6,7 +6,21 @@ from langflow.field_typing import Text
|
|||
|
||||
class TextInput(TextComponent):
|
||||
display_name = "Text Input"
|
||||
description = "Used to pass text input to the next component."
|
||||
description = "Capture Text or Record and send text inputs."
|
||||
|
||||
def build(self, input_value: Optional[str] = "") -> Text:
|
||||
return super().build(input_value=input_value)
|
||||
def build_config(self):
|
||||
return {
|
||||
"input_value": {
|
||||
"display_name": "Value",
|
||||
"input_types": ["Record"],
|
||||
"info": "Text or Record to be passed as input.",
|
||||
},
|
||||
"record_template": {"display_name": "Record Template", "multiline": True},
|
||||
}
|
||||
|
||||
def build(
|
||||
self,
|
||||
input_value: Optional[str] = "",
|
||||
record_template: Optional[str] = "{text}",
|
||||
) -> Text:
|
||||
return super().build(input_value=input_value, record_template=record_template)
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@ from .ChatInput import ChatInput
|
|||
from .Prompt import PromptComponent
|
||||
from .TextInput import TextInput
|
||||
|
||||
__all__ = ["ChatInput", "TextInput", "PromptComponent"]
|
||||
__all__ = ["ChatInput", "PromptComponent", "TextInput"]
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
from typing import Dict, Optional
|
||||
|
||||
from langchain_community.llms.ctransformers import CTransformers
|
||||
|
||||
from langflow.interface.custom.custom_component import CustomComponent
|
||||
|
||||
|
||||
class CTransformersComponent(CustomComponent):
|
||||
display_name = "CTransformers"
|
||||
description = "C Transformers LLM models"
|
||||
documentation = "https://python.langchain.com/docs/modules/model_io/models/llms/integrations/ctransformers"
|
||||
|
||||
def build_config(self):
|
||||
return {
|
||||
"model": {"display_name": "Model", "required": True},
|
||||
"model_file": {
|
||||
"display_name": "Model File",
|
||||
"required": False,
|
||||
"field_type": "file",
|
||||
"file_types": [".bin"],
|
||||
},
|
||||
"model_type": {"display_name": "Model Type", "required": True},
|
||||
"config": {
|
||||
"display_name": "Config",
|
||||
"advanced": True,
|
||||
"required": False,
|
||||
"field_type": "dict",
|
||||
"value": '{"top_k":40,"top_p":0.95,"temperature":0.8,"repetition_penalty":1.1,"last_n_tokens":64,"seed":-1,"max_new_tokens":256,"stop":"","stream":"False","reset":"True","batch_size":8,"threads":-1,"context_length":-1,"gpu_layers":0}',
|
||||
},
|
||||
}
|
||||
|
||||
def build(self, model: str, model_file: str, model_type: str, config: Optional[Dict] = None) -> CTransformers:
|
||||
return CTransformers(model=model, model_file=model_file, model_type=model_type, config=config) # type: ignore
|
||||
|
|
@ -3,8 +3,8 @@ from typing import Callable, Optional, Union
|
|||
from langchain_community.chat_models.anthropic import ChatAnthropic
|
||||
from pydantic.v1.types import SecretStr
|
||||
|
||||
from langflow.custom import CustomComponent
|
||||
from langflow.field_typing import BaseLanguageModel
|
||||
from langflow.interface.custom.custom_component import CustomComponent
|
||||
|
||||
|
||||
class ChatAnthropicComponent(CustomComponent):
|
||||
|
|
@ -20,31 +20,48 @@ class ChatAnthropicComponent(CustomComponent):
|
|||
"field_type": "str",
|
||||
"password": True,
|
||||
},
|
||||
"anthropic_api_url": {
|
||||
"display_name": "Anthropic API URL",
|
||||
"field_type": "str",
|
||||
},
|
||||
"model_kwargs": {
|
||||
"display_name": "Model Kwargs",
|
||||
"field_type": "dict",
|
||||
"advanced": True,
|
||||
},
|
||||
"model_name": {
|
||||
"display_name": "Model Name",
|
||||
"field_type": "str",
|
||||
"advanced": False,
|
||||
"required": False,
|
||||
"options": ["claude-3-opus-20240229", "claude-3-sonnet-20240229", "claude-3-haiku-20240307"],
|
||||
},
|
||||
"temperature": {
|
||||
"display_name": "Temperature",
|
||||
"field_type": "float",
|
||||
},
|
||||
"max_tokens": {
|
||||
"display_name": "Max Tokens",
|
||||
"field_type": "int",
|
||||
"advanced": False,
|
||||
"required": False,
|
||||
},
|
||||
"top_k": {"display_name": "Top K", "field_type": "int", "advanced": True},
|
||||
"top_p": {"display_name": "Top P", "field_type": "float", "advanced": True},
|
||||
}
|
||||
|
||||
def build(
|
||||
self,
|
||||
anthropic_api_key: str,
|
||||
anthropic_api_url: Optional[str] = None,
|
||||
model_kwargs: dict = {},
|
||||
model_name: str = "claude-3-opus-20240229",
|
||||
temperature: Optional[float] = None,
|
||||
max_tokens: Optional[int] = 1024,
|
||||
top_k: Optional[int] = None,
|
||||
top_p: Optional[float] = None,
|
||||
) -> Union[BaseLanguageModel, Callable]:
|
||||
return ChatAnthropic(
|
||||
anthropic_api_key=SecretStr(anthropic_api_key),
|
||||
anthropic_api_url=anthropic_api_url,
|
||||
model_kwargs=model_kwargs,
|
||||
model_name=model_name,
|
||||
temperature=temperature,
|
||||
max_tokens=max_tokens, # type: ignore
|
||||
top_k=top_k,
|
||||
top_p=top_p,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,131 +0,0 @@
|
|||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from langchain_community.llms.llamacpp import LlamaCpp
|
||||
|
||||
from langflow.interface.custom.custom_component import CustomComponent
|
||||
|
||||
|
||||
class LlamaCppComponent(CustomComponent):
|
||||
display_name = "LlamaCpp"
|
||||
description = "llama.cpp model."
|
||||
documentation = "https://python.langchain.com/docs/modules/model_io/models/llms/integrations/llamacpp"
|
||||
|
||||
def build_config(self):
|
||||
return {
|
||||
"grammar": {"display_name": "Grammar", "advanced": True},
|
||||
"cache": {"display_name": "Cache", "advanced": True},
|
||||
"client": {"display_name": "Client", "advanced": True},
|
||||
"echo": {"display_name": "Echo", "advanced": True},
|
||||
"f16_kv": {"display_name": "F16 KV", "advanced": True},
|
||||
"grammar_path": {"display_name": "Grammar Path", "advanced": True},
|
||||
"last_n_tokens_size": {"display_name": "Last N Tokens Size", "advanced": True},
|
||||
"logits_all": {"display_name": "Logits All", "advanced": True},
|
||||
"logprobs": {"display_name": "Logprobs", "advanced": True},
|
||||
"lora_base": {"display_name": "Lora Base", "advanced": True},
|
||||
"lora_path": {"display_name": "Lora Path", "advanced": True},
|
||||
"max_tokens": {"display_name": "Max Tokens", "advanced": True},
|
||||
"metadata": {"display_name": "Metadata", "advanced": True},
|
||||
"model_kwargs": {"display_name": "Model Kwargs", "advanced": True},
|
||||
"model_path": {
|
||||
"display_name": "Model Path",
|
||||
"field_type": "file",
|
||||
"file_types": [".bin"],
|
||||
"required": True,
|
||||
},
|
||||
"n_batch": {"display_name": "N Batch", "advanced": True},
|
||||
"n_ctx": {"display_name": "N Ctx", "advanced": True},
|
||||
"n_gpu_layers": {"display_name": "N GPU Layers", "advanced": True},
|
||||
"n_parts": {"display_name": "N Parts", "advanced": True},
|
||||
"n_threads": {"display_name": "N Threads", "advanced": True},
|
||||
"repeat_penalty": {"display_name": "Repeat Penalty", "advanced": True},
|
||||
"rope_freq_base": {"display_name": "Rope Freq Base", "advanced": True},
|
||||
"rope_freq_scale": {"display_name": "Rope Freq Scale", "advanced": True},
|
||||
"seed": {"display_name": "Seed", "advanced": True},
|
||||
"stop": {"display_name": "Stop", "advanced": True},
|
||||
"streaming": {"display_name": "Streaming", "advanced": True},
|
||||
"suffix": {"display_name": "Suffix", "advanced": True},
|
||||
"tags": {"display_name": "Tags", "advanced": True},
|
||||
"temperature": {"display_name": "Temperature"},
|
||||
"top_k": {"display_name": "Top K", "advanced": True},
|
||||
"top_p": {"display_name": "Top P", "advanced": True},
|
||||
"use_mlock": {"display_name": "Use Mlock", "advanced": True},
|
||||
"use_mmap": {"display_name": "Use Mmap", "advanced": True},
|
||||
"verbose": {"display_name": "Verbose", "advanced": True},
|
||||
"vocab_only": {"display_name": "Vocab Only", "advanced": True},
|
||||
}
|
||||
|
||||
def build(
|
||||
self,
|
||||
model_path: str,
|
||||
grammar: Optional[str] = None,
|
||||
cache: Optional[bool] = None,
|
||||
client: Optional[Any] = None,
|
||||
echo: Optional[bool] = False,
|
||||
f16_kv: bool = True,
|
||||
grammar_path: Optional[str] = None,
|
||||
last_n_tokens_size: Optional[int] = 64,
|
||||
logits_all: bool = False,
|
||||
logprobs: Optional[int] = None,
|
||||
lora_base: Optional[str] = None,
|
||||
lora_path: Optional[str] = None,
|
||||
max_tokens: Optional[int] = 256,
|
||||
metadata: Optional[Dict] = None,
|
||||
model_kwargs: Dict = {},
|
||||
n_batch: Optional[int] = 8,
|
||||
n_ctx: int = 512,
|
||||
n_gpu_layers: Optional[int] = 1,
|
||||
n_parts: int = -1,
|
||||
n_threads: Optional[int] = 1,
|
||||
repeat_penalty: Optional[float] = 1.1,
|
||||
rope_freq_base: float = 10000.0,
|
||||
rope_freq_scale: float = 1.0,
|
||||
seed: int = -1,
|
||||
stop: Optional[List[str]] = [],
|
||||
streaming: bool = True,
|
||||
suffix: Optional[str] = "",
|
||||
tags: Optional[List[str]] = [],
|
||||
temperature: Optional[float] = 0.8,
|
||||
top_k: Optional[int] = 40,
|
||||
top_p: Optional[float] = 0.95,
|
||||
use_mlock: bool = False,
|
||||
use_mmap: Optional[bool] = True,
|
||||
verbose: bool = True,
|
||||
vocab_only: bool = False,
|
||||
) -> LlamaCpp:
|
||||
return LlamaCpp(
|
||||
model_path=model_path,
|
||||
grammar=grammar,
|
||||
cache=cache,
|
||||
client=client,
|
||||
echo=echo,
|
||||
f16_kv=f16_kv,
|
||||
grammar_path=grammar_path,
|
||||
last_n_tokens_size=last_n_tokens_size,
|
||||
logits_all=logits_all,
|
||||
logprobs=logprobs,
|
||||
lora_base=lora_base,
|
||||
lora_path=lora_path,
|
||||
max_tokens=max_tokens,
|
||||
metadata=metadata,
|
||||
model_kwargs=model_kwargs,
|
||||
n_batch=n_batch,
|
||||
n_ctx=n_ctx,
|
||||
n_gpu_layers=n_gpu_layers,
|
||||
n_parts=n_parts,
|
||||
n_threads=n_threads,
|
||||
repeat_penalty=repeat_penalty,
|
||||
rope_freq_base=rope_freq_base,
|
||||
rope_freq_scale=rope_freq_scale,
|
||||
seed=seed,
|
||||
stop=stop,
|
||||
streaming=streaming,
|
||||
suffix=suffix,
|
||||
tags=tags,
|
||||
temperature=temperature,
|
||||
top_k=top_k,
|
||||
top_p=top_p,
|
||||
use_mlock=use_mlock,
|
||||
use_mmap=use_mmap,
|
||||
verbose=verbose,
|
||||
vocab_only=vocab_only,
|
||||
)
|
||||
|
|
@ -4,7 +4,6 @@ from .AnthropicSpecs import AnthropicComponent
|
|||
from .AzureChatOpenAISpecs import AzureChatOpenAISpecsComponent
|
||||
from .BaiduQianfanChatEndpointsSpecs import QianfanChatEndpointComponent
|
||||
from .BaiduQianfanLLMEndpointsSpecs import QianfanLLMEndpointComponent
|
||||
from .CTransformersSpecs import CTransformersComponent
|
||||
from .ChatAnthropicSpecs import ChatAnthropicComponent
|
||||
from .ChatLiteLLMSpecs import ChatLiteLLMComponent
|
||||
from .ChatOllamaEndpointSpecs import ChatOllamaComponent
|
||||
|
|
@ -13,7 +12,6 @@ from .ChatVertexAISpecs import ChatVertexAIComponent
|
|||
from .CohereSpecs import CohereComponent
|
||||
from .GoogleGenerativeAISpecs import GoogleGenerativeAIComponent
|
||||
from .HuggingFaceEndpointsSpecs import HuggingFaceEndpointsComponent
|
||||
from .LlamaCppSpecs import LlamaCppComponent
|
||||
from .OllamaLLMSpecs import OllamaLLM
|
||||
from .VertexAISpecs import VertexAIComponent
|
||||
|
||||
|
|
@ -24,7 +22,6 @@ __all__ = [
|
|||
"AzureChatOpenAISpecsComponent",
|
||||
"QianfanChatEndpointComponent",
|
||||
"QianfanLLMEndpointComponent",
|
||||
"CTransformersComponent",
|
||||
"ChatAnthropicComponent",
|
||||
"ChatLiteLLMComponent",
|
||||
"ChatOllamaComponent",
|
||||
|
|
@ -33,7 +30,6 @@ __all__ = [
|
|||
"CohereComponent",
|
||||
"GoogleGenerativeAIComponent",
|
||||
"HuggingFaceEndpointsComponent",
|
||||
"LlamaCppComponent",
|
||||
"OllamaLLM",
|
||||
"VertexAIComponent",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -10,31 +10,50 @@ class AmazonBedrockComponent(LCModelComponent):
|
|||
display_name: str = "Amazon Bedrock"
|
||||
description: str = "Generate text using LLM model from Amazon Bedrock."
|
||||
icon = "Amazon"
|
||||
field_order = [
|
||||
"model_id",
|
||||
"credentials_profile_name",
|
||||
"region_name",
|
||||
"model_kwargs",
|
||||
"endpoint_url",
|
||||
"cache",
|
||||
"stream",
|
||||
"input_value",
|
||||
"system_message",
|
||||
]
|
||||
|
||||
def build_config(self):
|
||||
return {
|
||||
"model_id": {
|
||||
"display_name": "Model Id",
|
||||
"options": [
|
||||
"ai21.j2-grande-instruct",
|
||||
"ai21.j2-jumbo-instruct",
|
||||
"ai21.j2-mid",
|
||||
"ai21.j2-mid-v1",
|
||||
"ai21.j2-ultra",
|
||||
"ai21.j2-ultra-v1",
|
||||
"anthropic.claude-instant-v1",
|
||||
"anthropic.claude-v1",
|
||||
"amazon.titan-text-express-v1",
|
||||
"amazon.titan-text-lite-v1",
|
||||
"amazon.titan-embed-text-v1",
|
||||
"amazon.titan-embed-image-v1",
|
||||
"amazon.titan-image-generator-v1",
|
||||
"anthropic.claude-v2",
|
||||
"anthropic.claude-v2:1",
|
||||
"anthropic.claude-3-sonnet-20240229-v1:0",
|
||||
"anthropic.claude-3-haiku-20240307-v1:0",
|
||||
"anthropic.claude-instant-v1",
|
||||
"ai21.j2-mid-v1",
|
||||
"ai21.j2-ultra-v1",
|
||||
"cohere.command-text-v14",
|
||||
"cohere.command-light-text-v14",
|
||||
"cohere.embed-english-v3",
|
||||
"cohere.embed-multilingual-v3",
|
||||
"meta.llama2-13b-chat-v1",
|
||||
"meta.llama2-70b-chat-v1",
|
||||
"mistral.mistral-7b-instruct-v0:2",
|
||||
"mistral.mixtral-8x7b-instruct-v0:1",
|
||||
],
|
||||
},
|
||||
"credentials_profile_name": {"display_name": "Credentials Profile Name"},
|
||||
"streaming": {"display_name": "Streaming", "field_type": "bool"},
|
||||
"endpoint_url": {"display_name": "Endpoint URL"},
|
||||
"region_name": {"display_name": "Region Name"},
|
||||
"model_kwargs": {"display_name": "Model Kwargs"},
|
||||
"cache": {"display_name": "Cache"},
|
||||
"code": {"advanced": True},
|
||||
"input_value": {"display_name": "Input"},
|
||||
"system_message": {"display_name": "System Message", "info": "System message to pass to the model."},
|
||||
"stream": {
|
||||
|
|
@ -52,7 +71,6 @@ class AmazonBedrockComponent(LCModelComponent):
|
|||
region_name: Optional[str] = None,
|
||||
model_kwargs: Optional[dict] = None,
|
||||
endpoint_url: Optional[str] = None,
|
||||
streaming: bool = False,
|
||||
cache: Optional[bool] = None,
|
||||
stream: bool = False,
|
||||
) -> Text:
|
||||
|
|
@ -63,7 +81,7 @@ class AmazonBedrockComponent(LCModelComponent):
|
|||
region_name=region_name,
|
||||
model_kwargs=model_kwargs,
|
||||
endpoint_url=endpoint_url,
|
||||
streaming=streaming,
|
||||
streaming=stream,
|
||||
cache=cache,
|
||||
) # type: ignore
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -17,15 +17,17 @@ class AnthropicLLM(LCModelComponent):
|
|||
"model": {
|
||||
"display_name": "Model Name",
|
||||
"options": [
|
||||
"claude-3-opus-20240229",
|
||||
"claude-3-sonnet-20240229",
|
||||
"claude-3-haiku-20240307",
|
||||
"claude-2.1",
|
||||
"claude-2.0",
|
||||
"claude-instant-1.2",
|
||||
"claude-instant-1",
|
||||
# Add more models as needed
|
||||
],
|
||||
"info": "https://python.langchain.com/docs/integrations/chat/anthropic",
|
||||
"required": True,
|
||||
"value": "claude-2.1",
|
||||
"value": "claude-3-opus-20240229",
|
||||
},
|
||||
"anthropic_api_key": {
|
||||
"display_name": "Anthropic API Key",
|
||||
|
|
@ -43,8 +45,8 @@ class AnthropicLLM(LCModelComponent):
|
|||
"field_type": "float",
|
||||
"value": 0.7,
|
||||
},
|
||||
"api_endpoint": {
|
||||
"display_name": "API Endpoint",
|
||||
"anthropic_api_url": {
|
||||
"display_name": "Anthropic API URL",
|
||||
"info": "Endpoint of the Anthropic API. Defaults to 'https://api.anthropic.com' if not specified.",
|
||||
},
|
||||
"code": {"show": False},
|
||||
|
|
@ -67,12 +69,12 @@ class AnthropicLLM(LCModelComponent):
|
|||
anthropic_api_key: Optional[str] = None,
|
||||
max_tokens: Optional[int] = None,
|
||||
temperature: Optional[float] = None,
|
||||
api_endpoint: Optional[str] = None,
|
||||
anthropic_api_url: Optional[str] = None,
|
||||
stream: bool = False,
|
||||
) -> Text:
|
||||
# Set default API endpoint if not provided
|
||||
if not api_endpoint:
|
||||
api_endpoint = "https://api.anthropic.com"
|
||||
if not anthropic_api_url:
|
||||
anthropic_api_url = "https://api.anthropic.com"
|
||||
|
||||
try:
|
||||
output = ChatAnthropic(
|
||||
|
|
@ -80,7 +82,7 @@ class AnthropicLLM(LCModelComponent):
|
|||
anthropic_api_key=(SecretStr(anthropic_api_key) if anthropic_api_key else None),
|
||||
max_tokens_to_sample=max_tokens, # type: ignore
|
||||
temperature=temperature,
|
||||
anthropic_api_url=api_endpoint,
|
||||
anthropic_api_url=anthropic_api_url,
|
||||
)
|
||||
except Exception as e:
|
||||
raise ValueError("Could not connect to Anthropic API.") from e
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from langflow.field_typing import Text
|
|||
|
||||
|
||||
class AzureChatOpenAIComponent(LCModelComponent):
|
||||
display_name: str = "AzureOpenAI"
|
||||
display_name: str = "Azure OpenAI"
|
||||
description: str = "Generate text using LLM model from Azure OpenAI."
|
||||
documentation: str = "https://python.langchain.com/docs/integrations/llms/azure_openai"
|
||||
beta = False
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from langflow.field_typing import Text
|
|||
|
||||
|
||||
class QianfanChatEndpointComponent(LCModelComponent):
|
||||
display_name: str = "QianfanChat"
|
||||
display_name: str = "Qianfan"
|
||||
description: str = (
|
||||
"Generate text using Baidu Qianfan chat models. Get more detail from "
|
||||
"https://python.langchain.com/docs/integrations/chat/baidu_qianfan_endpoint."
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
from typing import Dict, Optional
|
||||
|
||||
from langchain_community.llms.ctransformers import CTransformers
|
||||
|
||||
from langflow.base.models.model import LCModelComponent
|
||||
from langflow.field_typing import Text
|
||||
|
||||
|
||||
class CTransformersComponent(LCModelComponent):
|
||||
display_name = "CTransformers"
|
||||
description = "Generate text using CTransformers LLM models"
|
||||
documentation = "https://python.langchain.com/docs/modules/model_io/models/llms/integrations/ctransformers"
|
||||
|
||||
def build_config(self):
|
||||
return {
|
||||
"model": {"display_name": "Model", "required": True},
|
||||
"model_file": {
|
||||
"display_name": "Model File",
|
||||
"required": False,
|
||||
"field_type": "file",
|
||||
"file_types": [".bin"],
|
||||
},
|
||||
"model_type": {"display_name": "Model Type", "required": True},
|
||||
"config": {
|
||||
"display_name": "Config",
|
||||
"advanced": True,
|
||||
"required": False,
|
||||
"field_type": "dict",
|
||||
"value": '{"top_k":40,"top_p":0.95,"temperature":0.8,"repetition_penalty":1.1,"last_n_tokens":64,"seed":-1,"max_new_tokens":256,"stop":"","stream":"False","reset":"True","batch_size":8,"threads":-1,"context_length":-1,"gpu_layers":0}',
|
||||
},
|
||||
"input_value": {"display_name": "Input"},
|
||||
"stream": {
|
||||
"display_name": "Stream",
|
||||
"info": "Stream the response from the model.",
|
||||
},
|
||||
"system_message": {
|
||||
"display_name": "System Message",
|
||||
"info": "System message to pass to the model.",
|
||||
},
|
||||
}
|
||||
|
||||
def build(
|
||||
self,
|
||||
model: str,
|
||||
model_file: str,
|
||||
input_value: Text,
|
||||
model_type: str,
|
||||
stream: bool = False,
|
||||
config: Optional[Dict] = None,
|
||||
) -> Text:
|
||||
output = CTransformers(
|
||||
client=None,
|
||||
model=model,
|
||||
model_file=model_file,
|
||||
model_type=model_type,
|
||||
config=config, # noqa
|
||||
)
|
||||
|
||||
return self.get_result(runnable=output, stream=stream, input_value=input_value)
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from langchain_community.llms.llamacpp import LlamaCpp
|
||||
|
||||
from langflow.base.models.model import LCModelComponent
|
||||
from langflow.field_typing import Text
|
||||
|
||||
|
||||
class LlamaCppComponent(LCModelComponent):
|
||||
display_name = "LlamaCpp"
|
||||
description = "Generate text using llama.cpp model."
|
||||
documentation = "https://python.langchain.com/docs/modules/model_io/models/llms/integrations/llamacpp"
|
||||
|
||||
def build_config(self):
|
||||
return {
|
||||
"grammar": {"display_name": "Grammar", "advanced": True},
|
||||
"cache": {"display_name": "Cache", "advanced": True},
|
||||
"client": {"display_name": "Client", "advanced": True},
|
||||
"echo": {"display_name": "Echo", "advanced": True},
|
||||
"f16_kv": {"display_name": "F16 KV", "advanced": True},
|
||||
"grammar_path": {"display_name": "Grammar Path", "advanced": True},
|
||||
"last_n_tokens_size": {
|
||||
"display_name": "Last N Tokens Size",
|
||||
"advanced": True,
|
||||
},
|
||||
"logits_all": {"display_name": "Logits All", "advanced": True},
|
||||
"logprobs": {"display_name": "Logprobs", "advanced": True},
|
||||
"lora_base": {"display_name": "Lora Base", "advanced": True},
|
||||
"lora_path": {"display_name": "Lora Path", "advanced": True},
|
||||
"max_tokens": {"display_name": "Max Tokens", "advanced": True},
|
||||
"metadata": {"display_name": "Metadata", "advanced": True},
|
||||
"model_kwargs": {"display_name": "Model Kwargs", "advanced": True},
|
||||
"model_path": {
|
||||
"display_name": "Model Path",
|
||||
"field_type": "file",
|
||||
"file_types": [".bin"],
|
||||
"required": True,
|
||||
},
|
||||
"n_batch": {"display_name": "N Batch", "advanced": True},
|
||||
"n_ctx": {"display_name": "N Ctx", "advanced": True},
|
||||
"n_gpu_layers": {"display_name": "N GPU Layers", "advanced": True},
|
||||
"n_parts": {"display_name": "N Parts", "advanced": True},
|
||||
"n_threads": {"display_name": "N Threads", "advanced": True},
|
||||
"repeat_penalty": {"display_name": "Repeat Penalty", "advanced": True},
|
||||
"rope_freq_base": {"display_name": "Rope Freq Base", "advanced": True},
|
||||
"rope_freq_scale": {"display_name": "Rope Freq Scale", "advanced": True},
|
||||
"seed": {"display_name": "Seed", "advanced": True},
|
||||
"stop": {"display_name": "Stop", "advanced": True},
|
||||
"streaming": {"display_name": "Streaming", "advanced": True},
|
||||
"suffix": {"display_name": "Suffix", "advanced": True},
|
||||
"tags": {"display_name": "Tags", "advanced": True},
|
||||
"temperature": {"display_name": "Temperature"},
|
||||
"top_k": {"display_name": "Top K", "advanced": True},
|
||||
"top_p": {"display_name": "Top P", "advanced": True},
|
||||
"use_mlock": {"display_name": "Use Mlock", "advanced": True},
|
||||
"use_mmap": {"display_name": "Use Mmap", "advanced": True},
|
||||
"verbose": {"display_name": "Verbose", "advanced": True},
|
||||
"vocab_only": {"display_name": "Vocab Only", "advanced": True},
|
||||
"input_value": {"display_name": "Input"},
|
||||
"stream": {
|
||||
"display_name": "Stream",
|
||||
"info": "Stream the response from the model.",
|
||||
},
|
||||
"system_message": {
|
||||
"display_name": "System Message",
|
||||
"info": "System message to pass to the model.",
|
||||
},
|
||||
}
|
||||
|
||||
def build(
|
||||
self,
|
||||
model_path: str,
|
||||
input_value: Text,
|
||||
grammar: Optional[str] = None,
|
||||
cache: Optional[bool] = None,
|
||||
client: Optional[Any] = None,
|
||||
echo: Optional[bool] = False,
|
||||
f16_kv: bool = True,
|
||||
grammar_path: Optional[str] = None,
|
||||
last_n_tokens_size: Optional[int] = 64,
|
||||
logits_all: bool = False,
|
||||
logprobs: Optional[int] = None,
|
||||
lora_base: Optional[str] = None,
|
||||
lora_path: Optional[str] = None,
|
||||
max_tokens: Optional[int] = 256,
|
||||
metadata: Optional[Dict] = None,
|
||||
model_kwargs: Dict = {},
|
||||
n_batch: Optional[int] = 8,
|
||||
n_ctx: int = 512,
|
||||
n_gpu_layers: Optional[int] = 1,
|
||||
n_parts: int = -1,
|
||||
n_threads: Optional[int] = 1,
|
||||
repeat_penalty: Optional[float] = 1.1,
|
||||
rope_freq_base: float = 10000.0,
|
||||
rope_freq_scale: float = 1.0,
|
||||
seed: int = -1,
|
||||
stop: Optional[List[str]] = [],
|
||||
streaming: bool = True,
|
||||
suffix: Optional[str] = "",
|
||||
tags: Optional[List[str]] = [],
|
||||
temperature: Optional[float] = 0.8,
|
||||
top_k: Optional[int] = 40,
|
||||
top_p: Optional[float] = 0.95,
|
||||
use_mlock: bool = False,
|
||||
use_mmap: Optional[bool] = True,
|
||||
verbose: bool = True,
|
||||
vocab_only: bool = False,
|
||||
stream: bool = False,
|
||||
) -> Text:
|
||||
output = LlamaCpp(
|
||||
model_path=model_path,
|
||||
grammar=grammar,
|
||||
cache=cache,
|
||||
client=client,
|
||||
echo=echo,
|
||||
f16_kv=f16_kv,
|
||||
grammar_path=grammar_path,
|
||||
last_n_tokens_size=last_n_tokens_size,
|
||||
logits_all=logits_all,
|
||||
logprobs=logprobs,
|
||||
lora_base=lora_base,
|
||||
lora_path=lora_path,
|
||||
max_tokens=max_tokens,
|
||||
metadata=metadata,
|
||||
model_kwargs=model_kwargs,
|
||||
n_batch=n_batch,
|
||||
n_ctx=n_ctx,
|
||||
n_gpu_layers=n_gpu_layers,
|
||||
n_parts=n_parts,
|
||||
n_threads=n_threads,
|
||||
repeat_penalty=repeat_penalty,
|
||||
rope_freq_base=rope_freq_base,
|
||||
rope_freq_scale=rope_freq_scale,
|
||||
seed=seed,
|
||||
stop=stop,
|
||||
streaming=streaming,
|
||||
suffix=suffix,
|
||||
tags=tags,
|
||||
temperature=temperature,
|
||||
top_k=top_k,
|
||||
top_p=top_p,
|
||||
use_mlock=use_mlock,
|
||||
use_mmap=use_mmap,
|
||||
verbose=verbose,
|
||||
vocab_only=vocab_only,
|
||||
)
|
||||
|
||||
return self.get_result(runnable=output, stream=stream, input_value=input_value)
|
||||
|
|
@ -13,7 +13,7 @@ from langflow.field_typing import Text
|
|||
|
||||
|
||||
class ChatOllamaComponent(LCModelComponent):
|
||||
display_name = "ChatOllama"
|
||||
display_name = "Ollama"
|
||||
description = "Generate text using Local LLM for chat with Ollama."
|
||||
icon = "Ollama"
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from langflow.field_typing import Text
|
|||
|
||||
|
||||
class ChatVertexAIComponent(LCModelComponent):
|
||||
display_name = "ChatVertexAI"
|
||||
display_name = "Vertex AI"
|
||||
description = "Generate text using Vertex AI Chat large language models API."
|
||||
icon = "VertexAI"
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,9 @@ from .AmazonBedrockModel import AmazonBedrockComponent
|
|||
from .AnthropicModel import AnthropicLLM
|
||||
from .AzureOpenAIModel import AzureChatOpenAIComponent
|
||||
from .BaiduQianfanChatModel import QianfanChatEndpointComponent
|
||||
from .CTransformersModel import CTransformersComponent
|
||||
from .CohereModel import CohereComponent
|
||||
from .GoogleGenerativeAIModel import GoogleGenerativeAIComponent
|
||||
from .HuggingFaceModel import HuggingFaceEndpointsComponent
|
||||
from .LlamaCppModel import LlamaCppComponent
|
||||
from .OllamaModel import ChatOllamaComponent
|
||||
from .OpenAIModel import OpenAIModelComponent
|
||||
from .VertexAiModel import ChatVertexAIComponent
|
||||
|
|
@ -16,11 +14,9 @@ __all__ = [
|
|||
"AnthropicLLM",
|
||||
"AzureChatOpenAIComponent",
|
||||
"QianfanChatEndpointComponent",
|
||||
"CTransformersComponent",
|
||||
"CohereComponent",
|
||||
"GoogleGenerativeAIComponent",
|
||||
"HuggingFaceEndpointsComponent",
|
||||
"LlamaCppComponent",
|
||||
"ChatOllamaComponent",
|
||||
"OpenAIModelComponent",
|
||||
"ChatVertexAIComponent",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from langflow.schema import Record
|
|||
|
||||
class ChatOutput(ChatComponent):
|
||||
display_name = "Chat Output"
|
||||
description = "Used to send a message to the chat."
|
||||
description = "Used to send a chat message."
|
||||
icon = "ChatOutput"
|
||||
|
||||
def build(
|
||||
|
|
@ -17,6 +17,7 @@ class ChatOutput(ChatComponent):
|
|||
input_value: Optional[str] = None,
|
||||
session_id: Optional[str] = None,
|
||||
return_record: Optional[bool] = False,
|
||||
record_template: Optional[str] = "{text}",
|
||||
) -> Union[Text, Record]:
|
||||
return super().build(
|
||||
sender=sender,
|
||||
|
|
@ -24,4 +25,5 @@ class ChatOutput(ChatComponent):
|
|||
input_value=input_value,
|
||||
session_id=session_id,
|
||||
return_record=return_record,
|
||||
record_template=record_template,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,11 +6,17 @@ from langflow.field_typing import Text
|
|||
|
||||
class TextOutput(TextComponent):
|
||||
display_name = "Text Output"
|
||||
description = "Used to pass text output to the next component."
|
||||
description = "Used to send a text output."
|
||||
|
||||
field_config = {
|
||||
"input_value": {"display_name": "Value"},
|
||||
}
|
||||
def build_config(self):
|
||||
return {
|
||||
"input_value": {
|
||||
"display_name": "Value",
|
||||
"input_types": ["Record"],
|
||||
"info": "Text or Record to be passed as output.",
|
||||
},
|
||||
"record_template": {"display_name": "Record Template", "multiline": True},
|
||||
}
|
||||
|
||||
def build(self, input_value: Optional[Text] = "") -> Text:
|
||||
return super().build(input_value=input_value)
|
||||
def build(self, input_value: Optional[Text] = "", record_template: str = "{text}") -> Text:
|
||||
return super().build(input_value=input_value, record_template=record_template)
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ from .AmazonKendra import AmazonKendraRetrieverComponent
|
|||
from .MetalRetriever import MetalRetrieverComponent
|
||||
from .MultiQueryRetriever import MultiQueryRetrieverComponent
|
||||
from .VectaraSelfQueryRetriver import VectaraSelfQueryRetriverComponent
|
||||
from .VectorStoreRetriever import VectoStoreRetrieverComponent
|
||||
|
||||
__all__ = [
|
||||
"AmazonKendraRetrieverComponent",
|
||||
"MetalRetrieverComponent",
|
||||
"MultiQueryRetrieverComponent",
|
||||
"VectaraSelfQueryRetriverComponent",
|
||||
"VectoStoreRetrieverComponent",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
from .RetrieverTool import RetrieverToolComponent
|
||||
from .SearchAPITool import SearchApiToolComponent
|
||||
from .SearchApi import SearchApi
|
||||
|
||||
__all__ = ["RetrieverToolComponent", "SearchApiToolComponent", "SearchApi"]
|
||||
|
|
@ -23,51 +23,73 @@ class AstraDBSearchComponent(LCVectorStoreComponent):
|
|||
"info": "Input value to search",
|
||||
},
|
||||
"embedding": {"display_name": "Embedding", "info": "Embedding to use"},
|
||||
"collection_name": {"display_name": "Collection Name", "info": "Collection name"},
|
||||
"token": {"display_name": "Token", "info": "Token to use", "password": True},
|
||||
"api_endpoint": {"display_name": "API Endpoint", "info": "API Endpoint to use"},
|
||||
"namespace": {"display_name": "Namespace", "info": "Namespace to use", "advanced": True},
|
||||
"metric": {"display_name": "Metric", "info": "Metric to use", "advanced": True},
|
||||
"batch_size": {"display_name": "Batch Size", "info": "Batch size to use", "advanced": True},
|
||||
"collection_name": {
|
||||
"display_name": "Collection Name",
|
||||
"info": "The name of the collection within AstraDB where the vectors will be stored.",
|
||||
},
|
||||
"token": {
|
||||
"display_name": "Token",
|
||||
"info": "Authentication token for accessing AstraDB.",
|
||||
"password": True,
|
||||
},
|
||||
"api_endpoint": {
|
||||
"display_name": "API Endpoint",
|
||||
"info": "API endpoint URL for the AstraDB service.",
|
||||
},
|
||||
"namespace": {
|
||||
"display_name": "Namespace",
|
||||
"info": "Optional namespace within AstraDB to use for the collection.",
|
||||
"advanced": True,
|
||||
},
|
||||
"metric": {
|
||||
"display_name": "Metric",
|
||||
"info": "Optional distance metric for vector comparisons in the vector store.",
|
||||
"advanced": True,
|
||||
},
|
||||
"batch_size": {
|
||||
"display_name": "Batch Size",
|
||||
"info": "Optional number of records to process in a single batch.",
|
||||
"advanced": True,
|
||||
},
|
||||
"bulk_insert_batch_concurrency": {
|
||||
"display_name": "Bulk Insert Batch Concurrency",
|
||||
"info": "Bulk Insert Batch Concurrency to use",
|
||||
"info": "Optional concurrency level for bulk insert operations.",
|
||||
"advanced": True,
|
||||
},
|
||||
"bulk_insert_overwrite_concurrency": {
|
||||
"display_name": "Bulk Insert Overwrite Concurrency",
|
||||
"info": "Bulk Insert Overwrite Concurrency to use",
|
||||
"info": "Optional concurrency level for bulk insert operations that overwrite existing records.",
|
||||
"advanced": True,
|
||||
},
|
||||
"bulk_delete_concurrency": {
|
||||
"display_name": "Bulk Delete Concurrency",
|
||||
"info": "Bulk Delete Concurrency to use",
|
||||
"info": "Optional concurrency level for bulk delete operations.",
|
||||
"advanced": True,
|
||||
},
|
||||
"setup_mode": {
|
||||
"display_name": "Setup Mode",
|
||||
"info": "Setup mode for the vector store",
|
||||
"info": "Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.",
|
||||
"options": ["Sync", "Async", "Off"],
|
||||
"advanced": True,
|
||||
},
|
||||
"pre_delete_collection": {
|
||||
"display_name": "Pre Delete Collection",
|
||||
"info": "Pre delete collection",
|
||||
"info": "Boolean flag to determine whether to delete the collection before creating a new one.",
|
||||
"advanced": True,
|
||||
},
|
||||
"metadata_indexing_include": {
|
||||
"display_name": "Metadata Indexing Include",
|
||||
"info": "Metadata Indexing Include",
|
||||
"info": "Optional list of metadata fields to include in the indexing.",
|
||||
"advanced": True,
|
||||
},
|
||||
"metadata_indexing_exclude": {
|
||||
"display_name": "Metadata Indexing Exclude",
|
||||
"info": "Metadata Indexing Exclude",
|
||||
"info": "Optional list of metadata fields to exclude from the indexing.",
|
||||
"advanced": True,
|
||||
},
|
||||
"collection_indexing_policy": {
|
||||
"display_name": "Collection Indexing Policy",
|
||||
"info": "Collection Indexing Policy",
|
||||
"info": "Optional dictionary defining the indexing policy for the collection.",
|
||||
"advanced": True,
|
||||
},
|
||||
}
|
||||
|
|
@ -77,9 +99,9 @@ class AstraDBSearchComponent(LCVectorStoreComponent):
|
|||
embedding: Embeddings,
|
||||
collection_name: str,
|
||||
input_value: Text,
|
||||
token: str,
|
||||
api_endpoint: str,
|
||||
search_type: str = "Similarity",
|
||||
token: Optional[str] = None,
|
||||
api_endpoint: Optional[str] = None,
|
||||
namespace: Optional[str] = None,
|
||||
metric: Optional[str] = None,
|
||||
batch_size: Optional[int] = None,
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
from .AstraDBSearch import AstraDBSearchComponent
|
||||
from .ChromaSearch import ChromaSearchComponent
|
||||
from .FAISSSearch import FAISSSearchComponent
|
||||
from .MongoDBAtlasVectorSearch import MongoDBAtlasSearchComponent
|
||||
from .PineconeSearch import PineconeSearchComponent
|
||||
from .QdrantSearch import QdrantSearchComponent
|
||||
from .RedisSearch import RedisSearchComponent
|
||||
from .SupabaseVectorStoreSearch import SupabaseSearchComponent
|
||||
from .VectaraSearch import VectaraSearchComponent
|
||||
from .WeaviateSearch import WeaviateSearchVectorStore
|
||||
from .pgvectorSearch import PGVectorSearchComponent
|
||||
|
||||
__all__ = [
|
||||
"AstraDBSearchComponent",
|
||||
"ChromaSearchComponent",
|
||||
"FAISSSearchComponent",
|
||||
"MongoDBAtlasSearchComponent",
|
||||
"PineconeSearchComponent",
|
||||
"QdrantSearchComponent",
|
||||
"RedisSearchComponent",
|
||||
"SupabaseSearchComponent",
|
||||
"VectaraSearchComponent",
|
||||
"WeaviateSearchVectorStore",
|
||||
"PGVectorSearchComponent",
|
||||
]
|
||||
|
|
@ -16,53 +16,78 @@ class AstraDBVectorStoreComponent(CustomComponent):
|
|||
|
||||
def build_config(self):
|
||||
return {
|
||||
"inputs": {"display_name": "Inputs", "info": "Inputs to AstraDB"},
|
||||
"inputs": {
|
||||
"display_name": "Inputs",
|
||||
"info": "Optional list of records to be processed and stored in the vector store.",
|
||||
},
|
||||
"embedding": {"display_name": "Embedding", "info": "Embedding to use"},
|
||||
"collection_name": {"display_name": "Collection Name", "info": "Collection name"},
|
||||
"token": {"display_name": "Token", "info": "Token to use", "password": True},
|
||||
"api_endpoint": {"display_name": "API Endpoint", "info": "API Endpoint to use"},
|
||||
"namespace": {"display_name": "Namespace", "info": "Namespace to use", "advanced": True},
|
||||
"metric": {"display_name": "Metric", "info": "Metric to use", "advanced": True},
|
||||
"batch_size": {"display_name": "Batch Size", "info": "Batch size to use", "advanced": True},
|
||||
"collection_name": {
|
||||
"display_name": "Collection Name",
|
||||
"info": "The name of the collection within AstraDB where the vectors will be stored.",
|
||||
},
|
||||
"token": {
|
||||
"display_name": "Token",
|
||||
"info": "Authentication token for accessing AstraDB.",
|
||||
"password": True,
|
||||
},
|
||||
"api_endpoint": {
|
||||
"display_name": "API Endpoint",
|
||||
"info": "API endpoint URL for the AstraDB service.",
|
||||
},
|
||||
"namespace": {
|
||||
"display_name": "Namespace",
|
||||
"info": "Optional namespace within AstraDB to use for the collection.",
|
||||
"advanced": True,
|
||||
},
|
||||
"metric": {
|
||||
"display_name": "Metric",
|
||||
"info": "Optional distance metric for vector comparisons in the vector store.",
|
||||
"advanced": True,
|
||||
},
|
||||
"batch_size": {
|
||||
"display_name": "Batch Size",
|
||||
"info": "Optional number of records to process in a single batch.",
|
||||
"advanced": True,
|
||||
},
|
||||
"bulk_insert_batch_concurrency": {
|
||||
"display_name": "Bulk Insert Batch Concurrency",
|
||||
"info": "Bulk Insert Batch Concurrency to use",
|
||||
"info": "Optional concurrency level for bulk insert operations.",
|
||||
"advanced": True,
|
||||
},
|
||||
"bulk_insert_overwrite_concurrency": {
|
||||
"display_name": "Bulk Insert Overwrite Concurrency",
|
||||
"info": "Bulk Insert Overwrite Concurrency to use",
|
||||
"info": "Optional concurrency level for bulk insert operations that overwrite existing records.",
|
||||
"advanced": True,
|
||||
},
|
||||
"bulk_delete_concurrency": {
|
||||
"display_name": "Bulk Delete Concurrency",
|
||||
"info": "Bulk Delete Concurrency to use",
|
||||
"info": "Optional concurrency level for bulk delete operations.",
|
||||
"advanced": True,
|
||||
},
|
||||
"setup_mode": {
|
||||
"display_name": "Setup Mode",
|
||||
"info": "Setup mode for the vector store",
|
||||
"info": "Configuration mode for setting up the vector store, with options like “Sync”, “Async”, or “Off”.",
|
||||
"options": ["Sync", "Async", "Off"],
|
||||
"advanced": True,
|
||||
},
|
||||
"pre_delete_collection": {
|
||||
"display_name": "Pre Delete Collection",
|
||||
"info": "Pre delete collection",
|
||||
"info": "Boolean flag to determine whether to delete the collection before creating a new one.",
|
||||
"advanced": True,
|
||||
},
|
||||
"metadata_indexing_include": {
|
||||
"display_name": "Metadata Indexing Include",
|
||||
"info": "Metadata Indexing Include",
|
||||
"info": "Optional list of metadata fields to include in the indexing.",
|
||||
"advanced": True,
|
||||
},
|
||||
"metadata_indexing_exclude": {
|
||||
"display_name": "Metadata Indexing Exclude",
|
||||
"info": "Metadata Indexing Exclude",
|
||||
"info": "Optional list of metadata fields to exclude from the indexing.",
|
||||
"advanced": True,
|
||||
},
|
||||
"collection_indexing_policy": {
|
||||
"display_name": "Collection Indexing Policy",
|
||||
"info": "Collection Indexing Policy",
|
||||
"info": "Optional dictionary defining the indexing policy for the collection.",
|
||||
"advanced": True,
|
||||
},
|
||||
}
|
||||
|
|
@ -70,17 +95,17 @@ class AstraDBVectorStoreComponent(CustomComponent):
|
|||
def build(
|
||||
self,
|
||||
embedding: Embeddings,
|
||||
token: str,
|
||||
api_endpoint: str,
|
||||
collection_name: str,
|
||||
inputs: Optional[List[Record]] = None,
|
||||
token: Optional[str] = None,
|
||||
api_endpoint: Optional[str] = None,
|
||||
namespace: Optional[str] = None,
|
||||
metric: Optional[str] = None,
|
||||
batch_size: Optional[int] = None,
|
||||
bulk_insert_batch_concurrency: Optional[int] = None,
|
||||
bulk_insert_overwrite_concurrency: Optional[int] = None,
|
||||
bulk_delete_concurrency: Optional[int] = None,
|
||||
setup_mode: str = "Sync",
|
||||
setup_mode: str = "Async",
|
||||
pre_delete_collection: bool = False,
|
||||
metadata_indexing_include: Optional[List[str]] = None,
|
||||
metadata_indexing_exclude: Optional[List[str]] = None,
|
||||
|
|
|
|||
|
|
@ -1,44 +1,26 @@
|
|||
from .AstraDB import AstraDBVectorStoreComponent
|
||||
from .Chroma import ChromaComponent
|
||||
from .ChromaSearch import ChromaSearchComponent
|
||||
from .FAISS import FAISSComponent
|
||||
from .FAISSSearch import FAISSSearchComponent
|
||||
from .MongoDBAtlasVector import MongoDBAtlasComponent
|
||||
from .MongoDBAtlasVectorSearch import MongoDBAtlasSearchComponent
|
||||
from .Pinecone import PineconeComponent
|
||||
from .PineconeSearch import PineconeSearchComponent
|
||||
from .Qdrant import QdrantComponent
|
||||
from .QdrantSearch import QdrantSearchComponent
|
||||
from .Redis import RedisComponent
|
||||
from .RedisSearch import RedisSearchComponent
|
||||
from .SupabaseVectorStore import SupabaseComponent
|
||||
from .SupabaseVectorStoreSearch import SupabaseSearchComponent
|
||||
from .Vectara import VectaraComponent
|
||||
from .VectaraSearch import VectaraSearchComponent
|
||||
from .Weaviate import WeaviateVectorStoreComponent
|
||||
from .WeaviateSearch import WeaviateSearchVectorStore
|
||||
from .pgvector import PGVectorComponent
|
||||
from .pgvectorSearch import PGVectorSearchComponent
|
||||
|
||||
__all__ = [
|
||||
"AstraDBVectorStoreComponent",
|
||||
"ChromaComponent",
|
||||
"ChromaSearchComponent",
|
||||
"FAISSComponent",
|
||||
"FAISSSearchComponent",
|
||||
"MongoDBAtlasComponent",
|
||||
"MongoDBAtlasSearchComponent",
|
||||
"PineconeComponent",
|
||||
"PineconeSearchComponent",
|
||||
"QdrantComponent",
|
||||
"QdrantSearchComponent",
|
||||
"RedisComponent",
|
||||
"RedisSearchComponent",
|
||||
"SupabaseComponent",
|
||||
"SupabaseSearchComponent",
|
||||
"VectaraComponent",
|
||||
"VectaraSearchComponent",
|
||||
"WeaviateVectorStoreComponent",
|
||||
"WeaviateSearchVectorStore",
|
||||
"base",
|
||||
"PGVectorComponent",
|
||||
"PGVectorSearchComponent",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -237,10 +237,28 @@ class CodeParser:
|
|||
|
||||
def parse_return_statement(self, node: ast.FunctionDef) -> bool:
|
||||
"""
|
||||
Parses the return statement of a function or method node.
|
||||
Parses the return statement of a function or method node, including nested returns.
|
||||
"""
|
||||
|
||||
return any(isinstance(n, ast.Return) for n in node.body)
|
||||
def has_return(node):
|
||||
if isinstance(node, ast.Return):
|
||||
return True
|
||||
elif isinstance(node, ast.If):
|
||||
return any(has_return(child) for child in node.body) or any(has_return(child) for child in node.orelse)
|
||||
elif isinstance(node, ast.Try):
|
||||
return (
|
||||
any(has_return(child) for child in node.body)
|
||||
or any(has_return(child) for child in node.handlers)
|
||||
or any(has_return(child) for child in node.finalbody)
|
||||
)
|
||||
elif isinstance(node, (ast.For, ast.While)):
|
||||
return any(has_return(child) for child in node.body) or any(has_return(child) for child in node.orelse)
|
||||
elif isinstance(node, ast.With):
|
||||
return any(has_return(child) for child in node.body)
|
||||
else:
|
||||
return False
|
||||
|
||||
return any(has_return(child) for child in node.body)
|
||||
|
||||
def parse_assign(self, stmt):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ def check_tools_in_params(params: Dict):
|
|||
|
||||
def instantiate_from_template(class_object, params: Dict):
|
||||
from_template_params = {"template": params.pop("prompt", params.pop("template", ""))}
|
||||
|
||||
from_template_params.update(params)
|
||||
if not from_template_params.get("template"):
|
||||
raise ValueError("Prompt template is required")
|
||||
return class_object.from_template(**from_template_params)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from loguru import logger
|
|||
|
||||
from langflow.interface.base import LangChainTypeCreator
|
||||
from langflow.interface.custom_lists import llm_type_to_cls_dict
|
||||
from langflow.services.deps import get_settings_service
|
||||
from langflow.template.frontend_node.llms import LLMFrontendNode
|
||||
from langflow.utils.util import build_template_from_class
|
||||
|
||||
|
|
@ -33,10 +34,11 @@ class LLMCreator(LangChainTypeCreator):
|
|||
return None
|
||||
|
||||
def to_list(self) -> List[str]:
|
||||
settings_service = get_settings_service()
|
||||
return [
|
||||
llm.__name__
|
||||
for llm in self.type_to_loader_dict.values()
|
||||
# if llm.__name__ in settings_service.settings.LLMS or settings_service.settings.DEV
|
||||
if llm.__name__ in settings_service.settings.LLMS or settings_service.settings.DEV
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from importlib import metadata
|
||||
|
||||
try:
|
||||
__version__ = metadata.version(__package__)
|
||||
__version__ = metadata.version("langflow")
|
||||
except metadata.PackageNotFoundError:
|
||||
__version__ = ""
|
||||
del metadata
|
||||
|
|
|
|||
8
src/frontend/package-lock.json
generated
8
src/frontend/package-lock.json
generated
|
|
@ -55,7 +55,7 @@
|
|||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^4.0.11",
|
||||
"react-icons": "^4.10.1",
|
||||
"react-icons": "^5.0.1",
|
||||
"react-laag": "^2.0.5",
|
||||
"react-markdown": "^8.0.7",
|
||||
"react-router-dom": "^6.15.0",
|
||||
|
|
@ -9363,9 +9363,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react-icons": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz",
|
||||
"integrity": "sha512-IBaDuHiShdZqmfc/TwHu6+d6k2ltNCf3AszxNmjJc1KUfXdEeRJOKyNvLmAHaarhzGmTSVygNdyu8/opXv2gaw==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.0.1.tgz",
|
||||
"integrity": "sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==",
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@
|
|||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^4.0.11",
|
||||
"react-icons": "^4.10.1",
|
||||
"react-icons": "^5.0.1",
|
||||
"react-laag": "^2.0.5",
|
||||
"react-markdown": "^8.0.7",
|
||||
"react-router-dom": "^6.15.0",
|
||||
|
|
|
|||
|
|
@ -211,10 +211,12 @@ export default function GenericNode({
|
|||
}
|
||||
}, [validationStatus, validationStatus?.params]);
|
||||
|
||||
// const showNode = data.showNode ?? true;
|
||||
|
||||
const [showNode, setShowNode] = useState(data.showNode ?? true);
|
||||
|
||||
useEffect(() => {
|
||||
setShowNode(data.showNode ?? true);
|
||||
}, [data.showNode]);
|
||||
|
||||
const nameEditable = true;
|
||||
|
||||
const emojiRegex = /\p{Emoji}/u;
|
||||
|
|
@ -438,7 +440,7 @@ export default function GenericNode({
|
|||
event.preventDefault();
|
||||
}}
|
||||
data-testid={"title-" + data.node?.display_name}
|
||||
className="generic-node-tooltip-div text-primary"
|
||||
className="generic-node-tooltip-div cursor-text text-primary"
|
||||
>
|
||||
{data.node?.display_name}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ export default function DropdownButton({
|
|||
firstButtonName,
|
||||
onFirstBtnClick,
|
||||
options,
|
||||
plusButton = false,
|
||||
dropdownOptions = true,
|
||||
}: dropdownButtonPropsType): JSX.Element {
|
||||
const [showOptions, setShowOptions] = useState<boolean>(false);
|
||||
|
||||
|
|
@ -23,28 +25,33 @@ export default function DropdownButton({
|
|||
<Button
|
||||
id="new-project-btn"
|
||||
variant="primary"
|
||||
className="relative pr-10"
|
||||
className={"relative" + dropdownOptions ? "" : " pr-10"}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
onFirstBtnClick();
|
||||
}}
|
||||
>
|
||||
{plusButton && (
|
||||
<IconComponent name="Plus" className="main-page-nav-button" />
|
||||
)}
|
||||
{firstButtonName}
|
||||
<div
|
||||
className="absolute right-2 items-center text-muted-foreground"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
setShowOptions(!showOptions);
|
||||
}}
|
||||
>
|
||||
{!showOptions ? (
|
||||
<IconComponent name="ChevronDown" />
|
||||
) : (
|
||||
<IconComponent name="ChevronUp" />
|
||||
)}
|
||||
</div>
|
||||
{dropdownOptions && (
|
||||
<div
|
||||
className="absolute right-2 items-center text-muted-foreground"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
setShowOptions(!showOptions);
|
||||
}}
|
||||
>
|
||||
{!showOptions ? (
|
||||
<IconComponent name="ChevronDown" />
|
||||
) : (
|
||||
<IconComponent name="ChevronUp" />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ export default function IOView({
|
|||
{/* TODO ADAPT TO ALL TYPES OF INPUTS AND OUTPUTS */}
|
||||
<BaseModal.Header description={CHAT_FORM_DIALOG_SUBTITLE}>
|
||||
<div className="flex items-center">
|
||||
<span className="pr-2">Chat</span>
|
||||
<span className="pr-2">Interaction Panel</span>
|
||||
<IconComponent
|
||||
name="prompts"
|
||||
className="h-6 w-6 pl-1 text-foreground"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { useContext, useEffect } from "react";
|
||||
import { FaDiscord, FaGithub, FaTwitter } from "react-icons/fa";
|
||||
import { FaDiscord, FaGithub } from "react-icons/fa";
|
||||
import { RiTwitterXFill } from "react-icons/ri";
|
||||
import { Link, useLocation, useNavigate, useParams } from "react-router-dom";
|
||||
import AlertDropdown from "../../alerts/alertDropDown";
|
||||
import { USER_PROJECTS_HEADER } from "../../constants/constants";
|
||||
|
|
@ -127,7 +128,7 @@ export default function Header(): JSX.Element {
|
|||
rel="noreferrer"
|
||||
className="text-muted-foreground"
|
||||
>
|
||||
<FaTwitter className="side-bar-button-size" />
|
||||
<RiTwitterXFill className="side-bar-button-size" />
|
||||
</a>
|
||||
<a
|
||||
href="https://discord.gg/EqksyE2EX9"
|
||||
|
|
|
|||
|
|
@ -99,12 +99,16 @@ export default function InputComponent({
|
|||
type="text"
|
||||
onBlur={onInputLostFocus}
|
||||
value={
|
||||
selectedOption !== "" || !onChange ? selectedOption : value
|
||||
(selectedOption !== "" || !onChange) && setSelectedOption
|
||||
? selectedOption
|
||||
: value
|
||||
}
|
||||
autoFocus={autoFocus}
|
||||
disabled={disabled}
|
||||
onClick={() => {
|
||||
(selectedOption !== "" || !onChange) && setShowOptions(true);
|
||||
(selectedOption !== "" || !onChange) &&
|
||||
setSelectedOption &&
|
||||
setShowOptions(true);
|
||||
}}
|
||||
required={required}
|
||||
className={classNames(
|
||||
|
|
@ -115,8 +119,12 @@ export default function InputComponent({
|
|||
? " text-clip password "
|
||||
: "",
|
||||
editNode ? " input-edit-node " : "",
|
||||
password && selectedOption === "" && editNode ? "pr-8" : "",
|
||||
password && selectedOption === "" && !editNode ? "pr-10" : "",
|
||||
password && setSelectedOption ? "pr-16" : "",
|
||||
(!password && setSelectedOption) ||
|
||||
(password && !setSelectedOption)
|
||||
? "pr-8"
|
||||
: "",
|
||||
|
||||
className!
|
||||
)}
|
||||
placeholder={password && editNode ? "Key" : placeholder}
|
||||
|
|
@ -179,18 +187,32 @@ export default function InputComponent({
|
|||
setShowOptions(false);
|
||||
}}
|
||||
>
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<div className="group flex w-full items-center justify-between">
|
||||
<div className="flex items-center">
|
||||
<ForwardedIconComponent
|
||||
name="Check"
|
||||
<div
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4 text-primary",
|
||||
"relative mr-2 h-4 w-4",
|
||||
selectedOption === option
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
>
|
||||
<div className="absolute opacity-100 transition-all group-hover:opacity-0">
|
||||
<ForwardedIconComponent
|
||||
name="Check"
|
||||
className="mr-2 h-4 w-4 text-primary"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<div className="absolute opacity-0 transition-all group-hover:opacity-100">
|
||||
<ForwardedIconComponent
|
||||
name="X"
|
||||
className="mr-2 h-4 w-4 text-status-red"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{option}
|
||||
</div>
|
||||
{optionButton && optionButton(option)}
|
||||
|
|
@ -206,10 +228,12 @@ export default function InputComponent({
|
|||
<div
|
||||
className={cn(
|
||||
"pointer-events-auto absolute inset-y-0 h-full w-full cursor-pointer",
|
||||
selectedOption !== "" || !onChange ? "" : "hidden"
|
||||
(selectedOption !== "" || !onChange) && setSelectedOption
|
||||
? ""
|
||||
: "hidden"
|
||||
)}
|
||||
onClick={
|
||||
selectedOption !== "" || !onChange
|
||||
(selectedOption !== "" || !onChange) && setSelectedOption
|
||||
? (e) => {
|
||||
setShowOptions((old) => !old);
|
||||
e.preventDefault();
|
||||
|
|
@ -221,30 +245,32 @@ export default function InputComponent({
|
|||
</>
|
||||
)}
|
||||
|
||||
<span
|
||||
className={cn(
|
||||
password && selectedOption === "" ? "right-8" : "right-0",
|
||||
"absolute inset-y-0 flex items-center pr-2.5"
|
||||
)}
|
||||
>
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowOptions(!showOptions);
|
||||
}}
|
||||
{setSelectedOption && (
|
||||
<span
|
||||
className={cn(
|
||||
selectedOption !== ""
|
||||
? "text-medium-indigo"
|
||||
: "text-muted-foreground",
|
||||
"hover:text-accent-foreground"
|
||||
password && selectedOption === "" ? "right-8" : "right-0",
|
||||
"absolute inset-y-0 flex items-center pr-2.5"
|
||||
)}
|
||||
>
|
||||
<ForwardedIconComponent
|
||||
name={optionsIcon}
|
||||
className={"h-4 w-4"}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowOptions(!showOptions);
|
||||
}}
|
||||
className={cn(
|
||||
selectedOption !== ""
|
||||
? "text-medium-indigo"
|
||||
: "text-muted-foreground",
|
||||
"hover:text-accent-foreground"
|
||||
)}
|
||||
>
|
||||
<ForwardedIconComponent
|
||||
name={optionsIcon}
|
||||
className={"h-4 w-4"}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
)}
|
||||
|
||||
{password && selectedOption === "" && (
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ export const CODE_DIALOG_SUBTITLE =
|
|||
* @constant
|
||||
*/
|
||||
export const CHAT_FORM_DIALOG_SUBTITLE =
|
||||
"Set up the input variables defined in prompt templates. Interact with agents and chains.";
|
||||
"Adjust or overwrite input values, inspect outputs or interact through the chat console.";
|
||||
|
||||
/**
|
||||
* The base text for subtitle of Edit Node Dialog
|
||||
|
|
@ -732,12 +732,12 @@ export const PRIORITY_SIDEBAR_ORDER = [
|
|||
"saved_components",
|
||||
"inputs",
|
||||
"outputs",
|
||||
"prompts",
|
||||
"data",
|
||||
"prompt",
|
||||
"models",
|
||||
"vectorstores",
|
||||
"vectorsearch",
|
||||
"helpers",
|
||||
"experimental",
|
||||
];
|
||||
export const NATIVE_CATEGORIES = [
|
||||
"inputs",
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export default function ChatInput({
|
|||
<div className="relative">
|
||||
<Textarea
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" && !lockChat && !event.shiftKey) {
|
||||
if (event.key === "Enter" && !event.nativeEvent.isComposing && !lockChat && !event.shiftKey) {
|
||||
sendMessage();
|
||||
}
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
|||
import IconComponent from "../../../../components/genericIconComponent";
|
||||
import { Input } from "../../../../components/ui/input";
|
||||
import { Separator } from "../../../../components/ui/separator";
|
||||
import { PRIORITY_SIDEBAR_ORDER } from "../../../../constants/constants";
|
||||
import ExportModal from "../../../../modals/exportModal";
|
||||
import ShareModal from "../../../../modals/shareModal";
|
||||
import useAlertStore from "../../../../stores/alertStore";
|
||||
|
|
@ -282,35 +281,7 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
{index === PRIORITY_SIDEBAR_ORDER.length - 1 && (
|
||||
<>
|
||||
<a
|
||||
target={"_blank"}
|
||||
href="https://langflow.store"
|
||||
className="components-disclosure-arrangement"
|
||||
>
|
||||
<div className="flex gap-4">
|
||||
{/* BUG ON THIS ICON */}
|
||||
<SparklesIcon
|
||||
strokeWidth={1.5}
|
||||
className="w-[22px] text-primary"
|
||||
/>
|
||||
|
||||
<span className="components-disclosure-title">
|
||||
Discover More
|
||||
</span>
|
||||
</div>
|
||||
<div className="components-disclosure-div">
|
||||
<div>
|
||||
<LinkIcon className="h-4 w-4 text-foreground" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div className="p-2 px-4 text-sm font-semibold" key={index}>
|
||||
Legacy Components
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<DisclosureComponent
|
||||
openDisc={
|
||||
getFilterEdge.length !== 0 || search.length !== 0
|
||||
|
|
@ -371,6 +342,32 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
))}
|
||||
</div>
|
||||
</DisclosureComponent>
|
||||
{index === Object.keys(dataFilter).length - 1 && (
|
||||
<>
|
||||
<a
|
||||
target={"_blank"}
|
||||
href="https://langflow.store"
|
||||
className="components-disclosure-arrangement"
|
||||
>
|
||||
<div className="flex gap-4">
|
||||
{/* BUG ON THIS ICON */}
|
||||
<SparklesIcon
|
||||
strokeWidth={1.5}
|
||||
className="w-[22px] text-primary"
|
||||
/>
|
||||
|
||||
<span className="components-disclosure-title">
|
||||
Discover More
|
||||
</span>
|
||||
</div>
|
||||
<div className="components-disclosure-div">
|
||||
<div>
|
||||
<LinkIcon className="h-4 w-4 text-foreground" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div key={index}></div>
|
||||
|
|
|
|||
|
|
@ -85,7 +85,9 @@ export default function NodeToolbarComponent({
|
|||
const [showModalAdvanced, setShowModalAdvanced] = useState(false);
|
||||
const [showconfirmShare, setShowconfirmShare] = useState(false);
|
||||
const [showOverrideModal, setShowOverrideModal] = useState(false);
|
||||
const [flowComponent, setFlowComponent] = useState<FlowType>();
|
||||
const [flowComponent, setFlowComponent] = useState<FlowType>(
|
||||
createFlowComponent(cloneDeep(data), version)
|
||||
);
|
||||
|
||||
const openInNewTab = (url) => {
|
||||
window.open(url, "_blank", "noreferrer");
|
||||
|
|
@ -285,7 +287,13 @@ export default function NodeToolbarComponent({
|
|||
event.preventDefault();
|
||||
setShowconfirmShare((state) => !state);
|
||||
}
|
||||
if (selected && (event.ctrlKey || event.metaKey) && event.key === "q") {
|
||||
|
||||
if (
|
||||
selected &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.shiftKey &&
|
||||
event.key === "Q"
|
||||
) {
|
||||
event.preventDefault();
|
||||
if (isMinimal) {
|
||||
setShowState((show) => !show);
|
||||
|
|
@ -341,6 +349,10 @@ export default function NodeToolbarComponent({
|
|||
title: `${data.id} docs is not available at the moment.`,
|
||||
});
|
||||
}
|
||||
if (selected && (event.ctrlKey || event.metaKey) && event.key === "j") {
|
||||
event.preventDefault();
|
||||
downloadNode(flowComponent!);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("keydown", onKeyDown);
|
||||
|
|
@ -499,15 +511,17 @@ export default function NodeToolbarComponent({
|
|||
/>
|
||||
</SelectItem>
|
||||
)}
|
||||
{!hasStore && (
|
||||
{(!hasStore || !hasApiKey || !validApiKey) && (
|
||||
<SelectItem value={"Download"}>
|
||||
<div className="flex">
|
||||
<IconComponent
|
||||
name="Download"
|
||||
className="relative top-0.5 mr-2 h-4 w-4"
|
||||
/>{" "}
|
||||
Download{" "}
|
||||
</div>{" "}
|
||||
<ToolbarSelectItem
|
||||
value="Download"
|
||||
shift={false}
|
||||
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
|
||||
icon="Download"
|
||||
styleObj={{ iconClasses: "relative top-0.5 mr-2 h-4 w-4" }}
|
||||
keyboardKey={"J"}
|
||||
dataTestId={"Dowload-button-nodeToolbar"}
|
||||
/>
|
||||
</SelectItem>
|
||||
)}
|
||||
<SelectItem
|
||||
|
|
@ -525,24 +539,14 @@ export default function NodeToolbarComponent({
|
|||
</SelectItem>
|
||||
{isMinimal && (
|
||||
<SelectItem value={"show"}>
|
||||
<div className="flex">
|
||||
<IconComponent
|
||||
name={showNode ? "Minimize2" : "Maximize2"}
|
||||
className="relative top-0.5 mr-2 h-4 w-4"
|
||||
/>
|
||||
{showNode ? "Minimize" : "Expand"}
|
||||
{navigator.userAgent.toUpperCase().includes("MAC") ? (
|
||||
<IconComponent
|
||||
name="Command"
|
||||
className="absolute right-[1.25rem] top-[0.65em] h-3.5 w-3.5 stroke-2"
|
||||
></IconComponent>
|
||||
) : (
|
||||
<span className="absolute right-[1.30rem] top-[0.40em] stroke-2">
|
||||
Ctrl +{" "}
|
||||
</span>
|
||||
)}
|
||||
<span className="absolute right-2 top-[0.46em]">Q</span>
|
||||
</div>
|
||||
<ToolbarSelectItem
|
||||
icon={showNode ? "Minimize2" : "Maximize2"}
|
||||
value={showNode ? "Minimize" : "Expand"}
|
||||
isMac={navigator.userAgent.toUpperCase().includes("MAC")}
|
||||
shift={true}
|
||||
keyboardKey={"Q"}
|
||||
dataTestId={"minimize-button-nodeToolbar"}
|
||||
/>
|
||||
</SelectItem>
|
||||
)}
|
||||
{isGroup && (
|
||||
|
|
|
|||
|
|
@ -105,6 +105,8 @@ export default function HomePage(): JSX.Element {
|
|||
firstButtonName="New Project"
|
||||
onFirstBtnClick={() => setOpenModal(true)}
|
||||
options={dropdownOptions}
|
||||
plusButton={true}
|
||||
dropdownOptions={false}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { DarkStoreType } from "../types/zustand/dark";
|
|||
|
||||
const startedStars = Number(window.localStorage.getItem("githubStars")) ?? 0;
|
||||
|
||||
export const useDarkStore = create<DarkStoreType>((set) => ({
|
||||
export const useDarkStore = create<DarkStoreType>((set, get) => ({
|
||||
dark: JSON.parse(window.localStorage.getItem("isDark")!) ?? false,
|
||||
stars: startedStars,
|
||||
version: "",
|
||||
|
|
@ -15,14 +15,23 @@ export const useDarkStore = create<DarkStoreType>((set) => ({
|
|||
});
|
||||
},
|
||||
refreshStars: () => {
|
||||
if (window.localStorage.getItem("githubStars") !== null) {
|
||||
set(() => ({ stars: startedStars }));
|
||||
return;
|
||||
let lastUpdated = window.localStorage.getItem("githubStarsLastUpdated");
|
||||
let diff = 0;
|
||||
// check if lastUpdated actually exists
|
||||
if (lastUpdated !== null) {
|
||||
diff = Math.abs(new Date().getTime() - new Date(lastUpdated).getTime());
|
||||
}
|
||||
|
||||
getRepoStars("logspace-ai", "langflow").then((res) => {
|
||||
window.localStorage.setItem("githubStars", res.toString());
|
||||
set(() => ({ stars: res }));
|
||||
});
|
||||
// if lastUpdated is null or the difference is greater than 2 hours
|
||||
if (lastUpdated === null || diff > 7200000) {
|
||||
getRepoStars("logspace-ai", "langflow").then((res) => {
|
||||
window.localStorage.setItem("githubStars", res.toString());
|
||||
window.localStorage.setItem(
|
||||
"githubStarsLastUpdated",
|
||||
new Date().toString()
|
||||
);
|
||||
set(() => ({ stars: res, lastUpdated: new Date() }));
|
||||
});
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -689,6 +689,8 @@ export type dropdownButtonPropsType = {
|
|||
firstButtonName: string;
|
||||
onFirstBtnClick: () => void;
|
||||
options: Array<{ name: string; onBtnClick: () => void }>;
|
||||
plusButton?: boolean;
|
||||
dropdownOptions?: boolean;
|
||||
};
|
||||
|
||||
export type IOInputProps = {
|
||||
|
|
|
|||
|
|
@ -119,6 +119,8 @@ export async function buildVertices({
|
|||
try {
|
||||
onValidateNodes(verticesOrderResponse.verticesToRun);
|
||||
} catch (e) {
|
||||
useFlowStore.getState().setIsBuilding(false);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1170,7 +1170,7 @@ export function downloadNode(NodeFLow: FlowType) {
|
|||
type: "application/json",
|
||||
});
|
||||
element.href = URL.createObjectURL(file);
|
||||
element.download = `${NodeFLow.name}.json`;
|
||||
element.download = `${NodeFLow?.name??"node"}.json`;
|
||||
element.click();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -236,6 +236,7 @@ export const nodeColors: { [char: string]: string } = {
|
|||
embeddings: "#42BAA7",
|
||||
documentloaders: "#7AAE42",
|
||||
vectorstores: "#AA8742",
|
||||
vectorsearch: "#AA8742",
|
||||
textsplitters: "#B47CB5",
|
||||
toolkits: "#DB2C2C",
|
||||
wrappers: "#E6277A",
|
||||
|
|
@ -248,6 +249,7 @@ export const nodeColors: { [char: string]: string } = {
|
|||
retrievers: "#e6b25a",
|
||||
unknown: "#9CA3AF",
|
||||
custom_components: "#ab11ab",
|
||||
Record:"#31a3cc"
|
||||
};
|
||||
|
||||
export const nodeNames: { [char: string]: string } = {
|
||||
|
|
@ -267,6 +269,7 @@ export const nodeNames: { [char: string]: string } = {
|
|||
embeddings: "Embeddings",
|
||||
documentloaders: "Loaders",
|
||||
vectorstores: "Vector Stores",
|
||||
vectorsearch: "Vector Search",
|
||||
toolkits: "Toolkits",
|
||||
wrappers: "Wrappers",
|
||||
textsplitters: "Text Splitters",
|
||||
|
|
@ -369,6 +372,7 @@ export const nodeIconsLucide: iconsType = {
|
|||
saved_components: GradientSave,
|
||||
documentloaders: Paperclip,
|
||||
vectorstores: Layers,
|
||||
vectorsearch: Search,
|
||||
toolkits: Package2,
|
||||
textsplitters: Scissors,
|
||||
wrappers: Gift,
|
||||
|
|
@ -387,7 +391,6 @@ export const nodeIconsLucide: iconsType = {
|
|||
Trash2,
|
||||
Boxes,
|
||||
Network,
|
||||
X,
|
||||
XCircle,
|
||||
Info,
|
||||
CheckCircle2,
|
||||
|
|
|
|||
358
src/frontend/tests/end-to-end/assets/ChatTest.json
Normal file
358
src/frontend/tests/end-to-end/assets/ChatTest.json
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
{
|
||||
"id": "3f5e860d-1676-4fba-9d86-06db9f51e43a",
|
||||
"data": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "ChatInput-7hPDT",
|
||||
"type": "genericNode",
|
||||
"position": {
|
||||
"x": 687,
|
||||
"y": 41.9375
|
||||
},
|
||||
"data": {
|
||||
"type": "ChatInput",
|
||||
"node": {
|
||||
"template": {
|
||||
"code": {
|
||||
"type": "code",
|
||||
"required": true,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": true,
|
||||
"value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Used to get user input from the chat.\"\n icon = \"ChatInput\"\n\n def build(\n self,\n sender: Optional[str] = \"User\",\n sender_name: Optional[str] = \"User\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "code",
|
||||
"advanced": true,
|
||||
"dynamic": true,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false
|
||||
},
|
||||
"input_value": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": true,
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "input_value",
|
||||
"display_name": "Message",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false
|
||||
},
|
||||
"return_record": {
|
||||
"type": "bool",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"value": false,
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "return_record",
|
||||
"display_name": "Return Record",
|
||||
"advanced": false,
|
||||
"dynamic": false,
|
||||
"info": "Return the message as a record containing the sender, sender_name, and session_id.",
|
||||
"load_from_db": false,
|
||||
"title_case": false
|
||||
},
|
||||
"sender": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": true,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"value": "User",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"options": ["Machine", "User"],
|
||||
"name": "sender",
|
||||
"display_name": "Sender Type",
|
||||
"advanced": false,
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
},
|
||||
"sender_name": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"value": "User",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "sender_name",
|
||||
"display_name": "Sender Name",
|
||||
"advanced": false,
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
},
|
||||
"session_id": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "session_id",
|
||||
"display_name": "Session ID",
|
||||
"advanced": true,
|
||||
"dynamic": false,
|
||||
"info": "If provided, the message will be stored in the memory.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Used to get user input from the chat.",
|
||||
"icon": "ChatInput",
|
||||
"base_classes": ["Text", "object", "str", "Record"],
|
||||
"display_name": "Chat Input",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"sender": null,
|
||||
"sender_name": null,
|
||||
"input_value": null,
|
||||
"session_id": null,
|
||||
"return_record": null
|
||||
},
|
||||
"output_types": ["Text", "Record"],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
"beta": false
|
||||
},
|
||||
"id": "ChatInput-7hPDT"
|
||||
},
|
||||
"selected": false,
|
||||
"width": 384,
|
||||
"height": 569,
|
||||
"positionAbsolute": {
|
||||
"x": 687,
|
||||
"y": 41.9375
|
||||
},
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"id": "ChatOutput-4sm9Z",
|
||||
"type": "genericNode",
|
||||
"position": {
|
||||
"x": 4.939451516507972,
|
||||
"y": 103.3695231904992
|
||||
},
|
||||
"data": {
|
||||
"type": "ChatOutput",
|
||||
"node": {
|
||||
"template": {
|
||||
"code": {
|
||||
"type": "code",
|
||||
"required": true,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": true,
|
||||
"value": "from typing import Optional, Union\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.field_typing import Text\nfrom langflow.schema import Record\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Used to send a message to the chat.\"\n icon = \"ChatOutput\"\n\n def build(\n self,\n sender: Optional[str] = \"Machine\",\n sender_name: Optional[str] = \"AI\",\n input_value: Optional[str] = None,\n session_id: Optional[str] = None,\n return_record: Optional[bool] = False,\n ) -> Union[Text, Record]:\n return super().build(\n sender=sender,\n sender_name=sender_name,\n input_value=input_value,\n session_id=session_id,\n return_record=return_record,\n )\n",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "code",
|
||||
"advanced": true,
|
||||
"dynamic": true,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false
|
||||
},
|
||||
"input_value": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": true,
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "input_value",
|
||||
"display_name": "Message",
|
||||
"advanced": false,
|
||||
"input_types": ["Text"],
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false
|
||||
},
|
||||
"return_record": {
|
||||
"type": "bool",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"value": false,
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "return_record",
|
||||
"display_name": "Return Record",
|
||||
"advanced": false,
|
||||
"dynamic": false,
|
||||
"info": "Return the message as a record containing the sender, sender_name, and session_id.",
|
||||
"load_from_db": false,
|
||||
"title_case": false
|
||||
},
|
||||
"sender": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": true,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"value": "Machine",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"options": ["Machine", "User"],
|
||||
"name": "sender",
|
||||
"display_name": "Sender Type",
|
||||
"advanced": false,
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
},
|
||||
"sender_name": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"value": "AI",
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "sender_name",
|
||||
"display_name": "Sender Name",
|
||||
"advanced": false,
|
||||
"dynamic": false,
|
||||
"info": "",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
},
|
||||
"session_id": {
|
||||
"type": "str",
|
||||
"required": false,
|
||||
"placeholder": "",
|
||||
"list": false,
|
||||
"show": true,
|
||||
"multiline": false,
|
||||
"fileTypes": [],
|
||||
"file_path": "",
|
||||
"password": false,
|
||||
"name": "session_id",
|
||||
"display_name": "Session ID",
|
||||
"advanced": true,
|
||||
"dynamic": false,
|
||||
"info": "If provided, the message will be stored in the memory.",
|
||||
"load_from_db": false,
|
||||
"title_case": false,
|
||||
"input_types": ["Text"]
|
||||
},
|
||||
"_type": "CustomComponent"
|
||||
},
|
||||
"description": "Used to send a message to the chat.",
|
||||
"icon": "ChatOutput",
|
||||
"base_classes": ["Text", "object", "str", "Record"],
|
||||
"display_name": "Chat Output",
|
||||
"documentation": "",
|
||||
"custom_fields": {
|
||||
"sender": null,
|
||||
"sender_name": null,
|
||||
"input_value": null,
|
||||
"session_id": null,
|
||||
"return_record": null
|
||||
},
|
||||
"output_types": ["Text", "Record"],
|
||||
"field_formatters": {},
|
||||
"frozen": false,
|
||||
"field_order": [],
|
||||
"beta": false
|
||||
},
|
||||
"id": "ChatOutput-4sm9Z"
|
||||
},
|
||||
"selected": true,
|
||||
"width": 384,
|
||||
"height": 569,
|
||||
"positionAbsolute": {
|
||||
"x": 4.939451516507972,
|
||||
"y": 103.3695231904992
|
||||
},
|
||||
"dragging": false
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source": "ChatOutput-4sm9Z",
|
||||
"sourceHandle": "{œbaseClassesœ:[œTextœ,œobjectœ,œstrœ,œRecordœ],œdataTypeœ:œChatOutputœ,œidœ:œChatOutput-4sm9Zœ}",
|
||||
"target": "ChatInput-7hPDT",
|
||||
"targetHandle": "{œfieldNameœ:œinput_valueœ,œidœ:œChatInput-7hPDTœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}",
|
||||
"data": {
|
||||
"targetHandle": {
|
||||
"fieldName": "input_value",
|
||||
"id": "ChatInput-7hPDT",
|
||||
"inputTypes": ["Text"],
|
||||
"type": "str"
|
||||
},
|
||||
"sourceHandle": {
|
||||
"baseClasses": ["Text", "object", "str", "Record"],
|
||||
"dataType": "ChatOutput",
|
||||
"id": "ChatOutput-4sm9Z"
|
||||
}
|
||||
},
|
||||
"style": {
|
||||
"stroke": "#555"
|
||||
},
|
||||
"className": "stroke-gray-900 stroke-connection",
|
||||
"id": "reactflow__edge-ChatOutput-4sm9Z{œbaseClassesœ:[œTextœ,œobjectœ,œstrœ,œRecordœ],œdataTypeœ:œChatOutputœ,œidœ:œChatOutput-4sm9Zœ}-ChatInput-7hPDT{œfieldNameœ:œinput_valueœ,œidœ:œChatInput-7hPDTœ,œinputTypesœ:[œTextœ],œtypeœ:œstrœ}"
|
||||
}
|
||||
],
|
||||
"viewport": {
|
||||
"x": 316.78239920440234,
|
||||
"y": 182.84104875768622,
|
||||
"zoom": 0.6070974421975234
|
||||
}
|
||||
},
|
||||
"description": "flow to test ChatInput and output",
|
||||
"name": "ChatITest",
|
||||
"last_tested_version": "1.0.0a0",
|
||||
"is_component": false
|
||||
}
|
||||
46
src/frontend/tests/end-to-end/chat_io.spec.ts
Normal file
46
src/frontend/tests/end-to-end/chat_io.spec.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { test } from "@playwright/test";
|
||||
import { readFileSync } from "fs";
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// await page.waitForTimeout(20000);
|
||||
// test.setTimeout(120000);
|
||||
});
|
||||
test("chat_io_teste", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
await page.locator("span").filter({ hasText: "My Collection" }).isVisible();
|
||||
// Read your file into a buffer.
|
||||
const jsonContent = readFileSync(
|
||||
"tests/end-to-end/assets/ChatTest.json",
|
||||
"utf-8"
|
||||
);
|
||||
|
||||
// Create the DataTransfer and File
|
||||
const dataTransfer = await page.evaluateHandle((data) => {
|
||||
const dt = new DataTransfer();
|
||||
// Convert the buffer to a hex array
|
||||
const file = new File([data], "ChatTest.json", {
|
||||
type: "application/json",
|
||||
});
|
||||
dt.items.add(file);
|
||||
return dt;
|
||||
}, jsonContent);
|
||||
|
||||
await page.locator('//*[@id="new-project-btn"]').click();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
await page.getByTestId("blank-flow").click();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Now dispatch
|
||||
await page.dispatchEvent(
|
||||
'//*[@id="react-flow-id"]/div[1]/div[1]/div',
|
||||
"drop",
|
||||
{
|
||||
dataTransfer,
|
||||
}
|
||||
);
|
||||
await page.getByLabel("fit view").click();
|
||||
await page.getByText("Run", { exact: true }).click();
|
||||
await page.getByPlaceholder("Send a message...").click();
|
||||
await page.getByPlaceholder("Send a message...").fill("teste");
|
||||
await page.getByRole("button").nth(1).click();
|
||||
});
|
||||
|
|
@ -25,86 +25,31 @@ test("CodeAreaModalComponent", async ({ page }) => {
|
|||
await page.getByTestId("code-button-modal").click();
|
||||
|
||||
let value = await page.locator('//*[@id="codeValue"]').inputValue();
|
||||
|
||||
if (
|
||||
value !=
|
||||
'def python_function(text: str) -> str: """This is a default python function that returns the input text""" return text'
|
||||
) {
|
||||
expect(false).toBeTruthy();
|
||||
}
|
||||
|
||||
const code =
|
||||
'def python_function(text: str) -> str:\n """This is a default python function that returns the input text"""\n return text';
|
||||
const wCode =
|
||||
'def python_function(text: str) -> st: """This is a default python function that returns the input text""" return text';
|
||||
const assertCode =
|
||||
'def python_function(text: str) -> str: """This is a default python function that returns the input text""" return text';
|
||||
await page
|
||||
.locator("#CodeEditor div")
|
||||
.filter({ hasText: "def python_function(text: str" })
|
||||
.nth(1)
|
||||
.click();
|
||||
await page.locator("textarea").press("Control+a");
|
||||
await page.locator("textarea").fill(wCode);
|
||||
await page.locator('//*[@id="checkAndSaveBtn"]').click();
|
||||
|
||||
await page.getByTestId("div-generic-node").click();
|
||||
|
||||
await page.getByTestId("more-options-modal").click();
|
||||
await page.getByTestId("edit-button-modal").click();
|
||||
|
||||
await page.locator('//*[@id="showdescription"]').click();
|
||||
await page.waitForTimeout(1000);
|
||||
expect(
|
||||
await page.locator('//*[@id="showdescription"]').isChecked()
|
||||
).toBeFalsy();
|
||||
|
||||
await page.locator('//*[@id="showname"]').click();
|
||||
expect(await page.locator('//*[@id="showname"]').isChecked()).toBeFalsy();
|
||||
|
||||
await page.locator('//*[@id="showreturn_direct"]').click();
|
||||
expect(
|
||||
await page.locator('//*[@id="showreturn_direct"]').isChecked()
|
||||
).toBeFalsy();
|
||||
|
||||
await page.locator('//*[@id="showdescription"]').click();
|
||||
expect(
|
||||
await page.locator('//*[@id="showdescription"]').isChecked()
|
||||
await page.getByText("invalid syntax (<unknown>, line 1)").isVisible()
|
||||
).toBeTruthy();
|
||||
|
||||
await page.locator('//*[@id="showname"]').click();
|
||||
expect(await page.locator('//*[@id="showname"]').isChecked()).toBeTruthy();
|
||||
|
||||
await page.locator('//*[@id="showreturn_direct"]').click();
|
||||
expect(
|
||||
await page.locator('//*[@id="showreturn_direct"]').isChecked()
|
||||
).toBeTruthy();
|
||||
|
||||
await page.locator('//*[@id="showdescription"]').click();
|
||||
expect(
|
||||
await page.locator('//*[@id="showdescription"]').isChecked()
|
||||
).toBeFalsy();
|
||||
|
||||
await page.locator('//*[@id="showname"]').click();
|
||||
expect(await page.locator('//*[@id="showname"]').isChecked()).toBeFalsy();
|
||||
|
||||
await page.locator('//*[@id="showreturn_direct"]').click();
|
||||
expect(
|
||||
await page.locator('//*[@id="showreturn_direct"]').isChecked()
|
||||
).toBeFalsy();
|
||||
|
||||
await page.locator('//*[@id="showdescription"]').click();
|
||||
expect(
|
||||
await page.locator('//*[@id="showdescription"]').isChecked()
|
||||
).toBeTruthy();
|
||||
|
||||
await page.locator('//*[@id="showname"]').click();
|
||||
expect(await page.locator('//*[@id="showname"]').isChecked()).toBeTruthy();
|
||||
|
||||
await page.locator('//*[@id="showreturn_direct"]').click();
|
||||
expect(
|
||||
await page.locator('//*[@id="showreturn_direct"]').isChecked()
|
||||
).toBeTruthy();
|
||||
|
||||
await page.locator('//*[@id="saveChangesBtn"]').click();
|
||||
|
||||
const plusButtonLocator = page.locator('//*[@id="code-input-0"]');
|
||||
const elementCount = await plusButtonLocator.count();
|
||||
if (elementCount === 0) {
|
||||
expect(true).toBeTruthy();
|
||||
|
||||
await page.getByTestId("more-options-modal").click();
|
||||
await page.getByTestId("edit-button-modal").click();
|
||||
|
||||
await page.locator('//*[@id="saveChangesBtn"]').click();
|
||||
|
||||
await page.getByTestId("div-generic-node").click();
|
||||
await page.getByTestId("code-button-modal").click();
|
||||
}
|
||||
await page.locator("textarea").press("Control+a");
|
||||
await page.locator("textarea").fill(wCode);
|
||||
await page.locator("textarea").fill(code);
|
||||
await page.locator('//*[@id="checkAndSaveBtn"]').click();
|
||||
expect(await page.getByText("Code is ready to run").isVisible()).toBeTruthy();
|
||||
await page.getByTestId("code-button-modal").click();
|
||||
expect(await page.locator('//*[@id="codeValue"]').inputValue()).toBe(
|
||||
assertCode
|
||||
);
|
||||
});
|
||||
|
|
|
|||
17
src/frontend/tests/end-to-end/curl_api_generation.spec.ts
Normal file
17
src/frontend/tests/end-to-end/curl_api_generation.spec.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
|
||||
test("curl_api_generation", async ({ page, context }) => {
|
||||
await page.goto("/");
|
||||
await page.locator('//*[@id="new-project-btn"]').click();
|
||||
await context.grantPermissions(["clipboard-read", "clipboard-write"]);
|
||||
await page.getByRole("heading", { name: "Data Ingestion" }).click();
|
||||
await page.waitForTimeout(2000);
|
||||
await page.getByText("API", { exact: true }).click();
|
||||
await page.getByRole("tab", { name: "cURL" }).click();
|
||||
await page.getByRole("button", { name: "Copy Code" }).click();
|
||||
const handle = await page.evaluateHandle(() =>
|
||||
navigator.clipboard.readText()
|
||||
);
|
||||
const clipboardContent = await handle.jsonValue();
|
||||
expect(clipboardContent.length).toBeGreaterThan(0);
|
||||
});
|
||||
17
src/frontend/tests/end-to-end/python_api_generation.spec.ts
Normal file
17
src/frontend/tests/end-to-end/python_api_generation.spec.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
|
||||
test("python_api_generation", async ({ page, context }) => {
|
||||
await page.goto("/");
|
||||
await page.locator('//*[@id="new-project-btn"]').click();
|
||||
await context.grantPermissions(["clipboard-read", "clipboard-write"]);
|
||||
await page.getByRole("heading", { name: "Data Ingestion" }).click();
|
||||
await page.waitForTimeout(2000);
|
||||
await page.getByText("API", { exact: true }).click();
|
||||
await page.getByRole("tab", { name: "Python API" }).click();
|
||||
await page.getByRole("button", { name: "Copy Code" }).click();
|
||||
const handle = await page.evaluateHandle(() =>
|
||||
navigator.clipboard.readText()
|
||||
);
|
||||
const clipboardContent = await handle.jsonValue();
|
||||
expect(clipboardContent.length).toBeGreaterThan(0);
|
||||
});
|
||||
38
src/frontend/tests/end-to-end/tweaks_test.spec.ts
Normal file
38
src/frontend/tests/end-to-end/tweaks_test.spec.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
|
||||
test("curl_api_generation", async ({ page, context }) => {
|
||||
await page.goto("/");
|
||||
await page.locator('//*[@id="new-project-btn"]').click();
|
||||
await context.grantPermissions(["clipboard-read", "clipboard-write"]);
|
||||
await page.getByRole("heading", { name: "Data Ingestion" }).click();
|
||||
await page.waitForTimeout(2000);
|
||||
await page.getByText("API", { exact: true }).click();
|
||||
await page.getByRole("tab", { name: "cURL" }).click();
|
||||
await page.getByRole("button", { name: "Copy Code" }).click();
|
||||
const handle = await page.evaluateHandle(() =>
|
||||
navigator.clipboard.readText()
|
||||
);
|
||||
const clipboardContent = await handle.jsonValue();
|
||||
const oldValue = clipboardContent;
|
||||
expect(clipboardContent.length).toBeGreaterThan(0);
|
||||
await page.getByRole("tab", { name: "Tweaks" }).click();
|
||||
await page
|
||||
.getByRole("heading", { name: "URL" })
|
||||
.locator("div")
|
||||
.first()
|
||||
.click();
|
||||
await page.getByRole("textbox", { name: "Type something..." }).click();
|
||||
await page
|
||||
.getByRole("textbox", { name: "Type something..." })
|
||||
.press("Control+a");
|
||||
await page.getByRole("textbox", { name: "Type something..." }).fill("teste");
|
||||
await page.getByRole("tab", { name: "cURL" }).click();
|
||||
await page.getByRole("button", { name: "Copy Code" }).click();
|
||||
const handle2 = await page.evaluateHandle(() =>
|
||||
navigator.clipboard.readText()
|
||||
);
|
||||
const clipboardContent2 = await handle2.jsonValue();
|
||||
const newValue = clipboardContent2;
|
||||
expect(oldValue).not.toBe(newValue);
|
||||
expect(clipboardContent2.length).toBeGreaterThan(clipboardContent.length);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue