lfx-nightly 0.2.0.dev25__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.
Potentially problematic release.
This version of lfx-nightly might be problematic. Click here for more details.
- lfx/__init__.py +0 -0
- lfx/__main__.py +25 -0
- lfx/_assets/component_index.json +1 -0
- lfx/base/__init__.py +0 -0
- lfx/base/agents/__init__.py +0 -0
- lfx/base/agents/agent.py +375 -0
- lfx/base/agents/altk_base_agent.py +380 -0
- lfx/base/agents/altk_tool_wrappers.py +565 -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 +430 -0
- lfx/base/agents/utils.py +237 -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 +2584 -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 +810 -0
- lfx/base/data/docling_utils.py +338 -0
- lfx/base/data/storage_utils.py +192 -0
- lfx/base/data/utils.py +362 -0
- lfx/base/datastax/__init__.py +5 -0
- lfx/base/datastax/astradb_base.py +896 -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/embeddings_class.py +113 -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 +21 -0
- lfx/base/io/text.py +22 -0
- lfx/base/knowledge_bases/__init__.py +3 -0
- lfx/base/knowledge_bases/knowledge_base_utils.py +137 -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 +1659 -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 +51 -0
- lfx/base/models/aws_constants.py +151 -0
- lfx/base/models/chat_result.py +76 -0
- lfx/base/models/cometapi_constants.py +54 -0
- lfx/base/models/google_generative_ai_constants.py +70 -0
- lfx/base/models/google_generative_ai_model.py +38 -0
- lfx/base/models/groq_constants.py +150 -0
- lfx/base/models/groq_model_discovery.py +265 -0
- lfx/base/models/model.py +375 -0
- lfx/base/models/model_input_constants.py +378 -0
- lfx/base/models/model_metadata.py +41 -0
- lfx/base/models/model_utils.py +108 -0
- lfx/base/models/novita_constants.py +35 -0
- lfx/base/models/ollama_constants.py +52 -0
- lfx/base/models/openai_constants.py +129 -0
- lfx/base/models/sambanova_constants.py +18 -0
- lfx/base/models/watsonx_constants.py +36 -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 +698 -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 +327 -0
- lfx/cli/common.py +650 -0
- lfx/cli/run.py +506 -0
- lfx/cli/script_loader.py +289 -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 +428 -0
- lfx/components/_importing.py +42 -0
- lfx/components/agentql/__init__.py +3 -0
- lfx/components/agentql/agentql_api.py +151 -0
- lfx/components/aiml/__init__.py +37 -0
- lfx/components/aiml/aiml.py +115 -0
- lfx/components/aiml/aiml_embeddings.py +37 -0
- lfx/components/altk/__init__.py +34 -0
- lfx/components/altk/altk_agent.py +193 -0
- lfx/components/amazon/__init__.py +36 -0
- lfx/components/amazon/amazon_bedrock_converse.py +195 -0
- lfx/components/amazon/amazon_bedrock_embedding.py +109 -0
- lfx/components/amazon/amazon_bedrock_model.py +130 -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 +169 -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 +169 -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/cometapi/__init__.py +32 -0
- lfx/components/cometapi/cometapi.py +166 -0
- lfx/components/composio/__init__.py +222 -0
- lfx/components/composio/agentql_composio.py +11 -0
- lfx/components/composio/agiled_composio.py +11 -0
- lfx/components/composio/airtable_composio.py +11 -0
- lfx/components/composio/apollo_composio.py +11 -0
- lfx/components/composio/asana_composio.py +11 -0
- lfx/components/composio/attio_composio.py +11 -0
- lfx/components/composio/bitbucket_composio.py +11 -0
- lfx/components/composio/bolna_composio.py +11 -0
- lfx/components/composio/brightdata_composio.py +11 -0
- lfx/components/composio/calendly_composio.py +11 -0
- lfx/components/composio/canva_composio.py +11 -0
- lfx/components/composio/canvas_composio.py +11 -0
- lfx/components/composio/coda_composio.py +11 -0
- lfx/components/composio/composio_api.py +278 -0
- lfx/components/composio/contentful_composio.py +11 -0
- lfx/components/composio/digicert_composio.py +11 -0
- lfx/components/composio/discord_composio.py +11 -0
- lfx/components/composio/dropbox_compnent.py +11 -0
- lfx/components/composio/elevenlabs_composio.py +11 -0
- lfx/components/composio/exa_composio.py +11 -0
- lfx/components/composio/figma_composio.py +11 -0
- lfx/components/composio/finage_composio.py +11 -0
- lfx/components/composio/firecrawl_composio.py +11 -0
- lfx/components/composio/fireflies_composio.py +11 -0
- lfx/components/composio/fixer_composio.py +11 -0
- lfx/components/composio/flexisign_composio.py +11 -0
- lfx/components/composio/freshdesk_composio.py +11 -0
- lfx/components/composio/github_composio.py +11 -0
- lfx/components/composio/gmail_composio.py +38 -0
- lfx/components/composio/googlebigquery_composio.py +11 -0
- lfx/components/composio/googlecalendar_composio.py +11 -0
- lfx/components/composio/googleclassroom_composio.py +11 -0
- lfx/components/composio/googledocs_composio.py +11 -0
- lfx/components/composio/googlemeet_composio.py +11 -0
- lfx/components/composio/googlesheets_composio.py +11 -0
- lfx/components/composio/googletasks_composio.py +8 -0
- lfx/components/composio/heygen_composio.py +11 -0
- lfx/components/composio/instagram_composio.py +11 -0
- lfx/components/composio/jira_composio.py +11 -0
- lfx/components/composio/jotform_composio.py +11 -0
- lfx/components/composio/klaviyo_composio.py +11 -0
- lfx/components/composio/linear_composio.py +11 -0
- lfx/components/composio/listennotes_composio.py +11 -0
- lfx/components/composio/mem0_composio.py +11 -0
- lfx/components/composio/miro_composio.py +11 -0
- lfx/components/composio/missive_composio.py +11 -0
- lfx/components/composio/notion_composio.py +11 -0
- lfx/components/composio/onedrive_composio.py +11 -0
- lfx/components/composio/outlook_composio.py +11 -0
- lfx/components/composio/pandadoc_composio.py +11 -0
- lfx/components/composio/peopledatalabs_composio.py +11 -0
- lfx/components/composio/perplexityai_composio.py +11 -0
- lfx/components/composio/reddit_composio.py +11 -0
- lfx/components/composio/serpapi_composio.py +11 -0
- lfx/components/composio/slack_composio.py +11 -0
- lfx/components/composio/slackbot_composio.py +11 -0
- lfx/components/composio/snowflake_composio.py +11 -0
- lfx/components/composio/supabase_composio.py +11 -0
- lfx/components/composio/tavily_composio.py +11 -0
- lfx/components/composio/timelinesai_composio.py +11 -0
- lfx/components/composio/todoist_composio.py +11 -0
- lfx/components/composio/wrike_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 +108 -0
- lfx/components/crewai/hierarchical_crew.py +47 -0
- lfx/components/crewai/hierarchical_task.py +45 -0
- lfx/components/crewai/sequential_crew.py +53 -0
- lfx/components/crewai/sequential_task.py +74 -0
- lfx/components/crewai/sequential_task_agent.py +144 -0
- lfx/components/cuga/__init__.py +34 -0
- lfx/components/cuga/cuga_agent.py +730 -0
- lfx/components/custom_component/__init__.py +34 -0
- lfx/components/custom_component/custom_component.py +31 -0
- lfx/components/data/__init__.py +114 -0
- lfx/components/data_source/__init__.py +58 -0
- lfx/components/data_source/api_request.py +577 -0
- lfx/components/data_source/csv_to_data.py +101 -0
- lfx/components/data_source/json_to_data.py +106 -0
- lfx/components/data_source/mock_data.py +398 -0
- lfx/components/data_source/news_search.py +166 -0
- lfx/components/data_source/rss.py +71 -0
- lfx/components/data_source/sql_executor.py +101 -0
- lfx/components/data_source/url.py +311 -0
- lfx/components/data_source/web_search.py +326 -0
- lfx/components/datastax/__init__.py +76 -0
- lfx/components/datastax/astradb_assistant_manager.py +307 -0
- lfx/components/datastax/astradb_chatmemory.py +40 -0
- lfx/components/datastax/astradb_cql.py +288 -0
- lfx/components/datastax/astradb_graph.py +217 -0
- lfx/components/datastax/astradb_tool.py +378 -0
- lfx/components/datastax/astradb_vectorize.py +122 -0
- lfx/components/datastax/astradb_vectorstore.py +449 -0
- lfx/components/datastax/create_assistant.py +59 -0
- lfx/components/datastax/create_thread.py +33 -0
- lfx/components/datastax/dotenv.py +36 -0
- lfx/components/datastax/get_assistant.py +38 -0
- lfx/components/datastax/getenvvar.py +31 -0
- lfx/components/datastax/graph_rag.py +141 -0
- lfx/components/datastax/hcd.py +315 -0
- lfx/components/datastax/list_assistants.py +26 -0
- lfx/components/datastax/run.py +90 -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 +238 -0
- lfx/components/docling/docling_remote.py +195 -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 +789 -0
- lfx/components/elastic/opensearch_multimodal.py +1575 -0
- lfx/components/embeddings/__init__.py +37 -0
- lfx/components/embeddings/similarity.py +77 -0
- lfx/components/embeddings/text_embedder.py +65 -0
- lfx/components/exa/__init__.py +3 -0
- lfx/components/exa/exa_search.py +68 -0
- lfx/components/files_and_knowledge/__init__.py +47 -0
- lfx/components/files_and_knowledge/directory.py +113 -0
- lfx/components/files_and_knowledge/file.py +841 -0
- lfx/components/files_and_knowledge/ingestion.py +694 -0
- lfx/components/files_and_knowledge/retrieval.py +264 -0
- lfx/components/files_and_knowledge/save_file.py +746 -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/flow_controls/__init__.py +58 -0
- lfx/components/flow_controls/conditional_router.py +208 -0
- lfx/components/flow_controls/data_conditional_router.py +126 -0
- lfx/components/flow_controls/flow_tool.py +111 -0
- lfx/components/flow_controls/listen.py +29 -0
- lfx/components/flow_controls/loop.py +163 -0
- lfx/components/flow_controls/notify.py +88 -0
- lfx/components/flow_controls/pass_message.py +36 -0
- lfx/components/flow_controls/run_flow.py +108 -0
- lfx/components/flow_controls/sub_flow.py +115 -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 +193 -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 +144 -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 +143 -0
- lfx/components/helpers/__init__.py +154 -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 +199 -0
- lfx/components/huggingface/huggingface_inference_api.py +106 -0
- lfx/components/ibm/__init__.py +34 -0
- lfx/components/ibm/watsonx.py +207 -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 +40 -0
- lfx/components/input_output/chat.py +109 -0
- lfx/components/input_output/chat_output.py +184 -0
- lfx/components/input_output/text.py +27 -0
- lfx/components/input_output/text_output.py +29 -0
- lfx/components/input_output/webhook.py +56 -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/knowledge_bases/__init__.py +89 -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 +175 -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 +100 -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/llm_operations/__init__.py +46 -0
- lfx/components/llm_operations/batch_run.py +205 -0
- lfx/components/llm_operations/lambda_filter.py +218 -0
- lfx/components/llm_operations/llm_conditional_router.py +421 -0
- lfx/components/llm_operations/llm_selector.py +499 -0
- lfx/components/llm_operations/structured_output.py +244 -0
- lfx/components/lmstudio/__init__.py +34 -0
- lfx/components/lmstudio/lmstudioembeddings.py +89 -0
- lfx/components/lmstudio/lmstudiomodel.py +133 -0
- lfx/components/logic/__init__.py +181 -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 +147 -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 +89 -0
- lfx/components/models_and_agents/__init__.py +49 -0
- lfx/components/models_and_agents/agent.py +644 -0
- lfx/components/models_and_agents/embedding_model.py +423 -0
- lfx/components/models_and_agents/language_model.py +398 -0
- lfx/components/models_and_agents/mcp_component.py +594 -0
- lfx/components/models_and_agents/memory.py +268 -0
- lfx/components/models_and_agents/prompt.py +67 -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 +151 -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 +548 -0
- lfx/components/ollama/ollama_embeddings.py +103 -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 +104 -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 +72 -0
- lfx/components/processing/alter_metadata.py +109 -0
- lfx/components/processing/combine_text.py +40 -0
- lfx/components/processing/converter.py +248 -0
- lfx/components/processing/create_data.py +111 -0
- lfx/components/processing/create_list.py +40 -0
- lfx/components/processing/data_operations.py +528 -0
- lfx/components/processing/data_to_dataframe.py +71 -0
- lfx/components/processing/dataframe_operations.py +313 -0
- lfx/components/processing/dataframe_to_toolset.py +259 -0
- lfx/components/processing/dynamic_create_data.py +357 -0
- lfx/components/processing/extract_key.py +54 -0
- lfx/components/processing/filter_data.py +43 -0
- lfx/components/processing/filter_data_values.py +89 -0
- lfx/components/processing/json_cleaner.py +104 -0
- lfx/components/processing/merge_data.py +91 -0
- lfx/components/processing/message_to_data.py +37 -0
- lfx/components/processing/output_parser.py +46 -0
- lfx/components/processing/parse_data.py +71 -0
- lfx/components/processing/parse_dataframe.py +69 -0
- lfx/components/processing/parse_json_data.py +91 -0
- lfx/components/processing/parser.py +148 -0
- lfx/components/processing/regex.py +83 -0
- lfx/components/processing/select_data.py +49 -0
- lfx/components/processing/split_text.py +141 -0
- lfx/components/processing/store_message.py +91 -0
- lfx/components/processing/update_data.py +161 -0
- lfx/components/prototypes/__init__.py +35 -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 +66 -0
- lfx/components/tools/calculator.py +109 -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 +328 -0
- lfx/components/tools/python_repl.py +98 -0
- lfx/components/tools/search_api.py +88 -0
- lfx/components/tools/searxng.py +145 -0
- lfx/components/tools/serp_api.py +120 -0
- lfx/components/tools/tavily_search_tool.py +345 -0
- lfx/components/tools/wikidata_api.py +103 -0
- lfx/components/tools/wikipedia_api.py +50 -0
- lfx/components/tools/yahoo_finance.py +130 -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 +301 -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 +191 -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/utilities/__init__.py +43 -0
- lfx/components/utilities/calculator_core.py +89 -0
- lfx/components/utilities/current_date.py +42 -0
- lfx/components/utilities/id_generator.py +42 -0
- lfx/components/utilities/python_repl_core.py +98 -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 +34 -0
- lfx/components/vectorstores/local_db.py +270 -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/vlmrun/__init__.py +34 -0
- lfx/components/vlmrun/vlmrun_transcription.py +224 -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 +206 -0
- lfx/components/zep/__init__.py +3 -0
- lfx/components/zep/zep.py +45 -0
- lfx/constants.py +6 -0
- lfx/custom/__init__.py +7 -0
- lfx/custom/attributes.py +87 -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 +1890 -0
- lfx/custom/custom_component/component_with_cache.py +8 -0
- lfx/custom/custom_component/custom_component.py +650 -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 +523 -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 +216 -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 +300 -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 +2298 -0
- lfx/graph/graph/constants.py +63 -0
- lfx/graph/graph/runnable_vertices_manager.py +133 -0
- lfx/graph/graph/schema.py +53 -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 +250 -0
- lfx/graph/utils.py +206 -0
- lfx/graph/vertex/__init__.py +0 -0
- lfx/graph/vertex/base.py +826 -0
- lfx/graph/vertex/constants.py +0 -0
- lfx/graph/vertex/exceptions.py +4 -0
- lfx/graph/vertex/param_handler.py +316 -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 +141 -0
- lfx/helpers/base_model.py +71 -0
- lfx/helpers/custom.py +13 -0
- lfx/helpers/data.py +167 -0
- lfx/helpers/flow.py +308 -0
- lfx/inputs/__init__.py +68 -0
- lfx/inputs/constants.py +2 -0
- lfx/inputs/input_mixin.py +352 -0
- lfx/inputs/inputs.py +718 -0
- lfx/inputs/validators.py +19 -0
- lfx/interface/__init__.py +6 -0
- lfx/interface/components.py +897 -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 +317 -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 +295 -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 +411 -0
- lfx/logging/__init__.py +11 -0
- lfx/logging/logger.py +24 -0
- lfx/memory/__init__.py +70 -0
- lfx/memory/stubs.py +302 -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/cross_module.py +80 -0
- lfx/schema/data.py +309 -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 +184 -0
- lfx/schema/json_schema.py +186 -0
- lfx/schema/log.py +62 -0
- lfx/schema/message.py +493 -0
- lfx/schema/openai_responses_schemas.py +74 -0
- lfx/schema/properties.py +41 -0
- lfx/schema/schema.py +180 -0
- lfx/schema/serialize.py +13 -0
- lfx/schema/table.py +142 -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 +26 -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/database/__init__.py +5 -0
- lfx/services/database/service.py +25 -0
- lfx/services/deps.py +194 -0
- lfx/services/factory.py +19 -0
- lfx/services/initialize.py +19 -0
- lfx/services/interfaces.py +103 -0
- lfx/services/manager.py +185 -0
- lfx/services/mcp_composer/__init__.py +6 -0
- lfx/services/mcp_composer/factory.py +16 -0
- lfx/services/mcp_composer/service.py +1441 -0
- lfx/services/schema.py +21 -0
- lfx/services/session.py +87 -0
- lfx/services/settings/__init__.py +3 -0
- lfx/services/settings/auth.py +133 -0
- lfx/services/settings/base.py +668 -0
- lfx/services/settings/constants.py +43 -0
- lfx/services/settings/factory.py +23 -0
- lfx/services/settings/feature_flags.py +11 -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 +185 -0
- lfx/services/storage/service.py +177 -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 +260 -0
- lfx/template/field/prompt.py +15 -0
- lfx/template/frontend_node/__init__.py +6 -0
- lfx/template/frontend_node/base.py +214 -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 +233 -0
- lfx/utils/data_structure.py +212 -0
- lfx/utils/exceptions.py +22 -0
- lfx/utils/helpers.py +34 -0
- lfx/utils/image.py +79 -0
- lfx/utils/langflow_utils.py +52 -0
- lfx/utils/lazy_load.py +15 -0
- lfx/utils/request_utils.py +18 -0
- lfx/utils/schemas.py +139 -0
- lfx/utils/ssrf_protection.py +384 -0
- lfx/utils/util.py +626 -0
- lfx/utils/util_strings.py +56 -0
- lfx/utils/validate_cloud.py +26 -0
- lfx/utils/version.py +24 -0
- lfx_nightly-0.2.0.dev25.dist-info/METADATA +312 -0
- lfx_nightly-0.2.0.dev25.dist-info/RECORD +769 -0
- lfx_nightly-0.2.0.dev25.dist-info/WHEEL +4 -0
- lfx_nightly-0.2.0.dev25.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import re
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
from lfx.custom.custom_component.component import Component
|
|
8
|
+
from lfx.io import DataInput, HandleInput, IntInput, MultilineInput, Output
|
|
9
|
+
from lfx.schema.data import Data
|
|
10
|
+
from lfx.schema.dataframe import DataFrame
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from collections.abc import Callable
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class LambdaFilterComponent(Component):
|
|
17
|
+
display_name = "Smart Transform"
|
|
18
|
+
description = "Uses an LLM to generate a function for filtering or transforming structured data."
|
|
19
|
+
documentation: str = "https://docs.langflow.org/smart-transform"
|
|
20
|
+
icon = "square-function"
|
|
21
|
+
name = "Smart Transform"
|
|
22
|
+
|
|
23
|
+
inputs = [
|
|
24
|
+
DataInput(
|
|
25
|
+
name="data",
|
|
26
|
+
display_name="Data",
|
|
27
|
+
info="The structured data to filter or transform using a lambda function.",
|
|
28
|
+
input_types=["Data", "DataFrame"],
|
|
29
|
+
is_list=True,
|
|
30
|
+
required=True,
|
|
31
|
+
),
|
|
32
|
+
HandleInput(
|
|
33
|
+
name="llm",
|
|
34
|
+
display_name="Language Model",
|
|
35
|
+
info="Connect the 'Language Model' output from your LLM component here.",
|
|
36
|
+
input_types=["LanguageModel"],
|
|
37
|
+
required=True,
|
|
38
|
+
),
|
|
39
|
+
MultilineInput(
|
|
40
|
+
name="filter_instruction",
|
|
41
|
+
display_name="Instructions",
|
|
42
|
+
info=(
|
|
43
|
+
"Natural language instructions for how to filter or transform the data using a lambda function. "
|
|
44
|
+
"Example: Filter the data to only include items where the 'status' is 'active'."
|
|
45
|
+
),
|
|
46
|
+
value="Filter the data to...",
|
|
47
|
+
required=True,
|
|
48
|
+
),
|
|
49
|
+
IntInput(
|
|
50
|
+
name="sample_size",
|
|
51
|
+
display_name="Sample Size",
|
|
52
|
+
info="For large datasets, number of items to sample from head/tail.",
|
|
53
|
+
value=1000,
|
|
54
|
+
advanced=True,
|
|
55
|
+
),
|
|
56
|
+
IntInput(
|
|
57
|
+
name="max_size",
|
|
58
|
+
display_name="Max Size",
|
|
59
|
+
info="Number of characters for the data to be considered large.",
|
|
60
|
+
value=30000,
|
|
61
|
+
advanced=True,
|
|
62
|
+
),
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
outputs = [
|
|
66
|
+
Output(
|
|
67
|
+
display_name="Output",
|
|
68
|
+
name="data_output",
|
|
69
|
+
method="process_as_data",
|
|
70
|
+
),
|
|
71
|
+
Output(
|
|
72
|
+
display_name="Output",
|
|
73
|
+
name="dataframe_output",
|
|
74
|
+
method="process_as_dataframe",
|
|
75
|
+
),
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
def get_data_structure(self, data):
|
|
79
|
+
"""Extract the structure of data, replacing values with their types."""
|
|
80
|
+
if isinstance(data, list):
|
|
81
|
+
# For lists, get structure of first item if available
|
|
82
|
+
if data:
|
|
83
|
+
return [self.get_data_structure(data[0])]
|
|
84
|
+
return []
|
|
85
|
+
if isinstance(data, dict):
|
|
86
|
+
return {k: self.get_data_structure(v) for k, v in data.items()}
|
|
87
|
+
# For primitive types, return the type name
|
|
88
|
+
return type(data).__name__
|
|
89
|
+
|
|
90
|
+
def _validate_lambda(self, lambda_text: str) -> bool:
|
|
91
|
+
"""Validate the provided lambda function text."""
|
|
92
|
+
# Return False if the lambda function does not start with 'lambda' or does not contain a colon
|
|
93
|
+
return lambda_text.strip().startswith("lambda") and ":" in lambda_text
|
|
94
|
+
|
|
95
|
+
async def _execute_lambda(self) -> Any:
|
|
96
|
+
self.log(str(self.data))
|
|
97
|
+
|
|
98
|
+
# Convert input to a unified format
|
|
99
|
+
if isinstance(self.data, list):
|
|
100
|
+
# Handle list of Data or DataFrame objects
|
|
101
|
+
combined_data = []
|
|
102
|
+
for item in self.data:
|
|
103
|
+
if isinstance(item, DataFrame):
|
|
104
|
+
# DataFrame to list of dicts
|
|
105
|
+
combined_data.extend(item.to_dict(orient="records"))
|
|
106
|
+
elif hasattr(item, "data"):
|
|
107
|
+
# Data object
|
|
108
|
+
if isinstance(item.data, dict):
|
|
109
|
+
combined_data.append(item.data)
|
|
110
|
+
elif isinstance(item.data, list):
|
|
111
|
+
combined_data.extend(item.data)
|
|
112
|
+
|
|
113
|
+
# If we have a single dict, unwrap it so lambdas can access it directly
|
|
114
|
+
if len(combined_data) == 1 and isinstance(combined_data[0], dict):
|
|
115
|
+
data = combined_data[0]
|
|
116
|
+
elif len(combined_data) == 0:
|
|
117
|
+
data = {}
|
|
118
|
+
else:
|
|
119
|
+
data = combined_data # type: ignore[assignment]
|
|
120
|
+
elif isinstance(self.data, DataFrame):
|
|
121
|
+
# Single DataFrame to list of dicts
|
|
122
|
+
data = self.data.to_dict(orient="records")
|
|
123
|
+
elif hasattr(self.data, "data"):
|
|
124
|
+
# Single Data object
|
|
125
|
+
data = self.data.data
|
|
126
|
+
else:
|
|
127
|
+
data = self.data
|
|
128
|
+
|
|
129
|
+
dump = json.dumps(data)
|
|
130
|
+
self.log(str(data))
|
|
131
|
+
|
|
132
|
+
llm = self.llm
|
|
133
|
+
instruction = self.filter_instruction
|
|
134
|
+
sample_size = self.sample_size
|
|
135
|
+
|
|
136
|
+
# Get data structure and samples
|
|
137
|
+
data_structure = self.get_data_structure(data)
|
|
138
|
+
dump_structure = json.dumps(data_structure)
|
|
139
|
+
self.log(dump_structure)
|
|
140
|
+
|
|
141
|
+
# For large datasets, sample from head and tail
|
|
142
|
+
if len(dump) > self.max_size:
|
|
143
|
+
data_sample = (
|
|
144
|
+
f"Data is too long to display... \n\n First lines (head): {dump[:sample_size]} \n\n"
|
|
145
|
+
f" Last lines (tail): {dump[-sample_size:]})"
|
|
146
|
+
)
|
|
147
|
+
else:
|
|
148
|
+
data_sample = dump
|
|
149
|
+
|
|
150
|
+
self.log(data_sample)
|
|
151
|
+
|
|
152
|
+
prompt = f"""Given this data structure and examples, create a Python lambda function that
|
|
153
|
+
implements the following instruction:
|
|
154
|
+
|
|
155
|
+
Data Structure:
|
|
156
|
+
{dump_structure}
|
|
157
|
+
|
|
158
|
+
Example Items:
|
|
159
|
+
{data_sample}
|
|
160
|
+
|
|
161
|
+
Instruction: {instruction}
|
|
162
|
+
|
|
163
|
+
Return ONLY the lambda function and nothing else. No need for ```python or whatever.
|
|
164
|
+
Just a string starting with lambda.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
response = await llm.ainvoke(prompt)
|
|
168
|
+
response_text = response.content if hasattr(response, "content") else str(response)
|
|
169
|
+
self.log(response_text)
|
|
170
|
+
|
|
171
|
+
# Extract lambda using regex
|
|
172
|
+
lambda_match = re.search(r"lambda\s+\w+\s*:.*?(?=\n|$)", response_text)
|
|
173
|
+
if not lambda_match:
|
|
174
|
+
msg = f"Could not find lambda in response: {response_text}"
|
|
175
|
+
raise ValueError(msg)
|
|
176
|
+
|
|
177
|
+
lambda_text = lambda_match.group().strip()
|
|
178
|
+
self.log(lambda_text)
|
|
179
|
+
|
|
180
|
+
# Validation is commented out as requested
|
|
181
|
+
if not self._validate_lambda(lambda_text):
|
|
182
|
+
msg = f"Invalid lambda format: {lambda_text}"
|
|
183
|
+
raise ValueError(msg)
|
|
184
|
+
|
|
185
|
+
# Create and apply the function
|
|
186
|
+
fn: Callable[[Any], Any] = eval(lambda_text) # noqa: S307
|
|
187
|
+
|
|
188
|
+
# Apply the lambda function to the data
|
|
189
|
+
return fn(data)
|
|
190
|
+
|
|
191
|
+
async def process_as_data(self) -> Data:
|
|
192
|
+
"""Process the data and return as a Data object."""
|
|
193
|
+
result = await self._execute_lambda()
|
|
194
|
+
|
|
195
|
+
# Convert result to Data based on type
|
|
196
|
+
if isinstance(result, dict):
|
|
197
|
+
return Data(data=result)
|
|
198
|
+
if isinstance(result, list):
|
|
199
|
+
return Data(data={"_results": result})
|
|
200
|
+
# For other types, convert to string
|
|
201
|
+
return Data(data={"text": str(result)})
|
|
202
|
+
|
|
203
|
+
async def process_as_dataframe(self) -> DataFrame:
|
|
204
|
+
"""Process the data and return as a DataFrame."""
|
|
205
|
+
result = await self._execute_lambda()
|
|
206
|
+
|
|
207
|
+
# Convert result to DataFrame based on type
|
|
208
|
+
if isinstance(result, list):
|
|
209
|
+
# Check if it's a list of dicts
|
|
210
|
+
if all(isinstance(item, dict) for item in result):
|
|
211
|
+
return DataFrame(result)
|
|
212
|
+
# List of non-dicts: wrap each value
|
|
213
|
+
return DataFrame([{"value": item} for item in result])
|
|
214
|
+
if isinstance(result, dict):
|
|
215
|
+
# Single dict becomes single-row DataFrame
|
|
216
|
+
return DataFrame([result])
|
|
217
|
+
# Other types: convert to string and wrap
|
|
218
|
+
return DataFrame([{"value": str(result)}])
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from lfx.custom import Component
|
|
4
|
+
from lfx.io import BoolInput, HandleInput, MessageInput, MessageTextInput, MultilineInput, Output, TableInput
|
|
5
|
+
from lfx.schema.message import Message
|
|
6
|
+
from lfx.schema.table import EditMode
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SmartRouterComponent(Component):
|
|
10
|
+
display_name = "Smart Router"
|
|
11
|
+
description = "Routes an input message using LLM-based categorization."
|
|
12
|
+
icon = "route"
|
|
13
|
+
name = "SmartRouter"
|
|
14
|
+
|
|
15
|
+
def __init__(self, **kwargs):
|
|
16
|
+
super().__init__(**kwargs)
|
|
17
|
+
self._matched_category = None
|
|
18
|
+
|
|
19
|
+
inputs = [
|
|
20
|
+
HandleInput(
|
|
21
|
+
name="llm",
|
|
22
|
+
display_name="Language Model",
|
|
23
|
+
info="LLM to use for categorization.",
|
|
24
|
+
input_types=["LanguageModel"],
|
|
25
|
+
required=True,
|
|
26
|
+
),
|
|
27
|
+
MessageTextInput(
|
|
28
|
+
name="input_text",
|
|
29
|
+
display_name="Input",
|
|
30
|
+
info="The primary text input for the operation.",
|
|
31
|
+
required=True,
|
|
32
|
+
),
|
|
33
|
+
TableInput(
|
|
34
|
+
name="routes",
|
|
35
|
+
display_name="Routes",
|
|
36
|
+
info=(
|
|
37
|
+
"Define the categories for routing. Each row should have a route/category name "
|
|
38
|
+
"and optionally a custom output value."
|
|
39
|
+
),
|
|
40
|
+
table_schema=[
|
|
41
|
+
{
|
|
42
|
+
"name": "route_category",
|
|
43
|
+
"display_name": "Route Name",
|
|
44
|
+
"type": "str",
|
|
45
|
+
"description": "Name for the route (used for both output name and category matching)",
|
|
46
|
+
"edit_mode": EditMode.INLINE,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "route_description",
|
|
50
|
+
"display_name": "Route Description",
|
|
51
|
+
"type": "str",
|
|
52
|
+
"description": "Description of when this route should be used (helps LLM understand the category)",
|
|
53
|
+
"default": "",
|
|
54
|
+
"edit_mode": EditMode.POPOVER,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "output_value",
|
|
58
|
+
"display_name": "Route Message (Optional)",
|
|
59
|
+
"type": "str",
|
|
60
|
+
"description": (
|
|
61
|
+
"Optional message to send when this route is matched."
|
|
62
|
+
"Leave empty to pass through the original input text."
|
|
63
|
+
),
|
|
64
|
+
"default": "",
|
|
65
|
+
"edit_mode": EditMode.POPOVER,
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
value=[
|
|
69
|
+
{
|
|
70
|
+
"route_category": "Positive",
|
|
71
|
+
"route_description": "Positive feedback, satisfaction, or compliments",
|
|
72
|
+
"output_value": "",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"route_category": "Negative",
|
|
76
|
+
"route_description": "Complaints, issues, or dissatisfaction",
|
|
77
|
+
"output_value": "",
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
real_time_refresh=True,
|
|
81
|
+
required=True,
|
|
82
|
+
),
|
|
83
|
+
MessageInput(
|
|
84
|
+
name="message",
|
|
85
|
+
display_name="Override Output",
|
|
86
|
+
info=(
|
|
87
|
+
"Optional override message that will replace both the Input and Output Value "
|
|
88
|
+
"for all routes when filled."
|
|
89
|
+
),
|
|
90
|
+
required=False,
|
|
91
|
+
advanced=True,
|
|
92
|
+
),
|
|
93
|
+
BoolInput(
|
|
94
|
+
name="enable_else_output",
|
|
95
|
+
display_name="Include Else Output",
|
|
96
|
+
info="Include an Else output for cases that don't match any route.",
|
|
97
|
+
value=False,
|
|
98
|
+
advanced=True,
|
|
99
|
+
),
|
|
100
|
+
MultilineInput(
|
|
101
|
+
name="custom_prompt",
|
|
102
|
+
display_name="Additional Instructions",
|
|
103
|
+
info=(
|
|
104
|
+
"Additional instructions for LLM-based categorization. "
|
|
105
|
+
"These will be added to the base prompt. "
|
|
106
|
+
"Use {input_text} for the input text and {routes} for the available categories."
|
|
107
|
+
),
|
|
108
|
+
advanced=True,
|
|
109
|
+
),
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
outputs: list[Output] = []
|
|
113
|
+
|
|
114
|
+
def update_outputs(self, frontend_node: dict, field_name: str, field_value: Any) -> dict:
|
|
115
|
+
"""Create a dynamic output for each category in the categories table."""
|
|
116
|
+
if field_name in {"routes", "enable_else_output"}:
|
|
117
|
+
frontend_node["outputs"] = []
|
|
118
|
+
|
|
119
|
+
# Get the routes data - either from field_value (if routes field) or from component state
|
|
120
|
+
routes_data = field_value if field_name == "routes" else getattr(self, "routes", [])
|
|
121
|
+
|
|
122
|
+
# Add a dynamic output for each category - all using the same method
|
|
123
|
+
for i, row in enumerate(routes_data):
|
|
124
|
+
route_category = row.get("route_category", f"Category {i + 1}")
|
|
125
|
+
frontend_node["outputs"].append(
|
|
126
|
+
Output(
|
|
127
|
+
display_name=route_category,
|
|
128
|
+
name=f"category_{i + 1}_result",
|
|
129
|
+
method="process_case",
|
|
130
|
+
group_outputs=True,
|
|
131
|
+
)
|
|
132
|
+
)
|
|
133
|
+
# Add default output only if enabled
|
|
134
|
+
if field_name == "enable_else_output":
|
|
135
|
+
enable_else = field_value
|
|
136
|
+
else:
|
|
137
|
+
enable_else = getattr(self, "enable_else_output", False)
|
|
138
|
+
|
|
139
|
+
if enable_else:
|
|
140
|
+
frontend_node["outputs"].append(
|
|
141
|
+
Output(display_name="Else", name="default_result", method="default_response", group_outputs=True)
|
|
142
|
+
)
|
|
143
|
+
return frontend_node
|
|
144
|
+
|
|
145
|
+
def process_case(self) -> Message:
|
|
146
|
+
"""Process all categories using LLM categorization and return message for matching category."""
|
|
147
|
+
# Clear any previous match state
|
|
148
|
+
self._matched_category = None
|
|
149
|
+
|
|
150
|
+
# Get categories and input text
|
|
151
|
+
categories = getattr(self, "routes", [])
|
|
152
|
+
input_text = getattr(self, "input_text", "")
|
|
153
|
+
|
|
154
|
+
# Find the matching category using LLM-based categorization
|
|
155
|
+
matched_category = None
|
|
156
|
+
llm = getattr(self, "llm", None)
|
|
157
|
+
|
|
158
|
+
if llm and categories:
|
|
159
|
+
# Create prompt for categorization
|
|
160
|
+
category_info = []
|
|
161
|
+
for i, category in enumerate(categories):
|
|
162
|
+
cat_name = category.get("route_category", f"Category {i + 1}")
|
|
163
|
+
cat_desc = category.get("route_description", "")
|
|
164
|
+
if cat_desc and cat_desc.strip():
|
|
165
|
+
category_info.append(f'"{cat_name}": {cat_desc}')
|
|
166
|
+
else:
|
|
167
|
+
category_info.append(f'"{cat_name}"')
|
|
168
|
+
|
|
169
|
+
categories_text = "\n".join([f"- {info}" for info in category_info if info])
|
|
170
|
+
|
|
171
|
+
# Create base prompt
|
|
172
|
+
base_prompt = (
|
|
173
|
+
f"You are a text classifier. Given the following text and categories, "
|
|
174
|
+
f"determine which category best matches the text.\n\n"
|
|
175
|
+
f'Text to classify: "{input_text}"\n\n'
|
|
176
|
+
f"Available categories:\n{categories_text}\n\n"
|
|
177
|
+
f"Respond with ONLY the exact category name that best matches the text. "
|
|
178
|
+
f'If none match well, respond with "NONE".\n\n'
|
|
179
|
+
f"Category:"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# Use custom prompt as additional instructions if provided
|
|
183
|
+
custom_prompt = getattr(self, "custom_prompt", "")
|
|
184
|
+
if custom_prompt and custom_prompt.strip():
|
|
185
|
+
self.status = "Using custom prompt as additional instructions"
|
|
186
|
+
# Format custom prompt with variables
|
|
187
|
+
# For the routes variable, create a simpler format for custom prompt usage
|
|
188
|
+
simple_routes = ", ".join(
|
|
189
|
+
[f'"{cat.get("route_category", f"Category {i + 1}")}"' for i, cat in enumerate(categories)]
|
|
190
|
+
)
|
|
191
|
+
formatted_custom = custom_prompt.format(input_text=input_text, routes=simple_routes)
|
|
192
|
+
# Combine base prompt with custom instructions
|
|
193
|
+
prompt = f"{base_prompt}\n\nAdditional Instructions:\n{formatted_custom}"
|
|
194
|
+
else:
|
|
195
|
+
self.status = "Using default prompt for LLM categorization"
|
|
196
|
+
prompt = base_prompt
|
|
197
|
+
|
|
198
|
+
# Log the final prompt being sent to LLM
|
|
199
|
+
self.status = f"Prompt sent to LLM:\n{prompt}"
|
|
200
|
+
|
|
201
|
+
try:
|
|
202
|
+
# Use the LLM to categorize
|
|
203
|
+
if hasattr(llm, "invoke"):
|
|
204
|
+
response = llm.invoke(prompt)
|
|
205
|
+
if hasattr(response, "content"):
|
|
206
|
+
categorization = response.content.strip().strip('"')
|
|
207
|
+
else:
|
|
208
|
+
categorization = str(response).strip().strip('"')
|
|
209
|
+
else:
|
|
210
|
+
categorization = str(llm(prompt)).strip().strip('"')
|
|
211
|
+
|
|
212
|
+
# Log the categorization process
|
|
213
|
+
self.status = f"LLM response: '{categorization}'"
|
|
214
|
+
|
|
215
|
+
# Find matching category based on LLM response
|
|
216
|
+
for i, category in enumerate(categories):
|
|
217
|
+
route_category = category.get("route_category", "")
|
|
218
|
+
|
|
219
|
+
# Log each comparison attempt
|
|
220
|
+
self.status = (
|
|
221
|
+
f"Comparing '{categorization}' with category {i + 1}: route_category='{route_category}'"
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
# Case-insensitive match
|
|
225
|
+
if categorization.lower() == route_category.lower():
|
|
226
|
+
matched_category = i
|
|
227
|
+
self.status = f"MATCH FOUND! Category {i + 1} matched with '{categorization}'"
|
|
228
|
+
break
|
|
229
|
+
|
|
230
|
+
if matched_category is None:
|
|
231
|
+
self.status = (
|
|
232
|
+
f"No match found for '{categorization}'. Available categories: "
|
|
233
|
+
f"{[category.get('route_category', '') for category in categories]}"
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
except RuntimeError as e:
|
|
237
|
+
self.status = f"Error in LLM categorization: {e!s}"
|
|
238
|
+
else:
|
|
239
|
+
self.status = "No LLM provided for categorization"
|
|
240
|
+
|
|
241
|
+
if matched_category is not None:
|
|
242
|
+
# Store the matched category for other outputs to check
|
|
243
|
+
self._matched_category = matched_category
|
|
244
|
+
|
|
245
|
+
# Stop all category outputs except the matched one
|
|
246
|
+
for i in range(len(categories)):
|
|
247
|
+
if i != matched_category:
|
|
248
|
+
self.stop(f"category_{i + 1}_result")
|
|
249
|
+
|
|
250
|
+
# Also stop the default output (if it exists)
|
|
251
|
+
enable_else = getattr(self, "enable_else_output", False)
|
|
252
|
+
if enable_else:
|
|
253
|
+
self.stop("default_result")
|
|
254
|
+
|
|
255
|
+
route_category = categories[matched_category].get("route_category", f"Category {matched_category + 1}")
|
|
256
|
+
self.status = f"Categorized as {route_category}"
|
|
257
|
+
|
|
258
|
+
# Check if there's an override output (takes precedence over everything)
|
|
259
|
+
override_output = getattr(self, "message", None)
|
|
260
|
+
if (
|
|
261
|
+
override_output
|
|
262
|
+
and hasattr(override_output, "text")
|
|
263
|
+
and override_output.text
|
|
264
|
+
and str(override_output.text).strip()
|
|
265
|
+
):
|
|
266
|
+
return Message(text=str(override_output.text))
|
|
267
|
+
if override_output and isinstance(override_output, str) and override_output.strip():
|
|
268
|
+
return Message(text=str(override_output))
|
|
269
|
+
|
|
270
|
+
# Check if there's a custom output value for this category
|
|
271
|
+
custom_output = categories[matched_category].get("output_value", "")
|
|
272
|
+
# Treat None, empty string, or whitespace as blank
|
|
273
|
+
if custom_output and str(custom_output).strip() and str(custom_output).strip().lower() != "none":
|
|
274
|
+
# Use custom output value
|
|
275
|
+
return Message(text=str(custom_output))
|
|
276
|
+
# Use input as default output
|
|
277
|
+
return Message(text=input_text)
|
|
278
|
+
# No match found, stop all category outputs
|
|
279
|
+
for i in range(len(categories)):
|
|
280
|
+
self.stop(f"category_{i + 1}_result")
|
|
281
|
+
|
|
282
|
+
# Check if else output is enabled
|
|
283
|
+
enable_else = getattr(self, "enable_else_output", False)
|
|
284
|
+
if enable_else:
|
|
285
|
+
# The default_response will handle the else case
|
|
286
|
+
self.stop("process_case")
|
|
287
|
+
return Message(text="")
|
|
288
|
+
# No else output, so no output at all
|
|
289
|
+
self.status = "No match found and Else output is disabled"
|
|
290
|
+
return Message(text="")
|
|
291
|
+
|
|
292
|
+
def default_response(self) -> Message:
|
|
293
|
+
"""Handle the else case when no conditions match."""
|
|
294
|
+
# Check if else output is enabled
|
|
295
|
+
enable_else = getattr(self, "enable_else_output", False)
|
|
296
|
+
if not enable_else:
|
|
297
|
+
self.status = "Else output is disabled"
|
|
298
|
+
return Message(text="")
|
|
299
|
+
|
|
300
|
+
# Clear any previous match state if not already set
|
|
301
|
+
if not hasattr(self, "_matched_category"):
|
|
302
|
+
self._matched_category = None
|
|
303
|
+
|
|
304
|
+
categories = getattr(self, "routes", [])
|
|
305
|
+
input_text = getattr(self, "input_text", "")
|
|
306
|
+
|
|
307
|
+
# Check if a match was already found in process_case
|
|
308
|
+
if hasattr(self, "_matched_category") and self._matched_category is not None:
|
|
309
|
+
self.status = (
|
|
310
|
+
f"Match already found in process_case (Category {self._matched_category + 1}), "
|
|
311
|
+
"stopping default_response"
|
|
312
|
+
)
|
|
313
|
+
self.stop("default_result")
|
|
314
|
+
return Message(text="")
|
|
315
|
+
|
|
316
|
+
# Check if any category matches using LLM categorization
|
|
317
|
+
has_match = False
|
|
318
|
+
llm = getattr(self, "llm", None)
|
|
319
|
+
|
|
320
|
+
if llm and categories:
|
|
321
|
+
try:
|
|
322
|
+
# Create prompt for categorization
|
|
323
|
+
category_info = []
|
|
324
|
+
for i, category in enumerate(categories):
|
|
325
|
+
cat_name = category.get("route_category", f"Category {i + 1}")
|
|
326
|
+
cat_desc = category.get("route_description", "")
|
|
327
|
+
if cat_desc and cat_desc.strip():
|
|
328
|
+
category_info.append(f'"{cat_name}": {cat_desc}')
|
|
329
|
+
else:
|
|
330
|
+
category_info.append(f'"{cat_name}"')
|
|
331
|
+
|
|
332
|
+
categories_text = "\n".join([f"- {info}" for info in category_info if info])
|
|
333
|
+
|
|
334
|
+
# Create base prompt
|
|
335
|
+
base_prompt = (
|
|
336
|
+
"You are a text classifier. Given the following text and categories, "
|
|
337
|
+
"determine which category best matches the text.\n\n"
|
|
338
|
+
f'Text to classify: "{input_text}"\n\n'
|
|
339
|
+
f"Available categories:\n{categories_text}\n\n"
|
|
340
|
+
"Respond with ONLY the exact category name that best matches the text. "
|
|
341
|
+
'If none match well, respond with "NONE".\n\n'
|
|
342
|
+
"Category:"
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
# Use custom prompt as additional instructions if provided
|
|
346
|
+
custom_prompt = getattr(self, "custom_prompt", "")
|
|
347
|
+
if custom_prompt and custom_prompt.strip():
|
|
348
|
+
self.status = "Using custom prompt as additional instructions (default check)"
|
|
349
|
+
# Format custom prompt with variables
|
|
350
|
+
# For the routes variable, create a simpler format for custom prompt usage
|
|
351
|
+
simple_routes = ", ".join(
|
|
352
|
+
[f'"{cat.get("route_category", f"Category {i + 1}")}"' for i, cat in enumerate(categories)]
|
|
353
|
+
)
|
|
354
|
+
formatted_custom = custom_prompt.format(input_text=input_text, routes=simple_routes)
|
|
355
|
+
# Combine base prompt with custom instructions
|
|
356
|
+
prompt = f"{base_prompt}\n\nAdditional Instructions:\n{formatted_custom}"
|
|
357
|
+
else:
|
|
358
|
+
self.status = "Using default prompt for LLM categorization (default check)"
|
|
359
|
+
prompt = base_prompt
|
|
360
|
+
|
|
361
|
+
# Log the final prompt being sent to LLM for default check
|
|
362
|
+
self.status = f"Default check - Prompt sent to LLM:\n{prompt}"
|
|
363
|
+
|
|
364
|
+
# Use the LLM to categorize
|
|
365
|
+
if hasattr(llm, "invoke"):
|
|
366
|
+
response = llm.invoke(prompt)
|
|
367
|
+
if hasattr(response, "content"):
|
|
368
|
+
categorization = response.content.strip().strip('"')
|
|
369
|
+
else:
|
|
370
|
+
categorization = str(response).strip().strip('"')
|
|
371
|
+
else:
|
|
372
|
+
categorization = str(llm(prompt)).strip().strip('"')
|
|
373
|
+
|
|
374
|
+
# Log the categorization process for default check
|
|
375
|
+
self.status = f"Default check - LLM response: '{categorization}'"
|
|
376
|
+
|
|
377
|
+
# Check if LLM response matches any category
|
|
378
|
+
for i, category in enumerate(categories):
|
|
379
|
+
route_category = category.get("route_category", "")
|
|
380
|
+
|
|
381
|
+
# Log each comparison attempt
|
|
382
|
+
self.status = (
|
|
383
|
+
f"Default check - Comparing '{categorization}' with category {i + 1}: "
|
|
384
|
+
f"route_category='{route_category}'"
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
if categorization.lower() == route_category.lower():
|
|
388
|
+
has_match = True
|
|
389
|
+
self.status = f"Default check - MATCH FOUND! Category {i + 1} matched with '{categorization}'"
|
|
390
|
+
break
|
|
391
|
+
|
|
392
|
+
if not has_match:
|
|
393
|
+
self.status = (
|
|
394
|
+
f"Default check - No match found for '{categorization}'. "
|
|
395
|
+
f"Available categories: "
|
|
396
|
+
f"{[category.get('route_category', '') for category in categories]}"
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
except RuntimeError:
|
|
400
|
+
pass # If there's an error, treat as no match
|
|
401
|
+
|
|
402
|
+
if has_match:
|
|
403
|
+
# A case matches, stop this output
|
|
404
|
+
self.stop("default_result")
|
|
405
|
+
return Message(text="")
|
|
406
|
+
|
|
407
|
+
# No case matches, check for override output first, then use input as default
|
|
408
|
+
override_output = getattr(self, "message", None)
|
|
409
|
+
if (
|
|
410
|
+
override_output
|
|
411
|
+
and hasattr(override_output, "text")
|
|
412
|
+
and override_output.text
|
|
413
|
+
and str(override_output.text).strip()
|
|
414
|
+
):
|
|
415
|
+
self.status = "Routed to Else (no match) - using override output"
|
|
416
|
+
return Message(text=str(override_output.text))
|
|
417
|
+
if override_output and isinstance(override_output, str) and override_output.strip():
|
|
418
|
+
self.status = "Routed to Else (no match) - using override output"
|
|
419
|
+
return Message(text=str(override_output))
|
|
420
|
+
self.status = "Routed to Else (no match) - using input as default"
|
|
421
|
+
return Message(text=input_text)
|