openrag 0.5.0.dev33__tar.gz → 0.5.0.dev35__tar.gz

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 (172) hide show
  1. {openrag-0.5.0.dev33/src/openrag.egg-info → openrag-0.5.0.dev35}/PKG-INFO +1 -1
  2. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/pyproject.toml +1 -1
  3. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35/src/openrag.egg-info}/PKG-INFO +1 -1
  4. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/_assets/flows/ingestion_flow.json +16 -16
  5. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/managers/docling_manager.py +42 -45
  6. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/LICENSE +0 -0
  7. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/MANIFEST.in +0 -0
  8. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/README.md +0 -0
  9. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/setup.cfg +0 -0
  10. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/agent.py +0 -0
  11. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/__init__.py +0 -0
  12. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/auth.py +0 -0
  13. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/chat.py +0 -0
  14. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/connector_router.py +0 -0
  15. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/connectors.py +0 -0
  16. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/docling.py +0 -0
  17. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/documents.py +0 -0
  18. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/flows.py +0 -0
  19. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/keys.py +0 -0
  20. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/knowledge_filter.py +0 -0
  21. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/langflow_files.py +0 -0
  22. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/models.py +0 -0
  23. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/nudges.py +0 -0
  24. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/oidc.py +0 -0
  25. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/provider_health.py +0 -0
  26. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/provider_validation.py +0 -0
  27. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/router.py +0 -0
  28. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/search.py +0 -0
  29. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/settings.py +0 -0
  30. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/tasks.py +0 -0
  31. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/upload.py +0 -0
  32. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/v1/__init__.py +0 -0
  33. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/v1/chat.py +0 -0
  34. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/v1/documents.py +0 -0
  35. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/v1/knowledge_filters.py +0 -0
  36. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/v1/models.py +0 -0
  37. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/v1/search.py +0 -0
  38. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/api/v1/settings.py +0 -0
  39. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/auth/__init__.py +0 -0
  40. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/auth/ibm_auth.py +0 -0
  41. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/auth_context.py +0 -0
  42. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/bootstrap.py +0 -0
  43. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/config/__init__.py +0 -0
  44. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/config/config_manager.py +0 -0
  45. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/config/embedding_constants.py +0 -0
  46. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/config/model_constants.py +0 -0
  47. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/config/paths.py +0 -0
  48. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/config/settings.py +0 -0
  49. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/__init__.py +0 -0
  50. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/aws_s3/__init__.py +0 -0
  51. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/aws_s3/api.py +0 -0
  52. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/aws_s3/auth.py +0 -0
  53. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/aws_s3/connector.py +0 -0
  54. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/aws_s3/models.py +0 -0
  55. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/aws_s3/support.py +0 -0
  56. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/base.py +0 -0
  57. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/connection_manager.py +0 -0
  58. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/google_drive/__init__.py +0 -0
  59. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/google_drive/connector.py +0 -0
  60. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/google_drive/oauth.py +0 -0
  61. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/ibm_cos/__init__.py +0 -0
  62. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/ibm_cos/api.py +0 -0
  63. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/ibm_cos/auth.py +0 -0
  64. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/ibm_cos/connector.py +0 -0
  65. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/ibm_cos/models.py +0 -0
  66. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/ibm_cos/support.py +0 -0
  67. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/langflow_connector_service.py +0 -0
  68. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/onedrive/__init__.py +0 -0
  69. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/onedrive/connector.py +0 -0
  70. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/onedrive/oauth.py +0 -0
  71. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/service.py +0 -0
  72. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/sharepoint/__init__.py +0 -0
  73. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/sharepoint/connector.py +0 -0
  74. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/sharepoint/oauth.py +0 -0
  75. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/connectors/sharepoint/utils.py +0 -0
  76. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/dependencies.py +0 -0
  77. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/main.py +0 -0
  78. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/mcp_http/__init__.py +0 -0
  79. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/mcp_http/server.py +0 -0
  80. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/models/__init__.py +0 -0
  81. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/models/processors.py +0 -0
  82. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/models/tasks.py +0 -0
  83. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/models/url.py +0 -0
  84. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/openrag.egg-info/SOURCES.txt +0 -0
  85. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/openrag.egg-info/dependency_links.txt +0 -0
  86. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/openrag.egg-info/entry_points.txt +0 -0
  87. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/openrag.egg-info/requires.txt +0 -0
  88. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/openrag.egg-info/top_level.txt +0 -0
  89. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/__init__.py +0 -0
  90. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/api_key_service.py +0 -0
  91. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/auth_service.py +0 -0
  92. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/chat_service.py +0 -0
  93. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/conversation_persistence_service.py +0 -0
  94. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/document_service.py +0 -0
  95. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/flows_service.py +0 -0
  96. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/knowledge_filter_service.py +0 -0
  97. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/langflow_file_service.py +0 -0
  98. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/langflow_history_service.py +0 -0
  99. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/langflow_mcp_service.py +0 -0
  100. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/models_service.py +0 -0
  101. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/monitor_service.py +0 -0
  102. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/search_service.py +0 -0
  103. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/session_ownership_service.py +0 -0
  104. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/services/task_service.py +0 -0
  105. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/session_manager.py +0 -0
  106. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/__init__.py +0 -0
  107. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/_assets/docker-compose.gpu.yml +0 -0
  108. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/_assets/docker-compose.yml +0 -0
  109. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/_assets/flows/components/ollama_embedding.json +0 -0
  110. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/_assets/flows/components/ollama_llm.json +0 -0
  111. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/_assets/flows/components/ollama_llm_text.json +0 -0
  112. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/_assets/flows/components/watsonx_embedding.json +0 -0
  113. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/_assets/flows/components/watsonx_llm.json +0 -0
  114. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/_assets/flows/components/watsonx_llm_text.json +0 -0
  115. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/_assets/flows/openrag_agent.json +0 -0
  116. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/_assets/flows/openrag_nudges.json +0 -0
  117. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/_assets/flows/openrag_url_mcp.json +0 -0
  118. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/_assets/openrag-documents/docling.pdf +0 -0
  119. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/_assets/openrag-documents/ibm_anthropic.pdf +0 -0
  120. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/_assets/openrag-documents/warmup_ocr.pdf +0 -0
  121. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/cli.py +0 -0
  122. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/config_fields.py +0 -0
  123. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/main.py +0 -0
  124. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/managers/__init__.py +0 -0
  125. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/managers/container_manager.py +0 -0
  126. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/managers/env_manager.py +0 -0
  127. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/screens/__init__.py +0 -0
  128. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/screens/config.py +0 -0
  129. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/screens/diagnostics.py +0 -0
  130. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/screens/logs.py +0 -0
  131. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/screens/monitor.py +0 -0
  132. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/screens/welcome.py +0 -0
  133. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/utils/__init__.py +0 -0
  134. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/utils/clipboard.py +0 -0
  135. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/utils/platform.py +0 -0
  136. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/utils/startup_checks.py +0 -0
  137. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/utils/validation.py +0 -0
  138. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/utils/version_check.py +0 -0
  139. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/widgets/__init__.py +0 -0
  140. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/widgets/command_modal.py +0 -0
  141. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/widgets/diagnostics_notification.py +0 -0
  142. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/widgets/error_notification.py +0 -0
  143. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/widgets/factory_reset_warning_modal.py +0 -0
  144. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/widgets/flow_backup_warning_modal.py +0 -0
  145. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/widgets/prune_options_modal.py +0 -0
  146. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/widgets/upgrade_instructions_modal.py +0 -0
  147. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/widgets/version_mismatch_warning_modal.py +0 -0
  148. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/tui/widgets/waves.py +0 -0
  149. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/__init__.py +0 -0
  150. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/acl_utils.py +0 -0
  151. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/container_utils.py +0 -0
  152. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/docling_client.py +0 -0
  153. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/document_processing.py +0 -0
  154. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/embedding_fields.py +0 -0
  155. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/embeddings.py +0 -0
  156. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/encryption.py +0 -0
  157. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/env_utils.py +0 -0
  158. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/file_utils.py +0 -0
  159. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/gpu_detection.py +0 -0
  160. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/hash_utils.py +0 -0
  161. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/langflow_headers.py +0 -0
  162. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/langflow_utils.py +0 -0
  163. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/logging_config.py +0 -0
  164. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/opensearch_queries.py +0 -0
  165. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/opensearch_utils.py +0 -0
  166. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/paths.py +0 -0
  167. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/run_mode_utils.py +0 -0
  168. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/telemetry/__init__.py +0 -0
  169. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/telemetry/category.py +0 -0
  170. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/telemetry/client.py +0 -0
  171. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/telemetry/message_id.py +0 -0
  172. {openrag-0.5.0.dev33 → openrag-0.5.0.dev35}/src/utils/version_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openrag
3
- Version: 0.5.0.dev33
3
+ Version: 0.5.0.dev35
4
4
  Summary: OpenRAG is a comprehensive Retrieval-Augmented Generation platform that enables intelligent document search and AI-powered conversations.
5
5
  Classifier: Development Status :: 4 - Beta
6
6
  Classifier: Environment :: Console
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "openrag"
7
- version = "0.5.0.dev33"
7
+ version = "0.5.0.dev35"
8
8
  description = "OpenRAG is a comprehensive Retrieval-Augmented Generation platform that enables intelligent document search and AI-powered conversations."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openrag
3
- Version: 0.5.0.dev33
3
+ Version: 0.5.0.dev35
4
4
  Summary: OpenRAG is a comprehensive Retrieval-Augmented Generation platform that enables intelligent document search and AI-powered conversations.
5
5
  Classifier: Development Status :: 4 - Beta
6
6
  Classifier: Environment :: Console
@@ -828,7 +828,7 @@
828
828
  ],
829
829
  "frozen": false,
830
830
  "icon": "braces",
831
- "last_updated": "2026-04-15T17:08:23.611Z",
831
+ "last_updated": "2026-05-26T19:04:35.148Z",
832
832
  "legacy": false,
833
833
  "lf_version": "1.7.0.dev21",
834
834
  "metadata": {},
@@ -878,7 +878,7 @@
878
878
  "value": "5488df7c-b93f-4f87-a446-b67028bc0813"
879
879
  },
880
880
  "_frontend_node_folder_id": {
881
- "value": "e37c04f4-bd18-4083-8f6f-6ee172319d91"
881
+ "value": "d61134a0-3f8e-4e89-9165-ce13f2a14ac6"
882
882
  },
883
883
  "_type": "Component",
884
884
  "code": {
@@ -1337,7 +1337,7 @@
1337
1337
  "icon": "Docling",
1338
1338
  "legacy": false,
1339
1339
  "metadata": {
1340
- "code_hash": "409d771a961e",
1340
+ "code_hash": "dcf9aeedd059",
1341
1341
  "dependencies": {
1342
1342
  "dependencies": [
1343
1343
  {
@@ -1346,7 +1346,7 @@
1346
1346
  },
1347
1347
  {
1348
1348
  "name": "docling_core",
1349
- "version": "2.60.1"
1349
+ "version": "2.74.1"
1350
1350
  },
1351
1351
  {
1352
1352
  "name": "pydantic",
@@ -1354,7 +1354,7 @@
1354
1354
  },
1355
1355
  {
1356
1356
  "name": "lfx",
1357
- "version": null
1357
+ "version": "0.4.3"
1358
1358
  }
1359
1359
  ],
1360
1360
  "total_dependencies": 4
@@ -1447,7 +1447,7 @@
1447
1447
  "show": true,
1448
1448
  "title_case": false,
1449
1449
  "type": "code",
1450
- "value": "import base64\nimport time\nfrom concurrent.futures import Future, ThreadPoolExecutor\nfrom pathlib import Path\nfrom typing import Any\n\nimport httpx\nfrom docling_core.types.doc import DoclingDocument\nfrom pydantic import ValidationError\n\nfrom lfx.base.data import BaseFileComponent\nfrom lfx.inputs import IntInput, NestedDictInput, StrInput\nfrom lfx.inputs.inputs import FloatInput\nfrom lfx.schema import Data\nfrom lfx.utils.util import transform_localhost_url\n\n\nclass DoclingRemoteComponent(BaseFileComponent):\n display_name = \"Docling Serve\"\n description = \"Uses Docling to process input documents connecting to your instance of Docling Serve.\"\n documentation = \"https://docling-project.github.io/docling/\"\n trace_type = \"tool\"\n icon = \"Docling\"\n name = \"DoclingRemote\"\n\n MAX_500_RETRIES = 5\n\n # https://docling-project.github.io/docling/usage/supported_formats/\n VALID_EXTENSIONS = [\n \"adoc\",\n \"asciidoc\",\n \"asc\",\n \"bmp\",\n \"csv\",\n \"dotx\",\n \"dotm\",\n \"docm\",\n \"docx\",\n \"htm\",\n \"html\",\n \"jpeg\",\n \"jpg\",\n \"json\",\n \"md\",\n \"pdf\",\n \"png\",\n \"potx\",\n \"ppsx\",\n \"pptm\",\n \"potm\",\n \"ppsm\",\n \"pptx\",\n \"tiff\",\n \"txt\",\n \"xls\",\n \"xlsx\",\n \"xhtml\",\n \"xml\",\n \"webp\",\n ]\n\n inputs = [\n *BaseFileComponent.get_base_inputs(),\n StrInput(\n name=\"api_url\",\n display_name=\"Server address\",\n info=\"URL of the Docling Serve instance.\",\n required=True,\n ),\n IntInput(\n name=\"max_concurrency\",\n display_name=\"Concurrency\",\n info=\"Maximum number of concurrent requests for the server.\",\n advanced=True,\n value=2,\n input_types=[\"Message\"],\n ),\n FloatInput(\n name=\"max_poll_timeout\",\n display_name=\"Maximum poll time\",\n info=\"Maximum waiting time for the document conversion to complete.\",\n advanced=True,\n value=3600,\n input_types=[\"Message\"],\n ),\n NestedDictInput(\n name=\"api_headers\",\n display_name=\"HTTP headers\",\n advanced=True,\n required=False,\n info=(\"Optional dictionary of additional headers required for connecting to Docling Serve.\"),\n input_types=[\"Message\"],\n ),\n NestedDictInput(\n name=\"docling_serve_opts\",\n display_name=\"Docling options\",\n advanced=True,\n required=False,\n info=(\n \"Optional dictionary of additional options. \"\n \"See https://github.com/docling-project/docling-serve/blob/main/docs/usage.md for more information.\"\n ),\n input_types=[\"Message\"],\n ),\n ]\n\n outputs = [\n *BaseFileComponent.get_base_outputs(),\n ]\n\n def process_files(self, file_list: list[BaseFileComponent.BaseFile]) -> list[BaseFileComponent.BaseFile]:\n # Transform localhost URLs to container-accessible hosts when running in a container\n transformed_url = transform_localhost_url(self.api_url)\n base_url = f\"{transformed_url}/v1\"\n\n def _convert_document(client: httpx.Client, file_path: Path, options: dict[str, Any]) -> Data | None:\n encoded_doc = base64.b64encode(file_path.read_bytes()).decode()\n payload = {\n \"options\": options,\n \"sources\": [{\"kind\": \"file\", \"base64_string\": encoded_doc, \"filename\": file_path.name}],\n }\n\n response = client.post(f\"{base_url}/convert/source/async\", json=payload)\n response.raise_for_status()\n task = response.json()\n\n http_failures = 0\n retry_status_start = 500\n retry_status_end = 600\n start_wait_time = time.monotonic()\n while task[\"task_status\"] not in (\"success\", \"failure\"):\n # Check if processing exceeds the maximum poll timeout\n processing_time = time.monotonic() - start_wait_time\n if processing_time >= self.max_poll_timeout:\n msg = (\n f\"Processing time {processing_time=} exceeds the maximum poll timeout {self.max_poll_timeout=}.\"\n \"Please increase the max_poll_timeout parameter or review why the processing \"\n \"takes long on the server.\"\n )\n self.log(msg)\n raise RuntimeError(msg)\n\n # Call for a new status update\n time.sleep(2)\n response = client.get(f\"{base_url}/status/poll/{task['task_id']}\")\n\n # Check if the status call gets into 5xx errors and retry\n if retry_status_start <= response.status_code < retry_status_end:\n http_failures += 1\n if http_failures > self.MAX_500_RETRIES:\n self.log(f\"The status requests got a http response {response.status_code} too many times.\")\n return None\n continue\n\n # Update task status\n task = response.json()\n\n result_resp = client.get(f\"{base_url}/result/{task['task_id']}\")\n result_resp.raise_for_status()\n result = result_resp.json()\n\n if \"json_content\" not in result[\"document\"] or result[\"document\"][\"json_content\"] is None:\n self.log(\"No JSON DoclingDocument found in the result.\")\n return None\n\n try:\n doc = DoclingDocument.model_validate(result[\"document\"][\"json_content\"])\n return Data(data={\"doc\": doc, \"file_path\": str(file_path)})\n except ValidationError as e:\n self.log(f\"Error validating the document. {e}\")\n return None\n\n docling_options = {\n \"to_formats\": [\"json\"],\n \"image_export_mode\": \"placeholder\",\n **(self.docling_serve_opts or {}),\n }\n\n processed_data: list[Data | None] = []\n with (\n httpx.Client(headers=self.api_headers) as client,\n ThreadPoolExecutor(max_workers=self.max_concurrency) as executor,\n ):\n futures: list[tuple[int, Future]] = []\n for i, file in enumerate(file_list):\n if file.path is None:\n processed_data.append(None)\n continue\n\n futures.append((i, executor.submit(_convert_document, client, file.path, docling_options)))\n\n for _index, future in futures:\n try:\n result_data = future.result()\n processed_data.append(result_data)\n except (httpx.HTTPStatusError, httpx.RequestError, KeyError, ValueError) as exc:\n self.log(f\"Docling remote processing failed: {exc}\")\n raise\n\n return self.rollup_data(file_list, processed_data)\n"
1450
+ "value": "from __future__ import annotations\n\nimport base64\nimport json\nimport time\nfrom concurrent.futures import Future, ThreadPoolExecutor\nfrom pathlib import Path # noqa: TC003\nfrom typing import Any\n\nimport httpx\nfrom docling_core.types.doc import DoclingDocument\nfrom pydantic import ValidationError\n\nfrom lfx.base.data import BaseFileComponent\nfrom lfx.inputs import IntInput, NestedDictInput, StrInput, TableInput\nfrom lfx.inputs.inputs import FloatInput\nfrom lfx.schema import Data, dotdict\nfrom lfx.utils.util import transform_localhost_url\n\n\nclass DoclingRemoteComponent(BaseFileComponent):\n display_name = \"Docling Serve\"\n description = (\n \"Uses Docling to process input documents connecting to your instance of Docling Serve.\"\n )\n documentation = \"https://docling-project.github.io/docling/\"\n trace_type = \"tool\"\n icon = \"Docling\"\n name = \"DoclingRemote\"\n\n MAX_500_RETRIES = 5\n\n # https://docling-project.github.io/docling/usage/supported_formats/\n VALID_EXTENSIONS = [\n \"adoc\",\n \"asciidoc\",\n \"asc\",\n \"bmp\",\n \"csv\",\n \"dotx\",\n \"dotm\",\n \"docm\",\n \"docx\",\n \"htm\",\n \"html\",\n \"jpeg\",\n \"jpg\",\n \"json\",\n \"md\",\n \"pdf\",\n \"png\",\n \"potx\",\n \"ppsx\",\n \"pptm\",\n \"potm\",\n \"ppsm\",\n \"pptx\",\n \"tiff\",\n \"txt\",\n \"xls\",\n \"xlsx\",\n \"xhtml\",\n \"xml\",\n \"webp\",\n ]\n\n inputs = [\n *BaseFileComponent.get_base_inputs(),\n StrInput(\n name=\"api_url\",\n display_name=\"Server address\",\n info=\"URL of the Docling Serve instance.\",\n required=True,\n ),\n StrInput(\n name=\"task_id\",\n display_name=\"Task ID\",\n info=(\n \"Optional task ID from a previous Docling Serve upload. \"\n \"If provided, file input is ignored and the component polls for this task's results.\"\n ),\n required=False,\n ),\n IntInput(\n name=\"max_concurrency\",\n display_name=\"Concurrency\",\n info=\"Maximum number of concurrent requests for the server.\",\n advanced=True,\n value=2,\n input_types=[\"Message\"],\n ),\n FloatInput(\n name=\"max_poll_timeout\",\n display_name=\"Maximum poll time\",\n info=\"Maximum waiting time for the document conversion to complete.\",\n advanced=True,\n value=3600,\n input_types=[\"Message\"],\n ),\n TableInput(\n name=\"api_headers\",\n display_name=\"HTTP headers\",\n advanced=True,\n required=False,\n info=(\"Optional headers required for connecting to Docling Serve.\"),\n table_schema=[\n {\n \"name\": \"key\",\n \"display_name\": \"Key\",\n \"type\": \"string\",\n \"description\": \"Key name\",\n },\n {\n \"name\": \"value\",\n \"display_name\": \"Value\",\n \"load_from_db\": True,\n \"type\": \"string\",\n \"description\": \"Value of the header\",\n },\n ],\n value=[],\n real_time_refresh=True,\n input_types=[\"Data\", \"JSON\"],\n ),\n NestedDictInput(\n name=\"docling_serve_opts\",\n display_name=\"Docling options\",\n advanced=True,\n required=False,\n info=(\n \"Optional dictionary of additional options. \"\n \"See https://github.com/docling-project/docling-serve/blob/main/docs/usage.md for more information.\"\n ),\n input_types=[\"Message\"],\n ),\n ]\n\n outputs = [\n *BaseFileComponent.get_base_outputs(),\n ]\n\n def _process_headers(self) -> dict[str, str]:\n \"\"\"Process the headers input into a valid dictionary.\"\"\"\n if not self.api_headers:\n return {}\n\n component_headers_dict = {}\n # TableInput normalizes to list\n items = self.api_headers if isinstance(self.api_headers, list) else [self.api_headers]\n\n for item in items:\n if not item:\n continue\n\n # Case 1: Data object\n if hasattr(item, \"data\") and isinstance(item.data, dict):\n data = item.data\n if \"key\" in data and \"value\" in data:\n component_headers_dict[str(data[\"key\"])] = str(data[\"value\"])\n else:\n # Fallback: merge all keys from Data object\n for k, v in data.items():\n if k not in (\"text_key\", \"default_value\"):\n component_headers_dict[str(k)] = str(v)\n\n # Case 2: Dictionary (Table row)\n elif isinstance(item, dict):\n if \"key\" in item and \"value\" in item:\n component_headers_dict[str(item[\"key\"])] = str(item[\"value\"])\n else:\n # Fallback: merge all keys\n for k, v in item.items():\n component_headers_dict[str(k)] = str(v)\n\n # Case 3: Message object\n elif hasattr(item, \"text\") and isinstance(item.text, str):\n try:\n parsed = json.loads(item.text)\n if isinstance(parsed, dict):\n for k, v in parsed.items():\n component_headers_dict[str(k)] = str(v)\n except json.JSONDecodeError:\n pass\n\n return component_headers_dict\n\n def update_build_config(\n self, build_config: dotdict, field_value: Any, field_name: str | None = None\n ) -> dotdict:\n if field_name == \"api_headers\":\n if isinstance(field_value, dict):\n # If it's a dict, convert to list of {key, value} pairs for TableInput\n # This handles migration from NestedDictInput to TableInput\n new_value = [{\"key\": k, \"value\": v} for k, v in field_value.items()]\n build_config[\"api_headers\"][\"value\"] = new_value\n return build_config\n if field_value is None:\n build_config[\"api_headers\"][\"value\"] = []\n return build_config\n\n # Default behavior\n return super().update_build_config(build_config, field_value, field_name)\n\n def _poll_and_fetch_result(\n self, client: httpx.Client, base_url: str, task_id: str, file_path: str | None = None\n ) -> Data | None:\n \"\"\"Poll for task completion and fetch the result.\n\n Args:\n client: The HTTP client to use for requests.\n base_url: The base URL of the Docling Serve API.\n task_id: The task ID to poll for.\n file_path: Optional file path to include in the result data.\n\n Returns:\n Data object with the DoclingDocument, or None if processing failed.\n \"\"\"\n http_failures = 0\n retry_status_start = 500\n retry_status_end = 600\n start_wait_time = time.monotonic()\n\n response = client.get(f\"{base_url}/status/poll/{task_id}\")\n response.raise_for_status()\n task = response.json()\n\n while task[\"task_status\"] not in (\"success\", \"failure\"):\n processing_time = time.monotonic() - start_wait_time\n if processing_time >= self.max_poll_timeout:\n msg = (\n f\"Processing time {processing_time=} exceeds the maximum poll timeout {self.max_poll_timeout=}.\"\n \"Please increase the max_poll_timeout parameter or review why the processing \"\n \"takes long on the server.\"\n )\n self.log(msg)\n raise RuntimeError(msg)\n\n time.sleep(2)\n response = client.get(f\"{base_url}/status/poll/{task_id}\")\n\n if retry_status_start <= response.status_code < retry_status_end:\n http_failures += 1\n if http_failures > self.MAX_500_RETRIES:\n self.log(\n f\"The status requests got a http response {response.status_code} too many times.\"\n )\n return None\n continue\n\n task = response.json()\n\n result_resp = client.get(f\"{base_url}/result/{task_id}\")\n result_resp.raise_for_status()\n result = result_resp.json()\n\n if result.get(\"status\") == \"failure\" or result.get(\"errors\"):\n errors = result.get(\"errors\", [])\n err_msg_list = []\n for err in errors:\n if isinstance(err, dict) and \"error_message\" in err:\n err_msg_list.append(err[\"error_message\"])\n elif isinstance(err, str):\n err_msg_list.append(err)\n\n err_details = \"; \".join(err_msg_list) if err_msg_list else \"Unknown Docling processing error\"\n\n msg = f\"Docling processing failed: {err_details}\"\n raise ValueError(msg)\n\n if \"json_content\" not in result[\"document\"] or result[\"document\"][\"json_content\"] is None:\n self.log(\"No JSON DoclingDocument found in the result.\")\n return None\n\n try:\n doc = DoclingDocument.model_validate(result[\"document\"][\"json_content\"])\n data_dict: dict[str, Any] = {\"doc\": doc}\n if file_path:\n data_dict[\"file_path\"] = file_path\n return Data(data=data_dict)\n except ValidationError as e:\n self.log(f\"Error validating the document. {e}\")\n return None\n\n def _process_task_id(self) -> list[Data]:\n \"\"\"Process an existing task by polling for status and retrieving results.\n\n Returns:\n List containing the result Data object, or empty list if processing failed.\n \"\"\"\n transformed_url = transform_localhost_url(self.api_url)\n base_url = f\"{transformed_url}/v1\"\n\n with httpx.Client(headers=self._process_headers()) as client:\n result = self._poll_and_fetch_result(client, base_url, self.task_id)\n return [result] if result else []\n\n def load_files_base(self) -> list[Data]:\n \"\"\"Load and process files, or poll an existing task if task_id is provided.\n\n Returns:\n list[Data]: Parsed data from the processed files or task.\n \"\"\"\n if self.task_id:\n return self._process_task_id()\n return super().load_files_base()\n\n def process_files(\n self, file_list: list[BaseFileComponent.BaseFile]\n ) -> list[BaseFileComponent.BaseFile]:\n transformed_url = transform_localhost_url(self.api_url)\n base_url = f\"{transformed_url}/v1\"\n\n def _convert_document(\n client: httpx.Client, file_path: Path, options: dict[str, Any]\n ) -> Data | None:\n encoded_doc = base64.b64encode(file_path.read_bytes()).decode()\n payload = {\n \"options\": options,\n \"sources\": [\n {\"kind\": \"file\", \"base64_string\": encoded_doc, \"filename\": file_path.name}\n ],\n }\n\n response = client.post(f\"{base_url}/convert/source/async\", json=payload)\n response.raise_for_status()\n task = response.json()\n\n return self._poll_and_fetch_result(client, base_url, task[\"task_id\"], str(file_path))\n\n docling_options = {\n \"to_formats\": [\"json\"],\n \"image_export_mode\": \"placeholder\",\n **(self.docling_serve_opts or {}),\n }\n\n processed_data: list[Data | None] = []\n with (\n httpx.Client(headers=self._process_headers()) as client,\n ThreadPoolExecutor(max_workers=self.max_concurrency) as executor,\n ):\n futures: list[tuple[int, Future]] = []\n for i, file in enumerate(file_list):\n if file.path is None:\n processed_data.append(None)\n continue\n\n futures.append(\n (i, executor.submit(_convert_document, client, file.path, docling_options))\n )\n\n for _index, future in futures:\n try:\n result_data = future.result()\n processed_data.append(result_data)\n except (httpx.HTTPStatusError, httpx.RequestError, KeyError, ValueError) as exc:\n self.log(f\"Docling remote processing failed: {exc}\")\n raise\n\n return self.rollup_data(file_list, processed_data)\n"
1451
1451
  },
1452
1452
  "delete_server_file_after_processing": {
1453
1453
  "_input_type": "BoolInput",
@@ -1727,8 +1727,8 @@
1727
1727
  "width": 192
1728
1728
  },
1729
1729
  "position": {
1730
- "x": -18.22506037537059,
1731
- "y": 1767.7398128168159
1730
+ "x": -41.950234273170665,
1731
+ "y": 1766.6851884082719
1732
1732
  },
1733
1733
  "selected": false,
1734
1734
  "type": "genericNode"
@@ -4619,7 +4619,7 @@
4619
4619
  "value": "5488df7c-b93f-4f87-a446-b67028bc0813"
4620
4620
  },
4621
4621
  "_frontend_node_folder_id": {
4622
- "value": "e37c04f4-bd18-4083-8f6f-6ee172319d91"
4622
+ "value": "d61134a0-3f8e-4e89-9165-ce13f2a14ac6"
4623
4623
  },
4624
4624
  "_type": "Component",
4625
4625
  "api_base": {
@@ -6371,7 +6371,7 @@
6371
6371
  "value": "5488df7c-b93f-4f87-a446-b67028bc0813"
6372
6372
  },
6373
6373
  "_frontend_node_folder_id": {
6374
- "value": "e37c04f4-bd18-4083-8f6f-6ee172319d91"
6374
+ "value": "d61134a0-3f8e-4e89-9165-ce13f2a14ac6"
6375
6375
  },
6376
6376
  "_type": "Component",
6377
6377
  "api_base": {
@@ -6899,7 +6899,7 @@
6899
6899
  "value": "5488df7c-b93f-4f87-a446-b67028bc0813"
6900
6900
  },
6901
6901
  "_frontend_node_folder_id": {
6902
- "value": "e37c04f4-bd18-4083-8f6f-6ee172319d91"
6902
+ "value": "d61134a0-3f8e-4e89-9165-ce13f2a14ac6"
6903
6903
  },
6904
6904
  "_type": "Component",
6905
6905
  "api_base": {
@@ -7351,16 +7351,16 @@
7351
7351
  }
7352
7352
  ],
7353
7353
  "viewport": {
7354
- "x": -242.06812754438226,
7355
- "y": -952.9999906063429,
7356
- "zoom": 0.6625692775925841
7354
+ "x": 239.96894590419038,
7355
+ "y": -373.3174538705754,
7356
+ "zoom": 0.475706358533402
7357
7357
  }
7358
7358
  },
7359
7359
  "description": "Load your data for chat context with Retrieval Augmented Generation.",
7360
7360
  "endpoint_name": null,
7361
7361
  "id": "5488df7c-b93f-4f87-a446-b67028bc0813",
7362
7362
  "is_component": false,
7363
- "last_tested_version": "1.9.0",
7363
+ "last_tested_version": "1.9.3",
7364
7364
  "locked": true,
7365
7365
  "name": "OpenSearch Ingestion Flow",
7366
7366
  "tags": [
@@ -7369,4 +7369,4 @@
7369
7369
  "rag",
7370
7370
  "q-a"
7371
7371
  ]
7372
- }
7372
+ }
@@ -7,7 +7,9 @@ import sys
7
7
  import tempfile
8
8
  import threading
9
9
  import time
10
- from typing import Optional, Tuple, Dict, Any, List, AsyncIterator
10
+ from collections.abc import AsyncIterator
11
+ from typing import Any
12
+
11
13
  from utils.logging_config import get_logger
12
14
 
13
15
  logger = get_logger(__name__)
@@ -29,7 +31,7 @@ class DoclingManager:
29
31
  if self._initialized:
30
32
  return
31
33
 
32
- self._process: Optional[subprocess.Popen] = None
34
+ self._process: subprocess.Popen | None = None
33
35
  self._port = 5001
34
36
  # Bind to all interfaces by default (can be overridden with DOCLING_BIND_HOST env var)
35
37
  self._host = os.getenv("DOCLING_BIND_HOST", "0.0.0.0")
@@ -47,7 +49,7 @@ class DoclingManager:
47
49
  self._log_file_path = self._tui_dir / "docling-serve.log"
48
50
 
49
51
  # Log storage - simplified, no queue
50
- self._log_buffer: List[str] = []
52
+ self._log_buffer: list[str] = []
51
53
  self._max_log_lines = 1000
52
54
  self._log_lock = threading.Lock() # Thread-safe access to log buffer
53
55
 
@@ -71,7 +73,7 @@ class DoclingManager:
71
73
  except Exception as e:
72
74
  self._add_log_entry(f"Failed to save PID file: {e}")
73
75
 
74
- def _load_pid(self) -> Optional[int]:
76
+ def _load_pid(self) -> int | None:
75
77
  """Load the process PID from file."""
76
78
  try:
77
79
  if self._pid_file.exists():
@@ -105,9 +107,7 @@ class DoclingManager:
105
107
  pid = self._load_pid()
106
108
  if pid is not None:
107
109
  if self._is_process_running(pid):
108
- self._add_log_entry(
109
- f"Recovered existing docling-serve process (PID: {pid})"
110
- )
110
+ self._add_log_entry(f"Recovered existing docling-serve process (PID: {pid})")
111
111
  # Mark as external process since we didn't start it in this session
112
112
  self._external_process = True
113
113
  self._running = True
@@ -150,7 +150,7 @@ class DoclingManager:
150
150
  self._external_process = False
151
151
  return False
152
152
 
153
- def check_port_available(self) -> tuple[bool, Optional[str]]:
153
+ def check_port_available(self) -> tuple[bool, str | None]:
154
154
  """Check if the native service port is available.
155
155
 
156
156
  Returns:
@@ -173,7 +173,7 @@ class DoclingManager:
173
173
  # If we can't check, assume it's available
174
174
  return True, None
175
175
 
176
- def get_status(self) -> Dict[str, Any]:
176
+ def get_status(self) -> dict[str, Any]:
177
177
  """Get current status of docling serve."""
178
178
  # Check for starting state first
179
179
  if self._starting:
@@ -230,10 +230,10 @@ class DoclingManager:
230
230
  enable_ui: bool = False,
231
231
  workers: int | None = None,
232
232
  timeout: int = 10,
233
- ) -> Tuple[bool, str]:
233
+ ) -> tuple[bool, str]:
234
234
  """Start docling serve as external process.
235
235
 
236
-
236
+
237
237
  Args:
238
238
  port: Port to listen on (default: 5001)
239
239
  host: Host to bind to (default: from env or 0.0.0.0)
@@ -280,24 +280,33 @@ class DoclingManager:
280
280
  # override file is needed to *replace* (not merely supplement)
281
281
  # opencv-python, because docling-ibm-models hard-depends on it and
282
282
  # the resolver would install both packages otherwise.
283
- override_path: Optional[str] = None
283
+ override_path: str | None = None
284
284
  if sys.platform != "darwin":
285
- fd, override_path = tempfile.mkstemp(
286
- suffix=".txt", prefix="docling_cv_override_"
287
- )
285
+ fd, override_path = tempfile.mkstemp(suffix=".txt", prefix="docling_cv_override_")
288
286
  with os.fdopen(fd, "w") as f:
289
287
  f.write('opencv-python ; python_version < "0"\n')
290
288
 
291
289
  try:
292
- docling_extras = "ocrmac,easyocr,rapidocr,vlm" if sys.platform == "darwin" else "easyocr,rapidocr,vlm"
290
+ docling_extras = (
291
+ "ocrmac,easyocr,rapidocr,vlm"
292
+ if sys.platform == "darwin"
293
+ else "easyocr,rapidocr,vlm"
294
+ )
293
295
 
294
296
  cmd = [
295
297
  "uvx",
296
- "--from", "docling-serve[ui]==1.15.1",
297
- "--with", "onnxruntime",
298
- "--with", "easyocr",
299
- "--with", f"docling[{docling_extras}]",
300
- "--with", "docling-core==2.71.0",
298
+ "--from",
299
+ "docling-serve[ui]==1.20.0",
300
+ "--with",
301
+ "onnxruntime",
302
+ "--with",
303
+ "easyocr",
304
+ "--with",
305
+ f"docling[{docling_extras}]",
306
+ "--with",
307
+ "docling-core==2.77.1",
308
+ "--with",
309
+ "transformers>=5.8.1,<5.9.0",
301
310
  ]
302
311
  if override_path:
303
312
  cmd += ["--override", override_path, "--with", "opencv-python-headless"]
@@ -343,9 +352,7 @@ class DoclingManager:
343
352
  self._start_output_capture()
344
353
 
345
354
  # Wait for the process to start and begin listening
346
- self._add_log_entry(
347
- f"Waiting up to {timeout}s for docling-serve to start listening..."
348
- )
355
+ self._add_log_entry(f"Waiting up to {timeout}s for docling-serve to start listening...")
349
356
 
350
357
  for i in range(timeout):
351
358
  await asyncio.sleep(1.0)
@@ -369,8 +376,8 @@ class DoclingManager:
369
376
  )
370
377
  self._starting = False
371
378
  break
372
- except:
373
- pass
379
+ except Exception as e:
380
+ self._add_log_entry(f"Error waiting for docling-serve: {e}")
374
381
 
375
382
  if (i + 1) % 10 == 0:
376
383
  self._add_log_entry(f"Waiting for startup... ({i + 1}/{timeout}s)")
@@ -382,9 +389,7 @@ class DoclingManager:
382
389
  except OSError:
383
390
  pass
384
391
 
385
- self._add_log_entry(
386
- f"Process PID: {self._process.pid}, Poll: {self._process.poll()}"
387
- )
392
+ self._add_log_entry(f"Process PID: {self._process.pid}, Poll: {self._process.poll()}")
388
393
 
389
394
  if self._process.poll() is not None:
390
395
  # Process already exited - get return code and any output
@@ -447,7 +452,7 @@ class DoclingManager:
447
452
 
448
453
  self._add_log_entry("Starting log file capture thread")
449
454
  try:
450
- with open(self._log_file_path, "r") as f:
455
+ with open(self._log_file_path) as f:
451
456
  while self._running and self._process and self._process.poll() is None:
452
457
  line = f.readline()
453
458
  if line:
@@ -466,7 +471,7 @@ class DoclingManager:
466
471
 
467
472
  self._add_log_entry("Log file capture thread started")
468
473
 
469
- async def stop(self) -> Tuple[bool, str]:
474
+ async def stop(self) -> tuple[bool, str]:
470
475
  """Stop docling serve."""
471
476
  if not self.is_running():
472
477
  return False, "Docling serve is not running"
@@ -497,18 +502,14 @@ class DoclingManager:
497
502
  # This is a process we recovered from PID file
498
503
  pid_to_stop = self._load_pid()
499
504
  if pid_to_stop and self._is_process_running(pid_to_stop):
500
- self._add_log_entry(
501
- f"Stopping process from PID file (PID: {pid_to_stop})"
502
- )
505
+ self._add_log_entry(f"Stopping process from PID file (PID: {pid_to_stop})")
503
506
  try:
504
507
  os.kill(pid_to_stop, 15) # SIGTERM
505
508
  # Wait a bit for graceful shutdown
506
509
  await asyncio.sleep(2)
507
510
  if self._is_process_running(pid_to_stop):
508
511
  # Still running, force kill
509
- self._add_log_entry(
510
- f"Force killing process (PID: {pid_to_stop})"
511
- )
512
+ self._add_log_entry(f"Force killing process (PID: {pid_to_stop})")
512
513
  os.kill(pid_to_stop, 9) # SIGKILL
513
514
  except Exception as e:
514
515
  self._add_log_entry(f"Error stopping external process: {e}")
@@ -533,10 +534,10 @@ class DoclingManager:
533
534
 
534
535
  async def restart(
535
536
  self,
536
- port: Optional[int] = None,
537
- host: Optional[str] = None,
537
+ port: int | None = None,
538
+ host: str | None = None,
538
539
  enable_ui: bool = False,
539
- ) -> Tuple[bool, str]:
540
+ ) -> tuple[bool, str]:
540
541
  """Restart docling serve."""
541
542
  # Use current settings if not specified
542
543
  if port is None:
@@ -560,7 +561,7 @@ class DoclingManager:
560
561
  """Add a manual log entry - useful for debugging."""
561
562
  self._add_log_entry(f"MANUAL: {message}")
562
563
 
563
- def get_logs(self, lines: int = 50) -> Tuple[bool, str]:
564
+ def get_logs(self, lines: int = 50) -> tuple[bool, str]:
564
565
  """Get logs from the docling-serve process."""
565
566
  if self.is_running():
566
567
  with self._log_lock:
@@ -577,10 +578,6 @@ class DoclingManager:
577
578
 
578
579
  async def follow_logs(self) -> AsyncIterator[str]:
579
580
  """Follow logs from the docling-serve process in real-time."""
580
- # First yield status message and any existing logs
581
- display_host = "localhost" if self._host == "0.0.0.0" else self._host
582
- status_msg = f"Docling serve is running on http://{display_host}:{self._port}"
583
-
584
581
  with self._log_lock:
585
582
  if self._log_buffer:
586
583
  yield "\n".join(self._log_buffer)
File without changes
File without changes
File without changes
File without changes
File without changes