From 4601a07b766a59679ed5616041deeaf3ccd44aa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20Kardos?= Date: Mon, 14 Oct 2024 08:46:30 +0200 Subject: [PATCH 01/10] Relaxed numpy and sentence-transformers dependencies upwards --- turftopic/encoders/e5.py | 122 --------------------------------------- 1 file changed, 122 deletions(-) delete mode 100644 turftopic/encoders/e5.py diff --git a/turftopic/encoders/e5.py b/turftopic/encoders/e5.py deleted file mode 100644 index 2c29054..0000000 --- a/turftopic/encoders/e5.py +++ /dev/null @@ -1,122 +0,0 @@ -import warnings -from typing import Callable, Optional - -import numpy as np -from sentence_transformers import SentenceTransformer - - -class E5Encoder(SentenceTransformer): - """Encoder model oriented at using E5 models. - ```python - from turftopic.encoders import E5Encoder - from turftopic import GMM - model = GMM(10, encoder=E5Encoder(model_name="intfloat/multilingual-e5-small", prefix="query: ")) - ``` - Parameters - ---------- - model_name: str - Embedding model to use. - Either a SentenceTransformers pre-trained models or a model from HuggingFace Hub. - prefix : Optional[str] - A string that gets added to the start of each document (formats each document followingly: `f"{prefix}{text}"`). - Expected by most E5 models. Consult model cards on Hugging Face to see what prefix is expected by your specific model. - preprocessor : Optional[Callable] - A function that formats documents as desired. - Overwrites `prefix` and only applies if `prefix == None`. - Both input and output must be string. - First argument must be input text. - By default `None`. - Examples - -------- - Instructional models can also be used. - In this case, the documents should be prefixed with a one-sentence instruction that describes the task. - See Notes for available models and instruction suggestions. - ```python - from turftopic.encoders import E5Encoder - def add_instruct_prefix(document: str) -> str: - task_description = "YOUR_INSTRUCTION" - return f'Instruct: {task_description}\nQuery: {document}' - encoder = E5Encoder(model_name="intfloat/multilingual-e5-large-instruct", preprocessor=add_instruct_prefix) - model = GMM(10, encoder=encoder) - ``` - Or the same can be done using a `prefix` argument: - ```python - from turftopic.encoders import E5Encoder - from turftopic import GMM - prefix = "Instruct: YOUR_INSTRUCTION\nQuery: " - encoder = E5Encoder(model_name="intfloat/multilingual-e5-large-instruct", prefix=prefix) - model = GMM(10, encoder=encoder) - ``` - Notes - ----- - See available E5-based sentence transformers on Hugging Face Hub: - https://huggingface.co/models?library=sentence-transformers&sort=trending&search=e5 - Instruction templates: - https://github.com/microsoft/unilm/blob/9c0f1ff7ca53431fe47d2637dfe253643d94185b/e5/utils.py#L106 - """ - - def __init__( - self, - model_name: str, - prefix: Optional[str] = None, - preprocessor: Optional[Callable] = None, - **kwargs, - ): - super().__init__(model_name, **kwargs) - - # check for both prefix and preprocessor being specified - if prefix is not None and preprocessor is not None: - warnings.warn( - "Both `prefix` and `preprocessor` are specified. `preprocessor` will be ignored! " - "To avoid this warning, specify only one of them.", - ) - - # pick either prefix or preprocessor to do the job - if prefix is not None: - self.preprocessor = lambda x: f"{prefix}{x}" - else: - if preprocessor is not None: - try: - assert self._is_preprocessor_valid( - preprocessor=preprocessor - ) - self.preprocessor = preprocessor - except: - raise AssertionError( - "`preprocessor` failed vaildation. Please make sure your preprocessor returns type `str`." - ) - else: - raise ValueError( - "Either `prefix` or `preprocessor` must be specified." - ) - - @staticmethod - def _is_preprocessor_valid(preprocessor: Callable) -> bool: - """Check if preprocessor returns string.""" - input_0 = None - input_1 = "What are assertions? and why would you use them?" - output_0 = preprocessor(input_0) - output_1 = preprocessor(input_1) - - return all( - [ - isinstance(output_0, str), - isinstance(output_1, str), - ] - ) - - def encode(self, sentences: list[str], **kwargs) -> np.ndarray: - """ - Parameters - ---------- - sentences: list[str] - Input text. - Notes - ----- - See docs for `SentenceTransformer.encode` for available **kwargs - https://www.sbert.net/docs/package_reference/SentenceTransformer.html#sentence_transformers.SentenceTransformer.encode - """ - - sentences = [self.preprocessor(sentence) for sentence in sentences] - - return super().encode(sentences, **kwargs) From 831cd718e26da079ab6312000794429e321617be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20Kardos?= Date: Mon, 14 Oct 2024 08:47:37 +0200 Subject: [PATCH 02/10] Relaxed numpy and sentence-transformers dependencies upwards --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8dfa767..07268ef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,9 +14,9 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.9" -numpy = "^1.23.0" +numpy = ">=1.23.0" scikit-learn = "^1.2.0" -sentence-transformers = "^2.2.0" +sentence-transformers = ">=2.2.0" torch = "^2.1.0" scipy = "^1.10.0" rich = "^13.6.0" From 25dd60029e1d92b2abc1fd23f1b6b050b4674395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20Kardos?= Date: Mon, 14 Oct 2024 09:08:06 +0200 Subject: [PATCH 03/10] Added promptable embedding models to KeyNMF --- turftopic/encoders/__init__.py | 2 -- turftopic/models/_keynmf.py | 24 +++++++++++++++++++++--- turftopic/models/keynmf.py | 10 ++++++---- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/turftopic/encoders/__init__.py b/turftopic/encoders/__init__.py index 6797d16..9c89a74 100644 --- a/turftopic/encoders/__init__.py +++ b/turftopic/encoders/__init__.py @@ -2,12 +2,10 @@ from turftopic.encoders.cohere import CohereEmbeddings from turftopic.encoders.openai import OpenAIEmbeddings from turftopic.encoders.voyage import VoyageEmbeddings -from turftopic.encoders.e5 import E5Encoder __all__ = [ "CohereEmbeddings", "OpenAIEmbeddings", "VoyageEmbeddings", "ExternalEncoder", - "E5Encoder", ] diff --git a/turftopic/models/_keynmf.py b/turftopic/models/_keynmf.py index e48e585..e336a30 100644 --- a/turftopic/models/_keynmf.py +++ b/turftopic/models/_keynmf.py @@ -67,7 +67,7 @@ def fit_timeslice( return W, Ht.T, n_iter -class KeywordExtractor: +class SBertKeywordExtractor: def __init__( self, top_n: int, encoder: Encoder, vectorizer: CountVectorizer ): @@ -77,6 +77,14 @@ def __init__( self.key_to_index: dict[str, int] = {} self.term_embeddings: Optional[np.ndarray] = None + @property + def is_encoder_promptable(self) -> bool: + prompts = getattr(self.encoder, "prompts", None) + if prompts is None: + return False + if ("query" in prompts) and ("passage" in prompts): + return True + @property def n_vocab(self) -> int: return len(self.key_to_index) @@ -84,7 +92,12 @@ def n_vocab(self) -> int: def _add_terms(self, new_terms: list[str]): for term in new_terms: self.key_to_index[term] = self.n_vocab - term_encodings = self.encoder.encode(new_terms) + if not self.is_encoder_promptable: + term_encodings = self.encoder.encode(new_terms) + else: + term_encodings = self.encoder.encode( + new_terms, prompt_name="passage" + ) if self.term_embeddings is not None: self.term_embeddings = np.concatenate( (self.term_embeddings, term_encodings), axis=0 @@ -100,7 +113,12 @@ def batch_extract_keywords( if not len(documents): return [] if embeddings is None: - embeddings = self.encoder.encode(documents) + if not self.is_encoder_promptable: + embeddings = self.encoder.encode(documents) + else: + embeddings = self.encoder.encode( + documents, prompt_name="query" + ) if len(embeddings) != len(documents): raise ValueError( "Number of documents doesn't match number of embeddings." diff --git a/turftopic/models/keynmf.py b/turftopic/models/keynmf.py index b083cdb..3ec7dd7 100644 --- a/turftopic/models/keynmf.py +++ b/turftopic/models/keynmf.py @@ -14,7 +14,7 @@ from turftopic.data import TopicData from turftopic.dynamic import DynamicTopicModel from turftopic.hierarchical import TopicNode -from turftopic.models._keynmf import KeywordExtractor, KeywordNMF +from turftopic.models._keynmf import KeywordNMF, SBertKeywordExtractor from turftopic.models.wnmf import weighted_nmf from turftopic.vectorizer import default_vectorizer @@ -75,7 +75,7 @@ def __init__( self.model = KeywordNMF( n_components=n_components, seed=random_state, top_n=self.top_n ) - self.extractor = KeywordExtractor( + self.extractor = SBertKeywordExtractor( top_n=self.top_n, vectorizer=self.vectorizer, encoder=self.encoder_ ) @@ -269,12 +269,14 @@ def partial_fit( min_df = self.vectorizer.min_df max_df = self.vectorizer.max_df if (min_df != 1) or (max_df != 1.0): - warnings.warn(f"""When applying partial fitting, the vectorizer is fitted batch-wise in KeyNMF. + warnings.warn( + f"""When applying partial fitting, the vectorizer is fitted batch-wise in KeyNMF. You have a vectorizer with min_df={min_df}, and max_df={max_df}. If you continue with these settings, all tokens might get filtered out. We recommend setting min_df=1 and max_df=1.0 for online fitting. `model = KeyNMF(10, vectorizer=CountVectorizer(min_df=1, max_df=1.0)` - """) + """ + ) if keywords is None and raw_documents is None: raise ValueError( "You have to pass either keywords or raw_documents." From 04d96dbba7b1cdb48ca114df6003aaae5a9278d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20Kardos?= Date: Mon, 14 Oct 2024 10:13:52 +0200 Subject: [PATCH 04/10] Version bump --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 07268ef..bab8850 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ line-length=79 [tool.poetry] name = "turftopic" -version = "0.5.4" +version = "0.6.0" description = "Topic modeling with contextual representations from sentence transformers." authors = ["Márton Kardos "] license = "MIT" From 44d0828236f9a837d18d6bad7b48e5928446007a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20Kardos?= Date: Mon, 14 Oct 2024 10:30:38 +0200 Subject: [PATCH 05/10] Updated docs --- docs/KeyNMF.md | 45 ++++++++++++++++++++++++++++++++++ docs/basics.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/docs/KeyNMF.md b/docs/KeyNMF.md index 85742b7..cf5f428 100644 --- a/docs/KeyNMF.md +++ b/docs/KeyNMF.md @@ -109,6 +109,51 @@ keyword_matrix = model.extract_keywords(corpus) model.fit(None, keywords=keyword_matrix) ``` +## Asymmetric and Instruction-tuned Embedding Models + +Some embedding models can be used together with prompting, or encode queries and passages differently. +This is important for KeyNMF, as it is explicitly based on keyword retrieval, and its performance can be substantially enhanced by using asymmetric or prompted embeddings. +Microsoft's E5 models are, for instance, all prompted by default, and it would be detrimental to performance not to do so yourself. + +In these cases, you're better off NOT passing a string to Turftopic models, but explicitly loading the model using `sentence-transformers`. + +Here's an example of using instruct models for keyword retrieval with KeyNMF. +In this case, documents will serve as the queries and words as the passages: + +```python +from turftopic import KeyNMF +from sentence_transformers import SentenceTransformer + +encoder = SentenceTransformer( + "intfloat/multilingual-e5-large-instruct", + prompts={ + "query": "Instruct: Retrieve relevant keywords from the given document. Query: " + "passage": "Passage: " + }, + # Make sure to set default prompt to query! + default_prompt_name="query", +) +model = KeyNMF(10, encoder=encoder) +``` + +And a regular, asymmetric example: + +```python +encoder = SentenceTransformer( + "intfloat/e5-large-v2", + prompts={ + "query": "query: " + "passage": "passage: " + }, + # Make sure to set default prompt to query! + default_prompt_name="query", +) +model = KeyNMF(10, encoder=encoder) +``` + +Setting the default prompt to `query` is especially important, when you are precomputing embeddings, as `query` should always be your default prompt to embed documents with. + + ## Dynamic Topic Modeling KeyNMF is also capable of modeling topics over time. diff --git a/docs/basics.md b/docs/basics.md index cbef523..8c52228 100644 --- a/docs/basics.md +++ b/docs/basics.md @@ -27,7 +27,7 @@ Here's a model that uses E5 large as the embedding model, and only learns words from turftopic import SemanticSignalSeparation from sklearn.feature_extraction.text import CountVectorizer -model = SemanticSignalSeparation(10, encoder="intfloat/e5-large-v2", vectorizer=CountVectorizer(min_df=20)) +model = SemanticSignalSeparation(10, encoder="all-MiniLM-L6-v2", vectorizer=CountVectorizer(min_df=20)) ``` You can also use external models for encoding, here's an example with [OpenAI's embedding models](encoders.md#external_embeddings): @@ -60,6 +60,67 @@ corpus: list[str] = ["this is a a document", "this is yet another document", ... model.fit(corpus) ``` +## Prompting Embedding Models + +Some embedding models can be used together with prompting, or encode queries and passages differently. +This can significantly influence performance, especially in the case of models that are based on retrieval ([KeyNMF](KeyNMF.md)) or clustering ([ClusteringTopicModel](clustering.md)). +Microsoft's E5 models are, for instance all prompted by default, and it would be detrimental to performance not to do so yourself. + +In these cases, you're better off NOT passing a string to Turftopic models, but explicitly loading the model using `sentence-transformers`. + +Here's an example for clustering models: +```python +from turftopic import ClusteringTopicModel +from sentence_transformers import SentenceTransformer + +encoder = SentenceTransformer( + "intfloat/multilingual-e5-large-instruct", + prompts={ + "query": "Instruct: Cluster documents according to the topic they are about. Query: " + "passage": "Passage: " + }, + # Make sure to set default prompt to query! + default_prompt_name="query", +) +model = ClusteringTopicModel(encoder=encoder) +``` + +You can also use instruct models for keyword retrieval with KeyNMF. +In this case, documents will serve as the queries and words as the passages: + +```python +from turftopic import KeyNMF +from sentence_transformers import SentenceTransformer + +encoder = SentenceTransformer( + "intfloat/multilingual-e5-large-instruct", + prompts={ + "query": "Instruct: Retrieve relevant keywords from the given document. Query: " + "passage": "Passage: " + }, + # Make sure to set default prompt to query! + default_prompt_name="query", +) +model = KeyNMF(10, encoder=encoder) +``` + +When using KeyNMF with E5, make sure to specify the prompts even if you're not using instruct models: + +```python +encoder = SentenceTransformer( + "intfloat/e5-large-v2", + prompts={ + "query": "query: " + "passage": "passage: " + }, + # Make sure to set default prompt to query! + default_prompt_name="query", +) +model = KeyNMF(10, encoder=encoder) +``` + +Setting the default prompt to `query` is especially important, when you are precomputing embeddings, as `query` should always be your default prompt to embed documents with. + ## Precomputing Embeddings In order to cut down on costs/computational load when fitting multiple models in a row, you might want to encode the documents before fitting a model. @@ -78,7 +139,7 @@ import numpy as np from sentence_transformers import SentenceTransformer from turftopic import GMM, ClusteringTopicModel -encoder = SentenceTransformer("intfloat/e5-large-v2") +encoder = SentenceTransformer("intfloat/e5-large-v2", prompts={"query": "query: ", "passage": "passage: "}, default_prompt_name="query") corpus: list[str] = ["this is a a document", "this is yet another document", ...] embeddings = np.asarray(encoder.encode(corpus)) From 65a890779712f720662d2c3080143fef28330b4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20Kardos?= Date: Mon, 14 Oct 2024 10:32:58 +0200 Subject: [PATCH 06/10] Updated readme --- README.md | 45 ++++++++++++++++----------------------------- 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index d25833c..9691e46 100644 --- a/README.md +++ b/README.md @@ -20,42 +20,29 @@ > This package is still work in progress and scientific papers on some of the novel methods are currently undergoing peer-review. If you use this package and you encounter any problem, let us know by opening relevant issues. -### New in version 0.5.0 +### New in version 0.6.0 -#### Hierarchical KeyNMF +#### Prompting Embedding Models -You can now subdivide topics in KeyNMF at will. +KeyNMF and clustering topic models can now efficiently utilise asymmetric and instruction-finetuned embedding models. +This, in combination with the right embedding model, can enhance performance significantly. ```python from turftopic import KeyNMF - -model = KeyNMF(2, top_n=15, random_state=42).fit(corpus) -model.hierarchy.divide_children(n_subtopics=3) -print(model.hierarchy) -``` - -``` -Root -├── windows, dos, os, disk, card, drivers, file, pc, files, microsoft -│ ├── 0.0: dos, file, disk, files, program, windows, disks, shareware, norton, memory -│ ├── 0.1: os, unix, windows, microsoft, apps, nt, ibm, ms, os2, platform -│ └── 0.2: card, drivers, monitor, driver, vga, ram, motherboard, cards, graphics, ati -└── 1: atheism, atheist, atheists, religion, christians, religious, belief, christian, god, beliefs -. ├── 1.0: atheism, alt, newsgroup, reading, faq, islam, questions, read, newsgroups, readers -. ├── 1.1: atheists, atheist, belief, theists, beliefs, religious, religion, agnostic, gods, religions -. └── 1.2: morality, bible, christian, christians, moral, christianity, biblical, immoral, god, religion +from sentence_transformers import SentenceTransformer + +encoder = SentenceTransformer( + "intfloat/multilingual-e5-large-instruct", + prompts={ + "query": "Instruct: Retrieve relevant keywords from the given document. Query: " + "passage": "Passage: " + }, + # Make sure to set default prompt to query! + default_prompt_name="query", +) +model = KeyNMF(10, encoder=encoder) ``` -#### FASTopic *(Experimental)* - -You can now use [FASTopic](https://github.com/BobXWu/FASTopic) inside Turftopic. - -```python -from turftopic import FASTopic - -model = FASTopic(10).fit(corpus) -model.print_topics() -``` ## Basics [(Documentation)](https://x-tabdeveloping.github.io/turftopic/) [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/x-tabdeveloping/turftopic/blob/main/examples/basic_example_20newsgroups.ipynb) From bc00c5cb101bd8d7a5b1641fbc4f8c994dca770c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20Kardos?= Date: Mon, 14 Oct 2024 10:35:08 +0200 Subject: [PATCH 07/10] Added asymmetric embeddings to encoders docs --- docs/encoders.md | 50 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/docs/encoders.md b/docs/encoders.md index 921eae0..dbff9fc 100644 --- a/docs/encoders.md +++ b/docs/encoders.md @@ -21,6 +21,48 @@ model = GMM(10, encoder="paraphrase-multilingual-MiniLM-L12-v2") Different encoders have different performance and model sizes. To make an informed choice about which embedding model you should be using check out the [Massive Text Embedding Benchmark](https://huggingface.co/blog/mteb). +## Asymmetric and Instruction-tuned Embedding Models + +Some embedding models can be used together with prompting, or encode queries and passages differently. +Microsoft's E5 models are, for instance, all prompted by default, and it would be detrimental to performance not to do so yourself. + +In these cases, you're better off NOT passing a string to Turftopic models, but explicitly loading the model using `sentence-transformers`. + +Here's an example of using instruct models for keyword retrieval with KeyNMF. +In this case, documents will serve as the queries and words as the passages: + +```python +from turftopic import KeyNMF +from sentence_transformers import SentenceTransformer + +encoder = SentenceTransformer( + "intfloat/multilingual-e5-large-instruct", + prompts={ + "query": "Instruct: Retrieve relevant keywords from the given document. Query: " + "passage": "Passage: " + }, + # Make sure to set default prompt to query! + default_prompt_name="query", +) +model = KeyNMF(10, encoder=encoder) +``` + +And a regular, asymmetric example: + +```python +encoder = SentenceTransformer( + "intfloat/e5-large-v2", + prompts={ + "query": "query: " + "passage": "passage: " + }, + # Make sure to set default prompt to query! + default_prompt_name="query", +) +model = KeyNMF(10, encoder=encoder) +``` + + ## External Embeddings If you do not have the computational resources to run embedding models on your own infrastructure, you can also use high quality 3rd party embeddings. @@ -33,11 +75,3 @@ Turftopic currently supports OpenAI, Voyage and Cohere embeddings. :::turftopic.encoders.OpenAIEmbeddings :::turftopic.encoders.VoyageEmbeddings - -## E5 Embeddings - -Most E5 models expect the input to be prefixed with something like `"query: "` (see the [multilingual-e5-small](https://huggingface.co/intfloat/multilingual-e5-small) model card). -In instructional E5 models, it is also possible to add an instruction, following the format `f"Instruct: {task_description} \nQuery: {document}"` (see the [multilingual-e5-large-instruct](https://huggingface.co/intfloat/multilingual-e5-large-instruct) model card). -In Turftopic, E5 embeddings including the prefixing is handled by the `E5Encoder`. - -:::turftopic.encoders.E5Encoder \ No newline at end of file From f4a8479afccbf63d00a1f3d0bdb4de3a4f139355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20Kardos?= Date: Mon, 14 Oct 2024 10:37:37 +0200 Subject: [PATCH 08/10] Added ONNX to embedding docs --- docs/encoders.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/encoders.md b/docs/encoders.md index dbff9fc..ef79128 100644 --- a/docs/encoders.md +++ b/docs/encoders.md @@ -62,6 +62,23 @@ encoder = SentenceTransformer( model = KeyNMF(10, encoder=encoder) ``` +## Performance tips + +From `sentence-transformers` version `3.2.0` you can significantly speed up some models by using +the `onnx` backend instead of regular torch. + +``` +pip install sentence-transformers[onnx, onnx-gpu] +``` + +```python +from turftopic import SemanticSignalSeparation +from sentence_transformers import SentenceTransformer + +encoder = SentenceTransformer("all-MiniLM-L6-v2", backend="onnx") + +model = SemanticSignalSeparation(10, encoder=encoder) +``` ## External Embeddings From 42b65351371e95fa5d0338e6e149781846f7fbb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20Kardos?= Date: Mon, 14 Oct 2024 10:44:56 +0200 Subject: [PATCH 09/10] Tried fixing docs --- .github/workflows/documentation.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 7381aec..be73eac 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -23,7 +23,7 @@ jobs: - name: Dependencies run: | python -m pip install --upgrade pip - pip install "turftopic[pyro-ppl,docs]" + pip install "turftopic[pyro-ppl,docs]" "griffe" "mkdocstrings[python]" "mkdocs" "mkdocs-material" - name: Build and Deploy if: github.event_name == 'push' @@ -31,4 +31,4 @@ jobs: - name: Build if: github.event_name == 'pull_request' - run: mkdocs build \ No newline at end of file + run: mkdocs build From 75a33abffb20346ab2fd7befe09096263a2e4b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20Kardos?= Date: Mon, 14 Oct 2024 10:50:58 +0200 Subject: [PATCH 10/10] Tried fixing docs --- .github/workflows/documentation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index be73eac..15161bc 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -23,7 +23,7 @@ jobs: - name: Dependencies run: | python -m pip install --upgrade pip - pip install "turftopic[pyro-ppl,docs]" "griffe" "mkdocstrings[python]" "mkdocs" "mkdocs-material" + pip install "turftopic[pyro-ppl]" "griffe" "mkdocstrings[python]" "mkdocs" "mkdocs-material" - name: Build and Deploy if: github.event_name == 'push'