local-deep-research 0.3.11__tar.gz → 0.4.0__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 (194) hide show
  1. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/PKG-INFO +29 -4
  2. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/README.md +19 -2
  3. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/pyproject.toml +13 -2
  4. local_deep_research-0.4.0/src/local_deep_research/__version__.py +1 -0
  5. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/filters/base_filter.py +2 -3
  6. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/filters/cross_engine_filter.py +4 -5
  7. local_deep_research-0.4.0/src/local_deep_research/advanced_search_system/filters/journal_reputation_filter.py +298 -0
  8. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/findings/repository.py +0 -3
  9. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/strategies/base_strategy.py +1 -2
  10. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/strategies/iterdrag_strategy.py +14 -18
  11. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/strategies/parallel_search_strategy.py +4 -8
  12. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/strategies/rapid_search_strategy.py +5 -6
  13. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/strategies/source_based_strategy.py +2 -2
  14. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/strategies/standard_strategy.py +9 -7
  15. local_deep_research-0.4.0/src/local_deep_research/api/benchmark_functions.py +288 -0
  16. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/api/research_functions.py +8 -4
  17. local_deep_research-0.4.0/src/local_deep_research/benchmarks/README.md +162 -0
  18. local_deep_research-0.4.0/src/local_deep_research/benchmarks/__init__.py +51 -0
  19. local_deep_research-0.4.0/src/local_deep_research/benchmarks/benchmark_functions.py +353 -0
  20. local_deep_research-0.4.0/src/local_deep_research/benchmarks/cli/__init__.py +16 -0
  21. local_deep_research-0.4.0/src/local_deep_research/benchmarks/cli/benchmark_commands.py +338 -0
  22. local_deep_research-0.4.0/src/local_deep_research/benchmarks/cli.py +347 -0
  23. local_deep_research-0.4.0/src/local_deep_research/benchmarks/comparison/__init__.py +12 -0
  24. local_deep_research-0.4.0/src/local_deep_research/benchmarks/comparison/evaluator.py +768 -0
  25. local_deep_research-0.4.0/src/local_deep_research/benchmarks/datasets/__init__.py +53 -0
  26. local_deep_research-0.4.0/src/local_deep_research/benchmarks/datasets/base.py +295 -0
  27. local_deep_research-0.4.0/src/local_deep_research/benchmarks/datasets/browsecomp.py +116 -0
  28. local_deep_research-0.4.0/src/local_deep_research/benchmarks/datasets/custom_dataset_template.py +98 -0
  29. local_deep_research-0.4.0/src/local_deep_research/benchmarks/datasets/simpleqa.py +74 -0
  30. local_deep_research-0.4.0/src/local_deep_research/benchmarks/datasets/utils.py +116 -0
  31. local_deep_research-0.4.0/src/local_deep_research/benchmarks/datasets.py +31 -0
  32. local_deep_research-0.4.0/src/local_deep_research/benchmarks/efficiency/__init__.py +14 -0
  33. local_deep_research-0.4.0/src/local_deep_research/benchmarks/efficiency/resource_monitor.py +367 -0
  34. local_deep_research-0.4.0/src/local_deep_research/benchmarks/efficiency/speed_profiler.py +214 -0
  35. local_deep_research-0.4.0/src/local_deep_research/benchmarks/evaluators/__init__.py +18 -0
  36. local_deep_research-0.4.0/src/local_deep_research/benchmarks/evaluators/base.py +74 -0
  37. local_deep_research-0.4.0/src/local_deep_research/benchmarks/evaluators/browsecomp.py +83 -0
  38. local_deep_research-0.4.0/src/local_deep_research/benchmarks/evaluators/composite.py +121 -0
  39. local_deep_research-0.4.0/src/local_deep_research/benchmarks/evaluators/simpleqa.py +271 -0
  40. local_deep_research-0.4.0/src/local_deep_research/benchmarks/graders.py +410 -0
  41. local_deep_research-0.4.0/src/local_deep_research/benchmarks/metrics/README.md +80 -0
  42. local_deep_research-0.4.0/src/local_deep_research/benchmarks/metrics/__init__.py +24 -0
  43. local_deep_research-0.4.0/src/local_deep_research/benchmarks/metrics/calculation.py +385 -0
  44. local_deep_research-0.4.0/src/local_deep_research/benchmarks/metrics/reporting.py +155 -0
  45. local_deep_research-0.4.0/src/local_deep_research/benchmarks/metrics/visualization.py +205 -0
  46. local_deep_research-0.4.0/src/local_deep_research/benchmarks/metrics.py +11 -0
  47. local_deep_research-0.4.0/src/local_deep_research/benchmarks/optimization/__init__.py +32 -0
  48. local_deep_research-0.4.0/src/local_deep_research/benchmarks/optimization/api.py +274 -0
  49. local_deep_research-0.4.0/src/local_deep_research/benchmarks/optimization/metrics.py +20 -0
  50. local_deep_research-0.4.0/src/local_deep_research/benchmarks/optimization/optuna_optimizer.py +1163 -0
  51. local_deep_research-0.4.0/src/local_deep_research/benchmarks/runners.py +434 -0
  52. local_deep_research-0.4.0/src/local_deep_research/benchmarks/templates.py +65 -0
  53. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/config/llm_config.py +37 -25
  54. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/config/search_config.py +2 -6
  55. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/defaults/default_settings.json +109 -8
  56. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/search_system.py +16 -8
  57. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/utilities/db_utils.py +3 -6
  58. local_deep_research-0.4.0/src/local_deep_research/utilities/es_utils.py +441 -0
  59. local_deep_research-0.4.0/src/local_deep_research/utilities/log_utils.py +36 -0
  60. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/utilities/search_utilities.py +8 -9
  61. local_deep_research-0.4.0/src/local_deep_research/utilities/url_utils.py +57 -0
  62. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/app.py +7 -9
  63. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/app_factory.py +9 -12
  64. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/database/migrations.py +8 -5
  65. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/database/models.py +20 -0
  66. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/database/schema_upgrade.py +5 -8
  67. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/models/database.py +15 -18
  68. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/routes/api_routes.py +18 -9
  69. local_deep_research-0.4.0/src/local_deep_research/web/routes/benchmark_routes.py +427 -0
  70. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/routes/research_routes.py +13 -17
  71. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/routes/settings_routes.py +279 -72
  72. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/services/research_service.py +47 -57
  73. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/services/settings_manager.py +1 -4
  74. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/services/settings_service.py +4 -6
  75. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/css/styles.css +12 -0
  76. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/components/logpanel.js +164 -155
  77. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/components/research.js +44 -3
  78. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/components/settings.js +27 -0
  79. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/services/socket.js +47 -0
  80. local_deep_research-0.4.0/src/local_deep_research/web_search_engines/default_search_engines.py +38 -0
  81. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/meta_search_engine.py +100 -33
  82. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/search_engine_arxiv.py +31 -17
  83. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/search_engine_brave.py +8 -3
  84. local_deep_research-0.4.0/src/local_deep_research/web_search_engines/engines/search_engine_elasticsearch.py +343 -0
  85. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/search_engine_google_pse.py +14 -6
  86. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/search_engine_local.py +31 -26
  87. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/search_engine_local_all.py +9 -12
  88. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/search_engine_searxng.py +12 -17
  89. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/search_engine_serpapi.py +8 -4
  90. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/search_engine_base.py +22 -5
  91. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/search_engine_factory.py +32 -11
  92. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/search_engines_config.py +14 -1
  93. local_deep_research-0.4.0/tests/TESTING_PROPOSAL.md +294 -0
  94. local_deep_research-0.4.0/tests/feature_tests/IMPLEMENTATION_GUIDE_241.md +114 -0
  95. local_deep_research-0.4.0/tests/feature_tests/README.md +26 -0
  96. local_deep_research-0.4.0/tests/feature_tests/__init__.py +5 -0
  97. local_deep_research-0.4.0/tests/feature_tests/test_custom_context.py +139 -0
  98. local_deep_research-0.4.0/tests/test_settings_manager.py +98 -0
  99. local_deep_research-0.4.0/tests/test_url_utils.py +55 -0
  100. local_deep_research-0.4.0/tests/test_url_utils_debug.py +33 -0
  101. local_deep_research-0.4.0/tests/test_url_utils_simple.py +39 -0
  102. local_deep_research-0.3.11/src/local_deep_research/__version__.py +0 -1
  103. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/LICENSE +0 -0
  104. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/__init__.py +0 -0
  105. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/__init__.py +0 -0
  106. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/filters/__init__.py +0 -0
  107. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/findings/base_findings.py +0 -0
  108. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/knowledge/__init__.py +0 -0
  109. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/knowledge/base_knowledge.py +0 -0
  110. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/knowledge/standard_knowledge.py +0 -0
  111. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/questions/__init__.py +0 -0
  112. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/questions/base_question.py +0 -0
  113. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/questions/decomposition_question.py +0 -0
  114. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/questions/standard_question.py +0 -0
  115. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/repositories/__init__.py +0 -0
  116. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/strategies/__init__.py +0 -0
  117. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/tools/__init__.py +0 -0
  118. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/tools/base_tool.py +0 -0
  119. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/tools/knowledge_tools/__init__.py +0 -0
  120. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/tools/question_tools/__init__.py +0 -0
  121. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/advanced_search_system/tools/search_tools/__init__.py +0 -0
  122. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/api/__init__.py +0 -0
  123. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/app.py +0 -0
  124. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/citation_handler.py +0 -0
  125. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/config/__init__.py +0 -0
  126. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/defaults/.env.template +0 -0
  127. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/defaults/__init__.py +0 -0
  128. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/migrate_db.py +0 -0
  129. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/report_generator.py +0 -0
  130. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/setup_data_dir.py +0 -0
  131. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/test_migration.py +0 -0
  132. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/utilities/__init__.py +0 -0
  133. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/utilities/enums.py +0 -0
  134. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/utilities/llm_utils.py +0 -0
  135. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/utilities/setup_utils.py +0 -0
  136. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/__init__.py +0 -0
  137. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/database/README.md +0 -0
  138. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/database/migrate_to_ldr_db.py +0 -0
  139. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/models/settings.py +0 -0
  140. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/routes/history_routes.py +0 -0
  141. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/services/resource_service.py +0 -0
  142. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/services/socket_service.py +0 -0
  143. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/css/custom_dropdown.css +0 -0
  144. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/css/settings.css +0 -0
  145. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/components/custom_dropdown.js +0 -0
  146. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/components/detail.js +0 -0
  147. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/components/fallback/formatting.js +0 -0
  148. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/components/fallback/ui.js +0 -0
  149. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/components/history.js +0 -0
  150. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/components/progress.js +0 -0
  151. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/components/results.js +0 -0
  152. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/components/settings_sync.js +0 -0
  153. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/main.js +0 -0
  154. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/research_form.js +0 -0
  155. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/services/api.js +0 -0
  156. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/services/audio.js +0 -0
  157. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/services/formatting.js +0 -0
  158. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/services/pdf.js +0 -0
  159. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/js/services/ui.js +0 -0
  160. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/sounds/README.md +0 -0
  161. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/sounds/error.mp3 +0 -0
  162. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/static/sounds/success.mp3 +0 -0
  163. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/templates/base.html +0 -0
  164. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/templates/components/custom_dropdown.html +0 -0
  165. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/templates/components/log_panel.html +0 -0
  166. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/templates/components/mobile_nav.html +0 -0
  167. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/templates/components/settings_form.html +0 -0
  168. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/templates/components/sidebar.html +0 -0
  169. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/templates/pages/details.html +0 -0
  170. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/templates/pages/history.html +0 -0
  171. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/templates/pages/progress.html +0 -0
  172. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/templates/pages/research.html +0 -0
  173. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/templates/pages/results.html +0 -0
  174. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/templates/settings_dashboard.html +0 -0
  175. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/utils/__init__.py +0 -0
  176. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/utils/formatters.py +0 -0
  177. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web/utils/templates.py +0 -0
  178. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/__init__.py +0 -0
  179. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/__init__.py +0 -0
  180. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/full_search.py +0 -0
  181. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/search_engine_ddg.py +0 -0
  182. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/search_engine_github.py +0 -0
  183. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/search_engine_guardian.py +0 -0
  184. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/search_engine_pubmed.py +0 -0
  185. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/search_engine_semantic_scholar.py +0 -0
  186. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/search_engine_wayback.py +0 -0
  187. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/src/local_deep_research/web_search_engines/engines/search_engine_wikipedia.py +0 -0
  188. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/tests/__init__.py +0 -0
  189. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/tests/download_stuff_for_local_test.py +0 -0
  190. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/tests/fix_tests/README.md +0 -0
  191. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/tests/fix_tests/test_duplicate_links_fix.py +0 -0
  192. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/tests/searxng/test_searxng_instance.py +0 -0
  193. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/tests/searxng/test_searxng_integration.py +0 -0
  194. {local_deep_research-0.3.11 → local_deep_research-0.4.0}/tests/test_google_pse.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: local-deep-research
3
- Version: 0.3.11
3
+ Version: 0.4.0
4
4
  Summary: AI-powered research assistant with deep, iterative analysis using LLMs and web searches
5
5
  Author-Email: LearningCircuit <185559241+LearningCircuit@users.noreply.github.com>, HashedViking <6432677+HashedViking@users.noreply.github.com>
6
6
  License: MIT License
@@ -36,7 +36,7 @@ Requires-Dist: langchain-community>=0.3.17
36
36
  Requires-Dist: langchain-core>=0.3.34
37
37
  Requires-Dist: langchain-ollama>=0.2.3
38
38
  Requires-Dist: langchain-openai>=0.3.5
39
- Requires-Dist: langchain_anthropic>=0.3.7
39
+ Requires-Dist: langchain-anthropic>=0.3.13
40
40
  Requires-Dist: duckduckgo_search>=7.3.2
41
41
  Requires-Dist: python-dateutil>=2.9.0
42
42
  Requires-Dist: typing_extensions>=4.12.2
@@ -67,6 +67,14 @@ Requires-Dist: google-search-results
67
67
  Requires-Dist: importlib-resources>=6.5.2
68
68
  Requires-Dist: setuptools>=78.1.0
69
69
  Requires-Dist: flask-wtf>=1.2.2
70
+ Requires-Dist: optuna>=4.3.0
71
+ Requires-Dist: elasticsearch==8.14.0
72
+ Requires-Dist: methodtools>=0.4.7
73
+ Requires-Dist: loguru>=0.7.3
74
+ Requires-Dist: matplotlib>=3.10.3
75
+ Requires-Dist: pandas>=2.2.3
76
+ Requires-Dist: plotly>=6.0.1
77
+ Requires-Dist: kaleido==0.1.0
70
78
  Description-Content-Type: text/markdown
71
79
 
72
80
  # Local Deep Research
@@ -106,7 +114,24 @@ Local Deep Research combines the power of large language models with intelligent
106
114
 
107
115
  ## ⚡ Quick Start
108
116
 
109
- ### Option 1: Docker (Recommended)
117
+ ### Option 1: Docker (Quickstart no MAC/ARM)
118
+
119
+ ```bash
120
+ # Step 1: Pull and run SearXNG for optimal search results
121
+ docker pull searxng/searxng
122
+ docker run -d -p 8080:8080 --name searxng searxng/searxng
123
+
124
+ # Step 2: Pull and run Local Deep Research (Please build your own docker on ARM)
125
+ docker pull localdeepresearch/local-deep-research
126
+ docker run -d -p 5000:5000 --network host --name local-deep-research localdeepresearch/local-deep-research
127
+
128
+ # Start containers - Required after each reboot (can be automated with this flag in run command --restart unless-stopped)
129
+ docker start searxng
130
+ docker start local-deep-research
131
+
132
+ ```
133
+
134
+ ### Option 2: Docker Compose (Recommended)
110
135
 
111
136
  LDR uses Docker compose to bundle the web app and all it's dependencies so
112
137
  you can get up and running quickly.
@@ -145,7 +170,7 @@ Then visit `http://127.0.0.1:5000` to start researching!
145
170
  See [here](https://github.com/LearningCircuit/local-deep-research/wiki/Installation#docker-installation-recommended) for more information about
146
171
  using Docker.
147
172
 
148
- ### Option 2: Python Package (mostly for programmatic access)
173
+ ### Option 3: Python Package (mostly for programmatic access)
149
174
 
150
175
  ```bash
151
176
  # Install the package
@@ -35,7 +35,24 @@ Local Deep Research combines the power of large language models with intelligent
35
35
 
36
36
  ## ⚡ Quick Start
37
37
 
38
- ### Option 1: Docker (Recommended)
38
+ ### Option 1: Docker (Quickstart no MAC/ARM)
39
+
40
+ ```bash
41
+ # Step 1: Pull and run SearXNG for optimal search results
42
+ docker pull searxng/searxng
43
+ docker run -d -p 8080:8080 --name searxng searxng/searxng
44
+
45
+ # Step 2: Pull and run Local Deep Research (Please build your own docker on ARM)
46
+ docker pull localdeepresearch/local-deep-research
47
+ docker run -d -p 5000:5000 --network host --name local-deep-research localdeepresearch/local-deep-research
48
+
49
+ # Start containers - Required after each reboot (can be automated with this flag in run command --restart unless-stopped)
50
+ docker start searxng
51
+ docker start local-deep-research
52
+
53
+ ```
54
+
55
+ ### Option 2: Docker Compose (Recommended)
39
56
 
40
57
  LDR uses Docker compose to bundle the web app and all it's dependencies so
41
58
  you can get up and running quickly.
@@ -74,7 +91,7 @@ Then visit `http://127.0.0.1:5000` to start researching!
74
91
  See [here](https://github.com/LearningCircuit/local-deep-research/wiki/Installation#docker-installation-recommended) for more information about
75
92
  using Docker.
76
93
 
77
- ### Option 2: Python Package (mostly for programmatic access)
94
+ ### Option 3: Python Package (mostly for programmatic access)
78
95
 
79
96
  ```bash
80
97
  # Install the package
@@ -25,7 +25,7 @@ dependencies = [
25
25
  "langchain-core>=0.3.34",
26
26
  "langchain-ollama>=0.2.3",
27
27
  "langchain-openai>=0.3.5",
28
- "langchain_anthropic>=0.3.7",
28
+ "langchain-anthropic>=0.3.13",
29
29
  "duckduckgo_search>=7.3.2",
30
30
  "python-dateutil>=2.9.0",
31
31
  "typing_extensions>=4.12.2",
@@ -56,8 +56,16 @@ dependencies = [
56
56
  "importlib-resources>=6.5.2",
57
57
  "setuptools>=78.1.0",
58
58
  "flask-wtf>=1.2.2",
59
+ "optuna>=4.3.0",
60
+ "elasticsearch==8.14.0",
61
+ "methodtools>=0.4.7",
62
+ "loguru>=0.7.3",
63
+ "matplotlib>=3.10.3",
64
+ "pandas>=2.2.3",
65
+ "plotly>=6.0.1",
66
+ "kaleido==0.1.0",
59
67
  ]
60
- version = "0.3.11"
68
+ version = "0.4.0"
61
69
 
62
70
  [project.license]
63
71
  file = "LICENSE"
@@ -109,4 +117,7 @@ dev = [
109
117
  "flake8>=7.1.2",
110
118
  "jupyter>=1.1.1",
111
119
  "cookiecutter>=2.6.0",
120
+ "pandas>=2.2.3",
121
+ "optuna>=4.3.0",
122
+ "pytest-mock>=3.14.0",
112
123
  ]
@@ -0,0 +1 @@
1
+ __version__ = "0.4.0"
@@ -3,17 +3,16 @@
3
3
  Base class for search result filters.
4
4
  """
5
5
 
6
- import logging
7
6
  from abc import ABC, abstractmethod
8
7
  from typing import Dict, List
9
8
 
10
- logger = logging.getLogger(__name__)
9
+ from langchain_core.language_models.chat_models import BaseChatModel
11
10
 
12
11
 
13
12
  class BaseFilter(ABC):
14
13
  """Abstract base class for all search result filters."""
15
14
 
16
- def __init__(self, model=None):
15
+ def __init__(self, model: BaseChatModel | None = None):
17
16
  """
18
17
  Initialize the filter.
19
18
 
@@ -3,15 +3,14 @@ Cross-engine search result filter implementation.
3
3
  """
4
4
 
5
5
  import json
6
- import logging
7
6
  from typing import Dict, List
8
7
 
8
+ from loguru import logger
9
+
9
10
  from ...utilities.db_utils import get_db_setting
10
11
  from ...utilities.search_utilities import remove_think_tags
11
12
  from .base_filter import BaseFilter
12
13
 
13
- logger = logging.getLogger(__name__)
14
-
15
14
 
16
15
  class CrossEngineFilter(BaseFilter):
17
16
  """Filter that ranks and filters results from multiple search engines."""
@@ -194,8 +193,8 @@ If no results seem relevant to the query, return an empty array: []"""
194
193
  result["index"] = str(i + start_index + 1)
195
194
  return top_results
196
195
 
197
- except Exception as e:
198
- logger.error(f"Cross-engine filtering error: {e}")
196
+ except Exception:
197
+ logger.exception("Cross-engine filtering error")
199
198
  top_results = results[: min(self.max_results, len(results))]
200
199
  # Update indices if requested
201
200
  if reindex:
@@ -0,0 +1,298 @@
1
+ import time
2
+ import traceback
3
+ from datetime import timedelta
4
+ from typing import Any, Dict, List, Optional
5
+
6
+ from langchain_core.language_models.chat_models import BaseChatModel
7
+ from loguru import logger
8
+ from methodtools import lru_cache
9
+
10
+ from ...config.llm_config import get_llm
11
+ from ...search_system import AdvancedSearchSystem
12
+ from ...utilities.db_utils import get_db_session, get_db_setting
13
+ from ...web.database.models import Journal
14
+ from ...web_search_engines.search_engine_factory import create_search_engine
15
+ from .base_filter import BaseFilter
16
+
17
+
18
+ class JournalFilterError(Exception):
19
+ """
20
+ Custom exception for errors related to journal filtering.
21
+ """
22
+
23
+
24
+ class JournalReputationFilter(BaseFilter):
25
+ """
26
+ A filter for academic results that considers the reputation of journals.
27
+
28
+ Note that this filter requires SearXNG to be available in order to work.
29
+ """
30
+
31
+ def __init__(
32
+ self,
33
+ model: BaseChatModel | None = None,
34
+ reliability_threshold: int | None = None,
35
+ max_context: int | None = None,
36
+ exclude_non_published: bool | None = None,
37
+ quality_reanalysis_period: timedelta | None = None,
38
+ ):
39
+ """
40
+ Args:
41
+ model: The LLM model to use for analysis.
42
+ reliability_threshold: The filter scores journal reliability on a
43
+ scale of 1-10. Results from any journal with a reliability
44
+ below this threshold will be culled. Will be read from the
45
+ settings if not specified.
46
+ max_context: The maximum number of characters to feed into the
47
+ LLM when assessing journal reliability.
48
+ exclude_non_published: If true, it will exclude any results that
49
+ don't have an associated journal publication.
50
+ quality_reanalysis_period: Period at which to update journal
51
+ quality assessments.
52
+
53
+ """
54
+ super().__init__(model)
55
+
56
+ if self.model is None:
57
+ self.model = get_llm()
58
+
59
+ self.__threshold = reliability_threshold
60
+ if self.__threshold is None:
61
+ self.__threshold = int(
62
+ get_db_setting("search.journal_reputation.threshold", 4)
63
+ )
64
+ self.__max_context = max_context
65
+ if self.__max_context is None:
66
+ self.__max_context = int(
67
+ get_db_setting("search.journal_reputation.max_context", 3000)
68
+ )
69
+ self.__exclude_non_published = exclude_non_published
70
+ if self.__exclude_non_published is None:
71
+ self.__exclude_non_published = bool(
72
+ get_db_setting("search.journal_reputation.exclude_non_published", False)
73
+ )
74
+ self.__quality_reanalysis_period = quality_reanalysis_period
75
+ if self.__quality_reanalysis_period is None:
76
+ self.__quality_reanalysis_period = timedelta(
77
+ days=int(
78
+ get_db_setting("search.journal_reputation.reanalysis_period", 365)
79
+ )
80
+ )
81
+
82
+ # SearXNG is required so we can search the open web for reputational
83
+ # information.
84
+ self.__engine = create_search_engine("searxng", llm=self.model)
85
+ if self.__engine is None:
86
+ raise JournalFilterError("SearXNG initialization failed.")
87
+
88
+ self.__db_session = get_db_session()
89
+
90
+ @classmethod
91
+ def create_default(
92
+ cls, model: BaseChatModel | None = None, *, engine_name: str
93
+ ) -> Optional["JournalReputationFilter"]:
94
+ """
95
+ Initializes a default configuration of the filter based on the settings.
96
+
97
+ Args:
98
+ model: Explicitly specify the LLM to use.
99
+ engine_name: The name of the search engine. Will be used to check
100
+ the enablement status for that engine.
101
+
102
+ Returns:
103
+ The filter that it created, or None if filtering is disabled in
104
+ the settings, or misconfigured.
105
+
106
+ """
107
+ if not bool(
108
+ get_db_setting(
109
+ f"search.engine.web.{engine_name}.journal_reputation.enabled",
110
+ True,
111
+ )
112
+ ):
113
+ return None
114
+
115
+ try:
116
+ # Initialize the filter with default settings.
117
+ return JournalReputationFilter(model=model)
118
+ except JournalFilterError:
119
+ logger.error(
120
+ "SearXNG is not configured, but is required for "
121
+ "journal reputation filtering. Disabling filtering."
122
+ )
123
+ return None
124
+
125
+ def __make_search_system(self) -> AdvancedSearchSystem:
126
+ """
127
+ Creates a new `AdvancedSearchSystem` instance.
128
+
129
+ Returns:
130
+ The system it created.
131
+
132
+ """
133
+ return AdvancedSearchSystem(
134
+ llm=self.model,
135
+ search=self.__engine,
136
+ # We clamp down on the default iterations and questions for speed.
137
+ max_iterations=2,
138
+ questions_per_iteration=3,
139
+ )
140
+
141
+ @lru_cache(maxsize=1024)
142
+ def __analyze_journal_reputation(self, journal_name: str) -> int:
143
+ """
144
+ Analyzes the reputation of a particular journal.
145
+
146
+ Args:
147
+ journal_name: The name of the journal.
148
+
149
+ Returns:
150
+ The reputation of the journal, on a scale from 1-10.
151
+
152
+ """
153
+ logger.info(f"Analyzing reputation of journal '{journal_name}'...")
154
+
155
+ # Perform a search for information about this journal.
156
+ journal_info = self.__make_search_system().analyze_topic(
157
+ f'Assess the reputability and reliability of the journal "'
158
+ f'{journal_name}", with a particular focus on its quartile '
159
+ f"ranking and peer review status. Be sure to specify the journal "
160
+ f"name in any generated questions."
161
+ )
162
+ journal_info = "\n".join([f["content"] for f in journal_info["findings"]])
163
+ logger.debug(f"Received raw info about journal: {journal_info}")
164
+
165
+ # Have the LLM assess the reliability based on this information.
166
+ prompt = f"""
167
+ You are a research assistant helping to assess the reliability and
168
+ reputability of scientific journals. A reputable journal should be
169
+ peer-reviewed, not predatory, and high-impact. Please review the
170
+ following information on the journal "{journal_name}" and output a
171
+ reputability score between 1 and 10, where 1-3 is not reputable and
172
+ probably predatory, 4-6 is reputable but low-impact (Q2 or Q3),
173
+ and 7-10 is reputable Q1 journals. Only output the number, do not
174
+ provide any explanation or other output.
175
+
176
+ JOURNAL INFORMATION:
177
+
178
+ {journal_info}
179
+ """
180
+ if len(prompt) > self.__max_context:
181
+ # If the prompt is too long, truncate it to fit within the max context size.
182
+ prompt = prompt[: self.__max_context] + "..."
183
+
184
+ # Generate a response from the LLM model.
185
+ response = self.model.invoke(prompt).text()
186
+ logger.debug(f"Got raw LLM response: {response}")
187
+
188
+ # Extract the score from the response.
189
+ try:
190
+ reputation_score = int(response.strip())
191
+ except ValueError:
192
+ logger.error("Failed to parse reputation score from LLM response.")
193
+ raise ValueError("Failed to parse reputation score from LLM response.")
194
+
195
+ return max(min(reputation_score, 10), 1)
196
+
197
+ def __add_journal_to_db(self, *, name: str, quality: int) -> None:
198
+ """
199
+ Saves the journal quality information to the database.
200
+
201
+ Args:
202
+ name: The name of the journal.
203
+ quality: The quality assessment for the journal.
204
+
205
+ """
206
+ journal = self.__db_session.query(Journal).filter_by(name=name).first()
207
+ if journal is not None:
208
+ journal.quality = quality
209
+ journal.quality_model = self.model.name
210
+ journal.quality_analysis_time = int(time.time())
211
+ else:
212
+ journal = Journal(
213
+ name=name,
214
+ quality=quality,
215
+ quality_model=self.model.name,
216
+ quality_analysis_time=int(time.time()),
217
+ )
218
+ self.__db_session.add(journal)
219
+
220
+ self.__db_session.commit()
221
+
222
+ def __clean_journal_name(self, journal_name: str) -> str:
223
+ """
224
+ Cleans up the name of a journal to remove any extraneous information.
225
+ This is mostly to make caching more effective.
226
+
227
+ Args:
228
+ journal_name: The raw name of the journal.
229
+
230
+ Returns:
231
+ The cleaned name.
232
+
233
+ """
234
+ logger.debug(f"Cleaning raw journal name: {journal_name}")
235
+
236
+ prompt = f"""
237
+ Clean up the following journal or conference name:
238
+
239
+ "{journal_name}"
240
+
241
+ Remove any references to volumes, pages, months, or years. Expand
242
+ abbreviations if possible. For conferences, remove locations. Only
243
+ output the clean name, do not provide any explanation or other output.
244
+ """
245
+
246
+ response = self.model.invoke(prompt).text()
247
+ return response.strip()
248
+
249
+ def __check_result(self, result: Dict[str, Any]) -> bool:
250
+ """
251
+ Performs a search to determine the reputability of a result journal..
252
+
253
+ Args:
254
+ result: The result to check.
255
+
256
+ Returns:
257
+ True if the journal is reputable or if it couldn't determine a
258
+ reputability score, false otherwise.
259
+
260
+ """
261
+ journal_name = result.get("journal_ref")
262
+ if journal_name is None:
263
+ logger.debug(
264
+ f"Result {result.get('title')} has no associated "
265
+ f"journal, not evaluating reputation."
266
+ )
267
+ return not self.__exclude_non_published
268
+ journal_name = self.__clean_journal_name(journal_name)
269
+
270
+ # Check the database first.
271
+ journal = self.__db_session.query(Journal).filter_by(name=journal_name).first()
272
+ if (
273
+ journal is not None
274
+ and (time.time() - journal.quality_analysis_time)
275
+ < self.__quality_reanalysis_period.total_seconds()
276
+ ):
277
+ logger.debug(f"Found existing reputation for {journal_name} in database.")
278
+ return journal.quality >= self.__threshold
279
+
280
+ # Evaluate reputation.
281
+ try:
282
+ quality = self.__analyze_journal_reputation(journal_name)
283
+ # Save to the database.
284
+ self.__add_journal_to_db(name=journal_name, quality=quality)
285
+ return quality >= self.__threshold
286
+ except ValueError:
287
+ # The LLM behaved weirdly. In this case, we will just assume it's
288
+ # okay.
289
+ return True
290
+
291
+ def filter_results(self, results: List[Dict], query: str, **kwargs) -> List[Dict]:
292
+ try:
293
+ return list(filter(self.__check_result, results))
294
+ except Exception as e:
295
+ logger.error(
296
+ f"Journal quality filtering failed: {e}, {traceback.format_exc()}"
297
+ )
298
+ return results
@@ -291,9 +291,6 @@ Use IEEE style citations [1], [2], etc. Never make up your own citations.
291
291
 
292
292
  # Check if we're on Windows
293
293
  if platform.system() == "Windows":
294
- # Windows-compatible timeout using threading
295
- class TimeoutError(Exception):
296
- pass
297
294
 
298
295
  def timeout_handler(timeout_seconds, callback, args):
299
296
  def handler():
@@ -3,11 +3,10 @@ Base class for all search strategies.
3
3
  Defines the common interface and shared functionality for different search approaches.
4
4
  """
5
5
 
6
- import logging
7
6
  from abc import ABC, abstractmethod
8
7
  from typing import Callable, Dict, List, Optional
9
8
 
10
- logger = logging.getLogger(__name__)
9
+ from loguru import logger
11
10
 
12
11
 
13
12
  class BaseSearchStrategy(ABC):
@@ -3,10 +3,11 @@ IterDRAG strategy implementation.
3
3
  """
4
4
 
5
5
  import json
6
- import logging
7
6
  from datetime import datetime
8
7
  from typing import Dict, List
9
8
 
9
+ from loguru import logger
10
+
10
11
  from ...citation_handler import CitationHandler
11
12
  from ...config.llm_config import get_llm
12
13
  from ...config.search_config import get_search
@@ -17,8 +18,6 @@ from ..knowledge.standard_knowledge import StandardKnowledge
17
18
  from ..questions.decomposition_question import DecompositionQuestionGenerator
18
19
  from .base_strategy import BaseSearchStrategy
19
20
 
20
- logger = logging.getLogger(__name__)
21
-
22
21
 
23
22
  class IterDRAGStrategy(BaseSearchStrategy):
24
23
  """IterDRAG strategy that breaks queries into sub-queries."""
@@ -83,8 +82,8 @@ Initial Search Results:
83
82
  return self.question_generator.generate_questions(
84
83
  query, context, int(get_db_setting("search.questions_per_iteration"))
85
84
  )
86
- except Exception as e:
87
- logger.error(f"Error generating sub-queries: {str(e)}")
85
+ except Exception:
86
+ logger.exception("Error generating sub-queries")
88
87
  return []
89
88
 
90
89
  def analyze_topic(self, query: str) -> Dict:
@@ -204,8 +203,8 @@ Initial Search Results:
204
203
  "result_count": len(sub_results),
205
204
  },
206
205
  )
207
- except Exception as e:
208
- logger.error(f"Error searching for sub-query: {str(e)}")
206
+ except Exception:
207
+ logger.exception("Error searching for sub-query")
209
208
  sub_results = []
210
209
 
211
210
  try:
@@ -238,8 +237,8 @@ Initial Search Results:
238
237
  current_knowledge = (
239
238
  current_knowledge + "\n\n\n New: \n" + result["content"]
240
239
  )
241
- except Exception as e:
242
- logger.error(f"Error analyzing sub-query results: {str(e)}")
240
+ except Exception:
241
+ logger.exception("Error analyzing sub-query results:")
243
242
  finding = {
244
243
  "phase": f"Follow-up Iteration 0.{i + 1}",
245
244
  "content": "Error analyzing sub-query results.",
@@ -344,10 +343,7 @@ This is a fallback response using the accumulated knowledge.
344
343
  # Update current knowledge with the synthesized version
345
344
  current_knowledge = final_answer
346
345
  except Exception as e:
347
- logger.error(f"Error synthesizing final answer: {str(e)}")
348
- import traceback
349
-
350
- logger.error(traceback.format_exc())
346
+ logger.exception("Error synthesizing final answer")
351
347
 
352
348
  # Create an error finding
353
349
  error_finding = {
@@ -396,7 +392,7 @@ This is an automatically generated fallback response.
396
392
  final_answer = fallback_content
397
393
  except Exception as fallback_error:
398
394
  # Last resort fallback
399
- logger.error(f"Even fallback creation failed: {fallback_error}")
395
+ logger.exception("Even fallback creation failed")
400
396
  final_answer = f"""
401
397
  # Research Error
402
398
 
@@ -417,8 +413,8 @@ Please try again with a different query or contact support.
417
413
  current_knowledge = self.knowledge_generator.compress_knowledge(
418
414
  current_knowledge, query, section_links
419
415
  )
420
- except Exception as e:
421
- logger.error(f"Error compressing knowledge: {str(e)}")
416
+ except Exception:
417
+ logger.exception("Error compressing knowledge")
422
418
 
423
419
  # Format and save findings
424
420
  self._update_progress(
@@ -442,8 +438,8 @@ Please try again with a different query or contact support.
442
438
  formatted_findings = self.findings_repository.format_findings_to_text(
443
439
  findings, final_answer
444
440
  )
445
- except Exception as e:
446
- logger.error(f"Error formatting final findings: {str(e)}")
441
+ except Exception:
442
+ logger.exception("Error formatting final findings")
447
443
  formatted_findings = "Error: Could not format findings due to an error."
448
444
 
449
445
  self._update_progress("Research complete", 100, {"phase": "complete"})
@@ -3,9 +3,10 @@ Parallel search strategy implementation for maximum search speed.
3
3
  """
4
4
 
5
5
  import concurrent.futures
6
- import logging
7
6
  from typing import Dict
8
7
 
8
+ from loguru import logger
9
+
9
10
  from ...citation_handler import CitationHandler
10
11
  from ...config.llm_config import get_llm
11
12
  from ...config.search_config import get_search
@@ -16,8 +17,6 @@ from ..findings.repository import FindingsRepository
16
17
  from ..questions.standard_question import StandardQuestionGenerator
17
18
  from .base_strategy import BaseSearchStrategy
18
19
 
19
- logger = logging.getLogger(__name__)
20
-
21
20
 
22
21
  class ParallelSearchStrategy(BaseSearchStrategy):
23
22
  """
@@ -212,7 +211,7 @@ class ParallelSearchStrategy(BaseSearchStrategy):
212
211
  result = self.search.run(q)
213
212
  return {"question": q, "results": result or []}
214
213
  except Exception as e:
215
- logger.error(f"Error searching for '{q}': {str(e)}")
214
+ logger.exception(f"Error searching for '{q}'")
216
215
  return {"question": q, "results": [], "error": str(e)}
217
216
 
218
217
  # Run searches in parallel
@@ -408,11 +407,8 @@ class ParallelSearchStrategy(BaseSearchStrategy):
408
407
  )
409
408
 
410
409
  except Exception as e:
411
- import traceback
412
-
413
410
  error_msg = f"Error in research process: {str(e)}"
414
- logger.error(error_msg)
415
- logger.error(traceback.format_exc())
411
+ logger.exception(error_msg)
416
412
  synthesized_content = f"Error: {str(e)}"
417
413
  formatted_findings = f"Error: {str(e)}"
418
414
  finding = {