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,166 @@
|
|
|
1
|
+
"""Cache service implementations for lfx."""
|
|
2
|
+
|
|
3
|
+
import pickle
|
|
4
|
+
import threading
|
|
5
|
+
import time
|
|
6
|
+
from collections import OrderedDict
|
|
7
|
+
from typing import Generic, Union
|
|
8
|
+
|
|
9
|
+
from lfx.services.cache.base import CacheService, LockType
|
|
10
|
+
from lfx.services.cache.utils import CACHE_MISS
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ThreadingInMemoryCache(CacheService, Generic[LockType]):
|
|
14
|
+
"""A simple in-memory cache using an OrderedDict.
|
|
15
|
+
|
|
16
|
+
This cache supports setting a maximum size and expiration time for cached items.
|
|
17
|
+
When the cache is full, it uses a Least Recently Used (LRU) eviction policy.
|
|
18
|
+
Thread-safe using a threading Lock.
|
|
19
|
+
|
|
20
|
+
Attributes:
|
|
21
|
+
max_size (int, optional): Maximum number of items to store in the cache.
|
|
22
|
+
expiration_time (int, optional): Time in seconds after which a cached item expires. Default is 1 hour.
|
|
23
|
+
|
|
24
|
+
Example:
|
|
25
|
+
cache = ThreadingInMemoryCache(max_size=3, expiration_time=5)
|
|
26
|
+
|
|
27
|
+
# setting cache values
|
|
28
|
+
cache.set("a", 1)
|
|
29
|
+
cache.set("b", 2)
|
|
30
|
+
cache["c"] = 3
|
|
31
|
+
|
|
32
|
+
# getting cache values
|
|
33
|
+
a = cache.get("a")
|
|
34
|
+
b = cache["b"]
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, max_size=None, expiration_time=60 * 60) -> None:
|
|
38
|
+
"""Initialize a new ThreadingInMemoryCache instance.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
max_size (int, optional): Maximum number of items to store in the cache.
|
|
42
|
+
expiration_time (int, optional): Time in seconds after which a cached item expires. Default is 1 hour.
|
|
43
|
+
"""
|
|
44
|
+
self._cache: OrderedDict = OrderedDict()
|
|
45
|
+
self._lock = threading.RLock()
|
|
46
|
+
self.max_size = max_size
|
|
47
|
+
self.expiration_time = expiration_time
|
|
48
|
+
|
|
49
|
+
def get(self, key, lock: Union[threading.Lock, None] = None): # noqa: UP007
|
|
50
|
+
"""Retrieve an item from the cache.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
key: The key of the item to retrieve.
|
|
54
|
+
lock: A lock to use for the operation.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
The value associated with the key, or CACHE_MISS if the key is not found or the item has expired.
|
|
58
|
+
"""
|
|
59
|
+
with lock or self._lock:
|
|
60
|
+
return self._get_without_lock(key)
|
|
61
|
+
|
|
62
|
+
def _get_without_lock(self, key):
|
|
63
|
+
"""Retrieve an item from the cache without acquiring the lock."""
|
|
64
|
+
if item := self._cache.get(key):
|
|
65
|
+
if self.expiration_time is None or time.time() - item["time"] < self.expiration_time:
|
|
66
|
+
# Move the key to the end to make it recently used
|
|
67
|
+
self._cache.move_to_end(key)
|
|
68
|
+
# Check if the value is pickled
|
|
69
|
+
return pickle.loads(item["value"]) if isinstance(item["value"], bytes) else item["value"] # noqa: S301
|
|
70
|
+
self.delete(key)
|
|
71
|
+
return CACHE_MISS
|
|
72
|
+
|
|
73
|
+
def set(self, key, value, lock: Union[threading.Lock, None] = None) -> None: # noqa: UP007
|
|
74
|
+
"""Add an item to the cache.
|
|
75
|
+
|
|
76
|
+
If the cache is full, the least recently used item is evicted.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
key: The key of the item.
|
|
80
|
+
value: The value to cache.
|
|
81
|
+
lock: A lock to use for the operation.
|
|
82
|
+
"""
|
|
83
|
+
with lock or self._lock:
|
|
84
|
+
if key in self._cache:
|
|
85
|
+
# Remove existing key before re-inserting to update order
|
|
86
|
+
self.delete(key)
|
|
87
|
+
elif self.max_size and len(self._cache) >= self.max_size:
|
|
88
|
+
# Remove least recently used item
|
|
89
|
+
self._cache.popitem(last=False)
|
|
90
|
+
# pickle locally to mimic Redis
|
|
91
|
+
|
|
92
|
+
self._cache[key] = {"value": value, "time": time.time()}
|
|
93
|
+
|
|
94
|
+
def upsert(self, key, value, lock: Union[threading.Lock, None] = None) -> None: # noqa: UP007
|
|
95
|
+
"""Inserts or updates a value in the cache.
|
|
96
|
+
|
|
97
|
+
If the existing value and the new value are both dictionaries, they are merged.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
key: The key of the item.
|
|
101
|
+
value: The value to insert or update.
|
|
102
|
+
lock: A lock to use for the operation.
|
|
103
|
+
"""
|
|
104
|
+
with lock or self._lock:
|
|
105
|
+
existing_value = self._get_without_lock(key)
|
|
106
|
+
if existing_value is not CACHE_MISS and isinstance(existing_value, dict) and isinstance(value, dict):
|
|
107
|
+
existing_value.update(value)
|
|
108
|
+
value = existing_value
|
|
109
|
+
|
|
110
|
+
self.set(key, value)
|
|
111
|
+
|
|
112
|
+
def get_or_set(self, key, value, lock: Union[threading.Lock, None] = None): # noqa: UP007
|
|
113
|
+
"""Retrieve an item from the cache.
|
|
114
|
+
|
|
115
|
+
If the item does not exist, set it with the provided value.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
key: The key of the item.
|
|
119
|
+
value: The value to cache if the item doesn't exist.
|
|
120
|
+
lock: A lock to use for the operation.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
The cached value associated with the key.
|
|
124
|
+
"""
|
|
125
|
+
with lock or self._lock:
|
|
126
|
+
if key in self._cache:
|
|
127
|
+
return self.get(key)
|
|
128
|
+
self.set(key, value)
|
|
129
|
+
return value
|
|
130
|
+
|
|
131
|
+
def delete(self, key, lock: Union[threading.Lock, None] = None) -> None: # noqa: UP007
|
|
132
|
+
with lock or self._lock:
|
|
133
|
+
self._cache.pop(key, None)
|
|
134
|
+
|
|
135
|
+
def clear(self, lock: Union[threading.Lock, None] = None) -> None: # noqa: UP007
|
|
136
|
+
"""Clear all items from the cache."""
|
|
137
|
+
with lock or self._lock:
|
|
138
|
+
self._cache.clear()
|
|
139
|
+
|
|
140
|
+
def contains(self, key) -> bool:
|
|
141
|
+
"""Check if the key is in the cache."""
|
|
142
|
+
return key in self._cache
|
|
143
|
+
|
|
144
|
+
def __contains__(self, key) -> bool:
|
|
145
|
+
"""Check if the key is in the cache."""
|
|
146
|
+
return self.contains(key)
|
|
147
|
+
|
|
148
|
+
def __getitem__(self, key):
|
|
149
|
+
"""Retrieve an item from the cache using the square bracket notation."""
|
|
150
|
+
return self.get(key)
|
|
151
|
+
|
|
152
|
+
def __setitem__(self, key, value) -> None:
|
|
153
|
+
"""Add an item to the cache using the square bracket notation."""
|
|
154
|
+
self.set(key, value)
|
|
155
|
+
|
|
156
|
+
def __delitem__(self, key) -> None:
|
|
157
|
+
"""Remove an item from the cache using the square bracket notation."""
|
|
158
|
+
self.delete(key)
|
|
159
|
+
|
|
160
|
+
def __len__(self) -> int:
|
|
161
|
+
"""Return the number of items in the cache."""
|
|
162
|
+
return len(self._cache)
|
|
163
|
+
|
|
164
|
+
def __repr__(self) -> str:
|
|
165
|
+
"""Return a string representation of the ThreadingInMemoryCache instance."""
|
|
166
|
+
return f"ThreadingInMemoryCache(max_size={self.max_size}, expiration_time={self.expiration_time})"
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import contextlib
|
|
3
|
+
import hashlib
|
|
4
|
+
import tempfile
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
from fastapi import UploadFile
|
|
9
|
+
from platformdirs import user_cache_dir
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from lfx.schema.schema import BuildStatus
|
|
13
|
+
|
|
14
|
+
CACHE: dict[str, Any] = {}
|
|
15
|
+
|
|
16
|
+
CACHE_DIR = user_cache_dir("langflow", "langflow")
|
|
17
|
+
|
|
18
|
+
PREFIX = "langflow_cache"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CacheMiss:
|
|
22
|
+
def __repr__(self) -> str:
|
|
23
|
+
return "<CACHE_MISS>"
|
|
24
|
+
|
|
25
|
+
def __bool__(self) -> bool:
|
|
26
|
+
return False
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def create_cache_folder(func):
|
|
30
|
+
def wrapper(*args, **kwargs):
|
|
31
|
+
# Get the destination folder
|
|
32
|
+
cache_path = Path(CACHE_DIR) / PREFIX
|
|
33
|
+
|
|
34
|
+
# Create the destination folder if it doesn't exist
|
|
35
|
+
cache_path.mkdir(parents=True, exist_ok=True)
|
|
36
|
+
|
|
37
|
+
return func(*args, **kwargs)
|
|
38
|
+
|
|
39
|
+
return wrapper
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@create_cache_folder
|
|
43
|
+
def clear_old_cache_files(max_cache_size: int = 3) -> None:
|
|
44
|
+
cache_dir = Path(tempfile.gettempdir()) / PREFIX
|
|
45
|
+
cache_files = list(cache_dir.glob("*.dill"))
|
|
46
|
+
|
|
47
|
+
if len(cache_files) > max_cache_size:
|
|
48
|
+
cache_files_sorted_by_mtime = sorted(cache_files, key=lambda x: x.stat().st_mtime, reverse=True)
|
|
49
|
+
|
|
50
|
+
for cache_file in cache_files_sorted_by_mtime[max_cache_size:]:
|
|
51
|
+
with contextlib.suppress(OSError):
|
|
52
|
+
cache_file.unlink()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def filter_json(json_data):
|
|
56
|
+
filtered_data = json_data.copy()
|
|
57
|
+
|
|
58
|
+
# Remove 'viewport' and 'chatHistory' keys
|
|
59
|
+
if "viewport" in filtered_data:
|
|
60
|
+
del filtered_data["viewport"]
|
|
61
|
+
if "chatHistory" in filtered_data:
|
|
62
|
+
del filtered_data["chatHistory"]
|
|
63
|
+
|
|
64
|
+
# Filter nodes
|
|
65
|
+
if "nodes" in filtered_data:
|
|
66
|
+
for node in filtered_data["nodes"]:
|
|
67
|
+
if "position" in node:
|
|
68
|
+
del node["position"]
|
|
69
|
+
if "positionAbsolute" in node:
|
|
70
|
+
del node["positionAbsolute"]
|
|
71
|
+
if "selected" in node:
|
|
72
|
+
del node["selected"]
|
|
73
|
+
if "dragging" in node:
|
|
74
|
+
del node["dragging"]
|
|
75
|
+
|
|
76
|
+
return filtered_data
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@create_cache_folder
|
|
80
|
+
def save_binary_file(content: str, file_name: str, accepted_types: list[str]) -> str:
|
|
81
|
+
"""Save a binary file to the specified folder.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
content: The content of the file as a bytes object.
|
|
85
|
+
file_name: The name of the file, including its extension.
|
|
86
|
+
accepted_types: A list of accepted file types.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
The path to the saved file.
|
|
90
|
+
"""
|
|
91
|
+
if not any(file_name.endswith(suffix) for suffix in accepted_types):
|
|
92
|
+
msg = f"File {file_name} is not accepted"
|
|
93
|
+
raise ValueError(msg)
|
|
94
|
+
|
|
95
|
+
# Get the destination folder
|
|
96
|
+
cache_path = Path(CACHE_DIR) / PREFIX
|
|
97
|
+
if not content:
|
|
98
|
+
msg = "Please, reload the file in the loader."
|
|
99
|
+
raise ValueError(msg)
|
|
100
|
+
data = content.split(",")[1]
|
|
101
|
+
decoded_bytes = base64.b64decode(data)
|
|
102
|
+
|
|
103
|
+
# Create the full file path
|
|
104
|
+
file_path = cache_path / file_name
|
|
105
|
+
|
|
106
|
+
# Save the binary content to the file
|
|
107
|
+
file_path.write_bytes(decoded_bytes)
|
|
108
|
+
|
|
109
|
+
return str(file_path)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@create_cache_folder
|
|
113
|
+
def save_uploaded_file(file: UploadFile, folder_name):
|
|
114
|
+
"""Save an uploaded file to the specified folder with a hash of its content as the file name.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
file: The uploaded file object.
|
|
118
|
+
folder_name: The name of the folder to save the file in.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
The path to the saved file.
|
|
122
|
+
"""
|
|
123
|
+
cache_path = Path(CACHE_DIR)
|
|
124
|
+
folder_path = cache_path / folder_name
|
|
125
|
+
filename = file.filename
|
|
126
|
+
file_extension = Path(filename).suffix if isinstance(filename, str | Path) else ""
|
|
127
|
+
file_object = file.file
|
|
128
|
+
|
|
129
|
+
# Create the folder if it doesn't exist
|
|
130
|
+
if not folder_path.exists():
|
|
131
|
+
folder_path.mkdir()
|
|
132
|
+
|
|
133
|
+
# Create a hash of the file content
|
|
134
|
+
sha256_hash = hashlib.sha256()
|
|
135
|
+
# Reset the file cursor to the beginning of the file
|
|
136
|
+
file_object.seek(0)
|
|
137
|
+
# Iterate over the uploaded file in small chunks to conserve memory
|
|
138
|
+
while chunk := file_object.read(8192): # Read 8KB at a time (adjust as needed)
|
|
139
|
+
sha256_hash.update(chunk)
|
|
140
|
+
|
|
141
|
+
# Use the hex digest of the hash as the file name
|
|
142
|
+
hex_dig = sha256_hash.hexdigest()
|
|
143
|
+
file_name = f"{hex_dig}{file_extension}"
|
|
144
|
+
|
|
145
|
+
# Reset the file cursor to the beginning of the file
|
|
146
|
+
file_object.seek(0)
|
|
147
|
+
|
|
148
|
+
# Save the file with the hash as its name
|
|
149
|
+
file_path = folder_path / file_name
|
|
150
|
+
|
|
151
|
+
with file_path.open("wb") as new_file:
|
|
152
|
+
while chunk := file_object.read(8192):
|
|
153
|
+
new_file.write(chunk)
|
|
154
|
+
|
|
155
|
+
return file_path
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def update_build_status(cache_service, flow_id: str, status: "BuildStatus") -> None:
|
|
159
|
+
cached_flow = cache_service[flow_id]
|
|
160
|
+
if cached_flow is None:
|
|
161
|
+
msg = f"Flow {flow_id} not found in cache"
|
|
162
|
+
raise ValueError(msg)
|
|
163
|
+
cached_flow["status"] = status
|
|
164
|
+
cache_service[flow_id] = cached_flow
|
|
165
|
+
cached_flow["status"] = status
|
|
166
|
+
cache_service[flow_id] = cached_flow
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
CACHE_MISS = CacheMiss()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Chat service schemas
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from typing import Any, Protocol
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class GetCache(Protocol):
|
|
6
|
+
async def __call__(self, key: str, lock: asyncio.Lock | None = None) -> Any: ...
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SetCache(Protocol):
|
|
10
|
+
async def __call__(self, key: str, data: Any, lock: asyncio.Lock | None = None) -> bool: ...
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Database service implementations for lfx package."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from contextlib import asynccontextmanager
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class NoopDatabaseService:
|
|
9
|
+
"""No-operation database service for standalone lfx usage.
|
|
10
|
+
|
|
11
|
+
This provides a database service interface that always returns NoopSession,
|
|
12
|
+
allowing lfx to work without a real database connection.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
@asynccontextmanager
|
|
16
|
+
async def _with_session(self):
|
|
17
|
+
"""Internal method to create a session. DO NOT USE DIRECTLY.
|
|
18
|
+
|
|
19
|
+
Use session_scope() for write operations or session_scope_readonly() for read operations.
|
|
20
|
+
This method does not handle commits - it only provides a raw session.
|
|
21
|
+
"""
|
|
22
|
+
from lfx.services.session import NoopSession
|
|
23
|
+
|
|
24
|
+
async with NoopSession() as session:
|
|
25
|
+
yield session
|
lfx/services/deps.py
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""Service dependency functions for lfx package."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from contextlib import asynccontextmanager, suppress
|
|
6
|
+
from http import HTTPStatus
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
from fastapi import HTTPException
|
|
10
|
+
from sqlalchemy.exc import InvalidRequestError
|
|
11
|
+
|
|
12
|
+
from lfx.log.logger import logger
|
|
13
|
+
from lfx.services.schema import ServiceType
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from collections.abc import AsyncGenerator
|
|
17
|
+
|
|
18
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
19
|
+
|
|
20
|
+
from lfx.services.interfaces import (
|
|
21
|
+
CacheServiceProtocol,
|
|
22
|
+
ChatServiceProtocol,
|
|
23
|
+
DatabaseServiceProtocol,
|
|
24
|
+
SettingsServiceProtocol,
|
|
25
|
+
StorageServiceProtocol,
|
|
26
|
+
TracingServiceProtocol,
|
|
27
|
+
VariableServiceProtocol,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_service(service_type: ServiceType, default=None):
|
|
32
|
+
"""Retrieves the service instance for the given service type.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
service_type: The type of service to retrieve.
|
|
36
|
+
default: The default ServiceFactory to use if the service is not found.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
The service instance or None if not available.
|
|
40
|
+
"""
|
|
41
|
+
from lfx.services.manager import get_service_manager
|
|
42
|
+
|
|
43
|
+
service_manager = get_service_manager()
|
|
44
|
+
|
|
45
|
+
if not service_manager.are_factories_registered():
|
|
46
|
+
# ! This is a workaround to ensure that the service manager is initialized
|
|
47
|
+
# ! Not optimal, but it works for now
|
|
48
|
+
|
|
49
|
+
service_manager.register_factories(service_manager.get_factories())
|
|
50
|
+
|
|
51
|
+
if ServiceType.SETTINGS_SERVICE not in service_manager.factories:
|
|
52
|
+
from lfx.services.settings.factory import SettingsServiceFactory
|
|
53
|
+
|
|
54
|
+
service_manager.register_factory(service_factory=SettingsServiceFactory())
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
return service_manager.get(service_type, default)
|
|
58
|
+
except Exception: # noqa: BLE001
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_db_service() -> DatabaseServiceProtocol:
|
|
63
|
+
"""Retrieves the database service instance.
|
|
64
|
+
|
|
65
|
+
Returns a NoopDatabaseService if no real database service is available,
|
|
66
|
+
ensuring that session_scope() always has a valid database service to work with.
|
|
67
|
+
"""
|
|
68
|
+
from lfx.services.database.service import NoopDatabaseService
|
|
69
|
+
from lfx.services.schema import ServiceType
|
|
70
|
+
|
|
71
|
+
db_service = get_service(ServiceType.DATABASE_SERVICE)
|
|
72
|
+
if db_service is None:
|
|
73
|
+
# Return noop database service when no real database service is available
|
|
74
|
+
# This allows lfx to work in standalone mode without requiring database setup
|
|
75
|
+
return NoopDatabaseService()
|
|
76
|
+
return db_service
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_storage_service() -> StorageServiceProtocol | None:
|
|
80
|
+
"""Retrieves the storage service instance."""
|
|
81
|
+
from lfx.services.schema import ServiceType
|
|
82
|
+
|
|
83
|
+
return get_service(ServiceType.STORAGE_SERVICE)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def get_settings_service() -> SettingsServiceProtocol | None:
|
|
87
|
+
"""Retrieves the settings service instance."""
|
|
88
|
+
from lfx.services.schema import ServiceType
|
|
89
|
+
|
|
90
|
+
return get_service(ServiceType.SETTINGS_SERVICE)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_variable_service() -> VariableServiceProtocol | None:
|
|
94
|
+
"""Retrieves the variable service instance."""
|
|
95
|
+
from lfx.services.schema import ServiceType
|
|
96
|
+
|
|
97
|
+
return get_service(ServiceType.VARIABLE_SERVICE)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def get_shared_component_cache_service() -> CacheServiceProtocol | None:
|
|
101
|
+
"""Retrieves the shared component cache service instance."""
|
|
102
|
+
from lfx.services.shared_component_cache.factory import SharedComponentCacheServiceFactory
|
|
103
|
+
|
|
104
|
+
return get_service(ServiceType.SHARED_COMPONENT_CACHE_SERVICE, SharedComponentCacheServiceFactory())
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def get_chat_service() -> ChatServiceProtocol | None:
|
|
108
|
+
"""Retrieves the chat service instance."""
|
|
109
|
+
from lfx.services.schema import ServiceType
|
|
110
|
+
|
|
111
|
+
return get_service(ServiceType.CHAT_SERVICE)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def get_tracing_service() -> TracingServiceProtocol | None:
|
|
115
|
+
"""Retrieves the tracing service instance."""
|
|
116
|
+
from lfx.services.schema import ServiceType
|
|
117
|
+
|
|
118
|
+
return get_service(ServiceType.TRACING_SERVICE)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
async def get_session():
|
|
122
|
+
msg = "get_session is deprecated, use session_scope instead"
|
|
123
|
+
logger.warning(msg)
|
|
124
|
+
raise NotImplementedError(msg)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
async def injectable_session_scope():
|
|
128
|
+
async with session_scope() as session:
|
|
129
|
+
yield session
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@asynccontextmanager
|
|
133
|
+
async def session_scope() -> AsyncGenerator[AsyncSession, None]:
|
|
134
|
+
"""Context manager for managing an async session scope with auto-commit for write operations.
|
|
135
|
+
|
|
136
|
+
This is used with `async with session_scope() as session:` for direct session management.
|
|
137
|
+
It ensures that the session is properly committed if no exceptions occur,
|
|
138
|
+
and rolled back if an exception is raised.
|
|
139
|
+
Use session_scope_readonly() for read-only operations to avoid unnecessary commits and locks.
|
|
140
|
+
|
|
141
|
+
Yields:
|
|
142
|
+
AsyncSession: The async session object.
|
|
143
|
+
|
|
144
|
+
Raises:
|
|
145
|
+
Exception: If an error occurs during the session scope.
|
|
146
|
+
"""
|
|
147
|
+
db_service = get_db_service()
|
|
148
|
+
async with db_service._with_session() as session: # noqa: SLF001
|
|
149
|
+
try:
|
|
150
|
+
yield session
|
|
151
|
+
await session.commit()
|
|
152
|
+
except Exception as e:
|
|
153
|
+
# Log at appropriate level based on error type
|
|
154
|
+
if isinstance(e, HTTPException):
|
|
155
|
+
if HTTPStatus.BAD_REQUEST.value <= e.status_code < HTTPStatus.INTERNAL_SERVER_ERROR.value:
|
|
156
|
+
# Client errors (4xx) - log at info level
|
|
157
|
+
await logger.ainfo(f"Client error during session scope: {e.status_code}: {e.detail}")
|
|
158
|
+
else:
|
|
159
|
+
# Server errors (5xx) or other - log at error level
|
|
160
|
+
await logger.aexception("An error occurred during the session scope.", exception=e)
|
|
161
|
+
else:
|
|
162
|
+
# Non-HTTP exceptions - log at error level
|
|
163
|
+
await logger.aexception("An error occurred during the session scope.", exception=e)
|
|
164
|
+
|
|
165
|
+
# Only rollback if session is still in a valid state
|
|
166
|
+
if session.is_active:
|
|
167
|
+
with suppress(InvalidRequestError):
|
|
168
|
+
# Session was already rolled back by SQLAlchemy
|
|
169
|
+
await session.rollback()
|
|
170
|
+
raise
|
|
171
|
+
# No explicit close needed - _with_session() handles it
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
async def injectable_session_scope_readonly():
|
|
175
|
+
async with session_scope_readonly() as session:
|
|
176
|
+
yield session
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@asynccontextmanager
|
|
180
|
+
async def session_scope_readonly() -> AsyncGenerator[AsyncSession, None]:
|
|
181
|
+
"""Context manager for managing a read-only async session scope.
|
|
182
|
+
|
|
183
|
+
This is used with `async with session_scope_readonly() as session:` for direct session management
|
|
184
|
+
when only reading data. No auto-commit or rollback - the session is simply closed after use.
|
|
185
|
+
|
|
186
|
+
Yields:
|
|
187
|
+
AsyncSession: The async session object.
|
|
188
|
+
"""
|
|
189
|
+
db_service = get_db_service()
|
|
190
|
+
async with db_service._with_session() as session: # noqa: SLF001
|
|
191
|
+
yield session
|
|
192
|
+
# No commit - read-only
|
|
193
|
+
# No clean up - client is responsible (plus, read only sessions are not committed)
|
|
194
|
+
# No explicit close needed - _with_session() handles it
|
lfx/services/factory.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Base service factory classes for lfx package."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from lfx.services.base import Service
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ServiceFactory(ABC):
|
|
11
|
+
"""Base service factory class."""
|
|
12
|
+
|
|
13
|
+
def __init__(self):
|
|
14
|
+
self.service_class = None
|
|
15
|
+
self.dependencies = []
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def create(self, **kwargs) -> "Service":
|
|
19
|
+
"""Create a service instance."""
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Initialize services for lfx package."""
|
|
2
|
+
|
|
3
|
+
from lfx.services.settings.factory import SettingsServiceFactory
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def initialize_services():
|
|
7
|
+
"""Initialize required services for lfx."""
|
|
8
|
+
from lfx.services.manager import get_service_manager
|
|
9
|
+
|
|
10
|
+
# Register the settings service factory
|
|
11
|
+
service_manager = get_service_manager()
|
|
12
|
+
service_manager.register_factory(SettingsServiceFactory())
|
|
13
|
+
|
|
14
|
+
# Note: We don't create the service immediately,
|
|
15
|
+
# it will be created on first use via get_settings_service()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Initialize services when the module is imported
|
|
19
|
+
initialize_services()
|