bertrend 0.3.22__tar.gz → 0.3.24__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 (290) hide show
  1. {bertrend-0.3.22 → bertrend-0.3.24}/PKG-INFO +19 -15
  2. {bertrend-0.3.22 → bertrend-0.3.24}/README.md +15 -11
  3. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/BERTopicModel.py +3 -3
  4. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/BERTrend.py +1 -1
  5. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/article_scoring/scoring_agent.py +0 -1
  6. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/demos_utils/data_loading_component.py +1 -1
  7. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/streamlit_components/clickable_df_component.py +3 -1
  8. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/topic_analysis/demo_pages/explore_topics.py +1 -1
  9. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/llm_utils/newsletter_features.py +3 -2
  10. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/llm_utils/openai_client.py +1 -6
  11. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/metrics/temporal_metrics_embedding.py +3 -5
  12. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/authentication.py +24 -23
  13. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_client.py +42 -36
  14. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/routers/authentication.py +1 -1
  15. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/start.py +6 -3
  16. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/status.py +6 -6
  17. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_service.py +11 -9
  18. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/scheduling/docker-compose.yml +0 -1
  19. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/scheduling/job_utils/job_functions.py +10 -11
  20. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/scheduling/routers/scheduling.py +11 -6
  21. bertrend-0.3.24/bertrend/tests/apps/test_lazy_scheduler.py +72 -0
  22. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/apps/test_models.py +5 -24
  23. bertrend-0.3.24/bertrend/tests/apps/test_multiworker.py +58 -0
  24. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/apps/test_process_new_data.py +3 -3
  25. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/core/test_bertrend.py +6 -5
  26. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/core/test_temporal_metrics_embedding.py +0 -2
  27. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/core/test_topic_metrics.py +0 -3
  28. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/llm/test_agent_utils.py +5 -2
  29. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/services/embedding/test_embedding_client.py +7 -0
  30. bertrend-0.3.24/bertrend/tests/services/scheduling/test_job_exception_fix.py +74 -0
  31. bertrend-0.3.24/bertrend/tests/services/scheduling/test_stress_test.py +311 -0
  32. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/services/summarizer/test_abstractive_summarizer.py +0 -2
  33. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/services/summarizer/test_extractive_summarizer.py +0 -2
  34. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/test_integration.py +5 -5
  35. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/utils/test_apscheduler_utils.py +26 -43
  36. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/utils/test_crontab_utils.py +1 -3
  37. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/topic_analysis/visualizations.py +1 -1
  38. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/utils/data_loading.py +7 -1
  39. bertrend-0.3.24/bertrend_apps/__init__.py +43 -0
  40. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/common/apscheduler_utils.py +169 -58
  41. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/common/crontab_utils.py +16 -4
  42. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/common/scheduler_utils.py +16 -20
  43. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/data_provider/arxiv_provider.py +3 -3
  44. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/data_provider/data_provider.py +22 -6
  45. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/data_provider/newscatcher_provider.py +8 -4
  46. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/data_provider/utils.py +6 -7
  47. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/curebot/app_utils.py +3 -2
  48. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/geolocalization/spacy/dbpedia.py +5 -6
  49. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/newsletters/__main__.py +1 -2
  50. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/newsletters/newsletter_generation.py +2 -1
  51. bertrend-0.3.24/bertrend_apps/prospective_demo/.streamlit/secrets.toml.example +9 -0
  52. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/app.py +29 -2
  53. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/authentication.py +8 -0
  54. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/automated_report_generation.py +25 -14
  55. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/dashboard_analysis.py +14 -8
  56. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/dashboard_signals.py +1 -1
  57. bertrend-0.3.24/bertrend_apps/prospective_demo/docs/architecture.md +82 -0
  58. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/feeds_config.py +21 -7
  59. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/i18n_translations.py +8 -0
  60. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/models_info.py +27 -17
  61. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/process_new_data.py +8 -0
  62. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/report_generation.py +11 -4
  63. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/report_generation_utils.py +0 -1
  64. bertrend-0.3.24/bertrend_apps/services/config/default_config.toml +3 -0
  65. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/config/settings.py +0 -1
  66. bertrend-0.3.24/bertrend_apps/services/models/newsletters_models.py +16 -0
  67. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/routers/bertrend_app.py +2 -2
  68. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/routers/data_provider.py +1 -2
  69. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/routers/newsletters.py +20 -16
  70. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/start.py +2 -6
  71. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/status.py +6 -6
  72. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/utils/logging_utils.py +4 -0
  73. {bertrend-0.3.22 → bertrend-0.3.24}/pyproject.toml +5 -5
  74. bertrend-0.3.22/bertrend_apps/__init__.py +0 -36
  75. bertrend-0.3.22/bertrend_apps/config/newsletters/decarbonation_newsletter_from_scratch.toml +0 -38
  76. bertrend-0.3.22/bertrend_apps/config/newsletters/rte_newsletter_from_scratch.toml +0 -38
  77. bertrend-0.3.22/bertrend_apps/prospective_demo/.streamlit/secrets.toml +0 -14
  78. bertrend-0.3.22/bertrend_apps/services/config/default_config.toml +0 -4
  79. bertrend-0.3.22/bertrend_apps/services/models/newsletters_models.py +0 -34
  80. {bertrend-0.3.22 → bertrend-0.3.24}/AUTHORS.txt +0 -0
  81. {bertrend-0.3.22 → bertrend-0.3.24}/LICENSE.md +0 -0
  82. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/__init__.py +0 -0
  83. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/article_scoring/__init__.py +0 -0
  84. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/article_scoring/article_scoring.py +0 -0
  85. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/article_scoring/prompts.py +0 -0
  86. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/config/bertopic_default_config.toml +0 -0
  87. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/config/bertrend_default_config.toml +0 -0
  88. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/config/parameters.py +0 -0
  89. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/config/services_default_config.toml +0 -0
  90. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/__init__.py +0 -0
  91. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/demos_utils/__init__.py +0 -0
  92. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/demos_utils/embed_documents_component.py +0 -0
  93. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/demos_utils/i18n.py +0 -0
  94. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/demos_utils/i18n_translations.py +0 -0
  95. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/demos_utils/icons.py +0 -0
  96. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/demos_utils/parameters_component.py +0 -0
  97. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/demos_utils/state_utils.py +0 -0
  98. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/start_summarizer_app.sh +0 -0
  99. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/start_topic_analysis_app.sh +0 -0
  100. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/start_weak_signals_app.sh +0 -0
  101. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/streamlit_components/__init__.py +0 -0
  102. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/streamlit_components/input_with_pills_component.py +0 -0
  103. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/summarization/__init__.py +0 -0
  104. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/summarization/summarizer_app.py +0 -0
  105. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/topic_analysis/.streamlit/config.toml +0 -0
  106. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/topic_analysis/__init__.py +0 -0
  107. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/topic_analysis/app.py +0 -0
  108. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/topic_analysis/app_utils.py +0 -0
  109. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/topic_analysis/demo_pages/__init__.py +0 -0
  110. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/topic_analysis/demo_pages/newsletters_generation.py +0 -0
  111. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/topic_analysis/demo_pages/temporal_visualizations.py +0 -0
  112. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/topic_analysis/demo_pages/topic_visualizations.py +0 -0
  113. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/topic_analysis/demo_pages/training_page.py +0 -0
  114. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/topic_analysis/i18n_translations.py +0 -0
  115. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/weak_signals/.streamlit/config.toml +0 -0
  116. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/weak_signals/__init__.py +0 -0
  117. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/weak_signals/app.py +0 -0
  118. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/weak_signals/i18n_translations.py +0 -0
  119. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/demos/weak_signals/visualizations_utils.py +0 -0
  120. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/llm_utils/__init__.py +0 -0
  121. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/llm_utils/agent_utils.py +0 -0
  122. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/llm_utils/newsletter.css +0 -0
  123. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/llm_utils/newsletter_model.py +0 -0
  124. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/llm_utils/newsletter_outlook_template.html +0 -0
  125. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/llm_utils/newsletter_template.html +0 -0
  126. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/llm_utils/prompts.py +0 -0
  127. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/metrics/__init__.py +0 -0
  128. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/metrics/topic_metrics.py +0 -0
  129. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/resources/common_ngrams.json +0 -0
  130. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/resources/stopwords-en.json +0 -0
  131. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/resources/stopwords-fr.json +0 -0
  132. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/resources/stopwords-rte.json +0 -0
  133. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/__init__.py +0 -0
  134. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/cert.pem +0 -0
  135. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/README.md +0 -0
  136. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/__init__.py +0 -0
  137. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/bertrend_client_registry.json +0 -0
  138. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/config/default_config.toml +0 -0
  139. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/config/settings.py +0 -0
  140. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/main.py +0 -0
  141. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/models.py +0 -0
  142. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/requirements.txt +0 -0
  143. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/routers/__init__.py +0 -0
  144. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/routers/embeddings.py +0 -0
  145. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/routers/info.py +0 -0
  146. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/security.py +0 -0
  147. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/embedding_server/stop.py +0 -0
  148. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/key.pem +0 -0
  149. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/scheduling/.dockerignore +0 -0
  150. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/scheduling/Docker_setup.md +0 -0
  151. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/scheduling/Dockerfile +0 -0
  152. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/scheduling/__init__.py +0 -0
  153. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/scheduling/dashboard.html +0 -0
  154. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/scheduling/job_utils/__init__.py +0 -0
  155. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/scheduling/models/__init__.py +0 -0
  156. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/scheduling/models/scheduling_models.py +0 -0
  157. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/scheduling/requirements.txt +0 -0
  158. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/scheduling/routers/info.py +0 -0
  159. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/scheduling/scheduling_service.py +0 -0
  160. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/summarizer.py +0 -0
  161. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/summary/__init__.py +0 -0
  162. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/summary/abstractive_summarizer.py +0 -0
  163. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/summary/chatgpt_summarizer.py +0 -0
  164. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/summary/extractive_summarizer.py +0 -0
  165. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/summary/lexrank.py +0 -0
  166. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/services/summary/prompts.py +0 -0
  167. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/README_integration_tests.md +0 -0
  168. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/__init__.py +0 -0
  169. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/apps/__init__.py +0 -0
  170. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/apps/test_bertrend_service.py +0 -0
  171. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/apps/test_routers_bertrend_app.py +0 -0
  172. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/apps/test_routers_info.py +0 -0
  173. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/conftest.py +0 -0
  174. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/core/__init__.py +0 -0
  175. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/core/test_data_structure.py +0 -0
  176. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/core/test_representative_docs.py +0 -0
  177. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/core/test_topic_description.py +0 -0
  178. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/core/test_topic_model.py +0 -0
  179. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/core/test_trend_analysis_data_structure.py +0 -0
  180. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/core/test_trend_analysis_prompts.py +0 -0
  181. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/core/test_trend_analysis_visualizations.py +0 -0
  182. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/core/test_trend_analysis_weak_signals.py +0 -0
  183. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/core/test_visualizations.py +0 -0
  184. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/llm/__init__.py +0 -0
  185. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/llm/test_article_scoring.py +0 -0
  186. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/llm/test_article_scoring_models.py +0 -0
  187. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/llm/test_newsletter_features.py +0 -0
  188. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/llm/test_newsletter_model.py +0 -0
  189. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/llm/test_openai_client.py +0 -0
  190. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/services/__init__.py +0 -0
  191. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/services/embedding/__init__.py +0 -0
  192. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/services/scheduling/__init__.py +0 -0
  193. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/services/scheduling/test_scheduling_service.py +0 -0
  194. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/services/summarizer/__init__.py +0 -0
  195. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/services/summarizer/test_chatgpt_summarizer.py +0 -0
  196. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/services/summarizer/test_summarizer.py +0 -0
  197. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/test_installation.py +0 -0
  198. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/utils/__init__.py +0 -0
  199. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/utils/test_cache_utils.py +0 -0
  200. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/utils/test_config_utils.py +0 -0
  201. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/utils/test_data_loading.py +0 -0
  202. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/utils/test_date_utils.py +0 -0
  203. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/utils/test_mail_utils.py +0 -0
  204. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/utils/test_scheduler_utils.py +0 -0
  205. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/tests/utils/test_utils_init.py +0 -0
  206. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/topic_analysis/__init__.py +0 -0
  207. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/topic_analysis/data_structure.py +0 -0
  208. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/topic_analysis/prompts.py +0 -0
  209. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/topic_analysis/representative_docs.py +0 -0
  210. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/topic_analysis/topic_description.py +0 -0
  211. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/trend_analysis/__init__.py +0 -0
  212. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/trend_analysis/data_structure.py +0 -0
  213. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/trend_analysis/prompts.py +0 -0
  214. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/trend_analysis/signal_llm_template_en.html +0 -0
  215. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/trend_analysis/signal_llm_template_fr.html +0 -0
  216. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/trend_analysis/visualizations.py +0 -0
  217. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/trend_analysis/weak_signals.py +0 -0
  218. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/utils/__init__.py +0 -0
  219. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/utils/cache_utils.py +0 -0
  220. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend/utils/config_utils.py +0 -0
  221. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/common/__init__.py +0 -0
  222. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/common/date_utils.py +0 -0
  223. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/common/mail_utils.py +0 -0
  224. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/config/feeds/arxiv_feed.toml +0 -0
  225. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/config/feeds/decarbonation_feed.toml +0 -0
  226. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/config/feeds/llm_en_feed.toml +0 -0
  227. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/config/feeds/llm_feed.toml +0 -0
  228. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/config/feeds/nlp_feed.toml +0 -0
  229. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/config/feeds/rte_feed.toml +0 -0
  230. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/config/newsletters/arxiv_newsletter_from_last.toml +0 -0
  231. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/config/newsletters/decarbonation_newsletter_from_last.toml +0 -0
  232. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/config/newsletters/llm_en_newsletter_from_last.toml +0 -0
  233. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/config/newsletters/llm_newsletter_from_last.toml +0 -0
  234. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/config/newsletters/nlp_newsletter_from_last.toml +0 -0
  235. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/config/newsletters/rte_newsletter_from_last.toml +0 -0
  236. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/data_provider/__init__.py +0 -0
  237. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/data_provider/__main__.py +0 -0
  238. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/data_provider/atom_feed_provider.py +0 -0
  239. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/data_provider/bing_news_provider.py +0 -0
  240. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/data_provider/data_provider_utils.py +0 -0
  241. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/data_provider/google_news_provider.py +0 -0
  242. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/data_provider/rss_feed_provider.py +0 -0
  243. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/__init__.py +0 -0
  244. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/curebot/.streamlit/config.toml +0 -0
  245. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/curebot/__init__.py +0 -0
  246. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/curebot/app.py +0 -0
  247. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/curebot/config.toml +0 -0
  248. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/curebot/import_extraction_article.ipynb +0 -0
  249. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/curebot/prompts.py +0 -0
  250. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/curebot/start_newsletter_generator.sh +0 -0
  251. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/curebot/tabs/tab1.py +0 -0
  252. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/curebot/tabs/tab2.py +0 -0
  253. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/curebot/tabs/tab3.py +0 -0
  254. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/dataviz/Main_page.py +0 -0
  255. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/dataviz/__init__.py +0 -0
  256. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/dataviz/pages/1_Data_feeds.py +0 -0
  257. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/geolocalization/__init__.py +0 -0
  258. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/geolocalization/entity_utils.py +0 -0
  259. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/geolocalization/spacy/__init__.py +0 -0
  260. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/geolocalization/spacy/common_factory.py +0 -0
  261. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/geolocalization/spacy/nlp.config +0 -0
  262. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/geolocalization/spacy/utils.py +0 -0
  263. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/start_apps.sh +0 -0
  264. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/exploration/stop_apps.sh +0 -0
  265. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/install_feeds_and_newsletters.py +0 -0
  266. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/newsletters/__init__.py +0 -0
  267. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/newsletters/utils.py +0 -0
  268. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/.streamlit/config.toml +0 -0
  269. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/__init__.py +0 -0
  270. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/dashboard_common.py +0 -0
  271. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/dashboard_comparative.py +0 -0
  272. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/data_model.py +0 -0
  273. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/detailed_report_template.html +0 -0
  274. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/docs/automated_report_generation.md +0 -0
  275. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/feeds_common.py +0 -0
  276. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/feeds_data.py +0 -0
  277. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/i18n.py +0 -0
  278. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/llm_utils.py +0 -0
  279. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/perf_utils.py +0 -0
  280. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/start_demo.sh +0 -0
  281. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/prospective_demo/utils.py +0 -0
  282. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/__init__.py +0 -0
  283. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/bertrend_service.py +0 -0
  284. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/models/__init__.py +0 -0
  285. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/models/bertrend_app_models.py +0 -0
  286. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/models/data_provider_models.py +0 -0
  287. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/routers/__init__.py +0 -0
  288. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/routers/info.py +0 -0
  289. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/stop.py +0 -0
  290. {bertrend-0.3.22 → bertrend-0.3.24}/bertrend_apps/services/utils/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bertrend
3
- Version: 0.3.22
3
+ Version: 0.3.24
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
@@ -42,7 +42,7 @@ Requires-Dist: langdetect (>=1.0.9)
42
42
  Requires-Dist: loguru (>=0.7.3)
43
43
  Requires-Dist: lxml-html-clean (>=0.2.2)
44
44
  Requires-Dist: markdown (>=3.7)
45
- Requires-Dist: newscatcherapi (>=0.7.3) ; extra == "apps"
45
+ Requires-Dist: newscatcher-sdk (>=1.4.0) ; extra == "apps"
46
46
  Requires-Dist: newspaper4k (>=0.9.3.1) ; extra == "apps"
47
47
  Requires-Dist: nltk (>=3.9.1)
48
48
  Requires-Dist: numpy (<2)
@@ -53,6 +53,7 @@ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc (==1.25.0)
53
53
  Requires-Dist: pandas (>=2.2.2)
54
54
  Requires-Dist: plotly (>=5.24.1)
55
55
  Requires-Dist: plotly-resampler (>=0.10.0)
56
+ Requires-Dist: psutil (>=7.2.1)
56
57
  Requires-Dist: pyarrow (>=21.0.0)
57
58
  Requires-Dist: pygooglenews (>=0.1.3) ; extra == "apps"
58
59
  Requires-Dist: pylabeladjust (==0.1.13)
@@ -60,8 +61,8 @@ Requires-Dist: pytest (>=8.4.0)
60
61
  Requires-Dist: pytest-asyncio
61
62
  Requires-Dist: python-dotenv (>=1.1.1)
62
63
  Requires-Dist: requests (>=2.32.3)
64
+ Requires-Dist: ruff (>=0.14.14)
63
65
  Requires-Dist: scikit-learn (>=1.5.2)
64
- Requires-Dist: scipy (==1.12)
65
66
  Requires-Dist: seaborn (>=0.13.2)
66
67
  Requires-Dist: sentence-transformers (==3.0.1)
67
68
  Requires-Dist: sentencepiece (>=0.2.0)
@@ -72,7 +73,6 @@ Requires-Dist: supervisor (>=4.3.0)
72
73
  Requires-Dist: thefuzz (>=0.22.1)
73
74
  Requires-Dist: tiktoken (>=0.8.0)
74
75
  Requires-Dist: tldextract (>=2.0.1)
75
- Requires-Dist: tokenizers (<0.20.0)
76
76
  Requires-Dist: torch (>=2.7.0)
77
77
  Requires-Dist: tqdm (>=4.67.1)
78
78
  Requires-Dist: typer (>=0.16.0)
@@ -94,6 +94,11 @@ Description-Content-Type: text/markdown
94
94
  ![Static Badge](https://img.shields.io/badge/python-%3E%3D3.12-blue)
95
95
  ![GitHub License](https://img.shields.io/github/license/rte-france/BERTrend)
96
96
 
97
+ ## News
98
+ 2025-11-24: BERTrend has been integrated into the [Netminer 5](https://netminer.gitbook.io/netminer5/module-reference/text/bertopic/bertrend) data analysis tool !
99
+
100
+ ## Overview
101
+
97
102
  ![BERTrend pipeline](./BERTrend_overview.png)
98
103
 
99
104
  ## Paper
@@ -174,11 +179,10 @@ Recommended steps:
174
179
  - Misc: `CUDA_VISIBLE_DEVICES`
175
180
  2. Use a virtual environment and install dependencies inside it:
176
181
  ```bash
177
- python -m venv .venv
182
+ uv venv --python 3.13
178
183
  source .venv/bin/activate # Windows: .venv\\Scripts\\activate
179
- pip install -U pip
180
- pip install . # or pip install ".[apps]"
181
- pip install python-dotenv # ensures .env is auto-loaded
184
+ uv pip install . # or uv pip install .[apps]
185
+ uv pip install python-dotenv # ensures .env is auto-loaded
182
186
  ```
183
187
  3. Notes
184
188
  - If `python-dotenv` isn’t installed, `.env` won’t be auto-loaded; you can either install it or export variables via your shell/runner.
@@ -188,7 +192,7 @@ Recommended steps:
188
192
  ### Hardware and Software Requirements
189
193
 
190
194
  - Recommended: at least one GPU with 16GB RAM for faster processing
191
- - Python >= 3.12 is required
195
+ - Python >= 3.13 is required
192
196
 
193
197
  ### Docker Installation
194
198
 
@@ -198,28 +202,28 @@ For detailed instructions on using BERTrend with Docker, see the [Docker documen
198
202
 
199
203
  ### Package Installation
200
204
 
201
- - (Recommended): create a new python environment using `venv` or `conda`:
205
+ - (Recommended): create a new python environment using `uv`:
202
206
 
203
- `python -m venv <path>/bertrend`
207
+ `uv venv --python 3.13`
204
208
 
205
209
 
206
210
  - Installation from pypi
207
211
 
208
- `pip install bertrend`
212
+ `uv pip install bertrend`
209
213
 
210
214
 
211
215
  - Install using pip or poetry in the BERTrend home directory:
212
216
 
213
217
  ```bash
214
218
  # Basic installation with core dependencies
215
- pip install . # or poetry install
219
+ uv pip install .
216
220
 
217
221
  # Installation with apps dependencies
218
- pip install ".[apps]" # or poetry install --extras apps
222
+ uv pip install .[apps]
219
223
 
220
224
  ```
221
225
 
222
- - (Use `pip install -e .` for a local installation)
226
+ - (Use `uv pip install -e .` for a local installation)
223
227
 
224
228
  NB. Due to the number of dependencies, the installation may take some time on an empty environment.
225
229
 
@@ -9,6 +9,11 @@
9
9
  ![Static Badge](https://img.shields.io/badge/python-%3E%3D3.12-blue)
10
10
  ![GitHub License](https://img.shields.io/github/license/rte-france/BERTrend)
11
11
 
12
+ ## News
13
+ 2025-11-24: BERTrend has been integrated into the [Netminer 5](https://netminer.gitbook.io/netminer5/module-reference/text/bertopic/bertrend) data analysis tool !
14
+
15
+ ## Overview
16
+
12
17
  ![BERTrend pipeline](./BERTrend_overview.png)
13
18
 
14
19
  ## Paper
@@ -89,11 +94,10 @@ Recommended steps:
89
94
  - Misc: `CUDA_VISIBLE_DEVICES`
90
95
  2. Use a virtual environment and install dependencies inside it:
91
96
  ```bash
92
- python -m venv .venv
97
+ uv venv --python 3.13
93
98
  source .venv/bin/activate # Windows: .venv\\Scripts\\activate
94
- pip install -U pip
95
- pip install . # or pip install ".[apps]"
96
- pip install python-dotenv # ensures .env is auto-loaded
99
+ uv pip install . # or uv pip install .[apps]
100
+ uv pip install python-dotenv # ensures .env is auto-loaded
97
101
  ```
98
102
  3. Notes
99
103
  - If `python-dotenv` isn’t installed, `.env` won’t be auto-loaded; you can either install it or export variables via your shell/runner.
@@ -103,7 +107,7 @@ Recommended steps:
103
107
  ### Hardware and Software Requirements
104
108
 
105
109
  - Recommended: at least one GPU with 16GB RAM for faster processing
106
- - Python >= 3.12 is required
110
+ - Python >= 3.13 is required
107
111
 
108
112
  ### Docker Installation
109
113
 
@@ -113,28 +117,28 @@ For detailed instructions on using BERTrend with Docker, see the [Docker documen
113
117
 
114
118
  ### Package Installation
115
119
 
116
- - (Recommended): create a new python environment using `venv` or `conda`:
120
+ - (Recommended): create a new python environment using `uv`:
117
121
 
118
- `python -m venv <path>/bertrend`
122
+ `uv venv --python 3.13`
119
123
 
120
124
 
121
125
  - Installation from pypi
122
126
 
123
- `pip install bertrend`
127
+ `uv pip install bertrend`
124
128
 
125
129
 
126
130
  - Install using pip or poetry in the BERTrend home directory:
127
131
 
128
132
  ```bash
129
133
  # Basic installation with core dependencies
130
- pip install . # or poetry install
134
+ uv pip install .
131
135
 
132
136
  # Installation with apps dependencies
133
- pip install ".[apps]" # or poetry install --extras apps
137
+ uv pip install .[apps]
134
138
 
135
139
  ```
136
140
 
137
- - (Use `pip install -e .` for a local installation)
141
+ - (Use `uv pip install -e .` for a local installation)
138
142
 
139
143
  NB. Due to the number of dependencies, the installation may take some time on an empty environment.
140
144
 
@@ -257,9 +257,9 @@ class BERTopicModel:
257
257
  if zeroshot_topic_list:
258
258
  self.config["bertopic_model"]["zeroshot_topic_list"] = zeroshot_topic_list
259
259
  if zeroshot_min_similarity is not None:
260
- self.config["bertopic_model"][
261
- "zeroshot_min_similarity"
262
- ] = zeroshot_min_similarity
260
+ self.config["bertopic_model"]["zeroshot_min_similarity"] = (
261
+ zeroshot_min_similarity
262
+ )
263
263
  # Load and fit model
264
264
  try:
265
265
  logger.debug("\tInitializing BERTopic model")
@@ -287,7 +287,7 @@ class BERTrend:
287
287
 
288
288
  for i, (period, group) in enumerate(non_empty_groups):
289
289
  try:
290
- logger.info(f"Training topic model {i+1}/{len(non_empty_groups)}...")
290
+ logger.info(f"Training topic model {i + 1}/{len(non_empty_groups)}...")
291
291
  (
292
292
  new_topic_model,
293
293
  self.doc_groups[period],
@@ -37,7 +37,6 @@ async def score_articles(articles: list[str]):
37
37
 
38
38
 
39
39
  if __name__ == "__main__":
40
-
41
40
  path = Path("/DSIA/nlp/bertrend/data/feeds/feed_nlp/2025-01-07_feed_nlp.jsonl")
42
41
  df = load_data(path)
43
42
  print(len(df), df.columns)
@@ -55,7 +55,7 @@ FORMAT_ICONS = {
55
55
 
56
56
  @st.dialog(translate("column_selection"))
57
57
  def _select_alternative_columns(df: pd.DataFrame, message: str = ""):
58
- st.warning(message, icon=WARNING_ICON),
58
+ (st.warning(message, icon=WARNING_ICON),)
59
59
  if TEXT_COLUMN not in df.columns:
60
60
  text_column = st.selectbox(
61
61
  label=translate("text_column_selection"), options=df.columns
@@ -8,6 +8,8 @@ from typing import Callable
8
8
  import pandas as pd
9
9
  import streamlit as st
10
10
 
11
+ from bertrend_apps.prospective_demo.i18n import translate
12
+
11
13
 
12
14
  def clickable_df(
13
15
  df: pd.DataFrame, clickable_buttons: list[tuple[str | Callable, Callable, str]]
@@ -18,7 +20,7 @@ def clickable_df(
18
20
  cols = st.columns(len(df.columns) * [3] + len(clickable_buttons) * [1])
19
21
  for i, c in enumerate(df.columns):
20
22
  with cols[i]:
21
- st.write(f"**{c}**")
23
+ st.write(f"**{translate('col_' + c, default=c)}**")
22
24
  # Generate a unique identifier, this will be used to identify the keys in case multiple clickable_df are used
23
25
  unique_id = zlib.crc32(" ".join(df.columns.tolist()).encode())
24
26
  for index, row in df.iterrows():
@@ -226,7 +226,7 @@ def display_representative_documents(filtered_df: pd.DataFrame):
226
226
  date = doc.timestamp.strftime("%A %d %b %Y %H:%M:%S")
227
227
  snippet = doc.text[:200] + "..." if len(doc.text) > 150 else doc.text
228
228
 
229
- content = f"""**{doc.title}**\n\n{date} | {translate('unknown_source') if website_name == translate('unknown_source') else website_name}\n\n{snippet}"""
229
+ content = f"""**{doc.title}**\n\n{date} | {translate("unknown_source") if website_name == translate("unknown_source") else website_name}\n\n{snippet}"""
230
230
 
231
231
  if website_name != translate("unknown_source"):
232
232
  st.link_button(content, doc.url)
@@ -108,7 +108,6 @@ def generate_newsletter(
108
108
 
109
109
  # Iterate over topics
110
110
  for i in tqdm(range(top_n_topics), desc="Processing topics..."):
111
-
112
111
  topic_keywords = topics_info["Representation"].iloc[i]
113
112
 
114
113
  sub_df = get_most_representative_docs(
@@ -180,7 +179,9 @@ def generate_newsletter(
180
179
  article_summary = (
181
180
  summaries[i]
182
181
  if summary_mode == "document"
183
- else doc.text if summary_mode == "none" else None
182
+ else doc.text
183
+ if summary_mode == "none"
184
+ else None
184
185
  )
185
186
  article_list.append(
186
187
  Article(
@@ -8,17 +8,12 @@ import re
8
8
  from enum import Enum
9
9
  from typing import Type
10
10
 
11
- from dotenv import load_dotenv
12
11
  from openai import OpenAI, AzureOpenAI, Timeout, Stream
13
12
  from loguru import logger
14
13
  from openai.types.chat import ChatCompletion, ChatCompletionChunk
15
14
  from pydantic import BaseModel
16
15
 
17
- # Load environment variables at module import
18
- if load_dotenv(override=True):
19
- logger.info("Loaded .env file")
20
- else:
21
- logger.warning("Failed to load .env file")
16
+ # Note: .env is loaded in bertrend/__init__.py which is imported before this module
22
17
 
23
18
  MAX_ATTEMPTS = 3
24
19
  TIMEOUT = 60.0
@@ -187,9 +187,7 @@ class TempTopic:
187
187
  timestamps = documents["Timestamps"].unique()
188
188
 
189
189
  topics_over_time = [] # Accumulates the final data for each timestamp
190
- document_per_topic_list = (
191
- []
192
- ) # Tracks documents associated with each topic at each timestamp
190
+ document_per_topic_list = [] # Tracks documents associated with each topic at each timestamp
193
191
 
194
192
  previous_c_tf_idf = None
195
193
  previous_topics = None
@@ -437,7 +435,7 @@ class TempTopic:
437
435
  """
438
436
 
439
437
  with open(self.debug_file, "a", encoding="utf-8") as f:
440
- f.write(f"{'#'*50}\n")
438
+ f.write(f"{'#' * 50}\n")
441
439
  f.write(f"Failed match for Topic {topic_id} at Timestamp {timestamp}\n")
442
440
  f.write(f"Phrase to match: '{phrase}'\n")
443
441
  f.write(f"Best match: '{best_match}' with score {best_score}\n\n")
@@ -445,7 +443,7 @@ class TempTopic:
445
443
  for idx, doc in enumerate(token_strings):
446
444
  f.write(f"Document {idx}:\n")
447
445
  f.write(" ".join(doc) + "\n\n")
448
- f.write(f"{'#'*50}\n\n")
446
+ f.write(f"{'#' * 50}\n\n")
449
447
 
450
448
  def _calculate_representation_embeddings(
451
449
  self,
@@ -39,27 +39,28 @@ class SecureAPIClient:
39
39
  def _get_access_token(self, scope: str = None):
40
40
  """Obtain an access token using the client credentials flow"""
41
41
  token_url = f"{self.url}/token"
42
- response = requests.post(
43
- token_url,
44
- data={
45
- "username": self.client_id, # Send client_id as username
46
- "password": self.client_secret, # Send client_secret as password
47
- "scope": scope, # Requesting specific scopes
48
- },
49
- verify=False, # verify=False to avoid problems of certificate not generated by a trusted CA
50
- )
42
+ with (
43
+ requests.post(
44
+ token_url,
45
+ data={
46
+ "username": self.client_id, # Send client_id as username
47
+ "password": self.client_secret, # Send client_secret as password
48
+ "scope": scope, # Requesting specific scopes
49
+ },
50
+ verify=False, # verify=False to avoid problems of certificate not generated by a trusted CA
51
+ ) as response
52
+ ):
53
+ if response.status_code == status.HTTP_200_OK:
54
+ token_data = response.json()
55
+ access_token = token_data["access_token"]
56
+ expires_in = token_data.get(
57
+ "expires_in", 3600
58
+ ) # Default to 1 hour if expires_in is not provided
51
59
 
52
- if response.status_code == status.HTTP_200_OK:
53
- token_data = response.json()
54
- access_token = token_data["access_token"]
55
- expires_in = token_data.get(
56
- "expires_in", 3600
57
- ) # Default to 1 hour if expires_in is not provided
58
-
59
- # Set the token and its expiry time (current time + expires_in)
60
- self.token = access_token
61
- self.token_expiry = time.time() + expires_in
62
- else:
63
- raise Exception(
64
- f"Failed to obtain token: {response.status_code} {response.text}"
65
- )
60
+ # Set the token and its expiry time (current time + expires_in)
61
+ self.token = access_token
62
+ self.token_expiry = time.time() + expires_in
63
+ else:
64
+ raise Exception(
65
+ f"Failed to obtain token: {response.status_code} {response.text}"
66
+ )
@@ -43,33 +43,33 @@ class EmbeddingAPIClient(SecureAPIClient, Embeddings):
43
43
  """
44
44
  Return currently loaded model name in Embedding API.
45
45
  """
46
- response = requests.get(
46
+ with requests.get(
47
47
  self.url + "/model_name",
48
48
  verify=False,
49
- )
50
- if response.status_code == 200:
51
- model_name = response.json()
52
- logger.debug(f"Model name: {model_name}")
53
- return model_name
54
- else:
55
- logger.error(f"Error: {response.status_code}")
56
- raise Exception(f"Error: {response.status_code}")
49
+ ) as response:
50
+ if response.status_code == 200:
51
+ model_name = response.json()
52
+ logger.debug(f"Model name: {model_name}")
53
+ return model_name
54
+ else:
55
+ logger.error(f"Error: {response.status_code}")
56
+ raise Exception(f"Error: {response.status_code}")
57
57
 
58
58
  def get_num_workers(self) -> int:
59
59
  """
60
60
  Return currently loaded number of workers in Embedding API.
61
61
  """
62
- response = requests.get(
62
+ with requests.get(
63
63
  self.url + "/num_workers",
64
64
  verify=False,
65
- )
66
- if response.status_code == 200:
67
- num_workers = response.json()
68
- logger.debug(f"Number of workers: {num_workers}")
69
- return num_workers
70
- else:
71
- logger.error(f"Error: {response.status_code}")
72
- raise Exception(f"Error: {response.status_code}")
65
+ ) as response:
66
+ if response.status_code == 200:
67
+ num_workers = response.json()
68
+ logger.debug(f"Number of workers: {num_workers}")
69
+ return num_workers
70
+ else:
71
+ logger.error(f"Error: {response.status_code}")
72
+ raise Exception(f"Error: {response.status_code}")
73
73
 
74
74
  def embed_query(
75
75
  self, text: str | list[str], show_progress_bar: bool = False
@@ -78,36 +78,36 @@ class EmbeddingAPIClient(SecureAPIClient, Embeddings):
78
78
  text = [text]
79
79
  logger.debug(f"Calling EmbeddingAPI using model: {self.model_name}")
80
80
  logger.debug(f"Computing embeddings...")
81
- response = requests.post(
81
+ with requests.post(
82
82
  self.url + "/encode",
83
83
  data=json.dumps({"text": text, "show_progress_bar": show_progress_bar}),
84
84
  verify=False,
85
85
  headers=self._get_headers(),
86
- )
87
- if response.status_code == 200:
88
- embeddings = np.array(response.json()["embeddings"])
89
- logger.debug(f"Computing embeddings done")
90
- return embeddings.tolist()[0]
91
- else:
92
- logger.error(f"Error: {response.status_code}")
86
+ ) as response:
87
+ if response.status_code == 200:
88
+ embeddings = np.array(response.json()["embeddings"])
89
+ logger.debug(f"Computing embeddings done")
90
+ return embeddings.tolist()[0]
91
+ else:
92
+ logger.error(f"Error: {response.status_code}")
93
93
 
94
94
  def embed_batch(
95
95
  self, texts: list[str], show_progress_bar: bool = True
96
96
  ) -> list[list[float]]:
97
97
  logger.debug(f"Computing embeddings...")
98
- response = requests.post(
98
+ with requests.post(
99
99
  self.url + "/encode",
100
100
  data=json.dumps({"text": texts, "show_progress_bar": show_progress_bar}),
101
101
  verify=False,
102
102
  headers=self._get_headers(),
103
- )
104
- if response.status_code == 200:
105
- embeddings = np.array(response.json()["embeddings"])
106
- logger.debug(f"Computing embeddings done for batch")
107
- return embeddings.tolist()
108
- else:
109
- logger.error(f"Error: {response.status_code}")
110
- return []
103
+ ) as response:
104
+ if response.status_code == 200:
105
+ embeddings = np.array(response.json()["embeddings"])
106
+ logger.debug(f"Computing embeddings done for batch")
107
+ return embeddings.tolist()
108
+ else:
109
+ logger.error(f"Error: {response.status_code}")
110
+ return []
111
111
 
112
112
  def embed_documents(
113
113
  self,
@@ -133,7 +133,13 @@ class EmbeddingAPIClient(SecureAPIClient, Embeddings):
133
133
  )
134
134
 
135
135
  # Parallel request
136
- results = Parallel(n_jobs=MAX_N_JOBS)(
136
+ #
137
+ # We explicitly use a *thread-based* backend here. Using the default
138
+ # (process-based) backend would require pickling ``self`` and the
139
+ # underlying SecureAPIClient state (e.g. auth/session objects), which
140
+ # is fragile and can easily break. Threads share the same context and
141
+ # avoid these issues while still allowing concurrent HTTP requests.
142
+ results = Parallel(n_jobs=MAX_N_JOBS, prefer="threads")(
137
143
  delayed(self.embed_batch)(batch, show_progress_bar) for batch in batches
138
144
  )
139
145
 
@@ -31,7 +31,7 @@ async def login_for_access_token(
31
31
  "/list_registered_clients", summary="List registered clients (requires admin scope)"
32
32
  )
33
33
  async def list_clients(
34
- current_client: TokenData = Security(get_current_client, scopes=[ADMIN])
34
+ current_client: TokenData = Security(get_current_client, scopes=[ADMIN]),
35
35
  ):
36
36
  return list_registered_clients()
37
37
 
@@ -4,16 +4,19 @@
4
4
  # This file is part of BERTrend.
5
5
 
6
6
  import os
7
- import uvicorn
8
7
 
8
+ # Load the configuration BEFORE any other imports that might use CUDA
9
9
  from bertrend.services.embedding_server.config.settings import get_config
10
10
 
11
- # Load the configuration
12
11
  CONFIG = get_config()
13
12
 
14
- # Set the CUDA_VISIBLE_DEVICES environment variable
13
+ # Set the CUDA_VISIBLE_DEVICES environment variable BEFORE importing uvicorn
14
+ # This is critical because uvicorn will import the app module, which imports torch
15
+ # We override the value with the content of the config
15
16
  os.environ["CUDA_VISIBLE_DEVICES"] = CONFIG.cuda_visible_devices
16
17
 
18
+ import uvicorn
19
+
17
20
  # Start the FastAPI application
18
21
  if __name__ == "__main__":
19
22
  uvicorn.run(
@@ -17,13 +17,13 @@ if CONFIG.host == "0.0.0.0":
17
17
 
18
18
  # Try to check health endpoint and handle any connection errors
19
19
  try:
20
- response = requests.get(
20
+ with requests.get(
21
21
  f"https://{CONFIG.host}:{CONFIG.port}/health", timeout=5, verify=False
22
- )
23
- if response.status_code == 200:
24
- sys.exit(0)
25
- else:
26
- sys.exit(1)
22
+ ) as response:
23
+ if response.status_code == 200:
24
+ sys.exit(0)
25
+ else:
26
+ sys.exit(1)
27
27
 
28
28
  # If an error occurs, exit with status code 1
29
29
  except (requests.exceptions.RequestException, requests.exceptions.ConnectionError) as e:
@@ -79,7 +79,9 @@ class EmbeddingService(BaseEmbedder):
79
79
  self.embedding_model_name = model_name
80
80
  self.embedding_dtype = embedding_dtype
81
81
 
82
- def embed(self, texts: list[str] | pd.Series, verbose: bool = False) -> tuple[
82
+ def embed(
83
+ self, texts: list[str] | pd.Series, verbose: bool = False
84
+ ) -> tuple[
83
85
  np.ndarray,
84
86
  list[list[str]] | None,
85
87
  list[np.ndarray] | None,
@@ -267,14 +269,14 @@ class EmbeddingService(BaseEmbedder):
267
269
  Exception
268
270
  If the API request fails.
269
271
  """
270
- response = requests.get(self.url + "/model_name", verify=False)
271
- if response.status_code == 200:
272
- model_name = response.json()
273
- logger.debug(f"Model name: {model_name}")
274
- return model_name
275
- else:
276
- logger.error(f"Error: {response.status_code}")
277
- raise Exception(f"Error: {response.status_code}")
272
+ with requests.get(self.url + "/model_name", verify=False) as response:
273
+ if response.status_code == 200:
274
+ model_name = response.json()
275
+ logger.debug(f"Remote model name: {model_name}")
276
+ return model_name
277
+ else:
278
+ logger.error(f"Error: {response.status_code}")
279
+ raise Exception(f"Error: {response.status_code}")
278
280
 
279
281
 
280
282
  def _convert_to_numpy(obj, type=None):
@@ -4,7 +4,6 @@ services:
4
4
  context: .
5
5
  dockerfile: Dockerfile
6
6
  container_name: bertrend-scheduler
7
- user: "${HOST_UID:-1000}:${HOST_GID:-1000}"
8
7
  ports:
9
8
  - "8882:8000"
10
9
  volumes:
@@ -5,7 +5,6 @@
5
5
  import time
6
6
 
7
7
  import requests
8
- from fastapi import HTTPException
9
8
  from loguru import logger
10
9
 
11
10
 
@@ -24,27 +23,27 @@ def http_request(
24
23
  method: str = "GET",
25
24
  headers: dict = None,
26
25
  json_data: dict = None,
27
- timeout: int = 30,
26
+ timeout: int = 600, # 10 min
28
27
  ):
29
28
  """Execute an HTTP request (curl-like functionality)"""
30
29
  logger.info(f"Executing HTTP {method} request to {url}")
31
30
  try:
32
- response = requests.request(
31
+ with requests.request(
33
32
  method=method.upper(),
34
33
  url=url,
35
34
  headers=headers,
36
35
  json=json_data,
37
36
  timeout=timeout,
38
- )
39
- if response.status_code != 200:
40
- response.raise_for_status()
41
- logger.info(f"HTTP request completed with status code: {response.status_code}")
42
- return f"Request to {url} completed with status {response.status_code}"
37
+ ) as response:
38
+ if response.status_code != 200:
39
+ response.raise_for_status()
40
+ logger.info(
41
+ f"HTTP request completed with status code: {response.status_code}"
42
+ )
43
+ return f"Request to {url} completed with status {response.status_code}"
43
44
  except Exception as e:
44
45
  logger.error(f"HTTP request failed: {str(e)}")
45
- raise HTTPException(
46
- status_code=500, detail=f"Error executing request: {str(e)}"
47
- )
46
+ raise RuntimeError(f"Error executing request: {str(e)}")
48
47
 
49
48
 
50
49
  # Job function registry