diff --git a/src/backend/langflow/__main__.py b/src/backend/langflow/__main__.py index 2b1d4bbe3..cbfddf289 100644 --- a/src/backend/langflow/__main__.py +++ b/src/backend/langflow/__main__.py @@ -63,6 +63,8 @@ def set_var_for_macos_issue(): import os os.environ["OBJC_DISABLE_INITIALIZE_FORK_SAFETY"] = "YES" + # https://stackoverflow.com/questions/75747888/uwsgi-segmentation-fault-with-flask-python-app-behind-nginx-after-running-for-2 # noqa + os.environ["no_proxy"] = "*" # to avoid error with gunicorn logger.debug("Set OBJC_DISABLE_INITIALIZE_FORK_SAFETY to YES to avoid error") diff --git a/src/backend/langflow/api/v1/chat.py b/src/backend/langflow/api/v1/chat.py index 6ae9cd145..26765623a 100644 --- a/src/backend/langflow/api/v1/chat.py +++ b/src/backend/langflow/api/v1/chat.py @@ -187,7 +187,7 @@ async def stream_build( "duration": time_elapsed, } - yield str(StreamData(event="message", data=response)) + yield str(StreamData(event="message", data=response)) langchain_object = await graph.build() # Now we need to check the input_keys to send them to the client diff --git a/src/backend/langflow/api/v1/endpoints.py b/src/backend/langflow/api/v1/endpoints.py index e07b00614..6ebb04182 100644 --- a/src/backend/langflow/api/v1/endpoints.py +++ b/src/backend/langflow/api/v1/endpoints.py @@ -48,10 +48,9 @@ def get_all( logger.debug("Building langchain types dict") try: - types_dict = get_all_types_dict(settings_service) + return get_all_types_dict(settings_service) except Exception as exc: raise HTTPException(status_code=500, detail=str(exc)) from exc - return types_dict # For backwards compatibility we will keep the old endpoint @@ -64,7 +63,7 @@ def get_all( "/process/{flow_id}", response_model=ProcessResponse, ) -async def process_flow( +async def process( session: Annotated[Session, Depends(get_session)], flow_id: str, inputs: Optional[dict] = None, diff --git a/src/backend/langflow/api/v1/flows.py b/src/backend/langflow/api/v1/flows.py index fcf776a93..28c11dfb4 100644 --- a/src/backend/langflow/api/v1/flows.py +++ b/src/backend/langflow/api/v1/flows.py @@ -5,14 +5,13 @@ from uuid import UUID import orjson from fastapi import APIRouter, Depends, File, HTTPException, UploadFile from fastapi.encoders import jsonable_encoder -from sqlmodel import Session, select - from langflow.api.utils import remove_api_keys, validate_is_component from langflow.api.v1.schemas import FlowListCreate, FlowListRead from langflow.services.auth.utils import get_current_active_user from langflow.services.database.models.flow import Flow, FlowCreate, FlowRead, FlowUpdate from langflow.services.database.models.user.model import User from langflow.services.deps import get_session, get_settings_service +from sqlmodel import Session, select # build router router = APIRouter(prefix="/flows", tags=["Flows"]) @@ -123,7 +122,7 @@ def create_flows( db_flows = [] for flow in flow_list.flows: flow.user_id = current_user.id - db_flow = Flow.model_validate(flow) + db_flow = Flow.from_orm(flow) session.add(db_flow) db_flows.append(db_flow) session.commit() diff --git a/src/backend/langflow/api/v1/users.py b/src/backend/langflow/api/v1/users.py index 594ed5de7..9d4c3f32e 100644 --- a/src/backend/langflow/api/v1/users.py +++ b/src/backend/langflow/api/v1/users.py @@ -1,11 +1,6 @@ from uuid import UUID from fastapi import APIRouter, Depends, HTTPException -from sqlalchemy import func -from sqlalchemy.exc import IntegrityError -from sqlmodel import Session, select -from sqlmodel.sql.expression import SelectOfScalar - from langflow.api.v1.schemas import UsersResponse from langflow.services.auth.utils import ( get_current_active_superuser, @@ -16,6 +11,10 @@ from langflow.services.auth.utils import ( from langflow.services.database.models.user import User, UserCreate, UserRead, UserUpdate from langflow.services.database.models.user.crud import get_user_by_id, update_user from langflow.services.deps import get_session, get_settings_service +from sqlalchemy import func +from sqlalchemy.exc import IntegrityError +from sqlmodel import Session, select +from sqlmodel.sql.expression import SelectOfScalar router = APIRouter(tags=["Users"], prefix="/users") @@ -29,7 +28,7 @@ def add_user( """ Add a new user to the database. """ - new_user = User.model_validate(user) + new_user = User.from_orm(user) try: new_user.password = get_password_hash(user.password) new_user.is_active = settings_service.auth_settings.NEW_USER_IS_ACTIVE diff --git a/src/backend/langflow/components/agents/OpenAIConversationalAgent.py b/src/backend/langflow/components/agents/OpenAIConversationalAgent.py index f2df4c7d2..499775747 100644 --- a/src/backend/langflow/components/agents/OpenAIConversationalAgent.py +++ b/src/backend/langflow/components/agents/OpenAIConversationalAgent.py @@ -80,4 +80,5 @@ class ConversationalAgent(CustomComponent): memory=memory, verbose=True, return_intermediate_steps=True, + handle_parsing_errors=True, ) diff --git a/src/backend/langflow/components/chains/LLMChain.py b/src/backend/langflow/components/chains/LLMChain.py index d62f7ce06..ec88e128a 100644 --- a/src/backend/langflow/components/chains/LLMChain.py +++ b/src/backend/langflow/components/chains/LLMChain.py @@ -3,7 +3,12 @@ from typing import Callable, Optional, Union from langchain.chains import LLMChain from langflow import CustomComponent -from langflow.field_typing import BaseLanguageModel, BaseMemory, BasePromptTemplate, Chain +from langflow.field_typing import ( + BaseLanguageModel, + BaseMemory, + BasePromptTemplate, + Chain, +) class LLMChainComponent(CustomComponent): diff --git a/src/backend/langflow/components/documentloaders/__init__.py b/src/backend/langflow/components/documentloaders/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/backend/langflow/components/llms/AmazonBedrock.py b/src/backend/langflow/components/llms/AmazonBedrock.py new file mode 100644 index 000000000..04785db63 --- /dev/null +++ b/src/backend/langflow/components/llms/AmazonBedrock.py @@ -0,0 +1,45 @@ +from typing import Optional +from langflow import CustomComponent +from langchain.llms.bedrock import Bedrock +from langchain.llms.base import BaseLLM + + +class AmazonBedrockComponent(CustomComponent): + display_name: str = "Amazon Bedrock" + description: str = "LLM model from Amazon Bedrock." + + 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", + "anthropic.claude-v2", + "cohere.command-text-v14", + ], + }, + "credentials_profile_name": {"display_name": "Credentials Profile Name"}, + "streaming": {"display_name": "Streaming", "field_type": "bool"}, + "code": {"show": False}, + } + + def build( + self, + model_id: str = "anthropic.claude-instant-v1", + credentials_profile_name: Optional[str] = None, + ) -> BaseLLM: + try: + output = Bedrock( + credentials_profile_name=credentials_profile_name, + model_id=model_id, + ) # type: ignore + except Exception as e: + raise ValueError("Could not connect to AmazonBedrock API.") from e + return output diff --git a/src/backend/langflow/components/llms/BaiduQianfanLLMEndpoints.py b/src/backend/langflow/components/llms/BaiduQianfanLLMEndpoints.py new file mode 100644 index 000000000..786c4516b --- /dev/null +++ b/src/backend/langflow/components/llms/BaiduQianfanLLMEndpoints.py @@ -0,0 +1,92 @@ +from typing import Optional +from langflow import CustomComponent +from langchain.llms.baidu_qianfan_endpoint import QianfanLLMEndpoint +from langchain.llms.base import BaseLLM + + +class QianfanLLMEndpointComponent(CustomComponent): + display_name: str = "QianfanLLMEndpoint" + description: str = ( + "Baidu Qianfan hosted open source or customized models. " + "Get more detail from https://python.langchain.com/docs/integrations/chat/baidu_qianfan_endpoint" + ) + + def build_config(self): + return { + "model": { + "display_name": "Model Name", + "options": [ + "ERNIE-Bot", + "ERNIE-Bot-turbo", + "BLOOMZ-7B", + "Llama-2-7b-chat", + "Llama-2-13b-chat", + "Llama-2-70b-chat", + "Qianfan-BLOOMZ-7B-compressed", + "Qianfan-Chinese-Llama-2-7B", + "ChatGLM2-6B-32K", + "AquilaChat-7B", + ], + "info": "https://python.langchain.com/docs/integrations/chat/baidu_qianfan_endpoint", + "required": True, + }, + "qianfan_ak": { + "display_name": "Qianfan Ak", + "required": True, + "password": True, + "info": "which you could get from https://cloud.baidu.com/product/wenxinworkshop", + }, + "qianfan_sk": { + "display_name": "Qianfan Sk", + "required": True, + "password": True, + "info": "which you could get from https://cloud.baidu.com/product/wenxinworkshop", + }, + "top_p": { + "display_name": "Top p", + "field_type": "float", + "info": "Model params, only supported in ERNIE-Bot and ERNIE-Bot-turbo", + "value": 0.8, + }, + "temperature": { + "display_name": "Temperature", + "field_type": "float", + "info": "Model params, only supported in ERNIE-Bot and ERNIE-Bot-turbo", + "value": 0.95, + }, + "penalty_score": { + "display_name": "Penalty Score", + "field_type": "float", + "info": "Model params, only supported in ERNIE-Bot and ERNIE-Bot-turbo", + "value": 1.0, + }, + "endpoint": { + "display_name": "Endpoint", + "info": "Endpoint of the Qianfan LLM, required if custom model used.", + }, + "code": {"show": False}, + } + + def build( + self, + model: str = "ERNIE-Bot-turbo", + qianfan_ak: Optional[str] = None, + qianfan_sk: Optional[str] = None, + top_p: Optional[float] = None, + temperature: Optional[float] = None, + penalty_score: Optional[float] = None, + endpoint: Optional[str] = None, + ) -> BaseLLM: + try: + output = QianfanLLMEndpoint( # type: ignore + model=model, + qianfan_ak=qianfan_ak, + qianfan_sk=qianfan_sk, + top_p=top_p, + temperature=temperature, + penalty_score=penalty_score, + endpoint=endpoint, + ) + except Exception as e: + raise ValueError("Could not connect to Baidu Qianfan API.") from e + return output # type: ignore diff --git a/src/backend/langflow/components/llms/HuggingFaceEndpoints.py b/src/backend/langflow/components/llms/HuggingFaceEndpoints.py index ea2b4f20b..0d28d5b9b 100644 --- a/src/backend/langflow/components/llms/HuggingFaceEndpoints.py +++ b/src/backend/langflow/components/llms/HuggingFaceEndpoints.py @@ -1,6 +1,6 @@ from typing import Optional from langflow import CustomComponent -from langchain.llms import HuggingFaceEndpoint +from langchain.llms.huggingface_endpoint import HuggingFaceEndpoint from langchain.llms.base import BaseLLM @@ -13,7 +13,6 @@ class HuggingFaceEndpointsComponent(CustomComponent): "endpoint_url": {"display_name": "Endpoint URL", "password": True}, "task": { "display_name": "Task", - "type": "select", "options": ["text2text-generation", "text-generation", "summarization"], }, "huggingfacehub_api_token": {"display_name": "API token", "password": True}, @@ -27,7 +26,7 @@ class HuggingFaceEndpointsComponent(CustomComponent): def build( self, endpoint_url: str, - task="text2text-generation", + task: str = "text2text-generation", huggingfacehub_api_token: Optional[str] = None, model_kwargs: Optional[dict] = None, ) -> BaseLLM: @@ -36,6 +35,7 @@ class HuggingFaceEndpointsComponent(CustomComponent): endpoint_url=endpoint_url, task=task, huggingfacehub_api_token=huggingfacehub_api_token, + model_kwargs=model_kwargs, ) except Exception as e: raise ValueError("Could not connect to HuggingFace Endpoints API.") from e diff --git a/src/backend/langflow/components/retrievers/AmazonKendra.py b/src/backend/langflow/components/retrievers/AmazonKendra.py new file mode 100644 index 000000000..827945a51 --- /dev/null +++ b/src/backend/langflow/components/retrievers/AmazonKendra.py @@ -0,0 +1,48 @@ +from typing import Optional +from langflow import CustomComponent +from langchain.retrievers import AmazonKendraRetriever +from langchain.schema import BaseRetriever + + +class AmazonKendraRetrieverComponent(CustomComponent): + display_name: str = "Amazon Kendra Retriever" + description: str = "Retriever that uses the Amazon Kendra API." + + def build_config(self): + return { + "index_id": {"display_name": "Index ID"}, + "region_name": {"display_name": "Region Name"}, + "credentials_profile_name": {"display_name": "Credentials Profile Name"}, + "attribute_filter": { + "display_name": "Attribute Filter", + "field_type": "code", + }, + "top_k": {"display_name": "Top K", "field_type": "int"}, + "user_context": { + "display_name": "User Context", + "field_type": "code", + }, + "code": {"show": False}, + } + + def build( + self, + index_id: str, + top_k: int = 3, + region_name: Optional[str] = None, + credentials_profile_name: Optional[str] = None, + attribute_filter: Optional[dict] = None, + user_context: Optional[dict] = None, + ) -> BaseRetriever: + try: + output = AmazonKendraRetriever( + index_id=index_id, + top_k=top_k, + region_name=region_name, + credentials_profile_name=credentials_profile_name, + attribute_filter=attribute_filter, + user_context=user_context, + ) # type: ignore + except Exception as e: + raise ValueError("Could not connect to AmazonKendra API.") from e + return output diff --git a/src/backend/langflow/components/vectorstores/Chroma.py b/src/backend/langflow/components/vectorstores/Chroma.py index 4c877dc85..bf1273c43 100644 --- a/src/backend/langflow/components/vectorstores/Chroma.py +++ b/src/backend/langflow/components/vectorstores/Chroma.py @@ -14,7 +14,7 @@ class ChromaComponent(CustomComponent): A custom component for implementing a Vector Store using Chroma. """ - display_name: str = "Chroma (Custom Component)" + display_name: str = "Chroma" description: str = "Implementation of Vector Store using Chroma" documentation = "https://python.langchain.com/docs/integrations/vectorstores/chroma" beta: bool = True diff --git a/src/backend/langflow/components/vectorstores/Faiss.py b/src/backend/langflow/components/vectorstores/Faiss.py deleted file mode 100644 index cf014beaa..000000000 --- a/src/backend/langflow/components/vectorstores/Faiss.py +++ /dev/null @@ -1,62 +0,0 @@ -from typing import List, Optional, Union -from langflow import CustomComponent - -from langchain.vectorstores import FAISS -from langchain.vectorstores.base import VectorStore -from langchain.schema import BaseRetriever -from langchain.schema import Document -from langchain.embeddings.base import Embeddings - - -class FAISSComponent(CustomComponent): - """ - A custom component for implementing a Vector Store using FAISS. - """ - - display_name: str = "FAISS (Custom Component)" - description: str = "Implementation of Vector Store using FAISS" - documentation = "https://python.langchain.com/docs/integrations/vectorstores/faiss" - beta = True - - def build_config(self): - return { - "persistence": { - "display_name": "Persistence", - "options": ["In-Memory", "LocalDirectory"], - "value": "In-Memory", - }, - "folder_path": { - "display_name": "Folder Path", - "required": False, - }, - "index_name": {"display_name": "Index Name", "value": "faiss_index"}, - "documents": {"display_name": "Documents", "is_list": True}, - "embeddings": {"display_name": "Embeddings"}, - "code": {"display_name": "Code", "show": False}, - } - - def build( - self, - persistence: str, - index_name: str, - embeddings: Embeddings, - folder_path: Optional[str] = None, - documents: Optional[List[Document]] = None, - ) -> Union[VectorStore, BaseRetriever]: - if persistence == "LocalDirectory" and not folder_path: - raise ValueError("Folder path is required for local directory persistence") - - # Load if persistence is LocalDirectory - if documents is None and folder_path is not None: - return FAISS.load_local(folder_path=folder_path, embeddings=embeddings, index_name=index_name) - - if documents is None: - raise ValueError("Documents must be provided in the params") - - db = FAISS.from_documents(documents=documents, embedding=embeddings) - - # Save if persistence is LocalDirectory - if persistence == "LocalDirectory" and folder_path is not None: - db.save_local(folder_path=folder_path, index_name=index_name) - - return db diff --git a/src/backend/langflow/components/vectorstores/Vectara.py b/src/backend/langflow/components/vectorstores/Vectara.py index 09d8b500b..1f0d10179 100644 --- a/src/backend/langflow/components/vectorstores/Vectara.py +++ b/src/backend/langflow/components/vectorstores/Vectara.py @@ -1,6 +1,5 @@ from typing import Optional, Union -from langchain.embeddings.base import Embeddings from langchain.schema import BaseRetriever, Document from langchain.vectorstores import Vectara from langchain.vectorstores.base import VectorStore @@ -20,7 +19,6 @@ class VectaraComponent(CustomComponent): "vectara_api_key": {"display_name": "Vectara API Key", "password": True}, "code": {"show": False}, "documents": {"display_name": "Documents"}, - "embedding": {"display_name": "Embedding"}, } def build( @@ -28,21 +26,21 @@ class VectaraComponent(CustomComponent): vectara_customer_id: str, vectara_corpus_id: str, vectara_api_key: str, - embedding: Optional[Embeddings] = None, documents: Optional[Document] = None, ) -> Union[VectorStore, BaseRetriever]: # If documents, then we need to create a Vectara instance using .from_documents - if documents is not None and embedding is not None: + if documents is not None: return Vectara.from_documents( documents=documents, # type: ignore vectara_customer_id=vectara_customer_id, vectara_corpus_id=vectara_corpus_id, vectara_api_key=vectara_api_key, - embedding=embedding, + source="langflow", ) return Vectara( vectara_customer_id=vectara_customer_id, vectara_corpus_id=vectara_corpus_id, vectara_api_key=vectara_api_key, + source="langflow", ) diff --git a/src/backend/langflow/config.yaml b/src/backend/langflow/config.yaml index 60af58d63..186bfa621 100644 --- a/src/backend/langflow/config.yaml +++ b/src/backend/langflow/config.yaml @@ -118,10 +118,10 @@ llms: documentation: "https://python.langchain.com/docs/modules/model_io/models/llms/integrations/ctransformers" Cohere: documentation: "https://python.langchain.com/docs/modules/model_io/models/llms/integrations/cohere" - # Anthropic: - # documentation: "" - # ChatAnthropic: - # documentation: "https://python.langchain.com/docs/modules/model_io/models/chat/integrations/anthropic" + Anthropic: + documentation: "" + ChatAnthropic: + documentation: "https://python.langchain.com/docs/modules/model_io/models/chat/integrations/anthropic" HuggingFaceHub: documentation: "https://python.langchain.com/docs/modules/model_io/models/llms/integrations/huggingface_hub" VertexAI: @@ -266,14 +266,14 @@ retrievers: # ZepRetriever: # documentation: "https://python.langchain.com/docs/modules/data_connection/retrievers/integrations/zep_memorystore" vectorstores: - Chroma: - documentation: "https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/chroma" + # Chroma: + # documentation: "https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/chroma" Qdrant: documentation: "https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/qdrant" Weaviate: documentation: "https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/weaviate" - # FAISS: - # documentation: "https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/faiss" + FAISS: + documentation: "https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/faiss" Pinecone: documentation: "https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/pinecone" SupabaseVectorStore: diff --git a/src/backend/langflow/field_typing/base.py b/src/backend/langflow/field_typing/base.py deleted file mode 100644 index ed3219888..000000000 --- a/src/backend/langflow/field_typing/base.py +++ /dev/null @@ -1,4 +0,0 @@ -from typing import Union, Dict - -# Type alias for more complex dicts -NestedDict = Dict[str, Union[str, Dict]] diff --git a/src/backend/langflow/graph/graph/base.py b/src/backend/langflow/graph/graph/base.py index 31537c51e..3481fda87 100644 --- a/src/backend/langflow/graph/graph/base.py +++ b/src/backend/langflow/graph/graph/base.py @@ -17,7 +17,7 @@ class Graph: def __init__( self, - nodes: List[Dict[str, Union[str, Dict[str, Union[str, List[str]]]]]], + nodes: List[Dict], edges: List[Dict[str, str]], ) -> None: self._vertices = nodes @@ -27,8 +27,7 @@ class Graph: self.top_level_vertices = [] for vertex in self._vertices: if vertex_id := vertex.get("id"): - if isinstance(vertex_id, str): - self.top_level_vertices.append(vertex_id) + self.top_level_vertices.append(vertex_id) self._graph_data = process_flow(self.raw_graph_data) self._vertices = self._graph_data["nodes"] @@ -59,6 +58,7 @@ class Graph: edges = payload["edges"] return cls(vertices, edges) except KeyError as exc: + logger.exception(exc) raise ValueError( f"Invalid payload. Expected keys 'nodes' and 'edges'. Found {list(payload.keys())}" ) from exc diff --git a/src/backend/langflow/graph/vertex/base.py b/src/backend/langflow/graph/vertex/base.py index 477f8434e..01995c23e 100644 --- a/src/backend/langflow/graph/vertex/base.py +++ b/src/backend/langflow/graph/vertex/base.py @@ -35,8 +35,9 @@ class Vertex: self.artifacts: Dict[str, Any] = {} self.task_id: Optional[str] = None self.is_task = is_task - self.parent_node_id: Optional[str] = self._data.get("parent_node_id") self.params = params or {} + self.parent_node_id: Optional[str] = self._data.get("parent_node_id") + self.parent_is_top_level = False @property def edges(self) -> List["Edge"]: diff --git a/src/backend/langflow/graph/vertex/types.py b/src/backend/langflow/graph/vertex/types.py index 868cc6c67..7439876fa 100644 --- a/src/backend/langflow/graph/vertex/types.py +++ b/src/backend/langflow/graph/vertex/types.py @@ -131,7 +131,6 @@ class VectorStoreVertex(Vertex): super().__init__(data, graph=graph, base_type="vectorstores") self.params = params or {} - self.params.pop("code", None) # VectorStores may contain databse connections # so we need to define the __reduce__ method and the __setstate__ method @@ -201,6 +200,9 @@ class ChainVertex(Vertex): self.params.pop("code", None) # Check if the chain requires a PromptVertex + # Temporarily remove "code" from the params + self.params.pop("code", None) + for key, value in self.params.items(): if isinstance(value, PromptVertex): # Build the PromptVertex, passing the tools if available diff --git a/src/backend/langflow/interface/agents/custom.py b/src/backend/langflow/interface/agents/custom.py index 158723572..512623ef2 100644 --- a/src/backend/langflow/interface/agents/custom.py +++ b/src/backend/langflow/interface/agents/custom.py @@ -21,7 +21,6 @@ from langchain.tools.sql_database.prompt import QUERY_CHECKER from langchain_experimental.agents.agent_toolkits.pandas.prompt import PREFIX as PANDAS_PREFIX from langchain_experimental.agents.agent_toolkits.pandas.prompt import SUFFIX_WITH_DF as PANDAS_SUFFIX from langchain_experimental.tools.python.tool import PythonAstREPLTool - from langflow.interface.base import CustomAgentExecutor diff --git a/src/backend/langflow/interface/initialize/vector_store.py b/src/backend/langflow/interface/initialize/vector_store.py index 405f197e3..0b5ade7c8 100644 --- a/src/backend/langflow/interface/initialize/vector_store.py +++ b/src/backend/langflow/interface/initialize/vector_store.py @@ -1,17 +1,17 @@ -import os from typing import Any, Callable, Dict, Type - -import orjson -from langchain.schema import Document from langchain.vectorstores import ( - FAISS, - Chroma, - MongoDBAtlasVectorSearch, Pinecone, Qdrant, - SupabaseVectorStore, + Chroma, + FAISS, Weaviate, + SupabaseVectorStore, + MongoDBAtlasVectorSearch, ) +from langchain.schema import Document +import os + +import orjson def docs_in_params(params: dict) -> bool: @@ -26,8 +26,8 @@ def initialize_mongodb(class_object: Type[MongoDBAtlasVectorSearch], params: dic MONGODB_ATLAS_CLUSTER_URI = params.pop("mongodb_atlas_cluster_uri") if not MONGODB_ATLAS_CLUSTER_URI: raise ValueError("Mongodb atlas cluster uri must be provided in the params") - import certifi from pymongo import MongoClient + import certifi client: MongoClient = MongoClient(MONGODB_ATLAS_CLUSTER_URI, tlsCAFile=certifi.where()) db_name = params.pop("db_name", None) @@ -116,7 +116,6 @@ def initialize_faiss(class_object: Type[FAISS], params: dict): return class_object.load_local save_local = params.get("save_local") - params["embedding_function"] = params.pop("embedding") faiss_index = class_object(**params) if save_local: faiss_index.save_local(folder_path=save_local) diff --git a/src/backend/langflow/interface/tools/base.py b/src/backend/langflow/interface/tools/base.py index cc8e5cd75..875915a58 100644 --- a/src/backend/langflow/interface/tools/base.py +++ b/src/backend/langflow/interface/tools/base.py @@ -1,18 +1,27 @@ from typing import Dict, List, Optional -from langchain.agents.load_tools import _EXTRA_LLM_TOOLS, _EXTRA_OPTIONAL_TOOLS, _LLM_TOOLS -from langchain_experimental.tools.python.tool import PythonInputs +from langchain.agents.load_tools import ( + _EXTRA_LLM_TOOLS, + _EXTRA_OPTIONAL_TOOLS, + _LLM_TOOLS, +) from langflow.custom import customs from langflow.interface.base import LangChainTypeCreator -from langflow.interface.tools.constants import ALL_TOOLS_NAMES, CUSTOM_TOOLS, FILE_TOOLS, OTHER_TOOLS +from langflow.interface.tools.constants import ( + ALL_TOOLS_NAMES, + CUSTOM_TOOLS, + FILE_TOOLS, + OTHER_TOOLS, +) from langflow.interface.tools.util import get_tool_params from langflow.services.deps import get_settings_service + from langflow.template.field.base import TemplateField from langflow.template.template.base import Template from langflow.utils import util -from langflow.utils.logger import logger from langflow.utils.util import build_template_from_class +from langflow.utils.logger import logger TOOL_INPUTS = { "str": TemplateField( @@ -156,11 +165,8 @@ class ToolCreator(LangChainTypeCreator): template = Template(fields=fields, type_name=tool_type) tool_params = {**tool_params, **self.type_to_loader_dict[name]["params"]} - template_dict = template.to_dict() - if "args_schema" in template_dict and template_dict.get("args_schema").get("value") == PythonInputs: - template_dict["args_schema"]["value"] = "" return { - "template": util.format_dict(template_dict), + "template": util.format_dict(template.to_dict()), **tool_params, "base_classes": base_classes, } diff --git a/src/backend/langflow/processing/base.py b/src/backend/langflow/processing/base.py index d34fb4410..06dc0a063 100644 --- a/src/backend/langflow/processing/base.py +++ b/src/backend/langflow/processing/base.py @@ -2,11 +2,10 @@ from typing import TYPE_CHECKING, List, Union from langchain.agents.agent import AgentExecutor from langchain.callbacks.base import BaseCallbackHandler -from loguru import logger - from langflow.api.v1.callback import AsyncStreamingLLMCallbackHandler, StreamingLLMCallbackHandler from langflow.processing.process import fix_memory_inputs, format_actions from langflow.services.deps import get_plugins_service +from loguru import logger if TYPE_CHECKING: from langfuse.callback import CallbackHandler # type: ignore @@ -28,9 +27,8 @@ def setup_callbacks(sync, trace_id, **kwargs): def get_langfuse_callback(trace_id): - from langfuse.callback import CreateTrace - from langflow.services.deps import get_plugins_service + from langfuse.callback import CreateTrace logger.debug("Initializing langfuse callback") if langfuse := get_plugins_service().get("langfuse"): diff --git a/src/backend/langflow/processing/process.py b/src/backend/langflow/processing/process.py index c2e153846..de0890802 100644 --- a/src/backend/langflow/processing/process.py +++ b/src/backend/langflow/processing/process.py @@ -7,12 +7,11 @@ from langchain.agents import AgentExecutor from langchain.chains.base import Chain from langchain.schema import AgentAction, Document from langchain.vectorstores.base import VectorStore -from loguru import logger -from pydantic import BaseModel - from langflow.graph import Graph from langflow.interface.run import build_sorted_vertices, get_memory_key, update_memory_keys from langflow.services.deps import get_session_service +from loguru import logger +from pydantic import BaseModel def fix_memory_inputs(langchain_object): diff --git a/src/backend/langflow/services/database/models/api_key/crud.py b/src/backend/langflow/services/database/models/api_key/crud.py index 1a487cb9e..e5c7d9ddd 100644 --- a/src/backend/langflow/services/database/models/api_key/crud.py +++ b/src/backend/langflow/services/database/models/api_key/crud.py @@ -29,7 +29,7 @@ def create_api_key(session: Session, api_key_create: ApiKeyCreate, user_id: UUID session.add(api_key) session.commit() session.refresh(api_key) - unmasked = UnmaskedApiKeyRead.model_validate(api_key) + unmasked = UnmaskedApiKeyRead.from_orm(api_key) unmasked.api_key = generated_api_key return unmasked diff --git a/src/backend/langflow/services/database/service.py b/src/backend/langflow/services/database/service.py index 199e0dc34..3610f0dea 100644 --- a/src/backend/langflow/services/database/service.py +++ b/src/backend/langflow/services/database/service.py @@ -5,17 +5,16 @@ from typing import TYPE_CHECKING import sqlalchemy as sa from alembic import command, util from alembic.config import Config -from loguru import logger -from sqlalchemy import inspect -from sqlalchemy.exc import OperationalError -from sqlmodel import Session, SQLModel, create_engine, select, text - from langflow.services.base import Service from langflow.services.database import models # noqa from langflow.services.database.models.user.crud import get_user_by_username from langflow.services.database.utils import Result, TableResults from langflow.services.deps import get_settings_service from langflow.services.utils import teardown_superuser +from loguru import logger +from sqlalchemy import inspect +from sqlalchemy.exc import OperationalError +from sqlmodel import Session, SQLModel, create_engine, select, text if TYPE_CHECKING: from sqlalchemy.engine import Engine diff --git a/src/backend/langflow/services/database/utils.py b/src/backend/langflow/services/database/utils.py index c4ab1aac6..cf2c92cb3 100644 --- a/src/backend/langflow/services/database/utils.py +++ b/src/backend/langflow/services/database/utils.py @@ -31,7 +31,11 @@ def initialize_database(fix_migration: bool = False): try: database_service.run_migrations(fix=fix_migration) except CommandError as exc: - if "Can't locate revision identified by" not in str(exc): + # if "overlaps with other requested revisions" or "Can't locate revision identified by" + # are not in the exception, we can't handle it + if "overlaps with other requested revisions" not in str( + exc + ) and "Can't locate revision identified by" not in str(exc): raise exc # This means there's wrong revision in the DB # We need to delete the alembic_version table diff --git a/src/backend/langflow/services/task/backends/anyio.py b/src/backend/langflow/services/task/backends/anyio.py index d80e10f03..49c9c0e4f 100644 --- a/src/backend/langflow/services/task/backends/anyio.py +++ b/src/backend/langflow/services/task/backends/anyio.py @@ -1,10 +1,7 @@ -import traceback from typing import Any, Callable, Optional, Tuple - import anyio -from loguru import logger - from langflow.services.task.backends.base import TaskBackend +from loguru import logger class AnyIOTaskResult: @@ -13,7 +10,6 @@ class AnyIOTaskResult: self._status = "PENDING" self._result = None self._exception = None - self._traceback = None @property def status(self) -> str: @@ -21,10 +17,6 @@ class AnyIOTaskResult: return "FAILURE" if self._exception is not None else "SUCCESS" return self._status - @property - def traceback(self) -> Optional[str]: - return self._traceback - @property def result(self) -> Any: return self._result @@ -37,7 +29,6 @@ class AnyIOTaskResult: self._result = await func(*args, **kwargs) except Exception as e: self._exception = e - self._traceback = traceback.format_exc() finally: self._status = "DONE" diff --git a/src/backend/langflow/services/utils.py b/src/backend/langflow/services/utils.py index 65781911b..850c1c683 100644 --- a/src/backend/langflow/services/utils.py +++ b/src/backend/langflow/services/utils.py @@ -1,11 +1,10 @@ -from loguru import logger -from sqlmodel import Session, select - from langflow.services.auth.utils import create_super_user, verify_password from langflow.services.database.utils import initialize_database from langflow.services.manager import service_manager from langflow.services.schema import ServiceType from langflow.services.settings.constants import DEFAULT_SUPERUSER, DEFAULT_SUPERUSER_PASSWORD +from loguru import logger +from sqlmodel import Session, select from .deps import get_db_service, get_session, get_settings_service diff --git a/src/backend/langflow/template/frontend_node/base.py b/src/backend/langflow/template/frontend_node/base.py index 33523e5cb..6379dd358 100644 --- a/src/backend/langflow/template/frontend_node/base.py +++ b/src/backend/langflow/template/frontend_node/base.py @@ -42,7 +42,7 @@ class FieldFormatters(BaseModel): class FrontendNode(BaseModel): _format_template: bool = True template: Template - description: str + description: Optional[str] = None base_classes: List[str] name: str = "" display_name: Optional[str] = "" diff --git a/src/backend/langflow/template/frontend_node/chains.py b/src/backend/langflow/template/frontend_node/chains.py index acacd1753..5ff211f68 100644 --- a/src/backend/langflow/template/frontend_node/chains.py +++ b/src/backend/langflow/template/frontend_node/chains.py @@ -87,6 +87,8 @@ class ChainFrontendNode(FrontendNode): field.required = True field.show = True field.advanced = False + field.field_type = "BaseLanguageModel" # temporary fix + field.is_list = False if key == "return_source_documents": field.required = False diff --git a/src/backend/langflow/template/frontend_node/custom_components.py b/src/backend/langflow/template/frontend_node/custom_components.py index b1d2e6156..d604ae055 100644 --- a/src/backend/langflow/template/frontend_node/custom_components.py +++ b/src/backend/langflow/template/frontend_node/custom_components.py @@ -65,5 +65,5 @@ class CustomComponentFrontendNode(FrontendNode): ) ], ) - description: str = "Create any custom component you want!" + description: Optional[str] = None base_classes: list[str] = [] diff --git a/src/backend/langflow/utils/util.py b/src/backend/langflow/utils/util.py index a73b798ff..0a348601d 100644 --- a/src/backend/langflow/utils/util.py +++ b/src/backend/langflow/utils/util.py @@ -1,14 +1,14 @@ -import importlib -import inspect import re +import inspect +import importlib from functools import wraps -from typing import Any, Dict, List, Optional, Union +from typing import List, Optional, Dict, Any, Union from docstring_parser import parse -from langchain.schema import Document from langflow.template.frontend_node.constants import FORCE_SHOW_FIELDS from langflow.utils import constants +from langchain.schema import Document def remove_ansi_escape_codes(text):