lfx-nightly 0.1.11.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lfx/__init__.py +0 -0
- lfx/__main__.py +25 -0
- lfx/base/__init__.py +0 -0
- lfx/base/agents/__init__.py +0 -0
- lfx/base/agents/agent.py +268 -0
- lfx/base/agents/callback.py +130 -0
- lfx/base/agents/context.py +109 -0
- lfx/base/agents/crewai/__init__.py +0 -0
- lfx/base/agents/crewai/crew.py +231 -0
- lfx/base/agents/crewai/tasks.py +12 -0
- lfx/base/agents/default_prompts.py +23 -0
- lfx/base/agents/errors.py +15 -0
- lfx/base/agents/events.py +346 -0
- lfx/base/agents/utils.py +205 -0
- lfx/base/astra_assistants/__init__.py +0 -0
- lfx/base/astra_assistants/util.py +171 -0
- lfx/base/chains/__init__.py +0 -0
- lfx/base/chains/model.py +19 -0
- lfx/base/composio/__init__.py +0 -0
- lfx/base/composio/composio_base.py +1291 -0
- lfx/base/compressors/__init__.py +0 -0
- lfx/base/compressors/model.py +60 -0
- lfx/base/constants.py +46 -0
- lfx/base/curl/__init__.py +0 -0
- lfx/base/curl/parse.py +188 -0
- lfx/base/data/__init__.py +5 -0
- lfx/base/data/base_file.py +685 -0
- lfx/base/data/docling_utils.py +245 -0
- lfx/base/data/utils.py +198 -0
- lfx/base/document_transformers/__init__.py +0 -0
- lfx/base/document_transformers/model.py +43 -0
- lfx/base/embeddings/__init__.py +0 -0
- lfx/base/embeddings/aiml_embeddings.py +62 -0
- lfx/base/embeddings/model.py +26 -0
- lfx/base/flow_processing/__init__.py +0 -0
- lfx/base/flow_processing/utils.py +86 -0
- lfx/base/huggingface/__init__.py +0 -0
- lfx/base/huggingface/model_bridge.py +133 -0
- lfx/base/io/__init__.py +0 -0
- lfx/base/io/chat.py +20 -0
- lfx/base/io/text.py +22 -0
- lfx/base/langchain_utilities/__init__.py +0 -0
- lfx/base/langchain_utilities/model.py +35 -0
- lfx/base/langchain_utilities/spider_constants.py +1 -0
- lfx/base/langwatch/__init__.py +0 -0
- lfx/base/langwatch/utils.py +18 -0
- lfx/base/mcp/__init__.py +0 -0
- lfx/base/mcp/constants.py +2 -0
- lfx/base/mcp/util.py +1398 -0
- lfx/base/memory/__init__.py +0 -0
- lfx/base/memory/memory.py +49 -0
- lfx/base/memory/model.py +38 -0
- lfx/base/models/__init__.py +3 -0
- lfx/base/models/aiml_constants.py +51 -0
- lfx/base/models/anthropic_constants.py +47 -0
- lfx/base/models/aws_constants.py +151 -0
- lfx/base/models/chat_result.py +76 -0
- lfx/base/models/google_generative_ai_constants.py +70 -0
- lfx/base/models/groq_constants.py +134 -0
- lfx/base/models/model.py +375 -0
- lfx/base/models/model_input_constants.py +307 -0
- lfx/base/models/model_metadata.py +41 -0
- lfx/base/models/model_utils.py +8 -0
- lfx/base/models/novita_constants.py +35 -0
- lfx/base/models/ollama_constants.py +49 -0
- lfx/base/models/openai_constants.py +122 -0
- lfx/base/models/sambanova_constants.py +18 -0
- lfx/base/processing/__init__.py +0 -0
- lfx/base/prompts/__init__.py +0 -0
- lfx/base/prompts/api_utils.py +224 -0
- lfx/base/prompts/utils.py +61 -0
- lfx/base/textsplitters/__init__.py +0 -0
- lfx/base/textsplitters/model.py +28 -0
- lfx/base/tools/__init__.py +0 -0
- lfx/base/tools/base.py +26 -0
- lfx/base/tools/component_tool.py +325 -0
- lfx/base/tools/constants.py +49 -0
- lfx/base/tools/flow_tool.py +132 -0
- lfx/base/tools/run_flow.py +224 -0
- lfx/base/vectorstores/__init__.py +0 -0
- lfx/base/vectorstores/model.py +193 -0
- lfx/base/vectorstores/utils.py +22 -0
- lfx/base/vectorstores/vector_store_connection_decorator.py +52 -0
- lfx/cli/__init__.py +5 -0
- lfx/cli/commands.py +319 -0
- lfx/cli/common.py +650 -0
- lfx/cli/run.py +441 -0
- lfx/cli/script_loader.py +247 -0
- lfx/cli/serve_app.py +546 -0
- lfx/cli/validation.py +69 -0
- lfx/components/FAISS/__init__.py +34 -0
- lfx/components/FAISS/faiss.py +111 -0
- lfx/components/Notion/__init__.py +19 -0
- lfx/components/Notion/add_content_to_page.py +269 -0
- lfx/components/Notion/create_page.py +94 -0
- lfx/components/Notion/list_database_properties.py +68 -0
- lfx/components/Notion/list_pages.py +122 -0
- lfx/components/Notion/list_users.py +77 -0
- lfx/components/Notion/page_content_viewer.py +93 -0
- lfx/components/Notion/search.py +111 -0
- lfx/components/Notion/update_page_property.py +114 -0
- lfx/components/__init__.py +411 -0
- lfx/components/_importing.py +42 -0
- lfx/components/agentql/__init__.py +3 -0
- lfx/components/agentql/agentql_api.py +151 -0
- lfx/components/agents/__init__.py +34 -0
- lfx/components/agents/agent.py +558 -0
- lfx/components/agents/mcp_component.py +501 -0
- lfx/components/aiml/__init__.py +37 -0
- lfx/components/aiml/aiml.py +112 -0
- lfx/components/aiml/aiml_embeddings.py +37 -0
- lfx/components/amazon/__init__.py +36 -0
- lfx/components/amazon/amazon_bedrock_embedding.py +109 -0
- lfx/components/amazon/amazon_bedrock_model.py +124 -0
- lfx/components/amazon/s3_bucket_uploader.py +211 -0
- lfx/components/anthropic/__init__.py +34 -0
- lfx/components/anthropic/anthropic.py +187 -0
- lfx/components/apify/__init__.py +5 -0
- lfx/components/apify/apify_actor.py +325 -0
- lfx/components/arxiv/__init__.py +3 -0
- lfx/components/arxiv/arxiv.py +163 -0
- lfx/components/assemblyai/__init__.py +46 -0
- lfx/components/assemblyai/assemblyai_get_subtitles.py +83 -0
- lfx/components/assemblyai/assemblyai_lemur.py +183 -0
- lfx/components/assemblyai/assemblyai_list_transcripts.py +95 -0
- lfx/components/assemblyai/assemblyai_poll_transcript.py +72 -0
- lfx/components/assemblyai/assemblyai_start_transcript.py +188 -0
- lfx/components/azure/__init__.py +37 -0
- lfx/components/azure/azure_openai.py +95 -0
- lfx/components/azure/azure_openai_embeddings.py +83 -0
- lfx/components/baidu/__init__.py +32 -0
- lfx/components/baidu/baidu_qianfan_chat.py +113 -0
- lfx/components/bing/__init__.py +3 -0
- lfx/components/bing/bing_search_api.py +61 -0
- lfx/components/cassandra/__init__.py +40 -0
- lfx/components/cassandra/cassandra.py +264 -0
- lfx/components/cassandra/cassandra_chat.py +92 -0
- lfx/components/cassandra/cassandra_graph.py +238 -0
- lfx/components/chains/__init__.py +3 -0
- lfx/components/chroma/__init__.py +34 -0
- lfx/components/chroma/chroma.py +167 -0
- lfx/components/cleanlab/__init__.py +40 -0
- lfx/components/cleanlab/cleanlab_evaluator.py +155 -0
- lfx/components/cleanlab/cleanlab_rag_evaluator.py +254 -0
- lfx/components/cleanlab/cleanlab_remediator.py +131 -0
- lfx/components/clickhouse/__init__.py +34 -0
- lfx/components/clickhouse/clickhouse.py +135 -0
- lfx/components/cloudflare/__init__.py +32 -0
- lfx/components/cloudflare/cloudflare.py +81 -0
- lfx/components/cohere/__init__.py +40 -0
- lfx/components/cohere/cohere_embeddings.py +81 -0
- lfx/components/cohere/cohere_models.py +46 -0
- lfx/components/cohere/cohere_rerank.py +51 -0
- lfx/components/composio/__init__.py +74 -0
- lfx/components/composio/composio_api.py +268 -0
- lfx/components/composio/dropbox_compnent.py +11 -0
- lfx/components/composio/github_composio.py +11 -0
- lfx/components/composio/gmail_composio.py +38 -0
- lfx/components/composio/googlecalendar_composio.py +11 -0
- lfx/components/composio/googlemeet_composio.py +11 -0
- lfx/components/composio/googletasks_composio.py +8 -0
- lfx/components/composio/linear_composio.py +11 -0
- lfx/components/composio/outlook_composio.py +11 -0
- lfx/components/composio/reddit_composio.py +11 -0
- lfx/components/composio/slack_composio.py +582 -0
- lfx/components/composio/slackbot_composio.py +11 -0
- lfx/components/composio/supabase_composio.py +11 -0
- lfx/components/composio/todoist_composio.py +11 -0
- lfx/components/composio/youtube_composio.py +11 -0
- lfx/components/confluence/__init__.py +3 -0
- lfx/components/confluence/confluence.py +84 -0
- lfx/components/couchbase/__init__.py +34 -0
- lfx/components/couchbase/couchbase.py +102 -0
- lfx/components/crewai/__init__.py +49 -0
- lfx/components/crewai/crewai.py +107 -0
- lfx/components/crewai/hierarchical_crew.py +46 -0
- lfx/components/crewai/hierarchical_task.py +44 -0
- lfx/components/crewai/sequential_crew.py +52 -0
- lfx/components/crewai/sequential_task.py +73 -0
- lfx/components/crewai/sequential_task_agent.py +143 -0
- lfx/components/custom_component/__init__.py +34 -0
- lfx/components/custom_component/custom_component.py +31 -0
- lfx/components/data/__init__.py +64 -0
- lfx/components/data/api_request.py +544 -0
- lfx/components/data/csv_to_data.py +95 -0
- lfx/components/data/directory.py +113 -0
- lfx/components/data/file.py +577 -0
- lfx/components/data/json_to_data.py +98 -0
- lfx/components/data/news_search.py +164 -0
- lfx/components/data/rss.py +69 -0
- lfx/components/data/sql_executor.py +101 -0
- lfx/components/data/url.py +311 -0
- lfx/components/data/web_search.py +112 -0
- lfx/components/data/webhook.py +56 -0
- lfx/components/datastax/__init__.py +70 -0
- lfx/components/datastax/astra_assistant_manager.py +306 -0
- lfx/components/datastax/astra_db.py +75 -0
- lfx/components/datastax/astra_vectorize.py +124 -0
- lfx/components/datastax/astradb.py +1285 -0
- lfx/components/datastax/astradb_cql.py +314 -0
- lfx/components/datastax/astradb_graph.py +330 -0
- lfx/components/datastax/astradb_tool.py +414 -0
- lfx/components/datastax/astradb_vectorstore.py +1285 -0
- lfx/components/datastax/cassandra.py +92 -0
- lfx/components/datastax/create_assistant.py +58 -0
- lfx/components/datastax/create_thread.py +32 -0
- lfx/components/datastax/dotenv.py +35 -0
- lfx/components/datastax/get_assistant.py +37 -0
- lfx/components/datastax/getenvvar.py +30 -0
- lfx/components/datastax/graph_rag.py +141 -0
- lfx/components/datastax/hcd.py +314 -0
- lfx/components/datastax/list_assistants.py +25 -0
- lfx/components/datastax/run.py +89 -0
- lfx/components/deactivated/__init__.py +15 -0
- lfx/components/deactivated/amazon_kendra.py +66 -0
- lfx/components/deactivated/chat_litellm_model.py +158 -0
- lfx/components/deactivated/code_block_extractor.py +26 -0
- lfx/components/deactivated/documents_to_data.py +22 -0
- lfx/components/deactivated/embed.py +16 -0
- lfx/components/deactivated/extract_key_from_data.py +46 -0
- lfx/components/deactivated/json_document_builder.py +57 -0
- lfx/components/deactivated/list_flows.py +20 -0
- lfx/components/deactivated/mcp_sse.py +61 -0
- lfx/components/deactivated/mcp_stdio.py +62 -0
- lfx/components/deactivated/merge_data.py +93 -0
- lfx/components/deactivated/message.py +37 -0
- lfx/components/deactivated/metal.py +54 -0
- lfx/components/deactivated/multi_query.py +59 -0
- lfx/components/deactivated/retriever.py +43 -0
- lfx/components/deactivated/selective_passthrough.py +77 -0
- lfx/components/deactivated/should_run_next.py +40 -0
- lfx/components/deactivated/split_text.py +63 -0
- lfx/components/deactivated/store_message.py +24 -0
- lfx/components/deactivated/sub_flow.py +124 -0
- lfx/components/deactivated/vectara_self_query.py +76 -0
- lfx/components/deactivated/vector_store.py +24 -0
- lfx/components/deepseek/__init__.py +34 -0
- lfx/components/deepseek/deepseek.py +136 -0
- lfx/components/docling/__init__.py +43 -0
- lfx/components/docling/chunk_docling_document.py +186 -0
- lfx/components/docling/docling_inline.py +231 -0
- lfx/components/docling/docling_remote.py +193 -0
- lfx/components/docling/export_docling_document.py +117 -0
- lfx/components/documentloaders/__init__.py +3 -0
- lfx/components/duckduckgo/__init__.py +3 -0
- lfx/components/duckduckgo/duck_duck_go_search_run.py +92 -0
- lfx/components/elastic/__init__.py +37 -0
- lfx/components/elastic/elasticsearch.py +267 -0
- lfx/components/elastic/opensearch.py +243 -0
- lfx/components/embeddings/__init__.py +37 -0
- lfx/components/embeddings/similarity.py +76 -0
- lfx/components/embeddings/text_embedder.py +64 -0
- lfx/components/exa/__init__.py +3 -0
- lfx/components/exa/exa_search.py +68 -0
- lfx/components/firecrawl/__init__.py +43 -0
- lfx/components/firecrawl/firecrawl_crawl_api.py +88 -0
- lfx/components/firecrawl/firecrawl_extract_api.py +136 -0
- lfx/components/firecrawl/firecrawl_map_api.py +89 -0
- lfx/components/firecrawl/firecrawl_scrape_api.py +73 -0
- lfx/components/git/__init__.py +4 -0
- lfx/components/git/git.py +262 -0
- lfx/components/git/gitextractor.py +196 -0
- lfx/components/glean/__init__.py +3 -0
- lfx/components/glean/glean_search_api.py +173 -0
- lfx/components/google/__init__.py +17 -0
- lfx/components/google/gmail.py +192 -0
- lfx/components/google/google_bq_sql_executor.py +157 -0
- lfx/components/google/google_drive.py +92 -0
- lfx/components/google/google_drive_search.py +152 -0
- lfx/components/google/google_generative_ai.py +147 -0
- lfx/components/google/google_generative_ai_embeddings.py +141 -0
- lfx/components/google/google_oauth_token.py +89 -0
- lfx/components/google/google_search_api_core.py +68 -0
- lfx/components/google/google_serper_api_core.py +74 -0
- lfx/components/groq/__init__.py +34 -0
- lfx/components/groq/groq.py +136 -0
- lfx/components/helpers/__init__.py +52 -0
- lfx/components/helpers/calculator_core.py +89 -0
- lfx/components/helpers/create_list.py +40 -0
- lfx/components/helpers/current_date.py +42 -0
- lfx/components/helpers/id_generator.py +42 -0
- lfx/components/helpers/memory.py +251 -0
- lfx/components/helpers/output_parser.py +45 -0
- lfx/components/helpers/store_message.py +90 -0
- lfx/components/homeassistant/__init__.py +7 -0
- lfx/components/homeassistant/home_assistant_control.py +152 -0
- lfx/components/homeassistant/list_home_assistant_states.py +137 -0
- lfx/components/huggingface/__init__.py +37 -0
- lfx/components/huggingface/huggingface.py +197 -0
- lfx/components/huggingface/huggingface_inference_api.py +106 -0
- lfx/components/ibm/__init__.py +34 -0
- lfx/components/ibm/watsonx.py +203 -0
- lfx/components/ibm/watsonx_embeddings.py +135 -0
- lfx/components/icosacomputing/__init__.py +5 -0
- lfx/components/icosacomputing/combinatorial_reasoner.py +84 -0
- lfx/components/input_output/__init__.py +38 -0
- lfx/components/input_output/chat.py +120 -0
- lfx/components/input_output/chat_output.py +200 -0
- lfx/components/input_output/text.py +27 -0
- lfx/components/input_output/text_output.py +29 -0
- lfx/components/jigsawstack/__init__.py +23 -0
- lfx/components/jigsawstack/ai_scrape.py +126 -0
- lfx/components/jigsawstack/ai_web_search.py +136 -0
- lfx/components/jigsawstack/file_read.py +115 -0
- lfx/components/jigsawstack/file_upload.py +94 -0
- lfx/components/jigsawstack/image_generation.py +205 -0
- lfx/components/jigsawstack/nsfw.py +60 -0
- lfx/components/jigsawstack/object_detection.py +124 -0
- lfx/components/jigsawstack/sentiment.py +112 -0
- lfx/components/jigsawstack/text_to_sql.py +90 -0
- lfx/components/jigsawstack/text_translate.py +77 -0
- lfx/components/jigsawstack/vocr.py +107 -0
- lfx/components/langchain_utilities/__init__.py +109 -0
- lfx/components/langchain_utilities/character.py +53 -0
- lfx/components/langchain_utilities/conversation.py +59 -0
- lfx/components/langchain_utilities/csv_agent.py +107 -0
- lfx/components/langchain_utilities/fake_embeddings.py +26 -0
- lfx/components/langchain_utilities/html_link_extractor.py +35 -0
- lfx/components/langchain_utilities/json_agent.py +45 -0
- lfx/components/langchain_utilities/langchain_hub.py +126 -0
- lfx/components/langchain_utilities/language_recursive.py +49 -0
- lfx/components/langchain_utilities/language_semantic.py +138 -0
- lfx/components/langchain_utilities/llm_checker.py +39 -0
- lfx/components/langchain_utilities/llm_math.py +42 -0
- lfx/components/langchain_utilities/natural_language.py +61 -0
- lfx/components/langchain_utilities/openai_tools.py +53 -0
- lfx/components/langchain_utilities/openapi.py +48 -0
- lfx/components/langchain_utilities/recursive_character.py +60 -0
- lfx/components/langchain_utilities/retrieval_qa.py +83 -0
- lfx/components/langchain_utilities/runnable_executor.py +137 -0
- lfx/components/langchain_utilities/self_query.py +80 -0
- lfx/components/langchain_utilities/spider.py +142 -0
- lfx/components/langchain_utilities/sql.py +40 -0
- lfx/components/langchain_utilities/sql_database.py +35 -0
- lfx/components/langchain_utilities/sql_generator.py +78 -0
- lfx/components/langchain_utilities/tool_calling.py +59 -0
- lfx/components/langchain_utilities/vector_store_info.py +49 -0
- lfx/components/langchain_utilities/vector_store_router.py +33 -0
- lfx/components/langchain_utilities/xml_agent.py +71 -0
- lfx/components/langwatch/__init__.py +3 -0
- lfx/components/langwatch/langwatch.py +278 -0
- lfx/components/link_extractors/__init__.py +3 -0
- lfx/components/lmstudio/__init__.py +34 -0
- lfx/components/lmstudio/lmstudioembeddings.py +89 -0
- lfx/components/lmstudio/lmstudiomodel.py +129 -0
- lfx/components/logic/__init__.py +52 -0
- lfx/components/logic/conditional_router.py +171 -0
- lfx/components/logic/data_conditional_router.py +125 -0
- lfx/components/logic/flow_tool.py +110 -0
- lfx/components/logic/listen.py +29 -0
- lfx/components/logic/loop.py +125 -0
- lfx/components/logic/notify.py +88 -0
- lfx/components/logic/pass_message.py +35 -0
- lfx/components/logic/run_flow.py +71 -0
- lfx/components/logic/sub_flow.py +114 -0
- lfx/components/maritalk/__init__.py +32 -0
- lfx/components/maritalk/maritalk.py +52 -0
- lfx/components/mem0/__init__.py +3 -0
- lfx/components/mem0/mem0_chat_memory.py +136 -0
- lfx/components/milvus/__init__.py +34 -0
- lfx/components/milvus/milvus.py +115 -0
- lfx/components/mistral/__init__.py +37 -0
- lfx/components/mistral/mistral.py +114 -0
- lfx/components/mistral/mistral_embeddings.py +58 -0
- lfx/components/models/__init__.py +34 -0
- lfx/components/models/embedding_model.py +114 -0
- lfx/components/models/language_model.py +144 -0
- lfx/components/mongodb/__init__.py +34 -0
- lfx/components/mongodb/mongodb_atlas.py +213 -0
- lfx/components/needle/__init__.py +3 -0
- lfx/components/needle/needle.py +104 -0
- lfx/components/notdiamond/__init__.py +34 -0
- lfx/components/notdiamond/notdiamond.py +228 -0
- lfx/components/novita/__init__.py +32 -0
- lfx/components/novita/novita.py +130 -0
- lfx/components/nvidia/__init__.py +57 -0
- lfx/components/nvidia/nvidia.py +157 -0
- lfx/components/nvidia/nvidia_embedding.py +77 -0
- lfx/components/nvidia/nvidia_ingest.py +317 -0
- lfx/components/nvidia/nvidia_rerank.py +63 -0
- lfx/components/nvidia/system_assist.py +65 -0
- lfx/components/olivya/__init__.py +3 -0
- lfx/components/olivya/olivya.py +116 -0
- lfx/components/ollama/__init__.py +37 -0
- lfx/components/ollama/ollama.py +330 -0
- lfx/components/ollama/ollama_embeddings.py +106 -0
- lfx/components/openai/__init__.py +37 -0
- lfx/components/openai/openai.py +100 -0
- lfx/components/openai/openai_chat_model.py +176 -0
- lfx/components/openrouter/__init__.py +32 -0
- lfx/components/openrouter/openrouter.py +202 -0
- lfx/components/output_parsers/__init__.py +3 -0
- lfx/components/perplexity/__init__.py +34 -0
- lfx/components/perplexity/perplexity.py +75 -0
- lfx/components/pgvector/__init__.py +34 -0
- lfx/components/pgvector/pgvector.py +72 -0
- lfx/components/pinecone/__init__.py +34 -0
- lfx/components/pinecone/pinecone.py +134 -0
- lfx/components/processing/__init__.py +117 -0
- lfx/components/processing/alter_metadata.py +108 -0
- lfx/components/processing/batch_run.py +205 -0
- lfx/components/processing/combine_text.py +39 -0
- lfx/components/processing/converter.py +159 -0
- lfx/components/processing/create_data.py +110 -0
- lfx/components/processing/data_operations.py +438 -0
- lfx/components/processing/data_to_dataframe.py +70 -0
- lfx/components/processing/dataframe_operations.py +313 -0
- lfx/components/processing/extract_key.py +53 -0
- lfx/components/processing/filter_data.py +42 -0
- lfx/components/processing/filter_data_values.py +88 -0
- lfx/components/processing/json_cleaner.py +103 -0
- lfx/components/processing/lambda_filter.py +154 -0
- lfx/components/processing/llm_router.py +499 -0
- lfx/components/processing/merge_data.py +90 -0
- lfx/components/processing/message_to_data.py +36 -0
- lfx/components/processing/parse_data.py +70 -0
- lfx/components/processing/parse_dataframe.py +68 -0
- lfx/components/processing/parse_json_data.py +90 -0
- lfx/components/processing/parser.py +143 -0
- lfx/components/processing/prompt.py +67 -0
- lfx/components/processing/python_repl_core.py +98 -0
- lfx/components/processing/regex.py +82 -0
- lfx/components/processing/save_file.py +225 -0
- lfx/components/processing/select_data.py +48 -0
- lfx/components/processing/split_text.py +141 -0
- lfx/components/processing/structured_output.py +202 -0
- lfx/components/processing/update_data.py +160 -0
- lfx/components/prototypes/__init__.py +34 -0
- lfx/components/prototypes/python_function.py +73 -0
- lfx/components/qdrant/__init__.py +34 -0
- lfx/components/qdrant/qdrant.py +109 -0
- lfx/components/redis/__init__.py +37 -0
- lfx/components/redis/redis.py +89 -0
- lfx/components/redis/redis_chat.py +43 -0
- lfx/components/sambanova/__init__.py +32 -0
- lfx/components/sambanova/sambanova.py +84 -0
- lfx/components/scrapegraph/__init__.py +40 -0
- lfx/components/scrapegraph/scrapegraph_markdownify_api.py +64 -0
- lfx/components/scrapegraph/scrapegraph_search_api.py +64 -0
- lfx/components/scrapegraph/scrapegraph_smart_scraper_api.py +71 -0
- lfx/components/searchapi/__init__.py +34 -0
- lfx/components/searchapi/search.py +79 -0
- lfx/components/serpapi/__init__.py +3 -0
- lfx/components/serpapi/serp.py +115 -0
- lfx/components/supabase/__init__.py +34 -0
- lfx/components/supabase/supabase.py +76 -0
- lfx/components/tavily/__init__.py +4 -0
- lfx/components/tavily/tavily_extract.py +117 -0
- lfx/components/tavily/tavily_search.py +212 -0
- lfx/components/textsplitters/__init__.py +3 -0
- lfx/components/toolkits/__init__.py +3 -0
- lfx/components/tools/__init__.py +72 -0
- lfx/components/tools/calculator.py +108 -0
- lfx/components/tools/google_search_api.py +45 -0
- lfx/components/tools/google_serper_api.py +115 -0
- lfx/components/tools/python_code_structured_tool.py +327 -0
- lfx/components/tools/python_repl.py +97 -0
- lfx/components/tools/search_api.py +87 -0
- lfx/components/tools/searxng.py +145 -0
- lfx/components/tools/serp_api.py +119 -0
- lfx/components/tools/tavily_search_tool.py +344 -0
- lfx/components/tools/wikidata_api.py +102 -0
- lfx/components/tools/wikipedia_api.py +49 -0
- lfx/components/tools/yahoo_finance.py +129 -0
- lfx/components/twelvelabs/__init__.py +52 -0
- lfx/components/twelvelabs/convert_astra_results.py +84 -0
- lfx/components/twelvelabs/pegasus_index.py +311 -0
- lfx/components/twelvelabs/split_video.py +291 -0
- lfx/components/twelvelabs/text_embeddings.py +57 -0
- lfx/components/twelvelabs/twelvelabs_pegasus.py +408 -0
- lfx/components/twelvelabs/video_embeddings.py +100 -0
- lfx/components/twelvelabs/video_file.py +179 -0
- lfx/components/unstructured/__init__.py +3 -0
- lfx/components/unstructured/unstructured.py +121 -0
- lfx/components/upstash/__init__.py +34 -0
- lfx/components/upstash/upstash.py +124 -0
- lfx/components/vectara/__init__.py +37 -0
- lfx/components/vectara/vectara.py +97 -0
- lfx/components/vectara/vectara_rag.py +164 -0
- lfx/components/vectorstores/__init__.py +40 -0
- lfx/components/vectorstores/astradb.py +1285 -0
- lfx/components/vectorstores/astradb_graph.py +319 -0
- lfx/components/vectorstores/cassandra.py +264 -0
- lfx/components/vectorstores/cassandra_graph.py +238 -0
- lfx/components/vectorstores/chroma.py +167 -0
- lfx/components/vectorstores/clickhouse.py +135 -0
- lfx/components/vectorstores/couchbase.py +102 -0
- lfx/components/vectorstores/elasticsearch.py +267 -0
- lfx/components/vectorstores/faiss.py +111 -0
- lfx/components/vectorstores/graph_rag.py +141 -0
- lfx/components/vectorstores/hcd.py +314 -0
- lfx/components/vectorstores/local_db.py +261 -0
- lfx/components/vectorstores/milvus.py +115 -0
- lfx/components/vectorstores/mongodb_atlas.py +213 -0
- lfx/components/vectorstores/opensearch.py +243 -0
- lfx/components/vectorstores/pgvector.py +72 -0
- lfx/components/vectorstores/pinecone.py +134 -0
- lfx/components/vectorstores/qdrant.py +109 -0
- lfx/components/vectorstores/supabase.py +76 -0
- lfx/components/vectorstores/upstash.py +124 -0
- lfx/components/vectorstores/vectara.py +97 -0
- lfx/components/vectorstores/vectara_rag.py +164 -0
- lfx/components/vectorstores/weaviate.py +89 -0
- lfx/components/vertexai/__init__.py +37 -0
- lfx/components/vertexai/vertexai.py +71 -0
- lfx/components/vertexai/vertexai_embeddings.py +67 -0
- lfx/components/weaviate/__init__.py +34 -0
- lfx/components/weaviate/weaviate.py +89 -0
- lfx/components/wikipedia/__init__.py +4 -0
- lfx/components/wikipedia/wikidata.py +86 -0
- lfx/components/wikipedia/wikipedia.py +53 -0
- lfx/components/wolframalpha/__init__.py +3 -0
- lfx/components/wolframalpha/wolfram_alpha_api.py +54 -0
- lfx/components/xai/__init__.py +32 -0
- lfx/components/xai/xai.py +167 -0
- lfx/components/yahoosearch/__init__.py +3 -0
- lfx/components/yahoosearch/yahoo.py +137 -0
- lfx/components/youtube/__init__.py +52 -0
- lfx/components/youtube/channel.py +227 -0
- lfx/components/youtube/comments.py +231 -0
- lfx/components/youtube/playlist.py +33 -0
- lfx/components/youtube/search.py +120 -0
- lfx/components/youtube/trending.py +285 -0
- lfx/components/youtube/video_details.py +263 -0
- lfx/components/youtube/youtube_transcripts.py +118 -0
- lfx/components/zep/__init__.py +3 -0
- lfx/components/zep/zep.py +44 -0
- lfx/constants.py +6 -0
- lfx/custom/__init__.py +7 -0
- lfx/custom/attributes.py +86 -0
- lfx/custom/code_parser/__init__.py +3 -0
- lfx/custom/code_parser/code_parser.py +361 -0
- lfx/custom/custom_component/__init__.py +0 -0
- lfx/custom/custom_component/base_component.py +128 -0
- lfx/custom/custom_component/component.py +1808 -0
- lfx/custom/custom_component/component_with_cache.py +8 -0
- lfx/custom/custom_component/custom_component.py +588 -0
- lfx/custom/dependency_analyzer.py +165 -0
- lfx/custom/directory_reader/__init__.py +3 -0
- lfx/custom/directory_reader/directory_reader.py +359 -0
- lfx/custom/directory_reader/utils.py +171 -0
- lfx/custom/eval.py +12 -0
- lfx/custom/schema.py +32 -0
- lfx/custom/tree_visitor.py +21 -0
- lfx/custom/utils.py +877 -0
- lfx/custom/validate.py +488 -0
- lfx/events/__init__.py +1 -0
- lfx/events/event_manager.py +110 -0
- lfx/exceptions/__init__.py +0 -0
- lfx/exceptions/component.py +15 -0
- lfx/field_typing/__init__.py +91 -0
- lfx/field_typing/constants.py +215 -0
- lfx/field_typing/range_spec.py +35 -0
- lfx/graph/__init__.py +6 -0
- lfx/graph/edge/__init__.py +0 -0
- lfx/graph/edge/base.py +277 -0
- lfx/graph/edge/schema.py +119 -0
- lfx/graph/edge/utils.py +0 -0
- lfx/graph/graph/__init__.py +0 -0
- lfx/graph/graph/ascii.py +202 -0
- lfx/graph/graph/base.py +2238 -0
- lfx/graph/graph/constants.py +63 -0
- lfx/graph/graph/runnable_vertices_manager.py +133 -0
- lfx/graph/graph/schema.py +52 -0
- lfx/graph/graph/state_model.py +66 -0
- lfx/graph/graph/utils.py +1024 -0
- lfx/graph/schema.py +75 -0
- lfx/graph/state/__init__.py +0 -0
- lfx/graph/state/model.py +237 -0
- lfx/graph/utils.py +200 -0
- lfx/graph/vertex/__init__.py +0 -0
- lfx/graph/vertex/base.py +823 -0
- lfx/graph/vertex/constants.py +0 -0
- lfx/graph/vertex/exceptions.py +4 -0
- lfx/graph/vertex/param_handler.py +264 -0
- lfx/graph/vertex/schema.py +26 -0
- lfx/graph/vertex/utils.py +19 -0
- lfx/graph/vertex/vertex_types.py +489 -0
- lfx/helpers/__init__.py +1 -0
- lfx/helpers/base_model.py +71 -0
- lfx/helpers/custom.py +13 -0
- lfx/helpers/data.py +167 -0
- lfx/helpers/flow.py +194 -0
- lfx/inputs/__init__.py +68 -0
- lfx/inputs/constants.py +2 -0
- lfx/inputs/input_mixin.py +328 -0
- lfx/inputs/inputs.py +714 -0
- lfx/inputs/validators.py +19 -0
- lfx/interface/__init__.py +6 -0
- lfx/interface/components.py +489 -0
- lfx/interface/importing/__init__.py +5 -0
- lfx/interface/importing/utils.py +39 -0
- lfx/interface/initialize/__init__.py +3 -0
- lfx/interface/initialize/loading.py +224 -0
- lfx/interface/listing.py +26 -0
- lfx/interface/run.py +16 -0
- lfx/interface/utils.py +111 -0
- lfx/io/__init__.py +63 -0
- lfx/io/schema.py +289 -0
- lfx/load/__init__.py +8 -0
- lfx/load/load.py +256 -0
- lfx/load/utils.py +99 -0
- lfx/log/__init__.py +5 -0
- lfx/log/logger.py +385 -0
- lfx/memory/__init__.py +90 -0
- lfx/memory/stubs.py +283 -0
- lfx/processing/__init__.py +1 -0
- lfx/processing/process.py +238 -0
- lfx/processing/utils.py +25 -0
- lfx/py.typed +0 -0
- lfx/schema/__init__.py +66 -0
- lfx/schema/artifact.py +83 -0
- lfx/schema/content_block.py +62 -0
- lfx/schema/content_types.py +91 -0
- lfx/schema/data.py +308 -0
- lfx/schema/dataframe.py +210 -0
- lfx/schema/dotdict.py +74 -0
- lfx/schema/encoders.py +13 -0
- lfx/schema/graph.py +47 -0
- lfx/schema/image.py +131 -0
- lfx/schema/json_schema.py +141 -0
- lfx/schema/log.py +61 -0
- lfx/schema/message.py +473 -0
- lfx/schema/openai_responses_schemas.py +74 -0
- lfx/schema/properties.py +41 -0
- lfx/schema/schema.py +171 -0
- lfx/schema/serialize.py +13 -0
- lfx/schema/table.py +140 -0
- lfx/schema/validators.py +114 -0
- lfx/serialization/__init__.py +5 -0
- lfx/serialization/constants.py +2 -0
- lfx/serialization/serialization.py +314 -0
- lfx/services/__init__.py +23 -0
- lfx/services/base.py +28 -0
- lfx/services/cache/__init__.py +6 -0
- lfx/services/cache/base.py +183 -0
- lfx/services/cache/service.py +166 -0
- lfx/services/cache/utils.py +169 -0
- lfx/services/chat/__init__.py +1 -0
- lfx/services/chat/config.py +2 -0
- lfx/services/chat/schema.py +10 -0
- lfx/services/deps.py +129 -0
- lfx/services/factory.py +19 -0
- lfx/services/initialize.py +19 -0
- lfx/services/interfaces.py +103 -0
- lfx/services/manager.py +172 -0
- lfx/services/schema.py +20 -0
- lfx/services/session.py +82 -0
- lfx/services/settings/__init__.py +3 -0
- lfx/services/settings/auth.py +130 -0
- lfx/services/settings/base.py +539 -0
- lfx/services/settings/constants.py +31 -0
- lfx/services/settings/factory.py +23 -0
- lfx/services/settings/feature_flags.py +12 -0
- lfx/services/settings/service.py +35 -0
- lfx/services/settings/utils.py +40 -0
- lfx/services/shared_component_cache/__init__.py +1 -0
- lfx/services/shared_component_cache/factory.py +30 -0
- lfx/services/shared_component_cache/service.py +9 -0
- lfx/services/storage/__init__.py +5 -0
- lfx/services/storage/local.py +155 -0
- lfx/services/storage/service.py +54 -0
- lfx/services/tracing/__init__.py +1 -0
- lfx/services/tracing/service.py +21 -0
- lfx/settings.py +6 -0
- lfx/template/__init__.py +6 -0
- lfx/template/field/__init__.py +0 -0
- lfx/template/field/base.py +257 -0
- lfx/template/field/prompt.py +15 -0
- lfx/template/frontend_node/__init__.py +6 -0
- lfx/template/frontend_node/base.py +212 -0
- lfx/template/frontend_node/constants.py +65 -0
- lfx/template/frontend_node/custom_components.py +79 -0
- lfx/template/template/__init__.py +0 -0
- lfx/template/template/base.py +100 -0
- lfx/template/utils.py +217 -0
- lfx/type_extraction/__init__.py +19 -0
- lfx/type_extraction/type_extraction.py +75 -0
- lfx/type_extraction.py +80 -0
- lfx/utils/__init__.py +1 -0
- lfx/utils/async_helpers.py +42 -0
- lfx/utils/component_utils.py +154 -0
- lfx/utils/concurrency.py +60 -0
- lfx/utils/connection_string_parser.py +11 -0
- lfx/utils/constants.py +205 -0
- lfx/utils/data_structure.py +212 -0
- lfx/utils/exceptions.py +22 -0
- lfx/utils/helpers.py +28 -0
- lfx/utils/image.py +73 -0
- lfx/utils/lazy_load.py +15 -0
- lfx/utils/request_utils.py +18 -0
- lfx/utils/schemas.py +139 -0
- lfx/utils/util.py +481 -0
- lfx/utils/util_strings.py +56 -0
- lfx/utils/version.py +24 -0
- lfx_nightly-0.1.11.dev0.dist-info/METADATA +293 -0
- lfx_nightly-0.1.11.dev0.dist-info/RECORD +699 -0
- lfx_nightly-0.1.11.dev0.dist-info/WHEEL +4 -0
- lfx_nightly-0.1.11.dev0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
from typing import Annotated
|
2
|
+
|
3
|
+
from pydantic import BaseModel, Discriminator, Field, Tag, field_serializer, field_validator
|
4
|
+
from typing_extensions import TypedDict
|
5
|
+
|
6
|
+
from .content_types import CodeContent, ErrorContent, JSONContent, MediaContent, TextContent, ToolContent
|
7
|
+
|
8
|
+
|
9
|
+
def _get_type(d: dict | BaseModel) -> str | None:
|
10
|
+
if isinstance(d, dict):
|
11
|
+
return d.get("type")
|
12
|
+
return getattr(d, "type", None)
|
13
|
+
|
14
|
+
|
15
|
+
# Create a union type of all content types
|
16
|
+
ContentType = Annotated[
|
17
|
+
Annotated[ToolContent, Tag("tool_use")]
|
18
|
+
| Annotated[ErrorContent, Tag("error")]
|
19
|
+
| Annotated[TextContent, Tag("text")]
|
20
|
+
| Annotated[MediaContent, Tag("media")]
|
21
|
+
| Annotated[CodeContent, Tag("code")]
|
22
|
+
| Annotated[JSONContent, Tag("json")],
|
23
|
+
Discriminator(_get_type),
|
24
|
+
]
|
25
|
+
|
26
|
+
|
27
|
+
class ContentBlock(BaseModel):
|
28
|
+
"""A block of content that can contain different types of content."""
|
29
|
+
|
30
|
+
title: str
|
31
|
+
contents: list[ContentType]
|
32
|
+
allow_markdown: bool = Field(default=True)
|
33
|
+
media_url: list[str] | None = None
|
34
|
+
|
35
|
+
def __init__(self, **data) -> None:
|
36
|
+
super().__init__(**data)
|
37
|
+
schema_dict = self.__pydantic_core_schema__["schema"]
|
38
|
+
if "fields" in schema_dict:
|
39
|
+
fields = schema_dict["fields"]
|
40
|
+
elif "schema" in schema_dict:
|
41
|
+
fields = schema_dict["schema"]["fields"]
|
42
|
+
fields_with_default = (f for f, d in fields.items() if "default" in d["schema"])
|
43
|
+
self.model_fields_set.update(fields_with_default)
|
44
|
+
|
45
|
+
@field_validator("contents", mode="before")
|
46
|
+
@classmethod
|
47
|
+
def validate_contents(cls, v) -> list[ContentType]:
|
48
|
+
if isinstance(v, dict):
|
49
|
+
msg = "Contents must be a list of ContentTypes"
|
50
|
+
raise TypeError(msg)
|
51
|
+
return [v] if isinstance(v, BaseModel) else v
|
52
|
+
|
53
|
+
@field_serializer("contents")
|
54
|
+
def serialize_contents(self, value) -> list[dict]:
|
55
|
+
return [v.model_dump() for v in value]
|
56
|
+
|
57
|
+
|
58
|
+
class ContentBlockDict(TypedDict):
|
59
|
+
title: str
|
60
|
+
contents: list[dict]
|
61
|
+
allow_markdown: bool
|
62
|
+
media_url: list[str] | None
|
@@ -0,0 +1,91 @@
|
|
1
|
+
from typing import Any, Literal
|
2
|
+
|
3
|
+
from fastapi.encoders import jsonable_encoder
|
4
|
+
from pydantic import BaseModel, ConfigDict, Field, model_serializer
|
5
|
+
from typing_extensions import TypedDict
|
6
|
+
|
7
|
+
from lfx.schema.encoders import CUSTOM_ENCODERS
|
8
|
+
|
9
|
+
|
10
|
+
class HeaderDict(TypedDict, total=False):
|
11
|
+
title: str | None
|
12
|
+
icon: str | None
|
13
|
+
|
14
|
+
|
15
|
+
class BaseContent(BaseModel):
|
16
|
+
"""Base class for all content types."""
|
17
|
+
|
18
|
+
type: str = Field(..., description="Type of the content")
|
19
|
+
duration: int | None = None
|
20
|
+
header: HeaderDict | None = Field(default_factory=dict)
|
21
|
+
|
22
|
+
def to_dict(self) -> dict[str, Any]:
|
23
|
+
return self.model_dump()
|
24
|
+
|
25
|
+
@classmethod
|
26
|
+
def from_dict(cls, data: dict[str, Any]) -> "BaseContent":
|
27
|
+
return cls(**data)
|
28
|
+
|
29
|
+
@model_serializer(mode="wrap")
|
30
|
+
def serialize_model(self, nxt) -> dict[str, Any]:
|
31
|
+
try:
|
32
|
+
dump = nxt(self)
|
33
|
+
return jsonable_encoder(dump, custom_encoder=CUSTOM_ENCODERS)
|
34
|
+
except Exception: # noqa: BLE001
|
35
|
+
return nxt(self)
|
36
|
+
|
37
|
+
|
38
|
+
class ErrorContent(BaseContent):
|
39
|
+
"""Content type for error messages."""
|
40
|
+
|
41
|
+
type: Literal["error"] = Field(default="error")
|
42
|
+
component: str | None = None
|
43
|
+
field: str | None = None
|
44
|
+
reason: str | None = None
|
45
|
+
solution: str | None = None
|
46
|
+
traceback: str | None = None
|
47
|
+
|
48
|
+
|
49
|
+
class TextContent(BaseContent):
|
50
|
+
"""Content type for simple text content."""
|
51
|
+
|
52
|
+
type: Literal["text"] = Field(default="text")
|
53
|
+
text: str
|
54
|
+
duration: int | None = None
|
55
|
+
|
56
|
+
|
57
|
+
class MediaContent(BaseContent):
|
58
|
+
"""Content type for media content."""
|
59
|
+
|
60
|
+
type: Literal["media"] = Field(default="media")
|
61
|
+
urls: list[str]
|
62
|
+
caption: str | None = None
|
63
|
+
|
64
|
+
|
65
|
+
class JSONContent(BaseContent):
|
66
|
+
"""Content type for JSON content."""
|
67
|
+
|
68
|
+
type: Literal["json"] = Field(default="json")
|
69
|
+
data: dict[str, Any]
|
70
|
+
|
71
|
+
|
72
|
+
class CodeContent(BaseContent):
|
73
|
+
"""Content type for code snippets."""
|
74
|
+
|
75
|
+
type: Literal["code"] = Field(default="code")
|
76
|
+
code: str
|
77
|
+
language: str
|
78
|
+
title: str | None = None
|
79
|
+
|
80
|
+
|
81
|
+
class ToolContent(BaseContent):
|
82
|
+
"""Content type for tool start content."""
|
83
|
+
|
84
|
+
model_config = ConfigDict(populate_by_name=True)
|
85
|
+
|
86
|
+
type: Literal["tool_use"] = Field(default="tool_use")
|
87
|
+
name: str | None = None
|
88
|
+
tool_input: dict[str, Any] = Field(default_factory=dict, alias="input")
|
89
|
+
output: Any | None = None
|
90
|
+
error: Any | None = None
|
91
|
+
duration: int | None = None
|
lfx/schema/data.py
ADDED
@@ -0,0 +1,308 @@
|
|
1
|
+
"""Lightweight Data class for lfx package - contains only methods with no langflow dependencies."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
import copy
|
6
|
+
import json
|
7
|
+
from datetime import datetime, timezone
|
8
|
+
from decimal import Decimal
|
9
|
+
from typing import TYPE_CHECKING, cast
|
10
|
+
from uuid import UUID
|
11
|
+
|
12
|
+
from langchain_core.documents import Document
|
13
|
+
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage
|
14
|
+
from pydantic import BaseModel, ConfigDict, model_serializer, model_validator
|
15
|
+
|
16
|
+
from lfx.log.logger import logger
|
17
|
+
from lfx.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER
|
18
|
+
from lfx.utils.image import create_image_content_dict
|
19
|
+
|
20
|
+
if TYPE_CHECKING:
|
21
|
+
from lfx.schema.dataframe import DataFrame
|
22
|
+
from lfx.schema.message import Message
|
23
|
+
|
24
|
+
|
25
|
+
class Data(BaseModel):
|
26
|
+
"""Represents a record with text and optional data.
|
27
|
+
|
28
|
+
Attributes:
|
29
|
+
data (dict, optional): Additional data associated with the record.
|
30
|
+
"""
|
31
|
+
|
32
|
+
model_config = ConfigDict(validate_assignment=True)
|
33
|
+
|
34
|
+
text_key: str = "text"
|
35
|
+
data: dict = {}
|
36
|
+
default_value: str | None = ""
|
37
|
+
|
38
|
+
@model_validator(mode="before")
|
39
|
+
@classmethod
|
40
|
+
def validate_data(cls, values):
|
41
|
+
if not isinstance(values, dict):
|
42
|
+
msg = "Data must be a dictionary"
|
43
|
+
raise ValueError(msg) # noqa: TRY004
|
44
|
+
if "data" not in values or values["data"] is None:
|
45
|
+
values["data"] = {}
|
46
|
+
if not isinstance(values["data"], dict):
|
47
|
+
msg = (
|
48
|
+
f"Invalid data format: expected dictionary but got {type(values).__name__}."
|
49
|
+
" This will raise an error in version langflow==1.3.0."
|
50
|
+
)
|
51
|
+
logger.warning(msg)
|
52
|
+
# Any other keyword should be added to the data dictionary
|
53
|
+
for key in values:
|
54
|
+
if key not in values["data"] and key not in {"text_key", "data", "default_value"}:
|
55
|
+
values["data"][key] = values[key]
|
56
|
+
return values
|
57
|
+
|
58
|
+
@model_serializer(mode="plain", when_used="json")
|
59
|
+
def serialize_model(self):
|
60
|
+
return {k: v.to_json() if hasattr(v, "to_json") else v for k, v in self.data.items()}
|
61
|
+
|
62
|
+
def get_text(self):
|
63
|
+
"""Retrieves the text value from the data dictionary.
|
64
|
+
|
65
|
+
If the text key is present in the data dictionary, the corresponding value is returned.
|
66
|
+
Otherwise, the default value is returned.
|
67
|
+
|
68
|
+
Returns:
|
69
|
+
The text value from the data dictionary or the default value.
|
70
|
+
"""
|
71
|
+
return self.data.get(self.text_key, self.default_value)
|
72
|
+
|
73
|
+
def set_text(self, text: str | None) -> str:
|
74
|
+
r"""Sets the text value in the data dictionary.
|
75
|
+
|
76
|
+
The object's `text` value is set to `text parameter as given, with the following modifications:
|
77
|
+
|
78
|
+
- `text` value of `None` is converted to an empty string.
|
79
|
+
- `text` value is converted to `str` type.
|
80
|
+
|
81
|
+
Args:
|
82
|
+
text (str): The text to be set in the data dictionary.
|
83
|
+
|
84
|
+
Returns:
|
85
|
+
str: The text value that was set in the data dictionary.
|
86
|
+
"""
|
87
|
+
new_text = "" if text is None else str(text)
|
88
|
+
self.data[self.text_key] = new_text
|
89
|
+
return new_text
|
90
|
+
|
91
|
+
@classmethod
|
92
|
+
def from_document(cls, document: Document) -> Data:
|
93
|
+
"""Converts a Document to a Data.
|
94
|
+
|
95
|
+
Args:
|
96
|
+
document (Document): The Document to convert.
|
97
|
+
|
98
|
+
Returns:
|
99
|
+
Data: The converted Data.
|
100
|
+
"""
|
101
|
+
data = document.metadata
|
102
|
+
data["text"] = document.page_content
|
103
|
+
return cls(data=data, text_key="text")
|
104
|
+
|
105
|
+
@classmethod
|
106
|
+
def from_lc_message(cls, message: BaseMessage) -> Data:
|
107
|
+
"""Converts a BaseMessage to a Data.
|
108
|
+
|
109
|
+
Args:
|
110
|
+
message (BaseMessage): The BaseMessage to convert.
|
111
|
+
|
112
|
+
Returns:
|
113
|
+
Data: The converted Data.
|
114
|
+
"""
|
115
|
+
data: dict = {"text": message.content}
|
116
|
+
data["metadata"] = cast("dict", message.to_json())
|
117
|
+
return cls(data=data, text_key="text")
|
118
|
+
|
119
|
+
def __add__(self, other: Data) -> Data:
|
120
|
+
"""Combines the data of two data by attempting to add values for overlapping keys.
|
121
|
+
|
122
|
+
Combines the data of two data by attempting to add values for overlapping keys
|
123
|
+
for all types that support the addition operation. Falls back to the value from 'other'
|
124
|
+
record when addition is not supported.
|
125
|
+
"""
|
126
|
+
combined_data = self.data.copy()
|
127
|
+
for key, value in other.data.items():
|
128
|
+
# If the key exists in both data and both values support the addition operation
|
129
|
+
if key in combined_data:
|
130
|
+
try:
|
131
|
+
combined_data[key] += value
|
132
|
+
except TypeError:
|
133
|
+
# Fallback: Use the value from 'other' record if addition is not supported
|
134
|
+
combined_data[key] = value
|
135
|
+
else:
|
136
|
+
# If the key is not in the first record, simply add it
|
137
|
+
combined_data[key] = value
|
138
|
+
|
139
|
+
return Data(data=combined_data)
|
140
|
+
|
141
|
+
def to_lc_document(self) -> Document:
|
142
|
+
"""Converts the Data to a Document.
|
143
|
+
|
144
|
+
Returns:
|
145
|
+
Document: The converted Document.
|
146
|
+
"""
|
147
|
+
data_copy = self.data.copy()
|
148
|
+
text = data_copy.pop(self.text_key, self.default_value)
|
149
|
+
if isinstance(text, str):
|
150
|
+
return Document(page_content=text, metadata=data_copy)
|
151
|
+
return Document(page_content=str(text), metadata=data_copy)
|
152
|
+
|
153
|
+
def to_lc_message(
|
154
|
+
self,
|
155
|
+
) -> BaseMessage:
|
156
|
+
"""Converts the Data to a BaseMessage.
|
157
|
+
|
158
|
+
Returns:
|
159
|
+
BaseMessage: The converted BaseMessage.
|
160
|
+
"""
|
161
|
+
# The idea of this function is to be a helper to convert a Data to a BaseMessage
|
162
|
+
# It will use the "sender" key to determine if the message is Human or AI
|
163
|
+
# If the key is not present, it will default to AI
|
164
|
+
# But first we check if all required keys are present in the data dictionary
|
165
|
+
# they are: "text", "sender"
|
166
|
+
if not all(key in self.data for key in ["text", "sender"]):
|
167
|
+
msg = f"Missing required keys ('text', 'sender') in Data: {self.data}"
|
168
|
+
raise ValueError(msg)
|
169
|
+
sender = self.data.get("sender", MESSAGE_SENDER_AI)
|
170
|
+
text = self.data.get("text", "")
|
171
|
+
files = self.data.get("files", [])
|
172
|
+
if sender == MESSAGE_SENDER_USER:
|
173
|
+
if files:
|
174
|
+
from lfx.schema.image import get_file_paths
|
175
|
+
|
176
|
+
resolved_file_paths = get_file_paths(files)
|
177
|
+
contents = [create_image_content_dict(file_path) for file_path in resolved_file_paths]
|
178
|
+
# add to the beginning of the list
|
179
|
+
contents.insert(0, {"type": "text", "text": text})
|
180
|
+
human_message = HumanMessage(content=contents)
|
181
|
+
else:
|
182
|
+
human_message = HumanMessage(
|
183
|
+
content=[{"type": "text", "text": text}],
|
184
|
+
)
|
185
|
+
|
186
|
+
return human_message
|
187
|
+
|
188
|
+
return AIMessage(content=text)
|
189
|
+
|
190
|
+
def __getattr__(self, key):
|
191
|
+
"""Allows attribute-like access to the data dictionary."""
|
192
|
+
try:
|
193
|
+
if key.startswith("__"):
|
194
|
+
return self.__getattribute__(key)
|
195
|
+
if key in {"data", "text_key"} or key.startswith("_"):
|
196
|
+
return super().__getattr__(key)
|
197
|
+
return self.data[key]
|
198
|
+
except KeyError as e:
|
199
|
+
# Fallback to default behavior to raise AttributeError for undefined attributes
|
200
|
+
msg = f"'{type(self).__name__}' object has no attribute '{key}'"
|
201
|
+
raise AttributeError(msg) from e
|
202
|
+
|
203
|
+
def __setattr__(self, key, value) -> None:
|
204
|
+
"""Set attribute-like values in the data dictionary.
|
205
|
+
|
206
|
+
Allows attribute-like setting of values in the data dictionary.
|
207
|
+
while still allowing direct assignment to class attributes.
|
208
|
+
"""
|
209
|
+
if key in {"data", "text_key"} or key.startswith("_"):
|
210
|
+
super().__setattr__(key, value)
|
211
|
+
elif key in self.model_fields:
|
212
|
+
self.data[key] = value
|
213
|
+
super().__setattr__(key, value)
|
214
|
+
else:
|
215
|
+
self.data[key] = value
|
216
|
+
|
217
|
+
def __delattr__(self, key) -> None:
|
218
|
+
"""Allows attribute-like deletion from the data dictionary."""
|
219
|
+
if key in {"data", "text_key"} or key.startswith("_"):
|
220
|
+
super().__delattr__(key)
|
221
|
+
else:
|
222
|
+
del self.data[key]
|
223
|
+
|
224
|
+
def __deepcopy__(self, memo):
|
225
|
+
"""Custom deepcopy implementation to handle copying of the Data object."""
|
226
|
+
# Create a new Data object with a deep copy of the data dictionary
|
227
|
+
return Data(data=copy.deepcopy(self.data, memo), text_key=self.text_key, default_value=self.default_value)
|
228
|
+
|
229
|
+
# check which attributes the Data has by checking the keys in the data dictionary
|
230
|
+
def __dir__(self):
|
231
|
+
return super().__dir__() + list(self.data.keys())
|
232
|
+
|
233
|
+
def __str__(self) -> str:
|
234
|
+
# return a JSON string representation of the Data atributes
|
235
|
+
try:
|
236
|
+
data = {k: v.to_json() if hasattr(v, "to_json") else v for k, v in self.data.items()}
|
237
|
+
return serialize_data(data) # use the custom serializer
|
238
|
+
except Exception: # noqa: BLE001
|
239
|
+
logger.debug("Error converting Data to JSON", exc_info=True)
|
240
|
+
return str(self.data)
|
241
|
+
|
242
|
+
def __contains__(self, key) -> bool:
|
243
|
+
return key in self.data
|
244
|
+
|
245
|
+
def __eq__(self, /, other):
|
246
|
+
return isinstance(other, Data) and self.data == other.data
|
247
|
+
|
248
|
+
def filter_data(self, filter_str: str) -> Data:
|
249
|
+
"""Filters the data dictionary based on the filter string.
|
250
|
+
|
251
|
+
Args:
|
252
|
+
filter_str (str): The filter string to apply to the data dictionary.
|
253
|
+
|
254
|
+
Returns:
|
255
|
+
Data: The filtered Data.
|
256
|
+
"""
|
257
|
+
from lfx.template.utils import apply_json_filter
|
258
|
+
|
259
|
+
return apply_json_filter(self.data, filter_str)
|
260
|
+
|
261
|
+
def to_message(self) -> Message:
|
262
|
+
from lfx.schema.message import Message # Local import to avoid circular import
|
263
|
+
|
264
|
+
if self.text_key in self.data:
|
265
|
+
return Message(text=self.get_text())
|
266
|
+
return Message(text=str(self.data))
|
267
|
+
|
268
|
+
def to_dataframe(self) -> DataFrame:
|
269
|
+
from lfx.schema.dataframe import DataFrame # Local import to avoid circular import
|
270
|
+
|
271
|
+
data_dict = self.data
|
272
|
+
# If data contains only one key and the value is a list of dictionaries, convert to DataFrame
|
273
|
+
if (
|
274
|
+
len(data_dict) == 1
|
275
|
+
and isinstance(next(iter(data_dict.values())), list)
|
276
|
+
and all(isinstance(item, dict) for item in next(iter(data_dict.values())))
|
277
|
+
):
|
278
|
+
return DataFrame(data=next(iter(data_dict.values())))
|
279
|
+
return DataFrame(data=[self])
|
280
|
+
|
281
|
+
def __repr__(self) -> str:
|
282
|
+
"""Return string representation of the Data object."""
|
283
|
+
return f"Data(text_key={self.text_key!r}, data={self.data!r}, default_value={self.default_value!r})"
|
284
|
+
|
285
|
+
def __hash__(self) -> int:
|
286
|
+
"""Return hash of the Data object based on its string representation."""
|
287
|
+
return hash(self.__repr__())
|
288
|
+
|
289
|
+
|
290
|
+
def custom_serializer(obj):
|
291
|
+
if isinstance(obj, datetime):
|
292
|
+
utc_date = obj.replace(tzinfo=timezone.utc)
|
293
|
+
return utc_date.strftime("%Y-%m-%d %H:%M:%S %Z")
|
294
|
+
if isinstance(obj, Decimal):
|
295
|
+
return float(obj)
|
296
|
+
if isinstance(obj, UUID):
|
297
|
+
return str(obj)
|
298
|
+
if isinstance(obj, BaseModel):
|
299
|
+
return obj.model_dump()
|
300
|
+
if isinstance(obj, bytes):
|
301
|
+
return obj.decode("utf-8", errors="replace")
|
302
|
+
# Add more custom serialization rules as needed
|
303
|
+
msg = f"Type {type(obj)} not serializable"
|
304
|
+
raise TypeError(msg)
|
305
|
+
|
306
|
+
|
307
|
+
def serialize_data(data):
|
308
|
+
return json.dumps(data, indent=4, default=custom_serializer)
|
lfx/schema/dataframe.py
ADDED
@@ -0,0 +1,210 @@
|
|
1
|
+
from typing import TYPE_CHECKING, cast
|
2
|
+
|
3
|
+
import pandas as pd
|
4
|
+
from langchain_core.documents import Document
|
5
|
+
from pandas import DataFrame as pandas_DataFrame
|
6
|
+
|
7
|
+
from lfx.schema.data import Data
|
8
|
+
|
9
|
+
if TYPE_CHECKING:
|
10
|
+
from lfx.schema.message import Message
|
11
|
+
|
12
|
+
|
13
|
+
class DataFrame(pandas_DataFrame):
|
14
|
+
"""A pandas DataFrame subclass specialized for handling collections of Data objects.
|
15
|
+
|
16
|
+
This class extends pandas.DataFrame to provide seamless integration between
|
17
|
+
Langflow's Data objects and pandas' powerful data manipulation capabilities.
|
18
|
+
|
19
|
+
Args:
|
20
|
+
data: Input data in various formats:
|
21
|
+
- List[Data]: List of Data objects
|
22
|
+
- List[Dict]: List of dictionaries
|
23
|
+
- Dict: Dictionary of arrays/lists
|
24
|
+
- pandas.DataFrame: Existing DataFrame
|
25
|
+
- Any format supported by pandas.DataFrame
|
26
|
+
**kwargs: Additional arguments passed to pandas.DataFrame constructor
|
27
|
+
|
28
|
+
Examples:
|
29
|
+
>>> # From Data objects
|
30
|
+
>>> dataset = DataFrame([Data(data={"name": "John"}), Data(data={"name": "Jane"})])
|
31
|
+
|
32
|
+
>>> # From dictionaries
|
33
|
+
>>> dataset = DataFrame([{"name": "John"}, {"name": "Jane"}])
|
34
|
+
|
35
|
+
>>> # From dictionary of lists
|
36
|
+
>>> dataset = DataFrame({"name": ["John", "Jane"], "age": [30, 25]})
|
37
|
+
"""
|
38
|
+
|
39
|
+
def __init__(
|
40
|
+
self,
|
41
|
+
data: list[dict] | list[Data] | pd.DataFrame | None = None,
|
42
|
+
text_key: str = "text",
|
43
|
+
default_value: str = "",
|
44
|
+
**kwargs,
|
45
|
+
):
|
46
|
+
# Initialize pandas DataFrame first without data
|
47
|
+
super().__init__(**kwargs) # Removed data parameter
|
48
|
+
|
49
|
+
# Store attributes as private members to avoid conflicts with pandas
|
50
|
+
self._text_key = text_key
|
51
|
+
self._default_value = default_value
|
52
|
+
|
53
|
+
if data is None:
|
54
|
+
return
|
55
|
+
|
56
|
+
if isinstance(data, list):
|
57
|
+
if all(isinstance(x, Data) for x in data):
|
58
|
+
data = [d.data for d in data if hasattr(d, "data")]
|
59
|
+
elif not all(isinstance(x, dict) for x in data):
|
60
|
+
msg = "List items must be either all Data objects or all dictionaries"
|
61
|
+
raise ValueError(msg)
|
62
|
+
self._update(data, **kwargs)
|
63
|
+
elif isinstance(data, dict | pd.DataFrame): # Fixed type check syntax
|
64
|
+
self._update(data, **kwargs)
|
65
|
+
|
66
|
+
def _update(self, data, **kwargs):
|
67
|
+
"""Helper method to update DataFrame with new data."""
|
68
|
+
new_df = pd.DataFrame(data, **kwargs)
|
69
|
+
self._update_inplace(new_df)
|
70
|
+
|
71
|
+
# Update property accessors
|
72
|
+
@property
|
73
|
+
def text_key(self) -> str:
|
74
|
+
return self._text_key
|
75
|
+
|
76
|
+
@text_key.setter
|
77
|
+
def text_key(self, value: str) -> None:
|
78
|
+
if value not in self.columns:
|
79
|
+
msg = f"Text key '{value}' not found in DataFrame columns"
|
80
|
+
raise ValueError(msg)
|
81
|
+
self._text_key = value
|
82
|
+
|
83
|
+
@property
|
84
|
+
def default_value(self) -> str:
|
85
|
+
return self._default_value
|
86
|
+
|
87
|
+
@default_value.setter
|
88
|
+
def default_value(self, value: str) -> None:
|
89
|
+
self._default_value = value
|
90
|
+
|
91
|
+
def to_data_list(self) -> list[Data]:
|
92
|
+
"""Converts the DataFrame back to a list of Data objects."""
|
93
|
+
list_of_dicts = self.to_dict(orient="records")
|
94
|
+
# suggested change: [Data(**row) for row in list_of_dicts]
|
95
|
+
return [Data(data=row) for row in list_of_dicts]
|
96
|
+
|
97
|
+
def add_row(self, data: dict | Data) -> "DataFrame":
|
98
|
+
"""Adds a single row to the dataset.
|
99
|
+
|
100
|
+
Args:
|
101
|
+
data: Either a Data object or a dictionary to add as a new row
|
102
|
+
|
103
|
+
Returns:
|
104
|
+
DataFrame: A new DataFrame with the added row
|
105
|
+
|
106
|
+
Example:
|
107
|
+
>>> dataset = DataFrame([{"name": "John"}])
|
108
|
+
>>> dataset = dataset.add_row({"name": "Jane"})
|
109
|
+
"""
|
110
|
+
if isinstance(data, Data):
|
111
|
+
data = data.data
|
112
|
+
new_df = self._constructor([data])
|
113
|
+
return cast("DataFrame", pd.concat([self, new_df], ignore_index=True))
|
114
|
+
|
115
|
+
def add_rows(self, data: list[dict | Data]) -> "DataFrame":
|
116
|
+
"""Adds multiple rows to the dataset.
|
117
|
+
|
118
|
+
Args:
|
119
|
+
data: List of Data objects or dictionaries to add as new rows
|
120
|
+
|
121
|
+
Returns:
|
122
|
+
DataFrame: A new DataFrame with the added rows
|
123
|
+
"""
|
124
|
+
processed_data = []
|
125
|
+
for item in data:
|
126
|
+
if isinstance(item, Data):
|
127
|
+
processed_data.append(item.data)
|
128
|
+
else:
|
129
|
+
processed_data.append(item)
|
130
|
+
new_df = self._constructor(processed_data)
|
131
|
+
return cast("DataFrame", pd.concat([self, new_df], ignore_index=True))
|
132
|
+
|
133
|
+
@property
|
134
|
+
def _constructor(self):
|
135
|
+
def _c(*args, **kwargs):
|
136
|
+
return DataFrame(*args, **kwargs).__finalize__(self)
|
137
|
+
|
138
|
+
return _c
|
139
|
+
|
140
|
+
def __bool__(self):
|
141
|
+
"""Truth value testing for the DataFrame.
|
142
|
+
|
143
|
+
Returns True if the DataFrame has at least one row, False otherwise.
|
144
|
+
"""
|
145
|
+
return not self.empty
|
146
|
+
|
147
|
+
__hash__ = None # DataFrames are mutable and shouldn't be hashable
|
148
|
+
|
149
|
+
def to_lc_documents(self) -> list[Document]:
|
150
|
+
"""Converts the DataFrame to a list of Documents.
|
151
|
+
|
152
|
+
Returns:
|
153
|
+
list[Document]: The converted list of Documents.
|
154
|
+
"""
|
155
|
+
list_of_dicts = self.to_dict(orient="records")
|
156
|
+
documents = []
|
157
|
+
for row in list_of_dicts:
|
158
|
+
data_copy = row.copy()
|
159
|
+
text = data_copy.pop(self._text_key, self._default_value)
|
160
|
+
if isinstance(text, str):
|
161
|
+
documents.append(Document(page_content=text, metadata=data_copy))
|
162
|
+
else:
|
163
|
+
documents.append(Document(page_content=str(text), metadata=data_copy))
|
164
|
+
return documents
|
165
|
+
|
166
|
+
def _docs_to_dataframe(self, docs):
|
167
|
+
"""Converts a list of Documents to a DataFrame.
|
168
|
+
|
169
|
+
Args:
|
170
|
+
docs: List of Document objects
|
171
|
+
|
172
|
+
Returns:
|
173
|
+
DataFrame: A new DataFrame with the converted Documents
|
174
|
+
"""
|
175
|
+
return DataFrame(docs)
|
176
|
+
|
177
|
+
def __eq__(self, other):
|
178
|
+
"""Override equality to handle comparison with empty DataFrames and non-DataFrame objects."""
|
179
|
+
if self.empty:
|
180
|
+
return False
|
181
|
+
if isinstance(other, list) and not other: # Empty list case
|
182
|
+
return False
|
183
|
+
if not isinstance(other, DataFrame | pd.DataFrame): # Non-DataFrame case
|
184
|
+
return False
|
185
|
+
return super().__eq__(other)
|
186
|
+
|
187
|
+
def to_data(self) -> Data:
|
188
|
+
"""Convert this DataFrame to a Data object.
|
189
|
+
|
190
|
+
Returns:
|
191
|
+
Data: A Data object containing the DataFrame records under 'results' key.
|
192
|
+
"""
|
193
|
+
dict_list = self.to_dict(orient="records")
|
194
|
+
return Data(data={"results": dict_list})
|
195
|
+
|
196
|
+
def to_message(self) -> "Message":
|
197
|
+
from lfx.schema.message import Message
|
198
|
+
|
199
|
+
# Process DataFrame similar to the _safe_convert method
|
200
|
+
# Remove empty rows
|
201
|
+
processed_df = self.dropna(how="all")
|
202
|
+
# Remove empty lines in each cell
|
203
|
+
processed_df = processed_df.replace(r"^\s*$", "", regex=True)
|
204
|
+
# Replace multiple newlines with a single newline
|
205
|
+
processed_df = processed_df.replace(r"\n+", "\n", regex=True)
|
206
|
+
# Replace pipe characters to avoid markdown table issues
|
207
|
+
processed_df = processed_df.replace(r"\|", r"\\|", regex=True)
|
208
|
+
processed_df = processed_df.map(lambda x: str(x).replace("\n", "<br/>") if isinstance(x, str) else x)
|
209
|
+
# Convert to markdown and wrap in a Message
|
210
|
+
return Message(text=processed_df.to_markdown(index=False))
|