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,196 @@
|
|
1
|
+
import os
|
2
|
+
import shutil
|
3
|
+
import tempfile
|
4
|
+
from contextlib import asynccontextmanager
|
5
|
+
from pathlib import Path
|
6
|
+
|
7
|
+
import aiofiles
|
8
|
+
import git
|
9
|
+
|
10
|
+
from lfx.custom.custom_component.component import Component
|
11
|
+
from lfx.io import MessageTextInput, Output
|
12
|
+
from lfx.schema.data import Data
|
13
|
+
from lfx.schema.message import Message
|
14
|
+
|
15
|
+
|
16
|
+
class GitExtractorComponent(Component):
|
17
|
+
display_name = "GitExtractor"
|
18
|
+
description = "Analyzes a Git repository and returns file contents and complete repository information"
|
19
|
+
icon = "GitLoader"
|
20
|
+
|
21
|
+
inputs = [
|
22
|
+
MessageTextInput(
|
23
|
+
name="repository_url",
|
24
|
+
display_name="Repository URL",
|
25
|
+
info="URL of the Git repository (e.g., https://github.com/username/repo)",
|
26
|
+
value="",
|
27
|
+
),
|
28
|
+
]
|
29
|
+
|
30
|
+
outputs = [
|
31
|
+
Output(
|
32
|
+
display_name="Text-Based File Contents",
|
33
|
+
name="text_based_file_contents",
|
34
|
+
method="get_text_based_file_contents",
|
35
|
+
),
|
36
|
+
Output(display_name="Directory Structure", name="directory_structure", method="get_directory_structure"),
|
37
|
+
Output(display_name="Repository Info", name="repository_info", method="get_repository_info"),
|
38
|
+
Output(display_name="Statistics", name="statistics", method="get_statistics"),
|
39
|
+
Output(display_name="Files Content", name="files_content", method="get_files_content"),
|
40
|
+
]
|
41
|
+
|
42
|
+
@asynccontextmanager
|
43
|
+
async def temp_git_repo(self):
|
44
|
+
"""Async context manager for temporary git repository cloning."""
|
45
|
+
temp_dir = tempfile.mkdtemp()
|
46
|
+
try:
|
47
|
+
# Clone is still sync but wrapped in try/finally
|
48
|
+
git.Repo.clone_from(self.repository_url, temp_dir)
|
49
|
+
yield temp_dir
|
50
|
+
finally:
|
51
|
+
shutil.rmtree(temp_dir, ignore_errors=True)
|
52
|
+
|
53
|
+
async def get_repository_info(self) -> list[Data]:
|
54
|
+
try:
|
55
|
+
async with self.temp_git_repo() as temp_dir:
|
56
|
+
repo = git.Repo(temp_dir)
|
57
|
+
repo_info = {
|
58
|
+
"name": self.repository_url.split("/")[-1],
|
59
|
+
"url": self.repository_url,
|
60
|
+
"default_branch": repo.active_branch.name,
|
61
|
+
"remote_urls": [remote.url for remote in repo.remotes],
|
62
|
+
"last_commit": {
|
63
|
+
"hash": repo.head.commit.hexsha,
|
64
|
+
"author": str(repo.head.commit.author),
|
65
|
+
"message": repo.head.commit.message.strip(),
|
66
|
+
"date": str(repo.head.commit.committed_datetime),
|
67
|
+
},
|
68
|
+
"branches": [str(branch) for branch in repo.branches],
|
69
|
+
}
|
70
|
+
result = [Data(data=repo_info)]
|
71
|
+
self.status = result
|
72
|
+
return result
|
73
|
+
except git.GitError as e:
|
74
|
+
error_result = [Data(data={"error": f"Error getting repository info: {e!s}"})]
|
75
|
+
self.status = error_result
|
76
|
+
return error_result
|
77
|
+
|
78
|
+
async def get_statistics(self) -> list[Data]:
|
79
|
+
try:
|
80
|
+
async with self.temp_git_repo() as temp_dir:
|
81
|
+
total_files = 0
|
82
|
+
total_size = 0
|
83
|
+
total_lines = 0
|
84
|
+
binary_files = 0
|
85
|
+
directories = 0
|
86
|
+
|
87
|
+
for root, dirs, files in os.walk(temp_dir):
|
88
|
+
total_files += len(files)
|
89
|
+
directories += len(dirs)
|
90
|
+
for file in files:
|
91
|
+
file_path = Path(root) / file
|
92
|
+
total_size += file_path.stat().st_size
|
93
|
+
try:
|
94
|
+
async with aiofiles.open(file_path, encoding="utf-8") as f:
|
95
|
+
total_lines += sum(1 for _ in await f.readlines())
|
96
|
+
except UnicodeDecodeError:
|
97
|
+
binary_files += 1
|
98
|
+
|
99
|
+
statistics = {
|
100
|
+
"total_files": total_files,
|
101
|
+
"total_size_bytes": total_size,
|
102
|
+
"total_size_kb": round(total_size / 1024, 2),
|
103
|
+
"total_size_mb": round(total_size / (1024 * 1024), 2),
|
104
|
+
"total_lines": total_lines,
|
105
|
+
"binary_files": binary_files,
|
106
|
+
"directories": directories,
|
107
|
+
}
|
108
|
+
result = [Data(data=statistics)]
|
109
|
+
self.status = result
|
110
|
+
return result
|
111
|
+
except git.GitError as e:
|
112
|
+
error_result = [Data(data={"error": f"Error calculating statistics: {e!s}"})]
|
113
|
+
self.status = error_result
|
114
|
+
return error_result
|
115
|
+
|
116
|
+
async def get_directory_structure(self) -> Message:
|
117
|
+
try:
|
118
|
+
async with self.temp_git_repo() as temp_dir:
|
119
|
+
tree = ["Directory structure:"]
|
120
|
+
for root, _dirs, files in os.walk(temp_dir):
|
121
|
+
level = root.replace(temp_dir, "").count(os.sep)
|
122
|
+
indent = " " * level
|
123
|
+
if level == 0:
|
124
|
+
tree.append(f"└── {Path(root).name}")
|
125
|
+
else:
|
126
|
+
tree.append(f"{indent}├── {Path(root).name}")
|
127
|
+
subindent = " " * (level + 1)
|
128
|
+
tree.extend(f"{subindent}├── {f}" for f in files)
|
129
|
+
directory_structure = "\n".join(tree)
|
130
|
+
self.status = directory_structure
|
131
|
+
return Message(text=directory_structure)
|
132
|
+
except git.GitError as e:
|
133
|
+
error_message = f"Error getting directory structure: {e!s}"
|
134
|
+
self.status = error_message
|
135
|
+
return Message(text=error_message)
|
136
|
+
|
137
|
+
async def get_files_content(self) -> list[Data]:
|
138
|
+
try:
|
139
|
+
async with self.temp_git_repo() as temp_dir:
|
140
|
+
content_list = []
|
141
|
+
for root, _, files in os.walk(temp_dir):
|
142
|
+
for file in files:
|
143
|
+
file_path = Path(root) / file
|
144
|
+
relative_path = file_path.relative_to(temp_dir)
|
145
|
+
file_size = file_path.stat().st_size
|
146
|
+
try:
|
147
|
+
async with aiofiles.open(file_path, encoding="utf-8") as f:
|
148
|
+
file_content = await f.read()
|
149
|
+
except UnicodeDecodeError:
|
150
|
+
file_content = "[BINARY FILE]"
|
151
|
+
content_list.append(
|
152
|
+
Data(data={"path": str(relative_path), "size": file_size, "content": file_content})
|
153
|
+
)
|
154
|
+
self.status = content_list
|
155
|
+
return content_list
|
156
|
+
except git.GitError as e:
|
157
|
+
error_result = [Data(data={"error": f"Error getting files content: {e!s}"})]
|
158
|
+
self.status = error_result
|
159
|
+
return error_result
|
160
|
+
|
161
|
+
async def get_text_based_file_contents(self) -> Message:
|
162
|
+
try:
|
163
|
+
async with self.temp_git_repo() as temp_dir:
|
164
|
+
content_list = ["(Files content cropped to 300k characters, download full ingest to see more)"]
|
165
|
+
total_chars = 0
|
166
|
+
char_limit = 300000
|
167
|
+
|
168
|
+
for root, _, files in os.walk(temp_dir):
|
169
|
+
for file in files:
|
170
|
+
file_path = Path(root) / file
|
171
|
+
relative_path = file_path.relative_to(temp_dir)
|
172
|
+
content_list.extend(["=" * 50, f"File: /{relative_path}", "=" * 50])
|
173
|
+
|
174
|
+
try:
|
175
|
+
async with aiofiles.open(file_path, encoding="utf-8") as f:
|
176
|
+
file_content = await f.read()
|
177
|
+
if total_chars + len(file_content) > char_limit:
|
178
|
+
remaining_chars = char_limit - total_chars
|
179
|
+
file_content = file_content[:remaining_chars] + "\n... (content truncated)"
|
180
|
+
content_list.append(file_content)
|
181
|
+
total_chars += len(file_content)
|
182
|
+
except UnicodeDecodeError:
|
183
|
+
content_list.append("[BINARY FILE]")
|
184
|
+
|
185
|
+
content_list.append("")
|
186
|
+
|
187
|
+
if total_chars >= char_limit:
|
188
|
+
break
|
189
|
+
|
190
|
+
text_content = "\n".join(content_list)
|
191
|
+
self.status = text_content
|
192
|
+
return Message(text=text_content)
|
193
|
+
except git.GitError as e:
|
194
|
+
error_message = f"Error getting text-based file contents: {e!s}"
|
195
|
+
self.status = error_message
|
196
|
+
return Message(text=error_message)
|
@@ -0,0 +1,173 @@
|
|
1
|
+
import json
|
2
|
+
from typing import Any
|
3
|
+
from urllib.parse import urljoin
|
4
|
+
|
5
|
+
import httpx
|
6
|
+
from langchain_core.tools import StructuredTool, ToolException
|
7
|
+
from pydantic import BaseModel
|
8
|
+
from pydantic.v1 import Field
|
9
|
+
|
10
|
+
from lfx.base.langchain_utilities.model import LCToolComponent
|
11
|
+
from lfx.field_typing import Tool
|
12
|
+
from lfx.inputs.inputs import IntInput, MultilineInput, NestedDictInput, SecretStrInput, StrInput
|
13
|
+
from lfx.io import Output
|
14
|
+
from lfx.schema.data import Data
|
15
|
+
from lfx.schema.dataframe import DataFrame
|
16
|
+
|
17
|
+
|
18
|
+
class GleanSearchAPISchema(BaseModel):
|
19
|
+
query: str = Field(..., description="The search query")
|
20
|
+
page_size: int = Field(10, description="Maximum number of results to return")
|
21
|
+
request_options: dict[str, Any] | None = Field(default_factory=dict, description="Request Options")
|
22
|
+
|
23
|
+
|
24
|
+
class GleanAPIWrapper(BaseModel):
|
25
|
+
"""Wrapper around Glean API."""
|
26
|
+
|
27
|
+
glean_api_url: str
|
28
|
+
glean_access_token: str
|
29
|
+
act_as: str = "langflow-component@datastax.com" # TODO: Detect this
|
30
|
+
|
31
|
+
def _prepare_request(
|
32
|
+
self,
|
33
|
+
query: str,
|
34
|
+
page_size: int = 10,
|
35
|
+
request_options: dict[str, Any] | None = None,
|
36
|
+
) -> dict:
|
37
|
+
# Ensure there's a trailing slash
|
38
|
+
url = self.glean_api_url
|
39
|
+
if not url.endswith("/"):
|
40
|
+
url += "/"
|
41
|
+
|
42
|
+
return {
|
43
|
+
"url": urljoin(url, "search"),
|
44
|
+
"headers": {
|
45
|
+
"Authorization": f"Bearer {self.glean_access_token}",
|
46
|
+
"X-Scio-ActAs": self.act_as,
|
47
|
+
},
|
48
|
+
"payload": {
|
49
|
+
"query": query,
|
50
|
+
"pageSize": page_size,
|
51
|
+
"requestOptions": request_options,
|
52
|
+
},
|
53
|
+
}
|
54
|
+
|
55
|
+
def results(self, query: str, **kwargs: Any) -> list[dict[str, Any]]:
|
56
|
+
results = self._search_api_results(query, **kwargs)
|
57
|
+
|
58
|
+
if len(results) == 0:
|
59
|
+
msg = "No good Glean Search Result was found"
|
60
|
+
raise AssertionError(msg)
|
61
|
+
|
62
|
+
return results
|
63
|
+
|
64
|
+
def run(self, query: str, **kwargs: Any) -> list[dict[str, Any]]:
|
65
|
+
try:
|
66
|
+
results = self.results(query, **kwargs)
|
67
|
+
|
68
|
+
processed_results = []
|
69
|
+
for result in results:
|
70
|
+
if "title" in result:
|
71
|
+
result["snippets"] = result.get("snippets", [{"snippet": {"text": result["title"]}}])
|
72
|
+
if "text" not in result["snippets"][0]:
|
73
|
+
result["snippets"][0]["text"] = result["title"]
|
74
|
+
|
75
|
+
processed_results.append(result)
|
76
|
+
except Exception as e:
|
77
|
+
error_message = f"Error in Glean Search API: {e!s}"
|
78
|
+
raise ToolException(error_message) from e
|
79
|
+
|
80
|
+
return processed_results
|
81
|
+
|
82
|
+
def _search_api_results(self, query: str, **kwargs: Any) -> list[dict[str, Any]]:
|
83
|
+
request_details = self._prepare_request(query, **kwargs)
|
84
|
+
|
85
|
+
response = httpx.post(
|
86
|
+
request_details["url"],
|
87
|
+
json=request_details["payload"],
|
88
|
+
headers=request_details["headers"],
|
89
|
+
)
|
90
|
+
|
91
|
+
response.raise_for_status()
|
92
|
+
response_json = response.json()
|
93
|
+
|
94
|
+
return response_json.get("results", [])
|
95
|
+
|
96
|
+
@staticmethod
|
97
|
+
def _result_as_string(result: dict) -> str:
|
98
|
+
return json.dumps(result, indent=4)
|
99
|
+
|
100
|
+
|
101
|
+
class GleanSearchAPIComponent(LCToolComponent):
|
102
|
+
display_name: str = "Glean Search API"
|
103
|
+
description: str = "Search using Glean's API."
|
104
|
+
documentation: str = "https://docs.langflow.org/Components/components-tools#glean-search-api"
|
105
|
+
icon: str = "Glean"
|
106
|
+
|
107
|
+
outputs = [
|
108
|
+
Output(display_name="DataFrame", name="dataframe", method="fetch_content_dataframe"),
|
109
|
+
]
|
110
|
+
|
111
|
+
inputs = [
|
112
|
+
StrInput(name="glean_api_url", display_name="Glean API URL", required=True),
|
113
|
+
SecretStrInput(name="glean_access_token", display_name="Glean Access Token", required=True),
|
114
|
+
MultilineInput(name="query", display_name="Query", required=True, tool_mode=True),
|
115
|
+
IntInput(name="page_size", display_name="Page Size", value=10),
|
116
|
+
NestedDictInput(name="request_options", display_name="Request Options", required=False),
|
117
|
+
]
|
118
|
+
|
119
|
+
def build_tool(self) -> Tool:
|
120
|
+
wrapper = self._build_wrapper(
|
121
|
+
glean_api_url=self.glean_api_url,
|
122
|
+
glean_access_token=self.glean_access_token,
|
123
|
+
)
|
124
|
+
|
125
|
+
tool = StructuredTool.from_function(
|
126
|
+
name="glean_search_api",
|
127
|
+
description="Search Glean for relevant results.",
|
128
|
+
func=wrapper.run,
|
129
|
+
args_schema=GleanSearchAPISchema,
|
130
|
+
)
|
131
|
+
|
132
|
+
self.status = "Glean Search API Tool for Langchain"
|
133
|
+
|
134
|
+
return tool
|
135
|
+
|
136
|
+
def run_model(self) -> DataFrame:
|
137
|
+
return self.fetch_content_dataframe()
|
138
|
+
|
139
|
+
def fetch_content(self) -> list[Data]:
|
140
|
+
tool = self.build_tool()
|
141
|
+
|
142
|
+
results = tool.run(
|
143
|
+
{
|
144
|
+
"query": self.query,
|
145
|
+
"page_size": self.page_size,
|
146
|
+
"request_options": self.request_options,
|
147
|
+
}
|
148
|
+
)
|
149
|
+
|
150
|
+
# Build the data
|
151
|
+
data = [Data(data=result, text=result["snippets"][0]["text"]) for result in results]
|
152
|
+
self.status = data # type: ignore[assignment]
|
153
|
+
|
154
|
+
return data
|
155
|
+
|
156
|
+
def _build_wrapper(
|
157
|
+
self,
|
158
|
+
glean_api_url: str,
|
159
|
+
glean_access_token: str,
|
160
|
+
):
|
161
|
+
return GleanAPIWrapper(
|
162
|
+
glean_api_url=glean_api_url,
|
163
|
+
glean_access_token=glean_access_token,
|
164
|
+
)
|
165
|
+
|
166
|
+
def fetch_content_dataframe(self) -> DataFrame:
|
167
|
+
"""Convert the Glean search results to a DataFrame.
|
168
|
+
|
169
|
+
Returns:
|
170
|
+
DataFrame: A DataFrame containing the search results.
|
171
|
+
"""
|
172
|
+
data = self.fetch_content()
|
173
|
+
return DataFrame(data)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
from .gmail import GmailLoaderComponent
|
2
|
+
from .google_bq_sql_executor import BigQueryExecutorComponent
|
3
|
+
from .google_drive import GoogleDriveComponent
|
4
|
+
from .google_drive_search import GoogleDriveSearchComponent
|
5
|
+
from .google_generative_ai import GoogleGenerativeAIComponent
|
6
|
+
from .google_generative_ai_embeddings import GoogleGenerativeAIEmbeddingsComponent
|
7
|
+
from .google_oauth_token import GoogleOAuthToken
|
8
|
+
|
9
|
+
__all__ = [
|
10
|
+
"BigQueryExecutorComponent",
|
11
|
+
"GmailLoaderComponent",
|
12
|
+
"GoogleDriveComponent",
|
13
|
+
"GoogleDriveSearchComponent",
|
14
|
+
"GoogleGenerativeAIComponent",
|
15
|
+
"GoogleGenerativeAIEmbeddingsComponent",
|
16
|
+
"GoogleOAuthToken",
|
17
|
+
]
|
@@ -0,0 +1,192 @@
|
|
1
|
+
import base64
|
2
|
+
import json
|
3
|
+
import re
|
4
|
+
from collections.abc import Iterator
|
5
|
+
from json.decoder import JSONDecodeError
|
6
|
+
from typing import Any
|
7
|
+
|
8
|
+
from google.auth.exceptions import RefreshError
|
9
|
+
from google.oauth2.credentials import Credentials
|
10
|
+
from googleapiclient.discovery import build
|
11
|
+
from langchain_core.chat_sessions import ChatSession
|
12
|
+
from langchain_core.messages import HumanMessage
|
13
|
+
from langchain_google_community.gmail.loader import GMailLoader
|
14
|
+
|
15
|
+
from lfx.custom.custom_component.component import Component
|
16
|
+
from lfx.inputs.inputs import MessageTextInput
|
17
|
+
from lfx.io import SecretStrInput
|
18
|
+
from lfx.log.logger import logger
|
19
|
+
from lfx.schema.data import Data
|
20
|
+
from lfx.template.field.base import Output
|
21
|
+
|
22
|
+
|
23
|
+
class GmailLoaderComponent(Component):
|
24
|
+
display_name = "Gmail Loader"
|
25
|
+
description = "Loads emails from Gmail using provided credentials."
|
26
|
+
icon = "Google"
|
27
|
+
legacy: bool = True
|
28
|
+
|
29
|
+
inputs = [
|
30
|
+
SecretStrInput(
|
31
|
+
name="json_string",
|
32
|
+
display_name="JSON String of the Service Account Token",
|
33
|
+
info="JSON string containing OAuth 2.0 access token information for service account access",
|
34
|
+
required=True,
|
35
|
+
value="""{
|
36
|
+
"account": "",
|
37
|
+
"client_id": "",
|
38
|
+
"client_secret": "",
|
39
|
+
"expiry": "",
|
40
|
+
"refresh_token": "",
|
41
|
+
"scopes": [
|
42
|
+
"https://www.googleapis.com/auth/gmail.readonly",
|
43
|
+
],
|
44
|
+
"token": "",
|
45
|
+
"token_uri": "https://oauth2.googleapis.com/token",
|
46
|
+
"universe_domain": "googleapis.com"
|
47
|
+
}""",
|
48
|
+
),
|
49
|
+
MessageTextInput(
|
50
|
+
name="label_ids",
|
51
|
+
display_name="Label IDs",
|
52
|
+
info="Comma-separated list of label IDs to filter emails.",
|
53
|
+
required=True,
|
54
|
+
value="INBOX,SENT,UNREAD,IMPORTANT",
|
55
|
+
),
|
56
|
+
MessageTextInput(
|
57
|
+
name="max_results",
|
58
|
+
display_name="Max Results",
|
59
|
+
info="Maximum number of emails to load.",
|
60
|
+
required=True,
|
61
|
+
value="10",
|
62
|
+
),
|
63
|
+
]
|
64
|
+
|
65
|
+
outputs = [
|
66
|
+
Output(display_name="Data", name="data", method="load_emails"),
|
67
|
+
]
|
68
|
+
|
69
|
+
def load_emails(self) -> Data:
|
70
|
+
class CustomGMailLoader(GMailLoader):
|
71
|
+
def __init__(
|
72
|
+
self, creds: Any, *, n: int = 100, label_ids: list[str] | None = None, raise_error: bool = False
|
73
|
+
) -> None:
|
74
|
+
super().__init__(creds, n, raise_error)
|
75
|
+
self.label_ids = label_ids if label_ids is not None else ["SENT"]
|
76
|
+
|
77
|
+
def clean_message_content(self, message):
|
78
|
+
# Remove URLs
|
79
|
+
message = re.sub(r"http\S+|www\S+|https\S+", "", message, flags=re.MULTILINE)
|
80
|
+
|
81
|
+
# Remove email addresses
|
82
|
+
message = re.sub(r"\S+@\S+", "", message)
|
83
|
+
|
84
|
+
# Remove special characters and excessive whitespace
|
85
|
+
message = re.sub(r"[^A-Za-z0-9\s]+", " ", message)
|
86
|
+
message = re.sub(r"\s{2,}", " ", message)
|
87
|
+
|
88
|
+
# Trim leading and trailing whitespace
|
89
|
+
return message.strip()
|
90
|
+
|
91
|
+
def _extract_email_content(self, msg: Any) -> HumanMessage:
|
92
|
+
from_email = None
|
93
|
+
for values in msg["payload"]["headers"]:
|
94
|
+
name = values["name"]
|
95
|
+
if name == "From":
|
96
|
+
from_email = values["value"]
|
97
|
+
if from_email is None:
|
98
|
+
msg = "From email not found."
|
99
|
+
raise ValueError(msg)
|
100
|
+
|
101
|
+
parts = msg["payload"]["parts"] if "parts" in msg["payload"] else [msg["payload"]]
|
102
|
+
|
103
|
+
for part in parts:
|
104
|
+
if part["mimeType"] == "text/plain":
|
105
|
+
data = part["body"]["data"]
|
106
|
+
data = base64.urlsafe_b64decode(data).decode("utf-8")
|
107
|
+
pattern = re.compile(r"\r\nOn .+(\r\n)*wrote:\r\n")
|
108
|
+
newest_response = re.split(pattern, data)[0]
|
109
|
+
return HumanMessage(
|
110
|
+
content=self.clean_message_content(newest_response),
|
111
|
+
additional_kwargs={"sender": from_email},
|
112
|
+
)
|
113
|
+
msg = "No plain text part found in the email."
|
114
|
+
raise ValueError(msg)
|
115
|
+
|
116
|
+
def _get_message_data(self, service: Any, message: Any) -> ChatSession:
|
117
|
+
msg = service.users().messages().get(userId="me", id=message["id"]).execute()
|
118
|
+
message_content = self._extract_email_content(msg)
|
119
|
+
|
120
|
+
in_reply_to = None
|
121
|
+
email_data = msg["payload"]["headers"]
|
122
|
+
for values in email_data:
|
123
|
+
name = values["name"]
|
124
|
+
if name == "In-Reply-To":
|
125
|
+
in_reply_to = values["value"]
|
126
|
+
|
127
|
+
thread_id = msg["threadId"]
|
128
|
+
|
129
|
+
if in_reply_to:
|
130
|
+
thread = service.users().threads().get(userId="me", id=thread_id).execute()
|
131
|
+
messages = thread["messages"]
|
132
|
+
|
133
|
+
response_email = None
|
134
|
+
for _message in messages:
|
135
|
+
email_data = _message["payload"]["headers"]
|
136
|
+
for values in email_data:
|
137
|
+
if values["name"] == "Message-ID":
|
138
|
+
message_id = values["value"]
|
139
|
+
if message_id == in_reply_to:
|
140
|
+
response_email = _message
|
141
|
+
if response_email is None:
|
142
|
+
msg = "Response email not found in the thread."
|
143
|
+
raise ValueError(msg)
|
144
|
+
starter_content = self._extract_email_content(response_email)
|
145
|
+
return ChatSession(messages=[starter_content, message_content])
|
146
|
+
return ChatSession(messages=[message_content])
|
147
|
+
|
148
|
+
def lazy_load(self) -> Iterator[ChatSession]:
|
149
|
+
service = build("gmail", "v1", credentials=self.creds)
|
150
|
+
results = (
|
151
|
+
service.users().messages().list(userId="me", labelIds=self.label_ids, maxResults=self.n).execute()
|
152
|
+
)
|
153
|
+
messages = results.get("messages", [])
|
154
|
+
if not messages:
|
155
|
+
logger.warning("No messages found with the specified labels.")
|
156
|
+
for message in messages:
|
157
|
+
try:
|
158
|
+
yield self._get_message_data(service, message)
|
159
|
+
except Exception:
|
160
|
+
if self.raise_error:
|
161
|
+
raise
|
162
|
+
else:
|
163
|
+
logger.exception(f"Error processing message {message['id']}")
|
164
|
+
|
165
|
+
json_string = self.json_string
|
166
|
+
label_ids = self.label_ids.split(",") if self.label_ids else ["INBOX"]
|
167
|
+
max_results = int(self.max_results) if self.max_results else 100
|
168
|
+
|
169
|
+
# Load the token information from the JSON string
|
170
|
+
try:
|
171
|
+
token_info = json.loads(json_string)
|
172
|
+
except JSONDecodeError as e:
|
173
|
+
msg = "Invalid JSON string"
|
174
|
+
raise ValueError(msg) from e
|
175
|
+
|
176
|
+
creds = Credentials.from_authorized_user_info(token_info)
|
177
|
+
|
178
|
+
# Initialize the custom loader with the provided credentials
|
179
|
+
loader = CustomGMailLoader(creds=creds, n=max_results, label_ids=label_ids)
|
180
|
+
|
181
|
+
try:
|
182
|
+
docs = loader.load()
|
183
|
+
except RefreshError as e:
|
184
|
+
msg = "Authentication error: Unable to refresh authentication token. Please try to reauthenticate."
|
185
|
+
raise ValueError(msg) from e
|
186
|
+
except Exception as e:
|
187
|
+
msg = f"Error loading documents: {e}"
|
188
|
+
raise ValueError(msg) from e
|
189
|
+
|
190
|
+
# Return the loaded documents
|
191
|
+
self.status = docs
|
192
|
+
return Data(data={"text": docs})
|