OpenRAG 0.2.5__tar.gz → 0.3.1__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 (155) hide show
  1. {openrag-0.2.5/src/openrag.egg-info → openrag-0.3.1}/PKG-INFO +19 -7
  2. {openrag-0.2.5 → openrag-0.3.1}/README.md +8 -6
  3. {openrag-0.2.5 → openrag-0.3.1}/pyproject.toml +13 -1
  4. {openrag-0.2.5 → openrag-0.3.1}/src/agent.py +98 -46
  5. {openrag-0.2.5 → openrag-0.3.1}/src/api/documents.py +94 -39
  6. {openrag-0.2.5 → openrag-0.3.1}/src/api/settings.py +240 -39
  7. {openrag-0.2.5 → openrag-0.3.1}/src/api/v1/chat.py +22 -0
  8. {openrag-0.2.5 → openrag-0.3.1}/src/api/v1/documents.py +8 -28
  9. {openrag-0.2.5 → openrag-0.3.1}/src/config/config_manager.py +4 -1
  10. {openrag-0.2.5 → openrag-0.3.1}/src/config/settings.py +15 -0
  11. {openrag-0.2.5 → openrag-0.3.1}/src/dependencies.py +7 -3
  12. openrag-0.3.1/src/main.py +1933 -0
  13. {openrag-0.2.5 → openrag-0.3.1}/src/models/processors.py +21 -20
  14. openrag-0.3.1/src/models/url.py +157 -0
  15. {openrag-0.2.5 → openrag-0.3.1/src/openrag.egg-info}/PKG-INFO +19 -7
  16. {openrag-0.2.5 → openrag-0.3.1}/src/openrag.egg-info/SOURCES.txt +1 -0
  17. {openrag-0.2.5 → openrag-0.3.1}/src/services/auth_service.py +3 -2
  18. {openrag-0.2.5 → openrag-0.3.1}/src/services/chat_service.py +15 -5
  19. {openrag-0.2.5 → openrag-0.3.1}/src/services/flows_service.py +342 -597
  20. {openrag-0.2.5 → openrag-0.3.1}/src/services/langflow_file_service.py +262 -26
  21. {openrag-0.2.5 → openrag-0.3.1}/src/services/langflow_history_service.py +10 -2
  22. {openrag-0.2.5 → openrag-0.3.1}/src/services/models_service.py +0 -1
  23. {openrag-0.2.5 → openrag-0.3.1}/src/services/search_service.py +5 -5
  24. {openrag-0.2.5 → openrag-0.3.1}/src/services/task_service.py +32 -0
  25. {openrag-0.2.5 → openrag-0.3.1}/src/session_manager.py +12 -16
  26. {openrag-0.2.5 → openrag-0.3.1}/src/tui/_assets/docker-compose.yml +12 -11
  27. {openrag-0.2.5 → openrag-0.3.1}/src/tui/_assets/flows/ingestion_flow.json +2378 -1810
  28. openrag-0.3.1/src/tui/_assets/flows/openrag_agent.json +5230 -0
  29. openrag-0.3.1/src/tui/_assets/flows/openrag_nudges.json +4851 -0
  30. {openrag-0.2.5 → openrag-0.3.1}/src/tui/_assets/flows/openrag_url_mcp.json +1766 -1454
  31. {openrag-0.2.5 → openrag-0.3.1}/src/tui/main.py +15 -2
  32. {openrag-0.2.5 → openrag-0.3.1}/src/tui/managers/container_manager.py +100 -137
  33. {openrag-0.2.5 → openrag-0.3.1}/src/tui/managers/env_manager.py +58 -14
  34. {openrag-0.2.5 → openrag-0.3.1}/src/tui/utils/startup_checks.py +86 -4
  35. {openrag-0.2.5 → openrag-0.3.1}/src/utils/container_utils.py +18 -23
  36. {openrag-0.2.5 → openrag-0.3.1}/src/utils/embedding_fields.py +15 -2
  37. {openrag-0.2.5 → openrag-0.3.1}/src/utils/langflow_headers.py +14 -6
  38. {openrag-0.2.5 → openrag-0.3.1}/src/utils/opensearch_queries.py +1 -1
  39. {openrag-0.2.5 → openrag-0.3.1}/src/utils/telemetry/message_id.py +14 -0
  40. openrag-0.2.5/src/main.py +0 -995
  41. openrag-0.2.5/src/tui/_assets/flows/openrag_agent.json +0 -4795
  42. openrag-0.2.5/src/tui/_assets/flows/openrag_nudges.json +0 -4122
  43. {openrag-0.2.5 → openrag-0.3.1}/LICENSE +0 -0
  44. {openrag-0.2.5 → openrag-0.3.1}/MANIFEST.in +0 -0
  45. {openrag-0.2.5 → openrag-0.3.1}/setup.cfg +0 -0
  46. {openrag-0.2.5 → openrag-0.3.1}/src/api/__init__.py +0 -0
  47. {openrag-0.2.5 → openrag-0.3.1}/src/api/auth.py +0 -0
  48. {openrag-0.2.5 → openrag-0.3.1}/src/api/chat.py +0 -0
  49. {openrag-0.2.5 → openrag-0.3.1}/src/api/connector_router.py +0 -0
  50. {openrag-0.2.5 → openrag-0.3.1}/src/api/connectors.py +0 -0
  51. {openrag-0.2.5 → openrag-0.3.1}/src/api/docling.py +0 -0
  52. {openrag-0.2.5 → openrag-0.3.1}/src/api/flows.py +0 -0
  53. {openrag-0.2.5 → openrag-0.3.1}/src/api/keys.py +0 -0
  54. {openrag-0.2.5 → openrag-0.3.1}/src/api/knowledge_filter.py +0 -0
  55. {openrag-0.2.5 → openrag-0.3.1}/src/api/langflow_files.py +0 -0
  56. {openrag-0.2.5 → openrag-0.3.1}/src/api/models.py +0 -0
  57. {openrag-0.2.5 → openrag-0.3.1}/src/api/nudges.py +0 -0
  58. {openrag-0.2.5 → openrag-0.3.1}/src/api/oidc.py +0 -0
  59. {openrag-0.2.5 → openrag-0.3.1}/src/api/provider_health.py +0 -0
  60. {openrag-0.2.5 → openrag-0.3.1}/src/api/provider_validation.py +0 -0
  61. {openrag-0.2.5 → openrag-0.3.1}/src/api/router.py +0 -0
  62. {openrag-0.2.5 → openrag-0.3.1}/src/api/search.py +0 -0
  63. {openrag-0.2.5 → openrag-0.3.1}/src/api/tasks.py +0 -0
  64. {openrag-0.2.5 → openrag-0.3.1}/src/api/upload.py +0 -0
  65. {openrag-0.2.5 → openrag-0.3.1}/src/api/v1/__init__.py +0 -0
  66. {openrag-0.2.5 → openrag-0.3.1}/src/api/v1/knowledge_filters.py +0 -0
  67. {openrag-0.2.5 → openrag-0.3.1}/src/api/v1/models.py +0 -0
  68. {openrag-0.2.5 → openrag-0.3.1}/src/api/v1/search.py +0 -0
  69. {openrag-0.2.5 → openrag-0.3.1}/src/api/v1/settings.py +0 -0
  70. {openrag-0.2.5 → openrag-0.3.1}/src/auth_context.py +0 -0
  71. {openrag-0.2.5 → openrag-0.3.1}/src/config/__init__.py +0 -0
  72. {openrag-0.2.5 → openrag-0.3.1}/src/config/model_constants.py +0 -0
  73. {openrag-0.2.5 → openrag-0.3.1}/src/connectors/__init__.py +0 -0
  74. {openrag-0.2.5 → openrag-0.3.1}/src/connectors/base.py +0 -0
  75. {openrag-0.2.5 → openrag-0.3.1}/src/connectors/connection_manager.py +0 -0
  76. {openrag-0.2.5 → openrag-0.3.1}/src/connectors/google_drive/__init__.py +0 -0
  77. {openrag-0.2.5 → openrag-0.3.1}/src/connectors/google_drive/connector.py +0 -0
  78. {openrag-0.2.5 → openrag-0.3.1}/src/connectors/google_drive/oauth.py +0 -0
  79. {openrag-0.2.5 → openrag-0.3.1}/src/connectors/langflow_connector_service.py +0 -0
  80. {openrag-0.2.5 → openrag-0.3.1}/src/connectors/onedrive/__init__.py +0 -0
  81. {openrag-0.2.5 → openrag-0.3.1}/src/connectors/onedrive/connector.py +0 -0
  82. {openrag-0.2.5 → openrag-0.3.1}/src/connectors/onedrive/oauth.py +0 -0
  83. {openrag-0.2.5 → openrag-0.3.1}/src/connectors/service.py +0 -0
  84. {openrag-0.2.5 → openrag-0.3.1}/src/connectors/sharepoint/__init__.py +0 -0
  85. {openrag-0.2.5 → openrag-0.3.1}/src/connectors/sharepoint/connector.py +0 -0
  86. {openrag-0.2.5 → openrag-0.3.1}/src/connectors/sharepoint/oauth.py +0 -0
  87. {openrag-0.2.5 → openrag-0.3.1}/src/connectors/sharepoint/utils.py +0 -0
  88. {openrag-0.2.5 → openrag-0.3.1}/src/models/__init__.py +0 -0
  89. {openrag-0.2.5 → openrag-0.3.1}/src/models/tasks.py +0 -0
  90. {openrag-0.2.5 → openrag-0.3.1}/src/openrag.egg-info/dependency_links.txt +0 -0
  91. {openrag-0.2.5 → openrag-0.3.1}/src/openrag.egg-info/entry_points.txt +0 -0
  92. {openrag-0.2.5 → openrag-0.3.1}/src/openrag.egg-info/requires.txt +0 -0
  93. {openrag-0.2.5 → openrag-0.3.1}/src/openrag.egg-info/top_level.txt +0 -0
  94. {openrag-0.2.5 → openrag-0.3.1}/src/services/__init__.py +0 -0
  95. {openrag-0.2.5 → openrag-0.3.1}/src/services/api_key_service.py +0 -0
  96. {openrag-0.2.5 → openrag-0.3.1}/src/services/conversation_persistence_service.py +0 -0
  97. {openrag-0.2.5 → openrag-0.3.1}/src/services/document_service.py +0 -0
  98. {openrag-0.2.5 → openrag-0.3.1}/src/services/knowledge_filter_service.py +0 -0
  99. {openrag-0.2.5 → openrag-0.3.1}/src/services/langflow_mcp_service.py +0 -0
  100. {openrag-0.2.5 → openrag-0.3.1}/src/services/monitor_service.py +0 -0
  101. {openrag-0.2.5 → openrag-0.3.1}/src/services/session_ownership_service.py +0 -0
  102. {openrag-0.2.5 → openrag-0.3.1}/src/tui/__init__.py +0 -0
  103. {openrag-0.2.5 → openrag-0.3.1}/src/tui/_assets/docker-compose.gpu.yml +0 -0
  104. {openrag-0.2.5 → openrag-0.3.1}/src/tui/_assets/flows/components/ollama_embedding.json +0 -0
  105. {openrag-0.2.5 → openrag-0.3.1}/src/tui/_assets/flows/components/ollama_llm.json +0 -0
  106. {openrag-0.2.5 → openrag-0.3.1}/src/tui/_assets/flows/components/ollama_llm_text.json +0 -0
  107. {openrag-0.2.5 → openrag-0.3.1}/src/tui/_assets/flows/components/watsonx_embedding.json +0 -0
  108. {openrag-0.2.5 → openrag-0.3.1}/src/tui/_assets/flows/components/watsonx_llm.json +0 -0
  109. {openrag-0.2.5 → openrag-0.3.1}/src/tui/_assets/flows/components/watsonx_llm_text.json +0 -0
  110. {openrag-0.2.5 → openrag-0.3.1}/src/tui/_assets/openrag-documents/docling.pdf +0 -0
  111. {openrag-0.2.5 → openrag-0.3.1}/src/tui/_assets/openrag-documents/ibm_anthropic.pdf +0 -0
  112. {openrag-0.2.5 → openrag-0.3.1}/src/tui/_assets/openrag-documents/openrag-documentation.pdf +0 -0
  113. {openrag-0.2.5 → openrag-0.3.1}/src/tui/_assets/openrag-documents/warmup_ocr.pdf +0 -0
  114. {openrag-0.2.5 → openrag-0.3.1}/src/tui/cli.py +0 -0
  115. {openrag-0.2.5 → openrag-0.3.1}/src/tui/config_fields.py +0 -0
  116. {openrag-0.2.5 → openrag-0.3.1}/src/tui/managers/__init__.py +0 -0
  117. {openrag-0.2.5 → openrag-0.3.1}/src/tui/managers/docling_manager.py +0 -0
  118. {openrag-0.2.5 → openrag-0.3.1}/src/tui/screens/__init__.py +0 -0
  119. {openrag-0.2.5 → openrag-0.3.1}/src/tui/screens/config.py +0 -0
  120. {openrag-0.2.5 → openrag-0.3.1}/src/tui/screens/diagnostics.py +0 -0
  121. {openrag-0.2.5 → openrag-0.3.1}/src/tui/screens/logs.py +0 -0
  122. {openrag-0.2.5 → openrag-0.3.1}/src/tui/screens/monitor.py +0 -0
  123. {openrag-0.2.5 → openrag-0.3.1}/src/tui/screens/welcome.py +0 -0
  124. {openrag-0.2.5 → openrag-0.3.1}/src/tui/utils/__init__.py +0 -0
  125. {openrag-0.2.5 → openrag-0.3.1}/src/tui/utils/clipboard.py +0 -0
  126. {openrag-0.2.5 → openrag-0.3.1}/src/tui/utils/platform.py +0 -0
  127. {openrag-0.2.5 → openrag-0.3.1}/src/tui/utils/validation.py +0 -0
  128. {openrag-0.2.5 → openrag-0.3.1}/src/tui/utils/version_check.py +0 -0
  129. {openrag-0.2.5 → openrag-0.3.1}/src/tui/widgets/__init__.py +0 -0
  130. {openrag-0.2.5 → openrag-0.3.1}/src/tui/widgets/command_modal.py +0 -0
  131. {openrag-0.2.5 → openrag-0.3.1}/src/tui/widgets/diagnostics_notification.py +0 -0
  132. {openrag-0.2.5 → openrag-0.3.1}/src/tui/widgets/error_notification.py +0 -0
  133. {openrag-0.2.5 → openrag-0.3.1}/src/tui/widgets/factory_reset_warning_modal.py +0 -0
  134. {openrag-0.2.5 → openrag-0.3.1}/src/tui/widgets/flow_backup_warning_modal.py +0 -0
  135. {openrag-0.2.5 → openrag-0.3.1}/src/tui/widgets/prune_options_modal.py +0 -0
  136. {openrag-0.2.5 → openrag-0.3.1}/src/tui/widgets/upgrade_instructions_modal.py +0 -0
  137. {openrag-0.2.5 → openrag-0.3.1}/src/tui/widgets/version_mismatch_warning_modal.py +0 -0
  138. {openrag-0.2.5 → openrag-0.3.1}/src/tui/widgets/waves.py +0 -0
  139. {openrag-0.2.5 → openrag-0.3.1}/src/utils/__init__.py +0 -0
  140. {openrag-0.2.5 → openrag-0.3.1}/src/utils/acl_utils.py +0 -0
  141. {openrag-0.2.5 → openrag-0.3.1}/src/utils/docling_client.py +0 -0
  142. {openrag-0.2.5 → openrag-0.3.1}/src/utils/document_processing.py +0 -0
  143. {openrag-0.2.5 → openrag-0.3.1}/src/utils/embeddings.py +0 -0
  144. {openrag-0.2.5 → openrag-0.3.1}/src/utils/env_utils.py +0 -0
  145. {openrag-0.2.5 → openrag-0.3.1}/src/utils/file_utils.py +0 -0
  146. {openrag-0.2.5 → openrag-0.3.1}/src/utils/gpu_detection.py +0 -0
  147. {openrag-0.2.5 → openrag-0.3.1}/src/utils/hash_utils.py +0 -0
  148. {openrag-0.2.5 → openrag-0.3.1}/src/utils/langflow_utils.py +0 -0
  149. {openrag-0.2.5 → openrag-0.3.1}/src/utils/logging_config.py +0 -0
  150. {openrag-0.2.5 → openrag-0.3.1}/src/utils/opensearch_utils.py +0 -0
  151. {openrag-0.2.5 → openrag-0.3.1}/src/utils/paths.py +0 -0
  152. {openrag-0.2.5 → openrag-0.3.1}/src/utils/telemetry/__init__.py +0 -0
  153. {openrag-0.2.5 → openrag-0.3.1}/src/utils/telemetry/category.py +0 -0
  154. {openrag-0.2.5 → openrag-0.3.1}/src/utils/telemetry/client.py +0 -0
  155. {openrag-0.2.5 → openrag-0.3.1}/src/utils/version_utils.py +0 -0
@@ -1,7 +1,17 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openrag
3
- Version: 0.2.5
3
+ Version: 0.3.1
4
4
  Summary: OpenRAG is a comprehensive Retrieval-Augmented Generation platform that enables intelligent document search and AI-powered conversations.
5
+ Classifier: Development Status :: 4 - Beta
6
+ Classifier: Environment :: Console
7
+ Classifier: Intended Audience :: Developers
8
+ Classifier: Intended Audience :: Science/Research
9
+ Classifier: License :: OSI Approved :: Apache Software License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
14
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
5
15
  Requires-Python: >=3.13
6
16
  Description-Content-Type: text/markdown
7
17
  License-File: LICENSE
@@ -30,7 +40,7 @@ Dynamic: license-file
30
40
 
31
41
  <div align="center">
32
42
 
33
- <img src="./docs/static/img/openrag-logo-dog.svg" alt="OpenRAG Logo" width="120"/>
43
+ <img src="./docs/static/img/openrag-logo-dog.svg" alt="" width="120"/>
34
44
 
35
45
  # OpenRAG
36
46
 
@@ -39,7 +49,7 @@ Dynamic: license-file
39
49
  </h3>
40
50
 
41
51
  <!-- Badges -->
42
-
52
+
43
53
  [![Langflow](https://img.shields.io/badge/Langflow-1C1C1E?style=for-the-badge&logo=langflow)](https://github.com/langflow-ai/langflow)
44
54
  [![OpenSearch](https://img.shields.io/badge/OpenSearch-005EB8?style=for-the-badge&logo=opensearch&logoColor=white)](https://github.com/opensearch-project/OpenSearch)
45
55
  [![Docling](https://img.shields.io/badge/Docling-000000?style=for-the-badge)](https://github.com/docling-project/docling)
@@ -48,7 +58,7 @@ Dynamic: license-file
48
58
  [![GitHub stars](https://img.shields.io/github/stars/langflow-ai/openrag?style=social)](https://github.com/langflow-ai/openrag/stargazers)
49
59
  [![GitHub forks](https://img.shields.io/github/forks/langflow-ai/openrag?style=social)](https://github.com/langflow-ai/openrag/network/members)
50
60
 
51
- [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/langflow-ai/openrag)
61
+ [![Documentation](https://img.shields.io/badge/Documentation-773eff)](https://docs.openr.ag) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/langflow-ai/openrag)
52
62
 
53
63
  </div>
54
64
 
@@ -56,9 +66,11 @@ Dynamic: license-file
56
66
 
57
67
  OpenRAG is a comprehensive Retrieval-Augmented Generation platform that enables intelligent document search and AI-powered conversations.
58
68
 
59
- Users can upload, process, and query documents through a chat interface backed by large language models and semantic search capabilities. The system utilizes Langflow for document ingestion, retrieval workflows, and intelligent nudges, providing a seamless RAG experience.
69
+ Users can upload, process, and query documents through a chat interface backed by large language models and semantic search capabilities. The system utilizes Langflow for document ingestion, retrieval workflows, and intelligent nudges, providing a seamless RAG experience.
70
+
71
+ Check out the [documentation](https://docs.openr.ag/) or get started with the [quickstart](https://docs.openr.ag/quickstart).
60
72
 
61
- Built with [Starlette](https://github.com/Kludex/starlette) and [Next.js](https://github.com/vercel/next.js).
73
+ Built with [FastAPI](https://fastapi.tiangolo.com/) and [Next.js](https://github.com/vercel/next.js).
62
74
  Powered by [OpenSearch](https://github.com/opensearch-project/OpenSearch), [Langflow](https://github.com/langflow-ai/langflow), and [Docling](https://github.com/docling-project/docling).
63
75
 
64
76
  ---
@@ -189,7 +201,7 @@ The MCP server provides tools for RAG-enhanced chat, semantic search, and settin
189
201
 
190
202
  For developers who want to [contribute to OpenRAG](https://docs.openr.ag/support/contribute) or set up a development environment, see [CONTRIBUTING.md](CONTRIBUTING.md).
191
203
 
192
- ## 🆘 Troubleshooting
204
+ ## 🛟 Troubleshooting
193
205
 
194
206
  For assistance with OpenRAG, see [Troubleshoot OpenRAG](https://docs.openr.ag/support/troubleshoot) and visit the [Discussions page](https://github.com/langflow-ai/openrag/discussions).
195
207
 
@@ -1,6 +1,6 @@
1
1
  <div align="center">
2
2
 
3
- <img src="./docs/static/img/openrag-logo-dog.svg" alt="OpenRAG Logo" width="120"/>
3
+ <img src="./docs/static/img/openrag-logo-dog.svg" alt="" width="120"/>
4
4
 
5
5
  # OpenRAG
6
6
 
@@ -9,7 +9,7 @@
9
9
  </h3>
10
10
 
11
11
  <!-- Badges -->
12
-
12
+
13
13
  [![Langflow](https://img.shields.io/badge/Langflow-1C1C1E?style=for-the-badge&logo=langflow)](https://github.com/langflow-ai/langflow)
14
14
  [![OpenSearch](https://img.shields.io/badge/OpenSearch-005EB8?style=for-the-badge&logo=opensearch&logoColor=white)](https://github.com/opensearch-project/OpenSearch)
15
15
  [![Docling](https://img.shields.io/badge/Docling-000000?style=for-the-badge)](https://github.com/docling-project/docling)
@@ -18,7 +18,7 @@
18
18
  [![GitHub stars](https://img.shields.io/github/stars/langflow-ai/openrag?style=social)](https://github.com/langflow-ai/openrag/stargazers)
19
19
  [![GitHub forks](https://img.shields.io/github/forks/langflow-ai/openrag?style=social)](https://github.com/langflow-ai/openrag/network/members)
20
20
 
21
- [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/langflow-ai/openrag)
21
+ [![Documentation](https://img.shields.io/badge/Documentation-773eff)](https://docs.openr.ag) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/langflow-ai/openrag)
22
22
 
23
23
  </div>
24
24
 
@@ -26,9 +26,11 @@
26
26
 
27
27
  OpenRAG is a comprehensive Retrieval-Augmented Generation platform that enables intelligent document search and AI-powered conversations.
28
28
 
29
- Users can upload, process, and query documents through a chat interface backed by large language models and semantic search capabilities. The system utilizes Langflow for document ingestion, retrieval workflows, and intelligent nudges, providing a seamless RAG experience.
29
+ Users can upload, process, and query documents through a chat interface backed by large language models and semantic search capabilities. The system utilizes Langflow for document ingestion, retrieval workflows, and intelligent nudges, providing a seamless RAG experience.
30
+
31
+ Check out the [documentation](https://docs.openr.ag/) or get started with the [quickstart](https://docs.openr.ag/quickstart).
30
32
 
31
- Built with [Starlette](https://github.com/Kludex/starlette) and [Next.js](https://github.com/vercel/next.js).
33
+ Built with [FastAPI](https://fastapi.tiangolo.com/) and [Next.js](https://github.com/vercel/next.js).
32
34
  Powered by [OpenSearch](https://github.com/opensearch-project/OpenSearch), [Langflow](https://github.com/langflow-ai/langflow), and [Docling](https://github.com/docling-project/docling).
33
35
 
34
36
  ---
@@ -159,7 +161,7 @@ The MCP server provides tools for RAG-enhanced chat, semantic search, and settin
159
161
 
160
162
  For developers who want to [contribute to OpenRAG](https://docs.openr.ag/support/contribute) or set up a development environment, see [CONTRIBUTING.md](CONTRIBUTING.md).
161
163
 
162
- ## 🆘 Troubleshooting
164
+ ## 🛟 Troubleshooting
163
165
 
164
166
  For assistance with OpenRAG, see [Troubleshoot OpenRAG](https://docs.openr.ag/support/troubleshoot) and visit the [Discussions page](https://github.com/langflow-ai/openrag/discussions).
165
167
 
@@ -4,10 +4,22 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "openrag"
7
- version = "0.2.5"
7
+ version = "0.3.1"
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"
11
+ classifiers = [
12
+ "Development Status :: 4 - Beta",
13
+ "Environment :: Console",
14
+ "Intended Audience :: Developers",
15
+ "Intended Audience :: Science/Research",
16
+ "License :: OSI Approved :: Apache Software License",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3 :: Only",
19
+ "Programming Language :: Python :: 3.13",
20
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
21
+ "Topic :: Software Development :: Libraries :: Python Modules",
22
+ ]
11
23
  dependencies = [
12
24
  "agentd>=0.2.2",
13
25
  "aiofiles>=24.1.0",
@@ -135,14 +135,13 @@ async def async_response_stream(
135
135
 
136
136
  full_response = ""
137
137
  chunk_count = 0
138
- detected_tool_call = False # Track if we've detected a tool call
138
+ detected_tool_call = False
139
139
  async for chunk in response:
140
140
  chunk_count += 1
141
141
  logger.debug(
142
142
  "Stream chunk received", chunk_count=chunk_count, chunk=str(chunk)
143
143
  )
144
144
 
145
- # Yield the raw event as JSON for the UI to process
146
145
  import json
147
146
 
148
147
  # Also extract text content for logging
@@ -186,7 +185,7 @@ async def async_response_stream(
186
185
  if isinstance(chunk_data, dict):
187
186
  # Check for any fields that might indicate tool usage
188
187
  potential_tool_fields = {
189
- k: v for k, v in chunk_data.items()
188
+ k: v for k, v in chunk_data.items()
190
189
  if any(keyword in str(k).lower() for keyword in ['tool', 'call', 'retrieval', 'function', 'result', 'output'])
191
190
  }
192
191
  if potential_tool_fields:
@@ -235,8 +234,8 @@ async def async_response_stream(
235
234
  "tool_name": "Retrieval",
236
235
  "status": "completed",
237
236
  "inputs": {"implicit": True, "backend_detected": True},
238
- "results": chunk_data.get('results') or chunk_data.get('outputs') or
239
- chunk_data.get('retrieved_documents') or
237
+ "results": chunk_data.get('results') or chunk_data.get('outputs') or
238
+ chunk_data.get('retrieved_documents') or
240
239
  chunk_data.get('retrieval_results') or []
241
240
  }
242
241
  }
@@ -625,8 +624,25 @@ async def async_langflow_chat(
625
624
  message_count=len(conversation_state["messages"]),
626
625
  )
627
626
 
627
+ # Extract sources from retrieval tool calls in the response
628
+ sources = []
629
+ if hasattr(response_obj, "output") and response_obj.output:
630
+ for output_item in response_obj.output:
631
+ item_type = getattr(output_item, "type", None)
632
+ if item_type in ("tool_call", "retrieval_call"):
633
+ for result in getattr(output_item, "results", None) or []:
634
+ rd = result.model_dump() if hasattr(result, "model_dump") else (result if isinstance(result, dict) else {})
635
+ if "text" in rd:
636
+ sources.append({
637
+ "filename": rd.get("filename", ""),
638
+ "text": rd.get("text", ""),
639
+ "score": rd.get("score", 0),
640
+ "page": rd.get("page"),
641
+ "mimetype": rd.get("mimetype"),
642
+ })
643
+
628
644
  if not store_conversation:
629
- return response_text, response_id
645
+ return response_text, response_id, sources
630
646
 
631
647
  # Store the conversation thread with its response_id
632
648
  if response_id:
@@ -662,7 +678,7 @@ async def async_langflow_chat(
662
678
  else:
663
679
  logger.warning("No response_id received from langflow, conversation not stored")
664
680
 
665
- return response_text, response_id
681
+ return response_text, response_id, sources
666
682
 
667
683
 
668
684
  # Async langflow function with conversation storage (streaming)
@@ -698,47 +714,55 @@ async def async_langflow_chat_stream(
698
714
  response_id = None
699
715
  usage_data = None
700
716
  collected_chunks = [] # Store all chunks for function call data
717
+ error_occurred = False
701
718
 
702
- async for chunk in async_stream(
703
- langflow_client,
704
- prompt,
705
- flow_id,
706
- extra_headers=extra_headers,
707
- previous_response_id=previous_response_id,
708
- log_prefix="langflow",
709
- ):
710
- # Extract text content to build full response for history
711
- try:
712
- import json
713
-
714
- chunk_data = json.loads(chunk.decode("utf-8"))
715
- collected_chunks.append(chunk_data) # Collect all chunk data
716
-
717
- if "delta" in chunk_data and "content" in chunk_data["delta"]:
718
- full_response += chunk_data["delta"]["content"]
719
- # Extract response_id from chunk
720
- if "id" in chunk_data:
721
- response_id = chunk_data["id"]
722
- elif "response_id" in chunk_data:
723
- response_id = chunk_data["response_id"]
724
- # Capture usage from response.completed event
725
- if chunk_data.get("type") == "response.completed":
726
- response_obj = chunk_data.get("response", {})
727
- usage_data = response_obj.get("usage")
728
- except:
729
- pass
730
- yield chunk
719
+ try:
720
+ async for chunk in async_stream(
721
+ langflow_client,
722
+ prompt,
723
+ flow_id,
724
+ extra_headers=extra_headers,
725
+ previous_response_id=previous_response_id,
726
+ log_prefix="langflow",
727
+ ):
728
+ # Extract text content to build full response for history
729
+ try:
730
+ import json
731
+
732
+ chunk_data = json.loads(chunk.decode("utf-8"))
733
+ collected_chunks.append(chunk_data) # Collect all chunk data
734
+
735
+ if "delta" in chunk_data and "content" in chunk_data["delta"]:
736
+ full_response += chunk_data["delta"]["content"]
737
+ # Extract response_id from chunk
738
+ if "id" in chunk_data:
739
+ response_id = chunk_data["id"]
740
+ elif "response_id" in chunk_data:
741
+ response_id = chunk_data["response_id"]
742
+
743
+ # Check for error status
744
+ if chunk_data.get("finish_reason") == "error" or chunk_data.get("status") == "failed":
745
+ error_occurred = True
746
+ logger.error("Error detected in Langflow stream chunk")
747
+ # Capture usage from response.completed event
748
+ if chunk_data.get("type") == "response.completed":
749
+ response_obj = chunk_data.get("response", {})
750
+ usage_data = response_obj.get("usage")
751
+ except:
752
+ pass
753
+ yield chunk
731
754
 
732
- # Add the complete assistant response to message history with response_id, timestamp, and function call data
733
- if full_response:
734
- assistant_message = {
735
- "role": "assistant",
736
- "content": full_response,
737
- "response_id": response_id,
738
- "timestamp": datetime.now(),
739
- "chunks": collected_chunks, # Store complete chunk data for function calls
740
- }
741
- # Store usage data if available (from response.completed event)
755
+ # Add the complete assistant response to message history with response_id, timestamp, and function call data
756
+ if full_response:
757
+ assistant_message = {
758
+ "role": "assistant",
759
+ "content": full_response,
760
+ "response_id": response_id,
761
+ "timestamp": datetime.now(),
762
+ "chunks": collected_chunks, # Store complete chunk data for function calls
763
+ "error": error_occurred, # Mark if this was an error response
764
+ }
765
+ # Store usage data if available (from response.completed event)
742
766
  if usage_data:
743
767
  assistant_message["response_data"] = {"usage": usage_data}
744
768
  conversation_state["messages"].append(assistant_message)
@@ -760,6 +784,34 @@ async def async_langflow_chat_stream(
760
784
  logger.debug(
761
785
  f"Stored langflow conversation thread for user {user_id} with response_id: {response_id}"
762
786
  )
787
+ except Exception as e:
788
+ # Log the error
789
+ logger.error(f"Error in langflow chat stream: {e}", exc_info=True)
790
+ error_occurred = True
791
+
792
+ # Store error message in conversation history so it persists
793
+ error_message = {
794
+ "role": "assistant",
795
+ "content": f"Sorry, I encountered an error: {str(e)}",
796
+ "timestamp": datetime.now(),
797
+ "error": True,
798
+ }
799
+ conversation_state["messages"].append(error_message)
800
+
801
+ # Try to store the conversation with error message
802
+ # Use a temporary response_id if we don't have one
803
+ if not response_id:
804
+ response_id = f"error_{user_id}_{int(datetime.now().timestamp())}"
805
+
806
+ try:
807
+ conversation_state["last_activity"] = datetime.now()
808
+ await store_conversation_thread(user_id, response_id, conversation_state)
809
+ logger.debug(f"Stored conversation with error for user {user_id}")
810
+ except Exception as store_error:
811
+ logger.error(f"Failed to store error conversation: {store_error}")
812
+
813
+ # Re-raise the exception so it propagates to the API layer
814
+ raise
763
815
 
764
816
 
765
817
  async def delete_user_conversation(user_id: str, response_id: str) -> bool:
@@ -13,6 +13,92 @@ class DeleteDocumentBody(BaseModel):
13
13
  filename: str
14
14
 
15
15
 
16
+ async def delete_documents_by_filename_core(
17
+ filename: str,
18
+ session_manager,
19
+ user_id: str,
20
+ jwt_token: str | None,
21
+ ):
22
+ """Shared delete-by-filename logic for v1 and non-v1 endpoints."""
23
+ from config.settings import get_index_name
24
+ from utils.opensearch_queries import build_filename_delete_body
25
+
26
+ normalized_filename = (filename or "").strip()
27
+ if not normalized_filename:
28
+ return (
29
+ {
30
+ "success": False,
31
+ "deleted_chunks": 0,
32
+ "filename": normalized_filename,
33
+ "message": None,
34
+ "error": "Filename is required",
35
+ },
36
+ 400,
37
+ )
38
+
39
+ try:
40
+ opensearch_client = session_manager.get_user_opensearch_client(
41
+ user_id, jwt_token
42
+ )
43
+ delete_query = build_filename_delete_body(normalized_filename)
44
+ result = await opensearch_client.delete_by_query(
45
+ index=get_index_name(),
46
+ body=delete_query,
47
+ conflicts="proceed",
48
+ )
49
+
50
+ deleted_count = result.get("deleted", 0)
51
+ logger.info(
52
+ f"Deleted {deleted_count} chunks for filename {normalized_filename}",
53
+ user_id=user_id,
54
+ )
55
+
56
+ if deleted_count == 0:
57
+ return (
58
+ {
59
+ "success": False,
60
+ "deleted_chunks": 0,
61
+ "filename": normalized_filename,
62
+ "message": None,
63
+ "error": "No matching document chunks were deleted. The file may be missing or not deletable in the current user context.",
64
+ },
65
+ 404,
66
+ )
67
+
68
+ return (
69
+ {
70
+ "success": True,
71
+ "deleted_chunks": deleted_count,
72
+ "filename": normalized_filename,
73
+ "message": f"All documents with filename '{normalized_filename}' deleted successfully",
74
+ "error": None,
75
+ },
76
+ 200,
77
+ )
78
+ except Exception as e:
79
+ logger.error(
80
+ "Error deleting documents by filename",
81
+ filename=normalized_filename,
82
+ error=str(e),
83
+ )
84
+ error_str = str(e)
85
+ status_code = 403 if "AuthenticationException" in error_str else 500
86
+ return (
87
+ {
88
+ "success": False,
89
+ "deleted_chunks": 0,
90
+ "filename": normalized_filename,
91
+ "message": None,
92
+ "error": (
93
+ "Access denied: insufficient permissions"
94
+ if status_code == 403
95
+ else "An internal error has occurred while deleting documents"
96
+ ),
97
+ },
98
+ status_code,
99
+ )
100
+
101
+
16
102
  async def _ensure_index_exists():
17
103
  """Create the OpenSearch index if it doesn't exist yet."""
18
104
  from main import init_index
@@ -70,43 +156,12 @@ async def delete_documents_by_filename(
70
156
  body: DeleteDocumentBody,
71
157
  session_manager=Depends(get_session_manager),
72
158
  user: User = Depends(get_current_user),
73
- ):
159
+ ):
74
160
  """Delete all documents with a specific filename"""
75
- from config.settings import get_index_name
76
-
77
- jwt_token = user.jwt_token
78
-
79
- try:
80
- opensearch_client = session_manager.get_user_opensearch_client(
81
- user.user_id, jwt_token
82
- )
83
-
84
- from utils.opensearch_queries import build_filename_delete_body
85
-
86
- delete_query = build_filename_delete_body(body.filename)
87
-
88
- logger.debug(f"Deleting documents with filename: {body.filename}")
89
-
90
- result = await opensearch_client.delete_by_query(
91
- index=get_index_name(),
92
- body=delete_query,
93
- conflicts="proceed"
94
- )
95
-
96
- deleted_count = result.get("deleted", 0)
97
- logger.info(f"Deleted {deleted_count} chunks for filename {body.filename}", user_id=user.user_id)
98
-
99
- return JSONResponse({
100
- "success": True,
101
- "deleted_chunks": deleted_count,
102
- "filename": body.filename,
103
- "message": f"All documents with filename '{body.filename}' deleted successfully"
104
- }, status_code=200)
105
-
106
- except Exception as e:
107
- logger.error("Error deleting documents by filename", filename=body.filename, error=str(e))
108
- error_str = str(e)
109
- if "AuthenticationException" in error_str:
110
- return JSONResponse({"error": "Access denied: insufficient permissions"}, status_code=403)
111
- else:
112
- return JSONResponse({"error": str(e)}, status_code=500)
161
+ payload, status_code =await delete_documents_by_filename_core(
162
+ filename=body.filename,
163
+ session_manager=session_manager,
164
+ user_id=user.user_id,
165
+ jwt_token=user.jwt_token,
166
+ )
167
+ return JSONResponse(payload, status_code=status_code)