bertrend 0.3.12__tar.gz → 0.3.13__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.
- {bertrend-0.3.12 → bertrend-0.3.13}/PKG-INFO +2 -1
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/llm_utils/newsletter_model.py +8 -7
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/llm_utils/newsletter_outlook_template.html +25 -9
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/llm_utils/newsletter_template.html +20 -5
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_newsletter_model.py +4 -23
- bertrend-0.3.13/bertrend_apps/common/mail_utils.py +131 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/__init__.py +1 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/app.py +26 -0
- bertrend-0.3.13/bertrend_apps/prospective_demo/data_model.py +19 -0
- bertrend-0.3.13/bertrend_apps/prospective_demo/detailed_report_template.html +438 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/i18n_translations.py +4 -11
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/models_info.py +11 -17
- bertrend-0.3.13/bertrend_apps/prospective_demo/report_generation.py +325 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/pyproject.toml +2 -1
- bertrend-0.3.12/bertrend_apps/common/mail_utils.py +0 -91
- bertrend-0.3.12/bertrend_apps/prospective_demo/report_generation.py +0 -215
- bertrend-0.3.12/bertrend_apps/prospective_demo/report_template.html +0 -148
- bertrend-0.3.12/bertrend_apps/prospective_demo/report_utils.py +0 -132
- {bertrend-0.3.12 → bertrend-0.3.13}/AUTHORS.txt +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/LICENSE.md +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/README.md +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/BERTopicModel.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/BERTrend.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/config/bertopic_default_config.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/config/bertrend_default_config.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/config/parameters.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/config/services_default_config.toml +0 -0
- {bertrend-0.3.12/bertrend_apps/newsletters → bertrend-0.3.13/bertrend/demos}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/demos_utils/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/demos_utils/data_loading_component.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/demos_utils/embed_documents_component.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/demos_utils/i18n.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/demos_utils/i18n_translations.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/demos_utils/icons.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/demos_utils/parameters_component.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/demos_utils/state_utils.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/start_summarizer_app.sh +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/start_topic_analysis_app.sh +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/start_weak_signals_app.sh +0 -0
- {bertrend-0.3.12/bertrend_apps/exploration/curebot → bertrend-0.3.13/bertrend/demos/summarization}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/summarization/summarizer_app.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/topic_analysis/.streamlit/config.toml +0 -0
- {bertrend-0.3.12/bertrend_apps/exploration → bertrend-0.3.13/bertrend/demos/topic_analysis}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/topic_analysis/app.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/topic_analysis/app_utils.py +0 -0
- {bertrend-0.3.12/bertrend_apps/common → bertrend-0.3.13/bertrend/demos/topic_analysis/demo_pages}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/topic_analysis/demo_pages/explore_topics.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/topic_analysis/demo_pages/newsletters_generation.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/topic_analysis/demo_pages/temporal_visualizations.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/topic_analysis/demo_pages/topic_visualizations.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/topic_analysis/demo_pages/training_page.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/topic_analysis/i18n_translations.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/weak_signals/.streamlit/config.toml +0 -0
- {bertrend-0.3.12/bertrend_apps → bertrend-0.3.13/bertrend/demos/weak_signals}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/weak_signals/app.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/weak_signals/i18n_translations.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/demos/weak_signals/visualizations_utils.py +0 -0
- {bertrend-0.3.12/bertrend/trend_analysis → bertrend-0.3.13/bertrend/llm_utils}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/llm_utils/newsletter.css +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/llm_utils/newsletter_features.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/llm_utils/openai_client.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/llm_utils/prompts.py +0 -0
- {bertrend-0.3.12/bertrend/topic_analysis → bertrend-0.3.13/bertrend/metrics}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/metrics/temporal_metrics_embedding.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/metrics/topic_metrics.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/resources/common_ngrams.json +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/resources/stopwords-en.json +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/resources/stopwords-fr.json +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/resources/stopwords-rte.json +0 -0
- {bertrend-0.3.12/bertrend/tests → bertrend-0.3.13/bertrend/services}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/authentication.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_client.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_server/README.md +0 -0
- {bertrend-0.3.12/bertrend/services/summary → bertrend-0.3.13/bertrend/services/embedding_server}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_server/bertrend_client_registry.json +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_server/config/default_config.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_server/config/settings.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_server/main.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_server/models.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_server/routers/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_server/routers/authentication.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_server/routers/embeddings.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_server/routers/info.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_server/security.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_server/start.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_server/status.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_server/stop.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/embedding_service.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/summarizer.py +0 -0
- {bertrend-0.3.12/bertrend/services/embedding_server → bertrend-0.3.13/bertrend/services/summary}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/summary/abstractive_summarizer.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/summary/chatgpt_summarizer.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/summary/extractive_summarizer.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/summary/lexrank.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/services/summary/prompts.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/README_integration_tests.md +0 -0
- {bertrend-0.3.12/bertrend/services → bertrend-0.3.13/bertrend/tests}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/conftest.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_abstractive_summarizer.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_bertrend.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_cache_utils.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_chatgpt_summarizer.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_config_utils.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_data_loading.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_data_structure.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_embedding_client.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_extractive_summarizer.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_installation.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_integration.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_newsletter_features.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_openai_client.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_representative_docs.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_summarizer.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_temporal_metrics_embedding.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_topic_description.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_topic_metrics.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_topic_model.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_trend_analysis_data_structure.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_trend_analysis_prompts.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_trend_analysis_visualizations.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_trend_analysis_weak_signals.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_utils_init.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/tests/test_visualizations.py +0 -0
- {bertrend-0.3.12/bertrend/metrics → bertrend-0.3.13/bertrend/topic_analysis}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/topic_analysis/data_structure.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/topic_analysis/prompts.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/topic_analysis/representative_docs.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/topic_analysis/topic_description.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/topic_analysis/visualizations.py +0 -0
- {bertrend-0.3.12/bertrend/llm_utils → bertrend-0.3.13/bertrend/trend_analysis}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/trend_analysis/data_structure.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/trend_analysis/prompts.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/trend_analysis/signal_llm_template_en.html +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/trend_analysis/signal_llm_template_fr.html +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/trend_analysis/visualizations.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/trend_analysis/weak_signals.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/utils/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/utils/cache_utils.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/utils/config_utils.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend/utils/data_loading.py +0 -0
- {bertrend-0.3.12/bertrend/demos/weak_signals → bertrend-0.3.13/bertrend_apps}/__init__.py +0 -0
- {bertrend-0.3.12/bertrend/demos/topic_analysis/demo_pages → bertrend-0.3.13/bertrend_apps/common}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/common/crontab_utils.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/config/feeds/arxiv_feed.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/config/feeds/decarbonation_feed.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/config/feeds/llm_en_feed.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/config/feeds/llm_feed.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/config/feeds/nlp_feed.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/config/feeds/rte_feed.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/config/gmail_credentials.json +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/config/newsletters/arxiv_newsletter_from_last.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/config/newsletters/decarbonation_newsletter_from_last.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/config/newsletters/decarbonation_newsletter_from_scratch.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/config/newsletters/llm_en_newsletter_from_last.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/config/newsletters/llm_newsletter_from_last.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/config/newsletters/nlp_newsletter_from_last.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/config/newsletters/rte_newsletter_from_last.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/config/newsletters/rte_newsletter_from_scratch.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/data_provider/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/data_provider/__main__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/data_provider/arxiv_provider.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/data_provider/atom_feed_provider.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/data_provider/bing_news_provider.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/data_provider/data_provider.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/data_provider/google_news_provider.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/data_provider/newscatcher_provider.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/data_provider/utils.py +0 -0
- {bertrend-0.3.12/bertrend/demos/topic_analysis → bertrend-0.3.13/bertrend_apps/exploration}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/curebot/.streamlit/config.toml +0 -0
- {bertrend-0.3.12/bertrend/demos/summarization → bertrend-0.3.13/bertrend_apps/exploration/curebot}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/curebot/app.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/curebot/app_utils.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/curebot/config.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/curebot/import_extraction_article.ipynb +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/curebot/prompts.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/curebot/start_newsletter_generator.sh +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/curebot/tabs/tab1.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/curebot/tabs/tab2.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/curebot/tabs/tab3.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/dataviz/Main_page.py +0 -0
- {bertrend-0.3.12/bertrend_apps/exploration/geolocalization/spacy → bertrend-0.3.13/bertrend_apps/exploration/dataviz}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/dataviz/pages/1_Data_feeds.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/geolocalization/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/geolocalization/entity_utils.py +0 -0
- {bertrend-0.3.12/bertrend_apps/exploration/dataviz → bertrend-0.3.13/bertrend_apps/exploration/geolocalization/spacy}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/geolocalization/spacy/common_factory.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/geolocalization/spacy/dbpedia.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/geolocalization/spacy/nlp.config +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/exploration/geolocalization/spacy/utils.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/install_feeds_and_newsletters.py +0 -0
- {bertrend-0.3.12/bertrend/demos → bertrend-0.3.13/bertrend_apps/newsletters}/__init__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/newsletters/__main__.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/.streamlit/config.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/.streamlit/secrets.toml +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/authentication.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/dashboard_analysis.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/dashboard_common.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/dashboard_signals.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/feeds_common.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/feeds_config.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/feeds_data.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/llm_utils.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/perf_utils.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/process_new_data.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/start_demo.sh +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/prospective_demo/streamlit_utils.py +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/start_apps.sh +0 -0
- {bertrend-0.3.12 → bertrend-0.3.13}/bertrend_apps/stop_apps.sh +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: bertrend
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.13
|
|
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
|
Keywords: topics,BERTopic,transformers,weak signals,LLM
|
|
@@ -59,6 +59,7 @@ Requires-Dist: sentencepiece (>=0.2.0)
|
|
|
59
59
|
Requires-Dist: starlette (>=0.46.2)
|
|
60
60
|
Requires-Dist: streamlit (>=1.46)
|
|
61
61
|
Requires-Dist: streamlit-code-editor (>=0.1.22)
|
|
62
|
+
Requires-Dist: streamlit-tags
|
|
62
63
|
Requires-Dist: supervisor (>=4.2.5)
|
|
63
64
|
Requires-Dist: thefuzz (>=0.22.1)
|
|
64
65
|
Requires-Dist: tiktoken (>=0.8.0)
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
# See AUTHORS.txt
|
|
3
3
|
# SPDX-License-Identifier: MPL-2.0
|
|
4
4
|
# This file is part of BERTrend.
|
|
5
|
+
from typing import Optional
|
|
5
6
|
|
|
6
|
-
from typing import List
|
|
7
7
|
from pydantic import BaseModel
|
|
8
8
|
from datetime import date
|
|
9
9
|
|
|
@@ -16,7 +16,7 @@ class Article(BaseModel):
|
|
|
16
16
|
"""Article model."""
|
|
17
17
|
|
|
18
18
|
title: str
|
|
19
|
-
date: date
|
|
19
|
+
date: Optional[date]
|
|
20
20
|
summary: str | None = None
|
|
21
21
|
source: str | None = None
|
|
22
22
|
url: str | None = None
|
|
@@ -26,9 +26,9 @@ class Topic(BaseModel):
|
|
|
26
26
|
"""Topic model."""
|
|
27
27
|
|
|
28
28
|
title: str
|
|
29
|
-
hashtags:
|
|
29
|
+
hashtags: list[str] | None = None
|
|
30
30
|
summary: str | None = None
|
|
31
|
-
articles:
|
|
31
|
+
articles: list[Article]
|
|
32
32
|
topic_type: str = (
|
|
33
33
|
STRONG_TOPIC_TYPE # Default value "strong", can be "weak" or "noise"
|
|
34
34
|
)
|
|
@@ -38,7 +38,8 @@ class Newsletter(BaseModel):
|
|
|
38
38
|
"""Newsletter model."""
|
|
39
39
|
|
|
40
40
|
title: str
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
reference_period: date = None # has the precedence over the two other dates
|
|
42
|
+
period_start_date: date = None
|
|
43
|
+
period_end_date: date = None
|
|
44
|
+
topics: list[Topic]
|
|
44
45
|
debug_info: dict | None = None
|
|
@@ -58,13 +58,21 @@
|
|
|
58
58
|
<tr>
|
|
59
59
|
<td>
|
|
60
60
|
<h1 style="font-size: 32px; color: #333; margin: 0 0 10px 0; font-family: Arial, sans-serif;">{{ newsletter.title }}</h1>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
61
|
+
<p style="font-size: 18px; color: #555; margin: 0 0 30px 0; font-family: Arial, sans-serif;">
|
|
62
|
+
{% if newsletter.reference_period %}
|
|
63
|
+
{% if language == 'en' %}
|
|
64
|
+
Period: {{ newsletter.reference_period }}
|
|
65
|
+
{% else %}
|
|
66
|
+
Période : {{ newsletter.reference_period }}
|
|
67
|
+
{% endif %}
|
|
68
|
+
{% elif newsletter.period_start_date and newsletter.period_end_date %}
|
|
69
|
+
{% if language == 'en' %}
|
|
70
|
+
Period: {{ newsletter.period_start_date }} to {{ newsletter.period_end_date }}
|
|
71
|
+
{% else %}
|
|
72
|
+
Période : {{ newsletter.period_start_date }} au {{ newsletter.period_end_date }}
|
|
73
|
+
{% endif %}
|
|
74
|
+
{% endif %}
|
|
75
|
+
</p>
|
|
68
76
|
</td>
|
|
69
77
|
</tr>
|
|
70
78
|
</table>
|
|
@@ -123,7 +131,9 @@
|
|
|
123
131
|
|
|
124
132
|
<!-- Date and Source -->
|
|
125
133
|
<div style="font-size: 10px; color: #666; margin-bottom: 8px; font-family: Arial, sans-serif;">
|
|
134
|
+
{% if article.date %}
|
|
126
135
|
<span style="font-weight: bold;">{{ article.date }}</span>
|
|
136
|
+
{% endif %}
|
|
127
137
|
{% if article.source %}
|
|
128
138
|
<span style="margin: 0 5px;">|</span>
|
|
129
139
|
<span style="font-style: italic;">
|
|
@@ -150,6 +160,10 @@
|
|
|
150
160
|
</tr>
|
|
151
161
|
</table>
|
|
152
162
|
{% endfor %}
|
|
163
|
+
|
|
164
|
+
{% block detailed_topic_analysis scoped %}
|
|
165
|
+
<!-- Placeholder for detailed analysis -->
|
|
166
|
+
{% endblock %}
|
|
153
167
|
</td>
|
|
154
168
|
</tr>
|
|
155
169
|
</table>
|
|
@@ -174,6 +188,8 @@
|
|
|
174
188
|
</td>
|
|
175
189
|
</tr>
|
|
176
190
|
</table>
|
|
177
|
-
</body>
|
|
178
191
|
|
|
179
|
-
</
|
|
192
|
+
</body>
|
|
193
|
+
|
|
194
|
+
</html>
|
|
195
|
+
|
|
@@ -27,10 +27,18 @@
|
|
|
27
27
|
<header>
|
|
28
28
|
<h1>{{ newsletter.title }}</h1>
|
|
29
29
|
<p class="period">
|
|
30
|
-
{% if
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
{% if newsletter.reference_period %}
|
|
31
|
+
{% if language == 'en' %}
|
|
32
|
+
Period: {{ newsletter.reference_period }}
|
|
33
|
+
{% else %}
|
|
34
|
+
Période : {{ newsletter.reference_period }}
|
|
35
|
+
{% endif %}
|
|
36
|
+
{% elif newsletter.period_start_date and newsletter.period_end_date %}
|
|
37
|
+
{% if language == 'en' %}
|
|
38
|
+
Period: {{ newsletter.period_start_date }} to {{ newsletter.period_end_date }}
|
|
39
|
+
{% else %}
|
|
40
|
+
Période : {{ newsletter.period_start_date }} au {{ newsletter.period_end_date }}
|
|
41
|
+
{% endif %}
|
|
34
42
|
{% endif %}
|
|
35
43
|
</p>
|
|
36
44
|
</header>
|
|
@@ -61,7 +69,9 @@
|
|
|
61
69
|
{% endif %}
|
|
62
70
|
<!-- Date and Source Inline -->
|
|
63
71
|
<div class="timestamp">
|
|
64
|
-
|
|
72
|
+
{% if article.date %}
|
|
73
|
+
<div class="date">{{ article.date }}</div>
|
|
74
|
+
{% endif %}
|
|
65
75
|
{% if article.source %}
|
|
66
76
|
<span class="separator">|</span>
|
|
67
77
|
<div class="source">
|
|
@@ -87,6 +97,11 @@
|
|
|
87
97
|
</div>
|
|
88
98
|
{% endfor %}
|
|
89
99
|
</div>
|
|
100
|
+
|
|
101
|
+
<!-- Placeholder for additional info -->
|
|
102
|
+
{% block detailed_topic_analysis with topic=topic %}
|
|
103
|
+
{% endblock %}
|
|
104
|
+
|
|
90
105
|
</section>
|
|
91
106
|
{% endfor %}
|
|
92
107
|
</main>
|
|
@@ -127,11 +127,6 @@ class TestTopic:
|
|
|
127
127
|
Topic(hashtags=["#test"], articles=articles)
|
|
128
128
|
assert "title" in str(exc_info.value)
|
|
129
129
|
|
|
130
|
-
# Missing hashtags
|
|
131
|
-
with pytest.raises(ValidationError) as exc_info:
|
|
132
|
-
Topic(title="Test Topic", articles=articles)
|
|
133
|
-
assert "hashtags" in str(exc_info.value)
|
|
134
|
-
|
|
135
130
|
# Missing articles
|
|
136
131
|
with pytest.raises(ValidationError) as exc_info:
|
|
137
132
|
Topic(title="Test Topic", hashtags=["#test"])
|
|
@@ -246,30 +241,13 @@ class TestNewsletter:
|
|
|
246
241
|
# Missing title
|
|
247
242
|
with pytest.raises(ValidationError) as exc_info:
|
|
248
243
|
Newsletter(
|
|
244
|
+
reference_period=date(2024, 1, 31),
|
|
249
245
|
period_start_date=date(2024, 1, 1),
|
|
250
246
|
period_end_date=date(2024, 1, 31),
|
|
251
247
|
topics=topics,
|
|
252
248
|
)
|
|
253
249
|
assert "title" in str(exc_info.value)
|
|
254
250
|
|
|
255
|
-
# Missing period_start_date
|
|
256
|
-
with pytest.raises(ValidationError) as exc_info:
|
|
257
|
-
Newsletter(
|
|
258
|
-
title="Test Newsletter",
|
|
259
|
-
period_end_date=date(2024, 1, 31),
|
|
260
|
-
topics=topics,
|
|
261
|
-
)
|
|
262
|
-
assert "period_start_date" in str(exc_info.value)
|
|
263
|
-
|
|
264
|
-
# Missing period_end_date
|
|
265
|
-
with pytest.raises(ValidationError) as exc_info:
|
|
266
|
-
Newsletter(
|
|
267
|
-
title="Test Newsletter",
|
|
268
|
-
period_start_date=date(2024, 1, 1),
|
|
269
|
-
topics=topics,
|
|
270
|
-
)
|
|
271
|
-
assert "period_end_date" in str(exc_info.value)
|
|
272
|
-
|
|
273
251
|
# Missing topics
|
|
274
252
|
with pytest.raises(ValidationError) as exc_info:
|
|
275
253
|
Newsletter(
|
|
@@ -399,6 +377,7 @@ class TestIntegration:
|
|
|
399
377
|
title="Test Newsletter",
|
|
400
378
|
period_start_date=date(2024, 1, 1),
|
|
401
379
|
period_end_date=date(2024, 1, 31),
|
|
380
|
+
reference_period=date(2024, 1, 31),
|
|
402
381
|
topics=[topic],
|
|
403
382
|
)
|
|
404
383
|
|
|
@@ -409,6 +388,7 @@ class TestIntegration:
|
|
|
409
388
|
assert data["title"] == "Test Newsletter"
|
|
410
389
|
assert data["period_start_date"] == date(2024, 1, 1)
|
|
411
390
|
assert data["period_end_date"] == date(2024, 1, 31)
|
|
391
|
+
assert data["reference_period"] == date(2024, 1, 31)
|
|
412
392
|
assert len(data["topics"]) == 1
|
|
413
393
|
assert data["topics"][0]["title"] == "Test Topic"
|
|
414
394
|
assert len(data["topics"][0]["articles"]) == 1
|
|
@@ -420,4 +400,5 @@ class TestIntegration:
|
|
|
420
400
|
assert newsletter_from_dict.title == newsletter.title
|
|
421
401
|
assert newsletter_from_dict.period_start_date == newsletter.period_start_date
|
|
422
402
|
assert newsletter_from_dict.period_end_date == newsletter.period_end_date
|
|
403
|
+
assert newsletter_from_dict.reference_period == newsletter.reference_period
|
|
423
404
|
assert len(newsletter_from_dict.topics) == len(newsletter.topics)
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Copyright (c) 2024, 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 base64
|
|
7
|
+
import os
|
|
8
|
+
from email.message import EmailMessage
|
|
9
|
+
from email.utils import COMMASPACE
|
|
10
|
+
import mimetypes
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
# Gmail API utils
|
|
14
|
+
from google.auth.transport.requests import Request
|
|
15
|
+
from google.oauth2.credentials import Credentials
|
|
16
|
+
from google_auth_oauthlib.flow import InstalledAppFlow
|
|
17
|
+
from googleapiclient.discovery import build
|
|
18
|
+
from googleapiclient.errors import HttpError
|
|
19
|
+
from loguru import logger
|
|
20
|
+
|
|
21
|
+
from bertrend import BASE_PATH
|
|
22
|
+
|
|
23
|
+
SCOPES = ["https://mail.google.com/"] # full access to mail API
|
|
24
|
+
FROM = "wattelse.ai@gmail.com"
|
|
25
|
+
TOKEN_PATH = BASE_PATH / "gmail_token.json"
|
|
26
|
+
DEFAULT_GMAIL_CREDENTIALS_PATH = (
|
|
27
|
+
Path(__file__).parent.parent / "config" / "gmail_credentials.json"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Ensures to write with +rw for both user and groups
|
|
31
|
+
os.umask(0o002)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_credentials(
|
|
35
|
+
credentials_path: Path = DEFAULT_GMAIL_CREDENTIALS_PATH,
|
|
36
|
+
) -> Credentials:
|
|
37
|
+
"""Returns credentials for the user"""
|
|
38
|
+
creds = None
|
|
39
|
+
# The file token.json stores the user's access and refresh tokens, and is
|
|
40
|
+
# created automatically when the authorization flow completes for the first
|
|
41
|
+
# time.
|
|
42
|
+
logger.debug(f"Gmail credentials path: {credentials_path}")
|
|
43
|
+
logger.debug(f"Gmail token path: {TOKEN_PATH}")
|
|
44
|
+
if TOKEN_PATH.exists():
|
|
45
|
+
creds = Credentials.from_authorized_user_file(TOKEN_PATH, SCOPES)
|
|
46
|
+
# If there are no (valid) credentials available, let the user log in.
|
|
47
|
+
if not creds or not creds.valid:
|
|
48
|
+
if creds and creds.expired and creds.refresh_token:
|
|
49
|
+
creds.refresh(Request())
|
|
50
|
+
else:
|
|
51
|
+
flow = InstalledAppFlow.from_client_secrets_file(credentials_path, SCOPES)
|
|
52
|
+
creds = flow.run_local_server(port=0)
|
|
53
|
+
# Save the credentials for the next run
|
|
54
|
+
with open(TOKEN_PATH, "w") as token:
|
|
55
|
+
token.write(creds.to_json())
|
|
56
|
+
return creds
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def send_email(
|
|
60
|
+
credentials,
|
|
61
|
+
subject: str,
|
|
62
|
+
recipients: list[str],
|
|
63
|
+
content: str | Path,
|
|
64
|
+
content_type: str = "html",
|
|
65
|
+
file_name: str = None,
|
|
66
|
+
) -> None:
|
|
67
|
+
"""
|
|
68
|
+
Send an e-mail with Gmail API.
|
|
69
|
+
|
|
70
|
+
If *content* is a valid path it is attached as a file (with an optional filename),
|
|
71
|
+
otherwise it is used as the message body.
|
|
72
|
+
"""
|
|
73
|
+
try:
|
|
74
|
+
service = build("gmail", "v1", credentials=credentials)
|
|
75
|
+
|
|
76
|
+
msg = EmailMessage()
|
|
77
|
+
msg["Subject"] = subject
|
|
78
|
+
msg["From"] = FROM
|
|
79
|
+
msg["To"] = COMMASPACE.join(recipients)
|
|
80
|
+
|
|
81
|
+
# ------------------------------------------------------------------ #
|
|
82
|
+
# 1. Attach a file if *content* points to an existing file #
|
|
83
|
+
# ------------------------------------------------------------------ #
|
|
84
|
+
if isinstance(content, (str, Path)) and Path(content).is_file():
|
|
85
|
+
file_path = Path(content)
|
|
86
|
+
|
|
87
|
+
# Body text so the message is not “empty”
|
|
88
|
+
msg.set_content(
|
|
89
|
+
f"Please find {file_path.name} attached.",
|
|
90
|
+
subtype="plain",
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
mime_type, _ = mimetypes.guess_type(file_path)
|
|
94
|
+
mime_type = mime_type or "application/octet-stream"
|
|
95
|
+
maintype, subtype = mime_type.split("/", 1)
|
|
96
|
+
|
|
97
|
+
with file_path.open("rb") as fp:
|
|
98
|
+
msg.add_attachment(
|
|
99
|
+
fp.read(),
|
|
100
|
+
maintype=maintype,
|
|
101
|
+
subtype=subtype,
|
|
102
|
+
filename=file_path.name if not file_name else file_name,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# ------------------------------------------------------------------ #
|
|
106
|
+
# 2. Otherwise use *content* as the body #
|
|
107
|
+
# ------------------------------------------------------------------ #
|
|
108
|
+
else:
|
|
109
|
+
subtype = (
|
|
110
|
+
"plain"
|
|
111
|
+
if content_type.lower() in {"md", "text", "txt"}
|
|
112
|
+
else content_type
|
|
113
|
+
)
|
|
114
|
+
msg.set_content(content, subtype=subtype)
|
|
115
|
+
|
|
116
|
+
# ------------------------------------------------------------------ #
|
|
117
|
+
# 3. Send through Gmail API #
|
|
118
|
+
# ------------------------------------------------------------------ #
|
|
119
|
+
raw_message = base64.urlsafe_b64encode(msg.as_bytes()).decode()
|
|
120
|
+
service.users().messages().send(
|
|
121
|
+
userId="me", body={"raw": raw_message}
|
|
122
|
+
).execute()
|
|
123
|
+
|
|
124
|
+
logger.debug("E-mail successfully sent.")
|
|
125
|
+
|
|
126
|
+
except HttpError as err:
|
|
127
|
+
logger.error("Gmail API error: %s", err)
|
|
128
|
+
except FileNotFoundError:
|
|
129
|
+
logger.error("File not found: %s", content)
|
|
130
|
+
except Exception as err:
|
|
131
|
+
logger.exception("Unexpected error: %s", err)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# See AUTHORS.txt
|
|
3
3
|
# SPDX-License-Identifier: MPL-2.0
|
|
4
4
|
# This file is part of BERTrend.
|
|
5
|
+
from importlib.metadata import version
|
|
5
6
|
|
|
6
7
|
import torch
|
|
7
8
|
|
|
@@ -43,6 +44,29 @@ AUTHENTIFICATION = True
|
|
|
43
44
|
# AUTHENTIFICATION = False
|
|
44
45
|
|
|
45
46
|
|
|
47
|
+
def display_version_number():
|
|
48
|
+
# Display version at the bottom (using st.markdown and CSS for fixed footer)
|
|
49
|
+
footer = f"""
|
|
50
|
+
<style>
|
|
51
|
+
.footer {{
|
|
52
|
+
position: fixed;
|
|
53
|
+
right: 10px;
|
|
54
|
+
bottom: 10px;
|
|
55
|
+
color: #666;
|
|
56
|
+
font-size: 0.8em;
|
|
57
|
+
opacity: 0.6;
|
|
58
|
+
user-select: none;
|
|
59
|
+
pointer-events: none;
|
|
60
|
+
background: none;
|
|
61
|
+
}}
|
|
62
|
+
</style>
|
|
63
|
+
<div class="footer">
|
|
64
|
+
Version: {version('bertrend')}
|
|
65
|
+
</div>
|
|
66
|
+
"""
|
|
67
|
+
st.markdown(footer, unsafe_allow_html=True)
|
|
68
|
+
|
|
69
|
+
|
|
46
70
|
def main():
|
|
47
71
|
"""Main page"""
|
|
48
72
|
set_internationalization_language("fr")
|
|
@@ -54,6 +78,8 @@ def main():
|
|
|
54
78
|
page_icon=":part_alternation_mark:",
|
|
55
79
|
)
|
|
56
80
|
|
|
81
|
+
display_version_number()
|
|
82
|
+
|
|
57
83
|
st.title(":part_alternation_mark: " + page_title)
|
|
58
84
|
|
|
59
85
|
if AUTHENTIFICATION:
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Copyright (c) 2024, 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
|
+
from bertrend.llm_utils.newsletter_model import Topic, Newsletter
|
|
6
|
+
from bertrend.trend_analysis.data_structure import SignalAnalysis, TopicSummaryList
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TopicOverTime(Topic):
|
|
10
|
+
"""Topic model."""
|
|
11
|
+
|
|
12
|
+
topic_evolution: TopicSummaryList | None = None
|
|
13
|
+
topic_analysis: SignalAnalysis | None = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DetailedNewsletter(Newsletter):
|
|
17
|
+
"""Newsletter model with detailed information about topic evolution over time."""
|
|
18
|
+
|
|
19
|
+
topics: list[TopicOverTime]
|