* delete data and transfer data to dataframe * [autofix.ci] apply automated fixes * create a new bundle for search * fix type for dataframe * add data_to_dataframe function * [autofix.ci] apply automated fixes * fix test because of files movement * delete message and text * json update * fix search yahoo test * fix run_model output type * fix test errors * fix test errors * fix test error * try fix frontend tests * test fix * [autofix.ci] apply automated fixes * move serp search * fix test * fix test * fix test to pass ruff style check --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Edwin Jose <edwin.jose@datastax.com> Co-authored-by: Mike Fortman <michael.fortman@datastax.com>
1780 lines
No EOL
98 KiB
JSON
1780 lines
No EOL
98 KiB
JSON
{
|
||
"data": {
|
||
"edges": [
|
||
{
|
||
"animated": false,
|
||
"className": "",
|
||
"data": {
|
||
"sourceHandle": {
|
||
"dataType": "AnthropicModel",
|
||
"id": "AnthropicModel-G2MkR",
|
||
"name": "text_output",
|
||
"output_types": [
|
||
"Message"
|
||
]
|
||
},
|
||
"targetHandle": {
|
||
"fieldName": "message",
|
||
"id": "MessagetoData-jYebP",
|
||
"inputTypes": [
|
||
"Message"
|
||
],
|
||
"type": "str"
|
||
}
|
||
},
|
||
"id": "reactflow__edge-AnthropicModel-G2MkR{œdataTypeœ:œAnthropicModelœ,œidœ:œAnthropicModel-G2MkRœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-MessagetoData-jYebP{œfieldNameœ:œmessageœ,œidœ:œMessagetoData-jYebPœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
|
||
"selected": false,
|
||
"source": "AnthropicModel-G2MkR",
|
||
"sourceHandle": "{œdataTypeœ: œAnthropicModelœ, œidœ: œAnthropicModel-G2MkRœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
|
||
"target": "MessagetoData-jYebP",
|
||
"targetHandle": "{œfieldNameœ: œmessageœ, œidœ: œMessagetoData-jYebPœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
|
||
},
|
||
{
|
||
"animated": false,
|
||
"className": "",
|
||
"data": {
|
||
"sourceHandle": {
|
||
"dataType": "ChatInput",
|
||
"id": "ChatInput-5o3G0",
|
||
"name": "message",
|
||
"output_types": [
|
||
"Message"
|
||
]
|
||
},
|
||
"targetHandle": {
|
||
"fieldName": "search_query",
|
||
"id": "ArXivComponent-ylKFb",
|
||
"inputTypes": [
|
||
"Message"
|
||
],
|
||
"type": "str"
|
||
}
|
||
},
|
||
"id": "reactflow__edge-ChatInput-5o3G0{œdataTypeœ:œChatInputœ,œidœ:œChatInput-5o3G0œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-ArXivComponent-ylKFb{œfieldNameœ:œsearch_queryœ,œidœ:œArXivComponent-ylKFbœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
|
||
"selected": false,
|
||
"source": "ChatInput-5o3G0",
|
||
"sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-5o3G0œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
|
||
"target": "ArXivComponent-ylKFb",
|
||
"targetHandle": "{œfieldNameœ: œsearch_queryœ, œidœ: œArXivComponent-ylKFbœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
|
||
},
|
||
{
|
||
"animated": false,
|
||
"className": "",
|
||
"data": {
|
||
"sourceHandle": {
|
||
"dataType": "ParserComponent",
|
||
"id": "ParserComponent-ZhlLQ",
|
||
"name": "parsed_text",
|
||
"output_types": [
|
||
"Message"
|
||
]
|
||
},
|
||
"targetHandle": {
|
||
"fieldName": "input_value",
|
||
"id": "AnthropicModel-G2MkR",
|
||
"inputTypes": [
|
||
"Message"
|
||
],
|
||
"type": "str"
|
||
}
|
||
},
|
||
"id": "reactflow__edge-ParserComponent-ZhlLQ{œdataTypeœ:œParserComponentœ,œidœ:œParserComponent-ZhlLQœ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-AnthropicModel-G2MkR{œfieldNameœ:œinput_valueœ,œidœ:œAnthropicModel-G2MkRœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
|
||
"selected": false,
|
||
"source": "ParserComponent-ZhlLQ",
|
||
"sourceHandle": "{œdataTypeœ: œParserComponentœ, œidœ: œParserComponent-ZhlLQœ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}",
|
||
"target": "AnthropicModel-G2MkR",
|
||
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAnthropicModel-G2MkRœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
|
||
},
|
||
{
|
||
"animated": false,
|
||
"className": "",
|
||
"data": {
|
||
"sourceHandle": {
|
||
"dataType": "ArXivComponent",
|
||
"id": "ArXivComponent-ylKFb",
|
||
"name": "dataframe",
|
||
"output_types": [
|
||
"DataFrame"
|
||
]
|
||
},
|
||
"targetHandle": {
|
||
"fieldName": "data",
|
||
"id": "LoopComponent-9BK8B",
|
||
"inputTypes": [
|
||
"Data",
|
||
"DataFrame"
|
||
],
|
||
"type": "other"
|
||
}
|
||
},
|
||
"id": "xy-edge__ArXivComponent-ylKFb{œdataTypeœ:œArXivComponentœ,œidœ:œArXivComponent-ylKFbœ,œnameœ:œdataframeœ,œoutput_typesœ:[œDataFrameœ]}-LoopComponent-9BK8B{œfieldNameœ:œdataœ,œidœ:œLoopComponent-9BK8Bœ,œinputTypesœ:[œDataœ,œDataFrameœ],œtypeœ:œotherœ}",
|
||
"selected": false,
|
||
"source": "ArXivComponent-ylKFb",
|
||
"sourceHandle": "{œdataTypeœ: œArXivComponentœ, œidœ: œArXivComponent-ylKFbœ, œnameœ: œdataframeœ, œoutput_typesœ: [œDataFrameœ]}",
|
||
"target": "LoopComponent-9BK8B",
|
||
"targetHandle": "{œfieldNameœ: œdataœ, œidœ: œLoopComponent-9BK8Bœ, œinputTypesœ: [œDataœ, œDataFrameœ], œtypeœ: œotherœ}"
|
||
},
|
||
{
|
||
"animated": false,
|
||
"className": "",
|
||
"data": {
|
||
"sourceHandle": {
|
||
"dataType": "LoopComponent",
|
||
"id": "LoopComponent-9BK8B",
|
||
"name": "item",
|
||
"output_types": [
|
||
"Data"
|
||
]
|
||
},
|
||
"targetHandle": {
|
||
"fieldName": "input_data",
|
||
"id": "ParserComponent-ZhlLQ",
|
||
"inputTypes": [
|
||
"DataFrame",
|
||
"Data"
|
||
],
|
||
"type": "other"
|
||
}
|
||
},
|
||
"id": "xy-edge__LoopComponent-9BK8B{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-9BK8Bœ,œnameœ:œitemœ,œoutput_typesœ:[œDataœ]}-ParserComponent-ZhlLQ{œfieldNameœ:œinput_dataœ,œidœ:œParserComponent-ZhlLQœ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}",
|
||
"selected": false,
|
||
"source": "LoopComponent-9BK8B",
|
||
"sourceHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-9BK8Bœ, œnameœ: œitemœ, œoutput_typesœ: [œDataœ]}",
|
||
"target": "ParserComponent-ZhlLQ",
|
||
"targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œParserComponent-ZhlLQœ, œinputTypesœ: [œDataFrameœ, œDataœ], œtypeœ: œotherœ}"
|
||
},
|
||
{
|
||
"animated": false,
|
||
"className": "",
|
||
"data": {
|
||
"sourceHandle": {
|
||
"dataType": "LoopComponent",
|
||
"id": "LoopComponent-9BK8B",
|
||
"name": "done",
|
||
"output_types": [
|
||
"DataFrame"
|
||
]
|
||
},
|
||
"targetHandle": {
|
||
"fieldName": "input_value",
|
||
"id": "ChatOutput-oTh2r",
|
||
"inputTypes": [
|
||
"Data",
|
||
"DataFrame",
|
||
"Message"
|
||
],
|
||
"type": "str"
|
||
}
|
||
},
|
||
"id": "xy-edge__LoopComponent-9BK8B{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-9BK8Bœ,œnameœ:œdoneœ,œoutput_typesœ:[œDataFrameœ]}-ChatOutput-oTh2r{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-oTh2rœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}",
|
||
"selected": false,
|
||
"source": "LoopComponent-9BK8B",
|
||
"sourceHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-9BK8Bœ, œnameœ: œdoneœ, œoutput_typesœ: [œDataFrameœ]}",
|
||
"target": "ChatOutput-oTh2r",
|
||
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-oTh2rœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}"
|
||
},
|
||
{
|
||
"animated": false,
|
||
"className": "",
|
||
"data": {
|
||
"sourceHandle": {
|
||
"dataType": "MessagetoData",
|
||
"id": "MessagetoData-jYebP",
|
||
"name": "data",
|
||
"output_types": [
|
||
"Data"
|
||
]
|
||
},
|
||
"targetHandle": {
|
||
"dataType": "LoopComponent",
|
||
"id": "LoopComponent-9BK8B",
|
||
"name": "item",
|
||
"output_types": [
|
||
"Data"
|
||
]
|
||
}
|
||
},
|
||
"id": "xy-edge__MessagetoData-jYebP{œdataTypeœ:œMessagetoDataœ,œidœ:œMessagetoData-jYebPœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-LoopComponent-9BK8B{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-9BK8Bœ,œnameœ:œitemœ,œoutput_typesœ:[œDataœ]}",
|
||
"selected": false,
|
||
"source": "MessagetoData-jYebP",
|
||
"sourceHandle": "{œdataTypeœ: œMessagetoDataœ, œidœ: œMessagetoData-jYebPœ, œnameœ: œdataœ, œoutput_typesœ: [œDataœ]}",
|
||
"target": "LoopComponent-9BK8B",
|
||
"targetHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-9BK8Bœ, œnameœ: œitemœ, œoutput_typesœ: [œDataœ]}"
|
||
}
|
||
],
|
||
"nodes": [
|
||
{
|
||
"data": {
|
||
"id": "ArXivComponent-ylKFb",
|
||
"node": {
|
||
"base_classes": [
|
||
"Data"
|
||
],
|
||
"beta": false,
|
||
"conditional_paths": [],
|
||
"custom_fields": {},
|
||
"description": "Search and retrieve papers from arXiv.org",
|
||
"display_name": "arXiv",
|
||
"documentation": "",
|
||
"edited": false,
|
||
"field_order": [
|
||
"search_query",
|
||
"search_type",
|
||
"max_results"
|
||
],
|
||
"frozen": false,
|
||
"icon": "arXiv",
|
||
"legacy": false,
|
||
"lf_version": "1.4.2",
|
||
"metadata": {},
|
||
"minimized": false,
|
||
"output_types": [],
|
||
"outputs": [
|
||
{
|
||
"allows_loop": false,
|
||
"cache": true,
|
||
"display_name": "DataFrame",
|
||
"method": "search_papers_dataframe",
|
||
"name": "dataframe",
|
||
"selected": "DataFrame",
|
||
"tool_mode": true,
|
||
"types": [
|
||
"DataFrame"
|
||
],
|
||
"value": "__UNDEFINED__"
|
||
}
|
||
],
|
||
"pinned": false,
|
||
"template": {
|
||
"_type": "Component",
|
||
"code": {
|
||
"advanced": true,
|
||
"dynamic": true,
|
||
"fileTypes": [],
|
||
"file_path": "",
|
||
"info": "",
|
||
"list": false,
|
||
"load_from_db": false,
|
||
"multiline": true,
|
||
"name": "code",
|
||
"password": false,
|
||
"placeholder": "",
|
||
"required": true,
|
||
"show": true,
|
||
"title_case": false,
|
||
"type": "code",
|
||
"value": "import urllib.request\nfrom urllib.parse import urlparse\nfrom xml.etree.ElementTree import Element\n\nfrom defusedxml.ElementTree import fromstring\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_dataframe\nfrom langflow.io import DropdownInput, IntInput, MessageTextInput, Output\nfrom langflow.schema import Data, DataFrame\n\n\nclass ArXivComponent(Component):\n display_name = \"arXiv\"\n description = \"Search and retrieve papers from arXiv.org\"\n icon = \"arXiv\"\n\n inputs = [\n MessageTextInput(\n name=\"search_query\",\n display_name=\"Search Query\",\n info=\"The search query for arXiv papers (e.g., 'quantum computing')\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_type\",\n display_name=\"Search Field\",\n info=\"The field to search in\",\n options=[\"all\", \"title\", \"abstract\", \"author\", \"cat\"], # cat is for category\n value=\"all\",\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"Maximum number of results to return\",\n value=10,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"search_papers_dataframe\"),\n ]\n\n def build_query_url(self) -> str:\n \"\"\"Build the arXiv API query URL.\"\"\"\n base_url = \"http://export.arxiv.org/api/query?\"\n\n # Build the search query\n search_query = f\"{self.search_type}:{self.search_query}\"\n\n # URL parameters\n params = {\n \"search_query\": search_query,\n \"max_results\": str(self.max_results),\n }\n\n # Convert params to URL query string\n query_string = \"&\".join([f\"{k}={urllib.parse.quote(str(v))}\" for k, v in params.items()])\n\n return base_url + query_string\n\n def parse_atom_response(self, response_text: str) -> list[dict]:\n \"\"\"Parse the Atom XML response from arXiv.\"\"\"\n # Parse XML safely using defusedxml\n root = fromstring(response_text)\n\n # Define namespace dictionary for XML parsing\n ns = {\"atom\": \"http://www.w3.org/2005/Atom\", \"arxiv\": \"http://arxiv.org/schemas/atom\"}\n\n papers = []\n # Process each entry (paper)\n for entry in root.findall(\"atom:entry\", ns):\n paper = {\n \"id\": self._get_text(entry, \"atom:id\", ns),\n \"title\": self._get_text(entry, \"atom:title\", ns),\n \"summary\": self._get_text(entry, \"atom:summary\", ns),\n \"published\": self._get_text(entry, \"atom:published\", ns),\n \"updated\": self._get_text(entry, \"atom:updated\", ns),\n \"authors\": [author.find(\"atom:name\", ns).text for author in entry.findall(\"atom:author\", ns)],\n \"arxiv_url\": self._get_link(entry, \"alternate\", ns),\n \"pdf_url\": self._get_link(entry, \"related\", ns),\n \"comment\": self._get_text(entry, \"arxiv:comment\", ns),\n \"journal_ref\": self._get_text(entry, \"arxiv:journal_ref\", ns),\n \"primary_category\": self._get_category(entry, ns),\n \"categories\": [cat.get(\"term\") for cat in entry.findall(\"atom:category\", ns)],\n }\n papers.append(paper)\n\n return papers\n\n def _get_text(self, element: Element, path: str, ns: dict) -> str | None:\n \"\"\"Safely extract text from an XML element.\"\"\"\n el = element.find(path, ns)\n return el.text.strip() if el is not None and el.text else None\n\n def _get_link(self, element: Element, rel: str, ns: dict) -> str | None:\n \"\"\"Get link URL based on relation type.\"\"\"\n for link in element.findall(\"atom:link\", ns):\n if link.get(\"rel\") == rel:\n return link.get(\"href\")\n return None\n\n def _get_category(self, element: Element, ns: dict) -> str | None:\n \"\"\"Get primary category.\"\"\"\n cat = element.find(\"arxiv:primary_category\", ns)\n return cat.get(\"term\") if cat is not None else None\n\n def run_model(self) -> DataFrame:\n return self.search_papers_dataframe()\n\n def search_papers(self) -> list[Data]:\n \"\"\"Search arXiv and return results.\"\"\"\n try:\n # Build the query URL\n url = self.build_query_url()\n\n # Validate URL scheme and host\n parsed_url = urlparse(url)\n if parsed_url.scheme not in {\"http\", \"https\"}:\n error_msg = f\"Invalid URL scheme: {parsed_url.scheme}\"\n raise ValueError(error_msg)\n if parsed_url.hostname != \"export.arxiv.org\":\n error_msg = f\"Invalid host: {parsed_url.hostname}\"\n raise ValueError(error_msg)\n\n # Create a custom opener that only allows http/https schemes\n class RestrictedHTTPHandler(urllib.request.HTTPHandler):\n def http_open(self, req):\n return super().http_open(req)\n\n class RestrictedHTTPSHandler(urllib.request.HTTPSHandler):\n def https_open(self, req):\n return super().https_open(req)\n\n # Build opener with restricted handlers\n opener = urllib.request.build_opener(RestrictedHTTPHandler, RestrictedHTTPSHandler)\n urllib.request.install_opener(opener)\n\n # Make the request with validated URL using restricted opener\n response = opener.open(url)\n response_text = response.read().decode(\"utf-8\")\n\n # Parse the response\n papers = self.parse_atom_response(response_text)\n\n # Convert to Data objects\n results = [Data(data=paper) for paper in papers]\n self.status = results\n except (urllib.error.URLError, ValueError) as e:\n error_data = Data(data={\"error\": f\"Request error: {e!s}\"})\n self.status = error_data\n return [error_data]\n else:\n return results\n\n def search_papers_dataframe(self) -> DataFrame:\n \"\"\"Convert the Arxiv search results to a DataFrame.\n\n Returns:\n DataFrame: A DataFrame containing the search results.\n \"\"\"\n data = self.search_papers()\n return data_to_dataframe(data)\n"
|
||
},
|
||
"max_results": {
|
||
"_input_type": "IntInput",
|
||
"advanced": false,
|
||
"display_name": "Max Results",
|
||
"dynamic": false,
|
||
"info": "Maximum number of results to return",
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"name": "max_results",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_metadata": true,
|
||
"type": "int",
|
||
"value": 3
|
||
},
|
||
"search_query": {
|
||
"_input_type": "MessageTextInput",
|
||
"advanced": false,
|
||
"display_name": "Search Query",
|
||
"dynamic": false,
|
||
"info": "The search query for arXiv papers (e.g., 'quantum computing')",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "search_query",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": true,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": ""
|
||
},
|
||
"search_type": {
|
||
"_input_type": "DropdownInput",
|
||
"advanced": false,
|
||
"combobox": false,
|
||
"dialog_inputs": {},
|
||
"display_name": "Search Field",
|
||
"dynamic": false,
|
||
"info": "The field to search in",
|
||
"name": "search_type",
|
||
"options": [
|
||
"all",
|
||
"title",
|
||
"abstract",
|
||
"author",
|
||
"cat"
|
||
],
|
||
"options_metadata": [],
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": "all"
|
||
}
|
||
},
|
||
"tool_mode": false
|
||
},
|
||
"showNode": true,
|
||
"type": "ArXivComponent"
|
||
},
|
||
"dragging": false,
|
||
"id": "ArXivComponent-ylKFb",
|
||
"measured": {
|
||
"height": 443,
|
||
"width": 320
|
||
},
|
||
"position": {
|
||
"x": 81.59312530546094,
|
||
"y": 3.9397854556273906
|
||
},
|
||
"selected": false,
|
||
"type": "genericNode"
|
||
},
|
||
{
|
||
"data": {
|
||
"id": "AnthropicModel-G2MkR",
|
||
"node": {
|
||
"base_classes": [
|
||
"LanguageModel",
|
||
"Message"
|
||
],
|
||
"beta": false,
|
||
"category": "models",
|
||
"conditional_paths": [],
|
||
"custom_fields": {},
|
||
"description": "Generate text using Anthropic Chat&Completion LLMs with prefill support.",
|
||
"display_name": "Anthropic",
|
||
"documentation": "",
|
||
"edited": false,
|
||
"field_order": [
|
||
"input_value",
|
||
"system_message",
|
||
"stream",
|
||
"max_tokens",
|
||
"model_name",
|
||
"api_key",
|
||
"temperature",
|
||
"base_url",
|
||
"tool_model_enabled",
|
||
"prefill"
|
||
],
|
||
"frozen": false,
|
||
"icon": "Anthropic",
|
||
"key": "AnthropicModel",
|
||
"legacy": false,
|
||
"lf_version": "1.1.5",
|
||
"metadata": {
|
||
"keywords": [
|
||
"model",
|
||
"llm",
|
||
"language model",
|
||
"large language model"
|
||
]
|
||
},
|
||
"minimized": false,
|
||
"output_types": [],
|
||
"outputs": [
|
||
{
|
||
"allows_loop": false,
|
||
"cache": true,
|
||
"display_name": "Message",
|
||
"method": "text_response",
|
||
"name": "text_output",
|
||
"required_inputs": [],
|
||
"selected": "Message",
|
||
"tool_mode": true,
|
||
"types": [
|
||
"Message"
|
||
],
|
||
"value": "__UNDEFINED__"
|
||
},
|
||
{
|
||
"allows_loop": false,
|
||
"cache": true,
|
||
"display_name": "Language Model",
|
||
"method": "build_model",
|
||
"name": "model_output",
|
||
"required_inputs": [
|
||
"api_key"
|
||
],
|
||
"selected": "LanguageModel",
|
||
"tool_mode": true,
|
||
"types": [
|
||
"LanguageModel"
|
||
],
|
||
"value": "__UNDEFINED__"
|
||
}
|
||
],
|
||
"pinned": false,
|
||
"score": 0.0005851173668140926,
|
||
"template": {
|
||
"_type": "Component",
|
||
"api_key": {
|
||
"_input_type": "SecretStrInput",
|
||
"advanced": false,
|
||
"display_name": "Anthropic API Key",
|
||
"dynamic": false,
|
||
"info": "Your Anthropic API key.",
|
||
"input_types": [],
|
||
"load_from_db": false,
|
||
"name": "api_key",
|
||
"password": true,
|
||
"placeholder": "",
|
||
"real_time_refresh": true,
|
||
"required": true,
|
||
"show": true,
|
||
"title_case": false,
|
||
"type": "str",
|
||
"value": ""
|
||
},
|
||
"base_url": {
|
||
"_input_type": "MessageTextInput",
|
||
"advanced": true,
|
||
"display_name": "Anthropic API URL",
|
||
"dynamic": false,
|
||
"info": "Endpoint of the Anthropic API. Defaults to 'https://api.anthropic.com' if not specified.",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "base_url",
|
||
"placeholder": "",
|
||
"real_time_refresh": true,
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": "https://api.anthropic.com"
|
||
},
|
||
"code": {
|
||
"advanced": true,
|
||
"dynamic": true,
|
||
"fileTypes": [],
|
||
"file_path": "",
|
||
"info": "",
|
||
"list": false,
|
||
"load_from_db": false,
|
||
"multiline": true,
|
||
"name": "code",
|
||
"password": false,
|
||
"placeholder": "",
|
||
"required": true,
|
||
"show": true,
|
||
"title_case": false,
|
||
"type": "code",
|
||
"value": "from typing import Any, cast\n\nimport requests\nfrom loguru import logger\n\nfrom langflow.base.models.anthropic_constants import (\n ANTHROPIC_MODELS,\n DEFAULT_ANTHROPIC_API_URL,\n TOOL_CALLING_SUPPORTED_ANTHROPIC_MODELS,\n TOOL_CALLING_UNSUPPORTED_ANTHROPIC_MODELS,\n)\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, SecretStrInput, SliderInput\nfrom langflow.schema.dotdict import dotdict\n\n\nclass AnthropicModelComponent(LCModelComponent):\n display_name = \"Anthropic\"\n description = \"Generate text using Anthropic Chat&Completion LLMs with prefill support.\"\n icon = \"Anthropic\"\n name = \"AnthropicModel\"\n\n inputs = [\n *LCModelComponent._base_inputs,\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n value=4096,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n options=ANTHROPIC_MODELS,\n refresh_button=True,\n value=ANTHROPIC_MODELS[0],\n combobox=True,\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Anthropic API Key\",\n info=\"Your Anthropic API key.\",\n value=None,\n required=True,\n real_time_refresh=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n info=\"Run inference with this temperature. Must by in the closed interval [0.0, 1.0].\",\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n advanced=True,\n ),\n MessageTextInput(\n name=\"base_url\",\n display_name=\"Anthropic API URL\",\n info=\"Endpoint of the Anthropic API. Defaults to 'https://api.anthropic.com' if not specified.\",\n value=DEFAULT_ANTHROPIC_API_URL,\n real_time_refresh=True,\n advanced=True,\n ),\n BoolInput(\n name=\"tool_model_enabled\",\n display_name=\"Enable Tool Models\",\n info=(\n \"Select if you want to use models that can work with tools. If yes, only those models will be shown.\"\n ),\n advanced=False,\n value=False,\n real_time_refresh=True,\n ),\n MessageTextInput(\n name=\"prefill\", display_name=\"Prefill\", info=\"Prefill text to guide the model's response.\", advanced=True\n ),\n ]\n\n def build_model(self) -> LanguageModel: # type: ignore[type-var]\n try:\n from langchain_anthropic.chat_models import ChatAnthropic\n except ImportError as e:\n msg = \"langchain_anthropic is not installed. Please install it with `pip install langchain_anthropic`.\"\n raise ImportError(msg) from e\n try:\n output = ChatAnthropic(\n model=self.model_name,\n anthropic_api_key=self.api_key,\n max_tokens_to_sample=self.max_tokens,\n temperature=self.temperature,\n anthropic_api_url=DEFAULT_ANTHROPIC_API_URL,\n streaming=self.stream,\n )\n except Exception as e:\n msg = \"Could not connect to Anthropic API.\"\n raise ValueError(msg) from e\n\n return output\n\n def get_models(self, tool_model_enabled: bool | None = None) -> list[str]:\n try:\n import anthropic\n\n client = anthropic.Anthropic(api_key=self.api_key)\n models = client.models.list(limit=20).data\n model_ids = ANTHROPIC_MODELS + [model.id for model in models]\n except (ImportError, ValueError, requests.exceptions.RequestException) as e:\n logger.exception(f\"Error getting model names: {e}\")\n model_ids = ANTHROPIC_MODELS\n\n if tool_model_enabled:\n try:\n from langchain_anthropic.chat_models import ChatAnthropic\n except ImportError as e:\n msg = \"langchain_anthropic is not installed. Please install it with `pip install langchain_anthropic`.\"\n raise ImportError(msg) from e\n\n # Create a new list instead of modifying while iterating\n filtered_models = []\n for model in model_ids:\n if model in TOOL_CALLING_SUPPORTED_ANTHROPIC_MODELS:\n filtered_models.append(model)\n continue\n\n model_with_tool = ChatAnthropic(\n model=model, # Use the current model being checked\n anthropic_api_key=self.api_key,\n anthropic_api_url=cast(str, self.base_url) or DEFAULT_ANTHROPIC_API_URL,\n )\n\n if (\n not self.supports_tool_calling(model_with_tool)\n or model in TOOL_CALLING_UNSUPPORTED_ANTHROPIC_MODELS\n ):\n continue\n\n filtered_models.append(model)\n\n return filtered_models\n\n return model_ids\n\n def _get_exception_message(self, exception: Exception) -> str | None:\n \"\"\"Get a message from an Anthropic exception.\n\n Args:\n exception (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n try:\n from anthropic import BadRequestError\n except ImportError:\n return None\n if isinstance(exception, BadRequestError):\n message = exception.body.get(\"error\", {}).get(\"message\")\n if message:\n return message\n return None\n\n def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None):\n if \"base_url\" in build_config and build_config[\"base_url\"][\"value\"] is None:\n build_config[\"base_url\"][\"value\"] = DEFAULT_ANTHROPIC_API_URL\n self.base_url = DEFAULT_ANTHROPIC_API_URL\n if field_name in {\"base_url\", \"model_name\", \"tool_model_enabled\", \"api_key\"} and field_value:\n try:\n if len(self.api_key) == 0:\n ids = ANTHROPIC_MODELS\n else:\n try:\n ids = self.get_models(tool_model_enabled=self.tool_model_enabled)\n except (ImportError, ValueError, requests.exceptions.RequestException) as e:\n logger.exception(f\"Error getting model names: {e}\")\n ids = ANTHROPIC_MODELS\n build_config[\"model_name\"][\"options\"] = ids\n build_config[\"model_name\"][\"value\"] = ids[0]\n build_config[\"model_name\"][\"combobox\"] = True\n except Exception as e:\n msg = f\"Error getting model names: {e}\"\n raise ValueError(msg) from e\n return build_config\n"
|
||
},
|
||
"input_value": {
|
||
"_input_type": "MessageInput",
|
||
"advanced": false,
|
||
"display_name": "Input",
|
||
"dynamic": false,
|
||
"info": "",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "input_value",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": ""
|
||
},
|
||
"max_tokens": {
|
||
"_input_type": "IntInput",
|
||
"advanced": true,
|
||
"display_name": "Max Tokens",
|
||
"dynamic": false,
|
||
"info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.",
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"name": "max_tokens",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_metadata": true,
|
||
"type": "int",
|
||
"value": 4096
|
||
},
|
||
"model_name": {
|
||
"_input_type": "DropdownInput",
|
||
"advanced": false,
|
||
"combobox": true,
|
||
"dialog_inputs": {},
|
||
"display_name": "Model Name",
|
||
"dynamic": false,
|
||
"info": "",
|
||
"name": "model_name",
|
||
"options": [
|
||
"claude-3-7-sonnet-latest",
|
||
"claude-3-5-sonnet-latest",
|
||
"claude-3-5-haiku-latest",
|
||
"claude-3-opus-latest",
|
||
"claude-3-sonnet-20240229",
|
||
"claude-3-haiku-20240307"
|
||
],
|
||
"options_metadata": [],
|
||
"placeholder": "",
|
||
"refresh_button": true,
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": "claude-3-7-sonnet-latest"
|
||
},
|
||
"prefill": {
|
||
"_input_type": "MessageTextInput",
|
||
"advanced": true,
|
||
"display_name": "Prefill",
|
||
"dynamic": false,
|
||
"info": "Prefill text to guide the model's response.",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "prefill",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": ""
|
||
},
|
||
"stream": {
|
||
"_input_type": "BoolInput",
|
||
"advanced": true,
|
||
"display_name": "Stream",
|
||
"dynamic": false,
|
||
"info": "Stream the response from the model. Streaming works only in Chat.",
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"name": "stream",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_metadata": true,
|
||
"type": "bool",
|
||
"value": false
|
||
},
|
||
"system_message": {
|
||
"_input_type": "MultilineInput",
|
||
"advanced": false,
|
||
"display_name": "System Message",
|
||
"dynamic": false,
|
||
"info": "System message to pass to the model.",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"multiline": true,
|
||
"name": "system_message",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": "Translate to Portuguese and output in structured format\nReturn only the JSON and no additional text."
|
||
},
|
||
"temperature": {
|
||
"_input_type": "SliderInput",
|
||
"advanced": true,
|
||
"display_name": "Temperature",
|
||
"dynamic": false,
|
||
"info": "Run inference with this temperature. Must by in the closed interval [0.0, 1.0].",
|
||
"max_label": "",
|
||
"max_label_icon": "",
|
||
"min_label": "",
|
||
"min_label_icon": "",
|
||
"name": "temperature",
|
||
"placeholder": "",
|
||
"range_spec": {
|
||
"max": 1,
|
||
"min": 0,
|
||
"step": 0.01,
|
||
"step_type": "float"
|
||
},
|
||
"required": false,
|
||
"show": true,
|
||
"slider_buttons": false,
|
||
"slider_buttons_options": [],
|
||
"slider_input": false,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"type": "slider",
|
||
"value": 0.1
|
||
},
|
||
"tool_model_enabled": {
|
||
"_input_type": "BoolInput",
|
||
"advanced": false,
|
||
"display_name": "Enable Tool Models",
|
||
"dynamic": false,
|
||
"info": "Select if you want to use models that can work with tools. If yes, only those models will be shown.",
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"name": "tool_model_enabled",
|
||
"placeholder": "",
|
||
"real_time_refresh": true,
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_metadata": true,
|
||
"type": "bool",
|
||
"value": false
|
||
}
|
||
},
|
||
"tool_mode": false
|
||
},
|
||
"showNode": true,
|
||
"type": "AnthropicModel"
|
||
},
|
||
"dragging": false,
|
||
"id": "AnthropicModel-G2MkR",
|
||
"measured": {
|
||
"height": 588,
|
||
"width": 320
|
||
},
|
||
"position": {
|
||
"x": 1493.0259340837038,
|
||
"y": -225.9942853677759
|
||
},
|
||
"selected": false,
|
||
"type": "genericNode"
|
||
},
|
||
{
|
||
"data": {
|
||
"id": "MessagetoData-jYebP",
|
||
"node": {
|
||
"base_classes": [
|
||
"Data"
|
||
],
|
||
"beta": true,
|
||
"category": "processing",
|
||
"conditional_paths": [],
|
||
"custom_fields": {},
|
||
"description": "Convert a Message object to a Data object",
|
||
"display_name": "Message to Data",
|
||
"documentation": "",
|
||
"edited": false,
|
||
"field_order": [
|
||
"message"
|
||
],
|
||
"frozen": false,
|
||
"icon": "message-square-share",
|
||
"key": "MessagetoData",
|
||
"legacy": false,
|
||
"lf_version": "1.1.5",
|
||
"metadata": {},
|
||
"minimized": false,
|
||
"output_types": [],
|
||
"outputs": [
|
||
{
|
||
"allows_loop": false,
|
||
"cache": true,
|
||
"display_name": "Data",
|
||
"method": "convert_message_to_data",
|
||
"name": "data",
|
||
"selected": "Data",
|
||
"tool_mode": true,
|
||
"types": [
|
||
"Data"
|
||
],
|
||
"value": "__UNDEFINED__"
|
||
}
|
||
],
|
||
"pinned": false,
|
||
"score": 0.008222426499470714,
|
||
"template": {
|
||
"_type": "Component",
|
||
"code": {
|
||
"advanced": true,
|
||
"dynamic": true,
|
||
"fileTypes": [],
|
||
"file_path": "",
|
||
"info": "",
|
||
"list": false,
|
||
"load_from_db": false,
|
||
"multiline": true,
|
||
"name": "code",
|
||
"password": false,
|
||
"placeholder": "",
|
||
"required": true,
|
||
"show": true,
|
||
"title_case": false,
|
||
"type": "code",
|
||
"value": "from loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.io import MessageInput, Output\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass MessageToDataComponent(Component):\n display_name = \"Message to Data\"\n description = \"Convert a Message object to a Data object\"\n icon = \"message-square-share\"\n beta = True\n name = \"MessagetoData\"\n\n inputs = [\n MessageInput(\n name=\"message\",\n display_name=\"Message\",\n info=\"The Message object to convert to a Data object\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"convert_message_to_data\"),\n ]\n\n def convert_message_to_data(self) -> Data:\n if isinstance(self.message, Message):\n # Convert Message to Data\n return Data(data=self.message.data)\n\n msg = \"Error converting Message to Data: Input must be a Message object\"\n logger.opt(exception=True).debug(msg)\n self.status = msg\n return Data(data={\"error\": msg})\n"
|
||
},
|
||
"message": {
|
||
"_input_type": "MessageInput",
|
||
"advanced": false,
|
||
"display_name": "Message",
|
||
"dynamic": false,
|
||
"info": "The Message object to convert to a Data object",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "message",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": ""
|
||
}
|
||
},
|
||
"tool_mode": false
|
||
},
|
||
"showNode": true,
|
||
"type": "MessagetoData"
|
||
},
|
||
"dragging": false,
|
||
"id": "MessagetoData-jYebP",
|
||
"measured": {
|
||
"height": 230,
|
||
"width": 320
|
||
},
|
||
"position": {
|
||
"x": 1863.8805295746977,
|
||
"y": 440.56780240629814
|
||
},
|
||
"selected": false,
|
||
"type": "genericNode"
|
||
},
|
||
{
|
||
"data": {
|
||
"id": "ChatOutput-oTh2r",
|
||
"node": {
|
||
"base_classes": [
|
||
"Message"
|
||
],
|
||
"beta": false,
|
||
"conditional_paths": [],
|
||
"custom_fields": {},
|
||
"description": "Display a chat message in the Playground.",
|
||
"display_name": "Chat Output",
|
||
"documentation": "",
|
||
"edited": false,
|
||
"field_order": [
|
||
"input_value",
|
||
"should_store_message",
|
||
"sender",
|
||
"sender_name",
|
||
"session_id",
|
||
"data_template",
|
||
"background_color",
|
||
"chat_icon",
|
||
"text_color"
|
||
],
|
||
"frozen": false,
|
||
"icon": "MessagesSquare",
|
||
"legacy": false,
|
||
"lf_version": "1.4.2",
|
||
"metadata": {},
|
||
"minimized": true,
|
||
"output_types": [],
|
||
"outputs": [
|
||
{
|
||
"allows_loop": false,
|
||
"cache": true,
|
||
"display_name": "Message",
|
||
"method": "message_response",
|
||
"name": "message",
|
||
"selected": "Message",
|
||
"tool_mode": true,
|
||
"types": [
|
||
"Message"
|
||
],
|
||
"value": "__UNDEFINED__"
|
||
}
|
||
],
|
||
"pinned": false,
|
||
"template": {
|
||
"_type": "Component",
|
||
"background_color": {
|
||
"_input_type": "MessageTextInput",
|
||
"advanced": true,
|
||
"display_name": "Background Color",
|
||
"dynamic": false,
|
||
"info": "The background color of the icon.",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "background_color",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": ""
|
||
},
|
||
"chat_icon": {
|
||
"_input_type": "MessageTextInput",
|
||
"advanced": true,
|
||
"display_name": "Icon",
|
||
"dynamic": false,
|
||
"info": "The icon of the message.",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "chat_icon",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": ""
|
||
},
|
||
"clean_data": {
|
||
"_input_type": "BoolInput",
|
||
"advanced": true,
|
||
"display_name": "Basic Clean Data",
|
||
"dynamic": false,
|
||
"info": "Whether to clean the data",
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"name": "clean_data",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_metadata": true,
|
||
"type": "bool",
|
||
"value": true
|
||
},
|
||
"code": {
|
||
"advanced": true,
|
||
"dynamic": true,
|
||
"fileTypes": [],
|
||
"file_path": "",
|
||
"info": "",
|
||
"list": false,
|
||
"load_from_db": false,
|
||
"multiline": true,
|
||
"name": "code",
|
||
"password": false,
|
||
"placeholder": "",
|
||
"required": true,
|
||
"show": true,
|
||
"title_case": false,
|
||
"type": "code",
|
||
"value": "from collections.abc import Generator\nfrom typing import Any\n\nimport orjson\nfrom fastapi.encoders import jsonable_encoder\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.inputs.inputs import HandleInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Source\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n HandleInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n input_types=[\"Data\", \"DataFrame\", \"Message\"],\n required=True,\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n BoolInput(\n name=\"clean_data\",\n display_name=\"Basic Clean Data\",\n value=True,\n info=\"Whether to clean the data\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, id_: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if id_:\n source_dict[\"id\"] = id_\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n # Handle case where source is a ChatOpenAI object\n if hasattr(source, \"model_name\"):\n source_dict[\"source\"] = source.model_name\n elif hasattr(source, \"model\"):\n source_dict[\"source\"] = str(source.model)\n else:\n source_dict[\"source\"] = str(source)\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n # First convert the input to string if needed\n text = self.convert_to_string()\n\n # Get source properties\n source, icon, display_name, source_id = self.get_properties_from_source_component()\n background_color = self.background_color\n text_color = self.text_color\n if self.chat_icon:\n icon = self.chat_icon\n\n # Create or use existing Message object\n if isinstance(self.input_value, Message):\n message = self.input_value\n # Update message properties\n message.text = text\n else:\n message = Message(text=text)\n\n # Set message properties\n message.sender = self.sender\n message.sender_name = self.sender_name\n message.session_id = self.session_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n message.properties.icon = icon\n message.properties.background_color = background_color\n message.properties.text_color = text_color\n\n # Store message if needed\n if self.session_id and self.should_store_message:\n stored_message = await self.send_message(message)\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n\n def _validate_input(self) -> None:\n \"\"\"Validate the input data and raise ValueError if invalid.\"\"\"\n if self.input_value is None:\n msg = \"Input data cannot be None\"\n raise ValueError(msg)\n if isinstance(self.input_value, list) and not all(\n isinstance(item, Message | Data | DataFrame | str) for item in self.input_value\n ):\n invalid_types = [\n type(item).__name__\n for item in self.input_value\n if not isinstance(item, Message | Data | DataFrame | str)\n ]\n msg = f\"Expected Data or DataFrame or Message or str, got {invalid_types}\"\n raise TypeError(msg)\n if not isinstance(\n self.input_value,\n Message | Data | DataFrame | str | list | Generator | type(None),\n ):\n type_name = type(self.input_value).__name__\n msg = f\"Expected Data or DataFrame or Message or str, Generator or None, got {type_name}\"\n raise TypeError(msg)\n\n def _serialize_data(self, data: Data) -> str:\n \"\"\"Serialize Data object to JSON string.\"\"\"\n # Convert data.data to JSON-serializable format\n serializable_data = jsonable_encoder(data.data)\n # Serialize with orjson, enabling pretty printing with indentation\n json_bytes = orjson.dumps(serializable_data, option=orjson.OPT_INDENT_2)\n # Convert bytes to string and wrap in Markdown code blocks\n return \"```json\\n\" + json_bytes.decode(\"utf-8\") + \"\\n```\"\n\n def _safe_convert(self, data: Any) -> str:\n \"\"\"Safely convert input data to string.\"\"\"\n try:\n if isinstance(data, str):\n return data\n if isinstance(data, Message):\n return data.get_text()\n if isinstance(data, Data):\n return self._serialize_data(data)\n if isinstance(data, DataFrame):\n if self.clean_data:\n # Remove empty rows\n data = data.dropna(how=\"all\")\n # Remove empty lines in each cell\n data = data.replace(r\"^\\s*$\", \"\", regex=True)\n # Replace multiple newlines with a single newline\n data = data.replace(r\"\\n+\", \"\\n\", regex=True)\n\n # Replace pipe characters to avoid markdown table issues\n processed_data = data.replace(r\"\\|\", r\"\\\\|\", regex=True)\n\n processed_data = processed_data.map(\n lambda x: str(x).replace(\"\\n\", \"<br/>\") if isinstance(x, str) else x\n )\n\n return processed_data.to_markdown(index=False)\n return str(data)\n except (ValueError, TypeError, AttributeError) as e:\n msg = f\"Error converting data: {e!s}\"\n raise ValueError(msg) from e\n\n def convert_to_string(self) -> str | Generator[Any, None, None]:\n \"\"\"Convert input data to string with proper error handling.\"\"\"\n self._validate_input()\n if isinstance(self.input_value, list):\n return \"\\n\".join([self._safe_convert(item) for item in self.input_value])\n if isinstance(self.input_value, Generator):\n return self.input_value\n return self._safe_convert(self.input_value)\n"
|
||
},
|
||
"data_template": {
|
||
"_input_type": "MessageTextInput",
|
||
"advanced": true,
|
||
"display_name": "Data Template",
|
||
"dynamic": false,
|
||
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "data_template",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": "{text}"
|
||
},
|
||
"input_value": {
|
||
"_input_type": "MessageInput",
|
||
"advanced": false,
|
||
"display_name": "Text",
|
||
"dynamic": false,
|
||
"info": "Message to be passed as output.",
|
||
"input_types": [
|
||
"Data",
|
||
"DataFrame",
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "input_value",
|
||
"placeholder": "",
|
||
"required": true,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": ""
|
||
},
|
||
"sender": {
|
||
"_input_type": "DropdownInput",
|
||
"advanced": true,
|
||
"combobox": false,
|
||
"dialog_inputs": {},
|
||
"display_name": "Sender Type",
|
||
"dynamic": false,
|
||
"info": "Type of sender.",
|
||
"name": "sender",
|
||
"options": [
|
||
"Machine",
|
||
"User"
|
||
],
|
||
"options_metadata": [],
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": "Machine"
|
||
},
|
||
"sender_name": {
|
||
"_input_type": "MessageTextInput",
|
||
"advanced": true,
|
||
"display_name": "Sender Name",
|
||
"dynamic": false,
|
||
"info": "Name of the sender.",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "sender_name",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": "AI"
|
||
},
|
||
"session_id": {
|
||
"_input_type": "MessageTextInput",
|
||
"advanced": true,
|
||
"display_name": "Session ID",
|
||
"dynamic": false,
|
||
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "session_id",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": ""
|
||
},
|
||
"should_store_message": {
|
||
"_input_type": "BoolInput",
|
||
"advanced": true,
|
||
"display_name": "Store Messages",
|
||
"dynamic": false,
|
||
"info": "Store the message in the history.",
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"name": "should_store_message",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_metadata": true,
|
||
"type": "bool",
|
||
"value": true
|
||
},
|
||
"text_color": {
|
||
"_input_type": "MessageTextInput",
|
||
"advanced": true,
|
||
"display_name": "Text Color",
|
||
"dynamic": false,
|
||
"info": "The text color of the name",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "text_color",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": ""
|
||
}
|
||
},
|
||
"tool_mode": false
|
||
},
|
||
"showNode": false,
|
||
"type": "ChatOutput"
|
||
},
|
||
"dragging": false,
|
||
"id": "ChatOutput-oTh2r",
|
||
"measured": {
|
||
"height": 66,
|
||
"width": 192
|
||
},
|
||
"position": {
|
||
"x": 1123.1326758440127,
|
||
"y": 502.35977645059677
|
||
},
|
||
"selected": false,
|
||
"type": "genericNode"
|
||
},
|
||
{
|
||
"data": {
|
||
"id": "ChatInput-5o3G0",
|
||
"node": {
|
||
"base_classes": [
|
||
"Message"
|
||
],
|
||
"beta": false,
|
||
"conditional_paths": [],
|
||
"custom_fields": {},
|
||
"description": "Get chat inputs from the Playground.",
|
||
"display_name": "Chat Input",
|
||
"documentation": "",
|
||
"edited": false,
|
||
"field_order": [
|
||
"input_value",
|
||
"should_store_message",
|
||
"sender",
|
||
"sender_name",
|
||
"session_id",
|
||
"files",
|
||
"background_color",
|
||
"chat_icon",
|
||
"text_color"
|
||
],
|
||
"frozen": false,
|
||
"icon": "MessagesSquare",
|
||
"legacy": false,
|
||
"lf_version": "1.4.2",
|
||
"metadata": {},
|
||
"minimized": true,
|
||
"output_types": [],
|
||
"outputs": [
|
||
{
|
||
"allows_loop": false,
|
||
"cache": true,
|
||
"display_name": "Message",
|
||
"method": "message_response",
|
||
"name": "message",
|
||
"selected": "Message",
|
||
"tool_mode": true,
|
||
"types": [
|
||
"Message"
|
||
],
|
||
"value": "__UNDEFINED__"
|
||
}
|
||
],
|
||
"pinned": false,
|
||
"template": {
|
||
"_type": "Component",
|
||
"background_color": {
|
||
"_input_type": "MessageTextInput",
|
||
"advanced": true,
|
||
"display_name": "Background Color",
|
||
"dynamic": false,
|
||
"info": "The background color of the icon.",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "background_color",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": ""
|
||
},
|
||
"chat_icon": {
|
||
"_input_type": "MessageTextInput",
|
||
"advanced": true,
|
||
"display_name": "Icon",
|
||
"dynamic": false,
|
||
"info": "The icon of the message.",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "chat_icon",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": ""
|
||
},
|
||
"code": {
|
||
"advanced": true,
|
||
"dynamic": true,
|
||
"fileTypes": [],
|
||
"file_path": "",
|
||
"info": "",
|
||
"list": false,
|
||
"load_from_db": false,
|
||
"multiline": true,
|
||
"name": "code",
|
||
"password": false,
|
||
"placeholder": "",
|
||
"required": true,
|
||
"show": true,
|
||
"title_case": false,
|
||
"type": "code",
|
||
"value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import (\n DropdownInput,\n FileInput,\n MessageTextInput,\n MultilineInput,\n Output,\n)\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_USER,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n minimized = True\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n input_types=[],\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n temp_file=True,\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n async def message_response(self) -> Message:\n background_color = self.background_color\n text_color = self.text_color\n icon = self.chat_icon\n\n message = await Message.create(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n properties={\n \"background_color\": background_color,\n \"text_color\": text_color,\n \"icon\": icon,\n },\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = await self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
|
||
},
|
||
"files": {
|
||
"_input_type": "FileInput",
|
||
"advanced": true,
|
||
"display_name": "Files",
|
||
"dynamic": false,
|
||
"fileTypes": [
|
||
"txt",
|
||
"md",
|
||
"mdx",
|
||
"csv",
|
||
"json",
|
||
"yaml",
|
||
"yml",
|
||
"xml",
|
||
"html",
|
||
"htm",
|
||
"pdf",
|
||
"docx",
|
||
"py",
|
||
"sh",
|
||
"sql",
|
||
"js",
|
||
"ts",
|
||
"tsx",
|
||
"jpg",
|
||
"jpeg",
|
||
"png",
|
||
"bmp",
|
||
"image"
|
||
],
|
||
"file_path": "",
|
||
"info": "Files to be sent with the message.",
|
||
"list": true,
|
||
"list_add_label": "Add More",
|
||
"name": "files",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"trace_as_metadata": true,
|
||
"type": "file",
|
||
"value": ""
|
||
},
|
||
"input_value": {
|
||
"_input_type": "MultilineInput",
|
||
"advanced": false,
|
||
"display_name": "Text",
|
||
"dynamic": false,
|
||
"info": "Message to be passed as input.",
|
||
"input_types": [],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"multiline": true,
|
||
"name": "input_value",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": "ai"
|
||
},
|
||
"sender": {
|
||
"_input_type": "DropdownInput",
|
||
"advanced": true,
|
||
"combobox": false,
|
||
"dialog_inputs": {},
|
||
"display_name": "Sender Type",
|
||
"dynamic": false,
|
||
"info": "Type of sender.",
|
||
"name": "sender",
|
||
"options": [
|
||
"Machine",
|
||
"User"
|
||
],
|
||
"options_metadata": [],
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": "User"
|
||
},
|
||
"sender_name": {
|
||
"_input_type": "MessageTextInput",
|
||
"advanced": true,
|
||
"display_name": "Sender Name",
|
||
"dynamic": false,
|
||
"info": "Name of the sender.",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "sender_name",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": "User"
|
||
},
|
||
"session_id": {
|
||
"_input_type": "MessageTextInput",
|
||
"advanced": true,
|
||
"display_name": "Session ID",
|
||
"dynamic": false,
|
||
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "session_id",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": ""
|
||
},
|
||
"should_store_message": {
|
||
"_input_type": "BoolInput",
|
||
"advanced": true,
|
||
"display_name": "Store Messages",
|
||
"dynamic": false,
|
||
"info": "Store the message in the history.",
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"name": "should_store_message",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_metadata": true,
|
||
"type": "bool",
|
||
"value": true
|
||
},
|
||
"text_color": {
|
||
"_input_type": "MessageTextInput",
|
||
"advanced": true,
|
||
"display_name": "Text Color",
|
||
"dynamic": false,
|
||
"info": "The text color of the name",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "text_color",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": ""
|
||
}
|
||
},
|
||
"tool_mode": false
|
||
},
|
||
"showNode": true,
|
||
"type": "ChatInput"
|
||
},
|
||
"dragging": false,
|
||
"id": "ChatInput-5o3G0",
|
||
"measured": {
|
||
"height": 230,
|
||
"width": 320
|
||
},
|
||
"position": {
|
||
"x": -333.65585758816223,
|
||
"y": 107.75353484470551
|
||
},
|
||
"selected": false,
|
||
"type": "genericNode"
|
||
},
|
||
{
|
||
"data": {
|
||
"id": "note-Wcn5J",
|
||
"node": {
|
||
"description": "### 💡 Add your Anthropic API key here 👇",
|
||
"display_name": "",
|
||
"documentation": "",
|
||
"template": {
|
||
"backgroundColor": "transparent"
|
||
}
|
||
},
|
||
"type": "note"
|
||
},
|
||
"dragging": false,
|
||
"height": 324,
|
||
"id": "note-Wcn5J",
|
||
"measured": {
|
||
"height": 324,
|
||
"width": 358
|
||
},
|
||
"position": {
|
||
"x": 1479.4278434913201,
|
||
"y": -274.26903478612456
|
||
},
|
||
"resizing": false,
|
||
"selected": false,
|
||
"type": "noteNode",
|
||
"width": 359
|
||
},
|
||
{
|
||
"data": {
|
||
"id": "note-jY0b1",
|
||
"node": {
|
||
"description": "# **Langflow Loop Component Template - ArXiv search result Translator** \nThis template translates research paper summaries on ArXiv into Portuguese and summarizes them. \n Using **Langflow’s looping mechanism**, the template iterates through multiple research papers, translates them with the **Anthropic** model component, and outputs an aggregated version of all translated papers. \n\n## Quickstart \n 1. Add your Anthropic API key to the **Anthropic** component. \n2. In the **Playground**, enter a query related to a research topic (for example, “Quantum Computing Advancements”). \n\n The flow fetches a list of research papers from ArXiv matching the query. Each paper in the retrieved list is processed one-by-one using the Langflow **Loop component**. \n\n The abstract of each paper is translated into Portuguese by the **Anthropic** model component. \n\n Once all papers are translated, the system aggregates them into a **single structured output**.",
|
||
"display_name": "",
|
||
"documentation": "",
|
||
"template": {}
|
||
},
|
||
"type": "note"
|
||
},
|
||
"dragging": false,
|
||
"height": 647,
|
||
"id": "note-jY0b1",
|
||
"measured": {
|
||
"height": 647,
|
||
"width": 577
|
||
},
|
||
"position": {
|
||
"x": -890.9006297459302,
|
||
"y": -233.44894493951168
|
||
},
|
||
"resizing": false,
|
||
"selected": false,
|
||
"type": "noteNode",
|
||
"width": 576
|
||
},
|
||
{
|
||
"data": {
|
||
"id": "ParserComponent-ZhlLQ",
|
||
"node": {
|
||
"base_classes": [
|
||
"Message"
|
||
],
|
||
"beta": false,
|
||
"category": "processing",
|
||
"conditional_paths": [],
|
||
"custom_fields": {},
|
||
"description": "Format a DataFrame or Data object into text using a template. Enable 'Stringify' to convert input into a readable string instead.",
|
||
"display_name": "Parser",
|
||
"documentation": "",
|
||
"edited": false,
|
||
"field_order": [
|
||
"mode",
|
||
"pattern",
|
||
"input_data",
|
||
"sep"
|
||
],
|
||
"frozen": false,
|
||
"icon": "braces",
|
||
"key": "ParserComponent",
|
||
"legacy": false,
|
||
"lf_version": "1.4.2",
|
||
"metadata": {},
|
||
"minimized": false,
|
||
"output_types": [],
|
||
"outputs": [
|
||
{
|
||
"allows_loop": false,
|
||
"cache": true,
|
||
"display_name": "Parsed Text",
|
||
"method": "parse_combined_text",
|
||
"name": "parsed_text",
|
||
"selected": "Message",
|
||
"tool_mode": true,
|
||
"types": [
|
||
"Message"
|
||
],
|
||
"value": "__UNDEFINED__"
|
||
}
|
||
],
|
||
"pinned": false,
|
||
"score": 0.001,
|
||
"template": {
|
||
"_type": "Component",
|
||
"code": {
|
||
"advanced": true,
|
||
"dynamic": true,
|
||
"fileTypes": [],
|
||
"file_path": "",
|
||
"info": "",
|
||
"list": false,
|
||
"load_from_db": false,
|
||
"multiline": true,
|
||
"name": "code",
|
||
"password": false,
|
||
"placeholder": "",
|
||
"required": true,
|
||
"show": true,
|
||
"title_case": false,
|
||
"type": "code",
|
||
"value": "import json\nfrom typing import Any\n\nfrom langflow.custom import Component\nfrom langflow.io import (\n BoolInput,\n HandleInput,\n MessageTextInput,\n MultilineInput,\n Output,\n TabInput,\n)\nfrom langflow.schema import Data, DataFrame\nfrom langflow.schema.message import Message\n\n\nclass ParserComponent(Component):\n display_name = \"Parser\"\n description = (\n \"Format a DataFrame or Data object into text using a template. \"\n \"Enable 'Stringify' to convert input into a readable string instead.\"\n )\n icon = \"braces\"\n\n inputs = [\n TabInput(\n name=\"mode\",\n display_name=\"Mode\",\n options=[\"Parser\", \"Stringify\"],\n value=\"Parser\",\n info=\"Convert into raw string instead of using a template.\",\n real_time_refresh=True,\n ),\n MultilineInput(\n name=\"pattern\",\n display_name=\"Template\",\n info=(\n \"Use variables within curly brackets to extract column values for DataFrames \"\n \"or key values for Data.\"\n \"For example: `Name: {Name}, Age: {Age}, Country: {Country}`\"\n ),\n value=\"Text: {text}\", # Example default\n dynamic=True,\n show=True,\n required=True,\n ),\n HandleInput(\n name=\"input_data\",\n display_name=\"Data or DataFrame\",\n input_types=[\"DataFrame\", \"Data\"],\n info=\"Accepts either a DataFrame or a Data object.\",\n required=True,\n ),\n MessageTextInput(\n name=\"sep\",\n display_name=\"Separator\",\n advanced=True,\n value=\"\\n\",\n info=\"String used to separate rows/items.\",\n ),\n ]\n\n outputs = [\n Output(\n display_name=\"Parsed Text\",\n name=\"parsed_text\",\n info=\"Formatted text output.\",\n method=\"parse_combined_text\",\n ),\n ]\n\n def update_build_config(self, build_config, field_value, field_name=None):\n \"\"\"Dynamically hide/show `template` and enforce requirement based on `stringify`.\"\"\"\n if field_name == \"mode\":\n build_config[\"pattern\"][\"show\"] = self.mode == \"Parser\"\n build_config[\"pattern\"][\"required\"] = self.mode == \"Parser\"\n if field_value:\n clean_data = BoolInput(\n name=\"clean_data\",\n display_name=\"Clean Data\",\n info=(\n \"Enable to clean the data by removing empty rows and lines \"\n \"in each cell of the DataFrame/ Data object.\"\n ),\n value=True,\n advanced=True,\n required=False,\n )\n build_config[\"clean_data\"] = clean_data.to_dict()\n else:\n build_config.pop(\"clean_data\", None)\n\n return build_config\n\n def _clean_args(self):\n \"\"\"Prepare arguments based on input type.\"\"\"\n input_data = self.input_data\n\n match input_data:\n case list() if all(isinstance(item, Data) for item in input_data):\n msg = \"List of Data objects is not supported.\"\n raise ValueError(msg)\n case DataFrame():\n return input_data, None\n case Data():\n return None, input_data\n case dict() if \"data\" in input_data:\n try:\n if \"columns\" in input_data: # Likely a DataFrame\n return DataFrame.from_dict(input_data), None\n # Likely a Data object\n return None, Data(**input_data)\n except (TypeError, ValueError, KeyError) as e:\n msg = f\"Invalid structured input provided: {e!s}\"\n raise ValueError(msg) from e\n case _:\n msg = f\"Unsupported input type: {type(input_data)}. Expected DataFrame or Data.\"\n raise ValueError(msg)\n\n def parse_combined_text(self) -> Message:\n \"\"\"Parse all rows/items into a single text or convert input to string if `stringify` is enabled.\"\"\"\n # Early return for stringify option\n if self.mode == \"Stringify\":\n return self.convert_to_string()\n\n df, data = self._clean_args()\n\n lines = []\n if df is not None:\n for _, row in df.iterrows():\n formatted_text = self.pattern.format(**row.to_dict())\n lines.append(formatted_text)\n elif data is not None:\n formatted_text = self.pattern.format(**data.data)\n lines.append(formatted_text)\n\n combined_text = self.sep.join(lines)\n self.status = combined_text\n return Message(text=combined_text)\n\n def _safe_convert(self, data: Any) -> str:\n \"\"\"Safely convert input data to string.\"\"\"\n try:\n if isinstance(data, str):\n return data\n if isinstance(data, Message):\n return data.get_text()\n if isinstance(data, Data):\n return json.dumps(data.data)\n if isinstance(data, DataFrame):\n if hasattr(self, \"clean_data\") and self.clean_data:\n # Remove empty rows\n data = data.dropna(how=\"all\")\n # Remove empty lines in each cell\n data = data.replace(r\"^\\s*$\", \"\", regex=True)\n # Replace multiple newlines with a single newline\n data = data.replace(r\"\\n+\", \"\\n\", regex=True)\n return data.to_markdown(index=False)\n return str(data)\n except (ValueError, TypeError, AttributeError) as e:\n msg = f\"Error converting data: {e!s}\"\n raise ValueError(msg) from e\n\n def convert_to_string(self) -> Message:\n \"\"\"Convert input data to string with proper error handling.\"\"\"\n result = \"\"\n if isinstance(self.input_data, list):\n result = \"\\n\".join([self._safe_convert(item) for item in self.input_data])\n else:\n result = self._safe_convert(self.input_data)\n self.log(f\"Converted to string with length: {len(result)}\")\n\n message = Message(text=result)\n self.status = message\n return message\n"
|
||
},
|
||
"input_data": {
|
||
"_input_type": "HandleInput",
|
||
"advanced": false,
|
||
"display_name": "Data or DataFrame",
|
||
"dynamic": false,
|
||
"info": "Accepts either a DataFrame or a Data object.",
|
||
"input_types": [
|
||
"DataFrame",
|
||
"Data"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"name": "input_data",
|
||
"placeholder": "",
|
||
"required": true,
|
||
"show": true,
|
||
"title_case": false,
|
||
"trace_as_metadata": true,
|
||
"type": "other",
|
||
"value": ""
|
||
},
|
||
"mode": {
|
||
"_input_type": "TabInput",
|
||
"advanced": false,
|
||
"display_name": "Mode",
|
||
"dynamic": false,
|
||
"info": "Convert into raw string instead of using a template.",
|
||
"name": "mode",
|
||
"options": [
|
||
"Parser",
|
||
"Stringify"
|
||
],
|
||
"placeholder": "",
|
||
"real_time_refresh": true,
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_metadata": true,
|
||
"type": "tab",
|
||
"value": "Stringify"
|
||
},
|
||
"pattern": {
|
||
"_input_type": "MultilineInput",
|
||
"advanced": false,
|
||
"copy_field": false,
|
||
"display_name": "Template",
|
||
"dynamic": true,
|
||
"info": "Use variables within curly brackets to extract column values for DataFrames or key values for Data.For example: `Name: {Name}, Age: {Age}, Country: {Country}`",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"multiline": true,
|
||
"name": "pattern",
|
||
"placeholder": "",
|
||
"required": true,
|
||
"show": false,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": "Text: {dt}"
|
||
},
|
||
"sep": {
|
||
"_input_type": "MessageTextInput",
|
||
"advanced": true,
|
||
"display_name": "Separator",
|
||
"dynamic": false,
|
||
"info": "String used to separate rows/items.",
|
||
"input_types": [
|
||
"Message"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"load_from_db": false,
|
||
"name": "sep",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"tool_mode": false,
|
||
"trace_as_input": true,
|
||
"trace_as_metadata": true,
|
||
"type": "str",
|
||
"value": "\n"
|
||
}
|
||
},
|
||
"tool_mode": false
|
||
},
|
||
"showNode": true,
|
||
"type": "ParserComponent"
|
||
},
|
||
"dragging": false,
|
||
"id": "ParserComponent-ZhlLQ",
|
||
"measured": {
|
||
"height": 312,
|
||
"width": 320
|
||
},
|
||
"position": {
|
||
"x": 971.3987248215344,
|
||
"y": -186.6658506576822
|
||
},
|
||
"selected": false,
|
||
"type": "genericNode"
|
||
},
|
||
{
|
||
"data": {
|
||
"id": "LoopComponent-9BK8B",
|
||
"node": {
|
||
"base_classes": [
|
||
"Data",
|
||
"DataFrame"
|
||
],
|
||
"beta": false,
|
||
"category": "logic",
|
||
"conditional_paths": [],
|
||
"custom_fields": {},
|
||
"description": "Iterates over a list of Data objects, outputting one item at a time and aggregating results from loop inputs.",
|
||
"display_name": "Loop",
|
||
"documentation": "",
|
||
"edited": false,
|
||
"field_order": [
|
||
"data"
|
||
],
|
||
"frozen": false,
|
||
"icon": "infinity",
|
||
"key": "LoopComponent",
|
||
"legacy": false,
|
||
"lf_version": "1.4.2",
|
||
"metadata": {},
|
||
"minimized": false,
|
||
"output_types": [],
|
||
"outputs": [
|
||
{
|
||
"allows_loop": true,
|
||
"cache": true,
|
||
"display_name": "Item",
|
||
"method": "item_output",
|
||
"name": "item",
|
||
"selected": "Data",
|
||
"tool_mode": true,
|
||
"types": [
|
||
"Data"
|
||
],
|
||
"value": "__UNDEFINED__"
|
||
},
|
||
{
|
||
"allows_loop": false,
|
||
"cache": true,
|
||
"display_name": "Done",
|
||
"method": "done_output",
|
||
"name": "done",
|
||
"selected": "DataFrame",
|
||
"tool_mode": true,
|
||
"types": [
|
||
"DataFrame"
|
||
],
|
||
"value": "__UNDEFINED__"
|
||
}
|
||
],
|
||
"pinned": false,
|
||
"score": 2.220446049250313e-16,
|
||
"template": {
|
||
"_type": "Component",
|
||
"code": {
|
||
"advanced": true,
|
||
"dynamic": true,
|
||
"fileTypes": [],
|
||
"file_path": "",
|
||
"info": "",
|
||
"list": false,
|
||
"load_from_db": false,
|
||
"multiline": true,
|
||
"name": "code",
|
||
"password": false,
|
||
"placeholder": "",
|
||
"required": true,
|
||
"show": true,
|
||
"title_case": false,
|
||
"type": "code",
|
||
"value": "from langflow.custom import Component\nfrom langflow.io import HandleInput, Output\nfrom langflow.schema import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass LoopComponent(Component):\n display_name = \"Loop\"\n description = (\n \"Iterates over a list of Data objects, outputting one item at a time and aggregating results from loop inputs.\"\n )\n icon = \"infinity\"\n\n inputs = [\n HandleInput(\n name=\"data\",\n display_name=\"Data or DataFrame\",\n info=\"The initial list of Data objects or DataFrame to iterate over.\",\n input_types=[\"Data\", \"DataFrame\"],\n ),\n ]\n\n outputs = [\n Output(display_name=\"Item\", name=\"item\", method=\"item_output\", allows_loop=True),\n Output(display_name=\"Done\", name=\"done\", method=\"done_output\"),\n ]\n\n def initialize_data(self) -> None:\n \"\"\"Initialize the data list, context index, and aggregated list.\"\"\"\n if self.ctx.get(f\"{self._id}_initialized\", False):\n return\n\n # Ensure data is a list of Data objects\n data_list = self._validate_data(self.data)\n\n # Store the initial data and context variables\n self.update_ctx(\n {\n f\"{self._id}_data\": data_list,\n f\"{self._id}_index\": 0,\n f\"{self._id}_aggregated\": [],\n f\"{self._id}_initialized\": True,\n }\n )\n\n def _validate_data(self, data):\n \"\"\"Validate and return a list of Data objects.\"\"\"\n if isinstance(data, DataFrame):\n return data.to_data_list()\n if isinstance(data, Data):\n return [data]\n if isinstance(data, list) and all(isinstance(item, Data) for item in data):\n return data\n msg = \"The 'data' input must be a DataFrame, a list of Data objects, or a single Data object.\"\n raise TypeError(msg)\n\n def evaluate_stop_loop(self) -> bool:\n \"\"\"Evaluate whether to stop item or done output.\"\"\"\n current_index = self.ctx.get(f\"{self._id}_index\", 0)\n data_length = len(self.ctx.get(f\"{self._id}_data\", []))\n return current_index > data_length\n\n def item_output(self) -> Data:\n \"\"\"Output the next item in the list or stop if done.\"\"\"\n self.initialize_data()\n current_item = Data(text=\"\")\n\n if self.evaluate_stop_loop():\n self.stop(\"item\")\n return Data(text=\"\")\n\n # Get data list and current index\n data_list, current_index = self.loop_variables()\n if current_index < len(data_list):\n # Output current item and increment index\n try:\n current_item = data_list[current_index]\n except IndexError:\n current_item = Data(text=\"\")\n self.aggregated_output()\n self.update_ctx({f\"{self._id}_index\": current_index + 1})\n return current_item\n\n def done_output(self) -> DataFrame:\n \"\"\"Trigger the done output when iteration is complete.\"\"\"\n self.initialize_data()\n\n if self.evaluate_stop_loop():\n self.stop(\"item\")\n self.start(\"done\")\n\n aggregated = self.ctx.get(f\"{self._id}_aggregated\", [])\n\n return DataFrame(aggregated)\n self.stop(\"done\")\n return DataFrame([])\n\n def loop_variables(self):\n \"\"\"Retrieve loop variables from context.\"\"\"\n return (\n self.ctx.get(f\"{self._id}_data\", []),\n self.ctx.get(f\"{self._id}_index\", 0),\n )\n\n def aggregated_output(self) -> list[Data]:\n \"\"\"Return the aggregated list once all items are processed.\"\"\"\n self.initialize_data()\n\n # Get data list and aggregated list\n data_list = self.ctx.get(f\"{self._id}_data\", [])\n aggregated = self.ctx.get(f\"{self._id}_aggregated\", [])\n loop_input = self.item\n if loop_input is not None and not isinstance(loop_input, str) and len(aggregated) <= len(data_list):\n aggregated.append(loop_input)\n self.update_ctx({f\"{self._id}_aggregated\": aggregated})\n return aggregated\n"
|
||
},
|
||
"data": {
|
||
"_input_type": "HandleInput",
|
||
"advanced": false,
|
||
"display_name": "Data or DataFrame",
|
||
"dynamic": false,
|
||
"info": "The initial list of Data objects or DataFrame to iterate over.",
|
||
"input_types": [
|
||
"Data",
|
||
"DataFrame"
|
||
],
|
||
"list": false,
|
||
"list_add_label": "Add More",
|
||
"name": "data",
|
||
"placeholder": "",
|
||
"required": false,
|
||
"show": true,
|
||
"title_case": false,
|
||
"trace_as_metadata": true,
|
||
"type": "other",
|
||
"value": ""
|
||
}
|
||
},
|
||
"tool_mode": false
|
||
},
|
||
"showNode": true,
|
||
"type": "LoopComponent"
|
||
},
|
||
"dragging": false,
|
||
"id": "LoopComponent-9BK8B",
|
||
"measured": {
|
||
"height": 280,
|
||
"width": 320
|
||
},
|
||
"position": {
|
||
"x": 541.1188345961908,
|
||
"y": 181.38181401206583
|
||
},
|
||
"selected": false,
|
||
"type": "genericNode"
|
||
}
|
||
],
|
||
"viewport": {
|
||
"x": -116.69751133397563,
|
||
"y": 176.89760533769663,
|
||
"zoom": 0.5570453295917549
|
||
}
|
||
},
|
||
"description": "This template iterates over search results using LoopComponent and translates each result into Portuguese automatically. 🚀",
|
||
"endpoint_name": null,
|
||
"id": "105a54e1-198e-468e-8bb2-3a037f4d595a",
|
||
"is_component": false,
|
||
"last_tested_version": "1.4.2",
|
||
"name": "Research Translation Loop",
|
||
"tags": [
|
||
"chatbots",
|
||
"content-generation"
|
||
]
|
||
} |