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,408 @@
|
|
1
|
+
import json
|
2
|
+
import subprocess
|
3
|
+
import time
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
from tenacity import retry, stop_after_attempt, wait_exponential
|
8
|
+
from twelvelabs import TwelveLabs
|
9
|
+
|
10
|
+
from lfx.custom import Component
|
11
|
+
from lfx.field_typing.range_spec import RangeSpec
|
12
|
+
from lfx.inputs import DataInput, DropdownInput, MessageInput, MultilineInput, SecretStrInput, SliderInput
|
13
|
+
from lfx.io import Output
|
14
|
+
from lfx.schema.message import Message
|
15
|
+
|
16
|
+
|
17
|
+
class TaskError(Exception):
|
18
|
+
"""Error raised when a task fails."""
|
19
|
+
|
20
|
+
|
21
|
+
class TaskTimeoutError(Exception):
|
22
|
+
"""Error raised when a task times out."""
|
23
|
+
|
24
|
+
|
25
|
+
class IndexCreationError(Exception):
|
26
|
+
"""Error raised when there's an issue with an index."""
|
27
|
+
|
28
|
+
|
29
|
+
class ApiRequestError(Exception):
|
30
|
+
"""Error raised when an API request fails."""
|
31
|
+
|
32
|
+
|
33
|
+
class VideoValidationError(Exception):
|
34
|
+
"""Error raised when video validation fails."""
|
35
|
+
|
36
|
+
|
37
|
+
class TwelveLabsPegasus(Component):
|
38
|
+
display_name = "TwelveLabs Pegasus"
|
39
|
+
description = "Chat with videos using TwelveLabs Pegasus API."
|
40
|
+
icon = "TwelveLabs"
|
41
|
+
name = "TwelveLabsPegasus"
|
42
|
+
documentation = "https://github.com/twelvelabs-io/twelvelabs-developer-experience/blob/main/integrations/Langflow/TWELVE_LABS_COMPONENTS_README.md"
|
43
|
+
|
44
|
+
inputs = [
|
45
|
+
DataInput(name="videodata", display_name="Video Data", info="Video Data", is_list=True),
|
46
|
+
SecretStrInput(
|
47
|
+
name="api_key", display_name="TwelveLabs API Key", info="Enter your TwelveLabs API Key.", required=True
|
48
|
+
),
|
49
|
+
MessageInput(
|
50
|
+
name="video_id",
|
51
|
+
display_name="Pegasus Video ID",
|
52
|
+
info="Enter a Video ID for a previously indexed video.",
|
53
|
+
),
|
54
|
+
MessageInput(
|
55
|
+
name="index_name",
|
56
|
+
display_name="Index Name",
|
57
|
+
info="Name of the index to use. If the index doesn't exist, it will be created.",
|
58
|
+
required=False,
|
59
|
+
),
|
60
|
+
MessageInput(
|
61
|
+
name="index_id",
|
62
|
+
display_name="Index ID",
|
63
|
+
info="ID of an existing index to use. If provided, index_name will be ignored.",
|
64
|
+
required=False,
|
65
|
+
),
|
66
|
+
DropdownInput(
|
67
|
+
name="model_name",
|
68
|
+
display_name="Model",
|
69
|
+
info="Pegasus model to use for indexing",
|
70
|
+
options=["pegasus1.2"],
|
71
|
+
value="pegasus1.2",
|
72
|
+
advanced=False,
|
73
|
+
),
|
74
|
+
MultilineInput(
|
75
|
+
name="message",
|
76
|
+
display_name="Prompt",
|
77
|
+
info="Message to chat with the video.",
|
78
|
+
required=True,
|
79
|
+
),
|
80
|
+
SliderInput(
|
81
|
+
name="temperature",
|
82
|
+
display_name="Temperature",
|
83
|
+
value=0.7,
|
84
|
+
range_spec=RangeSpec(min=0, max=1, step=0.01),
|
85
|
+
info=(
|
86
|
+
"Controls randomness in responses. Lower values are more deterministic, "
|
87
|
+
"higher values are more creative."
|
88
|
+
),
|
89
|
+
),
|
90
|
+
]
|
91
|
+
|
92
|
+
outputs = [
|
93
|
+
Output(
|
94
|
+
display_name="Message",
|
95
|
+
name="response",
|
96
|
+
method="process_video",
|
97
|
+
type_=Message,
|
98
|
+
),
|
99
|
+
Output(
|
100
|
+
display_name="Video ID",
|
101
|
+
name="processed_video_id",
|
102
|
+
method="get_video_id",
|
103
|
+
type_=Message,
|
104
|
+
),
|
105
|
+
]
|
106
|
+
|
107
|
+
def __init__(self, **kwargs) -> None:
|
108
|
+
super().__init__(**kwargs)
|
109
|
+
|
110
|
+
self._task_id: str | None = None
|
111
|
+
self._video_id: str | None = None
|
112
|
+
self._index_id: str | None = None
|
113
|
+
self._index_name: str | None = None
|
114
|
+
self._message: str | None = None
|
115
|
+
|
116
|
+
def _get_or_create_index(self, client: TwelveLabs) -> tuple[str, str]:
|
117
|
+
"""Get existing index or create new one.
|
118
|
+
|
119
|
+
Returns (index_id, index_name).
|
120
|
+
"""
|
121
|
+
# First check if index_id is provided and valid
|
122
|
+
if hasattr(self, "_index_id") and self._index_id:
|
123
|
+
try:
|
124
|
+
index = client.index.retrieve(id=self._index_id)
|
125
|
+
self.log(f"Found existing index with ID: {self._index_id}")
|
126
|
+
except (ValueError, KeyError) as e:
|
127
|
+
self.log(f"Error retrieving index with ID {self._index_id}: {e!s}", "WARNING")
|
128
|
+
else:
|
129
|
+
return self._index_id, index.name
|
130
|
+
|
131
|
+
# If index_name is provided, try to find it
|
132
|
+
if hasattr(self, "_index_name") and self._index_name:
|
133
|
+
try:
|
134
|
+
# List all indexes and find by name
|
135
|
+
indexes = client.index.list()
|
136
|
+
for idx in indexes:
|
137
|
+
if idx.name == self._index_name:
|
138
|
+
self.log(f"Found existing index: {self._index_name} (ID: {idx.id})")
|
139
|
+
return idx.id, idx.name
|
140
|
+
|
141
|
+
# If we get here, index wasn't found - create it
|
142
|
+
self.log(f"Creating new index: {self._index_name}")
|
143
|
+
index = client.index.create(
|
144
|
+
name=self._index_name,
|
145
|
+
models=[
|
146
|
+
{
|
147
|
+
"name": self.model_name if hasattr(self, "model_name") else "pegasus1.2",
|
148
|
+
"options": ["visual", "audio"],
|
149
|
+
}
|
150
|
+
],
|
151
|
+
)
|
152
|
+
except (ValueError, KeyError) as e:
|
153
|
+
self.log(f"Error with index name {self._index_name}: {e!s}", "ERROR")
|
154
|
+
error_message = f"Error with index name {self._index_name}"
|
155
|
+
raise IndexCreationError(error_message) from e
|
156
|
+
else:
|
157
|
+
return index.id, index.name
|
158
|
+
|
159
|
+
# If neither is provided, create a new index with timestamp
|
160
|
+
try:
|
161
|
+
index_name = f"index_{int(time.time())}"
|
162
|
+
self.log(f"Creating new index: {index_name}")
|
163
|
+
index = client.index.create(
|
164
|
+
name=index_name,
|
165
|
+
models=[
|
166
|
+
{
|
167
|
+
"name": self.model_name if hasattr(self, "model_name") else "pegasus1.2",
|
168
|
+
"options": ["visual", "audio"],
|
169
|
+
}
|
170
|
+
],
|
171
|
+
)
|
172
|
+
except (ValueError, KeyError) as e:
|
173
|
+
self.log(f"Failed to create new index: {e!s}", "ERROR")
|
174
|
+
error_message = "Failed to create new index"
|
175
|
+
raise IndexCreationError(error_message) from e
|
176
|
+
else:
|
177
|
+
return index.id, index.name
|
178
|
+
|
179
|
+
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10), reraise=True)
|
180
|
+
async def _make_api_request(self, method: Any, *args: Any, **kwargs: Any) -> Any:
|
181
|
+
"""Make API request with retry logic.
|
182
|
+
|
183
|
+
Retries failed requests with exponential backoff.
|
184
|
+
"""
|
185
|
+
try:
|
186
|
+
return await method(*args, **kwargs)
|
187
|
+
except (ValueError, KeyError) as e:
|
188
|
+
self.log(f"API request failed: {e!s}", "ERROR")
|
189
|
+
error_message = "API request failed"
|
190
|
+
raise ApiRequestError(error_message) from e
|
191
|
+
|
192
|
+
def wait_for_task_completion(
|
193
|
+
self, client: TwelveLabs, task_id: str, max_retries: int = 120, sleep_time: int = 5
|
194
|
+
) -> Any:
|
195
|
+
"""Wait for task completion with timeout and improved error handling.
|
196
|
+
|
197
|
+
Polls the task status until completion or timeout.
|
198
|
+
"""
|
199
|
+
retries = 0
|
200
|
+
consecutive_errors = 0
|
201
|
+
max_consecutive_errors = 3
|
202
|
+
|
203
|
+
while retries < max_retries:
|
204
|
+
try:
|
205
|
+
self.log(f"Checking task status (attempt {retries + 1})")
|
206
|
+
result = client.task.retrieve(id=task_id)
|
207
|
+
consecutive_errors = 0 # Reset error counter on success
|
208
|
+
|
209
|
+
if result.status == "ready":
|
210
|
+
self.log("Task completed successfully!")
|
211
|
+
return result
|
212
|
+
if result.status == "failed":
|
213
|
+
error_msg = f"Task failed with status: {result.status}"
|
214
|
+
self.log(error_msg, "ERROR")
|
215
|
+
raise TaskError(error_msg)
|
216
|
+
if result.status == "error":
|
217
|
+
error_msg = f"Task encountered an error: {getattr(result, 'error', 'Unknown error')}"
|
218
|
+
self.log(error_msg, "ERROR")
|
219
|
+
raise TaskError(error_msg)
|
220
|
+
|
221
|
+
time.sleep(sleep_time)
|
222
|
+
retries += 1
|
223
|
+
status_msg = f"Processing video... {retries * sleep_time}s elapsed"
|
224
|
+
self.status = status_msg
|
225
|
+
self.log(status_msg)
|
226
|
+
|
227
|
+
except (ValueError, KeyError) as e:
|
228
|
+
consecutive_errors += 1
|
229
|
+
error_msg = f"Error checking task status: {e!s}"
|
230
|
+
self.log(error_msg, "WARNING")
|
231
|
+
|
232
|
+
if consecutive_errors >= max_consecutive_errors:
|
233
|
+
too_many_errors = "Too many consecutive errors"
|
234
|
+
raise TaskError(too_many_errors) from e
|
235
|
+
|
236
|
+
time.sleep(sleep_time * 2)
|
237
|
+
continue
|
238
|
+
|
239
|
+
timeout_msg = f"Timeout after {max_retries * sleep_time} seconds"
|
240
|
+
self.log(timeout_msg, "ERROR")
|
241
|
+
raise TaskTimeoutError(timeout_msg)
|
242
|
+
|
243
|
+
def validate_video_file(self, filepath: str) -> tuple[bool, str]:
|
244
|
+
"""Validate video file using ffprobe.
|
245
|
+
|
246
|
+
Returns (is_valid, error_message).
|
247
|
+
"""
|
248
|
+
# Ensure filepath is a string and doesn't contain shell metacharacters
|
249
|
+
if not isinstance(filepath, str) or any(c in filepath for c in ";&|`$(){}[]<>*?!#~"):
|
250
|
+
return False, "Invalid filepath"
|
251
|
+
|
252
|
+
try:
|
253
|
+
cmd = [
|
254
|
+
"ffprobe",
|
255
|
+
"-loglevel",
|
256
|
+
"error",
|
257
|
+
"-show_entries",
|
258
|
+
"stream=codec_type,codec_name",
|
259
|
+
"-of",
|
260
|
+
"default=nw=1",
|
261
|
+
"-print_format",
|
262
|
+
"json",
|
263
|
+
"-show_format",
|
264
|
+
filepath,
|
265
|
+
]
|
266
|
+
|
267
|
+
# Use subprocess with a list of arguments to avoid shell injection
|
268
|
+
# We need to skip the S603 warning here as we're taking proper precautions
|
269
|
+
# with input validation and using shell=False
|
270
|
+
result = subprocess.run( # noqa: S603
|
271
|
+
cmd,
|
272
|
+
capture_output=True,
|
273
|
+
text=True,
|
274
|
+
check=False,
|
275
|
+
shell=False, # Explicitly set shell=False for security
|
276
|
+
)
|
277
|
+
|
278
|
+
if result.returncode != 0:
|
279
|
+
return False, f"FFprobe error: {result.stderr}"
|
280
|
+
|
281
|
+
probe_data = json.loads(result.stdout)
|
282
|
+
|
283
|
+
has_video = any(stream.get("codec_type") == "video" for stream in probe_data.get("streams", []))
|
284
|
+
|
285
|
+
if not has_video:
|
286
|
+
return False, "No video stream found in file"
|
287
|
+
|
288
|
+
self.log(f"Video validation successful: {json.dumps(probe_data, indent=2)}")
|
289
|
+
except subprocess.SubprocessError as e:
|
290
|
+
return False, f"FFprobe process error: {e!s}"
|
291
|
+
except json.JSONDecodeError as e:
|
292
|
+
return False, f"FFprobe output parsing error: {e!s}"
|
293
|
+
except (ValueError, OSError) as e:
|
294
|
+
return False, f"Validation error: {e!s}"
|
295
|
+
else:
|
296
|
+
return True, ""
|
297
|
+
|
298
|
+
def on_task_update(self, task: Any) -> None:
|
299
|
+
"""Callback for task status updates.
|
300
|
+
|
301
|
+
Updates the component status with the current task status.
|
302
|
+
"""
|
303
|
+
self.status = f"Processing video... Status: {task.status}"
|
304
|
+
self.log(self.status)
|
305
|
+
|
306
|
+
def process_video(self) -> Message:
|
307
|
+
"""Process video using Pegasus and generate response if message is provided.
|
308
|
+
|
309
|
+
Handles video indexing and question answering using the TwelveLabs API.
|
310
|
+
"""
|
311
|
+
# Check and initialize inputs
|
312
|
+
if hasattr(self, "index_id") and self.index_id:
|
313
|
+
self._index_id = self.index_id.text if hasattr(self.index_id, "text") else self.index_id
|
314
|
+
|
315
|
+
if hasattr(self, "index_name") and self.index_name:
|
316
|
+
self._index_name = self.index_name.text if hasattr(self.index_name, "text") else self.index_name
|
317
|
+
|
318
|
+
if hasattr(self, "video_id") and self.video_id:
|
319
|
+
self._video_id = self.video_id.text if hasattr(self.video_id, "text") else self.video_id
|
320
|
+
|
321
|
+
if hasattr(self, "message") and self.message:
|
322
|
+
self._message = self.message.text if hasattr(self.message, "text") else self.message
|
323
|
+
|
324
|
+
try:
|
325
|
+
# If we have a message and already processed video, use existing video_id
|
326
|
+
if self._message and self._video_id and self._video_id != "":
|
327
|
+
self.status = f"Have video id: {self._video_id}"
|
328
|
+
|
329
|
+
client = TwelveLabs(api_key=self.api_key)
|
330
|
+
|
331
|
+
self.status = f"Processing query (w/ video ID): {self._video_id} {self._message}"
|
332
|
+
self.log(self.status)
|
333
|
+
|
334
|
+
response = client.generate.text(
|
335
|
+
video_id=self._video_id,
|
336
|
+
prompt=self._message,
|
337
|
+
temperature=self.temperature,
|
338
|
+
)
|
339
|
+
return Message(text=response.data)
|
340
|
+
|
341
|
+
# Otherwise process new video
|
342
|
+
if not self.videodata or not isinstance(self.videodata, list) or len(self.videodata) != 1:
|
343
|
+
return Message(text="Please provide exactly one video")
|
344
|
+
|
345
|
+
video_path = self.videodata[0].data.get("text")
|
346
|
+
if not video_path or not Path(video_path).exists():
|
347
|
+
return Message(text="Invalid video path")
|
348
|
+
|
349
|
+
if not self.api_key:
|
350
|
+
return Message(text="No API key provided")
|
351
|
+
|
352
|
+
client = TwelveLabs(api_key=self.api_key)
|
353
|
+
|
354
|
+
# Get or create index
|
355
|
+
try:
|
356
|
+
index_id, index_name = self._get_or_create_index(client)
|
357
|
+
self.status = f"Using index: {index_name} (ID: {index_id})"
|
358
|
+
self.log(f"Using index: {index_name} (ID: {index_id})")
|
359
|
+
self._index_id = index_id
|
360
|
+
self._index_name = index_name
|
361
|
+
except IndexCreationError as e:
|
362
|
+
return Message(text=f"Failed to get/create index: {e}")
|
363
|
+
|
364
|
+
with Path(video_path).open("rb") as video_file:
|
365
|
+
task = client.task.create(index_id=self._index_id, file=video_file)
|
366
|
+
self._task_id = task.id
|
367
|
+
|
368
|
+
# Wait for processing to complete
|
369
|
+
task.wait_for_done(sleep_interval=5, callback=self.on_task_update)
|
370
|
+
|
371
|
+
if task.status != "ready":
|
372
|
+
return Message(text=f"Processing failed with status {task.status}")
|
373
|
+
|
374
|
+
# Store video_id for future use
|
375
|
+
self._video_id = task.video_id
|
376
|
+
|
377
|
+
# Generate response if message provided
|
378
|
+
if self._message:
|
379
|
+
self.status = f"Processing query: {self._message}"
|
380
|
+
self.log(self.status)
|
381
|
+
|
382
|
+
response = client.generate.text(
|
383
|
+
video_id=self._video_id,
|
384
|
+
prompt=self._message,
|
385
|
+
temperature=self.temperature,
|
386
|
+
)
|
387
|
+
return Message(text=response.data)
|
388
|
+
|
389
|
+
success_msg = (
|
390
|
+
f"Video processed successfully. You can now ask questions about the video. Video ID: {self._video_id}"
|
391
|
+
)
|
392
|
+
return Message(text=success_msg)
|
393
|
+
|
394
|
+
except (ValueError, KeyError, IndexCreationError, TaskError, TaskTimeoutError) as e:
|
395
|
+
self.log(f"Error: {e!s}", "ERROR")
|
396
|
+
# Clear stored IDs on error
|
397
|
+
self._video_id = None
|
398
|
+
self._index_id = None
|
399
|
+
self._task_id = None
|
400
|
+
return Message(text=f"Error: {e!s}")
|
401
|
+
|
402
|
+
def get_video_id(self) -> Message:
|
403
|
+
"""Return the video ID of the processed video as a Message.
|
404
|
+
|
405
|
+
Returns an empty string if no video has been processed.
|
406
|
+
"""
|
407
|
+
video_id = self._video_id or ""
|
408
|
+
return Message(text=video_id)
|
@@ -0,0 +1,100 @@
|
|
1
|
+
import time
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import Any, cast
|
4
|
+
|
5
|
+
from twelvelabs import TwelveLabs
|
6
|
+
|
7
|
+
from lfx.base.embeddings.model import LCEmbeddingsModel
|
8
|
+
from lfx.field_typing import Embeddings
|
9
|
+
from lfx.io import DropdownInput, IntInput, SecretStrInput
|
10
|
+
|
11
|
+
|
12
|
+
class TwelveLabsVideoEmbeddings(Embeddings):
|
13
|
+
def __init__(self, api_key: str, model_name: str = "Marengo-retrieval-2.7") -> None:
|
14
|
+
self.client = TwelveLabs(api_key=api_key)
|
15
|
+
self.model_name = model_name
|
16
|
+
|
17
|
+
def _wait_for_task_completion(self, task_id: str) -> Any:
|
18
|
+
while True:
|
19
|
+
result = self.client.embed.task.retrieve(id=task_id)
|
20
|
+
if result.status == "ready":
|
21
|
+
return result
|
22
|
+
time.sleep(5)
|
23
|
+
|
24
|
+
def embed_documents(self, texts: list[str]) -> list[list[float]]:
|
25
|
+
embeddings: list[list[float]] = []
|
26
|
+
for text in texts:
|
27
|
+
video_path = text.page_content if hasattr(text, "page_content") else str(text)
|
28
|
+
result = self.embed_video(video_path)
|
29
|
+
|
30
|
+
# First try to use video embedding, then fall back to clip embedding if available
|
31
|
+
if result["video_embedding"] is not None:
|
32
|
+
embeddings.append(cast("list[float]", result["video_embedding"]))
|
33
|
+
elif result["clip_embeddings"] and len(result["clip_embeddings"]) > 0:
|
34
|
+
embeddings.append(cast("list[float]", result["clip_embeddings"][0]))
|
35
|
+
else:
|
36
|
+
# If neither is available, raise an error
|
37
|
+
error_msg = "No embeddings were generated for the video"
|
38
|
+
raise ValueError(error_msg)
|
39
|
+
|
40
|
+
return embeddings
|
41
|
+
|
42
|
+
def embed_query(self, text: str) -> list[float]:
|
43
|
+
video_path = text.page_content if hasattr(text, "page_content") else str(text)
|
44
|
+
result = self.embed_video(video_path)
|
45
|
+
|
46
|
+
# First try to use video embedding, then fall back to clip embedding if available
|
47
|
+
if result["video_embedding"] is not None:
|
48
|
+
return cast("list[float]", result["video_embedding"])
|
49
|
+
if result["clip_embeddings"] and len(result["clip_embeddings"]) > 0:
|
50
|
+
return cast("list[float]", result["clip_embeddings"][0])
|
51
|
+
# If neither is available, raise an error
|
52
|
+
error_msg = "No embeddings were generated for the video"
|
53
|
+
raise ValueError(error_msg)
|
54
|
+
|
55
|
+
def embed_video(self, video_path: str) -> dict[str, list[float] | list[list[float]]]:
|
56
|
+
file_path = Path(video_path)
|
57
|
+
with file_path.open("rb") as video_file:
|
58
|
+
task = self.client.embed.task.create(
|
59
|
+
model_name=self.model_name,
|
60
|
+
video_file=video_file,
|
61
|
+
video_embedding_scopes=["video", "clip"],
|
62
|
+
)
|
63
|
+
|
64
|
+
result = self._wait_for_task_completion(task.id)
|
65
|
+
|
66
|
+
video_embedding: dict[str, list[float] | list[list[float]]] = {
|
67
|
+
"video_embedding": [], # Initialize as empty list instead of None
|
68
|
+
"clip_embeddings": [],
|
69
|
+
}
|
70
|
+
|
71
|
+
if hasattr(result.video_embedding, "segments") and result.video_embedding.segments:
|
72
|
+
for seg in result.video_embedding.segments:
|
73
|
+
# Check for embeddings_float attribute (this is the correct attribute name)
|
74
|
+
if hasattr(seg, "embeddings_float") and seg.embedding_scope == "video":
|
75
|
+
# Convert to list of floats
|
76
|
+
video_embedding["video_embedding"] = [float(x) for x in seg.embeddings_float]
|
77
|
+
|
78
|
+
return video_embedding
|
79
|
+
|
80
|
+
|
81
|
+
class TwelveLabsVideoEmbeddingsComponent(LCEmbeddingsModel):
|
82
|
+
display_name = "TwelveLabs Video Embeddings"
|
83
|
+
description = "Generate embeddings from videos using TwelveLabs video embedding models."
|
84
|
+
name = "TwelveLabsVideoEmbeddings"
|
85
|
+
icon = "TwelveLabs"
|
86
|
+
documentation = "https://github.com/twelvelabs-io/twelvelabs-developer-experience/blob/main/integrations/Langflow/TWELVE_LABS_COMPONENTS_README.md"
|
87
|
+
inputs = [
|
88
|
+
SecretStrInput(name="api_key", display_name="API Key", required=True),
|
89
|
+
DropdownInput(
|
90
|
+
name="model_name",
|
91
|
+
display_name="Model",
|
92
|
+
advanced=False,
|
93
|
+
options=["Marengo-retrieval-2.7"],
|
94
|
+
value="Marengo-retrieval-2.7",
|
95
|
+
),
|
96
|
+
IntInput(name="request_timeout", display_name="Request Timeout", advanced=True),
|
97
|
+
]
|
98
|
+
|
99
|
+
def build_embeddings(self) -> Embeddings:
|
100
|
+
return TwelveLabsVideoEmbeddings(api_key=self.api_key, model_name=self.model_name)
|
@@ -0,0 +1,179 @@
|
|
1
|
+
from pathlib import Path
|
2
|
+
|
3
|
+
from lfx.base.data import BaseFileComponent
|
4
|
+
from lfx.io import FileInput
|
5
|
+
from lfx.schema import Data, DataFrame
|
6
|
+
|
7
|
+
|
8
|
+
class VideoFileComponent(BaseFileComponent):
|
9
|
+
"""Handles loading and processing of video files.
|
10
|
+
|
11
|
+
This component supports processing video files in common video formats.
|
12
|
+
"""
|
13
|
+
|
14
|
+
display_name = "Video File"
|
15
|
+
description = "Load a video file in common video formats."
|
16
|
+
icon = "TwelveLabs"
|
17
|
+
name = "VideoFile"
|
18
|
+
documentation = "https://github.com/twelvelabs-io/twelvelabs-developer-experience/blob/main/integrations/Langflow/TWELVE_LABS_COMPONENTS_README.md"
|
19
|
+
|
20
|
+
VALID_EXTENSIONS = [
|
21
|
+
# Common video formats
|
22
|
+
"mp4",
|
23
|
+
"avi",
|
24
|
+
"mov",
|
25
|
+
"mkv",
|
26
|
+
"webm",
|
27
|
+
"flv",
|
28
|
+
"wmv",
|
29
|
+
"mpg",
|
30
|
+
"mpeg",
|
31
|
+
"m4v",
|
32
|
+
"3gp",
|
33
|
+
"3g2",
|
34
|
+
"m2v",
|
35
|
+
# Professional video formats
|
36
|
+
"mxf",
|
37
|
+
"dv",
|
38
|
+
"vob",
|
39
|
+
# Additional video formats
|
40
|
+
"ogv",
|
41
|
+
"rm",
|
42
|
+
"rmvb",
|
43
|
+
"amv",
|
44
|
+
"divx",
|
45
|
+
"m2ts",
|
46
|
+
"mts",
|
47
|
+
"ts",
|
48
|
+
"qt",
|
49
|
+
"yuv",
|
50
|
+
"y4m",
|
51
|
+
]
|
52
|
+
|
53
|
+
inputs = [
|
54
|
+
FileInput(
|
55
|
+
display_name="Video File",
|
56
|
+
name="file_path",
|
57
|
+
file_types=[
|
58
|
+
# Common video formats
|
59
|
+
"mp4",
|
60
|
+
"avi",
|
61
|
+
"mov",
|
62
|
+
"mkv",
|
63
|
+
"webm",
|
64
|
+
"flv",
|
65
|
+
"wmv",
|
66
|
+
"mpg",
|
67
|
+
"mpeg",
|
68
|
+
"m4v",
|
69
|
+
"3gp",
|
70
|
+
"3g2",
|
71
|
+
"m2v",
|
72
|
+
# Professional video formats
|
73
|
+
"mxf",
|
74
|
+
"dv",
|
75
|
+
"vob",
|
76
|
+
# Additional video formats
|
77
|
+
"ogv",
|
78
|
+
"rm",
|
79
|
+
"rmvb",
|
80
|
+
"amv",
|
81
|
+
"divx",
|
82
|
+
"m2ts",
|
83
|
+
"mts",
|
84
|
+
"ts",
|
85
|
+
"qt",
|
86
|
+
"yuv",
|
87
|
+
"y4m",
|
88
|
+
],
|
89
|
+
required=True,
|
90
|
+
info="Upload a video file in any common video format supported by ffmpeg",
|
91
|
+
),
|
92
|
+
]
|
93
|
+
|
94
|
+
outputs = [
|
95
|
+
*BaseFileComponent.get_base_outputs(),
|
96
|
+
]
|
97
|
+
|
98
|
+
def process_files(self, file_list: list[BaseFileComponent.BaseFile]) -> list[BaseFileComponent.BaseFile]:
|
99
|
+
"""Process video files."""
|
100
|
+
self.log(f"DEBUG: Processing video files: {len(file_list)}")
|
101
|
+
|
102
|
+
if not file_list:
|
103
|
+
msg = "No files to process."
|
104
|
+
raise ValueError(msg)
|
105
|
+
|
106
|
+
processed_files = []
|
107
|
+
for file in file_list:
|
108
|
+
try:
|
109
|
+
file_path = str(file.path)
|
110
|
+
self.log(f"DEBUG: Processing video file: {file_path}")
|
111
|
+
|
112
|
+
# Verify file exists
|
113
|
+
file_path_obj = Path(file_path)
|
114
|
+
if not file_path_obj.exists():
|
115
|
+
error_msg = f"Video file not found: {file_path}"
|
116
|
+
raise FileNotFoundError(error_msg)
|
117
|
+
|
118
|
+
# Verify extension
|
119
|
+
if not file_path.lower().endswith(tuple(self.VALID_EXTENSIONS)):
|
120
|
+
error_msg = f"Invalid file type. Expected: {', '.join(self.VALID_EXTENSIONS)}"
|
121
|
+
raise ValueError(error_msg)
|
122
|
+
|
123
|
+
# Create a dictionary instead of a Document
|
124
|
+
doc_data = {"text": file_path, "metadata": {"source": file_path, "type": "video"}}
|
125
|
+
|
126
|
+
# Pass the dictionary to Data
|
127
|
+
file.data = Data(data=doc_data)
|
128
|
+
|
129
|
+
self.log(f"DEBUG: Created data: {doc_data}")
|
130
|
+
processed_files.append(file)
|
131
|
+
|
132
|
+
except Exception as e:
|
133
|
+
self.log(f"Error processing video file: {e!s}", "ERROR")
|
134
|
+
raise
|
135
|
+
|
136
|
+
return processed_files
|
137
|
+
|
138
|
+
def load_files(self) -> DataFrame:
|
139
|
+
"""Load video files and return a list of Data objects."""
|
140
|
+
try:
|
141
|
+
self.log("DEBUG: Starting video file load")
|
142
|
+
if not hasattr(self, "file_path") or not self.file_path:
|
143
|
+
self.log("DEBUG: No video file path provided")
|
144
|
+
return DataFrame()
|
145
|
+
|
146
|
+
self.log(f"DEBUG: Loading video from path: {self.file_path}")
|
147
|
+
|
148
|
+
# Verify file exists
|
149
|
+
file_path_obj = Path(self.file_path)
|
150
|
+
if not file_path_obj.exists():
|
151
|
+
self.log(f"DEBUG: Video file not found at path: {self.file_path}")
|
152
|
+
return DataFrame()
|
153
|
+
|
154
|
+
# Verify file size
|
155
|
+
file_size = file_path_obj.stat().st_size
|
156
|
+
self.log(f"DEBUG: Video file size: {file_size} bytes")
|
157
|
+
|
158
|
+
# Create a proper Data object with the video path
|
159
|
+
video_data = {
|
160
|
+
"text": self.file_path,
|
161
|
+
"metadata": {"source": self.file_path, "type": "video", "size": file_size},
|
162
|
+
}
|
163
|
+
|
164
|
+
self.log(f"DEBUG: Created video data: {video_data}")
|
165
|
+
result = DataFrame(data=[video_data])
|
166
|
+
|
167
|
+
# Log the result to verify it's a proper Data object
|
168
|
+
self.log("DEBUG: Returning list with Data objects")
|
169
|
+
except (FileNotFoundError, PermissionError, OSError) as e:
|
170
|
+
self.log(f"DEBUG: File error in video load_files: {e!s}", "ERROR")
|
171
|
+
return DataFrame()
|
172
|
+
except ImportError as e:
|
173
|
+
self.log(f"DEBUG: Import error in video load_files: {e!s}", "ERROR")
|
174
|
+
return DataFrame()
|
175
|
+
except (ValueError, TypeError) as e:
|
176
|
+
self.log(f"DEBUG: Value or type error in video load_files: {e!s}", "ERROR")
|
177
|
+
return DataFrame()
|
178
|
+
else:
|
179
|
+
return result
|