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,320 @@
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
+
7
+ from pathlib import Path
8
+ from loguru import logger
9
+
10
+ from bertopic import BERTopic
11
+ from bertopic.representation import (
12
+ MaximalMarginalRelevance,
13
+ OpenAI,
14
+ KeyBERTInspired,
15
+ BaseRepresentation,
16
+ )
17
+ from bertopic.vectorizers import ClassTfidfTransformer
18
+
19
+ from hdbscan import HDBSCAN
20
+ from sklearn.feature_extraction.text import CountVectorizer
21
+ from umap import UMAP
22
+ from sentence_transformers import SentenceTransformer
23
+
24
+ from bertrend import load_toml_config, BERTOPIC_DEFAULT_CONFIG_PATH, LLM_CONFIG
25
+ from bertrend.llm_utils.openai_client import OpenAI_Client
26
+ from bertrend.llm_utils.prompts import BERTOPIC_FRENCH_TOPIC_REPRESENTATION_PROMPT
27
+ from bertrend.config.parameters import (
28
+ STOPWORDS,
29
+ ENGLISH_STOPWORDS,
30
+ KEYBERT_TOP_N_WORDS,
31
+ KEYBERT_NR_REPR_DOCS,
32
+ KEYBERT_NR_CANDIDATE_WORDS,
33
+ OPENAI_NR_DOCS,
34
+ MMR_REPRESENTATION_MODEL,
35
+ OPENAI_REPRESENTATION_MODEL,
36
+ KEYBERTINSPIRED_REPRESENTATION_MODEL,
37
+ )
38
+
39
+
40
+ class BERTopicModelOutput:
41
+ """Wrapper to encapsulate all results related to topic model output"""
42
+
43
+ def __init__(self, topic_model: BERTopic):
44
+ """
45
+ - a BERTopic model
46
+ - a list of topics indices corresponding to the documents
47
+ - an array of probabilities
48
+ - the document embeddings
49
+ - the token embeddings of each document
50
+ - the tokens (str) of each documents
51
+ """
52
+ # Topic model
53
+ self.topic_model = topic_model
54
+ # List of topics indices corresponding to the documents
55
+ self.topics = None
56
+ # Array of probabilities
57
+ self.probs = None
58
+ # Document embeddings
59
+ self.embeddings = None
60
+ # Token embeddings of each document
61
+ self.token_embeddings = None
62
+ # Tokens (str) of each document
63
+ self.token_strings = None
64
+
65
+
66
+ class BERTopicModel:
67
+ """
68
+ Utility class to manage and configure BERTopic instances with custom parameters.
69
+ """
70
+
71
+ def __init__(self, config: str | Path | dict = BERTOPIC_DEFAULT_CONFIG_PATH):
72
+ """
73
+ Initialize a class from a TOML config file.
74
+
75
+ Parameters
76
+ ----------
77
+ config : str or Path or dict, default=BERTOPIC_DEFAULT_CONFIG_PATH
78
+ Configuration source, which can be:
79
+ - a `str` representing the TOML file
80
+ - a `Path` to a TOML file
81
+ - a `dict` (with the same structure of the default config) containing values
82
+ to be overridden compared to the default configuration
83
+
84
+ Notes
85
+ -----
86
+ To see file format and list of parameters: bertrend/config/topic_model_default_config.toml
87
+
88
+ Raises
89
+ ------
90
+ Exception
91
+ If the TOML config file cannot be loaded.
92
+ TypeError
93
+ If the config parameter is not a string, Path, or dict.
94
+ """
95
+ if isinstance(config, str | Path):
96
+ try:
97
+ self.config = load_toml_config(config)
98
+ except Exception as e:
99
+ raise Exception(f"Failed to load TOML config: {e}")
100
+ elif isinstance(config, dict):
101
+ # load default config
102
+ self.config = load_toml_config(BERTOPIC_DEFAULT_CONFIG_PATH)
103
+ # overrides keys with provided dict
104
+ for section, settings in config.items():
105
+ if section in config:
106
+ self.config[section].update(
107
+ settings
108
+ ) # Update the settings in that section
109
+ else:
110
+ self.config[section] = settings # If section doesn't exist, add it
111
+ else:
112
+ raise TypeError(
113
+ f"Config must be a string, Path or dict object, got: {type(config)}"
114
+ )
115
+
116
+ # Update config file (depending on language, etc.)
117
+ self._update_config()
118
+
119
+ # Initialize models based on those parameters
120
+ self._initialize_models()
121
+
122
+ # Get representation model
123
+ self.config["bertopic_model"]["representation_model"] = (
124
+ self._get_representation_models(
125
+ self.config["bertopic_model"]["representation_model"]
126
+ )
127
+ )
128
+
129
+ @classmethod
130
+ def get_default_config(cls) -> dict:
131
+ """
132
+ Helper function to get default configuration.
133
+
134
+ Returns
135
+ -------
136
+ dict
137
+ The default configuration dictionary loaded from the default config file.
138
+ """
139
+ return load_toml_config(BERTOPIC_DEFAULT_CONFIG_PATH)
140
+
141
+ def _update_config(self):
142
+ """
143
+ Update the config file depending on initially loaded parameters.
144
+ """
145
+ # Handle specific parameters
146
+ # Transform ngram_range into tuple
147
+ if self.config["vectorizer_model"].get("ngram_range"):
148
+ self.config["vectorizer_model"]["ngram_range"] = tuple(
149
+ self.config["vectorizer_model"]["ngram_range"]
150
+ )
151
+
152
+ # Load stop words list
153
+ if self.config["vectorizer_model"].get("stop_words"):
154
+ stop_words = (
155
+ STOPWORDS
156
+ if self.config["global"]["language"] == "French"
157
+ else ENGLISH_STOPWORDS
158
+ )
159
+ self.config["vectorizer_model"]["stop_words"] = stop_words
160
+
161
+ # BERTopic needs a "None" instead of an empty list, otherwise it'll attempt zeroshot topic modeling on an empty list
162
+ if not self.config["bertopic_model"].get("zeroshot_topic_list"): # empty list
163
+ self.config["bertopic_model"]["zeroshot_topic_list"] = None
164
+
165
+ def _initialize_models(self):
166
+ self.umap_model = UMAP(**self.config["umap_model"])
167
+
168
+ self.hdbscan_model = HDBSCAN(**self.config["hdbscan_model"])
169
+
170
+ self.vectorizer_model = CountVectorizer(**self.config["vectorizer_model"])
171
+
172
+ self.ctfidf_model = ClassTfidfTransformer(**self.config["ctfidf_model"])
173
+
174
+ self.mmr_model = MaximalMarginalRelevance(**self.config["mmr_model"])
175
+
176
+ def _initialize_openai_representation(self):
177
+ return OpenAI(
178
+ client=OpenAI_Client(
179
+ api_key=LLM_CONFIG["api_key"],
180
+ endpoint=LLM_CONFIG["endpoint"],
181
+ model=LLM_CONFIG["model"],
182
+ ).llm_client,
183
+ model=LLM_CONFIG["model"],
184
+ nr_docs=OPENAI_NR_DOCS,
185
+ prompt=(
186
+ BERTOPIC_FRENCH_TOPIC_REPRESENTATION_PROMPT
187
+ if self.config["global"]["language"] == "French"
188
+ else None
189
+ ),
190
+ chat=True,
191
+ )
192
+
193
+ @classmethod
194
+ def _initialize_keybert_representation(cls):
195
+ return KeyBERTInspired(
196
+ top_n_words=KEYBERT_TOP_N_WORDS,
197
+ nr_repr_docs=KEYBERT_NR_REPR_DOCS,
198
+ nr_candidate_words=KEYBERT_NR_CANDIDATE_WORDS,
199
+ )
200
+
201
+ def _get_representation_models(
202
+ self,
203
+ representation_model: list[str],
204
+ ) -> BaseRepresentation | list[BaseRepresentation]:
205
+ # NB. If OpenAI representation model is present, it will be used in separate step
206
+ model_map = {
207
+ MMR_REPRESENTATION_MODEL: self.mmr_model,
208
+ KEYBERTINSPIRED_REPRESENTATION_MODEL: self._initialize_keybert_representation(),
209
+ }
210
+ models = [
211
+ model_map[rep]
212
+ for rep in representation_model
213
+ if rep != OPENAI_REPRESENTATION_MODEL and rep in model_map
214
+ ]
215
+ self.use_openai_representation = (
216
+ OPENAI_REPRESENTATION_MODEL in representation_model
217
+ )
218
+
219
+ return models[0] if len(models) == 1 else models
220
+
221
+ def fit(
222
+ self,
223
+ docs: list[str],
224
+ embeddings: np.ndarray,
225
+ embedding_model: SentenceTransformer | str | None = None,
226
+ zeroshot_topic_list: list[str] | None = None,
227
+ zeroshot_min_similarity: float | None = None,
228
+ ) -> BERTopicModelOutput:
229
+ """
230
+ Create a TopicModelOutput model.
231
+
232
+ Parameters
233
+ ----------
234
+ docs : list[str]
235
+ List of documents.
236
+ embeddings : np.ndarray
237
+ Precomputed document embeddings.
238
+ embedding_model : SentenceTransformer or str or None, optional
239
+ Sentence transformer (or associated model name) model for embeddings.
240
+ zeroshot_topic_list : list[str] or None, optional
241
+ List of topics used for zeroshot classification.
242
+ zeroshot_min_similarity : float or None, optional
243
+ Parameter used for zeroshot classification.
244
+
245
+ Returns
246
+ -------
247
+ BERTopicModelOutput
248
+ A fitted BERTopic model output object containing the model and related data.
249
+
250
+ Raises
251
+ ------
252
+ Exception
253
+ If there's an error during the model creation or fitting process.
254
+ """
255
+ # Override zeroshot parameters if provided in method argument
256
+ if zeroshot_topic_list:
257
+ self.config["bertopic_model"]["zeroshot_topic_list"] = zeroshot_topic_list
258
+ if zeroshot_min_similarity is not None:
259
+ self.config["bertopic_model"][
260
+ "zeroshot_min_similarity"
261
+ ] = zeroshot_min_similarity
262
+ # Load and fit model
263
+ try:
264
+ logger.debug("\tInitializing BERTopic model")
265
+
266
+ topic_model = BERTopic(
267
+ embedding_model=embedding_model,
268
+ umap_model=self.umap_model,
269
+ hdbscan_model=self.hdbscan_model,
270
+ vectorizer_model=self.vectorizer_model,
271
+ ctfidf_model=self.ctfidf_model,
272
+ **self.config["bertopic_model"],
273
+ )
274
+ logger.success("\tBERTopic model instance created successfully")
275
+
276
+ logger.debug("\tFitting BERTopic model")
277
+ topics, probs = topic_model.fit_transform(docs, embeddings)
278
+
279
+ if not topic_model._outliers:
280
+ logger.warning("\tNo outliers to reduce.")
281
+ new_topics = topics
282
+ else:
283
+ logger.debug("\tReducing outliers")
284
+ new_topics = topic_model.reduce_outliers(
285
+ documents=docs,
286
+ topics=topics,
287
+ embeddings=embeddings,
288
+ strategy=self.config["reduce_outliers"]["strategy"],
289
+ )
290
+ logger.debug("\tUpdating topics")
291
+ topic_model.update_topics(
292
+ docs=docs,
293
+ topics=new_topics,
294
+ vectorizer_model=self.vectorizer_model,
295
+ ctfidf_model=self.ctfidf_model,
296
+ representation_model=self.config["bertopic_model"][
297
+ "representation_model"
298
+ ],
299
+ )
300
+
301
+ # If OpenAI model is present, apply it after reducing outliers
302
+ if self.use_openai_representation:
303
+ logger.info("\tApplying OpenAI representation model...")
304
+ backup_representation_model = topic_model.representation_model
305
+ topic_model.update_topics(
306
+ docs=docs,
307
+ topics=new_topics,
308
+ representation_model=self._initialize_openai_representation(),
309
+ )
310
+ topic_model.representation_model = backup_representation_model
311
+
312
+ logger.success("\tBERTopic model fitted successfully")
313
+ output = BERTopicModelOutput(topic_model)
314
+ output.topics = new_topics
315
+ output.probs = probs
316
+ return output
317
+ except Exception as e:
318
+ logger.error(f"\tError in create_topic_model: {str(e)}")
319
+ logger.exception("\tTraceback:")
320
+ raise