bertrend 0.3.1__py3-none-any.whl
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/BERTopicModel.py +320 -0
- bertrend/BERTrend.py +1211 -0
- bertrend/__init__.py +59 -0
- bertrend/config/bertopic_default_config.toml +48 -0
- bertrend/config/bertrend_default_config.toml +16 -0
- bertrend/config/parameters.py +92 -0
- bertrend/config/services_default_config.toml +32 -0
- bertrend/demos/__init__.py +4 -0
- bertrend/demos/demos_utils/__init__.py +13 -0
- bertrend/demos/demos_utils/data_loading_component.py +267 -0
- bertrend/demos/demos_utils/embed_documents_component.py +52 -0
- bertrend/demos/demos_utils/icons.py +41 -0
- bertrend/demos/demos_utils/messages.py +11 -0
- bertrend/demos/demos_utils/parameters_component.py +162 -0
- bertrend/demos/demos_utils/state_utils.py +99 -0
- bertrend/demos/start_summarizer_app.sh +9 -0
- bertrend/demos/start_topic_analysis_app.sh +9 -0
- bertrend/demos/start_weak_signals_app.sh +9 -0
- bertrend/demos/summarization/__init__.py +4 -0
- bertrend/demos/summarization/summarizer_app.py +98 -0
- bertrend/demos/topic_analysis/__init__.py +4 -0
- bertrend/demos/topic_analysis/app.py +87 -0
- bertrend/demos/topic_analysis/app_utils.py +69 -0
- bertrend/demos/topic_analysis/demo_pages/__init__.py +4 -0
- bertrend/demos/topic_analysis/demo_pages/explore_topics.py +455 -0
- bertrend/demos/topic_analysis/demo_pages/newsletters_generation.py +178 -0
- bertrend/demos/topic_analysis/demo_pages/temporal_visualizations.py +573 -0
- bertrend/demos/topic_analysis/demo_pages/topic_visualizations.py +280 -0
- bertrend/demos/topic_analysis/demo_pages/training_page.py +219 -0
- bertrend/demos/topic_analysis/messages.py +13 -0
- bertrend/demos/weak_signals/__init__.py +4 -0
- bertrend/demos/weak_signals/app.py +510 -0
- bertrend/demos/weak_signals/messages.py +32 -0
- bertrend/demos/weak_signals/visualizations_utils.py +403 -0
- bertrend/llm_utils/__init__.py +4 -0
- bertrend/llm_utils/newsletter.css +131 -0
- bertrend/llm_utils/newsletter_features.py +272 -0
- bertrend/llm_utils/openai_client.py +235 -0
- bertrend/llm_utils/prompts.py +94 -0
- bertrend/metrics/__init__.py +4 -0
- bertrend/metrics/temporal_metrics_embedding.py +861 -0
- bertrend/metrics/topic_metrics.py +199 -0
- bertrend/resources/common_ngrams.json +23 -0
- bertrend/resources/stopwords-en.json +3 -0
- bertrend/resources/stopwords-fr.json +1 -0
- bertrend/resources/stopwords-rte.json +15 -0
- bertrend/services/__init__.py +4 -0
- bertrend/services/authentication.py +66 -0
- bertrend/services/embedding_client.py +154 -0
- bertrend/services/embedding_service.py +380 -0
- bertrend/services/summarizer.py +45 -0
- bertrend/services/summary/__init__.py +4 -0
- bertrend/services/summary/abstractive_summarizer.py +74 -0
- bertrend/services/summary/chatgpt_summarizer.py +67 -0
- bertrend/services/summary/extractive_summarizer.py +368 -0
- bertrend/services/summary/lexrank.py +126 -0
- bertrend/services/summary/prompts.py +43 -0
- bertrend/tests/__init__.py +4 -0
- bertrend/tests/test_abstractive_summarizer.py +140 -0
- bertrend/tests/test_bertrend.py +1091 -0
- bertrend/tests/test_cache_utils.py +111 -0
- bertrend/tests/test_chatgpt_summarizer.py +150 -0
- bertrend/tests/test_config_utils.py +54 -0
- bertrend/tests/test_data_loading.py +326 -0
- bertrend/tests/test_data_structure.py +53 -0
- bertrend/tests/test_embedding_client.py +546 -0
- bertrend/tests/test_extractive_summarizer.py +250 -0
- bertrend/tests/test_installation.py +183 -0
- bertrend/tests/test_newsletter_features.py +354 -0
- bertrend/tests/test_openai_client.py +210 -0
- bertrend/tests/test_representative_docs.py +125 -0
- bertrend/tests/test_summarizer.py +115 -0
- bertrend/tests/test_temporal_metrics_embedding.py +349 -0
- bertrend/tests/test_topic_description.py +159 -0
- bertrend/tests/test_topic_metrics.py +233 -0
- bertrend/tests/test_topic_model.py +285 -0
- bertrend/tests/test_trend_analysis_data_structure.py +174 -0
- bertrend/tests/test_trend_analysis_prompts.py +225 -0
- bertrend/tests/test_trend_analysis_visualizations.py +307 -0
- bertrend/tests/test_trend_analysis_weak_signals.py +598 -0
- bertrend/tests/test_utils_init.py +70 -0
- bertrend/tests/test_visualizations.py +306 -0
- bertrend/topic_analysis/__init__.py +4 -0
- bertrend/topic_analysis/data_structure.py +13 -0
- bertrend/topic_analysis/prompts.py +42 -0
- bertrend/topic_analysis/representative_docs.py +57 -0
- bertrend/topic_analysis/topic_description.py +66 -0
- bertrend/topic_analysis/visualizations.py +315 -0
- bertrend/trend_analysis/__init__.py +4 -0
- bertrend/trend_analysis/data_structure.py +78 -0
- bertrend/trend_analysis/prompts.py +229 -0
- bertrend/trend_analysis/signal_llm_template_en.html +181 -0
- bertrend/trend_analysis/signal_llm_template_fr.html +181 -0
- bertrend/trend_analysis/visualizations.py +605 -0
- bertrend/trend_analysis/weak_signals.py +425 -0
- bertrend/utils/__init__.py +31 -0
- bertrend/utils/cache_utils.py +31 -0
- bertrend/utils/config_utils.py +41 -0
- bertrend/utils/data_loading.py +329 -0
- bertrend-0.3.1.dist-info/AUTHORS.txt +15 -0
- bertrend-0.3.1.dist-info/LICENSE.md +373 -0
- bertrend-0.3.1.dist-info/METADATA +400 -0
- bertrend-0.3.1.dist-info/RECORD +181 -0
- bertrend-0.3.1.dist-info/WHEEL +4 -0
- bertrend_apps/__init__.py +4 -0
- bertrend_apps/common/__init__.py +4 -0
- bertrend_apps/common/crontab_utils.py +113 -0
- bertrend_apps/common/mail_utils.py +91 -0
- bertrend_apps/config/feeds/arxiv_feed.toml +15 -0
- bertrend_apps/config/feeds/decarbonation_feed.toml +15 -0
- bertrend_apps/config/feeds/llm_en_feed.toml +15 -0
- bertrend_apps/config/feeds/llm_feed.toml +16 -0
- bertrend_apps/config/feeds/nlp_feed.toml +15 -0
- bertrend_apps/config/feeds/rte_feed.toml +15 -0
- bertrend_apps/config/gmail_credentials.json +1 -0
- bertrend_apps/config/newsletters/arxiv_newsletter_from_last.toml +39 -0
- bertrend_apps/config/newsletters/arxiv_newsletter_from_scratch.toml +39 -0
- bertrend_apps/config/newsletters/decarbonation_newsletter_from_last.toml +38 -0
- bertrend_apps/config/newsletters/decarbonation_newsletter_from_scratch.toml +38 -0
- bertrend_apps/config/newsletters/llm_en_newsletter_from_last.toml +38 -0
- bertrend_apps/config/newsletters/llm_newsletter_from_last.toml +39 -0
- bertrend_apps/config/newsletters/nlp_newsletter_from_last.toml +38 -0
- bertrend_apps/config/newsletters/rte_newsletter_from_last.toml +38 -0
- bertrend_apps/config/newsletters/rte_newsletter_from_scratch.toml +38 -0
- bertrend_apps/data_provider/__init__.py +9 -0
- bertrend_apps/data_provider/__main__.py +237 -0
- bertrend_apps/data_provider/arxiv_provider.py +161 -0
- bertrend_apps/data_provider/bing_news_provider.py +82 -0
- bertrend_apps/data_provider/curebot_provider.py +105 -0
- bertrend_apps/data_provider/data_provider.py +194 -0
- bertrend_apps/data_provider/google_news_provider.py +94 -0
- bertrend_apps/data_provider/newscatcher_provider.py +74 -0
- bertrend_apps/data_provider/utils.py +165 -0
- bertrend_apps/exploration/__init__.py +4 -0
- bertrend_apps/exploration/curebot/__init__.py +4 -0
- bertrend_apps/exploration/curebot/app.py +45 -0
- bertrend_apps/exploration/curebot/app_utils.py +317 -0
- bertrend_apps/exploration/curebot/config.toml +33 -0
- bertrend_apps/exploration/curebot/import_extraction_article.ipynb +108 -0
- bertrend_apps/exploration/curebot/old_veille_analyse.py +298 -0
- bertrend_apps/exploration/curebot/prompts.py +24 -0
- bertrend_apps/exploration/curebot/start_newsletter_generator.sh +8 -0
- bertrend_apps/exploration/curebot/tabs/tab1.py +150 -0
- bertrend_apps/exploration/curebot/tabs/tab2.py +95 -0
- bertrend_apps/exploration/curebot/tabs/tab3.py +125 -0
- bertrend_apps/exploration/dataviz/Main_page.py +10 -0
- bertrend_apps/exploration/dataviz/__init__.py +4 -0
- bertrend_apps/exploration/dataviz/pages/1_Data_feeds.py +105 -0
- bertrend_apps/exploration/geolocalization/__init__.py +4 -0
- bertrend_apps/exploration/geolocalization/entity_utils.py +118 -0
- bertrend_apps/exploration/geolocalization/spacy/__init__.py +4 -0
- bertrend_apps/exploration/geolocalization/spacy/common_factory.py +142 -0
- bertrend_apps/exploration/geolocalization/spacy/dbpedia.py +206 -0
- bertrend_apps/exploration/geolocalization/spacy/nlp.config +37 -0
- bertrend_apps/exploration/geolocalization/spacy/utils.py +39 -0
- bertrend_apps/install_feeds_and_newsletters.py +29 -0
- bertrend_apps/newsletters/__init__.py +4 -0
- bertrend_apps/newsletters/__main__.py +277 -0
- bertrend_apps/prospective_demo/.streamlit/config.toml +3 -0
- bertrend_apps/prospective_demo/.streamlit/secrets.toml +9 -0
- bertrend_apps/prospective_demo/__init__.py +70 -0
- bertrend_apps/prospective_demo/app.py +111 -0
- bertrend_apps/prospective_demo/authentication.py +44 -0
- bertrend_apps/prospective_demo/dashboard_analysis.py +132 -0
- bertrend_apps/prospective_demo/dashboard_common.py +79 -0
- bertrend_apps/prospective_demo/dashboard_signals.py +226 -0
- bertrend_apps/prospective_demo/feeds_common.py +38 -0
- bertrend_apps/prospective_demo/feeds_config.py +261 -0
- bertrend_apps/prospective_demo/feeds_data.py +95 -0
- bertrend_apps/prospective_demo/i18n.py +136 -0
- bertrend_apps/prospective_demo/llm_utils.py +34 -0
- bertrend_apps/prospective_demo/models_info.py +361 -0
- bertrend_apps/prospective_demo/perf_utils.py +23 -0
- bertrend_apps/prospective_demo/process_new_data.py +348 -0
- bertrend_apps/prospective_demo/report_generation.py +214 -0
- bertrend_apps/prospective_demo/report_template.html +148 -0
- bertrend_apps/prospective_demo/report_utils.py +132 -0
- bertrend_apps/prospective_demo/start_demo.sh +9 -0
- bertrend_apps/prospective_demo/streamlit_utils.py +37 -0
- bertrend_apps/start_apps.sh +15 -0
- bertrend_apps/stop_apps.sh +11 -0
|
@@ -0,0 +1,162 @@
|
|
|
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
|
+
import streamlit as st
|
|
6
|
+
|
|
7
|
+
from code_editor import code_editor
|
|
8
|
+
|
|
9
|
+
from bertrend import (
|
|
10
|
+
BERTOPIC_DEFAULT_CONFIG_PATH,
|
|
11
|
+
BERTREND_DEFAULT_CONFIG_PATH,
|
|
12
|
+
EMBEDDING_CONFIG,
|
|
13
|
+
load_toml_config,
|
|
14
|
+
)
|
|
15
|
+
from bertrend.demos.demos_utils.state_utils import (
|
|
16
|
+
register_widget,
|
|
17
|
+
save_widget_state,
|
|
18
|
+
SessionStateManager,
|
|
19
|
+
register_multiple_widget,
|
|
20
|
+
reset_widget_state,
|
|
21
|
+
)
|
|
22
|
+
from bertrend.config.parameters import (
|
|
23
|
+
EMBEDDING_DTYPES,
|
|
24
|
+
LANGUAGES,
|
|
25
|
+
ENGLISH_EMBEDDING_MODELS,
|
|
26
|
+
FRENCH_EMBEDDING_MODELS,
|
|
27
|
+
REPRESENTATION_MODELS,
|
|
28
|
+
MMR_REPRESENTATION_MODEL,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
from bertrend.demos.demos_utils.icons import INFO_ICON
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def display_local_embeddings():
|
|
35
|
+
"""UI settings for local embedding service"""
|
|
36
|
+
register_multiple_widget("language", "embedding_dtype", "embedding_model_name")
|
|
37
|
+
|
|
38
|
+
language = st.selectbox(
|
|
39
|
+
"Select Language",
|
|
40
|
+
LANGUAGES,
|
|
41
|
+
key="language",
|
|
42
|
+
on_change=_on_language_change,
|
|
43
|
+
)
|
|
44
|
+
st.selectbox(
|
|
45
|
+
"Embedding Dtype",
|
|
46
|
+
EMBEDDING_DTYPES,
|
|
47
|
+
key="embedding_dtype",
|
|
48
|
+
on_change=save_widget_state,
|
|
49
|
+
)
|
|
50
|
+
embedding_models = (
|
|
51
|
+
ENGLISH_EMBEDDING_MODELS if language == "English" else FRENCH_EMBEDDING_MODELS
|
|
52
|
+
)
|
|
53
|
+
st.selectbox(
|
|
54
|
+
"Embedding Model",
|
|
55
|
+
options=embedding_models,
|
|
56
|
+
key="embedding_model_name",
|
|
57
|
+
on_change=save_widget_state,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _on_language_change():
|
|
62
|
+
save_widget_state()
|
|
63
|
+
# required to handle multi-page app and restore_state call:
|
|
64
|
+
reset_widget_state("embedding_model_name")
|
|
65
|
+
st.session_state.pop("embedding_model_name")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def display_remote_embeddings():
|
|
69
|
+
"""UI settings for remote embedding service"""
|
|
70
|
+
register_widget("embedding_service_url")
|
|
71
|
+
if "embedding_service_url" not in st.session_state:
|
|
72
|
+
st.session_state["embedding_service_url"] = EMBEDDING_CONFIG["url"]
|
|
73
|
+
st.text_input(
|
|
74
|
+
"Embedding service URL",
|
|
75
|
+
key="embedding_service_url",
|
|
76
|
+
on_change=save_widget_state,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def display_embedding_hyperparameters():
|
|
81
|
+
"""UI settings for embedding hyperparameters"""
|
|
82
|
+
# Embedding model parameters
|
|
83
|
+
with st.expander("Embedding Model Settings", expanded=False):
|
|
84
|
+
register_widget("embedding_service_type")
|
|
85
|
+
if "embedding_service_type" not in st.session_state:
|
|
86
|
+
st.session_state["embedding_service_type"] = "remote"
|
|
87
|
+
st.segmented_control(
|
|
88
|
+
"Embedding service",
|
|
89
|
+
selection_mode="single",
|
|
90
|
+
key="embedding_service_type",
|
|
91
|
+
options=["local", "remote"],
|
|
92
|
+
on_change=save_widget_state,
|
|
93
|
+
)
|
|
94
|
+
if st.session_state["embedding_service_type"] == "local":
|
|
95
|
+
display_local_embeddings()
|
|
96
|
+
else:
|
|
97
|
+
display_remote_embeddings()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def display_bertopic_hyperparameters():
|
|
101
|
+
# BERTopic model parameters
|
|
102
|
+
with st.expander("BERTopic Model Settings", expanded=False):
|
|
103
|
+
# If BERTopic config is already in session state, use it
|
|
104
|
+
if "bertopic_config" in st.session_state:
|
|
105
|
+
toml_txt = st.session_state["bertopic_config"]
|
|
106
|
+
# Else get BERTopic default configuration
|
|
107
|
+
else:
|
|
108
|
+
with open(BERTOPIC_DEFAULT_CONFIG_PATH, "r") as f:
|
|
109
|
+
# Load default parameter the first time
|
|
110
|
+
toml_txt = f.read()
|
|
111
|
+
|
|
112
|
+
# Add code editor to edit the config file
|
|
113
|
+
st.write(INFO_ICON + " CTRL + Enter to update")
|
|
114
|
+
config_editor = code_editor(
|
|
115
|
+
toml_txt,
|
|
116
|
+
lang="toml",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# If code is edited, update config
|
|
120
|
+
if config_editor["text"] != "":
|
|
121
|
+
st.session_state["bertopic_config"] = config_editor["text"]
|
|
122
|
+
# Else use default config
|
|
123
|
+
else:
|
|
124
|
+
st.session_state["bertopic_config"] = toml_txt
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def display_bertrend_hyperparameters():
|
|
128
|
+
"""UI settings for Bertrend hyperparameters"""
|
|
129
|
+
with st.expander("BERTrend Model Settings", expanded=False):
|
|
130
|
+
# Get BERTrend default configuration
|
|
131
|
+
with open(BERTREND_DEFAULT_CONFIG_PATH, "r") as f:
|
|
132
|
+
# Load default parameter the first time
|
|
133
|
+
toml_txt = f.read()
|
|
134
|
+
|
|
135
|
+
# Add code editor to edit the config file
|
|
136
|
+
st.write(INFO_ICON + " CTRL + Enter to update")
|
|
137
|
+
config_editor = code_editor(toml_txt, lang="toml")
|
|
138
|
+
|
|
139
|
+
# If code is edited, update config
|
|
140
|
+
if config_editor["text"] != "":
|
|
141
|
+
st.session_state["bertrend_config"] = config_editor["text"]
|
|
142
|
+
# Else use default config
|
|
143
|
+
else:
|
|
144
|
+
st.session_state["bertrend_config"] = toml_txt
|
|
145
|
+
|
|
146
|
+
# Save granularity in session state as it is re-used in other components
|
|
147
|
+
st.session_state["granularity"] = load_toml_config(
|
|
148
|
+
st.session_state["bertrend_config"]
|
|
149
|
+
)["granularity"]
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def display_representation_model_options():
|
|
153
|
+
"""UI settings for representation model options"""
|
|
154
|
+
with st.expander("Representation model selection", expanded=False):
|
|
155
|
+
register_widget("representation_models")
|
|
156
|
+
selected_models = st.multiselect(
|
|
157
|
+
label="Select representation models",
|
|
158
|
+
options=REPRESENTATION_MODELS,
|
|
159
|
+
default=MMR_REPRESENTATION_MODEL,
|
|
160
|
+
key="representation_models",
|
|
161
|
+
on_change=save_widget_state,
|
|
162
|
+
)
|
|
@@ -0,0 +1,99 @@
|
|
|
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 typing import Any
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pandas as pd
|
|
9
|
+
|
|
10
|
+
import streamlit as st
|
|
11
|
+
|
|
12
|
+
STATE_KEYS = "state_keys"
|
|
13
|
+
WIDGET_STATE = "widget_state"
|
|
14
|
+
|
|
15
|
+
# Set of util functions to manage the state of widgets in streamlit
|
|
16
|
+
# - at the beginning of each page: add restore_widget_state() to restore the last selected values
|
|
17
|
+
# - each time a widget is used, call *before* register_widget with the *key* of the widget as argument
|
|
18
|
+
# and use the call_back of the widget (for example on_change) to call save_widget_state
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def register_widget(key: str):
|
|
22
|
+
"""Keeps track of widget state in case of multi-pages Streamlit app. It shall be called with the key of
|
|
23
|
+
the widget before the widget creation."""
|
|
24
|
+
if STATE_KEYS not in st.session_state.keys():
|
|
25
|
+
st.session_state[STATE_KEYS] = []
|
|
26
|
+
if key not in st.session_state[STATE_KEYS]:
|
|
27
|
+
st.session_state[STATE_KEYS].append(key)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def reset_widget_state(key: str):
|
|
31
|
+
"""Removes the widget state from session state."""
|
|
32
|
+
if WIDGET_STATE in st.session_state.keys():
|
|
33
|
+
st.session_state[WIDGET_STATE].pop(key)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def register_multiple_widget(*keys: str):
|
|
37
|
+
"""Keeps track of widget state in case of multi-pages Streamlit app. It shall be called with the key of
|
|
38
|
+
the widget before the widget creation."""
|
|
39
|
+
for key in keys:
|
|
40
|
+
register_widget(key)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def save_widget_state():
|
|
44
|
+
"""(Callback) Function to save the widget state in case of multi-pages Streamlit app.
|
|
45
|
+
It shall be used as the call_back of the widget (for example on_change)."""
|
|
46
|
+
if STATE_KEYS in st.session_state.keys():
|
|
47
|
+
st.session_state[WIDGET_STATE] = {
|
|
48
|
+
key: st.session_state[key]
|
|
49
|
+
for key in st.session_state[STATE_KEYS]
|
|
50
|
+
if key in st.session_state
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def restore_widget_state():
|
|
55
|
+
"""Function to restore widget states in case of multi-pages Streamlit app.
|
|
56
|
+
It shall be called at the start of each page."""
|
|
57
|
+
if WIDGET_STATE in st.session_state.keys():
|
|
58
|
+
for k, v in st.session_state[WIDGET_STATE].items():
|
|
59
|
+
st.session_state[k] = v
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class SessionStateManager:
|
|
63
|
+
"""Class to ease the management of Streamlit session state"""
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def get(key: str, default: Any = None) -> Any:
|
|
67
|
+
return st.session_state.get(key, default)
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
def set(key: str, value: Any) -> None:
|
|
71
|
+
st.session_state[key] = value
|
|
72
|
+
|
|
73
|
+
@staticmethod
|
|
74
|
+
def get_or_set(key: str, default: Any) -> Any:
|
|
75
|
+
if key not in st.session_state:
|
|
76
|
+
st.session_state[key] = default
|
|
77
|
+
return st.session_state[key]
|
|
78
|
+
|
|
79
|
+
@staticmethod
|
|
80
|
+
def get_multiple(*keys: str) -> dict[str, Any]:
|
|
81
|
+
return {key: st.session_state.get(key) for key in keys}
|
|
82
|
+
|
|
83
|
+
@staticmethod
|
|
84
|
+
def set_multiple(**kwargs: Any) -> None:
|
|
85
|
+
for key, value in kwargs.items():
|
|
86
|
+
st.session_state[key] = value
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def clear() -> None:
|
|
90
|
+
st.session_state.clear()
|
|
91
|
+
|
|
92
|
+
@staticmethod
|
|
93
|
+
def get_dataframe(key: str) -> pd.DataFrame | None:
|
|
94
|
+
df = st.session_state.get(key)
|
|
95
|
+
return df if isinstance(df, pd.DataFrame) else None
|
|
96
|
+
|
|
97
|
+
@staticmethod
|
|
98
|
+
def get_embeddings(key: str = "embeddings") -> np.ndarray | None:
|
|
99
|
+
return st.session_state.get(key)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2024, RTE (https://www.rte-france.com)
|
|
3
|
+
# See AUTHORS.txt
|
|
4
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
5
|
+
# This file is part of BERTrend.
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
# Starts the Summarizer app (a comparison of various method of text summarization)
|
|
9
|
+
CUDA_VISIBLE_DEVICES=0 OPENAI_API_KEY=$AZURE_WATTELSE_OPENAI_API_KEY OPENAI_ENDPOINT=$AZURE_WATTELSE_OPENAI_ENDPOINT OPENAI_DEFAULT_MODEL_NAME=$AZURE_WATTELSE_OPENAI_DEFAULT_MODEL_NAME streamlit run --theme.primaryColor royalblue summarization/summarizer_app.py
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2024, RTE (https://www.rte-france.com)
|
|
3
|
+
# See AUTHORS.txt
|
|
4
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
5
|
+
# This file is part of BERTrend.
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
# Starts the Topic Analysis application
|
|
9
|
+
CUDA_VISIBLE_DEVICES=0 streamlit run --theme.primaryColor royalblue topic_analysis/app.py
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2024, RTE (https://www.rte-france.com)
|
|
3
|
+
# See AUTHORS.txt
|
|
4
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
5
|
+
# This file is part of BERTrend.
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
# Starts the Trend Analysis application
|
|
9
|
+
CUDA_VISIBLE_DEVICES=0 streamlit run --theme.primaryColor royalblue weak_signals/app.py
|
|
@@ -0,0 +1,98 @@
|
|
|
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
|
+
import os
|
|
6
|
+
|
|
7
|
+
import streamlit as st
|
|
8
|
+
from loguru import logger
|
|
9
|
+
|
|
10
|
+
from bertrend.demos.demos_utils.icons import WARNING_ICON
|
|
11
|
+
from bertrend.services.summary.abstractive_summarizer import AbstractiveSummarizer
|
|
12
|
+
from bertrend.services.summary.chatgpt_summarizer import GPTSummarizer
|
|
13
|
+
from bertrend.services.summary.extractive_summarizer import (
|
|
14
|
+
EnhancedExtractiveSummarizer,
|
|
15
|
+
ExtractiveSummarizer,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
SUMMARIZER_OPTIONS_MAPPER = {
|
|
19
|
+
"GPTSummarizer": GPTSummarizer,
|
|
20
|
+
"EnhancedExtractiveSummarizer": EnhancedExtractiveSummarizer,
|
|
21
|
+
"ExtractiveSummarizer": ExtractiveSummarizer,
|
|
22
|
+
"AbstractiveSummarizer": AbstractiveSummarizer,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
DEFAULT_TEXT = """RTE, sigle du Réseau de transport d'électricité, est le gestionnaire de réseau de transport français responsable du réseau public de transport d'électricité haute tension en France métropolitaine (la Corse n'est pas gérée par RTE). Sa mission fondamentale est d’assurer à tous ses clients l’accès à une alimentation électrique économique, sûre et propre. RTE connecte ses clients par une infrastructure adaptée et leur fournit tous les outils et services qui leur permettent d’en tirer parti pour répondre à leurs besoins. À cet effet, RTE exploite, maintient et développe le réseau à haute et très haute tension. Il est le garant du bon fonctionnement et de la sûreté du système électrique. RTE achemine l’électricité entre les fournisseurs d’électricité (français et européens) et les consommateurs, qu’ils soient distributeurs d’électricité ou industriels directement raccordés au réseau de transport. Plus de 105 000 km de lignes comprises entre 45 000 et 400 000 volts et 50 lignes transfrontalières connectent le réseau français à 33 pays européens, offrant ainsi des opportunités d’échanges d’électricité essentiels pour l’optimisation économique du système électrique.
|
|
26
|
+
|
|
27
|
+
RTE fait partie du Réseau européen des gestionnaires de réseau de transport d’électricité (ENTSO-E), organisation qui regroupe les gestionnaires de réseaux de transport à haute et très haute tension de 35 pays3. Elle découle de la fusion le 1er juillet 2009 de l'UCTE, de BALTSO, de NORDEL, d'ATSOI et d'UKTSOA.
|
|
28
|
+
|
|
29
|
+
Les réseaux de ces sociétés desservent, via les réseaux de distribution, une population d'environ 500 millions de personnes. Ils se décomposent en cinq grands systèmes synchrones : l'Europe continentale (à laquelle est rattachée la Turquie), les pays baltes, les pays nordiques, l'Irlande et la Grande-Bretagne.
|
|
30
|
+
|
|
31
|
+
Les lignes à basse et moyenne tension françaises ne sont pas du ressort de RTE. Elles sont essentiellement exploitées par Enedis (anciennement ERDF, filiale de distribution électrique d'EDF), mais aussi par d'autres entreprises locales de distribution (ELD) comme Électricité de Strasbourg, l'Usine d'électricité de Metz, ou encore Gascogne Énergies Services à Aire-sur-l’Adour dans les Landes."""
|
|
32
|
+
|
|
33
|
+
models = {}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@st.cache_resource
|
|
37
|
+
def get_summarizer(summary_model):
|
|
38
|
+
"""Instantiates models once, keep them in memory"""
|
|
39
|
+
kwargs = {}
|
|
40
|
+
if summary_model == "GPTSummarizer":
|
|
41
|
+
kwargs["api_key"] = st.session_state.openai_api_key
|
|
42
|
+
kwargs["endpoint"] = st.session_state.openai_endpoint
|
|
43
|
+
|
|
44
|
+
summarizer_class = SUMMARIZER_OPTIONS_MAPPER[summary_model]
|
|
45
|
+
return summarizer_class(**kwargs)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def app():
|
|
49
|
+
st.title("Comparison of summarizers")
|
|
50
|
+
|
|
51
|
+
st.warning(
|
|
52
|
+
"Warning: be sure that when using a GPT summarizer, the server is on Azure or local. "
|
|
53
|
+
"Otherwise, use it EXCLUSIVELY on public data.",
|
|
54
|
+
icon=WARNING_ICON,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
summary_model = st.selectbox(
|
|
58
|
+
"summary model", SUMMARIZER_OPTIONS_MAPPER.keys(), key="summary_model"
|
|
59
|
+
)
|
|
60
|
+
summary_ratio = (
|
|
61
|
+
st.number_input(
|
|
62
|
+
"summary ratio", min_value=1, max_value=100, value=20, key="summary_ratio"
|
|
63
|
+
)
|
|
64
|
+
/ 100
|
|
65
|
+
)
|
|
66
|
+
st.text_input(
|
|
67
|
+
"Openai API key",
|
|
68
|
+
key="openai_api_key",
|
|
69
|
+
value=os.getenv("OPENAI_API_KEY"),
|
|
70
|
+
type="password",
|
|
71
|
+
)
|
|
72
|
+
st.text_input(
|
|
73
|
+
"Openai endpoint", key="openai_endpoint", value=os.getenv("OPENAI_ENDPOINT")
|
|
74
|
+
)
|
|
75
|
+
st.text_input(
|
|
76
|
+
"Openai model name",
|
|
77
|
+
key="openai_model_name",
|
|
78
|
+
value=os.getenv("OPENAI_DEFAULT_MODEL_NAME"),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
col1, col2 = st.columns(2)
|
|
82
|
+
with col1:
|
|
83
|
+
st.text_area("Input text", DEFAULT_TEXT, height=250, key="text")
|
|
84
|
+
with col2:
|
|
85
|
+
st.text_area("Summary", "", height=250, key="summary")
|
|
86
|
+
|
|
87
|
+
def on_click():
|
|
88
|
+
summarizer = get_summarizer(summary_model)
|
|
89
|
+
st.session_state.summary = summarizer.generate_summary(
|
|
90
|
+
st.session_state.text, max_length_ratio=summary_ratio
|
|
91
|
+
)
|
|
92
|
+
logger.debug(st.session_state.summary)
|
|
93
|
+
|
|
94
|
+
st.button("Summarize", on_click=on_click)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
if __name__ == "__main__":
|
|
98
|
+
app()
|
|
@@ -0,0 +1,87 @@
|
|
|
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 torch
|
|
7
|
+
|
|
8
|
+
# workaround with streamlit to avoid errors Examining the path of torch.classes raised: Tried to instantiate class 'path.path’, but it does not exist! Ensure that it is registered via torch::class
|
|
9
|
+
torch.classes.__path__ = []
|
|
10
|
+
|
|
11
|
+
import locale
|
|
12
|
+
|
|
13
|
+
import streamlit as st
|
|
14
|
+
|
|
15
|
+
from bertrend.demos.demos_utils.icons import (
|
|
16
|
+
SAVE_ICON,
|
|
17
|
+
TOPIC_EXPLORATION_ICON,
|
|
18
|
+
TOPIC_VISUALIZATION_ICON,
|
|
19
|
+
TEMPORAL_VISUALIZATION_ICON,
|
|
20
|
+
NEWSLETTER_ICON,
|
|
21
|
+
)
|
|
22
|
+
from bertrend.demos.demos_utils.state_utils import restore_widget_state
|
|
23
|
+
|
|
24
|
+
TITLE = "BERTrend - Topic Analysis demo"
|
|
25
|
+
LAYOUT = "wide"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# Set locale for French date names
|
|
29
|
+
locale.setlocale(locale.LC_TIME, "fr_FR.UTF-8")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def define_pages():
|
|
33
|
+
data_page = st.Page(
|
|
34
|
+
page="demo_pages/training_page.py",
|
|
35
|
+
title="Data loading & model training",
|
|
36
|
+
icon=SAVE_ICON,
|
|
37
|
+
)
|
|
38
|
+
topic_exploration_page = st.Page(
|
|
39
|
+
page="demo_pages/explore_topics.py",
|
|
40
|
+
title="Topic exploration",
|
|
41
|
+
icon=TOPIC_EXPLORATION_ICON,
|
|
42
|
+
)
|
|
43
|
+
topic_visualization_page = st.Page(
|
|
44
|
+
page="demo_pages/topic_visualizations.py",
|
|
45
|
+
title="Topic visualization",
|
|
46
|
+
icon=TOPIC_VISUALIZATION_ICON,
|
|
47
|
+
)
|
|
48
|
+
temporal_visualization_page = st.Page(
|
|
49
|
+
page="demo_pages/temporal_visualizations.py",
|
|
50
|
+
title="Temporal visualization",
|
|
51
|
+
icon=TEMPORAL_VISUALIZATION_ICON,
|
|
52
|
+
)
|
|
53
|
+
newsletter_page = st.Page(
|
|
54
|
+
page="demo_pages/newsletters_generation.py",
|
|
55
|
+
title="Newsletter generation",
|
|
56
|
+
icon=NEWSLETTER_ICON,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
pg = st.navigation(
|
|
60
|
+
{
|
|
61
|
+
"Topic Analysis": [
|
|
62
|
+
data_page,
|
|
63
|
+
topic_exploration_page,
|
|
64
|
+
topic_visualization_page,
|
|
65
|
+
temporal_visualization_page,
|
|
66
|
+
],
|
|
67
|
+
"Application example": [newsletter_page],
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
return pg
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def main():
|
|
74
|
+
pg = define_pages()
|
|
75
|
+
st.set_page_config(
|
|
76
|
+
page_title=TITLE,
|
|
77
|
+
layout=LAYOUT,
|
|
78
|
+
initial_sidebar_state="expanded",
|
|
79
|
+
page_icon=":part_alternation_mark:",
|
|
80
|
+
)
|
|
81
|
+
# Restore widget state
|
|
82
|
+
restore_widget_state()
|
|
83
|
+
pg.run()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
if __name__ == "__main__":
|
|
87
|
+
main()
|
|
@@ -0,0 +1,69 @@
|
|
|
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
|
+
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
7
|
+
import streamlit as st
|
|
8
|
+
from bertopic import BERTopic
|
|
9
|
+
|
|
10
|
+
from bertrend.utils.data_loading import (
|
|
11
|
+
TIMESTAMP_COLUMN,
|
|
12
|
+
GROUPED_TIMESTAMP_COLUMN,
|
|
13
|
+
TEXT_COLUMN,
|
|
14
|
+
TITLE_COLUMN,
|
|
15
|
+
URL_COLUMN,
|
|
16
|
+
CITATION_COUNT_COL,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _make_dynamic_topics_split(df: pd.DataFrame, nr_bins: int):
|
|
21
|
+
"""
|
|
22
|
+
Split docs into nr_bins and generate a llm_utils timestamp label into a new column
|
|
23
|
+
"""
|
|
24
|
+
df = df.sort_values(TIMESTAMP_COLUMN, ascending=False)
|
|
25
|
+
split_df = np.array_split(df, nr_bins)
|
|
26
|
+
for split in split_df:
|
|
27
|
+
split[GROUPED_TIMESTAMP_COLUMN] = split[TIMESTAMP_COLUMN].max()
|
|
28
|
+
return pd.concat(split_df)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@st.cache_data
|
|
32
|
+
def compute_topics_over_time(
|
|
33
|
+
_topic_model: BERTopic,
|
|
34
|
+
df: pd.DataFrame,
|
|
35
|
+
nr_bins: int,
|
|
36
|
+
):
|
|
37
|
+
"""Computes topics over time."""
|
|
38
|
+
df = _make_dynamic_topics_split(df, nr_bins)
|
|
39
|
+
res = _topic_model.topics_over_time(
|
|
40
|
+
df[TEXT_COLUMN],
|
|
41
|
+
df[GROUPED_TIMESTAMP_COLUMN],
|
|
42
|
+
global_tuning=False,
|
|
43
|
+
)
|
|
44
|
+
return res
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def print_docs_for_specific_topic(
|
|
48
|
+
df: pd.DataFrame, topics: list[int], topic_number: int
|
|
49
|
+
):
|
|
50
|
+
"""
|
|
51
|
+
Print documents for a specific topic
|
|
52
|
+
"""
|
|
53
|
+
columns_list = [
|
|
54
|
+
col
|
|
55
|
+
for col in [
|
|
56
|
+
TITLE_COLUMN,
|
|
57
|
+
TEXT_COLUMN,
|
|
58
|
+
URL_COLUMN,
|
|
59
|
+
TIMESTAMP_COLUMN,
|
|
60
|
+
CITATION_COUNT_COL,
|
|
61
|
+
]
|
|
62
|
+
if col in df.keys()
|
|
63
|
+
]
|
|
64
|
+
df = df.loc[pd.Series(topics) == topic_number][columns_list]
|
|
65
|
+
for _, doc in df.iterrows():
|
|
66
|
+
st.write(f"[{doc.title}]({doc.url})")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# TODO: Remove "put embeddings in cache" option since it's unadvised due to the large size of embeddings returned by embedding model (sentence and token embeddings)
|