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
lfx/schema/artifact.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from collections.abc import Generator
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
from fastapi.encoders import jsonable_encoder
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
from lfx.log.logger import logger
|
|
8
|
+
from lfx.schema.data import Data
|
|
9
|
+
from lfx.schema.dataframe import DataFrame
|
|
10
|
+
from lfx.schema.encoders import CUSTOM_ENCODERS
|
|
11
|
+
from lfx.schema.message import Message
|
|
12
|
+
from lfx.serialization.serialization import serialize
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ArtifactType(str, Enum):
|
|
16
|
+
TEXT = "text"
|
|
17
|
+
DATA = "data"
|
|
18
|
+
OBJECT = "object"
|
|
19
|
+
ARRAY = "array"
|
|
20
|
+
STREAM = "stream"
|
|
21
|
+
UNKNOWN = "unknown"
|
|
22
|
+
MESSAGE = "message"
|
|
23
|
+
RECORD = "record"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_artifact_type(value, build_result=None) -> str:
|
|
27
|
+
result = ArtifactType.UNKNOWN
|
|
28
|
+
match value:
|
|
29
|
+
case Message():
|
|
30
|
+
if not isinstance(value.text, str):
|
|
31
|
+
enum_value = get_artifact_type(value.text)
|
|
32
|
+
result = ArtifactType(enum_value)
|
|
33
|
+
else:
|
|
34
|
+
result = ArtifactType.MESSAGE
|
|
35
|
+
case Data():
|
|
36
|
+
enum_value = get_artifact_type(value.data)
|
|
37
|
+
result = ArtifactType(enum_value)
|
|
38
|
+
|
|
39
|
+
case str():
|
|
40
|
+
result = ArtifactType.TEXT
|
|
41
|
+
|
|
42
|
+
case dict():
|
|
43
|
+
result = ArtifactType.OBJECT
|
|
44
|
+
|
|
45
|
+
case list() | DataFrame():
|
|
46
|
+
result = ArtifactType.ARRAY
|
|
47
|
+
if result == ArtifactType.UNKNOWN and (
|
|
48
|
+
(build_result and isinstance(build_result, Generator))
|
|
49
|
+
or (isinstance(value, Message) and isinstance(value.text, Generator))
|
|
50
|
+
):
|
|
51
|
+
result = ArtifactType.STREAM
|
|
52
|
+
|
|
53
|
+
return result.value
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _to_list_of_dicts(raw):
|
|
57
|
+
raw_ = []
|
|
58
|
+
for item in raw:
|
|
59
|
+
if hasattr(item, "dict") or hasattr(item, "model_dump"):
|
|
60
|
+
raw_.append(serialize(item))
|
|
61
|
+
else:
|
|
62
|
+
raw_.append(str(item))
|
|
63
|
+
return raw_
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def post_process_raw(raw, artifact_type: str):
|
|
67
|
+
default_message = "Built Successfully ✨"
|
|
68
|
+
|
|
69
|
+
if artifact_type == ArtifactType.STREAM.value:
|
|
70
|
+
raw = ""
|
|
71
|
+
elif artifact_type == ArtifactType.ARRAY.value:
|
|
72
|
+
raw = raw.to_dict(orient="records") if isinstance(raw, DataFrame) else _to_list_of_dicts(raw)
|
|
73
|
+
elif artifact_type == ArtifactType.UNKNOWN.value and raw is not None:
|
|
74
|
+
if isinstance(raw, BaseModel | dict):
|
|
75
|
+
try:
|
|
76
|
+
raw = jsonable_encoder(raw, custom_encoder=CUSTOM_ENCODERS)
|
|
77
|
+
artifact_type = ArtifactType.OBJECT.value
|
|
78
|
+
except Exception: # noqa: BLE001
|
|
79
|
+
logger.debug(f"Error converting to json: {raw} ({type(raw)})", exc_info=True)
|
|
80
|
+
raw = default_message
|
|
81
|
+
else:
|
|
82
|
+
raw = default_message
|
|
83
|
+
return raw, artifact_type
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Discriminator, Field, Tag, field_serializer, field_validator
|
|
4
|
+
from typing_extensions import TypedDict
|
|
5
|
+
|
|
6
|
+
from .content_types import CodeContent, ErrorContent, JSONContent, MediaContent, TextContent, ToolContent
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _get_type(d: dict | BaseModel) -> str | None:
|
|
10
|
+
if isinstance(d, dict):
|
|
11
|
+
return d.get("type")
|
|
12
|
+
return getattr(d, "type", None)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Create a union type of all content types
|
|
16
|
+
ContentType = Annotated[
|
|
17
|
+
Annotated[ToolContent, Tag("tool_use")]
|
|
18
|
+
| Annotated[ErrorContent, Tag("error")]
|
|
19
|
+
| Annotated[TextContent, Tag("text")]
|
|
20
|
+
| Annotated[MediaContent, Tag("media")]
|
|
21
|
+
| Annotated[CodeContent, Tag("code")]
|
|
22
|
+
| Annotated[JSONContent, Tag("json")],
|
|
23
|
+
Discriminator(_get_type),
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ContentBlock(BaseModel):
|
|
28
|
+
"""A block of content that can contain different types of content."""
|
|
29
|
+
|
|
30
|
+
title: str
|
|
31
|
+
contents: list[ContentType]
|
|
32
|
+
allow_markdown: bool = Field(default=True)
|
|
33
|
+
media_url: list[str] | None = None
|
|
34
|
+
|
|
35
|
+
def __init__(self, **data) -> None:
|
|
36
|
+
super().__init__(**data)
|
|
37
|
+
schema_dict = self.__pydantic_core_schema__["schema"]
|
|
38
|
+
if "fields" in schema_dict:
|
|
39
|
+
fields = schema_dict["fields"]
|
|
40
|
+
elif "schema" in schema_dict:
|
|
41
|
+
fields = schema_dict["schema"]["fields"]
|
|
42
|
+
fields_with_default = (f for f, d in fields.items() if "default" in d["schema"])
|
|
43
|
+
self.model_fields_set.update(fields_with_default)
|
|
44
|
+
|
|
45
|
+
@field_validator("contents", mode="before")
|
|
46
|
+
@classmethod
|
|
47
|
+
def validate_contents(cls, v) -> list[ContentType]:
|
|
48
|
+
if isinstance(v, dict):
|
|
49
|
+
msg = "Contents must be a list of ContentTypes"
|
|
50
|
+
raise TypeError(msg)
|
|
51
|
+
return [v] if isinstance(v, BaseModel) else v
|
|
52
|
+
|
|
53
|
+
@field_serializer("contents")
|
|
54
|
+
def serialize_contents(self, value) -> list[dict]:
|
|
55
|
+
return [v.model_dump() for v in value]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class ContentBlockDict(TypedDict):
|
|
59
|
+
title: str
|
|
60
|
+
contents: list[dict]
|
|
61
|
+
allow_markdown: bool
|
|
62
|
+
media_url: list[str] | None
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from typing import Any, Literal
|
|
2
|
+
|
|
3
|
+
from fastapi.encoders import jsonable_encoder
|
|
4
|
+
from pydantic import BaseModel, ConfigDict, Field, model_serializer
|
|
5
|
+
from typing_extensions import TypedDict
|
|
6
|
+
|
|
7
|
+
from lfx.schema.encoders import CUSTOM_ENCODERS
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class HeaderDict(TypedDict, total=False):
|
|
11
|
+
title: str | None
|
|
12
|
+
icon: str | None
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BaseContent(BaseModel):
|
|
16
|
+
"""Base class for all content types."""
|
|
17
|
+
|
|
18
|
+
type: str = Field(..., description="Type of the content")
|
|
19
|
+
duration: int | None = None
|
|
20
|
+
header: HeaderDict | None = Field(default_factory=dict)
|
|
21
|
+
|
|
22
|
+
def to_dict(self) -> dict[str, Any]:
|
|
23
|
+
return self.model_dump()
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def from_dict(cls, data: dict[str, Any]) -> "BaseContent":
|
|
27
|
+
return cls(**data)
|
|
28
|
+
|
|
29
|
+
@model_serializer(mode="wrap")
|
|
30
|
+
def serialize_model(self, nxt) -> dict[str, Any]:
|
|
31
|
+
try:
|
|
32
|
+
dump = nxt(self)
|
|
33
|
+
return jsonable_encoder(dump, custom_encoder=CUSTOM_ENCODERS)
|
|
34
|
+
except Exception: # noqa: BLE001
|
|
35
|
+
return nxt(self)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ErrorContent(BaseContent):
|
|
39
|
+
"""Content type for error messages."""
|
|
40
|
+
|
|
41
|
+
type: Literal["error"] = Field(default="error")
|
|
42
|
+
component: str | None = None
|
|
43
|
+
field: str | None = None
|
|
44
|
+
reason: str | None = None
|
|
45
|
+
solution: str | None = None
|
|
46
|
+
traceback: str | None = None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class TextContent(BaseContent):
|
|
50
|
+
"""Content type for simple text content."""
|
|
51
|
+
|
|
52
|
+
type: Literal["text"] = Field(default="text")
|
|
53
|
+
text: str
|
|
54
|
+
duration: int | None = None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class MediaContent(BaseContent):
|
|
58
|
+
"""Content type for media content."""
|
|
59
|
+
|
|
60
|
+
type: Literal["media"] = Field(default="media")
|
|
61
|
+
urls: list[str]
|
|
62
|
+
caption: str | None = None
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class JSONContent(BaseContent):
|
|
66
|
+
"""Content type for JSON content."""
|
|
67
|
+
|
|
68
|
+
type: Literal["json"] = Field(default="json")
|
|
69
|
+
data: dict[str, Any]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class CodeContent(BaseContent):
|
|
73
|
+
"""Content type for code snippets."""
|
|
74
|
+
|
|
75
|
+
type: Literal["code"] = Field(default="code")
|
|
76
|
+
code: str
|
|
77
|
+
language: str
|
|
78
|
+
title: str | None = None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class ToolContent(BaseContent):
|
|
82
|
+
"""Content type for tool start content."""
|
|
83
|
+
|
|
84
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
85
|
+
|
|
86
|
+
type: Literal["tool_use"] = Field(default="tool_use")
|
|
87
|
+
name: str | None = None
|
|
88
|
+
tool_input: dict[str, Any] = Field(default_factory=dict, alias="input")
|
|
89
|
+
output: Any | None = None
|
|
90
|
+
error: Any | None = None
|
|
91
|
+
duration: int | None = None
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Cross-module BaseModel for handling re-exported classes.
|
|
2
|
+
|
|
3
|
+
This module provides a metaclass and base model that enable isinstance checks
|
|
4
|
+
to work across module boundaries for Pydantic models. This is particularly useful
|
|
5
|
+
when the same class is re-exported from different modules (e.g., lfx.Message vs
|
|
6
|
+
langflow.schema.Message) but Python's isinstance() checks fail due to different
|
|
7
|
+
module paths.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from pydantic import BaseModel
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CrossModuleMeta(type(BaseModel)): # type: ignore[misc]
|
|
18
|
+
"""Metaclass that enables cross-module isinstance checks for Pydantic models.
|
|
19
|
+
|
|
20
|
+
This metaclass overrides __instancecheck__ to perform structural type checking
|
|
21
|
+
based on the model's fields rather than strict class identity. This allows
|
|
22
|
+
instances of the same model from different module paths to be recognized as
|
|
23
|
+
compatible.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __instancecheck__(cls, instance: Any) -> bool:
|
|
27
|
+
"""Check if instance is compatible with this class across module boundaries.
|
|
28
|
+
|
|
29
|
+
First performs a standard isinstance check. If that fails, falls back to
|
|
30
|
+
checking if the instance has all required Pydantic model attributes and
|
|
31
|
+
a compatible set of model fields.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
instance: The object to check.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
bool: True if instance is compatible with this class.
|
|
38
|
+
"""
|
|
39
|
+
# First try standard isinstance check
|
|
40
|
+
if type.__instancecheck__(cls, instance):
|
|
41
|
+
return True
|
|
42
|
+
|
|
43
|
+
# If that fails, check for cross-module compatibility
|
|
44
|
+
# An object is cross-module compatible if it:
|
|
45
|
+
# 1. Has model_fields attribute (is a Pydantic model)
|
|
46
|
+
# 2. Has the same __class__.__name__
|
|
47
|
+
# 3. Has compatible model fields
|
|
48
|
+
if not hasattr(instance, "model_fields"):
|
|
49
|
+
return False
|
|
50
|
+
|
|
51
|
+
# Check if class names match
|
|
52
|
+
if instance.__class__.__name__ != cls.__name__:
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
# Check if the instance has all required fields from cls
|
|
56
|
+
cls_fields = set(cls.model_fields.keys()) if hasattr(cls, "model_fields") else set()
|
|
57
|
+
instance_fields = set(instance.model_fields.keys())
|
|
58
|
+
|
|
59
|
+
# The instance must have at least the same fields as the class
|
|
60
|
+
# (it can have more, but not fewer required fields)
|
|
61
|
+
return cls_fields.issubset(instance_fields)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class CrossModuleModel(BaseModel, metaclass=CrossModuleMeta):
|
|
65
|
+
"""Base Pydantic model with cross-module isinstance support.
|
|
66
|
+
|
|
67
|
+
This class should be used as the base for models that may be re-exported
|
|
68
|
+
from different modules. It enables isinstance() checks to work across
|
|
69
|
+
module boundaries by using structural type checking.
|
|
70
|
+
|
|
71
|
+
Example:
|
|
72
|
+
>>> class Message(CrossModuleModel):
|
|
73
|
+
... text: str
|
|
74
|
+
...
|
|
75
|
+
>>> # Even if Message is imported from different paths:
|
|
76
|
+
>>> from lfx.schema.message import Message as LfxMessage
|
|
77
|
+
>>> from langflow.schema import Message as LangflowMessage
|
|
78
|
+
>>> msg = LfxMessage(text="hello")
|
|
79
|
+
>>> isinstance(msg, LangflowMessage) # True (with cross-module support)
|
|
80
|
+
"""
|
lfx/schema/data.py
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"""Lightweight Data class for lfx package - contains only methods with no langflow dependencies."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import copy
|
|
6
|
+
import json
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
from decimal import Decimal
|
|
9
|
+
from typing import TYPE_CHECKING, cast
|
|
10
|
+
from uuid import UUID
|
|
11
|
+
|
|
12
|
+
from langchain_core.documents import Document
|
|
13
|
+
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage
|
|
14
|
+
from pydantic import BaseModel, ConfigDict, model_serializer, model_validator
|
|
15
|
+
|
|
16
|
+
from lfx.log.logger import logger
|
|
17
|
+
from lfx.schema.cross_module import CrossModuleModel
|
|
18
|
+
from lfx.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER
|
|
19
|
+
from lfx.utils.image import create_image_content_dict
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from lfx.schema.dataframe import DataFrame
|
|
23
|
+
from lfx.schema.message import Message
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Data(CrossModuleModel):
|
|
27
|
+
"""Represents a record with text and optional data.
|
|
28
|
+
|
|
29
|
+
Attributes:
|
|
30
|
+
data (dict, optional): Additional data associated with the record.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
model_config = ConfigDict(validate_assignment=True)
|
|
34
|
+
|
|
35
|
+
text_key: str = "text"
|
|
36
|
+
data: dict = {}
|
|
37
|
+
default_value: str | None = ""
|
|
38
|
+
|
|
39
|
+
@model_validator(mode="before")
|
|
40
|
+
@classmethod
|
|
41
|
+
def validate_data(cls, values):
|
|
42
|
+
if not isinstance(values, dict):
|
|
43
|
+
msg = "Data must be a dictionary"
|
|
44
|
+
raise ValueError(msg) # noqa: TRY004
|
|
45
|
+
if "data" not in values or values["data"] is None:
|
|
46
|
+
values["data"] = {}
|
|
47
|
+
if not isinstance(values["data"], dict):
|
|
48
|
+
msg = (
|
|
49
|
+
f"Invalid data format: expected dictionary but got {type(values).__name__}."
|
|
50
|
+
" This will raise an error in version langflow==1.3.0."
|
|
51
|
+
)
|
|
52
|
+
logger.warning(msg)
|
|
53
|
+
# Any other keyword should be added to the data dictionary
|
|
54
|
+
for key in values:
|
|
55
|
+
if key not in values["data"] and key not in {"text_key", "data", "default_value"}:
|
|
56
|
+
values["data"][key] = values[key]
|
|
57
|
+
return values
|
|
58
|
+
|
|
59
|
+
@model_serializer(mode="plain", when_used="json")
|
|
60
|
+
def serialize_model(self):
|
|
61
|
+
return {k: v.to_json() if hasattr(v, "to_json") else v for k, v in self.data.items()}
|
|
62
|
+
|
|
63
|
+
def get_text(self):
|
|
64
|
+
"""Retrieves the text value from the data dictionary.
|
|
65
|
+
|
|
66
|
+
If the text key is present in the data dictionary, the corresponding value is returned.
|
|
67
|
+
Otherwise, the default value is returned.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
The text value from the data dictionary or the default value.
|
|
71
|
+
"""
|
|
72
|
+
return self.data.get(self.text_key, self.default_value)
|
|
73
|
+
|
|
74
|
+
def set_text(self, text: str | None) -> str:
|
|
75
|
+
r"""Sets the text value in the data dictionary.
|
|
76
|
+
|
|
77
|
+
The object's `text` value is set to `text parameter as given, with the following modifications:
|
|
78
|
+
|
|
79
|
+
- `text` value of `None` is converted to an empty string.
|
|
80
|
+
- `text` value is converted to `str` type.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
text (str): The text to be set in the data dictionary.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
str: The text value that was set in the data dictionary.
|
|
87
|
+
"""
|
|
88
|
+
new_text = "" if text is None else str(text)
|
|
89
|
+
self.data[self.text_key] = new_text
|
|
90
|
+
return new_text
|
|
91
|
+
|
|
92
|
+
@classmethod
|
|
93
|
+
def from_document(cls, document: Document) -> Data:
|
|
94
|
+
"""Converts a Document to a Data.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
document (Document): The Document to convert.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Data: The converted Data.
|
|
101
|
+
"""
|
|
102
|
+
data = document.metadata
|
|
103
|
+
data["text"] = document.page_content
|
|
104
|
+
return cls(data=data, text_key="text")
|
|
105
|
+
|
|
106
|
+
@classmethod
|
|
107
|
+
def from_lc_message(cls, message: BaseMessage) -> Data:
|
|
108
|
+
"""Converts a BaseMessage to a Data.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
message (BaseMessage): The BaseMessage to convert.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Data: The converted Data.
|
|
115
|
+
"""
|
|
116
|
+
data: dict = {"text": message.content}
|
|
117
|
+
data["metadata"] = cast("dict", message.to_json())
|
|
118
|
+
return cls(data=data, text_key="text")
|
|
119
|
+
|
|
120
|
+
def __add__(self, other: Data) -> Data:
|
|
121
|
+
"""Combines the data of two data by attempting to add values for overlapping keys.
|
|
122
|
+
|
|
123
|
+
Combines the data of two data by attempting to add values for overlapping keys
|
|
124
|
+
for all types that support the addition operation. Falls back to the value from 'other'
|
|
125
|
+
record when addition is not supported.
|
|
126
|
+
"""
|
|
127
|
+
combined_data = self.data.copy()
|
|
128
|
+
for key, value in other.data.items():
|
|
129
|
+
# If the key exists in both data and both values support the addition operation
|
|
130
|
+
if key in combined_data:
|
|
131
|
+
try:
|
|
132
|
+
combined_data[key] += value
|
|
133
|
+
except TypeError:
|
|
134
|
+
# Fallback: Use the value from 'other' record if addition is not supported
|
|
135
|
+
combined_data[key] = value
|
|
136
|
+
else:
|
|
137
|
+
# If the key is not in the first record, simply add it
|
|
138
|
+
combined_data[key] = value
|
|
139
|
+
|
|
140
|
+
return Data(data=combined_data)
|
|
141
|
+
|
|
142
|
+
def to_lc_document(self) -> Document:
|
|
143
|
+
"""Converts the Data to a Document.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
Document: The converted Document.
|
|
147
|
+
"""
|
|
148
|
+
data_copy = self.data.copy()
|
|
149
|
+
text = data_copy.pop(self.text_key, self.default_value)
|
|
150
|
+
if isinstance(text, str):
|
|
151
|
+
return Document(page_content=text, metadata=data_copy)
|
|
152
|
+
return Document(page_content=str(text), metadata=data_copy)
|
|
153
|
+
|
|
154
|
+
def to_lc_message(
|
|
155
|
+
self,
|
|
156
|
+
) -> BaseMessage:
|
|
157
|
+
"""Converts the Data to a BaseMessage.
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
BaseMessage: The converted BaseMessage.
|
|
161
|
+
"""
|
|
162
|
+
# The idea of this function is to be a helper to convert a Data to a BaseMessage
|
|
163
|
+
# It will use the "sender" key to determine if the message is Human or AI
|
|
164
|
+
# If the key is not present, it will default to AI
|
|
165
|
+
# But first we check if all required keys are present in the data dictionary
|
|
166
|
+
# they are: "text", "sender"
|
|
167
|
+
if not all(key in self.data for key in ["text", "sender"]):
|
|
168
|
+
msg = f"Missing required keys ('text', 'sender') in Data: {self.data}"
|
|
169
|
+
raise ValueError(msg)
|
|
170
|
+
sender = self.data.get("sender", MESSAGE_SENDER_AI)
|
|
171
|
+
text = self.data.get("text", "")
|
|
172
|
+
files = self.data.get("files", [])
|
|
173
|
+
if sender == MESSAGE_SENDER_USER:
|
|
174
|
+
if files:
|
|
175
|
+
from lfx.schema.image import get_file_paths
|
|
176
|
+
|
|
177
|
+
resolved_file_paths = get_file_paths(files)
|
|
178
|
+
contents = [create_image_content_dict(file_path) for file_path in resolved_file_paths]
|
|
179
|
+
# add to the beginning of the list
|
|
180
|
+
contents.insert(0, {"type": "text", "text": text})
|
|
181
|
+
human_message = HumanMessage(content=contents)
|
|
182
|
+
else:
|
|
183
|
+
human_message = HumanMessage(
|
|
184
|
+
content=[{"type": "text", "text": text}],
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
return human_message
|
|
188
|
+
|
|
189
|
+
return AIMessage(content=text)
|
|
190
|
+
|
|
191
|
+
def __getattr__(self, key):
|
|
192
|
+
"""Allows attribute-like access to the data dictionary."""
|
|
193
|
+
try:
|
|
194
|
+
if key.startswith("__"):
|
|
195
|
+
return self.__getattribute__(key)
|
|
196
|
+
if key in {"data", "text_key"} or key.startswith("_"):
|
|
197
|
+
return super().__getattr__(key)
|
|
198
|
+
return self.data[key]
|
|
199
|
+
except KeyError as e:
|
|
200
|
+
# Fallback to default behavior to raise AttributeError for undefined attributes
|
|
201
|
+
msg = f"'{type(self).__name__}' object has no attribute '{key}'"
|
|
202
|
+
raise AttributeError(msg) from e
|
|
203
|
+
|
|
204
|
+
def __setattr__(self, key, value) -> None:
|
|
205
|
+
"""Set attribute-like values in the data dictionary.
|
|
206
|
+
|
|
207
|
+
Allows attribute-like setting of values in the data dictionary.
|
|
208
|
+
while still allowing direct assignment to class attributes.
|
|
209
|
+
"""
|
|
210
|
+
if key in {"data", "text_key"} or key.startswith("_"):
|
|
211
|
+
super().__setattr__(key, value)
|
|
212
|
+
elif key in self.model_fields:
|
|
213
|
+
self.data[key] = value
|
|
214
|
+
super().__setattr__(key, value)
|
|
215
|
+
else:
|
|
216
|
+
self.data[key] = value
|
|
217
|
+
|
|
218
|
+
def __delattr__(self, key) -> None:
|
|
219
|
+
"""Allows attribute-like deletion from the data dictionary."""
|
|
220
|
+
if key in {"data", "text_key"} or key.startswith("_"):
|
|
221
|
+
super().__delattr__(key)
|
|
222
|
+
else:
|
|
223
|
+
del self.data[key]
|
|
224
|
+
|
|
225
|
+
def __deepcopy__(self, memo):
|
|
226
|
+
"""Custom deepcopy implementation to handle copying of the Data object."""
|
|
227
|
+
# Create a new Data object with a deep copy of the data dictionary
|
|
228
|
+
return Data(data=copy.deepcopy(self.data, memo), text_key=self.text_key, default_value=self.default_value)
|
|
229
|
+
|
|
230
|
+
# check which attributes the Data has by checking the keys in the data dictionary
|
|
231
|
+
def __dir__(self):
|
|
232
|
+
return super().__dir__() + list(self.data.keys())
|
|
233
|
+
|
|
234
|
+
def __str__(self) -> str:
|
|
235
|
+
# return a JSON string representation of the Data atributes
|
|
236
|
+
try:
|
|
237
|
+
data = {k: v.to_json() if hasattr(v, "to_json") else v for k, v in self.data.items()}
|
|
238
|
+
return serialize_data(data) # use the custom serializer
|
|
239
|
+
except Exception: # noqa: BLE001
|
|
240
|
+
logger.debug("Error converting Data to JSON", exc_info=True)
|
|
241
|
+
return str(self.data)
|
|
242
|
+
|
|
243
|
+
def __contains__(self, key) -> bool:
|
|
244
|
+
return key in self.data
|
|
245
|
+
|
|
246
|
+
def __eq__(self, /, other):
|
|
247
|
+
return isinstance(other, Data) and self.data == other.data
|
|
248
|
+
|
|
249
|
+
def filter_data(self, filter_str: str) -> Data:
|
|
250
|
+
"""Filters the data dictionary based on the filter string.
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
filter_str (str): The filter string to apply to the data dictionary.
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
Data: The filtered Data.
|
|
257
|
+
"""
|
|
258
|
+
from lfx.template.utils import apply_json_filter
|
|
259
|
+
|
|
260
|
+
return apply_json_filter(self.data, filter_str)
|
|
261
|
+
|
|
262
|
+
def to_message(self) -> Message:
|
|
263
|
+
from lfx.schema.message import Message # Local import to avoid circular import
|
|
264
|
+
|
|
265
|
+
if self.text_key in self.data:
|
|
266
|
+
return Message(text=self.get_text())
|
|
267
|
+
return Message(text=str(self.data))
|
|
268
|
+
|
|
269
|
+
def to_dataframe(self) -> DataFrame:
|
|
270
|
+
from lfx.schema.dataframe import DataFrame # Local import to avoid circular import
|
|
271
|
+
|
|
272
|
+
data_dict = self.data
|
|
273
|
+
# If data contains only one key and the value is a list of dictionaries, convert to DataFrame
|
|
274
|
+
if (
|
|
275
|
+
len(data_dict) == 1
|
|
276
|
+
and isinstance(next(iter(data_dict.values())), list)
|
|
277
|
+
and all(isinstance(item, dict) for item in next(iter(data_dict.values())))
|
|
278
|
+
):
|
|
279
|
+
return DataFrame(data=next(iter(data_dict.values())))
|
|
280
|
+
return DataFrame(data=[self])
|
|
281
|
+
|
|
282
|
+
def __repr__(self) -> str:
|
|
283
|
+
"""Return string representation of the Data object."""
|
|
284
|
+
return f"Data(text_key={self.text_key!r}, data={self.data!r}, default_value={self.default_value!r})"
|
|
285
|
+
|
|
286
|
+
def __hash__(self) -> int:
|
|
287
|
+
"""Return hash of the Data object based on its string representation."""
|
|
288
|
+
return hash(self.__repr__())
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def custom_serializer(obj):
|
|
292
|
+
if isinstance(obj, datetime):
|
|
293
|
+
utc_date = obj.replace(tzinfo=timezone.utc)
|
|
294
|
+
return utc_date.strftime("%Y-%m-%d %H:%M:%S %Z")
|
|
295
|
+
if isinstance(obj, Decimal):
|
|
296
|
+
return float(obj)
|
|
297
|
+
if isinstance(obj, UUID):
|
|
298
|
+
return str(obj)
|
|
299
|
+
if isinstance(obj, BaseModel):
|
|
300
|
+
return obj.model_dump()
|
|
301
|
+
if isinstance(obj, bytes):
|
|
302
|
+
return obj.decode("utf-8", errors="replace")
|
|
303
|
+
# Add more custom serialization rules as needed
|
|
304
|
+
msg = f"Type {type(obj)} not serializable"
|
|
305
|
+
raise TypeError(msg)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def serialize_data(data):
|
|
309
|
+
return json.dumps(data, indent=4, default=custom_serializer)
|