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,544 @@
|
|
1
|
+
import json
|
2
|
+
import re
|
3
|
+
import tempfile
|
4
|
+
from datetime import datetime, timezone
|
5
|
+
from pathlib import Path
|
6
|
+
from typing import Any
|
7
|
+
from urllib.parse import parse_qsl, urlencode, urlparse, urlunparse
|
8
|
+
|
9
|
+
import aiofiles
|
10
|
+
import aiofiles.os as aiofiles_os
|
11
|
+
import httpx
|
12
|
+
import validators
|
13
|
+
|
14
|
+
from lfx.base.curl.parse import parse_context
|
15
|
+
from lfx.custom.custom_component.component import Component
|
16
|
+
from lfx.inputs.inputs import TabInput
|
17
|
+
from lfx.io import (
|
18
|
+
BoolInput,
|
19
|
+
DataInput,
|
20
|
+
DropdownInput,
|
21
|
+
IntInput,
|
22
|
+
MessageTextInput,
|
23
|
+
MultilineInput,
|
24
|
+
Output,
|
25
|
+
TableInput,
|
26
|
+
)
|
27
|
+
from lfx.schema.data import Data
|
28
|
+
from lfx.schema.dotdict import dotdict
|
29
|
+
from lfx.utils.component_utils import set_current_fields, set_field_advanced, set_field_display
|
30
|
+
|
31
|
+
# Define fields for each mode
|
32
|
+
MODE_FIELDS = {
|
33
|
+
"URL": [
|
34
|
+
"url_input",
|
35
|
+
"method",
|
36
|
+
],
|
37
|
+
"cURL": ["curl_input"],
|
38
|
+
}
|
39
|
+
|
40
|
+
# Fields that should always be visible
|
41
|
+
DEFAULT_FIELDS = ["mode"]
|
42
|
+
|
43
|
+
|
44
|
+
class APIRequestComponent(Component):
|
45
|
+
display_name = "API Request"
|
46
|
+
description = "Make HTTP requests using URL or cURL commands."
|
47
|
+
documentation: str = "https://docs.langflow.org/components-data#api-request"
|
48
|
+
icon = "Globe"
|
49
|
+
name = "APIRequest"
|
50
|
+
|
51
|
+
inputs = [
|
52
|
+
MessageTextInput(
|
53
|
+
name="url_input",
|
54
|
+
display_name="URL",
|
55
|
+
info="Enter the URL for the request.",
|
56
|
+
advanced=False,
|
57
|
+
tool_mode=True,
|
58
|
+
),
|
59
|
+
MultilineInput(
|
60
|
+
name="curl_input",
|
61
|
+
display_name="cURL",
|
62
|
+
info=(
|
63
|
+
"Paste a curl command to populate the fields. "
|
64
|
+
"This will fill in the dictionary fields for headers and body."
|
65
|
+
),
|
66
|
+
real_time_refresh=True,
|
67
|
+
tool_mode=True,
|
68
|
+
advanced=True,
|
69
|
+
show=False,
|
70
|
+
),
|
71
|
+
DropdownInput(
|
72
|
+
name="method",
|
73
|
+
display_name="Method",
|
74
|
+
options=["GET", "POST", "PATCH", "PUT", "DELETE"],
|
75
|
+
value="GET",
|
76
|
+
info="The HTTP method to use.",
|
77
|
+
real_time_refresh=True,
|
78
|
+
),
|
79
|
+
TabInput(
|
80
|
+
name="mode",
|
81
|
+
display_name="Mode",
|
82
|
+
options=["URL", "cURL"],
|
83
|
+
value="URL",
|
84
|
+
info="Enable cURL mode to populate fields from a cURL command.",
|
85
|
+
real_time_refresh=True,
|
86
|
+
),
|
87
|
+
DataInput(
|
88
|
+
name="query_params",
|
89
|
+
display_name="Query Parameters",
|
90
|
+
info="The query parameters to append to the URL.",
|
91
|
+
advanced=True,
|
92
|
+
),
|
93
|
+
TableInput(
|
94
|
+
name="body",
|
95
|
+
display_name="Body",
|
96
|
+
info="The body to send with the request as a dictionary (for POST, PATCH, PUT).",
|
97
|
+
table_schema=[
|
98
|
+
{
|
99
|
+
"name": "key",
|
100
|
+
"display_name": "Key",
|
101
|
+
"type": "str",
|
102
|
+
"description": "Parameter name",
|
103
|
+
},
|
104
|
+
{
|
105
|
+
"name": "value",
|
106
|
+
"display_name": "Value",
|
107
|
+
"description": "Parameter value",
|
108
|
+
},
|
109
|
+
],
|
110
|
+
value=[],
|
111
|
+
input_types=["Data"],
|
112
|
+
advanced=True,
|
113
|
+
real_time_refresh=True,
|
114
|
+
),
|
115
|
+
TableInput(
|
116
|
+
name="headers",
|
117
|
+
display_name="Headers",
|
118
|
+
info="The headers to send with the request",
|
119
|
+
table_schema=[
|
120
|
+
{
|
121
|
+
"name": "key",
|
122
|
+
"display_name": "Header",
|
123
|
+
"type": "str",
|
124
|
+
"description": "Header name",
|
125
|
+
},
|
126
|
+
{
|
127
|
+
"name": "value",
|
128
|
+
"display_name": "Value",
|
129
|
+
"type": "str",
|
130
|
+
"description": "Header value",
|
131
|
+
},
|
132
|
+
],
|
133
|
+
value=[{"key": "User-Agent", "value": "Langflow/1.0"}],
|
134
|
+
advanced=True,
|
135
|
+
input_types=["Data"],
|
136
|
+
real_time_refresh=True,
|
137
|
+
),
|
138
|
+
IntInput(
|
139
|
+
name="timeout",
|
140
|
+
display_name="Timeout",
|
141
|
+
value=30,
|
142
|
+
info="The timeout to use for the request.",
|
143
|
+
advanced=True,
|
144
|
+
),
|
145
|
+
BoolInput(
|
146
|
+
name="follow_redirects",
|
147
|
+
display_name="Follow Redirects",
|
148
|
+
value=True,
|
149
|
+
info="Whether to follow http redirects.",
|
150
|
+
advanced=True,
|
151
|
+
),
|
152
|
+
BoolInput(
|
153
|
+
name="save_to_file",
|
154
|
+
display_name="Save to File",
|
155
|
+
value=False,
|
156
|
+
info="Save the API response to a temporary file",
|
157
|
+
advanced=True,
|
158
|
+
),
|
159
|
+
BoolInput(
|
160
|
+
name="include_httpx_metadata",
|
161
|
+
display_name="Include HTTPx Metadata",
|
162
|
+
value=False,
|
163
|
+
info=(
|
164
|
+
"Include properties such as headers, status_code, response_headers, "
|
165
|
+
"and redirection_history in the output."
|
166
|
+
),
|
167
|
+
advanced=True,
|
168
|
+
),
|
169
|
+
]
|
170
|
+
|
171
|
+
outputs = [
|
172
|
+
Output(display_name="API Response", name="data", method="make_api_request"),
|
173
|
+
]
|
174
|
+
|
175
|
+
def _parse_json_value(self, value: Any) -> Any:
|
176
|
+
"""Parse a value that might be a JSON string."""
|
177
|
+
if not isinstance(value, str):
|
178
|
+
return value
|
179
|
+
|
180
|
+
try:
|
181
|
+
parsed = json.loads(value)
|
182
|
+
except json.JSONDecodeError:
|
183
|
+
return value
|
184
|
+
else:
|
185
|
+
return parsed
|
186
|
+
|
187
|
+
def _process_body(self, body: Any) -> dict:
|
188
|
+
"""Process the body input into a valid dictionary."""
|
189
|
+
if body is None:
|
190
|
+
return {}
|
191
|
+
if isinstance(body, dict):
|
192
|
+
return self._process_dict_body(body)
|
193
|
+
if isinstance(body, str):
|
194
|
+
return self._process_string_body(body)
|
195
|
+
if isinstance(body, list):
|
196
|
+
return self._process_list_body(body)
|
197
|
+
return {}
|
198
|
+
|
199
|
+
def _process_dict_body(self, body: dict) -> dict:
|
200
|
+
"""Process dictionary body by parsing JSON values."""
|
201
|
+
return {k: self._parse_json_value(v) for k, v in body.items()}
|
202
|
+
|
203
|
+
def _process_string_body(self, body: str) -> dict:
|
204
|
+
"""Process string body by attempting JSON parse."""
|
205
|
+
try:
|
206
|
+
return self._process_body(json.loads(body))
|
207
|
+
except json.JSONDecodeError:
|
208
|
+
return {"data": body}
|
209
|
+
|
210
|
+
def _process_list_body(self, body: list) -> dict:
|
211
|
+
"""Process list body by converting to key-value dictionary."""
|
212
|
+
processed_dict = {}
|
213
|
+
try:
|
214
|
+
for item in body:
|
215
|
+
if not self._is_valid_key_value_item(item):
|
216
|
+
continue
|
217
|
+
key = item["key"]
|
218
|
+
value = self._parse_json_value(item["value"])
|
219
|
+
processed_dict[key] = value
|
220
|
+
except (KeyError, TypeError, ValueError) as e:
|
221
|
+
self.log(f"Failed to process body list: {e}")
|
222
|
+
return {}
|
223
|
+
return processed_dict
|
224
|
+
|
225
|
+
def _is_valid_key_value_item(self, item: Any) -> bool:
|
226
|
+
"""Check if an item is a valid key-value dictionary."""
|
227
|
+
return isinstance(item, dict) and "key" in item and "value" in item
|
228
|
+
|
229
|
+
def parse_curl(self, curl: str, build_config: dotdict) -> dotdict:
|
230
|
+
"""Parse a cURL command and update build configuration."""
|
231
|
+
try:
|
232
|
+
parsed = parse_context(curl)
|
233
|
+
|
234
|
+
# Update basic configuration
|
235
|
+
url = parsed.url
|
236
|
+
# Normalize URL before setting it
|
237
|
+
url = self._normalize_url(url)
|
238
|
+
|
239
|
+
build_config["url_input"]["value"] = url
|
240
|
+
build_config["method"]["value"] = parsed.method.upper()
|
241
|
+
|
242
|
+
# Process headers
|
243
|
+
headers_list = [{"key": k, "value": v} for k, v in parsed.headers.items()]
|
244
|
+
build_config["headers"]["value"] = headers_list
|
245
|
+
|
246
|
+
# Process body data
|
247
|
+
if not parsed.data:
|
248
|
+
build_config["body"]["value"] = []
|
249
|
+
elif parsed.data:
|
250
|
+
try:
|
251
|
+
json_data = json.loads(parsed.data)
|
252
|
+
if isinstance(json_data, dict):
|
253
|
+
body_list = [
|
254
|
+
{"key": k, "value": json.dumps(v) if isinstance(v, dict | list) else str(v)}
|
255
|
+
for k, v in json_data.items()
|
256
|
+
]
|
257
|
+
build_config["body"]["value"] = body_list
|
258
|
+
else:
|
259
|
+
build_config["body"]["value"] = [{"key": "data", "value": json.dumps(json_data)}]
|
260
|
+
except json.JSONDecodeError:
|
261
|
+
build_config["body"]["value"] = [{"key": "data", "value": parsed.data}]
|
262
|
+
|
263
|
+
except Exception as exc:
|
264
|
+
msg = f"Error parsing curl: {exc}"
|
265
|
+
self.log(msg)
|
266
|
+
raise ValueError(msg) from exc
|
267
|
+
|
268
|
+
return build_config
|
269
|
+
|
270
|
+
def _normalize_url(self, url: str) -> str:
|
271
|
+
"""Normalize URL by adding https:// if no protocol is specified."""
|
272
|
+
if not url or not isinstance(url, str):
|
273
|
+
msg = "URL cannot be empty"
|
274
|
+
raise ValueError(msg)
|
275
|
+
|
276
|
+
url = url.strip()
|
277
|
+
if url.startswith(("http://", "https://")):
|
278
|
+
return url
|
279
|
+
return f"https://{url}"
|
280
|
+
|
281
|
+
async def make_request(
|
282
|
+
self,
|
283
|
+
client: httpx.AsyncClient,
|
284
|
+
method: str,
|
285
|
+
url: str,
|
286
|
+
headers: dict | None = None,
|
287
|
+
body: Any = None,
|
288
|
+
timeout: int = 5,
|
289
|
+
*,
|
290
|
+
follow_redirects: bool = True,
|
291
|
+
save_to_file: bool = False,
|
292
|
+
include_httpx_metadata: bool = False,
|
293
|
+
) -> Data:
|
294
|
+
method = method.upper()
|
295
|
+
if method not in {"GET", "POST", "PATCH", "PUT", "DELETE"}:
|
296
|
+
msg = f"Unsupported method: {method}"
|
297
|
+
raise ValueError(msg)
|
298
|
+
|
299
|
+
processed_body = self._process_body(body)
|
300
|
+
redirection_history = []
|
301
|
+
|
302
|
+
try:
|
303
|
+
# Prepare request parameters
|
304
|
+
request_params = {
|
305
|
+
"method": method,
|
306
|
+
"url": url,
|
307
|
+
"headers": headers,
|
308
|
+
"json": processed_body,
|
309
|
+
"timeout": timeout,
|
310
|
+
"follow_redirects": follow_redirects,
|
311
|
+
}
|
312
|
+
response = await client.request(**request_params)
|
313
|
+
|
314
|
+
redirection_history = [
|
315
|
+
{
|
316
|
+
"url": redirect.headers.get("Location", str(redirect.url)),
|
317
|
+
"status_code": redirect.status_code,
|
318
|
+
}
|
319
|
+
for redirect in response.history
|
320
|
+
]
|
321
|
+
|
322
|
+
is_binary, file_path = await self._response_info(response, with_file_path=save_to_file)
|
323
|
+
response_headers = self._headers_to_dict(response.headers)
|
324
|
+
|
325
|
+
# Base metadata
|
326
|
+
metadata = {
|
327
|
+
"source": url,
|
328
|
+
"status_code": response.status_code,
|
329
|
+
"response_headers": response_headers,
|
330
|
+
}
|
331
|
+
|
332
|
+
if redirection_history:
|
333
|
+
metadata["redirection_history"] = redirection_history
|
334
|
+
|
335
|
+
if save_to_file:
|
336
|
+
mode = "wb" if is_binary else "w"
|
337
|
+
encoding = response.encoding if mode == "w" else None
|
338
|
+
if file_path:
|
339
|
+
await aiofiles_os.makedirs(file_path.parent, exist_ok=True)
|
340
|
+
if is_binary:
|
341
|
+
async with aiofiles.open(file_path, "wb") as f:
|
342
|
+
await f.write(response.content)
|
343
|
+
await f.flush()
|
344
|
+
else:
|
345
|
+
async with aiofiles.open(file_path, "w", encoding=encoding) as f:
|
346
|
+
await f.write(response.text)
|
347
|
+
await f.flush()
|
348
|
+
metadata["file_path"] = str(file_path)
|
349
|
+
|
350
|
+
if include_httpx_metadata:
|
351
|
+
metadata.update({"headers": headers})
|
352
|
+
return Data(data=metadata)
|
353
|
+
|
354
|
+
# Handle response content
|
355
|
+
if is_binary:
|
356
|
+
result = response.content
|
357
|
+
else:
|
358
|
+
try:
|
359
|
+
result = response.json()
|
360
|
+
except json.JSONDecodeError:
|
361
|
+
self.log("Failed to decode JSON response")
|
362
|
+
result = response.text.encode("utf-8")
|
363
|
+
|
364
|
+
metadata["result"] = result
|
365
|
+
|
366
|
+
if include_httpx_metadata:
|
367
|
+
metadata.update({"headers": headers})
|
368
|
+
|
369
|
+
return Data(data=metadata)
|
370
|
+
except (httpx.HTTPError, httpx.RequestError, httpx.TimeoutException) as exc:
|
371
|
+
self.log(f"Error making request to {url}")
|
372
|
+
return Data(
|
373
|
+
data={
|
374
|
+
"source": url,
|
375
|
+
"headers": headers,
|
376
|
+
"status_code": 500,
|
377
|
+
"error": str(exc),
|
378
|
+
**({"redirection_history": redirection_history} if redirection_history else {}),
|
379
|
+
},
|
380
|
+
)
|
381
|
+
|
382
|
+
def add_query_params(self, url: str, params: dict) -> str:
|
383
|
+
"""Add query parameters to URL efficiently."""
|
384
|
+
if not params:
|
385
|
+
return url
|
386
|
+
url_parts = list(urlparse(url))
|
387
|
+
query = dict(parse_qsl(url_parts[4]))
|
388
|
+
query.update(params)
|
389
|
+
url_parts[4] = urlencode(query)
|
390
|
+
return urlunparse(url_parts)
|
391
|
+
|
392
|
+
def _headers_to_dict(self, headers: httpx.Headers) -> dict[str, str]:
|
393
|
+
"""Convert HTTP headers to a dictionary with lowercased keys."""
|
394
|
+
return {k.lower(): v for k, v in headers.items()}
|
395
|
+
|
396
|
+
def _process_headers(self, headers: Any) -> dict:
|
397
|
+
"""Process the headers input into a valid dictionary."""
|
398
|
+
if headers is None:
|
399
|
+
return {}
|
400
|
+
if isinstance(headers, dict):
|
401
|
+
return headers
|
402
|
+
if isinstance(headers, list):
|
403
|
+
return {item["key"]: item["value"] for item in headers if self._is_valid_key_value_item(item)}
|
404
|
+
return {}
|
405
|
+
|
406
|
+
async def make_api_request(self) -> Data:
|
407
|
+
"""Make HTTP request with optimized parameter handling."""
|
408
|
+
method = self.method
|
409
|
+
url = self.url_input.strip() if isinstance(self.url_input, str) else ""
|
410
|
+
headers = self.headers or {}
|
411
|
+
body = self.body or {}
|
412
|
+
timeout = self.timeout
|
413
|
+
follow_redirects = self.follow_redirects
|
414
|
+
save_to_file = self.save_to_file
|
415
|
+
include_httpx_metadata = self.include_httpx_metadata
|
416
|
+
|
417
|
+
# if self.mode == "cURL" and self.curl_input:
|
418
|
+
# self._build_config = self.parse_curl(self.curl_input, dotdict())
|
419
|
+
# # After parsing curl, get the normalized URL
|
420
|
+
# url = self._build_config["url_input"]["value"]
|
421
|
+
|
422
|
+
# Normalize URL before validation
|
423
|
+
url = self._normalize_url(url)
|
424
|
+
|
425
|
+
# Validate URL
|
426
|
+
if not validators.url(url):
|
427
|
+
msg = f"Invalid URL provided: {url}"
|
428
|
+
raise ValueError(msg)
|
429
|
+
|
430
|
+
# Process query parameters
|
431
|
+
if isinstance(self.query_params, str):
|
432
|
+
query_params = dict(parse_qsl(self.query_params))
|
433
|
+
else:
|
434
|
+
query_params = self.query_params.data if self.query_params else {}
|
435
|
+
|
436
|
+
# Process headers and body
|
437
|
+
headers = self._process_headers(headers)
|
438
|
+
body = self._process_body(body)
|
439
|
+
url = self.add_query_params(url, query_params)
|
440
|
+
|
441
|
+
async with httpx.AsyncClient() as client:
|
442
|
+
result = await self.make_request(
|
443
|
+
client,
|
444
|
+
method,
|
445
|
+
url,
|
446
|
+
headers,
|
447
|
+
body,
|
448
|
+
timeout,
|
449
|
+
follow_redirects=follow_redirects,
|
450
|
+
save_to_file=save_to_file,
|
451
|
+
include_httpx_metadata=include_httpx_metadata,
|
452
|
+
)
|
453
|
+
self.status = result
|
454
|
+
return result
|
455
|
+
|
456
|
+
def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None) -> dotdict:
|
457
|
+
"""Update the build config based on the selected mode."""
|
458
|
+
if field_name != "mode":
|
459
|
+
if field_name == "curl_input" and self.mode == "cURL" and self.curl_input:
|
460
|
+
return self.parse_curl(self.curl_input, build_config)
|
461
|
+
return build_config
|
462
|
+
|
463
|
+
# print(f"Current mode: {field_value}")
|
464
|
+
if field_value == "cURL":
|
465
|
+
set_field_display(build_config, "curl_input", value=True)
|
466
|
+
if build_config["curl_input"]["value"]:
|
467
|
+
build_config = self.parse_curl(build_config["curl_input"]["value"], build_config)
|
468
|
+
else:
|
469
|
+
set_field_display(build_config, "curl_input", value=False)
|
470
|
+
|
471
|
+
return set_current_fields(
|
472
|
+
build_config=build_config,
|
473
|
+
action_fields=MODE_FIELDS,
|
474
|
+
selected_action=field_value,
|
475
|
+
default_fields=DEFAULT_FIELDS,
|
476
|
+
func=set_field_advanced,
|
477
|
+
default_value=True,
|
478
|
+
)
|
479
|
+
|
480
|
+
async def _response_info(
|
481
|
+
self, response: httpx.Response, *, with_file_path: bool = False
|
482
|
+
) -> tuple[bool, Path | None]:
|
483
|
+
"""Determine the file path and whether the response content is binary.
|
484
|
+
|
485
|
+
Args:
|
486
|
+
response (Response): The HTTP response object.
|
487
|
+
with_file_path (bool): Whether to save the response content to a file.
|
488
|
+
|
489
|
+
Returns:
|
490
|
+
Tuple[bool, Path | None]:
|
491
|
+
A tuple containing a boolean indicating if the content is binary and the full file path (if applicable).
|
492
|
+
"""
|
493
|
+
content_type = response.headers.get("Content-Type", "")
|
494
|
+
is_binary = "application/octet-stream" in content_type or "application/binary" in content_type
|
495
|
+
|
496
|
+
if not with_file_path:
|
497
|
+
return is_binary, None
|
498
|
+
|
499
|
+
component_temp_dir = Path(tempfile.gettempdir()) / self.__class__.__name__
|
500
|
+
|
501
|
+
# Create directory asynchronously
|
502
|
+
await aiofiles_os.makedirs(component_temp_dir, exist_ok=True)
|
503
|
+
|
504
|
+
filename = None
|
505
|
+
if "Content-Disposition" in response.headers:
|
506
|
+
content_disposition = response.headers["Content-Disposition"]
|
507
|
+
filename_match = re.search(r'filename="(.+?)"', content_disposition)
|
508
|
+
if filename_match:
|
509
|
+
extracted_filename = filename_match.group(1)
|
510
|
+
filename = extracted_filename
|
511
|
+
|
512
|
+
# Step 3: Infer file extension or use part of the request URL if no filename
|
513
|
+
if not filename:
|
514
|
+
# Extract the last segment of the URL path
|
515
|
+
url_path = urlparse(str(response.request.url) if response.request else "").path
|
516
|
+
base_name = Path(url_path).name # Get the last segment of the path
|
517
|
+
if not base_name: # If the path ends with a slash or is empty
|
518
|
+
base_name = "response"
|
519
|
+
|
520
|
+
# Infer file extension
|
521
|
+
content_type_to_extension = {
|
522
|
+
"text/plain": ".txt",
|
523
|
+
"application/json": ".json",
|
524
|
+
"image/jpeg": ".jpg",
|
525
|
+
"image/png": ".png",
|
526
|
+
"application/octet-stream": ".bin",
|
527
|
+
}
|
528
|
+
extension = content_type_to_extension.get(content_type, ".bin" if is_binary else ".txt")
|
529
|
+
filename = f"{base_name}{extension}"
|
530
|
+
|
531
|
+
# Step 4: Define the full file path
|
532
|
+
file_path = component_temp_dir / filename
|
533
|
+
|
534
|
+
# Step 5: Check if file exists asynchronously and handle accordingly
|
535
|
+
try:
|
536
|
+
# Try to create the file exclusively (x mode) to check existence
|
537
|
+
async with aiofiles.open(file_path, "x") as _:
|
538
|
+
pass # File created successfully, we can use this path
|
539
|
+
except FileExistsError:
|
540
|
+
# If file exists, append a timestamp to the filename
|
541
|
+
timestamp = datetime.now(timezone.utc).strftime("%Y%m%d%H%M%S%f")
|
542
|
+
file_path = component_temp_dir / f"{timestamp}-{filename}"
|
543
|
+
|
544
|
+
return is_binary, file_path
|
@@ -0,0 +1,95 @@
|
|
1
|
+
import csv
|
2
|
+
import io
|
3
|
+
from pathlib import Path
|
4
|
+
|
5
|
+
from lfx.custom.custom_component.component import Component
|
6
|
+
from lfx.io import FileInput, MessageTextInput, MultilineInput, Output
|
7
|
+
from lfx.schema.data import Data
|
8
|
+
|
9
|
+
|
10
|
+
class CSVToDataComponent(Component):
|
11
|
+
display_name = "Load CSV"
|
12
|
+
description = "Load a CSV file, CSV from a file path, or a valid CSV string and convert it to a list of Data"
|
13
|
+
icon = "file-spreadsheet"
|
14
|
+
name = "CSVtoData"
|
15
|
+
legacy = True
|
16
|
+
|
17
|
+
inputs = [
|
18
|
+
FileInput(
|
19
|
+
name="csv_file",
|
20
|
+
display_name="CSV File",
|
21
|
+
file_types=["csv"],
|
22
|
+
info="Upload a CSV file to convert to a list of Data objects",
|
23
|
+
),
|
24
|
+
MessageTextInput(
|
25
|
+
name="csv_path",
|
26
|
+
display_name="CSV File Path",
|
27
|
+
info="Provide the path to the CSV file as pure text",
|
28
|
+
),
|
29
|
+
MultilineInput(
|
30
|
+
name="csv_string",
|
31
|
+
display_name="CSV String",
|
32
|
+
info="Paste a CSV string directly to convert to a list of Data objects",
|
33
|
+
),
|
34
|
+
MessageTextInput(
|
35
|
+
name="text_key",
|
36
|
+
display_name="Text Key",
|
37
|
+
info="The key to use for the text column. Defaults to 'text'.",
|
38
|
+
value="text",
|
39
|
+
),
|
40
|
+
]
|
41
|
+
|
42
|
+
outputs = [
|
43
|
+
Output(name="data_list", display_name="Data List", method="load_csv_to_data"),
|
44
|
+
]
|
45
|
+
|
46
|
+
def load_csv_to_data(self) -> list[Data]:
|
47
|
+
if sum(bool(field) for field in [self.csv_file, self.csv_path, self.csv_string]) != 1:
|
48
|
+
msg = "Please provide exactly one of: CSV file, file path, or CSV string."
|
49
|
+
raise ValueError(msg)
|
50
|
+
|
51
|
+
csv_data = None
|
52
|
+
try:
|
53
|
+
if self.csv_file:
|
54
|
+
resolved_path = self.resolve_path(self.csv_file)
|
55
|
+
file_path = Path(resolved_path)
|
56
|
+
if file_path.suffix.lower() != ".csv":
|
57
|
+
self.status = "The provided file must be a CSV file."
|
58
|
+
else:
|
59
|
+
with file_path.open(newline="", encoding="utf-8") as csvfile:
|
60
|
+
csv_data = csvfile.read()
|
61
|
+
|
62
|
+
elif self.csv_path:
|
63
|
+
file_path = Path(self.csv_path)
|
64
|
+
if file_path.suffix.lower() != ".csv":
|
65
|
+
self.status = "The provided file must be a CSV file."
|
66
|
+
else:
|
67
|
+
with file_path.open(newline="", encoding="utf-8") as csvfile:
|
68
|
+
csv_data = csvfile.read()
|
69
|
+
|
70
|
+
else:
|
71
|
+
csv_data = self.csv_string
|
72
|
+
|
73
|
+
if csv_data:
|
74
|
+
csv_reader = csv.DictReader(io.StringIO(csv_data))
|
75
|
+
result = [Data(data=row, text_key=self.text_key) for row in csv_reader]
|
76
|
+
|
77
|
+
if not result:
|
78
|
+
self.status = "The CSV data is empty."
|
79
|
+
return []
|
80
|
+
|
81
|
+
self.status = result
|
82
|
+
return result
|
83
|
+
|
84
|
+
except csv.Error as e:
|
85
|
+
error_message = f"CSV parsing error: {e}"
|
86
|
+
self.status = error_message
|
87
|
+
raise ValueError(error_message) from e
|
88
|
+
|
89
|
+
except Exception as e:
|
90
|
+
error_message = f"An error occurred: {e}"
|
91
|
+
self.status = error_message
|
92
|
+
raise ValueError(error_message) from e
|
93
|
+
|
94
|
+
# An error occurred
|
95
|
+
raise ValueError(self.status)
|