diff --git a/src/backend/langflow/components/custom_components/__init__.py b/src/backend/langflow/base/__init__.py similarity index 100% rename from src/backend/langflow/components/custom_components/__init__.py rename to src/backend/langflow/base/__init__.py diff --git a/src/backend/langflow/components/io/base/__init__.py b/src/backend/langflow/base/io/__init__.py similarity index 100% rename from src/backend/langflow/components/io/base/__init__.py rename to src/backend/langflow/base/io/__init__.py diff --git a/src/backend/langflow/components/io/base/chat.py b/src/backend/langflow/base/io/chat.py similarity index 100% rename from src/backend/langflow/components/io/base/chat.py rename to src/backend/langflow/base/io/chat.py diff --git a/src/backend/langflow/components/io/base/text.py b/src/backend/langflow/base/io/text.py similarity index 100% rename from src/backend/langflow/components/io/base/text.py rename to src/backend/langflow/base/io/text.py diff --git a/src/backend/langflow/components/documentloaders/FileLoader.py b/src/backend/langflow/components/data/FileLoader.py similarity index 100% rename from src/backend/langflow/components/documentloaders/FileLoader.py rename to src/backend/langflow/components/data/FileLoader.py diff --git a/src/backend/langflow/components/documentloaders/GatherRecords.py b/src/backend/langflow/components/data/GatherRecords.py similarity index 100% rename from src/backend/langflow/components/documentloaders/GatherRecords.py rename to src/backend/langflow/components/data/GatherRecords.py diff --git a/src/backend/langflow/components/documentloaders/UrlLoader.py b/src/backend/langflow/components/data/UrlLoader.py similarity index 91% rename from src/backend/langflow/components/documentloaders/UrlLoader.py rename to src/backend/langflow/components/data/UrlLoader.py index eb60ac572..c1346f142 100644 --- a/src/backend/langflow/components/documentloaders/UrlLoader.py +++ b/src/backend/langflow/components/data/UrlLoader.py @@ -40,7 +40,9 @@ class UrlLoaderComponent(CustomComponent): except Exception as e: raise ValueError(f"No loader found for: {web_path}") from e docs = loader_instance.load() - avg_length = sum(len(doc.page_content) for doc in docs if hasattr(doc, "page_content")) / len(docs) + avg_length = sum( + len(doc.page_content) for doc in docs if hasattr(doc, "page_content") + ) / len(docs) self.status = f"""{len(docs)} documents) \nAvg. Document Length (characters): {int(avg_length)} Documents: {docs[:3]}...""" diff --git a/src/backend/langflow/components/data/__init__.py b/src/backend/langflow/components/data/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/backend/langflow/components/io/ChatInput.py b/src/backend/langflow/components/inputs/ChatInput.py similarity index 92% rename from src/backend/langflow/components/io/ChatInput.py rename to src/backend/langflow/components/inputs/ChatInput.py index de8ce14cb..e5867751c 100644 --- a/src/backend/langflow/components/io/ChatInput.py +++ b/src/backend/langflow/components/inputs/ChatInput.py @@ -1,6 +1,6 @@ from typing import Optional, Union -from langflow.components.io.base.chat import ChatComponent +from langflow.base.io.chat import ChatComponent from langflow.field_typing import Text from langflow.schema import Record diff --git a/src/backend/langflow/components/io/TextInput.py b/src/backend/langflow/components/inputs/TextInput.py similarity index 84% rename from src/backend/langflow/components/io/TextInput.py rename to src/backend/langflow/components/inputs/TextInput.py index dc7ff1a73..034cf527b 100644 --- a/src/backend/langflow/components/io/TextInput.py +++ b/src/backend/langflow/components/inputs/TextInput.py @@ -1,6 +1,6 @@ from typing import Optional -from langflow.components.io.base.text import TextComponent +from langflow.base.io.text import TextComponent from langflow.field_typing import Text diff --git a/src/backend/langflow/components/inputs/__init__.py b/src/backend/langflow/components/inputs/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/backend/langflow/components/utilities/BingSearchAPIWrapper.py b/src/backend/langflow/components/langchain_utilities/BingSearchAPIWrapper.py similarity index 100% rename from src/backend/langflow/components/utilities/BingSearchAPIWrapper.py rename to src/backend/langflow/components/langchain_utilities/BingSearchAPIWrapper.py diff --git a/src/backend/langflow/components/utilities/DocumentToRecord.py b/src/backend/langflow/components/langchain_utilities/DocumentToRecord.py similarity index 100% rename from src/backend/langflow/components/utilities/DocumentToRecord.py rename to src/backend/langflow/components/langchain_utilities/DocumentToRecord.py diff --git a/src/backend/langflow/components/utilities/GoogleSearchAPIWrapper.py b/src/backend/langflow/components/langchain_utilities/GoogleSearchAPIWrapper.py similarity index 100% rename from src/backend/langflow/components/utilities/GoogleSearchAPIWrapper.py rename to src/backend/langflow/components/langchain_utilities/GoogleSearchAPIWrapper.py diff --git a/src/backend/langflow/components/utilities/GoogleSerperAPIWrapper.py b/src/backend/langflow/components/langchain_utilities/GoogleSerperAPIWrapper.py similarity index 100% rename from src/backend/langflow/components/utilities/GoogleSerperAPIWrapper.py rename to src/backend/langflow/components/langchain_utilities/GoogleSerperAPIWrapper.py diff --git a/src/backend/langflow/components/utilities/JSONDocumentBuilder.py b/src/backend/langflow/components/langchain_utilities/JSONDocumentBuilder.py similarity index 100% rename from src/backend/langflow/components/utilities/JSONDocumentBuilder.py rename to src/backend/langflow/components/langchain_utilities/JSONDocumentBuilder.py diff --git a/src/backend/langflow/components/utilities/SQLDatabase.py b/src/backend/langflow/components/langchain_utilities/SQLDatabase.py similarity index 100% rename from src/backend/langflow/components/utilities/SQLDatabase.py rename to src/backend/langflow/components/langchain_utilities/SQLDatabase.py diff --git a/src/backend/langflow/components/utilities/SearxSearchWrapper.py b/src/backend/langflow/components/langchain_utilities/SearxSearchWrapper.py similarity index 100% rename from src/backend/langflow/components/utilities/SearxSearchWrapper.py rename to src/backend/langflow/components/langchain_utilities/SearxSearchWrapper.py diff --git a/src/backend/langflow/components/utilities/SerpAPIWrapper.py b/src/backend/langflow/components/langchain_utilities/SerpAPIWrapper.py similarity index 100% rename from src/backend/langflow/components/utilities/SerpAPIWrapper.py rename to src/backend/langflow/components/langchain_utilities/SerpAPIWrapper.py diff --git a/src/backend/langflow/components/utilities/WikipediaAPIWrapper.py b/src/backend/langflow/components/langchain_utilities/WikipediaAPIWrapper.py similarity index 100% rename from src/backend/langflow/components/utilities/WikipediaAPIWrapper.py rename to src/backend/langflow/components/langchain_utilities/WikipediaAPIWrapper.py diff --git a/src/backend/langflow/components/utilities/WolframAlphaAPIWrapper.py b/src/backend/langflow/components/langchain_utilities/WolframAlphaAPIWrapper.py similarity index 100% rename from src/backend/langflow/components/utilities/WolframAlphaAPIWrapper.py rename to src/backend/langflow/components/langchain_utilities/WolframAlphaAPIWrapper.py diff --git a/src/backend/langflow/components/io/ChatOutput.py b/src/backend/langflow/components/outputs/ChatOutput.py similarity index 92% rename from src/backend/langflow/components/io/ChatOutput.py rename to src/backend/langflow/components/outputs/ChatOutput.py index a528b65b8..aa61159c9 100644 --- a/src/backend/langflow/components/io/ChatOutput.py +++ b/src/backend/langflow/components/outputs/ChatOutput.py @@ -1,6 +1,6 @@ from typing import Optional, Union -from langflow.components.io.base.chat import ChatComponent +from langflow.base.io.chat import ChatComponent from langflow.field_typing import Text from langflow.schema import Record diff --git a/src/backend/langflow/components/io/TextOutput.py b/src/backend/langflow/components/outputs/TextOutput.py similarity index 87% rename from src/backend/langflow/components/io/TextOutput.py rename to src/backend/langflow/components/outputs/TextOutput.py index f92e09146..c971a9699 100644 --- a/src/backend/langflow/components/io/TextOutput.py +++ b/src/backend/langflow/components/outputs/TextOutput.py @@ -1,6 +1,6 @@ from typing import Optional -from langflow.components.io.base.text import TextComponent +from langflow.base.io.text import TextComponent from langflow.field_typing import Text diff --git a/src/backend/langflow/components/outputs/__init__.py b/src/backend/langflow/components/outputs/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/backend/langflow/components/utilities/APIRequest.py b/src/backend/langflow/components/utilities/APIRequest.py new file mode 100644 index 000000000..2e73979ff --- /dev/null +++ b/src/backend/langflow/components/utilities/APIRequest.py @@ -0,0 +1,109 @@ +import asyncio +from typing import List, Optional, Union +import httpx + +import requests + +from langflow import CustomComponent +from langflow.schema import Record +from langflow.services.database.models.base import orjson_dumps + + +class APIRequest(CustomComponent): + display_name: str = "API Request" + description: str = "Make an HTTP request to the given URL." + output_types: list[str] = ["Record"] + documentation: str = "https://docs.langflow.org/components/utilities#api-request" + beta: bool = True + field_config = { + "url": {"display_name": "URL", "info": "The URL to make the request to."}, + "method": { + "display_name": "Method", + "info": "The HTTP method to use.", + "field_type": "str", + "options": ["GET", "POST", "PATCH", "PUT"], + "value": "GET", + }, + "headers": { + "display_name": "Headers", + "info": "The headers to send with the request.", + }, + "record": { + "display_name": "Record", + "info": "The record to send with the request (for POST, PATCH, PUT).", + }, + "timeout": { + "display_name": "Timeout", + "field_type": "int", + "info": "The timeout to use for the request.", + "value": 5, + }, + } + + async def make_request( + self, + session: requests.Session, + method: str, + url: str, + headers: Optional[dict] = None, + record: Optional[Record] = None, + timeout: int = 5, + ) -> Record: + method = method.upper() + if method not in ["GET", "POST", "PATCH", "PUT"]: + raise ValueError(f"Unsupported method: {method}") + + data = record.text if record else None + try: + async with httpx.AsyncClient() as client: + response = await client.request( + method, url, headers=headers, content=data, timeout=timeout + ) + try: + response_json = response.json() + result = orjson_dumps(response_json, indent_2=False) + except Exception: + result = response.text + return Record( + text=result, + data={ + "source": url, + "headers": headers, + "status_code": response.status_code, + }, + ) + except httpx.TimeoutException: + return Record( + text="Request Timed Out", + data={"source": url, "headers": headers, "status_code": 408}, + ) + except Exception as exc: + return Record( + text=str(exc), + data={"source": url, "headers": headers, "status_code": 500}, + ) + + async def build( + self, + method: str, + url: List[str], + headers: Optional[dict] = None, + record: Optional[Union[Record, List[Record]]] = None, + timeout: int = 5, + ) -> List[Record]: + if headers is None: + headers = {} + urls = url if isinstance(url, list) else [url] + records = ( + record + if isinstance(record, list) + else [record] if record else [None] * len(urls) + ) + + results = await asyncio.gather( + *[ + self.make_request(method, u, headers, doc, timeout) + for u, doc in zip(urls, records) + ] + ) + return results diff --git a/src/backend/langflow/components/custom_components/CustomComponent.py b/src/backend/langflow/components/utilities/CustomComponent.py similarity index 91% rename from src/backend/langflow/components/custom_components/CustomComponent.py rename to src/backend/langflow/components/utilities/CustomComponent.py index 533ccb727..c45b5effd 100644 --- a/src/backend/langflow/components/custom_components/CustomComponent.py +++ b/src/backend/langflow/components/utilities/CustomComponent.py @@ -4,6 +4,7 @@ from langflow.field_typing import Data class Component(CustomComponent): documentation: str = "http://docs.langflow.org/components/custom" + icon = "custom_components" def build_config(self): return {"param": {"display_name": "Parameter"}} diff --git a/src/backend/langflow/components/utilities/GetRequest.py b/src/backend/langflow/components/utilities/GetRequest.py deleted file mode 100644 index d6ee5a44f..000000000 --- a/src/backend/langflow/components/utilities/GetRequest.py +++ /dev/null @@ -1,75 +0,0 @@ -from typing import Optional, Text - -import requests -from langchain_core.documents import Document - -from langflow import CustomComponent -from langflow.services.database.models.base import orjson_dumps - - -class GetRequest(CustomComponent): - display_name: str = "GET Request" - description: str = "Make a GET request to the given URL." - output_types: list[str] = ["Document"] - documentation: str = "https://docs.langflow.org/components/utilities#get-request" - beta: bool = True - field_config = { - "url": { - "display_name": "URL", - "info": "The URL to make the request to", - "is_list": True, - }, - "headers": { - "display_name": "Headers", - "info": "The headers to send with the request.", - }, - "code": {"show": False}, - "timeout": { - "display_name": "Timeout", - "field_type": "int", - "info": "The timeout to use for the request.", - "value": 5, - }, - } - - def get_document(self, session: requests.Session, url: str, headers: Optional[dict], timeout: int) -> Document: - try: - response = session.get(url, headers=headers, timeout=int(timeout)) - try: - response_json = response.json() - result = orjson_dumps(response_json, indent_2=False) - except Exception: - result = response.text - self.repr_value = result - return Document( - page_content=result, - metadata={ - "source": url, - "headers": headers, - "status_code": response.status_code, - }, - ) - except requests.Timeout: - return Document( - page_content="Request Timed Out", - metadata={"source": url, "headers": headers, "status_code": 408}, - ) - except Exception as exc: - return Document( - page_content=Text(exc), - metadata={"source": url, "headers": headers, "status_code": 500}, - ) - - def build( - self, - url: str, - headers: Optional[dict] = None, - timeout: int = 5, - ) -> list[Document]: - if headers is None: - headers = {} - urls = url if isinstance(url, list) else [url] - with requests.Session() as session: - documents = [self.get_document(session, u, headers, timeout) for u in urls] - self.repr_value = documents - return documents diff --git a/src/backend/langflow/components/utilities/PostRequest.py b/src/backend/langflow/components/utilities/PostRequest.py deleted file mode 100644 index befc006c8..000000000 --- a/src/backend/langflow/components/utilities/PostRequest.py +++ /dev/null @@ -1,78 +0,0 @@ -from typing import Optional, Text - -import requests -from langchain_core.documents import Document - -from langflow import CustomComponent -from langflow.services.database.models.base import orjson_dumps - - -class PostRequest(CustomComponent): - display_name: str = "POST Request" - description: str = "Make a POST request to the given URL." - output_types: list[str] = ["Document"] - documentation: str = "https://docs.langflow.org/components/utilities#post-request" - beta: bool = True - field_config = { - "url": {"display_name": "URL", "info": "The URL to make the request to."}, - "headers": { - "display_name": "Headers", - "info": "The headers to send with the request.", - }, - "code": {"show": False}, - "document": {"display_name": "Document"}, - } - - def post_document( - self, - session: requests.Session, - document: Document, - url: str, - headers: Optional[dict] = None, - ) -> Document: - try: - response = session.post(url, headers=headers, data=document.page_content) - try: - response_json = response.json() - result = orjson_dumps(response_json, indent_2=False) - except Exception: - result = response.text - self.repr_value = result - return Document( - page_content=result, - metadata={ - "source": url, - "headers": headers, - "status_code": response, - }, - ) - except Exception as exc: - return Document( - page_content=Text(exc), - metadata={ - "source": url, - "headers": headers, - "status_code": 500, - }, - ) - - def build( - self, - document: Document, - url: str, - headers: Optional[dict] = None, - ) -> list[Document]: - if headers is None: - headers = {} - - if not isinstance(document, list) and isinstance(document, Document): - documents: list[Document] = [document] - elif isinstance(document, list) and all(isinstance(doc, Document) for doc in document): - documents = document - else: - raise ValueError("document must be a Document or a list of Documents") - - with requests.Session() as session: - documents = [self.post_document(session, doc, url, headers) for doc in documents] - self.repr_value = documents - return documents diff --git a/src/backend/langflow/components/utilities/UpdateRequest.py b/src/backend/langflow/components/utilities/UpdateRequest.py deleted file mode 100644 index 41a57eda6..000000000 --- a/src/backend/langflow/components/utilities/UpdateRequest.py +++ /dev/null @@ -1,89 +0,0 @@ -from typing import List, Optional, Text - -import requests -from langchain_core.documents import Document - -from langflow import CustomComponent -from langflow.services.database.models.base import orjson_dumps - - -class UpdateRequest(CustomComponent): - display_name: str = "Update Request" - description: str = "Make a PATCH request to the given URL." - output_types: list[str] = ["Document"] - documentation: str = "https://docs.langflow.org/components/utilities#update-request" - beta: bool = True - field_config = { - "url": {"display_name": "URL", "info": "The URL to make the request to."}, - "headers": { - "display_name": "Headers", - "field_type": "NestedDict", - "info": "The headers to send with the request.", - }, - "code": {"show": False}, - "document": {"display_name": "Document"}, - "method": { - "display_name": "Method", - "field_type": "str", - "info": "The HTTP method to use.", - "options": ["PATCH", "PUT"], - "value": "PATCH", - }, - } - - def update_document( - self, - session: requests.Session, - document: Document, - url: str, - headers: Optional[dict] = None, - method: str = "PATCH", - ) -> Document: - try: - if method == "PATCH": - response = session.patch(url, headers=headers, data=document.page_content) - elif method == "PUT": - response = session.put(url, headers=headers, data=document.page_content) - else: - raise ValueError(f"Unsupported method: {method}") - try: - response_json = response.json() - result = orjson_dumps(response_json, indent_2=False) - except Exception: - result = response.text - self.repr_value = result - return Document( - page_content=result, - metadata={ - "source": url, - "headers": headers, - "status_code": response.status_code, - }, - ) - except Exception as exc: - return Document( - page_content=Text(exc), - metadata={"source": url, "headers": headers, "status_code": 500}, - ) - - def build( - self, - method: str, - document: Document, - url: str, - headers: Optional[dict] = None, - ) -> List[Document]: - if headers is None: - headers = {} - - if not isinstance(document, list) and isinstance(document, Document): - documents: list[Document] = [document] - elif isinstance(document, list) and all(isinstance(doc, Document) for doc in document): - documents = document - else: - raise ValueError("document must be a Document or a list of Documents") - - with requests.Session() as session: - documents = [self.update_document(session, doc, url, headers, method) for doc in documents] - self.repr_value = documents - return documents diff --git a/src/backend/langflow/components/utilities/__init__.py b/src/backend/langflow/components/utilities/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx index fe78895c0..299507bbd 100644 --- a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx @@ -26,6 +26,7 @@ import { } from "../../../../utils/utils"; import DisclosureComponent from "../DisclosureComponent"; import SidebarDraggableComponent from "./sideBarDraggableComponent"; +import { sortKeys } from "./utils"; export default function ExtraSidebar(): JSX.Element { const data = useTypesStore((state) => state.data); @@ -320,19 +321,7 @@ export default function ExtraSidebar(): JSX.Element {