lfx-nightly 0.1.11.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (699) hide show
  1. lfx/__init__.py +0 -0
  2. lfx/__main__.py +25 -0
  3. lfx/base/__init__.py +0 -0
  4. lfx/base/agents/__init__.py +0 -0
  5. lfx/base/agents/agent.py +268 -0
  6. lfx/base/agents/callback.py +130 -0
  7. lfx/base/agents/context.py +109 -0
  8. lfx/base/agents/crewai/__init__.py +0 -0
  9. lfx/base/agents/crewai/crew.py +231 -0
  10. lfx/base/agents/crewai/tasks.py +12 -0
  11. lfx/base/agents/default_prompts.py +23 -0
  12. lfx/base/agents/errors.py +15 -0
  13. lfx/base/agents/events.py +346 -0
  14. lfx/base/agents/utils.py +205 -0
  15. lfx/base/astra_assistants/__init__.py +0 -0
  16. lfx/base/astra_assistants/util.py +171 -0
  17. lfx/base/chains/__init__.py +0 -0
  18. lfx/base/chains/model.py +19 -0
  19. lfx/base/composio/__init__.py +0 -0
  20. lfx/base/composio/composio_base.py +1291 -0
  21. lfx/base/compressors/__init__.py +0 -0
  22. lfx/base/compressors/model.py +60 -0
  23. lfx/base/constants.py +46 -0
  24. lfx/base/curl/__init__.py +0 -0
  25. lfx/base/curl/parse.py +188 -0
  26. lfx/base/data/__init__.py +5 -0
  27. lfx/base/data/base_file.py +685 -0
  28. lfx/base/data/docling_utils.py +245 -0
  29. lfx/base/data/utils.py +198 -0
  30. lfx/base/document_transformers/__init__.py +0 -0
  31. lfx/base/document_transformers/model.py +43 -0
  32. lfx/base/embeddings/__init__.py +0 -0
  33. lfx/base/embeddings/aiml_embeddings.py +62 -0
  34. lfx/base/embeddings/model.py +26 -0
  35. lfx/base/flow_processing/__init__.py +0 -0
  36. lfx/base/flow_processing/utils.py +86 -0
  37. lfx/base/huggingface/__init__.py +0 -0
  38. lfx/base/huggingface/model_bridge.py +133 -0
  39. lfx/base/io/__init__.py +0 -0
  40. lfx/base/io/chat.py +20 -0
  41. lfx/base/io/text.py +22 -0
  42. lfx/base/langchain_utilities/__init__.py +0 -0
  43. lfx/base/langchain_utilities/model.py +35 -0
  44. lfx/base/langchain_utilities/spider_constants.py +1 -0
  45. lfx/base/langwatch/__init__.py +0 -0
  46. lfx/base/langwatch/utils.py +18 -0
  47. lfx/base/mcp/__init__.py +0 -0
  48. lfx/base/mcp/constants.py +2 -0
  49. lfx/base/mcp/util.py +1398 -0
  50. lfx/base/memory/__init__.py +0 -0
  51. lfx/base/memory/memory.py +49 -0
  52. lfx/base/memory/model.py +38 -0
  53. lfx/base/models/__init__.py +3 -0
  54. lfx/base/models/aiml_constants.py +51 -0
  55. lfx/base/models/anthropic_constants.py +47 -0
  56. lfx/base/models/aws_constants.py +151 -0
  57. lfx/base/models/chat_result.py +76 -0
  58. lfx/base/models/google_generative_ai_constants.py +70 -0
  59. lfx/base/models/groq_constants.py +134 -0
  60. lfx/base/models/model.py +375 -0
  61. lfx/base/models/model_input_constants.py +307 -0
  62. lfx/base/models/model_metadata.py +41 -0
  63. lfx/base/models/model_utils.py +8 -0
  64. lfx/base/models/novita_constants.py +35 -0
  65. lfx/base/models/ollama_constants.py +49 -0
  66. lfx/base/models/openai_constants.py +122 -0
  67. lfx/base/models/sambanova_constants.py +18 -0
  68. lfx/base/processing/__init__.py +0 -0
  69. lfx/base/prompts/__init__.py +0 -0
  70. lfx/base/prompts/api_utils.py +224 -0
  71. lfx/base/prompts/utils.py +61 -0
  72. lfx/base/textsplitters/__init__.py +0 -0
  73. lfx/base/textsplitters/model.py +28 -0
  74. lfx/base/tools/__init__.py +0 -0
  75. lfx/base/tools/base.py +26 -0
  76. lfx/base/tools/component_tool.py +325 -0
  77. lfx/base/tools/constants.py +49 -0
  78. lfx/base/tools/flow_tool.py +132 -0
  79. lfx/base/tools/run_flow.py +224 -0
  80. lfx/base/vectorstores/__init__.py +0 -0
  81. lfx/base/vectorstores/model.py +193 -0
  82. lfx/base/vectorstores/utils.py +22 -0
  83. lfx/base/vectorstores/vector_store_connection_decorator.py +52 -0
  84. lfx/cli/__init__.py +5 -0
  85. lfx/cli/commands.py +319 -0
  86. lfx/cli/common.py +650 -0
  87. lfx/cli/run.py +441 -0
  88. lfx/cli/script_loader.py +247 -0
  89. lfx/cli/serve_app.py +546 -0
  90. lfx/cli/validation.py +69 -0
  91. lfx/components/FAISS/__init__.py +34 -0
  92. lfx/components/FAISS/faiss.py +111 -0
  93. lfx/components/Notion/__init__.py +19 -0
  94. lfx/components/Notion/add_content_to_page.py +269 -0
  95. lfx/components/Notion/create_page.py +94 -0
  96. lfx/components/Notion/list_database_properties.py +68 -0
  97. lfx/components/Notion/list_pages.py +122 -0
  98. lfx/components/Notion/list_users.py +77 -0
  99. lfx/components/Notion/page_content_viewer.py +93 -0
  100. lfx/components/Notion/search.py +111 -0
  101. lfx/components/Notion/update_page_property.py +114 -0
  102. lfx/components/__init__.py +411 -0
  103. lfx/components/_importing.py +42 -0
  104. lfx/components/agentql/__init__.py +3 -0
  105. lfx/components/agentql/agentql_api.py +151 -0
  106. lfx/components/agents/__init__.py +34 -0
  107. lfx/components/agents/agent.py +558 -0
  108. lfx/components/agents/mcp_component.py +501 -0
  109. lfx/components/aiml/__init__.py +37 -0
  110. lfx/components/aiml/aiml.py +112 -0
  111. lfx/components/aiml/aiml_embeddings.py +37 -0
  112. lfx/components/amazon/__init__.py +36 -0
  113. lfx/components/amazon/amazon_bedrock_embedding.py +109 -0
  114. lfx/components/amazon/amazon_bedrock_model.py +124 -0
  115. lfx/components/amazon/s3_bucket_uploader.py +211 -0
  116. lfx/components/anthropic/__init__.py +34 -0
  117. lfx/components/anthropic/anthropic.py +187 -0
  118. lfx/components/apify/__init__.py +5 -0
  119. lfx/components/apify/apify_actor.py +325 -0
  120. lfx/components/arxiv/__init__.py +3 -0
  121. lfx/components/arxiv/arxiv.py +163 -0
  122. lfx/components/assemblyai/__init__.py +46 -0
  123. lfx/components/assemblyai/assemblyai_get_subtitles.py +83 -0
  124. lfx/components/assemblyai/assemblyai_lemur.py +183 -0
  125. lfx/components/assemblyai/assemblyai_list_transcripts.py +95 -0
  126. lfx/components/assemblyai/assemblyai_poll_transcript.py +72 -0
  127. lfx/components/assemblyai/assemblyai_start_transcript.py +188 -0
  128. lfx/components/azure/__init__.py +37 -0
  129. lfx/components/azure/azure_openai.py +95 -0
  130. lfx/components/azure/azure_openai_embeddings.py +83 -0
  131. lfx/components/baidu/__init__.py +32 -0
  132. lfx/components/baidu/baidu_qianfan_chat.py +113 -0
  133. lfx/components/bing/__init__.py +3 -0
  134. lfx/components/bing/bing_search_api.py +61 -0
  135. lfx/components/cassandra/__init__.py +40 -0
  136. lfx/components/cassandra/cassandra.py +264 -0
  137. lfx/components/cassandra/cassandra_chat.py +92 -0
  138. lfx/components/cassandra/cassandra_graph.py +238 -0
  139. lfx/components/chains/__init__.py +3 -0
  140. lfx/components/chroma/__init__.py +34 -0
  141. lfx/components/chroma/chroma.py +167 -0
  142. lfx/components/cleanlab/__init__.py +40 -0
  143. lfx/components/cleanlab/cleanlab_evaluator.py +155 -0
  144. lfx/components/cleanlab/cleanlab_rag_evaluator.py +254 -0
  145. lfx/components/cleanlab/cleanlab_remediator.py +131 -0
  146. lfx/components/clickhouse/__init__.py +34 -0
  147. lfx/components/clickhouse/clickhouse.py +135 -0
  148. lfx/components/cloudflare/__init__.py +32 -0
  149. lfx/components/cloudflare/cloudflare.py +81 -0
  150. lfx/components/cohere/__init__.py +40 -0
  151. lfx/components/cohere/cohere_embeddings.py +81 -0
  152. lfx/components/cohere/cohere_models.py +46 -0
  153. lfx/components/cohere/cohere_rerank.py +51 -0
  154. lfx/components/composio/__init__.py +74 -0
  155. lfx/components/composio/composio_api.py +268 -0
  156. lfx/components/composio/dropbox_compnent.py +11 -0
  157. lfx/components/composio/github_composio.py +11 -0
  158. lfx/components/composio/gmail_composio.py +38 -0
  159. lfx/components/composio/googlecalendar_composio.py +11 -0
  160. lfx/components/composio/googlemeet_composio.py +11 -0
  161. lfx/components/composio/googletasks_composio.py +8 -0
  162. lfx/components/composio/linear_composio.py +11 -0
  163. lfx/components/composio/outlook_composio.py +11 -0
  164. lfx/components/composio/reddit_composio.py +11 -0
  165. lfx/components/composio/slack_composio.py +582 -0
  166. lfx/components/composio/slackbot_composio.py +11 -0
  167. lfx/components/composio/supabase_composio.py +11 -0
  168. lfx/components/composio/todoist_composio.py +11 -0
  169. lfx/components/composio/youtube_composio.py +11 -0
  170. lfx/components/confluence/__init__.py +3 -0
  171. lfx/components/confluence/confluence.py +84 -0
  172. lfx/components/couchbase/__init__.py +34 -0
  173. lfx/components/couchbase/couchbase.py +102 -0
  174. lfx/components/crewai/__init__.py +49 -0
  175. lfx/components/crewai/crewai.py +107 -0
  176. lfx/components/crewai/hierarchical_crew.py +46 -0
  177. lfx/components/crewai/hierarchical_task.py +44 -0
  178. lfx/components/crewai/sequential_crew.py +52 -0
  179. lfx/components/crewai/sequential_task.py +73 -0
  180. lfx/components/crewai/sequential_task_agent.py +143 -0
  181. lfx/components/custom_component/__init__.py +34 -0
  182. lfx/components/custom_component/custom_component.py +31 -0
  183. lfx/components/data/__init__.py +64 -0
  184. lfx/components/data/api_request.py +544 -0
  185. lfx/components/data/csv_to_data.py +95 -0
  186. lfx/components/data/directory.py +113 -0
  187. lfx/components/data/file.py +577 -0
  188. lfx/components/data/json_to_data.py +98 -0
  189. lfx/components/data/news_search.py +164 -0
  190. lfx/components/data/rss.py +69 -0
  191. lfx/components/data/sql_executor.py +101 -0
  192. lfx/components/data/url.py +311 -0
  193. lfx/components/data/web_search.py +112 -0
  194. lfx/components/data/webhook.py +56 -0
  195. lfx/components/datastax/__init__.py +70 -0
  196. lfx/components/datastax/astra_assistant_manager.py +306 -0
  197. lfx/components/datastax/astra_db.py +75 -0
  198. lfx/components/datastax/astra_vectorize.py +124 -0
  199. lfx/components/datastax/astradb.py +1285 -0
  200. lfx/components/datastax/astradb_cql.py +314 -0
  201. lfx/components/datastax/astradb_graph.py +330 -0
  202. lfx/components/datastax/astradb_tool.py +414 -0
  203. lfx/components/datastax/astradb_vectorstore.py +1285 -0
  204. lfx/components/datastax/cassandra.py +92 -0
  205. lfx/components/datastax/create_assistant.py +58 -0
  206. lfx/components/datastax/create_thread.py +32 -0
  207. lfx/components/datastax/dotenv.py +35 -0
  208. lfx/components/datastax/get_assistant.py +37 -0
  209. lfx/components/datastax/getenvvar.py +30 -0
  210. lfx/components/datastax/graph_rag.py +141 -0
  211. lfx/components/datastax/hcd.py +314 -0
  212. lfx/components/datastax/list_assistants.py +25 -0
  213. lfx/components/datastax/run.py +89 -0
  214. lfx/components/deactivated/__init__.py +15 -0
  215. lfx/components/deactivated/amazon_kendra.py +66 -0
  216. lfx/components/deactivated/chat_litellm_model.py +158 -0
  217. lfx/components/deactivated/code_block_extractor.py +26 -0
  218. lfx/components/deactivated/documents_to_data.py +22 -0
  219. lfx/components/deactivated/embed.py +16 -0
  220. lfx/components/deactivated/extract_key_from_data.py +46 -0
  221. lfx/components/deactivated/json_document_builder.py +57 -0
  222. lfx/components/deactivated/list_flows.py +20 -0
  223. lfx/components/deactivated/mcp_sse.py +61 -0
  224. lfx/components/deactivated/mcp_stdio.py +62 -0
  225. lfx/components/deactivated/merge_data.py +93 -0
  226. lfx/components/deactivated/message.py +37 -0
  227. lfx/components/deactivated/metal.py +54 -0
  228. lfx/components/deactivated/multi_query.py +59 -0
  229. lfx/components/deactivated/retriever.py +43 -0
  230. lfx/components/deactivated/selective_passthrough.py +77 -0
  231. lfx/components/deactivated/should_run_next.py +40 -0
  232. lfx/components/deactivated/split_text.py +63 -0
  233. lfx/components/deactivated/store_message.py +24 -0
  234. lfx/components/deactivated/sub_flow.py +124 -0
  235. lfx/components/deactivated/vectara_self_query.py +76 -0
  236. lfx/components/deactivated/vector_store.py +24 -0
  237. lfx/components/deepseek/__init__.py +34 -0
  238. lfx/components/deepseek/deepseek.py +136 -0
  239. lfx/components/docling/__init__.py +43 -0
  240. lfx/components/docling/chunk_docling_document.py +186 -0
  241. lfx/components/docling/docling_inline.py +231 -0
  242. lfx/components/docling/docling_remote.py +193 -0
  243. lfx/components/docling/export_docling_document.py +117 -0
  244. lfx/components/documentloaders/__init__.py +3 -0
  245. lfx/components/duckduckgo/__init__.py +3 -0
  246. lfx/components/duckduckgo/duck_duck_go_search_run.py +92 -0
  247. lfx/components/elastic/__init__.py +37 -0
  248. lfx/components/elastic/elasticsearch.py +267 -0
  249. lfx/components/elastic/opensearch.py +243 -0
  250. lfx/components/embeddings/__init__.py +37 -0
  251. lfx/components/embeddings/similarity.py +76 -0
  252. lfx/components/embeddings/text_embedder.py +64 -0
  253. lfx/components/exa/__init__.py +3 -0
  254. lfx/components/exa/exa_search.py +68 -0
  255. lfx/components/firecrawl/__init__.py +43 -0
  256. lfx/components/firecrawl/firecrawl_crawl_api.py +88 -0
  257. lfx/components/firecrawl/firecrawl_extract_api.py +136 -0
  258. lfx/components/firecrawl/firecrawl_map_api.py +89 -0
  259. lfx/components/firecrawl/firecrawl_scrape_api.py +73 -0
  260. lfx/components/git/__init__.py +4 -0
  261. lfx/components/git/git.py +262 -0
  262. lfx/components/git/gitextractor.py +196 -0
  263. lfx/components/glean/__init__.py +3 -0
  264. lfx/components/glean/glean_search_api.py +173 -0
  265. lfx/components/google/__init__.py +17 -0
  266. lfx/components/google/gmail.py +192 -0
  267. lfx/components/google/google_bq_sql_executor.py +157 -0
  268. lfx/components/google/google_drive.py +92 -0
  269. lfx/components/google/google_drive_search.py +152 -0
  270. lfx/components/google/google_generative_ai.py +147 -0
  271. lfx/components/google/google_generative_ai_embeddings.py +141 -0
  272. lfx/components/google/google_oauth_token.py +89 -0
  273. lfx/components/google/google_search_api_core.py +68 -0
  274. lfx/components/google/google_serper_api_core.py +74 -0
  275. lfx/components/groq/__init__.py +34 -0
  276. lfx/components/groq/groq.py +136 -0
  277. lfx/components/helpers/__init__.py +52 -0
  278. lfx/components/helpers/calculator_core.py +89 -0
  279. lfx/components/helpers/create_list.py +40 -0
  280. lfx/components/helpers/current_date.py +42 -0
  281. lfx/components/helpers/id_generator.py +42 -0
  282. lfx/components/helpers/memory.py +251 -0
  283. lfx/components/helpers/output_parser.py +45 -0
  284. lfx/components/helpers/store_message.py +90 -0
  285. lfx/components/homeassistant/__init__.py +7 -0
  286. lfx/components/homeassistant/home_assistant_control.py +152 -0
  287. lfx/components/homeassistant/list_home_assistant_states.py +137 -0
  288. lfx/components/huggingface/__init__.py +37 -0
  289. lfx/components/huggingface/huggingface.py +197 -0
  290. lfx/components/huggingface/huggingface_inference_api.py +106 -0
  291. lfx/components/ibm/__init__.py +34 -0
  292. lfx/components/ibm/watsonx.py +203 -0
  293. lfx/components/ibm/watsonx_embeddings.py +135 -0
  294. lfx/components/icosacomputing/__init__.py +5 -0
  295. lfx/components/icosacomputing/combinatorial_reasoner.py +84 -0
  296. lfx/components/input_output/__init__.py +38 -0
  297. lfx/components/input_output/chat.py +120 -0
  298. lfx/components/input_output/chat_output.py +200 -0
  299. lfx/components/input_output/text.py +27 -0
  300. lfx/components/input_output/text_output.py +29 -0
  301. lfx/components/jigsawstack/__init__.py +23 -0
  302. lfx/components/jigsawstack/ai_scrape.py +126 -0
  303. lfx/components/jigsawstack/ai_web_search.py +136 -0
  304. lfx/components/jigsawstack/file_read.py +115 -0
  305. lfx/components/jigsawstack/file_upload.py +94 -0
  306. lfx/components/jigsawstack/image_generation.py +205 -0
  307. lfx/components/jigsawstack/nsfw.py +60 -0
  308. lfx/components/jigsawstack/object_detection.py +124 -0
  309. lfx/components/jigsawstack/sentiment.py +112 -0
  310. lfx/components/jigsawstack/text_to_sql.py +90 -0
  311. lfx/components/jigsawstack/text_translate.py +77 -0
  312. lfx/components/jigsawstack/vocr.py +107 -0
  313. lfx/components/langchain_utilities/__init__.py +109 -0
  314. lfx/components/langchain_utilities/character.py +53 -0
  315. lfx/components/langchain_utilities/conversation.py +59 -0
  316. lfx/components/langchain_utilities/csv_agent.py +107 -0
  317. lfx/components/langchain_utilities/fake_embeddings.py +26 -0
  318. lfx/components/langchain_utilities/html_link_extractor.py +35 -0
  319. lfx/components/langchain_utilities/json_agent.py +45 -0
  320. lfx/components/langchain_utilities/langchain_hub.py +126 -0
  321. lfx/components/langchain_utilities/language_recursive.py +49 -0
  322. lfx/components/langchain_utilities/language_semantic.py +138 -0
  323. lfx/components/langchain_utilities/llm_checker.py +39 -0
  324. lfx/components/langchain_utilities/llm_math.py +42 -0
  325. lfx/components/langchain_utilities/natural_language.py +61 -0
  326. lfx/components/langchain_utilities/openai_tools.py +53 -0
  327. lfx/components/langchain_utilities/openapi.py +48 -0
  328. lfx/components/langchain_utilities/recursive_character.py +60 -0
  329. lfx/components/langchain_utilities/retrieval_qa.py +83 -0
  330. lfx/components/langchain_utilities/runnable_executor.py +137 -0
  331. lfx/components/langchain_utilities/self_query.py +80 -0
  332. lfx/components/langchain_utilities/spider.py +142 -0
  333. lfx/components/langchain_utilities/sql.py +40 -0
  334. lfx/components/langchain_utilities/sql_database.py +35 -0
  335. lfx/components/langchain_utilities/sql_generator.py +78 -0
  336. lfx/components/langchain_utilities/tool_calling.py +59 -0
  337. lfx/components/langchain_utilities/vector_store_info.py +49 -0
  338. lfx/components/langchain_utilities/vector_store_router.py +33 -0
  339. lfx/components/langchain_utilities/xml_agent.py +71 -0
  340. lfx/components/langwatch/__init__.py +3 -0
  341. lfx/components/langwatch/langwatch.py +278 -0
  342. lfx/components/link_extractors/__init__.py +3 -0
  343. lfx/components/lmstudio/__init__.py +34 -0
  344. lfx/components/lmstudio/lmstudioembeddings.py +89 -0
  345. lfx/components/lmstudio/lmstudiomodel.py +129 -0
  346. lfx/components/logic/__init__.py +52 -0
  347. lfx/components/logic/conditional_router.py +171 -0
  348. lfx/components/logic/data_conditional_router.py +125 -0
  349. lfx/components/logic/flow_tool.py +110 -0
  350. lfx/components/logic/listen.py +29 -0
  351. lfx/components/logic/loop.py +125 -0
  352. lfx/components/logic/notify.py +88 -0
  353. lfx/components/logic/pass_message.py +35 -0
  354. lfx/components/logic/run_flow.py +71 -0
  355. lfx/components/logic/sub_flow.py +114 -0
  356. lfx/components/maritalk/__init__.py +32 -0
  357. lfx/components/maritalk/maritalk.py +52 -0
  358. lfx/components/mem0/__init__.py +3 -0
  359. lfx/components/mem0/mem0_chat_memory.py +136 -0
  360. lfx/components/milvus/__init__.py +34 -0
  361. lfx/components/milvus/milvus.py +115 -0
  362. lfx/components/mistral/__init__.py +37 -0
  363. lfx/components/mistral/mistral.py +114 -0
  364. lfx/components/mistral/mistral_embeddings.py +58 -0
  365. lfx/components/models/__init__.py +34 -0
  366. lfx/components/models/embedding_model.py +114 -0
  367. lfx/components/models/language_model.py +144 -0
  368. lfx/components/mongodb/__init__.py +34 -0
  369. lfx/components/mongodb/mongodb_atlas.py +213 -0
  370. lfx/components/needle/__init__.py +3 -0
  371. lfx/components/needle/needle.py +104 -0
  372. lfx/components/notdiamond/__init__.py +34 -0
  373. lfx/components/notdiamond/notdiamond.py +228 -0
  374. lfx/components/novita/__init__.py +32 -0
  375. lfx/components/novita/novita.py +130 -0
  376. lfx/components/nvidia/__init__.py +57 -0
  377. lfx/components/nvidia/nvidia.py +157 -0
  378. lfx/components/nvidia/nvidia_embedding.py +77 -0
  379. lfx/components/nvidia/nvidia_ingest.py +317 -0
  380. lfx/components/nvidia/nvidia_rerank.py +63 -0
  381. lfx/components/nvidia/system_assist.py +65 -0
  382. lfx/components/olivya/__init__.py +3 -0
  383. lfx/components/olivya/olivya.py +116 -0
  384. lfx/components/ollama/__init__.py +37 -0
  385. lfx/components/ollama/ollama.py +330 -0
  386. lfx/components/ollama/ollama_embeddings.py +106 -0
  387. lfx/components/openai/__init__.py +37 -0
  388. lfx/components/openai/openai.py +100 -0
  389. lfx/components/openai/openai_chat_model.py +176 -0
  390. lfx/components/openrouter/__init__.py +32 -0
  391. lfx/components/openrouter/openrouter.py +202 -0
  392. lfx/components/output_parsers/__init__.py +3 -0
  393. lfx/components/perplexity/__init__.py +34 -0
  394. lfx/components/perplexity/perplexity.py +75 -0
  395. lfx/components/pgvector/__init__.py +34 -0
  396. lfx/components/pgvector/pgvector.py +72 -0
  397. lfx/components/pinecone/__init__.py +34 -0
  398. lfx/components/pinecone/pinecone.py +134 -0
  399. lfx/components/processing/__init__.py +117 -0
  400. lfx/components/processing/alter_metadata.py +108 -0
  401. lfx/components/processing/batch_run.py +205 -0
  402. lfx/components/processing/combine_text.py +39 -0
  403. lfx/components/processing/converter.py +159 -0
  404. lfx/components/processing/create_data.py +110 -0
  405. lfx/components/processing/data_operations.py +438 -0
  406. lfx/components/processing/data_to_dataframe.py +70 -0
  407. lfx/components/processing/dataframe_operations.py +313 -0
  408. lfx/components/processing/extract_key.py +53 -0
  409. lfx/components/processing/filter_data.py +42 -0
  410. lfx/components/processing/filter_data_values.py +88 -0
  411. lfx/components/processing/json_cleaner.py +103 -0
  412. lfx/components/processing/lambda_filter.py +154 -0
  413. lfx/components/processing/llm_router.py +499 -0
  414. lfx/components/processing/merge_data.py +90 -0
  415. lfx/components/processing/message_to_data.py +36 -0
  416. lfx/components/processing/parse_data.py +70 -0
  417. lfx/components/processing/parse_dataframe.py +68 -0
  418. lfx/components/processing/parse_json_data.py +90 -0
  419. lfx/components/processing/parser.py +143 -0
  420. lfx/components/processing/prompt.py +67 -0
  421. lfx/components/processing/python_repl_core.py +98 -0
  422. lfx/components/processing/regex.py +82 -0
  423. lfx/components/processing/save_file.py +225 -0
  424. lfx/components/processing/select_data.py +48 -0
  425. lfx/components/processing/split_text.py +141 -0
  426. lfx/components/processing/structured_output.py +202 -0
  427. lfx/components/processing/update_data.py +160 -0
  428. lfx/components/prototypes/__init__.py +34 -0
  429. lfx/components/prototypes/python_function.py +73 -0
  430. lfx/components/qdrant/__init__.py +34 -0
  431. lfx/components/qdrant/qdrant.py +109 -0
  432. lfx/components/redis/__init__.py +37 -0
  433. lfx/components/redis/redis.py +89 -0
  434. lfx/components/redis/redis_chat.py +43 -0
  435. lfx/components/sambanova/__init__.py +32 -0
  436. lfx/components/sambanova/sambanova.py +84 -0
  437. lfx/components/scrapegraph/__init__.py +40 -0
  438. lfx/components/scrapegraph/scrapegraph_markdownify_api.py +64 -0
  439. lfx/components/scrapegraph/scrapegraph_search_api.py +64 -0
  440. lfx/components/scrapegraph/scrapegraph_smart_scraper_api.py +71 -0
  441. lfx/components/searchapi/__init__.py +34 -0
  442. lfx/components/searchapi/search.py +79 -0
  443. lfx/components/serpapi/__init__.py +3 -0
  444. lfx/components/serpapi/serp.py +115 -0
  445. lfx/components/supabase/__init__.py +34 -0
  446. lfx/components/supabase/supabase.py +76 -0
  447. lfx/components/tavily/__init__.py +4 -0
  448. lfx/components/tavily/tavily_extract.py +117 -0
  449. lfx/components/tavily/tavily_search.py +212 -0
  450. lfx/components/textsplitters/__init__.py +3 -0
  451. lfx/components/toolkits/__init__.py +3 -0
  452. lfx/components/tools/__init__.py +72 -0
  453. lfx/components/tools/calculator.py +108 -0
  454. lfx/components/tools/google_search_api.py +45 -0
  455. lfx/components/tools/google_serper_api.py +115 -0
  456. lfx/components/tools/python_code_structured_tool.py +327 -0
  457. lfx/components/tools/python_repl.py +97 -0
  458. lfx/components/tools/search_api.py +87 -0
  459. lfx/components/tools/searxng.py +145 -0
  460. lfx/components/tools/serp_api.py +119 -0
  461. lfx/components/tools/tavily_search_tool.py +344 -0
  462. lfx/components/tools/wikidata_api.py +102 -0
  463. lfx/components/tools/wikipedia_api.py +49 -0
  464. lfx/components/tools/yahoo_finance.py +129 -0
  465. lfx/components/twelvelabs/__init__.py +52 -0
  466. lfx/components/twelvelabs/convert_astra_results.py +84 -0
  467. lfx/components/twelvelabs/pegasus_index.py +311 -0
  468. lfx/components/twelvelabs/split_video.py +291 -0
  469. lfx/components/twelvelabs/text_embeddings.py +57 -0
  470. lfx/components/twelvelabs/twelvelabs_pegasus.py +408 -0
  471. lfx/components/twelvelabs/video_embeddings.py +100 -0
  472. lfx/components/twelvelabs/video_file.py +179 -0
  473. lfx/components/unstructured/__init__.py +3 -0
  474. lfx/components/unstructured/unstructured.py +121 -0
  475. lfx/components/upstash/__init__.py +34 -0
  476. lfx/components/upstash/upstash.py +124 -0
  477. lfx/components/vectara/__init__.py +37 -0
  478. lfx/components/vectara/vectara.py +97 -0
  479. lfx/components/vectara/vectara_rag.py +164 -0
  480. lfx/components/vectorstores/__init__.py +40 -0
  481. lfx/components/vectorstores/astradb.py +1285 -0
  482. lfx/components/vectorstores/astradb_graph.py +319 -0
  483. lfx/components/vectorstores/cassandra.py +264 -0
  484. lfx/components/vectorstores/cassandra_graph.py +238 -0
  485. lfx/components/vectorstores/chroma.py +167 -0
  486. lfx/components/vectorstores/clickhouse.py +135 -0
  487. lfx/components/vectorstores/couchbase.py +102 -0
  488. lfx/components/vectorstores/elasticsearch.py +267 -0
  489. lfx/components/vectorstores/faiss.py +111 -0
  490. lfx/components/vectorstores/graph_rag.py +141 -0
  491. lfx/components/vectorstores/hcd.py +314 -0
  492. lfx/components/vectorstores/local_db.py +261 -0
  493. lfx/components/vectorstores/milvus.py +115 -0
  494. lfx/components/vectorstores/mongodb_atlas.py +213 -0
  495. lfx/components/vectorstores/opensearch.py +243 -0
  496. lfx/components/vectorstores/pgvector.py +72 -0
  497. lfx/components/vectorstores/pinecone.py +134 -0
  498. lfx/components/vectorstores/qdrant.py +109 -0
  499. lfx/components/vectorstores/supabase.py +76 -0
  500. lfx/components/vectorstores/upstash.py +124 -0
  501. lfx/components/vectorstores/vectara.py +97 -0
  502. lfx/components/vectorstores/vectara_rag.py +164 -0
  503. lfx/components/vectorstores/weaviate.py +89 -0
  504. lfx/components/vertexai/__init__.py +37 -0
  505. lfx/components/vertexai/vertexai.py +71 -0
  506. lfx/components/vertexai/vertexai_embeddings.py +67 -0
  507. lfx/components/weaviate/__init__.py +34 -0
  508. lfx/components/weaviate/weaviate.py +89 -0
  509. lfx/components/wikipedia/__init__.py +4 -0
  510. lfx/components/wikipedia/wikidata.py +86 -0
  511. lfx/components/wikipedia/wikipedia.py +53 -0
  512. lfx/components/wolframalpha/__init__.py +3 -0
  513. lfx/components/wolframalpha/wolfram_alpha_api.py +54 -0
  514. lfx/components/xai/__init__.py +32 -0
  515. lfx/components/xai/xai.py +167 -0
  516. lfx/components/yahoosearch/__init__.py +3 -0
  517. lfx/components/yahoosearch/yahoo.py +137 -0
  518. lfx/components/youtube/__init__.py +52 -0
  519. lfx/components/youtube/channel.py +227 -0
  520. lfx/components/youtube/comments.py +231 -0
  521. lfx/components/youtube/playlist.py +33 -0
  522. lfx/components/youtube/search.py +120 -0
  523. lfx/components/youtube/trending.py +285 -0
  524. lfx/components/youtube/video_details.py +263 -0
  525. lfx/components/youtube/youtube_transcripts.py +118 -0
  526. lfx/components/zep/__init__.py +3 -0
  527. lfx/components/zep/zep.py +44 -0
  528. lfx/constants.py +6 -0
  529. lfx/custom/__init__.py +7 -0
  530. lfx/custom/attributes.py +86 -0
  531. lfx/custom/code_parser/__init__.py +3 -0
  532. lfx/custom/code_parser/code_parser.py +361 -0
  533. lfx/custom/custom_component/__init__.py +0 -0
  534. lfx/custom/custom_component/base_component.py +128 -0
  535. lfx/custom/custom_component/component.py +1808 -0
  536. lfx/custom/custom_component/component_with_cache.py +8 -0
  537. lfx/custom/custom_component/custom_component.py +588 -0
  538. lfx/custom/dependency_analyzer.py +165 -0
  539. lfx/custom/directory_reader/__init__.py +3 -0
  540. lfx/custom/directory_reader/directory_reader.py +359 -0
  541. lfx/custom/directory_reader/utils.py +171 -0
  542. lfx/custom/eval.py +12 -0
  543. lfx/custom/schema.py +32 -0
  544. lfx/custom/tree_visitor.py +21 -0
  545. lfx/custom/utils.py +877 -0
  546. lfx/custom/validate.py +488 -0
  547. lfx/events/__init__.py +1 -0
  548. lfx/events/event_manager.py +110 -0
  549. lfx/exceptions/__init__.py +0 -0
  550. lfx/exceptions/component.py +15 -0
  551. lfx/field_typing/__init__.py +91 -0
  552. lfx/field_typing/constants.py +215 -0
  553. lfx/field_typing/range_spec.py +35 -0
  554. lfx/graph/__init__.py +6 -0
  555. lfx/graph/edge/__init__.py +0 -0
  556. lfx/graph/edge/base.py +277 -0
  557. lfx/graph/edge/schema.py +119 -0
  558. lfx/graph/edge/utils.py +0 -0
  559. lfx/graph/graph/__init__.py +0 -0
  560. lfx/graph/graph/ascii.py +202 -0
  561. lfx/graph/graph/base.py +2238 -0
  562. lfx/graph/graph/constants.py +63 -0
  563. lfx/graph/graph/runnable_vertices_manager.py +133 -0
  564. lfx/graph/graph/schema.py +52 -0
  565. lfx/graph/graph/state_model.py +66 -0
  566. lfx/graph/graph/utils.py +1024 -0
  567. lfx/graph/schema.py +75 -0
  568. lfx/graph/state/__init__.py +0 -0
  569. lfx/graph/state/model.py +237 -0
  570. lfx/graph/utils.py +200 -0
  571. lfx/graph/vertex/__init__.py +0 -0
  572. lfx/graph/vertex/base.py +823 -0
  573. lfx/graph/vertex/constants.py +0 -0
  574. lfx/graph/vertex/exceptions.py +4 -0
  575. lfx/graph/vertex/param_handler.py +264 -0
  576. lfx/graph/vertex/schema.py +26 -0
  577. lfx/graph/vertex/utils.py +19 -0
  578. lfx/graph/vertex/vertex_types.py +489 -0
  579. lfx/helpers/__init__.py +1 -0
  580. lfx/helpers/base_model.py +71 -0
  581. lfx/helpers/custom.py +13 -0
  582. lfx/helpers/data.py +167 -0
  583. lfx/helpers/flow.py +194 -0
  584. lfx/inputs/__init__.py +68 -0
  585. lfx/inputs/constants.py +2 -0
  586. lfx/inputs/input_mixin.py +328 -0
  587. lfx/inputs/inputs.py +714 -0
  588. lfx/inputs/validators.py +19 -0
  589. lfx/interface/__init__.py +6 -0
  590. lfx/interface/components.py +489 -0
  591. lfx/interface/importing/__init__.py +5 -0
  592. lfx/interface/importing/utils.py +39 -0
  593. lfx/interface/initialize/__init__.py +3 -0
  594. lfx/interface/initialize/loading.py +224 -0
  595. lfx/interface/listing.py +26 -0
  596. lfx/interface/run.py +16 -0
  597. lfx/interface/utils.py +111 -0
  598. lfx/io/__init__.py +63 -0
  599. lfx/io/schema.py +289 -0
  600. lfx/load/__init__.py +8 -0
  601. lfx/load/load.py +256 -0
  602. lfx/load/utils.py +99 -0
  603. lfx/log/__init__.py +5 -0
  604. lfx/log/logger.py +385 -0
  605. lfx/memory/__init__.py +90 -0
  606. lfx/memory/stubs.py +283 -0
  607. lfx/processing/__init__.py +1 -0
  608. lfx/processing/process.py +238 -0
  609. lfx/processing/utils.py +25 -0
  610. lfx/py.typed +0 -0
  611. lfx/schema/__init__.py +66 -0
  612. lfx/schema/artifact.py +83 -0
  613. lfx/schema/content_block.py +62 -0
  614. lfx/schema/content_types.py +91 -0
  615. lfx/schema/data.py +308 -0
  616. lfx/schema/dataframe.py +210 -0
  617. lfx/schema/dotdict.py +74 -0
  618. lfx/schema/encoders.py +13 -0
  619. lfx/schema/graph.py +47 -0
  620. lfx/schema/image.py +131 -0
  621. lfx/schema/json_schema.py +141 -0
  622. lfx/schema/log.py +61 -0
  623. lfx/schema/message.py +473 -0
  624. lfx/schema/openai_responses_schemas.py +74 -0
  625. lfx/schema/properties.py +41 -0
  626. lfx/schema/schema.py +171 -0
  627. lfx/schema/serialize.py +13 -0
  628. lfx/schema/table.py +140 -0
  629. lfx/schema/validators.py +114 -0
  630. lfx/serialization/__init__.py +5 -0
  631. lfx/serialization/constants.py +2 -0
  632. lfx/serialization/serialization.py +314 -0
  633. lfx/services/__init__.py +23 -0
  634. lfx/services/base.py +28 -0
  635. lfx/services/cache/__init__.py +6 -0
  636. lfx/services/cache/base.py +183 -0
  637. lfx/services/cache/service.py +166 -0
  638. lfx/services/cache/utils.py +169 -0
  639. lfx/services/chat/__init__.py +1 -0
  640. lfx/services/chat/config.py +2 -0
  641. lfx/services/chat/schema.py +10 -0
  642. lfx/services/deps.py +129 -0
  643. lfx/services/factory.py +19 -0
  644. lfx/services/initialize.py +19 -0
  645. lfx/services/interfaces.py +103 -0
  646. lfx/services/manager.py +172 -0
  647. lfx/services/schema.py +20 -0
  648. lfx/services/session.py +82 -0
  649. lfx/services/settings/__init__.py +3 -0
  650. lfx/services/settings/auth.py +130 -0
  651. lfx/services/settings/base.py +539 -0
  652. lfx/services/settings/constants.py +31 -0
  653. lfx/services/settings/factory.py +23 -0
  654. lfx/services/settings/feature_flags.py +12 -0
  655. lfx/services/settings/service.py +35 -0
  656. lfx/services/settings/utils.py +40 -0
  657. lfx/services/shared_component_cache/__init__.py +1 -0
  658. lfx/services/shared_component_cache/factory.py +30 -0
  659. lfx/services/shared_component_cache/service.py +9 -0
  660. lfx/services/storage/__init__.py +5 -0
  661. lfx/services/storage/local.py +155 -0
  662. lfx/services/storage/service.py +54 -0
  663. lfx/services/tracing/__init__.py +1 -0
  664. lfx/services/tracing/service.py +21 -0
  665. lfx/settings.py +6 -0
  666. lfx/template/__init__.py +6 -0
  667. lfx/template/field/__init__.py +0 -0
  668. lfx/template/field/base.py +257 -0
  669. lfx/template/field/prompt.py +15 -0
  670. lfx/template/frontend_node/__init__.py +6 -0
  671. lfx/template/frontend_node/base.py +212 -0
  672. lfx/template/frontend_node/constants.py +65 -0
  673. lfx/template/frontend_node/custom_components.py +79 -0
  674. lfx/template/template/__init__.py +0 -0
  675. lfx/template/template/base.py +100 -0
  676. lfx/template/utils.py +217 -0
  677. lfx/type_extraction/__init__.py +19 -0
  678. lfx/type_extraction/type_extraction.py +75 -0
  679. lfx/type_extraction.py +80 -0
  680. lfx/utils/__init__.py +1 -0
  681. lfx/utils/async_helpers.py +42 -0
  682. lfx/utils/component_utils.py +154 -0
  683. lfx/utils/concurrency.py +60 -0
  684. lfx/utils/connection_string_parser.py +11 -0
  685. lfx/utils/constants.py +205 -0
  686. lfx/utils/data_structure.py +212 -0
  687. lfx/utils/exceptions.py +22 -0
  688. lfx/utils/helpers.py +28 -0
  689. lfx/utils/image.py +73 -0
  690. lfx/utils/lazy_load.py +15 -0
  691. lfx/utils/request_utils.py +18 -0
  692. lfx/utils/schemas.py +139 -0
  693. lfx/utils/util.py +481 -0
  694. lfx/utils/util_strings.py +56 -0
  695. lfx/utils/version.py +24 -0
  696. lfx_nightly-0.1.11.dev0.dist-info/METADATA +293 -0
  697. lfx_nightly-0.1.11.dev0.dist-info/RECORD +699 -0
  698. lfx_nightly-0.1.11.dev0.dist-info/WHEEL +4 -0
  699. lfx_nightly-0.1.11.dev0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,544 @@
1
+ import json
2
+ import re
3
+ import tempfile
4
+ from datetime import datetime, timezone
5
+ from pathlib import Path
6
+ from typing import Any
7
+ from urllib.parse import parse_qsl, urlencode, urlparse, urlunparse
8
+
9
+ import aiofiles
10
+ import aiofiles.os as aiofiles_os
11
+ import httpx
12
+ import validators
13
+
14
+ from lfx.base.curl.parse import parse_context
15
+ from lfx.custom.custom_component.component import Component
16
+ from lfx.inputs.inputs import TabInput
17
+ from lfx.io import (
18
+ BoolInput,
19
+ DataInput,
20
+ DropdownInput,
21
+ IntInput,
22
+ MessageTextInput,
23
+ MultilineInput,
24
+ Output,
25
+ TableInput,
26
+ )
27
+ from lfx.schema.data import Data
28
+ from lfx.schema.dotdict import dotdict
29
+ from lfx.utils.component_utils import set_current_fields, set_field_advanced, set_field_display
30
+
31
+ # Define fields for each mode
32
+ MODE_FIELDS = {
33
+ "URL": [
34
+ "url_input",
35
+ "method",
36
+ ],
37
+ "cURL": ["curl_input"],
38
+ }
39
+
40
+ # Fields that should always be visible
41
+ DEFAULT_FIELDS = ["mode"]
42
+
43
+
44
+ class APIRequestComponent(Component):
45
+ display_name = "API Request"
46
+ description = "Make HTTP requests using URL or cURL commands."
47
+ documentation: str = "https://docs.langflow.org/components-data#api-request"
48
+ icon = "Globe"
49
+ name = "APIRequest"
50
+
51
+ inputs = [
52
+ MessageTextInput(
53
+ name="url_input",
54
+ display_name="URL",
55
+ info="Enter the URL for the request.",
56
+ advanced=False,
57
+ tool_mode=True,
58
+ ),
59
+ MultilineInput(
60
+ name="curl_input",
61
+ display_name="cURL",
62
+ info=(
63
+ "Paste a curl command to populate the fields. "
64
+ "This will fill in the dictionary fields for headers and body."
65
+ ),
66
+ real_time_refresh=True,
67
+ tool_mode=True,
68
+ advanced=True,
69
+ show=False,
70
+ ),
71
+ DropdownInput(
72
+ name="method",
73
+ display_name="Method",
74
+ options=["GET", "POST", "PATCH", "PUT", "DELETE"],
75
+ value="GET",
76
+ info="The HTTP method to use.",
77
+ real_time_refresh=True,
78
+ ),
79
+ TabInput(
80
+ name="mode",
81
+ display_name="Mode",
82
+ options=["URL", "cURL"],
83
+ value="URL",
84
+ info="Enable cURL mode to populate fields from a cURL command.",
85
+ real_time_refresh=True,
86
+ ),
87
+ DataInput(
88
+ name="query_params",
89
+ display_name="Query Parameters",
90
+ info="The query parameters to append to the URL.",
91
+ advanced=True,
92
+ ),
93
+ TableInput(
94
+ name="body",
95
+ display_name="Body",
96
+ info="The body to send with the request as a dictionary (for POST, PATCH, PUT).",
97
+ table_schema=[
98
+ {
99
+ "name": "key",
100
+ "display_name": "Key",
101
+ "type": "str",
102
+ "description": "Parameter name",
103
+ },
104
+ {
105
+ "name": "value",
106
+ "display_name": "Value",
107
+ "description": "Parameter value",
108
+ },
109
+ ],
110
+ value=[],
111
+ input_types=["Data"],
112
+ advanced=True,
113
+ real_time_refresh=True,
114
+ ),
115
+ TableInput(
116
+ name="headers",
117
+ display_name="Headers",
118
+ info="The headers to send with the request",
119
+ table_schema=[
120
+ {
121
+ "name": "key",
122
+ "display_name": "Header",
123
+ "type": "str",
124
+ "description": "Header name",
125
+ },
126
+ {
127
+ "name": "value",
128
+ "display_name": "Value",
129
+ "type": "str",
130
+ "description": "Header value",
131
+ },
132
+ ],
133
+ value=[{"key": "User-Agent", "value": "Langflow/1.0"}],
134
+ advanced=True,
135
+ input_types=["Data"],
136
+ real_time_refresh=True,
137
+ ),
138
+ IntInput(
139
+ name="timeout",
140
+ display_name="Timeout",
141
+ value=30,
142
+ info="The timeout to use for the request.",
143
+ advanced=True,
144
+ ),
145
+ BoolInput(
146
+ name="follow_redirects",
147
+ display_name="Follow Redirects",
148
+ value=True,
149
+ info="Whether to follow http redirects.",
150
+ advanced=True,
151
+ ),
152
+ BoolInput(
153
+ name="save_to_file",
154
+ display_name="Save to File",
155
+ value=False,
156
+ info="Save the API response to a temporary file",
157
+ advanced=True,
158
+ ),
159
+ BoolInput(
160
+ name="include_httpx_metadata",
161
+ display_name="Include HTTPx Metadata",
162
+ value=False,
163
+ info=(
164
+ "Include properties such as headers, status_code, response_headers, "
165
+ "and redirection_history in the output."
166
+ ),
167
+ advanced=True,
168
+ ),
169
+ ]
170
+
171
+ outputs = [
172
+ Output(display_name="API Response", name="data", method="make_api_request"),
173
+ ]
174
+
175
+ def _parse_json_value(self, value: Any) -> Any:
176
+ """Parse a value that might be a JSON string."""
177
+ if not isinstance(value, str):
178
+ return value
179
+
180
+ try:
181
+ parsed = json.loads(value)
182
+ except json.JSONDecodeError:
183
+ return value
184
+ else:
185
+ return parsed
186
+
187
+ def _process_body(self, body: Any) -> dict:
188
+ """Process the body input into a valid dictionary."""
189
+ if body is None:
190
+ return {}
191
+ if isinstance(body, dict):
192
+ return self._process_dict_body(body)
193
+ if isinstance(body, str):
194
+ return self._process_string_body(body)
195
+ if isinstance(body, list):
196
+ return self._process_list_body(body)
197
+ return {}
198
+
199
+ def _process_dict_body(self, body: dict) -> dict:
200
+ """Process dictionary body by parsing JSON values."""
201
+ return {k: self._parse_json_value(v) for k, v in body.items()}
202
+
203
+ def _process_string_body(self, body: str) -> dict:
204
+ """Process string body by attempting JSON parse."""
205
+ try:
206
+ return self._process_body(json.loads(body))
207
+ except json.JSONDecodeError:
208
+ return {"data": body}
209
+
210
+ def _process_list_body(self, body: list) -> dict:
211
+ """Process list body by converting to key-value dictionary."""
212
+ processed_dict = {}
213
+ try:
214
+ for item in body:
215
+ if not self._is_valid_key_value_item(item):
216
+ continue
217
+ key = item["key"]
218
+ value = self._parse_json_value(item["value"])
219
+ processed_dict[key] = value
220
+ except (KeyError, TypeError, ValueError) as e:
221
+ self.log(f"Failed to process body list: {e}")
222
+ return {}
223
+ return processed_dict
224
+
225
+ def _is_valid_key_value_item(self, item: Any) -> bool:
226
+ """Check if an item is a valid key-value dictionary."""
227
+ return isinstance(item, dict) and "key" in item and "value" in item
228
+
229
+ def parse_curl(self, curl: str, build_config: dotdict) -> dotdict:
230
+ """Parse a cURL command and update build configuration."""
231
+ try:
232
+ parsed = parse_context(curl)
233
+
234
+ # Update basic configuration
235
+ url = parsed.url
236
+ # Normalize URL before setting it
237
+ url = self._normalize_url(url)
238
+
239
+ build_config["url_input"]["value"] = url
240
+ build_config["method"]["value"] = parsed.method.upper()
241
+
242
+ # Process headers
243
+ headers_list = [{"key": k, "value": v} for k, v in parsed.headers.items()]
244
+ build_config["headers"]["value"] = headers_list
245
+
246
+ # Process body data
247
+ if not parsed.data:
248
+ build_config["body"]["value"] = []
249
+ elif parsed.data:
250
+ try:
251
+ json_data = json.loads(parsed.data)
252
+ if isinstance(json_data, dict):
253
+ body_list = [
254
+ {"key": k, "value": json.dumps(v) if isinstance(v, dict | list) else str(v)}
255
+ for k, v in json_data.items()
256
+ ]
257
+ build_config["body"]["value"] = body_list
258
+ else:
259
+ build_config["body"]["value"] = [{"key": "data", "value": json.dumps(json_data)}]
260
+ except json.JSONDecodeError:
261
+ build_config["body"]["value"] = [{"key": "data", "value": parsed.data}]
262
+
263
+ except Exception as exc:
264
+ msg = f"Error parsing curl: {exc}"
265
+ self.log(msg)
266
+ raise ValueError(msg) from exc
267
+
268
+ return build_config
269
+
270
+ def _normalize_url(self, url: str) -> str:
271
+ """Normalize URL by adding https:// if no protocol is specified."""
272
+ if not url or not isinstance(url, str):
273
+ msg = "URL cannot be empty"
274
+ raise ValueError(msg)
275
+
276
+ url = url.strip()
277
+ if url.startswith(("http://", "https://")):
278
+ return url
279
+ return f"https://{url}"
280
+
281
+ async def make_request(
282
+ self,
283
+ client: httpx.AsyncClient,
284
+ method: str,
285
+ url: str,
286
+ headers: dict | None = None,
287
+ body: Any = None,
288
+ timeout: int = 5,
289
+ *,
290
+ follow_redirects: bool = True,
291
+ save_to_file: bool = False,
292
+ include_httpx_metadata: bool = False,
293
+ ) -> Data:
294
+ method = method.upper()
295
+ if method not in {"GET", "POST", "PATCH", "PUT", "DELETE"}:
296
+ msg = f"Unsupported method: {method}"
297
+ raise ValueError(msg)
298
+
299
+ processed_body = self._process_body(body)
300
+ redirection_history = []
301
+
302
+ try:
303
+ # Prepare request parameters
304
+ request_params = {
305
+ "method": method,
306
+ "url": url,
307
+ "headers": headers,
308
+ "json": processed_body,
309
+ "timeout": timeout,
310
+ "follow_redirects": follow_redirects,
311
+ }
312
+ response = await client.request(**request_params)
313
+
314
+ redirection_history = [
315
+ {
316
+ "url": redirect.headers.get("Location", str(redirect.url)),
317
+ "status_code": redirect.status_code,
318
+ }
319
+ for redirect in response.history
320
+ ]
321
+
322
+ is_binary, file_path = await self._response_info(response, with_file_path=save_to_file)
323
+ response_headers = self._headers_to_dict(response.headers)
324
+
325
+ # Base metadata
326
+ metadata = {
327
+ "source": url,
328
+ "status_code": response.status_code,
329
+ "response_headers": response_headers,
330
+ }
331
+
332
+ if redirection_history:
333
+ metadata["redirection_history"] = redirection_history
334
+
335
+ if save_to_file:
336
+ mode = "wb" if is_binary else "w"
337
+ encoding = response.encoding if mode == "w" else None
338
+ if file_path:
339
+ await aiofiles_os.makedirs(file_path.parent, exist_ok=True)
340
+ if is_binary:
341
+ async with aiofiles.open(file_path, "wb") as f:
342
+ await f.write(response.content)
343
+ await f.flush()
344
+ else:
345
+ async with aiofiles.open(file_path, "w", encoding=encoding) as f:
346
+ await f.write(response.text)
347
+ await f.flush()
348
+ metadata["file_path"] = str(file_path)
349
+
350
+ if include_httpx_metadata:
351
+ metadata.update({"headers": headers})
352
+ return Data(data=metadata)
353
+
354
+ # Handle response content
355
+ if is_binary:
356
+ result = response.content
357
+ else:
358
+ try:
359
+ result = response.json()
360
+ except json.JSONDecodeError:
361
+ self.log("Failed to decode JSON response")
362
+ result = response.text.encode("utf-8")
363
+
364
+ metadata["result"] = result
365
+
366
+ if include_httpx_metadata:
367
+ metadata.update({"headers": headers})
368
+
369
+ return Data(data=metadata)
370
+ except (httpx.HTTPError, httpx.RequestError, httpx.TimeoutException) as exc:
371
+ self.log(f"Error making request to {url}")
372
+ return Data(
373
+ data={
374
+ "source": url,
375
+ "headers": headers,
376
+ "status_code": 500,
377
+ "error": str(exc),
378
+ **({"redirection_history": redirection_history} if redirection_history else {}),
379
+ },
380
+ )
381
+
382
+ def add_query_params(self, url: str, params: dict) -> str:
383
+ """Add query parameters to URL efficiently."""
384
+ if not params:
385
+ return url
386
+ url_parts = list(urlparse(url))
387
+ query = dict(parse_qsl(url_parts[4]))
388
+ query.update(params)
389
+ url_parts[4] = urlencode(query)
390
+ return urlunparse(url_parts)
391
+
392
+ def _headers_to_dict(self, headers: httpx.Headers) -> dict[str, str]:
393
+ """Convert HTTP headers to a dictionary with lowercased keys."""
394
+ return {k.lower(): v for k, v in headers.items()}
395
+
396
+ def _process_headers(self, headers: Any) -> dict:
397
+ """Process the headers input into a valid dictionary."""
398
+ if headers is None:
399
+ return {}
400
+ if isinstance(headers, dict):
401
+ return headers
402
+ if isinstance(headers, list):
403
+ return {item["key"]: item["value"] for item in headers if self._is_valid_key_value_item(item)}
404
+ return {}
405
+
406
+ async def make_api_request(self) -> Data:
407
+ """Make HTTP request with optimized parameter handling."""
408
+ method = self.method
409
+ url = self.url_input.strip() if isinstance(self.url_input, str) else ""
410
+ headers = self.headers or {}
411
+ body = self.body or {}
412
+ timeout = self.timeout
413
+ follow_redirects = self.follow_redirects
414
+ save_to_file = self.save_to_file
415
+ include_httpx_metadata = self.include_httpx_metadata
416
+
417
+ # if self.mode == "cURL" and self.curl_input:
418
+ # self._build_config = self.parse_curl(self.curl_input, dotdict())
419
+ # # After parsing curl, get the normalized URL
420
+ # url = self._build_config["url_input"]["value"]
421
+
422
+ # Normalize URL before validation
423
+ url = self._normalize_url(url)
424
+
425
+ # Validate URL
426
+ if not validators.url(url):
427
+ msg = f"Invalid URL provided: {url}"
428
+ raise ValueError(msg)
429
+
430
+ # Process query parameters
431
+ if isinstance(self.query_params, str):
432
+ query_params = dict(parse_qsl(self.query_params))
433
+ else:
434
+ query_params = self.query_params.data if self.query_params else {}
435
+
436
+ # Process headers and body
437
+ headers = self._process_headers(headers)
438
+ body = self._process_body(body)
439
+ url = self.add_query_params(url, query_params)
440
+
441
+ async with httpx.AsyncClient() as client:
442
+ result = await self.make_request(
443
+ client,
444
+ method,
445
+ url,
446
+ headers,
447
+ body,
448
+ timeout,
449
+ follow_redirects=follow_redirects,
450
+ save_to_file=save_to_file,
451
+ include_httpx_metadata=include_httpx_metadata,
452
+ )
453
+ self.status = result
454
+ return result
455
+
456
+ def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None) -> dotdict:
457
+ """Update the build config based on the selected mode."""
458
+ if field_name != "mode":
459
+ if field_name == "curl_input" and self.mode == "cURL" and self.curl_input:
460
+ return self.parse_curl(self.curl_input, build_config)
461
+ return build_config
462
+
463
+ # print(f"Current mode: {field_value}")
464
+ if field_value == "cURL":
465
+ set_field_display(build_config, "curl_input", value=True)
466
+ if build_config["curl_input"]["value"]:
467
+ build_config = self.parse_curl(build_config["curl_input"]["value"], build_config)
468
+ else:
469
+ set_field_display(build_config, "curl_input", value=False)
470
+
471
+ return set_current_fields(
472
+ build_config=build_config,
473
+ action_fields=MODE_FIELDS,
474
+ selected_action=field_value,
475
+ default_fields=DEFAULT_FIELDS,
476
+ func=set_field_advanced,
477
+ default_value=True,
478
+ )
479
+
480
+ async def _response_info(
481
+ self, response: httpx.Response, *, with_file_path: bool = False
482
+ ) -> tuple[bool, Path | None]:
483
+ """Determine the file path and whether the response content is binary.
484
+
485
+ Args:
486
+ response (Response): The HTTP response object.
487
+ with_file_path (bool): Whether to save the response content to a file.
488
+
489
+ Returns:
490
+ Tuple[bool, Path | None]:
491
+ A tuple containing a boolean indicating if the content is binary and the full file path (if applicable).
492
+ """
493
+ content_type = response.headers.get("Content-Type", "")
494
+ is_binary = "application/octet-stream" in content_type or "application/binary" in content_type
495
+
496
+ if not with_file_path:
497
+ return is_binary, None
498
+
499
+ component_temp_dir = Path(tempfile.gettempdir()) / self.__class__.__name__
500
+
501
+ # Create directory asynchronously
502
+ await aiofiles_os.makedirs(component_temp_dir, exist_ok=True)
503
+
504
+ filename = None
505
+ if "Content-Disposition" in response.headers:
506
+ content_disposition = response.headers["Content-Disposition"]
507
+ filename_match = re.search(r'filename="(.+?)"', content_disposition)
508
+ if filename_match:
509
+ extracted_filename = filename_match.group(1)
510
+ filename = extracted_filename
511
+
512
+ # Step 3: Infer file extension or use part of the request URL if no filename
513
+ if not filename:
514
+ # Extract the last segment of the URL path
515
+ url_path = urlparse(str(response.request.url) if response.request else "").path
516
+ base_name = Path(url_path).name # Get the last segment of the path
517
+ if not base_name: # If the path ends with a slash or is empty
518
+ base_name = "response"
519
+
520
+ # Infer file extension
521
+ content_type_to_extension = {
522
+ "text/plain": ".txt",
523
+ "application/json": ".json",
524
+ "image/jpeg": ".jpg",
525
+ "image/png": ".png",
526
+ "application/octet-stream": ".bin",
527
+ }
528
+ extension = content_type_to_extension.get(content_type, ".bin" if is_binary else ".txt")
529
+ filename = f"{base_name}{extension}"
530
+
531
+ # Step 4: Define the full file path
532
+ file_path = component_temp_dir / filename
533
+
534
+ # Step 5: Check if file exists asynchronously and handle accordingly
535
+ try:
536
+ # Try to create the file exclusively (x mode) to check existence
537
+ async with aiofiles.open(file_path, "x") as _:
538
+ pass # File created successfully, we can use this path
539
+ except FileExistsError:
540
+ # If file exists, append a timestamp to the filename
541
+ timestamp = datetime.now(timezone.utc).strftime("%Y%m%d%H%M%S%f")
542
+ file_path = component_temp_dir / f"{timestamp}-{filename}"
543
+
544
+ return is_binary, file_path
@@ -0,0 +1,95 @@
1
+ import csv
2
+ import io
3
+ from pathlib import Path
4
+
5
+ from lfx.custom.custom_component.component import Component
6
+ from lfx.io import FileInput, MessageTextInput, MultilineInput, Output
7
+ from lfx.schema.data import Data
8
+
9
+
10
+ class CSVToDataComponent(Component):
11
+ display_name = "Load CSV"
12
+ description = "Load a CSV file, CSV from a file path, or a valid CSV string and convert it to a list of Data"
13
+ icon = "file-spreadsheet"
14
+ name = "CSVtoData"
15
+ legacy = True
16
+
17
+ inputs = [
18
+ FileInput(
19
+ name="csv_file",
20
+ display_name="CSV File",
21
+ file_types=["csv"],
22
+ info="Upload a CSV file to convert to a list of Data objects",
23
+ ),
24
+ MessageTextInput(
25
+ name="csv_path",
26
+ display_name="CSV File Path",
27
+ info="Provide the path to the CSV file as pure text",
28
+ ),
29
+ MultilineInput(
30
+ name="csv_string",
31
+ display_name="CSV String",
32
+ info="Paste a CSV string directly to convert to a list of Data objects",
33
+ ),
34
+ MessageTextInput(
35
+ name="text_key",
36
+ display_name="Text Key",
37
+ info="The key to use for the text column. Defaults to 'text'.",
38
+ value="text",
39
+ ),
40
+ ]
41
+
42
+ outputs = [
43
+ Output(name="data_list", display_name="Data List", method="load_csv_to_data"),
44
+ ]
45
+
46
+ def load_csv_to_data(self) -> list[Data]:
47
+ if sum(bool(field) for field in [self.csv_file, self.csv_path, self.csv_string]) != 1:
48
+ msg = "Please provide exactly one of: CSV file, file path, or CSV string."
49
+ raise ValueError(msg)
50
+
51
+ csv_data = None
52
+ try:
53
+ if self.csv_file:
54
+ resolved_path = self.resolve_path(self.csv_file)
55
+ file_path = Path(resolved_path)
56
+ if file_path.suffix.lower() != ".csv":
57
+ self.status = "The provided file must be a CSV file."
58
+ else:
59
+ with file_path.open(newline="", encoding="utf-8") as csvfile:
60
+ csv_data = csvfile.read()
61
+
62
+ elif self.csv_path:
63
+ file_path = Path(self.csv_path)
64
+ if file_path.suffix.lower() != ".csv":
65
+ self.status = "The provided file must be a CSV file."
66
+ else:
67
+ with file_path.open(newline="", encoding="utf-8") as csvfile:
68
+ csv_data = csvfile.read()
69
+
70
+ else:
71
+ csv_data = self.csv_string
72
+
73
+ if csv_data:
74
+ csv_reader = csv.DictReader(io.StringIO(csv_data))
75
+ result = [Data(data=row, text_key=self.text_key) for row in csv_reader]
76
+
77
+ if not result:
78
+ self.status = "The CSV data is empty."
79
+ return []
80
+
81
+ self.status = result
82
+ return result
83
+
84
+ except csv.Error as e:
85
+ error_message = f"CSV parsing error: {e}"
86
+ self.status = error_message
87
+ raise ValueError(error_message) from e
88
+
89
+ except Exception as e:
90
+ error_message = f"An error occurred: {e}"
91
+ self.status = error_message
92
+ raise ValueError(error_message) from e
93
+
94
+ # An error occurred
95
+ raise ValueError(self.status)