langflow/src/backend/base/langflow/initial_setup/starter_projects/Research Translation Loop.json
Yuqi Tang 19cc82f45c
fix: update several other templates (#8569)
* Update Vector Store RAG.json

* fix: make starter projects auto refactor not remove selected output (#8400)

* Fixed bug where starter projects were refactored incorrectly

* fix: improve handling of selected outputs in custom component template builder

- Added checks to ensure selected output is valid before attempting to set its state.
- Enhanced code readability with comments explaining the logic for selecting outputs.

* Set selected output as the previous selected output

* Update base.py

---------

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
Co-authored-by: Edwin Jose <edwin.jose@datastax.com>

* fix: made clean edges clean after changing dropdown of output (#8460)

fixed output considering all outputs not just selected one

* refactor(docker): remove --extra deploy flag from uv sync commands (#8485)

🔧 (build_and_push_with_extras.Dockerfile): remove unnecessary uv sync command options to improve build efficiency and reduce redundancy

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>

* fix: refactor mcp and freeze tests to be less prone to flaky results (#8486)

* Fixed mcp test to be less prone to errors

* Fix freeze spec

* fix: made button disabled state more congruent, made edit flow details submit on enter (#8339)

* Changed textarea classes

* Changed flowsettingscomponent to use form

* changed edit flow settings to use form and to submit on enter

* Reset form data on close

* Updated disabled state to have lower opacity instead of to have set background

* Fixed loading state of button

* Fix: chat memory store issue and fix output types (#8463)

* fix chat memory

* update template

* update update outputs

* update update outputs

---------

Co-authored-by: Edwin Jose <edwin.jose@datastax.com>

* ci: update setup-uv to possibly fix caching (#8490)

* update templates

* update templates

* First round of template updates

* Update templates

* fix: Update SaaS, Social Media, and YouTube json file (#8441)

* update SaaS, Social Media, and YouTube json file

* fix: make starter projects auto refactor not remove selected output (#8400)

* Fixed bug where starter projects were refactored incorrectly

* fix: improve handling of selected outputs in custom component template builder

- Added checks to ensure selected output is valid before attempting to set its state.
- Enhanced code readability with comments explaining the logic for selecting outputs.

* Set selected output as the previous selected output

* Update base.py

---------

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
Co-authored-by: Edwin Jose <edwin.jose@datastax.com>

* fix: made clean edges clean after changing dropdown of output (#8460)

fixed output considering all outputs not just selected one

* refactor(docker): remove --extra deploy flag from uv sync commands (#8485)

🔧 (build_and_push_with_extras.Dockerfile): remove unnecessary uv sync command options to improve build efficiency and reduce redundancy

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>

* fix: refactor mcp and freeze tests to be less prone to flaky results (#8486)

* Fixed mcp test to be less prone to errors

* Fix freeze spec

* fix: made button disabled state more congruent, made edit flow details submit on enter (#8339)

* Changed textarea classes

* Changed flowsettingscomponent to use form

* changed edit flow settings to use form and to submit on enter

* Reset form data on close

* Updated disabled state to have lower opacity instead of to have set background

* Fixed loading state of button

* Fix: chat memory store issue and fix output types (#8463)

* fix chat memory

* update template

* update update outputs

* update update outputs

---------

Co-authored-by: Edwin Jose <edwin.jose@datastax.com>

* ci: update setup-uv to possibly fix caching (#8490)

* update json

* fix custom component

* revert change

---------

Co-authored-by: Lucas Oliveira <62335616+lucaseduoli@users.noreply.github.com>
Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
Co-authored-by: Cristhian Zanforlin Lousa <cristhian.lousa@gmail.com>

* fix: templates (#8499)

* basic-prompting-template-updated

* show-system-message

* names

* blog-writer-tested

* financial-report-parser

* image-sentiment-analysis

* seo-keyword-generator

* seo-keyword-generator

* Merge branch 'fix-vector-search-template' into mendons-template-branch

---------

Co-authored-by: Eric Hare <ericrhare@gmail.com>

* Update Basic Prompting.json

* Update Blog Writer.json

* Further template updates

* Update Image Sentiment Analysis.json

* Update templates

* Update Financial Report Parser.json

* Update Market Research.json

* Update Market Research.json

* update several templates

* Update Image Sentiment Analysis.json

* Update Market Research.json

* Update image sentiment analysis template

* Update Market Research.json

* Update Custom Component Maker.json

* Update Custom Component Maker.json

* Update Hybrid Search RAG.json

* Update Hybrid Search RAG.json

* Update Hybrid Search RAG.json

* More template updates

* Update Financial Report Parser.json

* updated templates

* change custom component maker

* Update Twitter Thread Generator.json

* updates from main

* change model

* Update Research Translation Loop.json

* expanded output component to fix tests

* update template

* autofix

* fix error

* fix change back

* change back

* ci: Skip truncated values test for refactoring (#8670)

* refactor: simplify init target by removing cache cleanup and adding pre-commit hook (#8590)

* build: add pyyaml dependency

* refactor: simplify init command by removing cache cleaning and langflow run call

* refactor: simplify init target by removing cache cleanup and adding pre-commit hook

* refactor: update langchain_core.prompts import paths to use specific modules

---------

Co-authored-by: Edwin Jose <edwin.jose@datastax.com>

* feat: update structured output to multiline input and revise system prompt (#8585)

* Update structured_output.py

* [autofix.ci] apply automated fixes

* Update structured_output.py

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* update to prompt

* template updates

* Update src/backend/base/langflow/components/processing/structured_output.py

* [autofix.ci] apply automated fixes

* Update src/backend/base/langflow/components/processing/structured_output.py

* Update src/backend/base/langflow/components/processing/structured_output.py

* Update src/backend/base/langflow/components/processing/structured_output.py

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

* feat: add sessions endpoint with session management enhancements (#8596)

* 📝 (monitor.py): Add endpoint to get sessions and handle session_id encoding for API requests
📝 (use-get-messages-mutation.ts): Implement a mutation function to fetch messages with query parameters and handle session_id encoding for API requests
📝 (use-get-messages-polling.ts): Ensure proper encoding of session_id for API requests in polling mutation
📝 (use-get-messages.ts): Handle session_id encoding for API requests in messages query
📝 (new-modal.tsx): Implement functions to handle session deletion and proper encoding of session_id for API requests
📝 (utils.ts): Add functions to encode, decode, validate, format, and prepare session IDs for API requests

* 📝 (constants.ts): Add SESSIONS constant to API URLs for monitoring sessions
🔧 (use-delete-messages.ts): Add queryClient to UseRequestProcessor to invalidate sessions query
 (use-get-sessions-from-flow.ts): Introduce useGetSessionsFromFlowQuery to fetch sessions from flow
🔧 (use-rename-session.ts): Change refetchQueries to invalidateQueries for useGetSessionsFromFlowQuery
🔧 (custom-new-modal.tsx): Update import path for IOModal to playground-modal
🔧 (session-selector.tsx): Add setActiveSession function to handle setting active session
🔧 (sidebar-open-view.tsx): Add setActiveSession function to handle setting active session
♻️ (new-modal.tsx): Refactor IOModal into playground-modal and update functionality
♻️ (playground-modal.tsx): Refactor IOModal to handle playground-specific functionality
⬆️ (flowStore.ts): Add newChatOnPlayground state and setNewChatOnPlayground function
⬆️ (index.ts): Update FlowStoreType to include newChatOnPlayground and setNewChatOnPlayground

* 🔧 (pyproject.toml): update testpaths to point to the correct directory for tests
 (test_session_endpoint.py): add unit tests for sessions endpoint with flow_id filtering
♻️ (session-selector.tsx): refactor to trim editedSession before setting it
♻️ (sidebar-open-view.tsx): refactor to set visibleSession instead of activeSession

*  (use-get-sessions-from-flow.ts): Always include the flow ID as the default session if it's not already present
♻️ (playground-modal.tsx): Refactor setting sessions to include currentFlowId as the default session if not present, and handle visibility of sessions more efficiently

* ♻️ (use-get-messages-mutation.ts): remove unused imports and refactor code for better readability and maintainability

*  (test_session_endpoint.py): refactor test function names for better clarity and consistency

*  (create-new-session-name.ts): add function to generate a new session name based on the current date and time
🔧 (playground-modal.tsx): import createNewSessionName function to dynamically set a new session name when no session is visible

* [autofix.ci] apply automated fixes

*  (monitor.py): rename get_sessions endpoint to get_message_sessions for clarity and consistency
🔧 (constants.ts): remove unused SESSIONS constant from API URLs
🔧 (use-delete-messages.ts): remove commented out code and unnecessary comments
 (use-delete-sessions.ts): add functionality to delete sessions in frontend
🔧 (use-get-sessions-from-flow.ts): update API endpoint for getting sessions to match backend changes
🔧 (playground-modal.tsx): add functionality to delete sessions and associated messages in the UI, update UI optimistically, and handle errors appropriately

* [autofix.ci] apply automated fixes

* 🐛 (monitor.py): Fix type hinting issue in delete_messages function
📝 (monitor.py): Add comments and improve readability in test_messages_endpoints.py
📝 (session_endpoint.py): Update endpoint paths for consistency and clarity in test_session_endpoint.py

* [autofix.ci] apply automated fixes

* fix: update SQL statement to use col() for session_id filtering in get_message_sessions function

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>

* fix: implemented cached values and temporary MCP servers on MCP component (#8628)

* Added actionCount to fetch only servers without actionCount

* Updated queries and uses to use servers without action data first, and then to fetch them

* removed comment

* updated constants

* Added loading dropdown

* Make options persist

* Implemented new value format for McpComponent and implemented saving and removing temp Mcp Server if config is existent

* Changed value type

* Implemented cache and saving the server config

* Fixed mcp server test

* fix backend formatting

* fixed lint

* Added await

* Fixed save button not appearing when no servers are available

* added condition to only show save button when options is not null

* template autofix

* change template

* update text sentiment analysis

* change basic prompt back

* change image sentiment back

* update text sentiment and twitter

* Update Twitter Thread Generator.json

* Add back the input for the chat

* add change

* fix text sentiment

* update research translation

* Update Research Translation Loop.json

---------

Co-authored-by: Eric Hare <ericrhare@gmail.com>
Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
Co-authored-by: Lucas Oliveira <62335616+lucaseduoli@users.noreply.github.com>
Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
Co-authored-by: Cristhian Zanforlin Lousa <cristhian.lousa@gmail.com>
Co-authored-by: Mendon Kissling <59585235+mendonk@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-06-23 20:39:28 +00:00

1889 lines
No EOL
103 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"data": {
"edges": [
{
"animated": false,
"className": "",
"data": {
"sourceHandle": {
"dataType": "ChatInput",
"id": "ChatInput-OF2vZ",
"name": "message",
"output_types": [
"Message"
]
},
"targetHandle": {
"fieldName": "search_query",
"id": "ArXivComponent-WxSYF",
"inputTypes": [
"Message"
],
"type": "str"
}
},
"id": "reactflow__edge-ChatInput-OF2vZ{œdataTypeœ:œChatInputœ,œidœ:œChatInput-OF2vZœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-ArXivComponent-WxSYF{œfieldNameœ:œsearch_queryœ,œidœ:œArXivComponent-WxSYFœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
"selected": false,
"source": "ChatInput-OF2vZ",
"sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-OF2vZœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
"target": "ArXivComponent-WxSYF",
"targetHandle": "{œfieldNameœ: œsearch_queryœ, œidœ: œArXivComponent-WxSYFœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
"className": "",
"data": {
"sourceHandle": {
"dataType": "ArXivComponent",
"id": "ArXivComponent-WxSYF",
"name": "dataframe",
"output_types": [
"DataFrame"
]
},
"targetHandle": {
"fieldName": "data",
"id": "LoopComponent-zuKTL",
"inputTypes": [
"DataFrame"
],
"type": "other"
}
},
"id": "reactflow__edge-ArXivComponent-WxSYF{œdataTypeœ:œArXivComponentœ,œidœ:œArXivComponent-WxSYFœ,œnameœ:œdataframeœ,œoutput_typesœ:[œDataFrameœ]}-LoopComponent-zuKTL{œfieldNameœ:œdataœ,œidœ:œLoopComponent-zuKTLœ,œinputTypesœ:[œDataFrameœ],œtypeœ:œotherœ}",
"selected": false,
"source": "ArXivComponent-WxSYF",
"sourceHandle": "{œdataTypeœ: œArXivComponentœ, œidœ: œArXivComponent-WxSYFœ, œnameœ: œdataframeœ, œoutput_typesœ: [œDataFrameœ]}",
"target": "LoopComponent-zuKTL",
"targetHandle": "{œfieldNameœ: œdataœ, œidœ: œLoopComponent-zuKTLœ, œinputTypesœ: [œDataFrameœ], œtypeœ: œotherœ}"
},
{
"animated": false,
"className": "",
"data": {
"sourceHandle": {
"dataType": "LoopComponent",
"id": "LoopComponent-zuKTL",
"name": "item",
"output_types": [
"Data"
]
},
"targetHandle": {
"fieldName": "input_data",
"id": "ParserComponent-2OCL9",
"inputTypes": [
"DataFrame",
"Data"
],
"type": "other"
}
},
"id": "reactflow__edge-LoopComponent-zuKTL{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-zuKTLœ,œnameœ:œitemœ,œoutput_typesœ:[œDataœ]}-ParserComponent-2OCL9{œfieldNameœ:œinput_dataœ,œidœ:œParserComponent-2OCL9œ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}",
"selected": false,
"source": "LoopComponent-zuKTL",
"sourceHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-zuKTLœ, œnameœ: œitemœ, œoutput_typesœ: [œDataœ]}",
"target": "ParserComponent-2OCL9",
"targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œParserComponent-2OCL9œ, œinputTypesœ: [œDataFrameœ, œDataœ], œtypeœ: œotherœ}"
},
{
"animated": false,
"className": "",
"data": {
"sourceHandle": {
"dataType": "LoopComponent",
"id": "LoopComponent-zuKTL",
"name": "done",
"output_types": [
"DataFrame"
]
},
"targetHandle": {
"fieldName": "input_data",
"id": "TypeConverterComponent-mWgMR",
"inputTypes": [
"Message",
"Data",
"DataFrame"
],
"type": "other"
}
},
"id": "reactflow__edge-LoopComponent-zuKTL{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-zuKTLœ,œnameœ:œdoneœ,œoutput_typesœ:[œDataFrameœ]}-TypeConverterComponent-mWgMR{œfieldNameœ:œinput_dataœ,œidœ:œTypeConverterComponent-mWgMRœ,œinputTypesœ:[œMessageœ,œDataœ,œDataFrameœ],œtypeœ:œotherœ}",
"selected": false,
"source": "LoopComponent-zuKTL",
"sourceHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-zuKTLœ, œnameœ: œdoneœ, œoutput_typesœ: [œDataFrameœ]}",
"target": "TypeConverterComponent-mWgMR",
"targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œTypeConverterComponent-mWgMRœ, œinputTypesœ: [œMessageœ, œDataœ, œDataFrameœ], œtypeœ: œotherœ}"
},
{
"animated": false,
"className": "",
"data": {
"sourceHandle": {
"dataType": "TypeConverterComponent",
"id": "TypeConverterComponent-mWgMR",
"name": "message_output",
"output_types": [
"Message"
]
},
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-ylHrO",
"inputTypes": [
"Data",
"DataFrame",
"Message"
],
"type": "other"
}
},
"id": "reactflow__edge-TypeConverterComponent-mWgMR{œdataTypeœ:œTypeConverterComponentœ,œidœ:œTypeConverterComponent-mWgMRœ,œnameœ:œmessage_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-ylHrO{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-ylHrOœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}",
"selected": false,
"source": "TypeConverterComponent-mWgMR",
"sourceHandle": "{œdataTypeœ: œTypeConverterComponentœ, œidœ: œTypeConverterComponent-mWgMRœ, œnameœ: œmessage_outputœ, œoutput_typesœ: [œMessageœ]}",
"target": "ChatOutput-ylHrO",
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-ylHrOœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}"
},
{
"animated": false,
"className": "",
"data": {
"sourceHandle": {
"dataType": "ParserComponent",
"id": "ParserComponent-2OCL9",
"name": "parsed_text",
"output_types": [
"Message"
]
},
"targetHandle": {
"fieldName": "input_value",
"id": "LanguageModelComponent-Te29P",
"inputTypes": [
"Message"
],
"type": "str"
}
},
"id": "reactflow__edge-ParserComponent-2OCL9{œdataTypeœ:œParserComponentœ,œidœ:œParserComponent-2OCL9œ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-Te29P{œfieldNameœ:œinput_valueœ,œidœ:œLanguageModelComponent-Te29Pœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
"selected": false,
"source": "ParserComponent-2OCL9",
"sourceHandle": "{œdataTypeœ: œParserComponentœ, œidœ: œParserComponent-2OCL9œ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}",
"target": "LanguageModelComponent-Te29P",
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œLanguageModelComponent-Te29Pœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
"className": "",
"data": {
"sourceHandle": {
"dataType": "LanguageModelComponent",
"id": "LanguageModelComponent-Te29P",
"name": "text_output",
"output_types": [
"Message"
]
},
"targetHandle": {
"fieldName": "message",
"id": "MessagetoData-IbO6b",
"inputTypes": [
"Message"
],
"type": "str"
}
},
"id": "reactflow__edge-LanguageModelComponent-Te29P{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-Te29Pœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-MessagetoData-IbO6b{œfieldNameœ:œmessageœ,œidœ:œMessagetoData-IbO6bœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
"selected": false,
"source": "LanguageModelComponent-Te29P",
"sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-Te29Pœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
"target": "MessagetoData-IbO6b",
"targetHandle": "{œfieldNameœ: œmessageœ, œidœ: œMessagetoData-IbO6bœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
"className": "",
"data": {
"sourceHandle": {
"dataType": "MessagetoData",
"id": "MessagetoData-IbO6b",
"name": "data",
"output_types": [
"Data"
]
},
"targetHandle": {
"dataType": "LoopComponent",
"id": "LoopComponent-zuKTL",
"name": "item",
"output_types": [
"Data"
]
}
},
"id": "reactflow__edge-MessagetoData-IbO6b{œdataTypeœ:œMessagetoDataœ,œidœ:œMessagetoData-IbO6bœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-LoopComponent-zuKTL{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-zuKTLœ,œnameœ:œitemœ,œoutput_typesœ:[œDataœ]}",
"selected": false,
"source": "MessagetoData-IbO6b",
"sourceHandle": "{œdataTypeœ: œMessagetoDataœ, œidœ: œMessagetoData-IbO6bœ, œnameœ: œdataœ, œoutput_typesœ: [œDataœ]}",
"target": "LoopComponent-zuKTL",
"targetHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-zuKTLœ, œnameœ: œitemœ, œoutput_typesœ: [œDataœ]}"
}
],
"nodes": [
{
"data": {
"id": "ArXivComponent-WxSYF",
"node": {
"base_classes": [
"DataFrame"
],
"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.3",
"metadata": {},
"minimized": false,
"output_types": [],
"outputs": [
{
"allows_loop": false,
"cache": true,
"display_name": "DataFrame",
"group_outputs": false,
"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.custom_component.component import Component\nfrom langflow.io import DropdownInput, IntInput, MessageTextInput, Output\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import 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 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",
"load_from_db": false,
"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,
"toggle": false,
"tool_mode": false,
"trace_as_metadata": true,
"type": "str",
"value": "all"
}
},
"tool_mode": false
},
"showNode": true,
"type": "ArXivComponent"
},
"dragging": false,
"id": "ArXivComponent-WxSYF",
"measured": {
"height": 368,
"width": 320
},
"position": {
"x": 81.59312530546094,
"y": 3.9397854556273906
},
"selected": false,
"type": "genericNode"
},
{
"data": {
"id": "ChatOutput-ylHrO",
"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",
"clean_data"
],
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"lf_version": "1.4.3",
"metadata": {},
"minimized": true,
"output_types": [],
"outputs": [
{
"allows_loop": false,
"cache": true,
"display_name": "Output Message",
"group_outputs": false,
"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.helpers.data import safe_convert\nfrom langflow.inputs.inputs import BoolInput, DropdownInput, HandleInput, MessageTextInput\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.template.field.base import Output\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=\"Inputs\",\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=\"Output 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 _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 _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 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([safe_convert(item, clean_data=self.clean_data) for item in self.input_value])\n if isinstance(self.input_value, Generator):\n return self.input_value\n return 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": "HandleInput",
"advanced": false,
"display_name": "Inputs",
"dynamic": false,
"info": "Message to be passed as output.",
"input_types": [
"Data",
"DataFrame",
"Message"
],
"list": false,
"list_add_label": "Add More",
"name": "input_value",
"placeholder": "",
"required": true,
"show": true,
"title_case": false,
"trace_as_metadata": true,
"type": "other",
"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,
"toggle": 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-ylHrO",
"measured": {
"height": 48,
"width": 192
},
"position": {
"x": 1340.6435418555936,
"y": 570.8905972487661
},
"selected": false,
"type": "genericNode"
},
{
"data": {
"id": "ChatInput-OF2vZ",
"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.3",
"metadata": {},
"minimized": true,
"output_types": [],
"outputs": [
{
"allows_loop": false,
"cache": true,
"display_name": "Chat Message",
"group_outputs": false,
"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.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=\"Input 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=\"Chat 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,
"temp_file": true,
"title_case": false,
"trace_as_metadata": true,
"type": "file",
"value": ""
},
"input_value": {
"_input_type": "MultilineInput",
"advanced": false,
"copy_field": false,
"display_name": "Input 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,
"toggle": 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-OF2vZ",
"measured": {
"height": 203,
"width": 320
},
"position": {
"x": -333.65585758816223,
"y": 107.75353484470551
},
"selected": false,
"type": "genericNode"
},
{
"data": {
"id": "note-uG7pK",
"node": {
"description": "### 💡 Add your Anthropic API key here 👇",
"display_name": "",
"documentation": "",
"template": {
"backgroundColor": "transparent"
}
},
"type": "note"
},
"dragging": false,
"height": 324,
"id": "note-uG7pK",
"measured": {
"height": 324,
"width": 359
},
"position": {
"x": 1479.4278434913201,
"y": -274.26903478612456
},
"resizing": false,
"selected": false,
"type": "noteNode",
"width": 359
},
{
"data": {
"id": "note-F4Ff1",
"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 **Langflows looping mechanism**, the template iterates through multiple research papers, translates them with the **OpenAI** model component, and outputs an aggregated version of all translated papers. \n\n## Quickstart \n 1. Add your OpenAI API key to the **Language Model** 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 **OpenAI** 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-F4Ff1",
"measured": {
"height": 647,
"width": 576
},
"position": {
"x": -890.9006297459302,
"y": -233.44894493951168
},
"resizing": false,
"selected": false,
"type": "noteNode",
"width": 576
},
{
"data": {
"id": "ParserComponent-2OCL9",
"node": {
"base_classes": [
"Message"
],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
"description": "Extracts text using a template.",
"display_name": "Parser",
"documentation": "",
"edited": false,
"field_order": [
"input_data",
"mode",
"pattern",
"sep"
],
"frozen": false,
"icon": "braces",
"legacy": false,
"metadata": {},
"minimized": false,
"output_types": [],
"outputs": [
{
"allows_loop": false,
"cache": true,
"display_name": "Parsed Text",
"group_outputs": false,
"method": "parse_combined_text",
"name": "parsed_text",
"selected": "Message",
"tool_mode": true,
"types": [
"Message"
],
"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": "from langflow.custom.custom_component.component import Component\nfrom langflow.helpers.data import safe_convert\nfrom langflow.inputs.inputs import BoolInput, HandleInput, MessageTextInput, MultilineInput, TabInput\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.schema.message import Message\nfrom langflow.template.field.base import Output\n\n\nclass ParserComponent(Component):\n display_name = \"Parser\"\n description = \"Extracts text using a template.\"\n icon = \"braces\"\n\n inputs = [\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 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 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 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([safe_convert(item, clean_data=self.clean_data or False) for item in self.input_data])\n else:\n result = safe_convert(self.input_data or False)\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.",
"load_from_db": false,
"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": true,
"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-2OCL9",
"measured": {
"height": 328,
"width": 320
},
"position": {
"x": 971.3987248215344,
"y": -186.6658506576822
},
"selected": false,
"type": "genericNode"
},
{
"data": {
"id": "LoopComponent-zuKTL",
"node": {
"base_classes": [
"Data",
"DataFrame"
],
"beta": false,
"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",
"legacy": false,
"lf_version": "1.4.3",
"metadata": {},
"minimized": false,
"output_types": [],
"outputs": [
{
"allows_loop": true,
"cache": true,
"display_name": "Item",
"group_outputs": true,
"method": "item_output",
"name": "item",
"selected": "Data",
"tool_mode": true,
"types": [
"Data"
],
"value": "__UNDEFINED__"
},
{
"allows_loop": false,
"cache": true,
"display_name": "Done",
"group_outputs": true,
"method": "done_output",
"name": "done",
"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": "from langflow.custom.custom_component.component import Component\nfrom langflow.inputs.inputs import HandleInput\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.template.field.base import Output\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=\"Inputs\",\n info=\"The initial list of Data objects or DataFrame to iterate over.\",\n input_types=[\"DataFrame\"],\n ),\n ]\n\n outputs = [\n Output(display_name=\"Item\", name=\"item\", method=\"item_output\", allows_loop=True, group_outputs=True),\n Output(display_name=\"Done\", name=\"done\", method=\"done_output\", group_outputs=True),\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 else:\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\n # Now we need to update the dependencies for the next run\n self.update_dependency()\n return current_item\n\n def update_dependency(self):\n item_dependency_id = self.get_incoming_edge_by_target_param(\"item\")\n\n self.graph.run_manager.run_predecessors[self._id].append(item_dependency_id)\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": "Inputs",
"dynamic": false,
"info": "The initial list of Data objects or DataFrame to iterate over.",
"input_types": [
"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-zuKTL",
"measured": {
"height": 241,
"width": 320
},
"position": {
"x": 541.1188345961908,
"y": 181.38181401206583
},
"selected": false,
"type": "genericNode"
},
{
"data": {
"id": "TypeConverterComponent-mWgMR",
"node": {
"base_classes": [
"Message"
],
"beta": false,
"category": "processing",
"conditional_paths": [],
"custom_fields": {},
"description": "Convert between different types (Message, Data, DataFrame)",
"display_name": "Type Convert",
"documentation": "",
"edited": false,
"field_order": [
"input_data",
"output_type"
],
"frozen": false,
"icon": "repeat",
"key": "TypeConverterComponent",
"legacy": false,
"lf_version": "1.4.3",
"metadata": {},
"minimized": false,
"output_types": [],
"outputs": [
{
"allows_loop": false,
"cache": true,
"display_name": "Message Output",
"group_outputs": false,
"method": "convert_to_message",
"name": "message_output",
"selected": "Message",
"tool_mode": true,
"types": [
"Message"
],
"value": "__UNDEFINED__"
}
],
"pinned": false,
"score": 0.008834292878014125,
"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 typing import Any\n\nfrom langflow.custom import Component\nfrom langflow.io import HandleInput, Output, TabInput\nfrom langflow.schema import Data, DataFrame, Message\n\n\ndef convert_to_message(v) -> Message:\n \"\"\"Convert input to Message type.\n\n Args:\n v: Input to convert (Message, Data, DataFrame, or dict)\n\n Returns:\n Message: Converted Message object\n \"\"\"\n return v if isinstance(v, Message) else v.to_message()\n\n\ndef convert_to_data(v: DataFrame | Data | Message | dict) -> Data:\n \"\"\"Convert input to Data type.\n\n Args:\n v: Input to convert (Message, Data, DataFrame, or dict)\n\n Returns:\n Data: Converted Data object\n \"\"\"\n if isinstance(v, dict):\n return Data(v)\n return v if isinstance(v, Data) else v.to_data()\n\n\ndef convert_to_dataframe(v: DataFrame | Data | Message | dict) -> DataFrame:\n \"\"\"Convert input to DataFrame type.\n\n Args:\n v: Input to convert (Message, Data, DataFrame, or dict)\n\n Returns:\n DataFrame: Converted DataFrame object\n \"\"\"\n if isinstance(v, dict):\n return DataFrame([v])\n return v if isinstance(v, DataFrame) else v.to_dataframe()\n\n\nclass TypeConverterComponent(Component):\n display_name = \"Type Convert\"\n description = \"Convert between different types (Message, Data, DataFrame)\"\n icon = \"repeat\"\n\n inputs = [\n HandleInput(\n name=\"input_data\",\n display_name=\"Input\",\n input_types=[\"Message\", \"Data\", \"DataFrame\"],\n info=\"Accept Message, Data or DataFrame as input\",\n required=True,\n ),\n TabInput(\n name=\"output_type\",\n display_name=\"Output Type\",\n options=[\"Message\", \"Data\", \"DataFrame\"],\n info=\"Select the desired output data type\",\n real_time_refresh=True,\n value=\"Message\",\n ),\n ]\n\n outputs = [\n Output(\n display_name=\"Message Output\",\n name=\"message_output\",\n method=\"convert_to_message\",\n )\n ]\n\n def update_outputs(self, frontend_node: dict, field_name: str, field_value: Any) -> dict:\n \"\"\"Dynamically show only the relevant output based on the selected output type.\"\"\"\n if field_name == \"output_type\":\n # Start with empty outputs\n frontend_node[\"outputs\"] = []\n\n # Add only the selected output type\n if field_value == \"Message\":\n frontend_node[\"outputs\"].append(\n Output(\n display_name=\"Message Output\",\n name=\"message_output\",\n method=\"convert_to_message\",\n ).to_dict()\n )\n elif field_value == \"Data\":\n frontend_node[\"outputs\"].append(\n Output(\n display_name=\"Data Output\",\n name=\"data_output\",\n method=\"convert_to_data\",\n ).to_dict()\n )\n elif field_value == \"DataFrame\":\n frontend_node[\"outputs\"].append(\n Output(\n display_name=\"DataFrame Output\",\n name=\"dataframe_output\",\n method=\"convert_to_dataframe\",\n ).to_dict()\n )\n\n return frontend_node\n\n def convert_to_message(self) -> Message:\n \"\"\"Convert input to Message type.\"\"\"\n input_value = self.input_data[0] if isinstance(self.input_data, list) else self.input_data\n\n # Handle string input by converting to Message first\n if isinstance(input_value, str):\n input_value = Message(text=input_value)\n\n result = convert_to_message(input_value)\n self.status = result\n return result\n\n def convert_to_data(self) -> Data:\n \"\"\"Convert input to Data type.\"\"\"\n input_value = self.input_data[0] if isinstance(self.input_data, list) else self.input_data\n\n # Handle string input by converting to Message first\n if isinstance(input_value, str):\n input_value = Message(text=input_value)\n\n result = convert_to_data(input_value)\n self.status = result\n return result\n\n def convert_to_dataframe(self) -> DataFrame:\n \"\"\"Convert input to DataFrame type.\"\"\"\n input_value = self.input_data[0] if isinstance(self.input_data, list) else self.input_data\n\n # Handle string input by converting to Message first\n if isinstance(input_value, str):\n input_value = Message(text=input_value)\n\n result = convert_to_dataframe(input_value)\n self.status = result\n return result\n"
},
"input_data": {
"_input_type": "HandleInput",
"advanced": false,
"display_name": "Input",
"dynamic": false,
"info": "Accept Message, Data or DataFrame as input",
"input_types": [
"Message",
"Data",
"DataFrame"
],
"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": ""
},
"output_type": {
"_input_type": "TabInput",
"advanced": false,
"display_name": "Output Type",
"dynamic": false,
"info": "Select the desired output data type",
"name": "output_type",
"options": [
"Message",
"Data",
"DataFrame"
],
"placeholder": "",
"real_time_refresh": true,
"required": false,
"show": true,
"title_case": false,
"tool_mode": false,
"trace_as_metadata": true,
"type": "tab",
"value": "Message"
}
},
"tool_mode": false
},
"showNode": true,
"type": "TypeConverterComponent"
},
"dragging": false,
"id": "TypeConverterComponent-mWgMR",
"measured": {
"height": 262,
"width": 320
},
"position": {
"x": 949.5742678542961,
"y": 469.18776022439897
},
"selected": false,
"type": "genericNode"
},
{
"data": {
"id": "LanguageModelComponent-Te29P",
"node": {
"base_classes": [
"LanguageModel",
"Message"
],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
"description": "Runs a language model given a specified provider. ",
"display_name": "Language Model",
"documentation": "",
"edited": false,
"field_order": [
"provider",
"model_name",
"api_key",
"input_value",
"system_message",
"stream",
"temperature"
],
"frozen": false,
"icon": "brain-circuit",
"legacy": false,
"metadata": {
"keywords": [
"model",
"llm",
"language model",
"large language model"
]
},
"minimized": false,
"output_types": [],
"outputs": [
{
"allows_loop": false,
"cache": true,
"display_name": "Model Response",
"group_outputs": false,
"method": "text_response",
"name": "text_output",
"selected": "Message",
"tool_mode": true,
"types": [
"Message"
],
"value": "__UNDEFINED__"
},
{
"allows_loop": false,
"cache": true,
"display_name": "Language Model",
"group_outputs": false,
"method": "build_model",
"name": "model_output",
"selected": "LanguageModel",
"tool_mode": true,
"types": [
"LanguageModel"
],
"value": "__UNDEFINED__"
}
],
"pinned": false,
"priority": 0,
"template": {
"_type": "Component",
"api_key": {
"_input_type": "SecretStrInput",
"advanced": false,
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "Model Provider API key",
"input_types": [],
"load_from_db": true,
"name": "api_key",
"password": true,
"placeholder": "",
"real_time_refresh": true,
"required": false,
"show": true,
"title_case": false,
"type": "str",
"value": "OPENAI_API_KEY"
},
"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\n\nfrom langchain_anthropic import ChatAnthropic\nfrom langchain_google_genai import ChatGoogleGenerativeAI\nfrom langchain_openai import ChatOpenAI\n\nfrom langflow.base.models.anthropic_constants import ANTHROPIC_MODELS\nfrom langflow.base.models.google_generative_ai_constants import GOOGLE_GENERATIVE_AI_MODELS\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import OPENAI_MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MultilineInput, SecretStrInput, SliderInput\nfrom langflow.schema.dotdict import dotdict\n\n\nclass LanguageModelComponent(LCModelComponent):\n display_name = \"Language Model\"\n description = \"Runs a language model given a specified provider. \"\n icon = \"brain-circuit\"\n category = \"models\"\n priority = 0 # Set priority to 0 to make it appear first\n\n inputs = [\n DropdownInput(\n name=\"provider\",\n display_name=\"Model Provider\",\n options=[\"OpenAI\", \"Anthropic\", \"Google\"],\n value=\"OpenAI\",\n info=\"Select the model provider\",\n real_time_refresh=True,\n options_metadata=[{\"icon\": \"OpenAI\"}, {\"icon\": \"Anthropic\"}, {\"icon\": \"GoogleGenerativeAI\"}],\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n options=OPENAI_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[0],\n info=\"Select the model to use\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"Model Provider API key\",\n required=False,\n show=True,\n real_time_refresh=True,\n ),\n MessageInput(\n name=\"input_value\",\n display_name=\"Input\",\n info=\"The input text to send to the model\",\n ),\n MultilineInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"A system message that helps set the behavior of the assistant\",\n advanced=True,\n ),\n BoolInput(\n name=\"stream\",\n display_name=\"Stream\",\n info=\"Whether to stream the response\",\n value=False,\n advanced=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n info=\"Controls randomness in responses\",\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n advanced=True,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n provider = self.provider\n model_name = self.model_name\n temperature = self.temperature\n stream = self.stream\n\n if provider == \"OpenAI\":\n if not self.api_key:\n msg = \"OpenAI API key is required when using OpenAI provider\"\n raise ValueError(msg)\n return ChatOpenAI(\n model_name=model_name,\n temperature=temperature,\n streaming=stream,\n openai_api_key=self.api_key,\n )\n if provider == \"Anthropic\":\n if not self.api_key:\n msg = \"Anthropic API key is required when using Anthropic provider\"\n raise ValueError(msg)\n return ChatAnthropic(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n anthropic_api_key=self.api_key,\n )\n if provider == \"Google\":\n if not self.api_key:\n msg = \"Google API key is required when using Google provider\"\n raise ValueError(msg)\n return ChatGoogleGenerativeAI(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n google_api_key=self.api_key,\n )\n msg = f\"Unknown provider: {provider}\"\n raise ValueError(msg)\n\n def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None) -> dotdict:\n if field_name == \"provider\":\n if field_value == \"OpenAI\":\n build_config[\"model_name\"][\"options\"] = OPENAI_MODEL_NAMES\n build_config[\"model_name\"][\"value\"] = OPENAI_MODEL_NAMES[0]\n build_config[\"api_key\"][\"display_name\"] = \"OpenAI API Key\"\n elif field_value == \"Anthropic\":\n build_config[\"model_name\"][\"options\"] = ANTHROPIC_MODELS\n build_config[\"model_name\"][\"value\"] = ANTHROPIC_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Anthropic API Key\"\n elif field_value == \"Google\":\n build_config[\"model_name\"][\"options\"] = GOOGLE_GENERATIVE_AI_MODELS\n build_config[\"model_name\"][\"value\"] = GOOGLE_GENERATIVE_AI_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Google API Key\"\n return build_config\n"
},
"input_value": {
"_input_type": "MessageInput",
"advanced": false,
"display_name": "Input",
"dynamic": false,
"info": "The input text to send to the model",
"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": ""
},
"model_name": {
"_input_type": "DropdownInput",
"advanced": false,
"combobox": false,
"dialog_inputs": {},
"display_name": "Model Name",
"dynamic": false,
"info": "Select the model to use",
"name": "model_name",
"options": [
"gpt-4o-mini",
"gpt-4o",
"gpt-4.1",
"gpt-4.1-mini",
"gpt-4.1-nano",
"gpt-4.5-preview",
"gpt-4-turbo",
"gpt-4-turbo-preview",
"gpt-4",
"gpt-3.5-turbo"
],
"options_metadata": [],
"placeholder": "",
"required": false,
"show": true,
"title_case": false,
"toggle": false,
"tool_mode": false,
"trace_as_metadata": true,
"type": "str",
"value": "gpt-4o-mini"
},
"provider": {
"_input_type": "DropdownInput",
"advanced": false,
"combobox": false,
"dialog_inputs": {},
"display_name": "Model Provider",
"dynamic": false,
"info": "Select the model provider",
"name": "provider",
"options": [
"OpenAI",
"Anthropic",
"Google"
],
"options_metadata": [
{
"icon": "Anthropic"
},
{
"icon": "OpenAI"
},
{
"icon": "Google"
}
],
"placeholder": "",
"real_time_refresh": true,
"required": false,
"show": true,
"title_case": false,
"toggle": false,
"tool_mode": false,
"trace_as_metadata": true,
"type": "str",
"value": "OpenAI"
},
"stream": {
"_input_type": "BoolInput",
"advanced": true,
"display_name": "Stream",
"dynamic": false,
"info": "Whether to stream the response",
"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,
"copy_field": false,
"display_name": "System Message",
"dynamic": false,
"info": "A system message that helps set the behavior of the assistant",
"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 formatReturn only the JSON and no additional text."
},
"temperature": {
"_input_type": "SliderInput",
"advanced": true,
"display_name": "Temperature",
"dynamic": false,
"info": "Controls randomness in responses",
"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_mode": false
},
"showNode": true,
"type": "LanguageModelComponent"
},
"dragging": false,
"id": "LanguageModelComponent-Te29P",
"measured": {
"height": 532,
"width": 320
},
"position": {
"x": 1472.0991866325971,
"y": -182.4108205734875
},
"selected": false,
"type": "genericNode"
},
{
"data": {
"id": "MessagetoData-IbO6b",
"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": true,
"metadata": {},
"minimized": false,
"output_types": [],
"outputs": [
{
"allows_loop": false,
"cache": true,
"display_name": "Data",
"group_outputs": false,
"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.custom_component.component import Component\nfrom langflow.io import MessageInput, Output\nfrom langflow.schema.data 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 legacy = True\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-IbO6b",
"measured": {
"height": 203,
"width": 320
},
"position": {
"x": 1836.3049922790483,
"y": 411.76970008520357
},
"selected": false,
"type": "genericNode"
}
],
"viewport": {
"x": 718.2366665584553,
"y": 264.2875075099402,
"zoom": 0.46271902027504264
}
},
"description": "This template iterates over search results using LoopComponent and translates each result into Portuguese automatically. 🚀",
"endpoint_name": null,
"id": "00674d9d-d897-4c75-aedd-dcca1c8e8d9d",
"is_component": false,
"last_tested_version": "1.4.3",
"name": "Research Translation Loop",
"tags": [
"chatbots",
"content-generation"
]
}