bertrend 0.4.0__tar.gz → 0.4.2__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 (329) hide show
  1. {bertrend-0.4.0 → bertrend-0.4.2}/PKG-INFO +5 -1
  2. bertrend-0.4.2/bertrend/bertrend_apps/config/feeds/feed_deep_research_example.toml +9 -0
  3. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/data_provider/arxiv_provider.py +3 -4
  4. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/data_provider/data_provider_utils.py +9 -2
  5. bertrend-0.4.2/bertrend/bertrend_apps/data_provider/deep_research_provider.py +501 -0
  6. bertrend-0.4.2/bertrend/bertrend_apps/exploration/geoviz/.streamlit/config.toml +6 -0
  7. bertrend-0.4.2/bertrend/bertrend_apps/exploration/geoviz/app.py +174 -0
  8. bertrend-0.4.2/bertrend/bertrend_apps/exploration/geoviz/backend.py +190 -0
  9. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/feeds_config.py +11 -11
  10. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/bertrend/models/data_provider_models.py +2 -2
  11. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/config/services_default_config.toml +5 -1
  12. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/llm_utils/agent_utils.py +3 -1
  13. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/scheduling/docker-compose.yml +3 -5
  14. bertrend-0.4.2/bertrend/services/scheduling/start_docker_scheduling_service.sh +16 -0
  15. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/summarizer.py +1 -1
  16. bertrend-0.4.2/bertrend/services/summary_client.py +70 -0
  17. bertrend-0.4.2/bertrend/services/summary_server/config/default_config.toml +3 -0
  18. bertrend-0.4.2/bertrend/services/summary_server/config/settings.py +32 -0
  19. bertrend-0.4.2/bertrend/services/summary_server/main.py +12 -0
  20. bertrend-0.4.2/bertrend/services/summary_server/models.py +30 -0
  21. bertrend-0.4.2/bertrend/services/summary_server/routers/info.py +33 -0
  22. bertrend-0.4.2/bertrend/services/summary_server/routers/summarize.py +87 -0
  23. bertrend-0.4.2/bertrend/services/summary_server/start.py +18 -0
  24. bertrend-0.4.2/bertrend/tests/data_provider/test_arxiv_provider.py +59 -0
  25. bertrend-0.4.2/bertrend/tests/data_provider/test_bing_news_provider.py +46 -0
  26. bertrend-0.4.2/bertrend/tests/data_provider/test_data_provider_base.py +123 -0
  27. bertrend-0.4.2/bertrend/tests/data_provider/test_data_provider_utils.py +99 -0
  28. bertrend-0.4.2/bertrend/tests/data_provider/test_deep_research_live.py +81 -0
  29. bertrend-0.4.2/bertrend/tests/data_provider/test_deep_research_provider.py +489 -0
  30. bertrend-0.4.2/bertrend/tests/data_provider/test_google_news_provider.py +52 -0
  31. bertrend-0.4.2/bertrend/tests/data_provider/test_newscatcher_provider.py +54 -0
  32. bertrend-0.4.2/bertrend/tests/data_provider/test_rss_atom_provider.py +73 -0
  33. bertrend-0.4.2/bertrend/tests/services/summarizer/__init__.py +4 -0
  34. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/services/summarizer/test_summarizer.py +2 -2
  35. bertrend-0.4.2/bertrend/tests/services/summary/__init__.py +4 -0
  36. bertrend-0.4.2/bertrend/tests/services/summary/test_summary_client.py +182 -0
  37. bertrend-0.4.2/bertrend/tests/services/summary/test_summary_config.py +44 -0
  38. bertrend-0.4.2/bertrend/tests/services/summary/test_summary_server.py +230 -0
  39. bertrend-0.4.2/bertrend/tests/utils/__init__.py +4 -0
  40. {bertrend-0.4.0 → bertrend-0.4.2}/pyproject.toml +6 -2
  41. bertrend-0.4.0/bertrend/bertrend_apps/exploration/dataviz/Main_page.py +0 -10
  42. bertrend-0.4.0/bertrend/bertrend_apps/exploration/dataviz/pages/1_Data_feeds.py +0 -105
  43. bertrend-0.4.0/bertrend/bertrend_apps/exploration/geolocalization/entity_utils.py +0 -118
  44. bertrend-0.4.0/bertrend/bertrend_apps/exploration/geolocalization/spacy/common_factory.py +0 -142
  45. bertrend-0.4.0/bertrend/bertrend_apps/exploration/geolocalization/spacy/dbpedia.py +0 -204
  46. bertrend-0.4.0/bertrend/bertrend_apps/exploration/geolocalization/spacy/nlp.config +0 -37
  47. bertrend-0.4.0/bertrend/bertrend_apps/exploration/geolocalization/spacy/utils.py +0 -42
  48. bertrend-0.4.0/bertrend/bertrend_apps/services/queue_monitor/__init__.py +0 -5
  49. {bertrend-0.4.0 → bertrend-0.4.2}/AUTHORS.txt +0 -0
  50. {bertrend-0.4.0 → bertrend-0.4.2}/LICENSE.md +0 -0
  51. {bertrend-0.4.0 → bertrend-0.4.2}/README.md +0 -0
  52. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/BERTopicModel.py +0 -0
  53. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/BERTrend.py +0 -0
  54. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/__init__.py +0 -0
  55. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/article_scoring/__init__.py +0 -0
  56. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/article_scoring/article_scoring.py +0 -0
  57. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/article_scoring/prompts.py +0 -0
  58. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/article_scoring/scoring_agent.py +0 -0
  59. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/__init__.py +0 -0
  60. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/common/__init__.py +0 -0
  61. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/common/apscheduler_utils.py +0 -0
  62. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/common/crontab_utils.py +0 -0
  63. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/common/date_utils.py +0 -0
  64. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/common/mail_utils.py +0 -0
  65. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/common/scheduler_utils.py +0 -0
  66. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/config/feeds/arxiv_feed.toml +0 -0
  67. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/config/feeds/decarbonation_feed.toml +0 -0
  68. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/config/feeds/llm_en_feed.toml +0 -0
  69. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/config/feeds/llm_feed.toml +0 -0
  70. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/config/feeds/nlp_feed.toml +0 -0
  71. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/config/feeds/rte_feed.toml +0 -0
  72. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/config/newsletters/arxiv_newsletter_from_last.toml +0 -0
  73. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/config/newsletters/decarbonation_newsletter_from_last.toml +0 -0
  74. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/config/newsletters/llm_en_newsletter_from_last.toml +0 -0
  75. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/config/newsletters/llm_newsletter_from_last.toml +0 -0
  76. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/config/newsletters/nlp_newsletter_from_last.toml +0 -0
  77. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/config/newsletters/rte_newsletter_from_last.toml +0 -0
  78. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/data_provider/__init__.py +0 -0
  79. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/data_provider/__main__.py +0 -0
  80. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/data_provider/atom_feed_provider.py +0 -0
  81. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/data_provider/bing_news_provider.py +0 -0
  82. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/data_provider/data_provider.py +0 -0
  83. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/data_provider/google_news_provider.py +0 -0
  84. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/data_provider/newscatcher_provider.py +0 -0
  85. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/data_provider/rss_feed_provider.py +0 -0
  86. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/data_provider/utils.py +0 -0
  87. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/exploration/__init__.py +0 -0
  88. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/exploration/curebot/.streamlit/config.toml +0 -0
  89. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/exploration/curebot/__init__.py +0 -0
  90. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/exploration/curebot/app.py +0 -0
  91. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/exploration/curebot/app_utils.py +0 -0
  92. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/exploration/curebot/config.toml +0 -0
  93. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/exploration/curebot/import_extraction_article.ipynb +0 -0
  94. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/exploration/curebot/prompts.py +0 -0
  95. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/exploration/curebot/start_newsletter_generator.sh +0 -0
  96. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/exploration/curebot/tabs/__init__.py +0 -0
  97. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/exploration/curebot/tabs/tab1.py +0 -0
  98. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/exploration/curebot/tabs/tab2.py +0 -0
  99. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/exploration/curebot/tabs/tab3.py +0 -0
  100. {bertrend-0.4.0/bertrend/bertrend_apps/exploration/dataviz → bertrend-0.4.2/bertrend/bertrend_apps/exploration/geoviz}/__init__.py +0 -0
  101. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/exploration/start_apps.sh +0 -0
  102. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/exploration/stop_apps.sh +0 -0
  103. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/install_feeds_and_newsletters.py +0 -0
  104. {bertrend-0.4.0/bertrend/bertrend_apps/exploration/geolocalization → bertrend-0.4.2/bertrend/bertrend_apps/newsletters}/__init__.py +0 -0
  105. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/newsletters/__main__.py +0 -0
  106. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/newsletters/newsletter_generation.py +0 -0
  107. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/newsletters/utils.py +0 -0
  108. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/.streamlit/config.toml +0 -0
  109. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/.streamlit/secrets.toml.example +0 -0
  110. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/__init__.py +0 -0
  111. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/app.py +0 -0
  112. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/authentication.py +0 -0
  113. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/automated_report_generation.py +0 -0
  114. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/dashboard_analysis.py +0 -0
  115. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/dashboard_common.py +0 -0
  116. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/dashboard_comparative.py +0 -0
  117. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/dashboard_signals.py +0 -0
  118. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/data_model.py +0 -0
  119. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/detailed_report_template.html +0 -0
  120. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/feeds_common.py +0 -0
  121. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/feeds_data.py +0 -0
  122. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/i18n.py +0 -0
  123. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/i18n_translations.py +0 -0
  124. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/llm_utils.py +0 -0
  125. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/models_info.py +0 -0
  126. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/perf_utils.py +0 -0
  127. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/process_new_data.py +0 -0
  128. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/report_generation.py +0 -0
  129. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/report_generation_utils.py +0 -0
  130. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/start_demo.sh +0 -0
  131. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/prospective_demo/utils.py +0 -0
  132. {bertrend-0.4.0/bertrend/bertrend_apps/exploration/geolocalization/spacy → bertrend-0.4.2/bertrend/bertrend_apps/services}/__init__.py +0 -0
  133. {bertrend-0.4.0/bertrend/bertrend_apps/exploration/dataviz/pages → bertrend-0.4.2/bertrend/bertrend_apps/services/bertrend}/__init__.py +0 -0
  134. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/bertrend/bertrend_service.py +0 -0
  135. {bertrend-0.4.0/bertrend/bertrend_apps/services/bertrend → bertrend-0.4.2/bertrend/bertrend_apps/services/bertrend/config}/__init__.py +0 -0
  136. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/bertrend/config/default_config.toml +0 -0
  137. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/bertrend/config/settings.py +0 -0
  138. {bertrend-0.4.0/bertrend/bertrend_apps/newsletters → bertrend-0.4.2/bertrend/bertrend_apps/services/bertrend/models}/__init__.py +0 -0
  139. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/bertrend/models/bertrend_app_models.py +0 -0
  140. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/bertrend/models/newsletters_models.py +0 -0
  141. {bertrend-0.4.0/bertrend/bertrend_apps/services → bertrend-0.4.2/bertrend/bertrend_apps/services/bertrend/routers}/__init__.py +0 -0
  142. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/bertrend/routers/bertrend_app.py +0 -0
  143. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/bertrend/routers/data_provider.py +0 -0
  144. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/bertrend/routers/info.py +0 -0
  145. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/bertrend/routers/newsletters.py +0 -0
  146. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/bertrend/start.py +0 -0
  147. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/bertrend/status.py +0 -0
  148. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/bertrend/stop.py +0 -0
  149. {bertrend-0.4.0/bertrend/bertrend_apps/services/bertrend/config → bertrend-0.4.2/bertrend/bertrend_apps/services/queue_management}/__init__.py +0 -0
  150. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/queue_management/bertrend_worker.py +0 -0
  151. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/queue_management/client.py +0 -0
  152. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/queue_management/docker-compose-rabbitmq.yml +0 -0
  153. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/queue_management/queue_manager.py +0 -0
  154. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/queue_management/rabbitmq_config.py +0 -0
  155. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/queue_management/start_rabbitmq.sh +0 -0
  156. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/queue_monitor/.streamlit/config.toml +0 -0
  157. {bertrend-0.4.0/bertrend/bertrend_apps/services/queue_management → bertrend-0.4.2/bertrend/bertrend_apps/services/queue_monitor}/__init__.py +0 -0
  158. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/queue_monitor/app.py +0 -0
  159. {bertrend-0.4.0/bertrend/bertrend_apps/services/bertrend/models → bertrend-0.4.2/bertrend/bertrend_apps/services/utils}/__init__.py +0 -0
  160. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/bertrend_apps/services/utils/logging_utils.py +0 -0
  161. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/config/bertopic_default_config.toml +0 -0
  162. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/config/bertrend_default_config.toml +0 -0
  163. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/config/parameters.py +0 -0
  164. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/__init__.py +0 -0
  165. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/demos_utils/__init__.py +0 -0
  166. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/demos_utils/data_loading_component.py +0 -0
  167. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/demos_utils/embed_documents_component.py +0 -0
  168. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/demos_utils/i18n.py +0 -0
  169. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/demos_utils/i18n_translations.py +0 -0
  170. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/demos_utils/icons.py +0 -0
  171. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/demos_utils/parameters_component.py +0 -0
  172. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/demos_utils/state_utils.py +0 -0
  173. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/start_summarizer_app.sh +0 -0
  174. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/start_topic_analysis_app.sh +0 -0
  175. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/start_weak_signals_app.sh +0 -0
  176. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/streamlit_components/__init__.py +0 -0
  177. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/streamlit_components/clickable_df_component.py +0 -0
  178. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/streamlit_components/input_with_pills_component.py +0 -0
  179. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/summarization/__init__.py +0 -0
  180. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/summarization/summarizer_app.py +0 -0
  181. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/topic_analysis/.streamlit/config.toml +0 -0
  182. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/topic_analysis/__init__.py +0 -0
  183. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/topic_analysis/app.py +0 -0
  184. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/topic_analysis/app_utils.py +0 -0
  185. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/topic_analysis/demo_pages/__init__.py +0 -0
  186. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/topic_analysis/demo_pages/explore_topics.py +0 -0
  187. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/topic_analysis/demo_pages/newsletters_generation.py +0 -0
  188. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/topic_analysis/demo_pages/temporal_visualizations.py +0 -0
  189. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/topic_analysis/demo_pages/topic_visualizations.py +0 -0
  190. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/topic_analysis/demo_pages/training_page.py +0 -0
  191. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/topic_analysis/i18n_translations.py +0 -0
  192. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/weak_signals/.streamlit/config.toml +0 -0
  193. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/weak_signals/__init__.py +0 -0
  194. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/weak_signals/app.py +0 -0
  195. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/weak_signals/i18n_translations.py +0 -0
  196. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/demos/weak_signals/visualizations_utils.py +0 -0
  197. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/llm_utils/__init__.py +0 -0
  198. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/llm_utils/newsletter.css +0 -0
  199. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/llm_utils/newsletter_features.py +0 -0
  200. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/llm_utils/newsletter_model.py +0 -0
  201. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/llm_utils/newsletter_outlook_template.html +0 -0
  202. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/llm_utils/newsletter_template.html +0 -0
  203. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/llm_utils/openai_client.py +0 -0
  204. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/llm_utils/prompts.py +0 -0
  205. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/metrics/__init__.py +0 -0
  206. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/metrics/temporal_metrics_embedding.py +0 -0
  207. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/metrics/topic_metrics.py +0 -0
  208. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/resources/common_ngrams.json +0 -0
  209. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/resources/stopwords-en.json +0 -0
  210. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/resources/stopwords-fr.json +0 -0
  211. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/resources/stopwords-rte.json +0 -0
  212. {bertrend-0.4.0/bertrend/bertrend_apps/services/bertrend/routers → bertrend-0.4.2/bertrend/services}/__init__.py +0 -0
  213. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/authentication.py +0 -0
  214. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/cert.pem +0 -0
  215. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_client.py +0 -0
  216. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_server/README.md +0 -0
  217. {bertrend-0.4.0/bertrend/bertrend_apps/services/utils → bertrend-0.4.2/bertrend/services/embedding_server}/__init__.py +0 -0
  218. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_server/bertrend_client_registry.json +0 -0
  219. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_server/config/default_config.toml +0 -0
  220. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_server/config/settings.py +0 -0
  221. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_server/main.py +0 -0
  222. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_server/models.py +0 -0
  223. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_server/requirements.txt +0 -0
  224. {bertrend-0.4.0/bertrend/services → bertrend-0.4.2/bertrend/services/embedding_server/routers}/__init__.py +0 -0
  225. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_server/routers/authentication.py +0 -0
  226. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_server/routers/embeddings.py +0 -0
  227. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_server/routers/info.py +0 -0
  228. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_server/security.py +0 -0
  229. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_server/start.py +0 -0
  230. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_server/status.py +0 -0
  231. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_server/stop.py +0 -0
  232. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/embedding_service.py +0 -0
  233. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/key.pem +0 -0
  234. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/scheduling/.dockerignore +0 -0
  235. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/scheduling/Docker_setup.md +0 -0
  236. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/scheduling/Dockerfile +0 -0
  237. {bertrend-0.4.0/bertrend/services/embedding_server → bertrend-0.4.2/bertrend/services/scheduling}/__init__.py +0 -0
  238. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/scheduling/dashboard.html +0 -0
  239. {bertrend-0.4.0/bertrend/services/embedding_server/routers → bertrend-0.4.2/bertrend/services/scheduling/job_utils}/__init__.py +0 -0
  240. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/scheduling/job_utils/job_functions.py +0 -0
  241. {bertrend-0.4.0/bertrend/services/scheduling → bertrend-0.4.2/bertrend/services/scheduling/models}/__init__.py +0 -0
  242. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/scheduling/models/scheduling_models.py +0 -0
  243. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/scheduling/requirements.txt +0 -0
  244. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/scheduling/routers/info.py +0 -0
  245. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/scheduling/routers/scheduling.py +0 -0
  246. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/scheduling/scheduling_service.py +0 -0
  247. {bertrend-0.4.0/bertrend/services/scheduling/job_utils → bertrend-0.4.2/bertrend/services/summary}/__init__.py +0 -0
  248. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/summary/abstractive_summarizer.py +0 -0
  249. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/summary/chatgpt_summarizer.py +0 -0
  250. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/summary/extractive_summarizer.py +0 -0
  251. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/summary/lexrank.py +0 -0
  252. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/services/summary/prompts.py +0 -0
  253. {bertrend-0.4.0/bertrend/services/scheduling/models → bertrend-0.4.2/bertrend/services/summary_server}/__init__.py +0 -0
  254. {bertrend-0.4.0/bertrend/services/summary → bertrend-0.4.2/bertrend/services/summary_server/config}/__init__.py +0 -0
  255. {bertrend-0.4.0/bertrend/tests → bertrend-0.4.2/bertrend/services/summary_server/routers}/__init__.py +0 -0
  256. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/README_integration_tests.md +0 -0
  257. {bertrend-0.4.0/bertrend/tests/apps → bertrend-0.4.2/bertrend/tests}/__init__.py +0 -0
  258. {bertrend-0.4.0/bertrend/tests/core → bertrend-0.4.2/bertrend/tests/apps}/__init__.py +0 -0
  259. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/apps/test_bertrend_service.py +0 -0
  260. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/apps/test_lazy_scheduler.py +0 -0
  261. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/apps/test_models.py +0 -0
  262. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/apps/test_multiworker.py +0 -0
  263. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/apps/test_process_new_data.py +0 -0
  264. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/apps/test_routers_bertrend_app.py +0 -0
  265. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/apps/test_routers_info.py +0 -0
  266. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/conftest.py +0 -0
  267. {bertrend-0.4.0/bertrend/tests/llm → bertrend-0.4.2/bertrend/tests/core}/__init__.py +0 -0
  268. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/core/test_bertrend.py +0 -0
  269. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/core/test_data_structure.py +0 -0
  270. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/core/test_representative_docs.py +0 -0
  271. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/core/test_temporal_metrics_embedding.py +0 -0
  272. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/core/test_topic_description.py +0 -0
  273. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/core/test_topic_metrics.py +0 -0
  274. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/core/test_topic_model.py +0 -0
  275. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/core/test_trend_analysis_data_structure.py +0 -0
  276. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/core/test_trend_analysis_prompts.py +0 -0
  277. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/core/test_trend_analysis_visualizations.py +0 -0
  278. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/core/test_trend_analysis_weak_signals.py +0 -0
  279. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/core/test_visualizations.py +0 -0
  280. {bertrend-0.4.0/bertrend/tests/services → bertrend-0.4.2/bertrend/tests/data_provider}/__init__.py +0 -0
  281. {bertrend-0.4.0/bertrend/tests/services/embedding → bertrend-0.4.2/bertrend/tests/llm}/__init__.py +0 -0
  282. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/llm/test_agent_utils.py +0 -0
  283. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/llm/test_article_scoring.py +0 -0
  284. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/llm/test_article_scoring_models.py +0 -0
  285. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/llm/test_newsletter_features.py +0 -0
  286. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/llm/test_newsletter_model.py +0 -0
  287. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/llm/test_openai_client.py +0 -0
  288. {bertrend-0.4.0/bertrend/tests/services/queue → bertrend-0.4.2/bertrend/tests/services}/__init__.py +0 -0
  289. {bertrend-0.4.0/bertrend/tests/services/scheduling → bertrend-0.4.2/bertrend/tests/services/embedding}/__init__.py +0 -0
  290. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/services/embedding/test_embedding_client.py +0 -0
  291. {bertrend-0.4.0/bertrend/tests/services/summarizer → bertrend-0.4.2/bertrend/tests/services/queue}/__init__.py +0 -0
  292. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/services/queue/test_bertrend_worker.py +0 -0
  293. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/services/queue/test_client.py +0 -0
  294. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/services/queue/test_queue_manager.py +0 -0
  295. {bertrend-0.4.0/bertrend/tests/utils → bertrend-0.4.2/bertrend/tests/services/scheduling}/__init__.py +0 -0
  296. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/services/scheduling/test_job_exception_fix.py +0 -0
  297. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/services/scheduling/test_scheduling_service.py +0 -0
  298. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/services/scheduling/test_stress_test.py +0 -0
  299. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/services/summarizer/test_abstractive_summarizer.py +0 -0
  300. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/services/summarizer/test_chatgpt_summarizer.py +0 -0
  301. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/services/summarizer/test_extractive_summarizer.py +0 -0
  302. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/test_installation.py +0 -0
  303. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/test_integration.py +0 -0
  304. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/utils/test_apscheduler_utils.py +0 -0
  305. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/utils/test_cache_utils.py +0 -0
  306. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/utils/test_config_utils.py +0 -0
  307. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/utils/test_crontab_utils.py +0 -0
  308. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/utils/test_data_loading.py +0 -0
  309. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/utils/test_date_utils.py +0 -0
  310. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/utils/test_mail_utils.py +0 -0
  311. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/utils/test_scheduler_utils.py +0 -0
  312. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/tests/utils/test_utils_init.py +0 -0
  313. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/topic_analysis/__init__.py +0 -0
  314. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/topic_analysis/data_structure.py +0 -0
  315. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/topic_analysis/prompts.py +0 -0
  316. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/topic_analysis/representative_docs.py +0 -0
  317. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/topic_analysis/topic_description.py +0 -0
  318. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/topic_analysis/visualizations.py +0 -0
  319. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/trend_analysis/__init__.py +0 -0
  320. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/trend_analysis/data_structure.py +0 -0
  321. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/trend_analysis/prompts.py +0 -0
  322. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/trend_analysis/signal_llm_template_en.html +0 -0
  323. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/trend_analysis/signal_llm_template_fr.html +0 -0
  324. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/trend_analysis/visualizations.py +0 -0
  325. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/trend_analysis/weak_signals.py +0 -0
  326. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/utils/__init__.py +0 -0
  327. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/utils/cache_utils.py +0 -0
  328. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/utils/config_utils.py +0 -0
  329. {bertrend-0.4.0 → bertrend-0.4.2}/bertrend/utils/data_loading.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bertrend
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: BERTrend analyses topic evolution over time using state-of-the-art transformer models: topic modelling and LLM
5
5
  License: LICENSE.md
6
6
  License-File: AUTHORS.txt
@@ -25,10 +25,13 @@ Requires-Dist: cron-descriptor (>=1.4.5)
25
25
  Requires-Dist: dask (==2024.12.0)
26
26
  Requires-Dist: datamapplot (==0.3.0)
27
27
  Requires-Dist: dateparser (>=1.2.0)
28
+ Requires-Dist: ddgs (>=9.10.0)
28
29
  Requires-Dist: dill (>=0.4.0)
29
30
  Requires-Dist: fastapi (>=0.120.0)
30
31
  Requires-Dist: feedparser (>=6.0.11)
32
+ Requires-Dist: folium (>=0.20.0)
31
33
  Requires-Dist: gensim (>=4.3.3)
34
+ Requires-Dist: geopy (>=2.4.1)
32
35
  Requires-Dist: google-api-python-client (>=2.148.0)
33
36
  Requires-Dist: google-auth-oauthlib (>=1.2.1)
34
37
  Requires-Dist: googlenewsdecoder (>=0.1.7)
@@ -69,6 +72,7 @@ Requires-Dist: sentencepiece (>=0.2.0)
69
72
  Requires-Dist: starlette (>=0.46.2)
70
73
  Requires-Dist: streamlit (>=1.51.0)
71
74
  Requires-Dist: streamlit-code-editor (>=0.1.22)
75
+ Requires-Dist: streamlit-folium (>=0.26.1)
72
76
  Requires-Dist: supervisor (>=4.3.0)
73
77
  Requires-Dist: thefuzz (>=0.22.1)
74
78
  Requires-Dist: tiktoken (>=0.8.0)
@@ -0,0 +1,9 @@
1
+ [data-feed]
2
+ id = "feed_deep_research_example"
3
+ query = "artificial intelligence energy grid"
4
+ provider = "deep_research"
5
+ max_results = 3
6
+ number_of_days = 7
7
+ feed_dir_path = "feed_deep_research"
8
+ language = "en"
9
+ update_frequency = "0 6 * * 1"
@@ -27,8 +27,6 @@ NUM_RETRIES = 10
27
27
  query = "cat:cs.AI"
28
28
  max_results = float("inf")
29
29
 
30
- ### Parameters Semantic Scholar ###
31
- SEMANTIC_SCHOLAR_API_KEY = os.getenv("SEMANTIC_SCHOLAR_API_KEY")
32
30
 
33
31
  PAPERS_PER_REQUEST = 500 # should not be more than 500
34
32
  SEMANTIC_SCHOLAR_FIELDS = "title,abstract,citationCount,publicationDate,url"
@@ -130,14 +128,15 @@ class ArxivProvider(DataProvider):
130
128
  @wait(1)
131
129
  def _request_semantic_scholar_chunk(self, chunk: list[dict]):
132
130
  """Get information from semantic scholar API per batch of articles IDs"""
133
- if not SEMANTIC_SCHOLAR_API_KEY:
131
+ api_key = os.getenv("SEMANTIC_SCHOLAR_API_KEY")
132
+ if not api_key:
134
133
  raise ValueError("SEMANTIC_SCHOLAR_API_KEY environment variable is not set")
135
134
  ids_list = ["URL:" + entry["id"] for entry in chunk]
136
135
  with requests.post(
137
136
  "https://api.semanticscholar.org/graph/v1/paper/batch",
138
137
  params={"fields": SEMANTIC_SCHOLAR_FIELDS},
139
138
  json={"ids": ids_list},
140
- headers={"x-api-key": SEMANTIC_SCHOLAR_API_KEY},
139
+ headers={"x-api-key": api_key},
141
140
  ) as response:
142
141
  return [item for item in response.json() if item is not None]
143
142
 
@@ -14,6 +14,9 @@ from bertrend.bertrend_apps.common.date_utils import daterange
14
14
  from bertrend.bertrend_apps.data_provider.arxiv_provider import ArxivProvider
15
15
  from bertrend.bertrend_apps.data_provider.atom_feed_provider import ATOMFeedProvider
16
16
  from bertrend.bertrend_apps.data_provider.bing_news_provider import BingNewsProvider
17
+ from bertrend.bertrend_apps.data_provider.deep_research_provider import (
18
+ DeepResearchProvider,
19
+ )
17
20
  from bertrend.bertrend_apps.data_provider.google_news_provider import GoogleNewsProvider
18
21
  from bertrend.bertrend_apps.data_provider.newscatcher_provider import (
19
22
  NewsCatcherProvider,
@@ -27,6 +30,7 @@ PROVIDERS = {
27
30
  "google": GoogleNewsProvider,
28
31
  "bing": BingNewsProvider,
29
32
  "newscatcher": NewsCatcherProvider,
33
+ "deep_research": DeepResearchProvider,
30
34
  }
31
35
 
32
36
 
@@ -145,8 +149,11 @@ def scrape_feed_from_config(
145
149
 
146
150
  # Generate a query file
147
151
  with tempfile.NamedTemporaryFile() as query_file:
148
- if (
149
- provider == "arxiv" or provider == "atom" or provider == "rss"
152
+ if provider in (
153
+ "arxiv",
154
+ "atom",
155
+ "rss",
156
+ "deep_research",
150
157
  ): # already returns batches
151
158
  scrape(
152
159
  keywords=keywords,
@@ -0,0 +1,501 @@
1
+ # Copyright (c) 2024-2026, RTE (https://www.rte-france.com)
2
+ # See AUTHORS.txt
3
+ # SPDX-License-Identifier: MPL-2.0
4
+ # This file is part of BERTrend.
5
+
6
+ import asyncio
7
+ import os
8
+ import time
9
+ from datetime import datetime
10
+
11
+ from agents import Runner, function_tool
12
+ from ddgs import DDGS
13
+ from dotenv import load_dotenv
14
+ from loguru import logger
15
+ from pydantic import BaseModel, Field
16
+
17
+ from bertrend.bertrend_apps.data_provider.data_provider import DataProvider
18
+ from bertrend.bertrend_apps.data_provider.utils import wait
19
+ from bertrend.llm_utils.agent_utils import BaseAgentFactory, run_config_no_tracing
20
+
21
+ load_dotenv(override=True)
22
+
23
+ DEFAULT_MODEL = os.getenv("OPENAI_DEFAULT_MODEL", "gpt-4.1-mini")
24
+ DEFAULT_MAX_SUB_QUERIES = 5
25
+ DEFAULT_SEARCH_DELAY = 3.0 # seconds between DuckDuckGo requests to avoid rate limiting
26
+
27
+
28
+ # ----------------------------------------------------------------------------
29
+ # Custom web search (to ensure it works both with openAI and
30
+ # and openAI compatible (ex. LiteLLM) environments)
31
+ # ----------------------------------------------------------------------------
32
+ def _make_news_search_tool(
33
+ collected_articles: list[dict],
34
+ language_code: str = "us-en",
35
+ ):
36
+ """Create a news_search function tool that also records every article found.
37
+
38
+ Parameters
39
+ ----------
40
+ collected_articles : list[dict]
41
+ Mutable list where every raw article dict returned by DuckDuckGo
42
+ will be appended, so that no URL is lost even if the LLM agent
43
+ omits it from its structured output.
44
+ """
45
+
46
+ @function_tool
47
+ def news_search(
48
+ query: str,
49
+ max_results: int = 10,
50
+ timelimit: str = None,
51
+ ) -> list[dict]:
52
+ """Search for recent news articles.
53
+
54
+ Args:
55
+ query: The search query string.
56
+ max_results: Maximum number of results to return.
57
+ timelimit: Time limit for results (e.g., 'd' for day, 'w' for week, 'm' for month).
58
+
59
+ Returns:
60
+ List of article dicts with title, url, date, source, body
61
+ """
62
+ try:
63
+ time.sleep(DEFAULT_SEARCH_DELAY)
64
+ with DDGS() as ddgs:
65
+ kwargs = {"query": query, "max_results": max_results}
66
+ kwargs["region"] = language_code
67
+
68
+ if timelimit:
69
+ kwargs["timelimit"] = timelimit
70
+ news_results = list(ddgs.news(**kwargs))
71
+
72
+ if not news_results:
73
+ return []
74
+
75
+ articles = [
76
+ {
77
+ "title": article.get("title", "No title"),
78
+ "url": article.get("url", ""),
79
+ "date": article.get("date", ""),
80
+ "source": article.get("source", ""),
81
+ "body": article.get("body", ""),
82
+ }
83
+ for article in news_results
84
+ ]
85
+
86
+ # Record every article so the aggregation step never loses URLs, avoiding duplicates
87
+ collected_articles.extend(articles)
88
+
89
+ return articles
90
+ except Exception as e:
91
+ logger.error(f"News search error: {str(e)}")
92
+ return []
93
+
94
+ return news_search
95
+
96
+
97
+ # ---------------------------------------------------------------------------
98
+ # Pydantic models for structured agent outputs
99
+ # ---------------------------------------------------------------------------
100
+
101
+
102
+ class ResearchPlan(BaseModel):
103
+ """Output of the planning step: a list of targeted sub-questions."""
104
+
105
+ sub_queries: list[str] = Field(
106
+ description="List of specific, targeted sub-questions to research"
107
+ )
108
+
109
+
110
+ class SubQueryResult(BaseModel):
111
+ """Output of a single research sub-query."""
112
+
113
+ sub_query: str = Field(description="The sub-question that was researched")
114
+ findings: str = Field(
115
+ description="Detailed findings from web research on this sub-question"
116
+ )
117
+ source_urls: list[str] = Field(
118
+ default_factory=list,
119
+ description="URLs of sources consulted for this sub-query",
120
+ )
121
+
122
+
123
+ # ---------------------------------------------------------------------------
124
+ # System prompts for each step
125
+ # ---------------------------------------------------------------------------
126
+
127
+ PLAN_PROMPT = """You are a research planning expert. Given a topic and date range, break it down into specific, targeted sub-questions that together will provide comprehensive coverage of the topic.
128
+
129
+ Each sub-question should:
130
+ - Be specific enough to yield focused search results
131
+ - Cover a different angle or aspect of the topic
132
+ - Be answerable through web research
133
+
134
+ Decide how many sub-questions are needed based on the complexity and breadth of the topic. Use fewer sub-questions for narrow or simple topics and more for broad or complex ones. You must return between 1 and {max_sub_queries} sub-questions (inclusive)."""
135
+
136
+ RESEARCH_PROMPT = """You are an Advanced Web Research Analyst. Your task is to investigate a specific user query, synthesize findings from high-quality sources, and provide a curated list of references.
137
+
138
+ **Search Constraints & Source Selection:**
139
+ 1. **Accessibility First:** Do NOT cite sources that are behind strict paywalls, require user registration, or are likely to be broken (404).
140
+ 2. **Quality Control:** Prioritize primary sources, official documentation, academic institutions, and reputable journalism. Strictly exclude SEO-spam, content farms, clickbait, and low-quality aggregators.
141
+ 3. **Information Utility (No Redundancy):** Only include a new URL if it provides *unique* value (e.g., a distinct statistic, a counter-argument, or a primary account) not found in the other sources. Do not list multiple sources that merely regurgitate the exact same AP wire or press release.
142
+
143
+ **Research Guidelines:**
144
+ - **Scope:** Focus on information from the date range: {after} to {before}.
145
+ - **Depth:** Look for specific data points, hard statistics, exact dates, and key stakeholder names.
146
+ - **Nuance:** actively seek out and highlight conflicting information or distinct viewpoints between sources.
147
+
148
+ **Output Format:**
149
+ 1. **Executive Summary:** A concise answer to the query.
150
+ 2. **Curated Source List:**
151
+ - Format: [Title](URL)
152
+ - *Requirement:* For each URL you consulted, add a one-line note explaining *what unique information* this specific link contributes (e.g., "Contains the 2024 financial table" or "Provides the opposing legal argument").
153
+
154
+ """
155
+
156
+
157
+ class DeepResearchProvider(DataProvider):
158
+ """Data provider that uses an agent-based approach to perform
159
+ multi-step deep web research and return individual news articles
160
+ with their URLs.
161
+
162
+ The research process follows two steps:
163
+ 1. PLAN — Break the query into targeted sub-questions
164
+ 2. RESEARCH — Search the web for each sub-question independently (in parallel)
165
+
166
+ URLs are deduplicated across all sub-queries and each unique URL is
167
+ returned as a separate article entry.
168
+ """
169
+
170
+ def __init__(
171
+ self,
172
+ model: str = None,
173
+ max_sub_queries: int = DEFAULT_MAX_SUB_QUERIES,
174
+ parallel_research: bool = True,
175
+ ):
176
+ # Do NOT call super().__init__() — we don't need Goose3 article parser
177
+ # since text is generated by the agent, not scraped from URLs.
178
+ self.model = model or DEFAULT_MODEL
179
+ self.max_sub_queries = max_sub_queries
180
+ self.parallel_research = parallel_research
181
+ self._factory = BaseAgentFactory(model_name=self.model)
182
+
183
+ # ------------------------------------------------------------------
184
+ # Step 1: PLAN
185
+ # ------------------------------------------------------------------
186
+
187
+ def _plan(
188
+ self, query: str, after: str, before: str, language: str = None
189
+ ) -> list[str]:
190
+ """Break the research query into targeted sub-questions."""
191
+ agent = self._factory.create_agent(
192
+ name="research_planner",
193
+ instructions=PLAN_PROMPT.format(max_sub_queries=self.max_sub_queries),
194
+ output_type=ResearchPlan,
195
+ )
196
+
197
+ prompt = (
198
+ f"Topic: {query}\n"
199
+ f"Date range: {after} to {before}\n"
200
+ f"Current date: {datetime.now().strftime('%Y-%m-%d')}"
201
+ )
202
+ if language:
203
+ prompt += f"\nGenerate sub-questions in {language}."
204
+
205
+ result = Runner.run_sync(agent, input=prompt, run_config=run_config_no_tracing)
206
+ plan: ResearchPlan = result.final_output
207
+ return plan.sub_queries
208
+
209
+ # ------------------------------------------------------------------
210
+ # Step 2: RESEARCH each sub-question
211
+ # ------------------------------------------------------------------
212
+
213
+ def _research_sub_query(
214
+ self,
215
+ sub_query: str,
216
+ after: str,
217
+ before: str,
218
+ collected_articles: list[dict] | None = None,
219
+ language_code: str = "us-en",
220
+ ) -> SubQueryResult:
221
+ """Search the web for a single sub-question and return findings."""
222
+ if collected_articles is None:
223
+ collected_articles = []
224
+ tool = _make_news_search_tool(collected_articles, language_code)
225
+ agent = self._factory.create_agent(
226
+ name="web_researcher",
227
+ instructions=RESEARCH_PROMPT.format(after=after, before=before),
228
+ tools=[tool],
229
+ output_type=SubQueryResult,
230
+ )
231
+
232
+ result = Runner.run_sync(
233
+ agent, input=sub_query, run_config=run_config_no_tracing
234
+ )
235
+ return result.final_output
236
+
237
+ async def _research_sub_query_async(
238
+ self,
239
+ sub_query: str,
240
+ after: str,
241
+ before: str,
242
+ collected_articles: list[dict] | None = None,
243
+ language_code: str = "us-en",
244
+ ) -> SubQueryResult:
245
+ """Async version of _research_sub_query for parallel execution."""
246
+ if collected_articles is None:
247
+ collected_articles = []
248
+ tool = _make_news_search_tool(collected_articles, language_code)
249
+ agent = self._factory.create_agent(
250
+ name="web_researcher",
251
+ instructions=RESEARCH_PROMPT.format(after=after, before=before),
252
+ tools=[tool],
253
+ output_type=SubQueryResult,
254
+ )
255
+
256
+ result = await Runner.run(
257
+ agent, input=sub_query, run_config=run_config_no_tracing
258
+ )
259
+ return result.final_output
260
+
261
+ async def _research_all_async(
262
+ self,
263
+ sub_queries: list[str],
264
+ after: str,
265
+ before: str,
266
+ collected_articles: list[dict] | None = None,
267
+ language_code: str = "us-en",
268
+ ) -> list[SubQueryResult]:
269
+ """Research all sub-queries concurrently and return successful results."""
270
+ if collected_articles is None:
271
+ collected_articles = []
272
+ tasks = [
273
+ self._research_sub_query_async(
274
+ sq, after, before, collected_articles, language_code
275
+ )
276
+ for sq in sub_queries
277
+ ]
278
+ results = await asyncio.gather(*tasks, return_exceptions=True)
279
+
280
+ findings: list[SubQueryResult] = []
281
+ for i, result in enumerate(results):
282
+ if isinstance(result, Exception):
283
+ logger.warning(f" → Sub-query {i + 1} failed: {result} (skipping)")
284
+ else:
285
+ n_sources = len(result.source_urls)
286
+ logger.info(
287
+ f" → Sub-query {i + 1}/{len(sub_queries)} complete: "
288
+ f"{n_sources} source(s)"
289
+ )
290
+ findings.append(result)
291
+ return findings
292
+
293
+ # ------------------------------------------------------------------
294
+ # Main entry point (DataProvider interface)
295
+ # ------------------------------------------------------------------
296
+
297
+ @wait(2)
298
+ def get_articles(
299
+ self,
300
+ query: str,
301
+ after: str,
302
+ before: str,
303
+ max_results: int,
304
+ language: str = None,
305
+ ) -> list[dict]:
306
+ """Perform multi-step deep web research and return individual articles.
307
+
308
+ The process follows two steps:
309
+ 1. PLAN — Break the query into targeted sub-questions
310
+ 2. RESEARCH — Search the web for each sub-question (in parallel)
311
+
312
+ URLs are deduplicated across all sub-queries and each unique URL is
313
+ returned as a separate article entry.
314
+
315
+ Parameters
316
+ ----------
317
+ query : str
318
+ Keywords or topic to research.
319
+ after : str
320
+ Start date formatted as YYYY-MM-DD.
321
+ before : str
322
+ End date formatted as YYYY-MM-DD.
323
+ max_results : int
324
+ Maximum number of articles to return.
325
+ language : str, optional
326
+ Language hint (unused, kept for interface compatibility).
327
+
328
+ Returns
329
+ -------
330
+ list[dict]
331
+ A list of article dicts with keys: title, text, summary, url,
332
+ link, timestamp.
333
+ """
334
+ logger.info(
335
+ f"DeepResearchProvider: starting multi-step research for '{query}' "
336
+ f"(date range: {after} to {before}, max_results: {max_results})"
337
+ )
338
+ articles = []
339
+ try:
340
+ result = self._run_research_pipeline(query, after, before, language)
341
+ if result is not None:
342
+ articles = result
343
+ except Exception as e:
344
+ logger.error(
345
+ f"DeepResearchProvider: error in research pipeline "
346
+ f"for query '{query}': {e}"
347
+ )
348
+
349
+ # Respect max_results
350
+ articles = articles[:max_results]
351
+
352
+ logger.info(
353
+ f"DeepResearchProvider: completed with {len(articles)} article(s) "
354
+ f"for query '{query}'"
355
+ )
356
+ return articles
357
+
358
+ def _run_research_pipeline(
359
+ self, query: str, after: str, before: str, language: str = None
360
+ ) -> list[dict] | None:
361
+ """Execute the full PLAN → RESEARCH → AGGREGATE pipeline.
362
+
363
+ Returns a list of article dicts with deduplicated URLs from all
364
+ sub-query findings.
365
+ """
366
+ language_code = "fr-fr" if language == "fr" else "us-en"
367
+
368
+ # Step 1: PLAN
369
+ logger.info("[PLAN] Breaking query into sub-questions...")
370
+ sub_queries = self._plan(query, after, before, language)
371
+ for j, sq in enumerate(sub_queries, 1):
372
+ logger.info(f" → Sub-question {j}/{len(sub_queries)}: {sq}")
373
+
374
+ # Step 2: RESEARCH each sub-question
375
+ use_async = self.parallel_research
376
+ if use_async:
377
+ try:
378
+ loop = asyncio.get_running_loop()
379
+ if loop.is_running():
380
+ # Already inside an async context — fall back to sequential
381
+ use_async = False
382
+ except RuntimeError:
383
+ pass
384
+
385
+ # collected_articles accumulates every raw article dict returned by
386
+ # the news_search tool, so that no URL is lost even if the LLM agent
387
+ # omits it from its structured SubQueryResult.source_urls.
388
+ collected_articles: list[dict] = []
389
+
390
+ if use_async:
391
+ logger.info(
392
+ f"[RESEARCH] Searching {len(sub_queries)} sub-queries in parallel..."
393
+ )
394
+ findings = asyncio.run(
395
+ self._research_all_async(
396
+ sub_queries, after, before, collected_articles, language_code
397
+ )
398
+ )
399
+ else:
400
+ logger.info(
401
+ f"[RESEARCH] Searching {len(sub_queries)} sub-queries sequentially..."
402
+ )
403
+ findings: list[SubQueryResult] = []
404
+ for j, sq in enumerate(sub_queries, 1):
405
+ logger.info(f'[RESEARCH {j}/{len(sub_queries)}] Searching: "{sq}"')
406
+ try:
407
+ sub_result = self._research_sub_query(
408
+ sq, after, before, collected_articles, language_code
409
+ )
410
+ findings.append(sub_result)
411
+ n_sources = len(sub_result.source_urls)
412
+ logger.info(f" → Found {n_sources} source(s)")
413
+ except Exception as e:
414
+ logger.warning(f" → Sub-query {j} failed: {e} (skipping)")
415
+ continue
416
+
417
+ if not findings and not collected_articles:
418
+ logger.error("DeepResearchProvider: all sub-queries failed, no findings")
419
+ return None
420
+
421
+ # Step 3: AGGREGATE deduplicated URLs
422
+ logger.info(
423
+ f"[AGGREGATE] Deduplicating URLs from {len(findings)} sub-query results "
424
+ f"and {len(collected_articles)} raw search result(s)..."
425
+ )
426
+ return self._aggregate_articles(findings, collected_articles)
427
+
428
+ def _parse_entry(self, entry: dict) -> dict | None:
429
+ """Not used — aggregation is handled by _aggregate_articles."""
430
+ return entry
431
+
432
+ def _aggregate_articles(
433
+ self,
434
+ findings: list[SubQueryResult],
435
+ collected_articles: list[dict] | None = None,
436
+ ) -> list[dict]:
437
+ """Aggregate and deduplicate URLs from all sub-query findings and
438
+ raw search results.
439
+
440
+ Each unique URL becomes a separate article entry. The raw
441
+ ``collected_articles`` (captured directly from the news_search tool)
442
+ are the primary source of truth so that no URL is lost even when the
443
+ LLM agent omits it from its structured output.
444
+
445
+ Parameters
446
+ ----------
447
+ findings : list[SubQueryResult]
448
+ Results from all sub-query research steps.
449
+ collected_articles : list[dict] | None
450
+ Raw article dicts captured directly from the news_search tool.
451
+
452
+ Returns
453
+ -------
454
+ list[dict]
455
+ A list of article dicts with keys: title, text, summary, url,
456
+ link, timestamp.
457
+ """
458
+ articles = []
459
+ seen_urls: set[str] = set()
460
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
461
+
462
+ # First, add every article captured directly from the search tool
463
+ # (this is the authoritative source — no URL can be lost here).
464
+ for raw in collected_articles or []:
465
+ url = raw.get("url", "")
466
+ if url and url not in seen_urls:
467
+ seen_urls.add(url)
468
+ # title = raw.get("title", "")
469
+ # body = raw.get("body", "")
470
+ text, title = self._get_text(url=url)
471
+ if text:
472
+ articles.append(
473
+ {
474
+ "title": title,
475
+ "text": text,
476
+ "summary": text[:200] if text else "",
477
+ "url": url,
478
+ "link": url,
479
+ "timestamp": timestamp,
480
+ }
481
+ )
482
+
483
+ # Then, add any URLs from the agent's structured output that the
484
+ # search tool might not have returned (e.g. URLs the agent found
485
+ # in page content).
486
+ for finding in findings:
487
+ for url in finding.source_urls:
488
+ if url and url not in seen_urls:
489
+ seen_urls.add(url)
490
+ articles.append(
491
+ {
492
+ "title": finding.sub_query,
493
+ "text": finding.findings,
494
+ "summary": finding.findings[:200],
495
+ "url": url,
496
+ "link": url,
497
+ "timestamp": timestamp,
498
+ }
499
+ )
500
+
501
+ return articles
@@ -0,0 +1,6 @@
1
+ [theme]
2
+ primaryColor = "royalblue"
3
+ baseFontSize = 13
4
+
5
+ [server]
6
+ port = 8089