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.
Files changed (181) hide show
  1. bertrend/BERTopicModel.py +320 -0
  2. bertrend/BERTrend.py +1211 -0
  3. bertrend/__init__.py +59 -0
  4. bertrend/config/bertopic_default_config.toml +48 -0
  5. bertrend/config/bertrend_default_config.toml +16 -0
  6. bertrend/config/parameters.py +92 -0
  7. bertrend/config/services_default_config.toml +32 -0
  8. bertrend/demos/__init__.py +4 -0
  9. bertrend/demos/demos_utils/__init__.py +13 -0
  10. bertrend/demos/demos_utils/data_loading_component.py +267 -0
  11. bertrend/demos/demos_utils/embed_documents_component.py +52 -0
  12. bertrend/demos/demos_utils/icons.py +41 -0
  13. bertrend/demos/demos_utils/messages.py +11 -0
  14. bertrend/demos/demos_utils/parameters_component.py +162 -0
  15. bertrend/demos/demos_utils/state_utils.py +99 -0
  16. bertrend/demos/start_summarizer_app.sh +9 -0
  17. bertrend/demos/start_topic_analysis_app.sh +9 -0
  18. bertrend/demos/start_weak_signals_app.sh +9 -0
  19. bertrend/demos/summarization/__init__.py +4 -0
  20. bertrend/demos/summarization/summarizer_app.py +98 -0
  21. bertrend/demos/topic_analysis/__init__.py +4 -0
  22. bertrend/demos/topic_analysis/app.py +87 -0
  23. bertrend/demos/topic_analysis/app_utils.py +69 -0
  24. bertrend/demos/topic_analysis/demo_pages/__init__.py +4 -0
  25. bertrend/demos/topic_analysis/demo_pages/explore_topics.py +455 -0
  26. bertrend/demos/topic_analysis/demo_pages/newsletters_generation.py +178 -0
  27. bertrend/demos/topic_analysis/demo_pages/temporal_visualizations.py +573 -0
  28. bertrend/demos/topic_analysis/demo_pages/topic_visualizations.py +280 -0
  29. bertrend/demos/topic_analysis/demo_pages/training_page.py +219 -0
  30. bertrend/demos/topic_analysis/messages.py +13 -0
  31. bertrend/demos/weak_signals/__init__.py +4 -0
  32. bertrend/demos/weak_signals/app.py +510 -0
  33. bertrend/demos/weak_signals/messages.py +32 -0
  34. bertrend/demos/weak_signals/visualizations_utils.py +403 -0
  35. bertrend/llm_utils/__init__.py +4 -0
  36. bertrend/llm_utils/newsletter.css +131 -0
  37. bertrend/llm_utils/newsletter_features.py +272 -0
  38. bertrend/llm_utils/openai_client.py +235 -0
  39. bertrend/llm_utils/prompts.py +94 -0
  40. bertrend/metrics/__init__.py +4 -0
  41. bertrend/metrics/temporal_metrics_embedding.py +861 -0
  42. bertrend/metrics/topic_metrics.py +199 -0
  43. bertrend/resources/common_ngrams.json +23 -0
  44. bertrend/resources/stopwords-en.json +3 -0
  45. bertrend/resources/stopwords-fr.json +1 -0
  46. bertrend/resources/stopwords-rte.json +15 -0
  47. bertrend/services/__init__.py +4 -0
  48. bertrend/services/authentication.py +66 -0
  49. bertrend/services/embedding_client.py +154 -0
  50. bertrend/services/embedding_service.py +380 -0
  51. bertrend/services/summarizer.py +45 -0
  52. bertrend/services/summary/__init__.py +4 -0
  53. bertrend/services/summary/abstractive_summarizer.py +74 -0
  54. bertrend/services/summary/chatgpt_summarizer.py +67 -0
  55. bertrend/services/summary/extractive_summarizer.py +368 -0
  56. bertrend/services/summary/lexrank.py +126 -0
  57. bertrend/services/summary/prompts.py +43 -0
  58. bertrend/tests/__init__.py +4 -0
  59. bertrend/tests/test_abstractive_summarizer.py +140 -0
  60. bertrend/tests/test_bertrend.py +1091 -0
  61. bertrend/tests/test_cache_utils.py +111 -0
  62. bertrend/tests/test_chatgpt_summarizer.py +150 -0
  63. bertrend/tests/test_config_utils.py +54 -0
  64. bertrend/tests/test_data_loading.py +326 -0
  65. bertrend/tests/test_data_structure.py +53 -0
  66. bertrend/tests/test_embedding_client.py +546 -0
  67. bertrend/tests/test_extractive_summarizer.py +250 -0
  68. bertrend/tests/test_installation.py +183 -0
  69. bertrend/tests/test_newsletter_features.py +354 -0
  70. bertrend/tests/test_openai_client.py +210 -0
  71. bertrend/tests/test_representative_docs.py +125 -0
  72. bertrend/tests/test_summarizer.py +115 -0
  73. bertrend/tests/test_temporal_metrics_embedding.py +349 -0
  74. bertrend/tests/test_topic_description.py +159 -0
  75. bertrend/tests/test_topic_metrics.py +233 -0
  76. bertrend/tests/test_topic_model.py +285 -0
  77. bertrend/tests/test_trend_analysis_data_structure.py +174 -0
  78. bertrend/tests/test_trend_analysis_prompts.py +225 -0
  79. bertrend/tests/test_trend_analysis_visualizations.py +307 -0
  80. bertrend/tests/test_trend_analysis_weak_signals.py +598 -0
  81. bertrend/tests/test_utils_init.py +70 -0
  82. bertrend/tests/test_visualizations.py +306 -0
  83. bertrend/topic_analysis/__init__.py +4 -0
  84. bertrend/topic_analysis/data_structure.py +13 -0
  85. bertrend/topic_analysis/prompts.py +42 -0
  86. bertrend/topic_analysis/representative_docs.py +57 -0
  87. bertrend/topic_analysis/topic_description.py +66 -0
  88. bertrend/topic_analysis/visualizations.py +315 -0
  89. bertrend/trend_analysis/__init__.py +4 -0
  90. bertrend/trend_analysis/data_structure.py +78 -0
  91. bertrend/trend_analysis/prompts.py +229 -0
  92. bertrend/trend_analysis/signal_llm_template_en.html +181 -0
  93. bertrend/trend_analysis/signal_llm_template_fr.html +181 -0
  94. bertrend/trend_analysis/visualizations.py +605 -0
  95. bertrend/trend_analysis/weak_signals.py +425 -0
  96. bertrend/utils/__init__.py +31 -0
  97. bertrend/utils/cache_utils.py +31 -0
  98. bertrend/utils/config_utils.py +41 -0
  99. bertrend/utils/data_loading.py +329 -0
  100. bertrend-0.3.1.dist-info/AUTHORS.txt +15 -0
  101. bertrend-0.3.1.dist-info/LICENSE.md +373 -0
  102. bertrend-0.3.1.dist-info/METADATA +400 -0
  103. bertrend-0.3.1.dist-info/RECORD +181 -0
  104. bertrend-0.3.1.dist-info/WHEEL +4 -0
  105. bertrend_apps/__init__.py +4 -0
  106. bertrend_apps/common/__init__.py +4 -0
  107. bertrend_apps/common/crontab_utils.py +113 -0
  108. bertrend_apps/common/mail_utils.py +91 -0
  109. bertrend_apps/config/feeds/arxiv_feed.toml +15 -0
  110. bertrend_apps/config/feeds/decarbonation_feed.toml +15 -0
  111. bertrend_apps/config/feeds/llm_en_feed.toml +15 -0
  112. bertrend_apps/config/feeds/llm_feed.toml +16 -0
  113. bertrend_apps/config/feeds/nlp_feed.toml +15 -0
  114. bertrend_apps/config/feeds/rte_feed.toml +15 -0
  115. bertrend_apps/config/gmail_credentials.json +1 -0
  116. bertrend_apps/config/newsletters/arxiv_newsletter_from_last.toml +39 -0
  117. bertrend_apps/config/newsletters/arxiv_newsletter_from_scratch.toml +39 -0
  118. bertrend_apps/config/newsletters/decarbonation_newsletter_from_last.toml +38 -0
  119. bertrend_apps/config/newsletters/decarbonation_newsletter_from_scratch.toml +38 -0
  120. bertrend_apps/config/newsletters/llm_en_newsletter_from_last.toml +38 -0
  121. bertrend_apps/config/newsletters/llm_newsletter_from_last.toml +39 -0
  122. bertrend_apps/config/newsletters/nlp_newsletter_from_last.toml +38 -0
  123. bertrend_apps/config/newsletters/rte_newsletter_from_last.toml +38 -0
  124. bertrend_apps/config/newsletters/rte_newsletter_from_scratch.toml +38 -0
  125. bertrend_apps/data_provider/__init__.py +9 -0
  126. bertrend_apps/data_provider/__main__.py +237 -0
  127. bertrend_apps/data_provider/arxiv_provider.py +161 -0
  128. bertrend_apps/data_provider/bing_news_provider.py +82 -0
  129. bertrend_apps/data_provider/curebot_provider.py +105 -0
  130. bertrend_apps/data_provider/data_provider.py +194 -0
  131. bertrend_apps/data_provider/google_news_provider.py +94 -0
  132. bertrend_apps/data_provider/newscatcher_provider.py +74 -0
  133. bertrend_apps/data_provider/utils.py +165 -0
  134. bertrend_apps/exploration/__init__.py +4 -0
  135. bertrend_apps/exploration/curebot/__init__.py +4 -0
  136. bertrend_apps/exploration/curebot/app.py +45 -0
  137. bertrend_apps/exploration/curebot/app_utils.py +317 -0
  138. bertrend_apps/exploration/curebot/config.toml +33 -0
  139. bertrend_apps/exploration/curebot/import_extraction_article.ipynb +108 -0
  140. bertrend_apps/exploration/curebot/old_veille_analyse.py +298 -0
  141. bertrend_apps/exploration/curebot/prompts.py +24 -0
  142. bertrend_apps/exploration/curebot/start_newsletter_generator.sh +8 -0
  143. bertrend_apps/exploration/curebot/tabs/tab1.py +150 -0
  144. bertrend_apps/exploration/curebot/tabs/tab2.py +95 -0
  145. bertrend_apps/exploration/curebot/tabs/tab3.py +125 -0
  146. bertrend_apps/exploration/dataviz/Main_page.py +10 -0
  147. bertrend_apps/exploration/dataviz/__init__.py +4 -0
  148. bertrend_apps/exploration/dataviz/pages/1_Data_feeds.py +105 -0
  149. bertrend_apps/exploration/geolocalization/__init__.py +4 -0
  150. bertrend_apps/exploration/geolocalization/entity_utils.py +118 -0
  151. bertrend_apps/exploration/geolocalization/spacy/__init__.py +4 -0
  152. bertrend_apps/exploration/geolocalization/spacy/common_factory.py +142 -0
  153. bertrend_apps/exploration/geolocalization/spacy/dbpedia.py +206 -0
  154. bertrend_apps/exploration/geolocalization/spacy/nlp.config +37 -0
  155. bertrend_apps/exploration/geolocalization/spacy/utils.py +39 -0
  156. bertrend_apps/install_feeds_and_newsletters.py +29 -0
  157. bertrend_apps/newsletters/__init__.py +4 -0
  158. bertrend_apps/newsletters/__main__.py +277 -0
  159. bertrend_apps/prospective_demo/.streamlit/config.toml +3 -0
  160. bertrend_apps/prospective_demo/.streamlit/secrets.toml +9 -0
  161. bertrend_apps/prospective_demo/__init__.py +70 -0
  162. bertrend_apps/prospective_demo/app.py +111 -0
  163. bertrend_apps/prospective_demo/authentication.py +44 -0
  164. bertrend_apps/prospective_demo/dashboard_analysis.py +132 -0
  165. bertrend_apps/prospective_demo/dashboard_common.py +79 -0
  166. bertrend_apps/prospective_demo/dashboard_signals.py +226 -0
  167. bertrend_apps/prospective_demo/feeds_common.py +38 -0
  168. bertrend_apps/prospective_demo/feeds_config.py +261 -0
  169. bertrend_apps/prospective_demo/feeds_data.py +95 -0
  170. bertrend_apps/prospective_demo/i18n.py +136 -0
  171. bertrend_apps/prospective_demo/llm_utils.py +34 -0
  172. bertrend_apps/prospective_demo/models_info.py +361 -0
  173. bertrend_apps/prospective_demo/perf_utils.py +23 -0
  174. bertrend_apps/prospective_demo/process_new_data.py +348 -0
  175. bertrend_apps/prospective_demo/report_generation.py +214 -0
  176. bertrend_apps/prospective_demo/report_template.html +148 -0
  177. bertrend_apps/prospective_demo/report_utils.py +132 -0
  178. bertrend_apps/prospective_demo/start_demo.sh +9 -0
  179. bertrend_apps/prospective_demo/streamlit_utils.py +37 -0
  180. bertrend_apps/start_apps.sh +15 -0
  181. bertrend_apps/stop_apps.sh +11 -0
@@ -0,0 +1,317 @@
1
+ import tomllib
2
+ import json
3
+ from bertopic import BERTopic
4
+ import numpy as np
5
+ import pandas as pd
6
+ from pathlib import Path
7
+
8
+ import streamlit as st
9
+ from streamlit.runtime.uploaded_file_manager import UploadedFile
10
+ import plotly.graph_objects as go
11
+ from urllib.parse import urlparse
12
+
13
+ from bertrend import LLM_CONFIG
14
+ from bertrend.BERTopicModel import BERTopicModel
15
+ from bertrend.llm_utils.openai_client import OpenAI_Client
16
+ from bertrend.services.embedding_service import EmbeddingService
17
+ from bertrend_apps.exploration.curebot.prompts import (
18
+ TOPIC_DESCRIPTION_SYSTEM_PROMPT,
19
+ TOPIC_SUMMARY_SYSTEM_PROMPT,
20
+ )
21
+
22
+ # Get configuration file
23
+ CONFIG = tomllib.load(open(Path(__file__).parent / "config.toml", "rb"))
24
+
25
+ # Set curebot column name
26
+ URL_COLUMN = CONFIG["data"]["url_column"]
27
+ TEXT_COLUMN = CONFIG["data"]["text_column"]
28
+ TITLE_COLUMN = CONFIG["data"]["title_column"]
29
+ SOURCE_COLUMN = CONFIG["data"]["source_column"]
30
+ TIMESTAMP_COLUMN = CONFIG["data"]["timestamp_column"]
31
+ TAGS_COLUMN = CONFIG["data"]["tags_column"]
32
+
33
+ # Topics config
34
+ TOP_N_WORDS = CONFIG["topics"]["top_n_words"]
35
+
36
+ # Newsletter
37
+ NEWSLETTER_TEMPLATE = CONFIG["newsletter"]["template"]
38
+
39
+ # Load embdding model
40
+ EMBEDDING_SERVICE = EmbeddingService(local=False)
41
+
42
+
43
+ @st.cache_data(show_spinner=False)
44
+ def concat_data_from_files(files: list[UploadedFile]) -> pd.DataFrame:
45
+ """
46
+ Concatenate data from multiple Excel files into a single DataFrame.
47
+ """
48
+ df_list = []
49
+ for file in files:
50
+ df_list.append(pd.read_excel(file))
51
+ df = pd.concat(df_list, ignore_index=True)
52
+
53
+ return df
54
+
55
+
56
+ @st.cache_data(show_spinner=False)
57
+ def chunk_df(
58
+ df: pd.DataFrame, chunk_size: int = 100, overlap: int = 20
59
+ ) -> pd.DataFrame:
60
+ """
61
+ Split df texts into overlapping chunks while preserving other columns.
62
+
63
+ Parameters:
64
+ -----------
65
+ df : pandas.DataFrame
66
+ Input DataFrame containing text and other columns
67
+ chunk_size : int
68
+ Number of words in each chunk
69
+ overlap : int
70
+ Number of words to overlap between chunks
71
+
72
+ Returns:
73
+ --------
74
+ pandas.DataFrame
75
+ DataFrame with chunked texts, preserving other column values
76
+ """
77
+
78
+ # # Apply chunking to each row
79
+ # chunked_data = []
80
+ # for _, row in df.iterrows():
81
+ # chunked_data.extend(split_text_to_chunks(row, chunk_size, overlap))
82
+
83
+ # # Create new DataFrame from chunked data
84
+ # df_split = (
85
+ # pd.DataFrame(chunked_data)
86
+ # .sort_values(by=TIMESTAMP_COLUMN)
87
+ # .reset_index(drop=True)
88
+ # )
89
+
90
+ return df.copy()
91
+
92
+
93
+ @st.cache_data(show_spinner=False)
94
+ def get_embeddings(texts: list[str]) -> np.ndarray:
95
+ """Get embeddings for a list of texts."""
96
+ embeddings, _, _ = EMBEDDING_SERVICE.embed(texts)
97
+ return embeddings
98
+
99
+
100
+ @st.cache_data(show_spinner=False)
101
+ def fit_bertopic(
102
+ docs: list[str],
103
+ embeddings: np.ndarray,
104
+ min_articles_per_topic: int,
105
+ zeroshot_topic_list: list[str] | None = None,
106
+ ) -> tuple[BERTopic, list[int]]:
107
+ """
108
+ Fit BERTopic model on a list of documents and their embeddings.
109
+ """
110
+ # Override default parameters
111
+ bertopic_config = {"hdbscan_model": {"min_cluster_size": min_articles_per_topic}}
112
+ # Initialize topic model
113
+ topic_model = BERTopicModel(config=bertopic_config)
114
+
115
+ # Train topic model
116
+ topic_model_output = topic_model.fit(
117
+ docs=docs,
118
+ embeddings=embeddings,
119
+ zeroshot_topic_list=zeroshot_topic_list,
120
+ zeroshot_min_similarity=0.65,
121
+ )
122
+
123
+ return topic_model_output.topic_model, topic_model_output.topics
124
+
125
+
126
+ @st.cache_data(show_spinner=False)
127
+ def get_improved_topic_description(
128
+ df: pd.DataFrame, _topics_info: pd.DataFrame
129
+ ) -> list[str]:
130
+ """Get improved topic description using LLM."""
131
+ # Get llm client
132
+ llm_client = OpenAI_Client(
133
+ api_key=LLM_CONFIG["api_key"],
134
+ endpoint=LLM_CONFIG["endpoint"],
135
+ model=LLM_CONFIG["model"],
136
+ )
137
+
138
+ # List of improved topics description
139
+ improved_descriptions = []
140
+
141
+ # Loop over topics
142
+ for topic_number in range(len(_topics_info)):
143
+ topic_df = df[df["topics"] == topic_number]
144
+ user_prompt = "\n\n".join(
145
+ topic_df.apply(
146
+ lambda row: f"Titre : {row[TITLE_COLUMN]}\nArticle : {row[TEXT_COLUMN][0:2000]}...",
147
+ axis=1,
148
+ )
149
+ )
150
+ response = llm_client.generate(
151
+ user_prompt=user_prompt,
152
+ system_prompt=TOPIC_DESCRIPTION_SYSTEM_PROMPT,
153
+ response_format={"type": "json_object"},
154
+ )
155
+ improved_descriptions.append(json.loads(response)["titre"])
156
+
157
+ return improved_descriptions
158
+
159
+
160
+ @st.cache_data(show_spinner=False)
161
+ def create_newsletter(
162
+ df: pd.DataFrame,
163
+ topics_info: pd.DataFrame,
164
+ nb_topics: int,
165
+ nb_articles_per_topic: int,
166
+ ):
167
+ """
168
+ Create newsletter dict from containing the newsletter content in the following format:
169
+ {
170
+ "title": "Newsletter",
171
+ "min_timestamp": "Monday 01 January 2025",
172
+ "max_timestamp": "Sunday 07 January 2025",
173
+ "topics": [
174
+ {
175
+ "title": "Topic 1",
176
+ "keywords": "#keyword1 #keyword2 #keyword3",
177
+ "summary": "Summary of topic 1"
178
+ "articles": [
179
+ {
180
+ "title": "Article 1",
181
+ "url": "https://www.article1.com",
182
+ "timestamp": "Monday 01 January 2023",
183
+ "source": "Source 1"
184
+ },
185
+ ...
186
+ ]
187
+ },
188
+ ...
189
+ ]
190
+ }
191
+ """
192
+ # Create newsletter dict that stores the newsletter content
193
+ newsletter_dict = {"title": "Newsletter"}
194
+
195
+ # Get min and max date of the articles in the dataframe
196
+ newsletter_dict["min_timestamp"] = (
197
+ df[TIMESTAMP_COLUMN].min().strftime("%A %d %B %Y")
198
+ )
199
+ newsletter_dict["max_timestamp"] = (
200
+ df[TIMESTAMP_COLUMN].max().strftime("%A %d %B %Y")
201
+ )
202
+
203
+ newsletter_dict["topics"] = []
204
+ for i in range(nb_topics):
205
+ # Dict to store topic info
206
+ topic_dict = {}
207
+
208
+ # Get title and key words
209
+ topic_dict["title"] = topics_info.iloc[i]["llm_description"]
210
+ topic_dict["keywords"] = (
211
+ "#" + " #".join(topics_info.iloc[i]["Representation"]).strip()
212
+ )
213
+
214
+ # Filter df to get articles for the topic
215
+ topic_df = df[df["topics"] == i]
216
+
217
+ # Get first `newsletter_nb_articles_per_topic` articles for the topic
218
+ topic_df = topic_df.head(min(nb_articles_per_topic, len(topic_df)))
219
+
220
+ # Get a summary of the topic
221
+ user_prompt = "\n\n".join(
222
+ topic_df.apply(
223
+ lambda row: f"Titre : {row[TITLE_COLUMN]}\nArticle : {row[TEXT_COLUMN][0:2000]}...",
224
+ axis=1,
225
+ )
226
+ )
227
+ llm_client = OpenAI_Client(
228
+ api_key=LLM_CONFIG["api_key"],
229
+ endpoint=LLM_CONFIG["endpoint"],
230
+ model=LLM_CONFIG["model"],
231
+ )
232
+ response = llm_client.generate(
233
+ user_prompt=user_prompt,
234
+ system_prompt=TOPIC_SUMMARY_SYSTEM_PROMPT,
235
+ response_format={"type": "json_object"},
236
+ )
237
+ topic_dict["summary"] = json.loads(response)["résumé"]
238
+ topic_dict["articles"] = []
239
+ for _, row in topic_df.iterrows():
240
+ article_dict = {}
241
+ article_dict["title"] = row[TITLE_COLUMN]
242
+ article_dict["url"] = row[URL_COLUMN]
243
+ article_dict["timestamp"] = row[TIMESTAMP_COLUMN].strftime("%A %d %B %Y")
244
+ article_dict["source"] = row[SOURCE_COLUMN]
245
+ topic_dict["articles"].append(article_dict)
246
+ newsletter_dict["topics"].append(topic_dict)
247
+ return newsletter_dict
248
+
249
+
250
+ def display_source_distribution(
251
+ representative_df: pd.DataFrame, selected_sources: list[str]
252
+ ):
253
+ """Display the distribution of sources in a pie chart."""
254
+
255
+ source_counts = representative_df[URL_COLUMN].apply(get_website_name).value_counts()
256
+
257
+ # Create a list to store the 'pull' values for each slice
258
+ pull = []
259
+
260
+ # Determine which slices should be pulled out
261
+ for source in source_counts.index:
262
+ if source in selected_sources and "All" not in selected_sources:
263
+ pull.append(0.2)
264
+ else:
265
+ pull.append(0)
266
+
267
+ fig = go.Figure(
268
+ data=[
269
+ go.Pie(
270
+ labels=source_counts.index,
271
+ values=source_counts.values,
272
+ pull=pull,
273
+ textposition="inside",
274
+ textinfo="percent+label",
275
+ hole=0.3,
276
+ )
277
+ ]
278
+ )
279
+
280
+ fig.update_layout(
281
+ showlegend=False, height=600, width=500, margin=dict(t=0, b=0, l=0, r=0)
282
+ )
283
+
284
+ st.plotly_chart(fig, use_container_width=True)
285
+
286
+
287
+ def get_website_name(url):
288
+ """Extract website name from URL, handling None, NaN, and invalid URLs."""
289
+ if pd.isna(url) or url is None or isinstance(url, float):
290
+ return "Unknown Source"
291
+ try:
292
+ return (
293
+ urlparse(str(url)).netloc.replace("www.", "").split(".")[0]
294
+ or "Unknown Source"
295
+ )
296
+ except:
297
+ return "Unknown Source"
298
+
299
+
300
+ def display_representative_documents(filtered_df: pd.DataFrame):
301
+ """Display representative documents for the selected topic."""
302
+ with st.container(border=False, height=600):
303
+ for _, doc in filtered_df.iterrows():
304
+ website_name = get_website_name(doc[URL_COLUMN])
305
+ date = doc[TIMESTAMP_COLUMN].strftime("%A %d %b %Y %H:%M:%S")
306
+ snippet = (
307
+ doc[TEXT_COLUMN][:200] + "..."
308
+ if len(doc[TEXT_COLUMN]) > 200
309
+ else doc[TEXT_COLUMN]
310
+ )
311
+
312
+ content = f"""**{doc[TITLE_COLUMN]}**\n\n{date} | {'Unknown Source' if website_name == 'Unknown Source' else website_name}\n\n{snippet}"""
313
+
314
+ if website_name != "Unknown Source":
315
+ st.link_button(content, doc[URL_COLUMN])
316
+ else:
317
+ st.markdown(content)
@@ -0,0 +1,33 @@
1
+ [embedding]
2
+ model_name = "dangvantuan/french-document-embedding"
3
+
4
+ [data]
5
+ title_column = "Titre de la ressource"
6
+ text_column = "Contenu de la ressource"
7
+ url_column = "URL de la ressource"
8
+ source_column = "Domaine de la ressource"
9
+ timestamp_column = "Date de trouvaille"
10
+ tags_column = "Tags"
11
+
12
+ [topics]
13
+ top_n_words = 5
14
+
15
+ [newsletter]
16
+ template = """
17
+ # {{ title }}
18
+
19
+ *Du {{ min_timestamp }} au {{ max_timestamp }}.*
20
+
21
+ {% for topic in topics %}
22
+ ## {{ topic.title }}
23
+
24
+ **{{ topic.keywords }}**
25
+
26
+ {{ topic.summary }}
27
+
28
+ {% for article in topic.articles %}
29
+ * [{{ article.title }}]({{ article.url }}) - **{{ article.source }}** - *{{ article.timestamp }}*
30
+
31
+ {% endfor %}
32
+ {% endfor %}
33
+ """
@@ -0,0 +1,108 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "metadata": {},
5
+ "cell_type": "markdown",
6
+ "source": "Import articles extracted from Curebot tool",
7
+ "id": "3c7e4968da937628"
8
+ },
9
+ {
10
+ "metadata": {},
11
+ "cell_type": "code",
12
+ "source": [
13
+ "from pathlib import Path\n",
14
+ "import pandas as pd\n",
15
+ "from bertrend_apps.data_provider.curebot_provider import CurebotProvider\n",
16
+ "from loguru import logger\n",
17
+ "from typing import Dict, List, Optional\n",
18
+ "import dateparser\n"
19
+ ],
20
+ "id": "4a4893bf8790823b",
21
+ "outputs": [],
22
+ "execution_count": null
23
+ },
24
+ {
25
+ "metadata": {},
26
+ "cell_type": "code",
27
+ "source": "file_path = Path(\"/home/jerome/shared/synthèses veille énergie/Extraction article VA Energie mars-avril 24 pour IA.xlsx\")\n",
28
+ "id": "4f83820d787a541a",
29
+ "outputs": [],
30
+ "execution_count": null
31
+ },
32
+ {
33
+ "metadata": {},
34
+ "cell_type": "code",
35
+ "source": [
36
+ "# Extract full text from resources\n",
37
+ "provider = CurebotProvider(file_path)"
38
+ ],
39
+ "id": "4d3eda06ea551b8f",
40
+ "outputs": [],
41
+ "execution_count": null
42
+ },
43
+ {
44
+ "metadata": {},
45
+ "cell_type": "code",
46
+ "source": "articles = provider.get_articles()",
47
+ "id": "2609aa269898c1d5",
48
+ "outputs": [],
49
+ "execution_count": null
50
+ },
51
+ {
52
+ "metadata": {},
53
+ "cell_type": "code",
54
+ "source": [
55
+ "len(articles)\n",
56
+ "\n"
57
+ ],
58
+ "id": "35d63ab115d45ca0",
59
+ "outputs": [],
60
+ "execution_count": null
61
+ },
62
+ {
63
+ "metadata": {},
64
+ "cell_type": "code",
65
+ "source": "print(articles[0]['text'])",
66
+ "id": "9368a9ec655007cf",
67
+ "outputs": [],
68
+ "execution_count": null
69
+ },
70
+ {
71
+ "metadata": {},
72
+ "cell_type": "code",
73
+ "source": "output_file = '/home/jerome/shared/curebot_articles.jsonl'",
74
+ "id": "cd1e15ca55c99788",
75
+ "outputs": [],
76
+ "execution_count": null
77
+ },
78
+ {
79
+ "metadata": {},
80
+ "cell_type": "code",
81
+ "source": "provider.store_articles(articles, output_file)",
82
+ "id": "ca0e88d25f0d84c3",
83
+ "outputs": [],
84
+ "execution_count": null
85
+ }
86
+ ],
87
+ "metadata": {
88
+ "kernelspec": {
89
+ "display_name": "Python 3",
90
+ "language": "python",
91
+ "name": "python3"
92
+ },
93
+ "language_info": {
94
+ "codemirror_mode": {
95
+ "name": "ipython",
96
+ "version": 2
97
+ },
98
+ "file_extension": ".py",
99
+ "mimetype": "text/x-python",
100
+ "name": "python",
101
+ "nbconvert_exporter": "python",
102
+ "pygments_lexer": "ipython2",
103
+ "version": "2.7.6"
104
+ }
105
+ },
106
+ "nbformat": 4,
107
+ "nbformat_minor": 5
108
+ }