Update dependencies and refactor import statements (#1435)

This pull request updates the python-multipart version, updates the
dependencies in pyproject.toml, adds Python 3.11 support to lint and
test workflows, and refactors import statements in Qdrant.py.
This commit is contained in:
Gabriel Luiz Freitas Almeida 2024-02-15 18:33:08 -03:00 committed by GitHub
commit b9ad74cf4e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 1315 additions and 1150 deletions

View file

@ -2,13 +2,12 @@ import asyncio
from typing import Any, Dict, List, Optional
from uuid import UUID
from langchain.callbacks.base import AsyncCallbackHandler, BaseCallbackHandler
from langchain.schema import AgentAction, AgentFinish
from loguru import logger
from langchain_core.callbacks.base import AsyncCallbackHandler, BaseCallbackHandler
from langflow.api.v1.schemas import ChatResponse, PromptResponse
from langflow.services.deps import get_chat_service
from langflow.utils.util import remove_ansi_escape_codes
from loguru import logger
# https://github.com/hwchase17/chat-langchain/blob/master/callback.py

View file

@ -1,10 +1,8 @@
from langflow import CustomComponent
from typing import Callable, Union
from langchain.chains import LLMCheckerChain
from typing import Union, Callable
from langflow.field_typing import (
BaseLanguageModel,
Chain,
)
from langflow import CustomComponent
from langflow.field_typing import BaseLanguageModel, Chain
class LLMCheckerChainComponent(CustomComponent):
@ -21,4 +19,4 @@ class LLMCheckerChainComponent(CustomComponent):
self,
llm: BaseLanguageModel,
) -> Union[Chain, Callable]:
return LLMCheckerChain(llm=llm)
return LLMCheckerChain.from_llm(llm=llm)

View file

@ -1,6 +1,8 @@
from langflow import CustomComponent
from typing import Any, Dict, List
from langchain.docstore.document import Document
from typing import Optional, Dict, Any
from langchain.document_loaders.directory import DirectoryLoader
from langflow import CustomComponent
class DirectoryLoaderComponent(CustomComponent):
@ -23,20 +25,18 @@ class DirectoryLoaderComponent(CustomComponent):
self,
glob: str,
path: str,
load_hidden: Optional[bool] = False,
max_concurrency: Optional[int] = 10,
metadata: Optional[dict] = {},
recursive: Optional[bool] = True,
silent_errors: Optional[bool] = False,
use_multithreading: Optional[bool] = True,
) -> Document:
return Document(
max_concurrency: int = 2,
load_hidden: bool = False,
recursive: bool = True,
silent_errors: bool = False,
use_multithreading: bool = True,
) -> List[Document]:
return DirectoryLoader(
glob=glob,
path=path,
load_hidden=load_hidden,
max_concurrency=max_concurrency,
metadata=metadata,
recursive=recursive,
silent_errors=silent_errors,
use_multithreading=use_multithreading,
)
).load()

View file

@ -1,14 +1,14 @@
from langflow import CustomComponent
from typing import Optional, Dict
from typing import Dict, Optional
from langchain_community.embeddings.huggingface import HuggingFaceInferenceAPIEmbeddings
from langflow import CustomComponent
from pydantic.v1.types import SecretStr
class HuggingFaceInferenceAPIEmbeddingsComponent(CustomComponent):
display_name = "HuggingFaceInferenceAPIEmbeddings"
description = "HuggingFace sentence_transformers embedding models, API version."
documentation = (
"https://github.com/huggingface/text-embeddings-inference"
)
documentation = "https://github.com/huggingface/text-embeddings-inference"
def build_config(self):
return {
@ -31,12 +31,12 @@ class HuggingFaceInferenceAPIEmbeddingsComponent(CustomComponent):
model_kwargs: Optional[Dict] = {},
multi_process: bool = False,
) -> HuggingFaceInferenceAPIEmbeddings:
if api_key:
secret_api_key = SecretStr(api_key)
else:
raise ValueError("API Key is required")
return HuggingFaceInferenceAPIEmbeddings(
api_key=api_key,
api_key=secret_api_key,
api_url=api_url,
model_name=model_name,
cache_folder=cache_folder,
encode_kwargs=encode_kwargs,
model_kwargs=model_kwargs,
multi_process=multi_process,
)

View file

@ -1,9 +1,9 @@
from typing import Any, Callable, Dict, List, Optional, Union
from langchain_openai.embeddings.base import OpenAIEmbeddings
from langflow import CustomComponent
from langflow.field_typing import NestedDict
from pydantic.v1.types import SecretStr
class OpenAIEmbeddingsComponent(CustomComponent):
@ -67,7 +67,7 @@ class OpenAIEmbeddingsComponent(CustomComponent):
},
"skip_empty": {"display_name": "Skip Empty", "advanced": True},
"tiktoken_model_name": {"display_name": "TikToken Model Name"},
"tikToken_enable": {"display_name": "TikToken Enable"},
"tikToken_enable": {"display_name": "TikToken Enable", "advanced": True},
}
def build(
@ -92,14 +92,17 @@ class OpenAIEmbeddingsComponent(CustomComponent):
request_timeout: Optional[float] = None,
show_progress_bar: bool = False,
skip_empty: bool = False,
tikToken_enable: bool = True,
tiktoken_enable: bool = True,
tiktoken_model_name: Optional[str] = None,
) -> Union[OpenAIEmbeddings, Callable]:
# This is to avoid errors with Vector Stores (e.g Chroma)
if disallowed_special == ["all"]:
disallowed_special = "all"
disallowed_special = "all" # type: ignore
api_key = SecretStr(openai_api_key) if openai_api_key else None
return OpenAIEmbeddings(
tiktoken_enabled=tikToken_enable,
tiktoken_enabled=tiktoken_enable,
default_headers=default_headers,
default_query=default_query,
allowed_special=set(allowed_special),
@ -112,7 +115,7 @@ class OpenAIEmbeddingsComponent(CustomComponent):
model=model,
model_kwargs=model_kwargs,
base_url=openai_api_base,
api_key=openai_api_key,
api_key=api_key,
openai_api_type=openai_api_type,
api_version=openai_api_version,
organization=openai_organization,

View file

@ -1,4 +1,4 @@
from pydantic import SecretStr
from pydantic.v1.types import SecretStr
from langflow import CustomComponent
from typing import Optional, Union, Callable
from langflow.field_typing import BaseLanguageModel

View file

@ -1,9 +1,9 @@
from typing import Optional
from langchain_google_genai import ChatGoogleGenerativeAI # type: ignore
from langflow import CustomComponent
from langflow.field_typing import BaseLanguageModel, RangeSpec, TemplateField
from pydantic.v1.types import SecretStr
class GoogleGenerativeAIComponent(CustomComponent):
@ -63,10 +63,10 @@ class GoogleGenerativeAIComponent(CustomComponent):
) -> BaseLanguageModel:
return ChatGoogleGenerativeAI(
model=model,
max_output_tokens=max_output_tokens or None,
max_output_tokens=max_output_tokens or None, # type: ignore
temperature=temperature,
top_k=top_k or None,
top_p=top_p or None,
top_p=top_p or None, # type: ignore
n=n or 1,
google_api_key=google_api_key,
google_api_key=SecretStr(google_api_key),
)

View file

@ -1,8 +1,7 @@
from langchain_community.agent_toolkits.openapi.toolkit import BaseToolkit, OpenAPIToolkit
from langchain_community.utilities.requests import TextRequestsWrapper
from langflow import CustomComponent
from langflow.field_typing import AgentExecutor
from typing import Callable
from langchain_community.utilities.requests import TextRequestsWrapper
from langchain_community.agent_toolkits.openapi.toolkit import OpenAPIToolkit
class OpenAPIToolkitComponent(CustomComponent):
@ -19,5 +18,5 @@ class OpenAPIToolkitComponent(CustomComponent):
self,
json_agent: AgentExecutor,
requests_wrapper: TextRequestsWrapper,
) -> Callable:
) -> BaseToolkit:
return OpenAPIToolkit(json_agent=json_agent, requests_wrapper=requests_wrapper)

View file

@ -1,6 +1,7 @@
from langflow import CustomComponent
from typing import Union, Callable
from typing import Callable, Union
from langchain_community.utilities.google_search import GoogleSearchAPIWrapper
from langflow import CustomComponent
class GoogleSearchAPIWrapperComponent(CustomComponent):
@ -18,4 +19,4 @@ class GoogleSearchAPIWrapperComponent(CustomComponent):
google_api_key: str,
google_cse_id: str,
) -> Union[GoogleSearchAPIWrapper, Callable]:
return GoogleSearchAPIWrapper(google_api_key=google_api_key, google_cse_id=google_cse_id)
return GoogleSearchAPIWrapper(google_api_key=google_api_key, google_cse_id=google_cse_id) # type: ignore

View file

@ -1,9 +1,9 @@
from langflow import CustomComponent
from typing import Dict, Optional
from typing import Dict
# Assuming the existence of GoogleSerperAPIWrapper class in the serper module
# If this class does not exist, you would need to create it or import the appropriate class from another module
from langchain_community.utilities.google_serper import GoogleSerperAPIWrapper
from langflow import CustomComponent
class GoogleSerperAPIWrapperComponent(CustomComponent):
@ -42,6 +42,5 @@ class GoogleSerperAPIWrapperComponent(CustomComponent):
def build(
self,
serper_api_key: str,
result_key_for_type: Optional[Dict[str, str]] = None,
) -> GoogleSerperAPIWrapper:
return GoogleSerperAPIWrapper(result_key_for_type=result_key_for_type, serper_api_key=serper_api_key)
return GoogleSerperAPIWrapper(serper_api_key=serper_api_key)

View file

@ -5,7 +5,6 @@ import pinecone # type: ignore
from langchain.schema import BaseRetriever
from langchain_community.vectorstores import VectorStore
from langchain_community.vectorstores.pinecone import Pinecone
from langflow import CustomComponent
from langflow.field_typing import Document, Embeddings
@ -31,11 +30,11 @@ class PineconeComponent(CustomComponent):
embedding: Embeddings,
pinecone_env: str,
documents: List[Document],
text_key: str = "text",
pool_threads: int = 4,
index_name: Optional[str] = None,
pinecone_api_key: Optional[str] = None,
text_key: Optional[str] = "text",
namespace: Optional[str] = "default",
pool_threads: Optional[int] = None,
) -> Union[VectorStore, Pinecone, BaseRetriever]:
if pinecone_api_key is None or pinecone_env is None:
raise ValueError("Pinecone API Key and Environment are required.")
@ -43,6 +42,8 @@ class PineconeComponent(CustomComponent):
raise ValueError("Pinecone API Key is required.")
pinecone.init(api_key=pinecone_api_key, environment=pinecone_env) # type: ignore
if not index_name:
raise ValueError("Index Name is required.")
if documents:
return Pinecone.from_documents(
documents=documents,

View file

@ -1,4 +1,4 @@
from typing import List, Optional, Union
from typing import Optional, Union
from langchain.schema import BaseRetriever
from langchain_community.vectorstores import VectorStore
@ -36,14 +36,14 @@ class QdrantComponent(CustomComponent):
def build(
self,
embedding: Embeddings,
collection_name: str,
documents: Optional[Document] = None,
api_key: Optional[str] = None,
collection_name: Optional[str] = None,
content_payload_key: str = "page_content",
distance_func: str = "Cosine",
grpc_port: Optional[int] = 6334,
host: Optional[str] = None,
grpc_port: int = 6334,
https: bool = False,
host: Optional[str] = None,
location: Optional[str] = None,
metadata_payload_key: str = "metadata",
path: Optional[str] = None,
@ -51,14 +51,15 @@ class QdrantComponent(CustomComponent):
prefer_grpc: bool = False,
prefix: Optional[str] = None,
search_kwargs: Optional[NestedDict] = None,
timeout: Optional[float] = None,
timeout: Optional[int] = None,
url: Optional[str] = None,
) -> Union[VectorStore, Qdrant, BaseRetriever]:
if documents is None:
from qdrant_client import QdrantClient
client = QdrantClient(
location=location,
url=host,
url=host,
port=port,
grpc_port=grpc_port,
https=https,
@ -71,17 +72,16 @@ class QdrantComponent(CustomComponent):
collection_name=collection_name,
host=host,
path=path,
)
vs = Qdrant(client=client,
collection_name=collection_name,
embeddings=embedding,
search_kwargs=search_kwargs,
distance_func=distance_func,
)
)
vs = Qdrant(
client=client,
collection_name=collection_name,
embeddings=embedding,
)
return vs
else:
vs = Qdrant.from_documents(
documents=documents,
documents=documents, # type: ignore
embedding=embedding,
api_key=api_key,
collection_name=collection_name,
@ -99,5 +99,5 @@ class QdrantComponent(CustomComponent):
search_kwargs=search_kwargs,
timeout=timeout,
url=url,
)
)
return vs

View file

@ -5,7 +5,6 @@ from langchain_community.vectorstores import VectorStore
from langchain_community.vectorstores.redis import Redis
from langchain_core.documents import Document
from langchain_core.retrievers import BaseRetriever
from langflow import CustomComponent
@ -31,6 +30,7 @@ class RedisComponent(CustomComponent):
"code": {"show": False, "display_name": "Code"},
"documents": {"display_name": "Documents", "is_list": True},
"embedding": {"display_name": "Embedding"},
"schema": {"display_name": "Schema", "file_types": [".yaml"]},
"redis_server_url": {
"display_name": "Redis Server Connection String",
"advanced": False,
@ -43,6 +43,7 @@ class RedisComponent(CustomComponent):
embedding: Embeddings,
redis_server_url: str,
redis_index_name: str,
schema: Optional[str] = None,
documents: Optional[Document] = None,
) -> Union[VectorStore, BaseRetriever]:
"""
@ -58,10 +59,12 @@ class RedisComponent(CustomComponent):
- VectorStore: The Vector Store object.
"""
if documents is None:
if schema is None:
raise ValueError("If no documents are provided, a schema must be provided.")
redis_vs = Redis.from_existing_index(
embedding=embedding,
index_name=redis_index_name,
schema=None,
schema=schema,
key_prefix=None,
redis_url=redis_server_url,
)

View file

@ -6,7 +6,6 @@ from typing import List, Optional, Union
from langchain_community.embeddings import FakeEmbeddings
from langchain_community.vectorstores.vectara import Vectara
from langchain_core.vectorstores import VectorStore
from langflow import CustomComponent
from langflow.field_typing import BaseRetriever, Document
@ -46,7 +45,7 @@ class VectaraComponent(CustomComponent):
if documents is not None:
return Vectara.from_documents(
documents=documents,
documents=documents, # type: ignore
embedding=FakeEmbeddings(size=768),
vectara_customer_id=vectara_customer_id,
vectara_corpus_id=vectara_corpus_id,

View file

@ -5,7 +5,6 @@ from langchain_community.vectorstores import VectorStore
from langchain_community.vectorstores.pgvector import PGVector
from langchain_core.documents import Document
from langchain_core.retrievers import BaseRetriever
from langflow import CustomComponent
@ -63,13 +62,13 @@ class PGVectorComponent(CustomComponent):
collection_name=collection_name,
connection_string=pg_server_url,
)
vector_store = PGVector.from_documents(
embedding=embedding,
documents=documents,
collection_name=collection_name,
connection_string=pg_server_url,
)
else:
vector_store = PGVector.from_documents(
embedding=embedding,
documents=documents, # type: ignore
collection_name=collection_name,
connection_string=pg_server_url,
)
except Exception as e:
raise RuntimeError(f"Failed to build PGVector: {e}")
return vector_store

View file

@ -36,7 +36,7 @@ class Component:
setattr(self, key, value)
# Validate the emoji at the icon field
if self.icon:
if hasattr(self, "icon") and self.icon:
self.icon = self.validate_icon(self.icon)
def __setattr__(self, key, value):

View file

@ -7,8 +7,6 @@ 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 langflow.processing.process import fix_memory_inputs, format_actions
from langflow.services.deps import get_plugins_service
if TYPE_CHECKING:
from langfuse.callback import CallbackHandler # type: ignore

View file

@ -7,16 +7,20 @@ import {
DropdownMenuTrigger,
} from "../../../ui/dropdown-menu";
import { useNavigate, useParams } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import { Node } from "reactflow";
import FlowSettingsModal from "../../../../modals/flowSettingsModal";
import useAlertStore from "../../../../stores/alertStore";
import useFlowStore from "../../../../stores/flowStore";
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
import IconComponent from "../../../genericIconComponent";
import { Button } from "../../../ui/button";
import { Node } from "reactflow";
import useFlowStore from "../../../../stores/flowStore";
export const MenuBar = ({removeFunction}: {removeFunction: (nodes: Node[]) => void}): JSX.Element => {
export const MenuBar = ({
removeFunction,
}: {
removeFunction: (nodes: Node[]) => void;
}): JSX.Element => {
const addFlow = useFlowsManagerStore((state) => state.addFlow);
const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
const setErrorData = useAlertStore((state) => state.setErrorData);
@ -42,7 +46,7 @@ export const MenuBar = ({removeFunction}: {removeFunction: (nodes: Node[]) => vo
<div className="round-button-div">
<button
onClick={() => {
removeFunction(n)
removeFunction(n);
navigate(-1);
}}
>

View file

@ -5,8 +5,11 @@ import AlertDropdown from "../../alerts/alertDropDown";
import { USER_PROJECTS_HEADER } from "../../constants/constants";
import { AuthContext } from "../../contexts/authContext";
import { Node } from "reactflow";
import useAlertStore from "../../stores/alertStore";
import { useDarkStore } from "../../stores/darkStore";
import useFlowStore from "../../stores/flowStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
import { useStoreStore } from "../../stores/storeStore";
import { gradients } from "../../utils/styleUtils";
import IconComponent from "../genericIconComponent";
@ -21,9 +24,6 @@ import {
} from "../ui/dropdown-menu";
import { Separator } from "../ui/separator";
import MenuBar from "./components/menuBar";
import useFlowsManagerStore from "../../stores/flowsManagerStore";
import useFlowStore from "../../stores/flowStore";
import { Node } from "reactflow";
export default function Header(): JSX.Element {
const notificationCenter = useAlertStore((state) => state.notificationCenter);
@ -32,7 +32,7 @@ export default function Header(): JSX.Element {
const navigate = useNavigate();
const removeFlow = useFlowsManagerStore((store) => store.removeFlow);
const hasStore = useStoreStore((state) => state.hasStore);
const {id} = useParams();
const { id } = useParams();
const n = useFlowStore((state) => state.nodes);
const dark = useDarkStore((state) => state.dark);
@ -50,7 +50,7 @@ export default function Header(): JSX.Element {
async function checkForChanges(nodes: Node[]): Promise<void> {
if (nodes.length === 0) {
await removeFlow(id!)
await removeFlow(id!);
}
}
@ -73,7 +73,9 @@ export default function Header(): JSX.Element {
: "secondary"
}
size="sm"
onClick={() => {checkForChanges(n)}}
onClick={() => {
checkForChanges(n);
}}
>
<IconComponent name="Home" className="h-4 w-4" />
<div className="hidden flex-1 md:block">{USER_PROJECTS_HEADER}</div>
@ -97,7 +99,9 @@ export default function Header(): JSX.Element {
className="gap-2"
variant={location.pathname === "/store" ? "primary" : "secondary"}
size="sm"
onClick={() => {checkForChanges(n)}}
onClick={() => {
checkForChanges(n);
}}
>
<IconComponent name="Store" className="h-4 w-4" />
<div className="flex-1">Store</div>

View file

@ -37,7 +37,6 @@ import {
createRandomKey,
getFieldTitle,
getRandomDescription,
getRandomName,
toTitleCase,
} from "./utils";
const uid = new ShortUniqueId({ length: 5 });