🔧 chore(docs): update custom-component.mdx

🐛 fix(custom-component.mdx): change class name from BestComponent to DocumentProcessor to improve semantics and clarity
✨ feat(custom-component.mdx): add support for processing the page content of a document based on a selected function
📝 docs(custom-component.mdx): update example and explanations to reflect the changes made in the code

🐛 fix(custom-component.mdx): fix code indentation and remove unused imports
✨ feat(custom-component.mdx): update component name and description to improve clarity and semantics
🐛 fix(custom-component.mdx): update build method parameters and return type to match the actual implementation
✨ feat(custom-component.mdx): add support for configuring fields in the build_config method
🐛 fix(custom-component.mdx): fix code indentation and remove unused imports in the build_config method
✨ feat(custom-component.mdx): add support for configuring fields in the build_config method
This commit is contained in:
Gabriel Luiz Freitas Almeida 2023-07-28 09:30:56 -03:00
commit 28cebb2d39

View file

@ -26,29 +26,28 @@ Here is an example:
```python ```python
from langflow import CustomComponent from langflow import CustomComponent
from langchain.chains import LLMChain from langchain.schema import Document
from langchain.chains.base import Chain
from langchain import PromptTemplate
from langchain.llms.base import BaseLLM
from langchain import Tool
class BestComponent(CustomComponent): class DocumentProcessor(CustomComponent):
display_name = "Best Component" display_name = "Document Processor"
description = "This is the best component ever" description = "This component processes a document"
def build_config(self) -> dict: def build_config(self) -> dict:
cool_tool_names = ["Cool Tool", options = ["Uppercase", "Lowercase", "Titlecase"]
"Cooler Tool",
"Coolest Tool"]
return { return {
"description": {"multiline": True}, "function": {"is_list": True,
"name": {"is_list": True, "options": options,
"options": cool_tool_names}} "value": options[0]}}
def build(self, name: str, description: str, chain: Chain): def build(self, document: Document, function: str) -> Document:
return Tool(name=name, page_content = document.page_content
description=description, if function == "Uppercase":
func=chain.run) page_content = page_content.upper()
elif function == "Lowercase":
page_content = page_content.lower()
elif function == "Titlecase":
page_content = page_content.title()
return Document(page_content=page_content)
``` ```
</CH.Code> </CH.Code>
@ -66,23 +65,17 @@ The Python script for every Custom Component should follow a set of rules. Let's
The script must contain a **single class** that inherits from _`CustomComponent`_. The script must contain a **single class** that inherits from _`CustomComponent`_.
```python ```python
# focus
from langflow import CustomComponent from langflow import CustomComponent
from langchain.chains import LLMChain from langchain.schema import Document
from langchain.chains.base import Chain
from langchain import PromptTemplate
from langchain.llms.base import BaseLLM
from langchain import Tool
# focus class MyComponent(CustomComponent):
class BestComponent(CustomComponent):
display_name = "Custom Component" display_name = "Custom Component"
description = "This is a custom component" description = "This is a custom component"
def build_config(self) -> dict: def build_config(self) -> dict:
... ...
def build(self): def build(self, document: Document, function: str) -> Document:
... ...
``` ```
@ -94,21 +87,18 @@ This class requires a _`build`_ method, which is used to run the component and d
```python ```python
from langflow import CustomComponent from langflow import CustomComponent
from langchain.chains import LLMChain from langchain.schema import Document
from langchain.chains.base import Chain
from langchain import PromptTemplate
from langchain.llms.base import BaseLLM
from langchain import Tool
class BestComponent(CustomComponent): class MyComponent(CustomComponent):
display_name = "Custom Component" display_name = "Custom Component"
description = "This is a custom component" description = "This is a custom component"
def build_config(self) -> dict: def build_config(self) -> dict:
... ...
# focus[1:20] # focus
def build(self) -> Tool: # mark
def build(self) -> Document:
... ...
``` ```
@ -118,21 +108,18 @@ The [Return Type Annotation](https://docs.python.org/3/library/typing.html) of t
```python ```python
from langflow import CustomComponent from langflow import CustomComponent
from langchain.chains import LLMChain from langchain.schema import Document
from langchain.chains.base import Chain
from langchain import PromptTemplate
from langchain.llms.base import BaseLLM
from langchain import Tool
class BestComponent(CustomComponent): class MyComponent(CustomComponent):
display_name = "Custom Component" display_name = "Custom Component"
description = "This is a custom component" description = "This is a custom component"
def build_config(self) -> dict: def build_config(self) -> dict:
... ...
# focus[21:30] # focus[20:31]
def build(self) -> Tool: # mark
def build(self) -> Document:
... ...
``` ```
@ -140,27 +127,22 @@ class BestComponent(CustomComponent):
```python ```python
from langflow import CustomComponent from langflow import CustomComponent
from langchain.chains import LLMChain from langchain.schema import Document
from langchain.chains.base import Chain
from langchain import PromptTemplate
from langchain.llms.base import BaseLLM
from langchain import Tool
class BestComponent(CustomComponent): class MyComponent(CustomComponent):
display_name = "Custom Component" display_name = "Custom Component"
description = "This is a custom component" description = "This is a custom component"
# focus
def build_config(self) -> dict: def build_config(self) -> dict:
... ...
def build(self) -> Tool: def build(self) -> Document:
... ...
``` ```
### Rule 3 ### Rule 3
The class can have a [_`build_config`_](focus://11:19) method, which is used to define configuration fields for the component. The _`build_config`_ method should always return a dictionary with specific keys representing the field names and their corresponding configurations. It must follow the format described below: The class can have a [_`build_config`_](focus://8) method, which is used to define configuration fields for the component. The [_`build_config`_](focus://8) method should always return a dictionary with specific keys representing the field names and their corresponding configurations. It must follow the format described below:
- Top-level keys are field names. - Top-level keys are field names.
- Their values are also of type _`dict`_. They specify the behavior of the generated fields. - Their values are also of type _`dict`_. They specify the behavior of the generated fields.
@ -171,28 +153,26 @@ Check out the [component reference](../components/custom) for more details on th
```python ```python
from langflow import CustomComponent from langflow import CustomComponent
from langchain.chains import LLMChain from langchain.schema import Document
from langchain.chains.base import Chain
from langchain import PromptTemplate class MyComponent(CustomComponent):
from langchain.llms.base import BaseLLM display_name = "Custom Component"
from langchain import Tool description = "This is a custom component"
class BestComponent(CustomComponent):
# focus
def build_config(self) -> dict: def build_config(self) -> dict:
... ...
def build(self) -> Tool: def build(self) -> Document:
... ...
``` ```
## Example ## Example
Let's create a custom component that will convert a chain into a tool. It should receive as input a chain component, a tool name, and a description (for an agent to access it). Let's create a simple component that takes a document and a function name as input and returns a document with the page content processed by the selected function.
<Admonition type="info" label="Tip"> <Admonition type="info" label="Tip">
This is also possible with Langflow native components. It's being reproduced here with a custom component for demonstration purposes. If you were to do this using Langflow's native components, you would create a Tool and ask the agent to use it.
</Admonition> </Admonition>
@ -201,22 +181,22 @@ This is also possible with Langflow native components. It's being reproduced her
### Pick a display name ### Pick a display name
First, let's choose a name for our component by adding a _`display_name`_ attribute. This is the component name to be displayed in the canvas. First, let's choose a name for our component by adding a _`display_name`_ attribute. This is the component name to be displayed in the canvas.
The name of the class is not important, but let's call it _`DocumentProcessor`_.
```python focus=9 ```python
from langflow import CustomComponent from langflow import CustomComponent
from langchain.chains import LLMChain from langchain.schema import Document
from langchain.chains.base import Chain
from langchain import PromptTemplate
from langchain.llms.base import BaseLLM
from langchain import Tool
class BestComponent(CustomComponent): # focus
display_name = "Best Component" class DocumentProcessor(CustomComponent):
# focus
display_name = "Document Processor"
description = "This is a custom component"
def build_config(self) -> dict: def build_config(self) -> dict:
... ...
def build(self) -> Tool: def build(self) -> Document:
... ...
``` ```
@ -226,128 +206,140 @@ class BestComponent(CustomComponent):
We can also write a description for it using the _`description`_ attribute. We can also write a description for it using the _`description`_ attribute.
```python focus=10 ```python
from langflow import CustomComponent from langflow import CustomComponent
from langchain.chains import LLMChain from langchain.schema import Document
from langchain.chains.base import Chain
from langchain import PromptTemplate
from langchain.llms.base import BaseLLM
from langchain import Tool
class BestComponent(CustomComponent): class DocumentProcessor(CustomComponent):
display_name = "Best Component" display_name = "Document Processor"
description = "This is the best component ever" description = "This component processes a document"
def build_config(self) -> dict: def build_config(self) -> dict:
... ...
def build(self) -> Tool: def build(self) -> Document:
... ...
``` ```
--- ---
```python
from langflow import CustomComponent
from langchain.schema import Document
class DocumentProcessor(CustomComponent):
display_name = "Document Processor"
description = "This component processes a document"
def build_config(self) -> dict:
...
def build(self, document: Document, function: str) -> Document:
page_content = document.page_content
if function == "Uppercase":
page_content = page_content.upper()
elif function == "Lowercase":
page_content = page_content.lower()
elif function == "Titlecase":
page_content = page_content.title()
return Document(page_content=page_content)
```
### Add the build method
The parameters used are:
- _`document`_ is the document to be processed.
- _`function`_ is the name of the function to be applied to the document.
The return type is _`Document`_.
This method is called when the component is built (i.e. when you click the _Build_ button in the canvas).
<Admonition type="info">
One important aspect of the Type Hints is that generally base Python types add
different kinds of fields while other types such as Document add a
[handle](../guidelines/components) to the component.
</Admonition>
---
### Customize the fields ### Customize the fields
The _`build_config`_ method will be used to configure the fields of the component. The _`build_config`_ method will be used to configure the fields of the component.
- _`multiline`_ allows editing text in an expansive text editor.
- _`is_list`_ allows an input field to contain multiple values. When paired with _`options`_, it will transform it into a dropdown menu. - _`is_list`_ allows an input field to contain multiple values. When paired with _`options`_, it will transform it into a dropdown menu.
- _`options`_ is a list of values to be used in the dropdown menu.
- _`value`_ is the default value of the field.
- _`display_name`_ is the name of the field to be displayed in the canvas.
```python focus=12:19 This method is called when the code is processed (i.e. when you click _Check and Save_ in the code editor).
```python
from langflow import CustomComponent from langflow import CustomComponent
from langchain.chains import LLMChain from langchain.schema import Document
from langchain.chains.base import Chain
from langchain import PromptTemplate
from langchain.llms.base import BaseLLM
from langchain import Tool
class BestComponent(CustomComponent): class DocumentProcessor(CustomComponent):
display_name = "Best Component" display_name = "Document Processor"
description = "This is the best component ever" description = "This component processes a document"
def build_config(self) -> dict: def build_config(self) -> dict:
cool_tool_names = ["Summarizer", options = ["Uppercase", "Lowercase", "Titlecase"]
"Enhancer",
"Translator"]
return { return {
"description": {"multiline": True}, "function": {"is_list": True,
"name": {"is_list": True, "options": options,
"options": cool_tool_names}} "value": options[0],
"display_name": "Function"
},
"document": {"display_name": "Document"}
}
def build(self) -> Tool: def build(self, document: Document, function: str) -> Document:
... page_content = document.page_content
if function == "Uppercase":
page_content = page_content.upper()
elif function == "Lowercase":
page_content = page_content.lower()
elif function == "Titlecase":
page_content = page_content.title()
return Document(page_content=page_content)
``` ```
---
```python focus=21:25
from langflow import CustomComponent
from langchain.chains import LLMChain
from langchain.chains.base import Chain
from langchain import PromptTemplate
from langchain.llms.base import BaseLLM
from langchain import Tool
class BestComponent(CustomComponent):
display_name = "Best Component"
description = "This is the best component ever"
def build_config(self) -> dict:
cool_tool_names = ["Cool Tool",
"Cooler Tool",
"Coolest Tool"]
return {
"description": {"multiline": True},
"name": {"is_list": True,
"options": cool_tool_names}}
def build(self, name: str, description: str,
chain: Chain) -> Tool:
return Tool(name=name,
description=description,
func=chain.run)
```
### Add the build method
The parameters used are:
- name is a string
- description is a string
- chain is a Chain
- The return type is Tool
We then instantiate a Tool and return it.
</CH.Scrollycoding> </CH.Scrollycoding>
In Langflow, this is how our script looks like: In Langflow, this is how our script looks like:
<div {" "}
style={{ marginBottom: "20px", display: "flex", justifyContent: "center" }}
> <ZoomableImage
<ZoomableImage alt="Document Processor code"
alt="Docusaurus themed image" sources={{
sources={{ light: "img/document_processor_code.png",
light: "img/new_langflow2.gif", }}
}} style={{
/> maxWidth: "70%",
</div> margin: "0 auto",
display: "flex",
justifyContent: "center",
}}
/>
And here is our brand new custom component: And here is our brand new custom component:
<div {" "}
style={{ marginBottom: "20px", display: "flex", justifyContent: "center" }}
> <ZoomableImage
<ZoomableImage alt="Document Processor component"
alt="Docusaurus themed image" sources={{
sources={{ light: "img/document_processor.png",
light: "img/new_langflow2.gif", }}
}} style={{
/> width: "50%",
</div> margin: "0 auto",
display: "flex",
justifyContent: "center",
}}
/>
## FlowRunner Example ## FlowRunner Example