bertrend 0.4.7__tar.gz → 0.4.9__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 (346) hide show
  1. {bertrend-0.4.7 → bertrend-0.4.9}/PKG-INFO +6 -1
  2. {bertrend-0.4.7 → bertrend-0.4.9}/README.md +5 -0
  3. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/data_provider/data_provider.py +39 -14
  4. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/queue_management/bertrend_worker.py +82 -21
  5. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/queue_management/queue_manager.py +49 -0
  6. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/queue_management/rabbitmq_config.py +4 -1
  7. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/queue_monitor/app.py +156 -5
  8. bertrend-0.4.9/bertrend/services/article_scoring_server/config/default_config.toml +3 -0
  9. bertrend-0.4.9/bertrend/services/article_scoring_server/config/settings.py +32 -0
  10. bertrend-0.4.9/bertrend/services/article_scoring_server/models.py +21 -0
  11. bertrend-0.4.9/bertrend/services/article_scoring_server/routers/info.py +19 -0
  12. bertrend-0.4.9/bertrend/services/article_scoring_server/routers/scoring.py +43 -0
  13. bertrend-0.4.9/bertrend/services/article_scoring_server/scoring_service.py +12 -0
  14. bertrend-0.4.9/bertrend/services/article_scoring_server/start.py +18 -0
  15. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/data_provider/test_data_provider_base.py +40 -12
  16. bertrend-0.4.9/bertrend/tests/services/article_scoring/test_article_scoring_server.py +84 -0
  17. bertrend-0.4.9/bertrend/tests/services/queue_management/__init__.py +4 -0
  18. bertrend-0.4.9/bertrend/tests/services/queue_management/test_bertrend_worker.py +294 -0
  19. bertrend-0.4.9/bertrend/tests/services/queue_management/test_queue_manager.py +146 -0
  20. bertrend-0.4.9/bertrend/tests/services/scheduling/__init__.py +4 -0
  21. bertrend-0.4.9/bertrend/tests/services/summarizer/__init__.py +4 -0
  22. bertrend-0.4.9/bertrend/tests/services/summary/__init__.py +4 -0
  23. bertrend-0.4.9/bertrend/tests/utils/__init__.py +4 -0
  24. {bertrend-0.4.7 → bertrend-0.4.9}/pyproject.toml +1 -1
  25. {bertrend-0.4.7 → bertrend-0.4.9}/AUTHORS.txt +0 -0
  26. {bertrend-0.4.7 → bertrend-0.4.9}/LICENSE.md +0 -0
  27. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/BERTopicModel.py +0 -0
  28. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/BERTrend.py +0 -0
  29. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/__init__.py +0 -0
  30. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/article_scoring/__init__.py +0 -0
  31. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/article_scoring/article_scoring.py +0 -0
  32. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/article_scoring/prompts.py +0 -0
  33. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/article_scoring/scoring_agent.py +0 -0
  34. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/__init__.py +0 -0
  35. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/common/__init__.py +0 -0
  36. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/common/apscheduler_utils.py +0 -0
  37. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/common/crontab_utils.py +0 -0
  38. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/common/date_utils.py +0 -0
  39. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/common/mail_utils.py +0 -0
  40. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/common/scheduler_utils.py +0 -0
  41. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/config/feeds/arxiv_feed.toml +0 -0
  42. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/config/feeds/decarbonation_feed.toml +0 -0
  43. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/config/feeds/feed_deep_research_example.toml +0 -0
  44. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/config/feeds/llm_en_feed.toml +0 -0
  45. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/config/feeds/llm_feed.toml +0 -0
  46. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/config/feeds/nlp_feed.toml +0 -0
  47. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/config/feeds/rte_feed.toml +0 -0
  48. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/config/newsletters/arxiv_newsletter_from_last.toml +0 -0
  49. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/config/newsletters/decarbonation_newsletter_from_last.toml +0 -0
  50. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/config/newsletters/llm_en_newsletter_from_last.toml +0 -0
  51. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/config/newsletters/llm_newsletter_from_last.toml +0 -0
  52. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/config/newsletters/nlp_newsletter_from_last.toml +0 -0
  53. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/config/newsletters/rte_newsletter_from_last.toml +0 -0
  54. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/data_provider/__init__.py +0 -0
  55. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/data_provider/__main__.py +0 -0
  56. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/data_provider/arxiv_provider.py +0 -0
  57. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/data_provider/atom_feed_provider.py +0 -0
  58. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/data_provider/bing_news_provider.py +0 -0
  59. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/data_provider/data_provider_utils.py +0 -0
  60. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/data_provider/deep_research_provider.py +0 -0
  61. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/data_provider/google_news_provider.py +0 -0
  62. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/data_provider/newscatcher_provider.py +0 -0
  63. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/data_provider/rss_feed_provider.py +0 -0
  64. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/data_provider/utils.py +0 -0
  65. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/__init__.py +0 -0
  66. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/curebot/.streamlit/config.toml +0 -0
  67. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/curebot/__init__.py +0 -0
  68. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/curebot/app.py +0 -0
  69. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/curebot/app_utils.py +0 -0
  70. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/curebot/config.toml +0 -0
  71. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/curebot/import_extraction_article.ipynb +0 -0
  72. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/curebot/prompts.py +0 -0
  73. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/curebot/start_newsletter_generator.sh +0 -0
  74. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/curebot/tabs/__init__.py +0 -0
  75. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/curebot/tabs/tab1.py +0 -0
  76. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/curebot/tabs/tab2.py +0 -0
  77. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/curebot/tabs/tab3.py +0 -0
  78. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/geoviz/.streamlit/config.toml +0 -0
  79. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/geoviz/__init__.py +0 -0
  80. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/geoviz/app.py +0 -0
  81. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/geoviz/backend.py +0 -0
  82. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/start_apps.sh +0 -0
  83. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/exploration/stop_apps.sh +0 -0
  84. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/install_feeds_and_newsletters.py +0 -0
  85. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/newsletters/__init__.py +0 -0
  86. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/newsletters/__main__.py +0 -0
  87. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/newsletters/newsletter_generation.py +0 -0
  88. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/newsletters/utils.py +0 -0
  89. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/.streamlit/config.toml +0 -0
  90. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/.streamlit/secrets.toml.example +0 -0
  91. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/__init__.py +0 -0
  92. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/app.py +0 -0
  93. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/authentication.py +0 -0
  94. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/automated_report_generation.py +0 -0
  95. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/dashboard_analysis.py +0 -0
  96. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/dashboard_common.py +0 -0
  97. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/dashboard_comparative.py +0 -0
  98. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/dashboard_signals.py +0 -0
  99. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/data_model.py +0 -0
  100. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/detailed_report_template.html +0 -0
  101. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/feeds_common.py +0 -0
  102. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/feeds_config.py +0 -0
  103. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/feeds_data.py +0 -0
  104. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/i18n.py +0 -0
  105. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/i18n_translations.py +0 -0
  106. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/llm_utils.py +0 -0
  107. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/models_info.py +0 -0
  108. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/perf_utils.py +0 -0
  109. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/process_new_data.py +0 -0
  110. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/report_generation.py +0 -0
  111. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/report_generation_utils.py +0 -0
  112. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/start_demo.sh +0 -0
  113. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/prospective_demo/utils.py +0 -0
  114. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/__init__.py +0 -0
  115. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/__init__.py +0 -0
  116. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/bertrend_service.py +0 -0
  117. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/config/__init__.py +0 -0
  118. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/config/default_config.toml +0 -0
  119. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/config/settings.py +0 -0
  120. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/models/__init__.py +0 -0
  121. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/models/bertrend_app_models.py +0 -0
  122. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/models/data_provider_models.py +0 -0
  123. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/models/newsletters_models.py +0 -0
  124. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/routers/__init__.py +0 -0
  125. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/routers/bertrend_app.py +0 -0
  126. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/routers/data_provider.py +0 -0
  127. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/routers/info.py +0 -0
  128. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/routers/newsletters.py +0 -0
  129. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/start.py +0 -0
  130. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/status.py +0 -0
  131. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/bertrend/stop.py +0 -0
  132. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/queue_management/__init__.py +0 -0
  133. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/queue_management/client.py +0 -0
  134. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/queue_management/docker-compose-rabbitmq.yml +0 -0
  135. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/queue_management/start_rabbitmq.sh +0 -0
  136. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/queue_monitor/.streamlit/config.toml +0 -0
  137. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/queue_monitor/__init__.py +0 -0
  138. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/utils/__init__.py +0 -0
  139. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/bertrend_apps/services/utils/logging_utils.py +0 -0
  140. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/config/bertopic_default_config.toml +0 -0
  141. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/config/bertrend_default_config.toml +0 -0
  142. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/config/parameters.py +0 -0
  143. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/config/services_default_config.toml +0 -0
  144. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/__init__.py +0 -0
  145. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/demos_utils/__init__.py +0 -0
  146. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/demos_utils/data_loading_component.py +0 -0
  147. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/demos_utils/embed_documents_component.py +0 -0
  148. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/demos_utils/i18n.py +0 -0
  149. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/demos_utils/i18n_translations.py +0 -0
  150. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/demos_utils/icons.py +0 -0
  151. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/demos_utils/parameters_component.py +0 -0
  152. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/demos_utils/state_utils.py +0 -0
  153. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/start_summarizer_app.sh +0 -0
  154. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/start_topic_analysis_app.sh +0 -0
  155. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/start_weak_signals_app.sh +0 -0
  156. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/streamlit_components/__init__.py +0 -0
  157. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/streamlit_components/clickable_df_component.py +0 -0
  158. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/streamlit_components/input_with_pills_component.py +0 -0
  159. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/summarization/__init__.py +0 -0
  160. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/summarization/summarizer_app.py +0 -0
  161. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/topic_analysis/.streamlit/config.toml +0 -0
  162. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/topic_analysis/__init__.py +0 -0
  163. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/topic_analysis/app.py +0 -0
  164. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/topic_analysis/app_utils.py +0 -0
  165. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/topic_analysis/demo_pages/__init__.py +0 -0
  166. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/topic_analysis/demo_pages/explore_topics.py +0 -0
  167. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/topic_analysis/demo_pages/newsletters_generation.py +0 -0
  168. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/topic_analysis/demo_pages/temporal_visualizations.py +0 -0
  169. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/topic_analysis/demo_pages/topic_visualizations.py +0 -0
  170. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/topic_analysis/demo_pages/training_page.py +0 -0
  171. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/topic_analysis/i18n_translations.py +0 -0
  172. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/weak_signals/.streamlit/config.toml +0 -0
  173. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/weak_signals/__init__.py +0 -0
  174. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/weak_signals/app.py +0 -0
  175. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/weak_signals/i18n_translations.py +0 -0
  176. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/demos/weak_signals/visualizations_utils.py +0 -0
  177. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/llm_utils/__init__.py +0 -0
  178. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/llm_utils/agent_utils.py +0 -0
  179. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/llm_utils/newsletter.css +0 -0
  180. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/llm_utils/newsletter_features.py +0 -0
  181. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/llm_utils/newsletter_model.py +0 -0
  182. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/llm_utils/newsletter_outlook_template.html +0 -0
  183. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/llm_utils/newsletter_template.html +0 -0
  184. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/llm_utils/openai_client.py +0 -0
  185. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/llm_utils/prompts.py +0 -0
  186. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/metrics/__init__.py +0 -0
  187. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/metrics/temporal_metrics_embedding.py +0 -0
  188. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/metrics/topic_metrics.py +0 -0
  189. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/resources/common_ngrams.json +0 -0
  190. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/resources/stopwords-en.json +0 -0
  191. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/resources/stopwords-fr.json +0 -0
  192. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/resources/stopwords-rte.json +0 -0
  193. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/__init__.py +0 -0
  194. {bertrend-0.4.7/bertrend/services/embedding_server → bertrend-0.4.9/bertrend/services/article_scoring_server}/__init__.py +0 -0
  195. {bertrend-0.4.7/bertrend/services/embedding_server/routers → bertrend-0.4.9/bertrend/services/article_scoring_server/config}/__init__.py +0 -0
  196. {bertrend-0.4.7/bertrend/services/scheduling → bertrend-0.4.9/bertrend/services/article_scoring_server/routers}/__init__.py +0 -0
  197. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/authentication.py +0 -0
  198. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/cert.pem +0 -0
  199. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_client.py +0 -0
  200. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_server/README.md +0 -0
  201. {bertrend-0.4.7/bertrend/services/scheduling/job_utils → bertrend-0.4.9/bertrend/services/embedding_server}/__init__.py +0 -0
  202. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_server/bertrend_client_registry.json +0 -0
  203. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_server/config/default_config.toml +0 -0
  204. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_server/config/settings.py +0 -0
  205. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_server/main.py +0 -0
  206. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_server/models.py +0 -0
  207. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_server/requirements.txt +0 -0
  208. {bertrend-0.4.7/bertrend/services/scheduling/models → bertrend-0.4.9/bertrend/services/embedding_server/routers}/__init__.py +0 -0
  209. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_server/routers/authentication.py +0 -0
  210. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_server/routers/embeddings.py +0 -0
  211. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_server/routers/info.py +0 -0
  212. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_server/security.py +0 -0
  213. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_server/start.py +0 -0
  214. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_server/status.py +0 -0
  215. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_server/stop.py +0 -0
  216. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/embedding_service.py +0 -0
  217. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/key.pem +0 -0
  218. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/scheduling/.dockerignore +0 -0
  219. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/scheduling/Docker_setup.md +0 -0
  220. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/scheduling/Dockerfile +0 -0
  221. {bertrend-0.4.7/bertrend/services/summary → bertrend-0.4.9/bertrend/services/scheduling}/__init__.py +0 -0
  222. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/scheduling/dashboard_scheduling.py +0 -0
  223. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/scheduling/docker-compose.yml +0 -0
  224. {bertrend-0.4.7/bertrend/services/summary_server → bertrend-0.4.9/bertrend/services/scheduling/job_utils}/__init__.py +0 -0
  225. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/scheduling/job_utils/job_functions.py +0 -0
  226. {bertrend-0.4.7/bertrend/services/summary_server/config → bertrend-0.4.9/bertrend/services/scheduling/models}/__init__.py +0 -0
  227. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/scheduling/models/scheduling_models.py +0 -0
  228. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/scheduling/requirements.txt +0 -0
  229. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/scheduling/routers/info.py +0 -0
  230. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/scheduling/routers/scheduling.py +0 -0
  231. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/scheduling/scheduling_service.py +0 -0
  232. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/scheduling/start_docker_scheduling_service.sh +0 -0
  233. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/summarizer.py +0 -0
  234. {bertrend-0.4.7/bertrend/services/summary_server/routers → bertrend-0.4.9/bertrend/services/summary}/__init__.py +0 -0
  235. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/summary/abstractive_summarizer.py +0 -0
  236. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/summary/chatgpt_summarizer.py +0 -0
  237. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/summary/extractive_summarizer.py +0 -0
  238. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/summary/lexrank.py +0 -0
  239. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/summary/prompts.py +0 -0
  240. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/summary_client.py +0 -0
  241. {bertrend-0.4.7/bertrend/tests → bertrend-0.4.9/bertrend/services/summary_server}/__init__.py +0 -0
  242. {bertrend-0.4.7/bertrend/tests/apps → bertrend-0.4.9/bertrend/services/summary_server/config}/__init__.py +0 -0
  243. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/summary_server/config/default_config.toml +0 -0
  244. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/summary_server/config/settings.py +0 -0
  245. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/summary_server/main.py +0 -0
  246. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/summary_server/models.py +0 -0
  247. {bertrend-0.4.7/bertrend/tests/core → bertrend-0.4.9/bertrend/services/summary_server/routers}/__init__.py +0 -0
  248. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/summary_server/routers/info.py +0 -0
  249. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/summary_server/routers/summarize.py +0 -0
  250. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/services/summary_server/start.py +0 -0
  251. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/README_integration_tests.md +0 -0
  252. {bertrend-0.4.7/bertrend/tests/data_provider → bertrend-0.4.9/bertrend/tests}/__init__.py +0 -0
  253. {bertrend-0.4.7/bertrend/tests/demos → bertrend-0.4.9/bertrend/tests/apps}/__init__.py +0 -0
  254. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/apps/test_process_new_data.py +0 -0
  255. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/conftest.py +0 -0
  256. {bertrend-0.4.7/bertrend/tests/demos/summarization → bertrend-0.4.9/bertrend/tests/core}/__init__.py +0 -0
  257. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/core/test_bertrend.py +0 -0
  258. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/core/test_data_structure.py +0 -0
  259. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/core/test_representative_docs.py +0 -0
  260. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/core/test_temporal_metrics_embedding.py +0 -0
  261. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/core/test_topic_description.py +0 -0
  262. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/core/test_topic_metrics.py +0 -0
  263. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/core/test_topic_model.py +0 -0
  264. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/core/test_trend_analysis_data_structure.py +0 -0
  265. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/core/test_trend_analysis_prompts.py +0 -0
  266. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/core/test_trend_analysis_visualizations.py +0 -0
  267. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/core/test_trend_analysis_weak_signals.py +0 -0
  268. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/core/test_visualizations.py +0 -0
  269. {bertrend-0.4.7/bertrend/tests/llm → bertrend-0.4.9/bertrend/tests/data_provider}/__init__.py +0 -0
  270. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/data_provider/test_arxiv_provider.py +0 -0
  271. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/data_provider/test_bing_news_provider.py +0 -0
  272. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/data_provider/test_data_provider_utils.py +0 -0
  273. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/data_provider/test_deep_research_live.py +0 -0
  274. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/data_provider/test_deep_research_provider.py +0 -0
  275. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/data_provider/test_google_news_provider.py +0 -0
  276. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/data_provider/test_newscatcher_provider.py +0 -0
  277. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/data_provider/test_rss_atom_provider.py +0 -0
  278. {bertrend-0.4.7/bertrend/tests/services → bertrend-0.4.9/bertrend/tests/demos}/__init__.py +0 -0
  279. {bertrend-0.4.7/bertrend/tests/services/embedding → bertrend-0.4.9/bertrend/tests/demos/summarization}/__init__.py +0 -0
  280. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/demos/summarization/test_summarizer_app.py +0 -0
  281. {bertrend-0.4.7/bertrend/tests/services/embedding_server → bertrend-0.4.9/bertrend/tests/llm}/__init__.py +0 -0
  282. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/llm/test_agent_utils.py +0 -0
  283. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/llm/test_article_scoring.py +0 -0
  284. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/llm/test_article_scoring_models.py +0 -0
  285. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/llm/test_newsletter_features.py +0 -0
  286. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/llm/test_newsletter_model.py +0 -0
  287. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/llm/test_openai_client.py +0 -0
  288. {bertrend-0.4.7/bertrend/tests/services/queue → bertrend-0.4.9/bertrend/tests/services}/__init__.py +0 -0
  289. {bertrend-0.4.7/bertrend/tests/services/scheduling → bertrend-0.4.9/bertrend/tests/services/article_scoring}/__init__.py +0 -0
  290. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/bertrend/__init__.py +0 -0
  291. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/bertrend/test_bertrend_service.py +0 -0
  292. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/bertrend/test_models.py +0 -0
  293. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/bertrend/test_routers_bertrend_app.py +0 -0
  294. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/bertrend/test_routers_info.py +0 -0
  295. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/bertrend/test_routers_newsletters.py +0 -0
  296. {bertrend-0.4.7/bertrend/tests/services/summarizer → bertrend-0.4.9/bertrend/tests/services/embedding}/__init__.py +0 -0
  297. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/embedding/test_embedding_client.py +0 -0
  298. {bertrend-0.4.7/bertrend/tests/services/summary → bertrend-0.4.9/bertrend/tests/services/embedding_server}/__init__.py +0 -0
  299. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/embedding_server/test_models.py +0 -0
  300. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/embedding_server/test_routers.py +0 -0
  301. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/embedding_server/test_security.py +0 -0
  302. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/embedding_server/test_settings.py +0 -0
  303. {bertrend-0.4.7/bertrend/tests/utils → bertrend-0.4.9/bertrend/tests/services/queue}/__init__.py +0 -0
  304. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/queue/test_bertrend_worker.py +0 -0
  305. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/queue/test_client.py +0 -0
  306. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/queue/test_queue_manager.py +0 -0
  307. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/scheduling/test_job_exception_fix.py +0 -0
  308. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/scheduling/test_scheduling_service.py +0 -0
  309. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/scheduling/test_stress_test.py +0 -0
  310. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/summarizer/test_abstractive_summarizer.py +0 -0
  311. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/summarizer/test_chatgpt_summarizer.py +0 -0
  312. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/summarizer/test_extractive_summarizer.py +0 -0
  313. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/summarizer/test_summarizer.py +0 -0
  314. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/summary/test_summary_client.py +0 -0
  315. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/summary/test_summary_config.py +0 -0
  316. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/services/summary/test_summary_server.py +0 -0
  317. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/test_installation.py +0 -0
  318. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/test_integration.py +0 -0
  319. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/utils/test_apscheduler_utils.py +0 -0
  320. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/utils/test_cache_utils.py +0 -0
  321. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/utils/test_config_utils.py +0 -0
  322. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/utils/test_crontab_utils.py +0 -0
  323. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/utils/test_data_loading.py +0 -0
  324. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/utils/test_date_utils.py +0 -0
  325. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/utils/test_lazy_scheduler.py +0 -0
  326. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/utils/test_mail_utils.py +0 -0
  327. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/utils/test_multiworker.py +0 -0
  328. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/utils/test_scheduler_utils.py +0 -0
  329. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/tests/utils/test_utils_init.py +0 -0
  330. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/topic_analysis/__init__.py +0 -0
  331. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/topic_analysis/data_structure.py +0 -0
  332. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/topic_analysis/prompts.py +0 -0
  333. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/topic_analysis/representative_docs.py +0 -0
  334. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/topic_analysis/topic_description.py +0 -0
  335. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/topic_analysis/visualizations.py +0 -0
  336. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/trend_analysis/__init__.py +0 -0
  337. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/trend_analysis/data_structure.py +0 -0
  338. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/trend_analysis/prompts.py +0 -0
  339. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/trend_analysis/signal_llm_template_en.html +0 -0
  340. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/trend_analysis/signal_llm_template_fr.html +0 -0
  341. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/trend_analysis/visualizations.py +0 -0
  342. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/trend_analysis/weak_signals.py +0 -0
  343. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/utils/__init__.py +0 -0
  344. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/utils/cache_utils.py +0 -0
  345. {bertrend-0.4.7 → bertrend-0.4.9}/bertrend/utils/config_utils.py +0 -0
  346. {bertrend-0.4.7 → bertrend-0.4.9}/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.7
3
+ Version: 0.4.9
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
@@ -448,6 +448,11 @@ Provides various statistics about topics:
448
448
 
449
449
  ![llm_interpretation](docs/images/llm_interpretation.png)
450
450
 
451
+ ## Article Scoring Service
452
+
453
+ For service setup and API details, see:
454
+ [`docs/services/article_scoring_service.md`](docs/services/article_scoring_service.md).
455
+
451
456
  ## Support
452
457
 
453
458
  Please use the 'Issues' section to report and discuss any problems with BERTrend.
@@ -364,6 +364,11 @@ Provides various statistics about topics:
364
364
 
365
365
  ![llm_interpretation](docs/images/llm_interpretation.png)
366
366
 
367
+ ## Article Scoring Service
368
+
369
+ For service setup and API details, see:
370
+ [`docs/services/article_scoring_service.md`](docs/services/article_scoring_service.md).
371
+
367
372
  ## Support
368
373
 
369
374
  Please use the 'Issues' section to report and discuss any problems with BERTrend.
@@ -2,7 +2,6 @@
2
2
  # See AUTHORS.txt
3
3
  # SPDX-License-Identifier: MPL-2.0
4
4
  # This file is part of BERTrend.
5
- import asyncio
6
5
  import os
7
6
  from abc import ABC, abstractmethod
8
7
  from pathlib import Path
@@ -10,6 +9,7 @@ from pathlib import Path
10
9
  import jsonlines
11
10
  import langdetect
12
11
  import pandas as pd
12
+ import requests
13
13
  from dateutil import parser
14
14
  from goose3 import Goose
15
15
  from joblib import Parallel, delayed
@@ -17,12 +17,11 @@ from loguru import logger
17
17
  from newspaper import Article
18
18
 
19
19
  from bertrend.article_scoring.article_scoring import QualityLevel
20
- from bertrend.article_scoring.scoring_agent import score_articles
21
- from bertrend.utils.data_loading import TEXT_COLUMN
22
20
  from bertrend.bertrend_apps.data_provider.utils import (
23
21
  decode_google_news_url,
24
22
  wait_if_seen_url,
25
23
  )
24
+ from bertrend.utils.data_loading import TEXT_COLUMN
26
25
 
27
26
  # Ensures to write with +rw for both user and groups
28
27
  os.umask(0o002)
@@ -85,27 +84,53 @@ class DataProvider(ABC):
85
84
 
86
85
  @staticmethod
87
86
  def evaluate_quality(
88
- articles: list[dict], minimum_quality_level: QualityLevel
87
+ articles: list[dict], minimum_quality_level: QualityLevel = QualityLevel.AVERAGE
89
88
  ) -> list[dict]:
90
89
  texts = [article[TEXT_COLUMN] for article in articles]
90
+ article_scoring_service_url = os.getenv("ARTICLE_SCORING_SERVICE_URL")
91
+
92
+ if not article_scoring_service_url:
93
+ logger.warning(
94
+ "ARTICLE_SCORING_SERVICE_URL is not set; skipping article quality filtering."
95
+ )
96
+ return articles
97
+
98
+ try:
99
+ response = requests.post(
100
+ f"{article_scoring_service_url.rstrip('/')}/score",
101
+ json={"articles": texts},
102
+ timeout=300,
103
+ )
104
+ response.raise_for_status()
105
+ payload = response.json()
106
+ results = payload.get("results", [])
107
+ except requests.RequestException as exc:
108
+ logger.warning(
109
+ f"Article scoring service unavailable at {article_scoring_service_url}: {exc}. "
110
+ "Skipping article quality filtering."
111
+ )
112
+ return articles
91
113
 
92
- # Evaluate quality of articles using a LLM agent
93
- results = asyncio.run(score_articles(texts))
114
+ if len(results) != len(texts):
115
+ logger.warning(
116
+ "Article scoring service returned an unexpected number of results; "
117
+ "skipping article quality filtering."
118
+ )
119
+ return articles
94
120
 
95
- # Filter out articles with quality < minimum_quality
121
+ # Filter out articles with quality < minimum_quality_level
96
122
  filtered_articles = [
97
123
  {
98
124
  **article,
99
- "quality_metrics": results[i].output.model_dump(),
100
- "overall_quality": results[i].output.quality_level.name,
125
+ "quality_metrics": results[i]["quality_metrics"],
126
+ "overall_quality": results[i]["overall_quality"],
101
127
  }
102
- # 1. Ensure output is NOT None before proceeding
103
128
  for i, article in enumerate(articles)
104
- if results[i].output is not None
105
- # 2. Then, check the quality level
106
- and results[i].output.quality_level >= minimum_quality_level
129
+ if results[i].get("overall_quality") in QualityLevel.__members__
130
+ and QualityLevel[results[i]["overall_quality"]] >= minimum_quality_level
131
+ and not results[i].get("error")
107
132
  ]
108
- assert len(results) == len(texts)
133
+
109
134
  logger.info(
110
135
  f"Filtered out {len(articles) - len(filtered_articles)} articles with quality < {minimum_quality_level.name}"
111
136
  )
@@ -253,6 +253,45 @@ class BertrendWorker:
253
253
  "traceback": traceback.format_exc(),
254
254
  }
255
255
 
256
+ def _get_retry_count(self, message: aio_pika.abc.AbstractIncomingMessage) -> int:
257
+ """Return the current retry count stored in the message header x-retry-count."""
258
+ headers = message.headers or {}
259
+ try:
260
+ return int(headers.get("x-retry-count", 0))
261
+ except (TypeError, ValueError):
262
+ return 0
263
+
264
+ async def _nack_or_discard(
265
+ self,
266
+ message: aio_pika.abc.AbstractIncomingMessage,
267
+ reason: str,
268
+ correlation_id: str | None,
269
+ ):
270
+ """
271
+ Retry the message if the retry limit has not been reached, otherwise
272
+ reject it (requeue=False) so it goes to the DLQ.
273
+
274
+ Delegates the retry-limit check to republish_with_retry(), which
275
+ returns False when the limit is reached (and skips publishing).
276
+ The original message is always rejected with requeue=False so that
277
+ RabbitMQ does not re-deliver the same copy.
278
+ """
279
+ retry_count = self._get_retry_count(message)
280
+ republished = await self.queue_manager.republish_with_retry(
281
+ message, retry_count
282
+ )
283
+ if republished:
284
+ logger.warning(
285
+ f"Message {correlation_id} failed (attempt {retry_count + 1}/{self.config.max_retries}) "
286
+ f"— republished with incremented retry count. Reason: {reason}"
287
+ )
288
+ else:
289
+ logger.warning(
290
+ f"Message {correlation_id} exceeded max retries ({self.config.max_retries}) "
291
+ f"— sending to DLQ. Reason: {reason}"
292
+ )
293
+ await message.reject(requeue=False)
294
+
256
295
  async def callback(
257
296
  self,
258
297
  message: aio_pika.abc.AbstractIncomingMessage,
@@ -268,41 +307,63 @@ class BertrendWorker:
268
307
 
269
308
  logger.info(f"Request endpoint: {request_data.get('endpoint')}")
270
309
 
271
- # Process request
272
- response_data = await self.process_request(request_data)
310
+ # Process request with a timeout to avoid blocking the queue indefinitely
311
+ response_data = await asyncio.wait_for(
312
+ self.process_request(request_data),
313
+ timeout=self.config.job_timeout,
314
+ )
273
315
 
274
316
  # Add metadata
275
317
  response_data["correlation_id"] = correlation_id
276
318
  response_data["request_data"] = request_data
277
319
 
278
- # Publish response/error if reply_to is specified
279
- if message.reply_to:
280
- if response_data.get("status") == "error":
281
- await self.queue_manager.publish_error(
282
- error_data=response_data, correlation_id=correlation_id
283
- )
284
- else:
285
- await self.queue_manager.publish_response(
286
- response_data=response_data, correlation_id=correlation_id
287
- )
288
-
289
- # Acknowledge message
290
- await message.ack()
291
- logger.info(
292
- f"Completed request: {correlation_id} - Status: {response_data.get('status')}"
293
- )
294
-
295
320
  except json.JSONDecodeError as e:
296
321
  logger.error(f"Invalid message format: {str(e)}")
297
322
  # Reject and don't requeue invalid messages
298
323
  await message.reject(requeue=False)
324
+ return
325
+
326
+ except asyncio.TimeoutError:
327
+ await self._nack_or_discard(
328
+ message,
329
+ reason=f"job timed out after {self.config.job_timeout}s",
330
+ correlation_id=correlation_id,
331
+ )
332
+ return
299
333
 
300
334
  except Exception as e:
301
335
  logger.error(f"Error processing message: {str(e)}")
302
336
  logger.error(traceback.format_exc())
337
+ await self._nack_or_discard(
338
+ message,
339
+ reason=str(e),
340
+ correlation_id=correlation_id,
341
+ )
342
+ return
303
343
 
304
- # Requeue for retry (will go to DLQ after max retries)
305
- await message.nack(requeue=True)
344
+ # Acknowledge message before publishing the response, so that the message
345
+ # is always acked regardless of any subsequent publish failure
346
+ await message.ack()
347
+ logger.info(
348
+ f"Completed request: {correlation_id} - Status: {response_data.get('status')}"
349
+ )
350
+
351
+ # Publish response/error if reply_to is specified
352
+ if message.reply_to:
353
+ try:
354
+ if response_data.get("status") == "error":
355
+ await self.queue_manager.publish_error(
356
+ error_data=response_data, correlation_id=correlation_id
357
+ )
358
+ else:
359
+ await self.queue_manager.publish_response(
360
+ response_data=response_data, correlation_id=correlation_id
361
+ )
362
+ except Exception as e:
363
+ logger.error(
364
+ f"Failed to publish response for {correlation_id}: {str(e)}"
365
+ )
366
+ logger.error(traceback.format_exc())
306
367
 
307
368
  async def start(self):
308
369
  """Start the worker"""
@@ -159,6 +159,55 @@ class QueueManager:
159
159
 
160
160
  await queue.consume(callback, no_ack=False)
161
161
 
162
+ async def republish_with_retry(
163
+ self,
164
+ original_message: aio_pika.abc.AbstractIncomingMessage,
165
+ retry_count: int,
166
+ ) -> bool:
167
+ """Republish a failed message with an incremented x-retry-count header.
168
+
169
+ RabbitMQ does not modify headers on requeue, so we must republish
170
+ manually with the updated counter instead of using nack(requeue=True).
171
+
172
+ Returns True if the message was republished, False if the retry limit
173
+ has already been reached and the message was not republished.
174
+ """
175
+ new_retry_count = retry_count + 1
176
+ if new_retry_count > self.config.max_retries:
177
+ logger.warning(
178
+ f"Message {original_message.correlation_id} has reached the maximum "
179
+ f"retry limit ({self.config.max_retries}) — not republishing."
180
+ )
181
+ return False
182
+
183
+ if not self.channel or self.channel.is_closed:
184
+ await self.connect()
185
+
186
+ # Carry over all existing headers and bump the retry counter
187
+ headers = dict(original_message.headers or {})
188
+ headers["x-retry-count"] = new_retry_count
189
+
190
+ message = aio_pika.Message(
191
+ body=original_message.body,
192
+ headers=headers,
193
+ delivery_mode=aio_pika.DeliveryMode.PERSISTENT,
194
+ priority=original_message.priority,
195
+ correlation_id=original_message.correlation_id,
196
+ content_type=original_message.content_type,
197
+ reply_to=original_message.reply_to,
198
+ )
199
+
200
+ await self.channel.default_exchange.publish(
201
+ message,
202
+ routing_key=self.config.request_queue,
203
+ )
204
+
205
+ logger.info(
206
+ f"Republished message {original_message.correlation_id} "
207
+ f"with x-retry-count={new_retry_count}"
208
+ )
209
+ return True
210
+
162
211
  async def publish_response(self, response_data: dict, correlation_id: str):
163
212
  """Publish response to response queue_management"""
164
213
  if not self.channel or self.channel.is_closed:
@@ -36,5 +36,8 @@ class RabbitMQConfig:
36
36
  prefetch_count: int = int(os.getenv("RABBITMQ_PREFETCH_COUNT", 1))
37
37
 
38
38
  # Retry configuration
39
- max_retries: int = int(os.getenv("RABBITMQ_MAX_RETRIES", 3))
39
+ max_retries: int = int(os.getenv("RABBITMQ_MAX_RETRIES", 2))
40
40
  retry_delay: int = int(os.getenv("RABBITMQ_RETRY_DELAY", 5000)) # milliseconds
41
+
42
+ # Job timeout: max seconds a single job may run before being nacked (default: 1 hour)
43
+ job_timeout: int = int(os.getenv("RABBITMQ_JOB_TIMEOUT", 3600))
@@ -60,6 +60,18 @@ class RabbitMQAdminClient:
60
60
  r.raise_for_status()
61
61
  return r.json()
62
62
 
63
+ def get_consumers(self) -> List[Dict[str, Any]]:
64
+ url = f"{self.base_url}/api/consumers/{self._vhost_path()}"
65
+ r = self._session.get(url, timeout=5)
66
+ r.raise_for_status()
67
+ return r.json()
68
+
69
+ def get_channels(self) -> List[Dict[str, Any]]:
70
+ url = f"{self.base_url}/api/channels"
71
+ r = self._session.get(url, timeout=5)
72
+ r.raise_for_status()
73
+ return r.json()
74
+
63
75
  def peek_messages(self, name: str, count: int = 10) -> List[Dict[str, Any]]:
64
76
  url = f"{self.base_url}/api/queues/{self._vhost_path()}/{quote(name, safe='')}/get"
65
77
  payload = {
@@ -262,7 +274,14 @@ client = RabbitMQAdminClient(client_cfg, management_url=mgmt_url)
262
274
 
263
275
  # --- Data Fetching ---
264
276
  queue_data = {}
265
- global_stats = {"total": 0, "ready": 0, "unacked": 0, "consumers": 0}
277
+ global_stats = {
278
+ "total": 0,
279
+ "requests": 0,
280
+ "responses": 0,
281
+ "failed": 0,
282
+ "unacked": 0,
283
+ "consumers": 0,
284
+ }
266
285
  error_msg = None
267
286
 
268
287
  try:
@@ -272,9 +291,14 @@ try:
272
291
 
273
292
  # Aggregation
274
293
  global_stats["total"] += info.get("messages", 0)
275
- global_stats["ready"] += info.get("messages_ready", 0)
276
294
  global_stats["unacked"] += info.get("messages_unacknowledged", 0)
277
295
  global_stats["consumers"] += info.get("consumers", 0)
296
+ if "requests" in q:
297
+ global_stats["requests"] += info.get("messages", 0)
298
+ elif "responses" in q or "response" in q:
299
+ global_stats["responses"] += info.get("messages", 0)
300
+ elif "failed" in q:
301
+ global_stats["failed"] += info.get("messages", 0)
278
302
 
279
303
  except Exception as e:
280
304
  error_msg = str(e)
@@ -288,18 +312,33 @@ if error_msg:
288
312
 
289
313
  # 1. Global Overview Row
290
314
  st.markdown(f"### {DASHBOARD_ICON} System Overview")
291
- kpi1, kpi2, kpi3, kpi4 = st.columns(4)
315
+ kpi1, kpi2, kpi3, kpi4, kpi5, kpi6 = st.columns(6)
292
316
  kpi1.metric(
293
317
  "Total Backlog", global_stats["total"], help="Total messages in all selected queues"
294
318
  )
295
- kpi2.metric("Ready to Process", global_stats["ready"], delta_color="normal")
319
+ kpi2.metric(
320
+ "Requests",
321
+ global_stats["requests"],
322
+ help="Messages in bertrend_requests queue",
323
+ )
296
324
  kpi3.metric(
325
+ "Responses",
326
+ global_stats["responses"],
327
+ help="Messages in bertrend_responses queue",
328
+ )
329
+ kpi4.metric(
330
+ "Failed",
331
+ global_stats["failed"],
332
+ delta_color="inverse",
333
+ help="Messages in bertrend_failed queue",
334
+ )
335
+ kpi5.metric(
297
336
  "Unacknowledged",
298
337
  global_stats["unacked"],
299
338
  delta_color="inverse",
300
339
  help="Messages currently being processed but not acked",
301
340
  )
302
- kpi4.metric("Active Consumers", global_stats["consumers"])
341
+ kpi6.metric("Active Consumers", global_stats["consumers"])
303
342
 
304
343
  st.divider()
305
344
 
@@ -327,6 +366,108 @@ else:
327
366
 
328
367
  st.divider()
329
368
 
369
+ # B. Unacknowledged Messages Details
370
+ unacked_count = info.get("messages_unacknowledged", 0)
371
+ with st.expander(
372
+ f"Unacknowledged Messages ({unacked_count})",
373
+ expanded=unacked_count > 0,
374
+ ):
375
+ if unacked_count == 0:
376
+ st.info("No unacknowledged messages in this queue.", icon=INFO_ICON)
377
+ else:
378
+ try:
379
+ all_consumers = client.get_consumers()
380
+ all_channels = client.get_channels()
381
+
382
+ # Filter consumers for this queue
383
+ queue_consumers = [
384
+ c
385
+ for c in all_consumers
386
+ if c.get("queue", {}).get("name") == qname
387
+ ]
388
+
389
+ # Build a map of channel_name -> channel details
390
+ channel_map = {ch.get("name"): ch for ch in all_channels}
391
+
392
+ if not queue_consumers:
393
+ st.warning(
394
+ "Unacknowledged messages exist but no active consumers found. "
395
+ "Messages may be held by a disconnected consumer."
396
+ )
397
+ else:
398
+ st.caption(
399
+ f"{len(queue_consumers)} consumer(s) holding unacknowledged messages:"
400
+ )
401
+ for cons in queue_consumers:
402
+ ch_name = cons.get("channel_details", {}).get(
403
+ "name", ""
404
+ )
405
+ ch = channel_map.get(ch_name, {})
406
+ ch_unacked = ch.get("messages_unacknowledged", 0)
407
+ consumer_tag = cons.get("consumer_tag", "unknown")
408
+ peer_host = cons.get("channel_details", {}).get(
409
+ "peer_host", "?"
410
+ )
411
+ peer_port = cons.get("channel_details", {}).get(
412
+ "peer_port", ""
413
+ )
414
+ prefetch = cons.get("prefetch_count", 0)
415
+ ack_required = cons.get("ack_required", True)
416
+
417
+ with st.container(border=True):
418
+ cc1, cc2, cc3, cc4 = st.columns(4)
419
+ cc1.metric("Unacked (channel)", ch_unacked)
420
+ cc2.markdown(f"**Consumer Tag**\n`{consumer_tag}`")
421
+ cc3.markdown(
422
+ f"**Client**\n`{peer_host}:{peer_port}`"
423
+ )
424
+ cc4.markdown(
425
+ f"**Prefetch / Ack required**\n`{prefetch}` / `{ack_required}`"
426
+ )
427
+
428
+ # Channel-level stats
429
+ ch_stats = ch.get("message_stats", {})
430
+ ack_rate = (
431
+ ch_stats.get("ack_details", {}).get("rate", 0.0)
432
+ if ch_stats
433
+ else 0.0
434
+ )
435
+ deliver_rate = (
436
+ ch_stats.get("deliver_details", {}).get(
437
+ "rate", 0.0
438
+ )
439
+ if ch_stats
440
+ else 0.0
441
+ )
442
+ total_acked = (
443
+ ch_stats.get("ack", 0) if ch_stats else 0
444
+ )
445
+ total_delivered = (
446
+ ch_stats.get("deliver", 0) if ch_stats else 0
447
+ )
448
+
449
+ sc1, sc2, sc3, sc4 = st.columns(4)
450
+ sc1.metric("Ack Rate", f"{ack_rate:.2f}/s")
451
+ sc2.metric("Deliver Rate", f"{deliver_rate:.2f}/s")
452
+ sc3.metric("Total Acked", total_acked)
453
+ sc4.metric("Total Delivered", total_delivered)
454
+
455
+ # Connection info
456
+ conn = ch.get("connection_details", {})
457
+ if conn:
458
+ st.caption(
459
+ f"Connection: `{conn.get('name', ch_name)}` "
460
+ f"— state: `{ch.get('state', '?')}`"
461
+ )
462
+
463
+ except Exception as e:
464
+ st.error(
465
+ f"Failed to fetch consumer/channel details: {e}",
466
+ icon=ERROR_ICON,
467
+ )
468
+
469
+ st.divider()
470
+
330
471
  # B. Message Peeking Interface
331
472
  c_head, c_peek_n, c_sort = st.columns([3, 1, 1])
332
473
  c_head.subheader("Message Browser")
@@ -546,6 +687,7 @@ else:
546
687
  obj = d["obj"]
547
688
 
548
689
  props = m.get("properties", {})
690
+ headers = props.get("headers") or {}
549
691
  corr_id = props.get("correlation_id", "No-ID")
550
692
  msg_size = (
551
693
  m.get("payload_bytes", 0)
@@ -562,6 +704,9 @@ else:
562
704
  info_tags.append(f"User: {d['user']}")
563
705
  if d["model_id"]:
564
706
  info_tags.append(f"Model: {d['model_id']}")
707
+ retry_count = headers.get("x-retry-count")
708
+ if retry_count is not None:
709
+ info_tags.append(f"Retry: {retry_count}")
565
710
 
566
711
  info_str = f" | {' | '.join(info_tags)}" if info_tags else ""
567
712
  label = f"#{idx + 1} | {fmt} | CID: {corr_id}{info_str} | {msg_size} bytes"
@@ -617,6 +762,12 @@ else:
617
762
  "Key": "App ID",
618
763
  "Val": str(props.get("app_id") or ""),
619
764
  },
765
+ {
766
+ "Key": "x-retry-count",
767
+ "Val": str(headers.get("x-retry-count"))
768
+ if headers.get("x-retry-count") is not None
769
+ else "",
770
+ },
620
771
  ]
621
772
  ).dropna()
622
773
  st.dataframe(meta_df, hide_index=True, width="stretch")
@@ -0,0 +1,3 @@
1
+ host = "0.0.0.0"
2
+ port = 8887
3
+ number_workers = 1
@@ -0,0 +1,32 @@
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 os
7
+ import tomllib
8
+ from pathlib import Path
9
+
10
+ from pydantic_settings import BaseSettings
11
+
12
+ DEFAULT_CONFIG_FILE = Path(__file__).parent / "default_config.toml"
13
+
14
+
15
+ class ArticleScoringAPIConfig(BaseSettings):
16
+ host: str
17
+ port: int
18
+ number_workers: int
19
+
20
+
21
+ def get_config() -> ArticleScoringAPIConfig:
22
+ """
23
+ Return the configuration for the summary API.
24
+ The configuration is loaded from a toml file.
25
+ The path to the toml file can be specified using the environment variable `SUMMARY_API_CONFIG_FILE`.
26
+ If the environment variable is not set, the default configuration file is used.
27
+ """
28
+ config_file = os.environ.get("ARTICLE_SCORING_API_CONFIG_FILE", None)
29
+ if config_file is None:
30
+ config_file = DEFAULT_CONFIG_FILE
31
+ with open(config_file, "rb") as f:
32
+ return ArticleScoringAPIConfig(**tomllib.load(f))
@@ -0,0 +1,21 @@
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
+ from pydantic import BaseModel
7
+
8
+
9
+ class ScoreArticlesRequest(BaseModel):
10
+ articles: list[str]
11
+
12
+
13
+ class ScoredArticle(BaseModel):
14
+ article_index: int
15
+ quality_metrics: dict | None = None
16
+ overall_quality: str | None = None
17
+ error: str | None = None
18
+
19
+
20
+ class ScoreArticlesResponse(BaseModel):
21
+ results: list[ScoredArticle]
@@ -0,0 +1,19 @@
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
+ from fastapi import APIRouter
7
+ from starlette.responses import RedirectResponse
8
+
9
+ router = APIRouter()
10
+
11
+
12
+ @router.get("/health")
13
+ def health():
14
+ return {"status": "ok"}
15
+
16
+
17
+ @router.get("/", summary="Redirect to API documentation")
18
+ def root():
19
+ return RedirectResponse(url="/docs")
@@ -0,0 +1,43 @@
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
+ from fastapi import APIRouter, HTTPException
7
+
8
+ from bertrend.article_scoring.scoring_agent import score_articles
9
+ from bertrend.services.article_scoring_server.models import (
10
+ ScoreArticlesRequest,
11
+ ScoreArticlesResponse,
12
+ ScoredArticle,
13
+ )
14
+
15
+ router = APIRouter()
16
+
17
+
18
+ @router.post("/score", response_model=ScoreArticlesResponse)
19
+ async def score(request: ScoreArticlesRequest):
20
+ try:
21
+ score_results = await score_articles(request.articles)
22
+ except Exception as e:
23
+ raise HTTPException(
24
+ status_code=500,
25
+ detail=f"Failed to score articles: {e}",
26
+ ) from e
27
+
28
+ results = []
29
+ for index, item in enumerate(score_results):
30
+ quality_metrics = item.output.serialize_model() if item.output else None
31
+ overall_quality = (
32
+ item.output.quality_level.name if item.output and not item.error else None
33
+ )
34
+ results.append(
35
+ ScoredArticle(
36
+ article_index=index,
37
+ quality_metrics=quality_metrics,
38
+ overall_quality=overall_quality,
39
+ error=item.error,
40
+ )
41
+ )
42
+
43
+ return ScoreArticlesResponse(results=results)