-
Notifications
You must be signed in to change notification settings - Fork 351
Expand file tree
/
Copy pathllms.txt
More file actions
1617 lines (1157 loc) · 67.5 KB
/
Copy pathllms.txt
File metadata and controls
1617 lines (1157 loc) · 67.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<div align="center">
## 🦛 Chonkie Docs 📚
</div>
> "Ugh, writing docs is such a pain — I'm going to make chonkie so simple that people will just get it!"
> — @chonknick, probably
Unfortunately, we do need docs for Chonkie (we tried!). While official docs are available at [docs.chonkie.ai](https://docs.chonkie.ai), these docs are meant as an additional resource to help you get the most out of Chonkie. Since these docs live inside the repo, they are a bit more flexible and can be updated more frequently, and are also a bit more detailed. Furthermore, they are easy to edit with AI, so you can ask the AI to update them with examples, recipes, and more! (Haha, less work for the maintainers! 🤖)
> [!NOTE]
> Since these docs are a single markdown file, they make it ultra-simple to add into your LLM of choice to answer questions about Chonkie! Cool, huh? Yeah, Chonkie is super cool. 🦛✨
## Table of Contents
- [🦛 Chonkie Docs 📚](#-chonkie-docs-)
- [Table of Contents](#table-of-contents)
- [📦 Installation](#-installation)
- [Optional Dependencies](#optional-dependencies)
- [Usage](#usage)
- [Types and Data Structures](#types-and-data-structures)
- [The `Chunk` Type](#the-chunk-type)
- [CHONKosophy](#chonkosophy)
- [How does Chonkie think about chunking?](#how-does-chonkie-think-about-chunking)
- [Chunkers](#chunkers)
- [`TokenChunker`](#tokenchunker)
- [`SentenceChunker`](#sentencechunker)
- [`RecursiveChunker`](#recursivechunker)
- [`SemanticChunker`](#semanticchunker)
- [`SDPMChunker`](#sdpmchunker)
- [`LateChunker`](#latechunker)
- [Refinery](#refinery)
- [`OverlapRefinery`](#overlaprefinery)
- [`EmbeddingRefinery`](#embeddingrefinery)
- [Chefs](#chefs)
- [Tokenizers](#tokenizers)
- [Embeddings](#embeddings)
- [Custom Embeddings](#custom-embeddings)
- [Genies](#genies)
- [`GeminiGenie`](#geminigenie)
- [`OpenAIGenie`](#openaigenie)
- [Porters](#porters)
- [`JSONPorter`](#jsonporter)
- [Handshakes](#handshakes)
- [`ChromaHandshake`](#chromahandshake)
- [`QdrantHandshake`](#qdranthandshake)
- [`PgvectorHandshake`](#pgvectorhandshake)
- [`TurbopufferHandshake`](#turbopufferhandshake)
- [Package Versioning](#package-versioning)
## 📦 Installation
Chonkie is available for direct installation from PyPI, via the following command:
```bash
pip install chonkie
```
We believe in the rule of **minimum default dependencies** and **Make-Your-Own-Package (MYOP)** principles, so Chonkie has a bunch of optional dependencies that you can configure to get the most out of your Chonkie experience. Though, we do realize that it might be a pain to configure, so you can just install it all with the following command:
```bash
pip install "chonkie[all]"
```
We detail the optional dependencies below.
### Optional Dependencies
You can install optional features using the `pip install "chonkie[feature]"` syntax. Here's a breakdown of the available features:
| Feature | Description |
| :--------- | :------------------------------------------------------------------------------------------------------ |
| `hub` | Interact with the Hugging Face Hub for models and configurations. Required to access `from_recipe` options in Chunkers. |
| `viz` | Enables the `Visualizer` which allows for cool visuals on the terminal and HTML output. |
| `code` | Required for `CodeChunker`. Installs `tree-sitter` and `magika`. |
| `model2vec` | Required to leverage `Model2VecEmbeddings` with the semantic and late chunkers. |
| `st` | Use `sentence-transformers` for generating embeddings, enabling semantic chunking strategies. |
| `openai` | Integrate with OpenAI's API for `tiktoken` token counting and OpenAI embeddings. |
| `voyageai` | Use Voyage AI's embedding models. |
| `cohere` | Integrate with Cohere's embedding models. |
| `jina` | Use Jina AI's embedding models. |
| `gemini` | Use Google's Gemini embedding models. |
| `semantic` | Enable semantic chunking capabilities, potentially leveraging `model2vec`. |
| `neural` | Utilize local Hugging Face `transformers` models (with `torch`) for advanced NLP tasks. |
| `genie` | Integrate with Google's Generative AI (Gemini) models for advanced functionalities. |
| `chroma` | Connect and integrate with ChromaDB vector database. |
| `qdrant` | Connect and integrate with Qdrant vector database. |
| `pgvector` | Connect and integrate with PostgreSQL using pgvector extension via vecs. |
| `turbopuffer` | Connect and integrate with Turbopuffer vector database. |
| `all` | Install all optional dependencies for the complete Chonkie experience. Not recommended for prod. |
> [!NOTE]
> You can install multiple features at once by passing a list of features to the `pip install` command. For example, `pip install "chonkie[hub,viz]"` will install the `hub` and `viz` features.
## Usage
Chonkie is designed to be ultra-simple to use. There are usually always 3 steps: Install, Import, and CHONK! We'll go over a simple example below.
First, let's install Chonkie. We only need the base package since we'll be using the `RecursiveChunker` for this example
```bash
pip install chonkie
```
Next, we'll import Chonkie and create a `Chonkie` object.
```python
from chonkie import RecursiveChunker
chunker = RecursiveChunker()
```
Now, we'll use the `chunk` method to chunk some text.
```python
text = "Hello, world!"
chunks = chunker(text)
```
And that's it! We've just chonked some text. The `chunks` object is a list of `Chunk` objects. We can print them out to see what we've got.
```python
# Print out the chunks
for chunk in chunks:
print(chunk.text)
print(chunk.token_count)
print(chunk.start_index)
print(chunk.end_index)
```
## Types and Data Structures
### The `Chunk` Type
All chunkers in Chonkie now return the base `Chunk` type for consistency and simplicity. The `Chunk` type is a dataclass with the following attributes:
```python
@dataclass
class Chunk:
text: str # The text content of the chunk
start_index: int # Starting position in original text
end_index: int # Ending position in original text
token_count: int # Number of tokens in the chunk
context: Optional[Context] = None # Optional context metadata
embedding: Union[list[float], "np.ndarray", None] = None # Optional embedding vector (list or numpy array)
```
The `embedding` attribute can store embedding vectors (as lists or numpy arrays) which are automatically added when using `EmbeddingsRefinery` or certain chunkers like `LateChunker`.
### The `Sentence` Type
The `Sentence` type is used internally by sentence-based chunkers and represents individual sentences with metadata:
```python
@dataclass
class Sentence:
text: str # The sentence text
start_index: int # Starting position in original text
end_index: int # Ending position in original text
token_count: int # Number of tokens in the sentence
embedding: Union[list[float], "np.ndarray", None] = None # Optional embedding vector
```
> [!NOTE]
> As of version 1.3.0, all specialized types have been simplified. The specialized chunk types (`SentenceChunk`, `RecursiveChunk`, `SemanticChunk`, `CodeChunk`, and `LateChunk`) have been removed - all chunkers now return the base `Chunk` type. Similarly, `SemanticSentence` has been removed as the base `Sentence` type now includes an optional `embedding` field. This simplifies the API and makes it easier to chain different components together.
## CHONKosophy
Chonkie truly believes that chunking should be simple to understand, easy to use and performant where it matters. It is fundamental to Chonkie's design principles. We truly believe that chunking should never be brought into the foreground of your codebase, and should be a primitive that you don't even think about. Just like how we don't think about the `for` loop or the `if` statement at the assembly level (sorry assembly devs 🤖).
### How does Chonkie think about chunking?
In Chonkie, we think of chunking as a pipeline, not just a single operation. Generally, the pipeline looks like this:
`Input Data -> Chef -> Chunker(s) -> Refinery(s) -> Porter/Handshake`
The `Chef` is responsible for fetching the data, cleaning it, and preparing it for chunking. The `Chunker` is responsible for chunking the data. The `Refinery` is responsible for refining the chunks, and the `Porter` and `Handshake` are responsible for the final step of the pipeline, which is to return the chunks in a format that can be used by the user or to upsert into a database.
## Chunkers
Chunkers are the core of Chonkie. They are responsible for chunking the text into smaller, more manageable pieces. There are many different types of chunkers, each with their own unique properties and use cases. We'll go over the different types of chunkers below.
### `TokenChunker`
The `TokenChunker` is the most basic type of chunker. It simply splits the text into chunks of a given token length. It comes with the default installation of Chonkie.
**Parameters:**
- `tokenizer (Union[str, Any])`: The tokenizer to use. Defaults to `character` tokenizer. You can also pass `word` to use the word tokenizer, or any string identifier like `gpt2` to use the `tokenizers.Tokenizer` library. More details mentioned in the [Tokenizers](#tokenizers) section.
- `chunk_size (int)`: The number of tokens to chunk the text into. Defaults to `512`.
- `overlap (int)`: The number of tokens to overlap between chunks. Defaults to `0`.
**Methods:**
- `chunk(text: str) -> list[Chunk]`: Chunks a string into a list of `Chunk` objects.
- `chunk_batch(texts: list[str]) -> list[list[Chunk]]`: Chunks a list of strings into a list of lists of `Chunk` objects.
- `__call__(text: str) -> Union[list[Chunk], list[list[Chunk]]]`: Chunks a string or list of strings into chunk objects.
**Examples:**
Here are a couple of examples on how to use the `TokenChunker` in practice.
<details>
<summary><strong>1. Basic Usage of `TokenChunker`</strong></summary>
```python
from chonkie import TokenChunker
chunker = TokenChunker()
chunks = chunker("Hello, world!")
# Print out the chunks
for chunk in chunks:
print(chunk.text)
print(chunk.token_count)
print(chunk.start_index)
print(chunk.end_index)
```
</details>
<details>
<summary><strong>2. Using `TokenChunker` with a custom tokenizer</strong></summary>
```python
from chonkie import TokenChunker
chunker = TokenChunker(tokenizer="gpt2") # Or use default: TokenChunker()
chunks = chunker("Hello, world!")
```
</details>
<details>
<summary><strong>3. Chunking a batch of text</strong></summary>
```python
from chonkie import TokenChunker
batch = [
"Hello, world!",
"This is a test",
"Chunking is fun!"
]
chunker = TokenChunker()
chunks = chunker.chunk_batch(batch)
```
</details>
<details>
<summary><strong>4. Visualizing the chunks with `Visualizer`</strong></summary>
```python
from chonkie import TokenChunker, Visualizer
chunker = TokenChunker()
chunks = chunker("Hello, world!")
viz = Visualizer()
viz(chunks)
```
</details>
### `SentenceChunker`
The `SentenceChunker` is a chunker that splits the text into sentences and then groups the sentences together into chunks based on a given `chunk_size`, where `chunk_size` is the maximum tokens a chunk can have. Given that it groups naturally occurring sentence together, it's `token_count` value is not as consistent as the `TokenChunker`. However, it makes an excellent choice for chunking well formatted text, being both simple and fast.
**Parameters:**
- `tokenizer_or_token_counter (Union[str, Callable, Any])`: The tokenizer or token counter to use. Defaults to `gpt2` with `tokenizers.Tokenizer`. You can also pass `character` or `word` to use the character or word tokenizer respectively. Additionally, you can also pass a `Callable` that takes in a string and returns the number of tokens in the string. More details mentioned in the [Tokenizers](#tokenizers) section.
- `chunk_size (int)`: The maximum number of tokens a chunk can have. Defaults to `512`.
- `chunk_overlap (int)`: The number of tokens to overlap between chunks. Defaults to `0`.
- `min_sentences_per_chunk (int)`: Minimum number of sentences per chunk. Defaults to `1`.
- `min_characters_per_sentence (int)`: Minimum number of characters per sentence. Defaults to `12`.
- `approximate (bool)`: [DEPRECATED] Whether to use approximate token counting. Defaults to `False`.
- `delim (Union[str, list[str]])`: Delimiters to split sentences on. Defaults to `[". ", "! ", "? ", "\n"]`.
- `include_delim (Optional[Literal["prev", "next"]])`: Whether to include delimiters in the current chunk (`"prev"`), the next chunk (`"next"`), or not at all (`None`). Defaults to `"prev"`.
**Methods:**
- `chunk(text: str) -> list[Chunk]`: Chunks a string into a list of `Chunk` objects. Returns the base `Chunk` type.
- `chunk_batch(texts: list[str]) -> list[list[Chunk]]`: Chunks a list of strings into a list of lists of `Chunk` objects. (Inherited)
- `from_recipe(name: str, lang: str, **kwargs) -> SentenceChunker`: Creates a `SentenceChunker` instance using pre-defined recipes from the [Chonkie Recipe Store](https://huggingface.co/datasets/chonkie-ai/recipes). This allows easy configuration for specific languages or splitting behaviors.
- `__call__(text: str) -> Union[list[Chunk], list[list[Chunk]]]`: Chunks a string or list of strings. Calls `chunk` or `chunk_batch` depending on input type. (Inherited)
**Examples:**
Here are a couple of examples on how to use the `SentenceChunker` in practice.
<details>
<summary><strong>1. Basic Usage of `SentenceChunker`</strong></summary>
```python
from chonkie import SentenceChunker
# Initialize with default settings (character tokenizer, chunk_size 512)
chunker = SentenceChunker()
text = "This is the first sentence. This is the second sentence, which is a bit longer. And finally, the third sentence!"
chunks = chunker(text)
# Print out the chunks
for chunk in chunks:
print(f"Text: {chunk.text}")
print(f"Token Count: {chunk.token_count}")
print(f"Start Index: {chunk.start_index}")
print(f"End Index: {chunk.end_index}")
# All chunkers now return the base Chunk type for consistency
print("-" * 10)
```
</details>
<details>
<summary><strong>2. Using `SentenceChunker` with custom delimiters and smaller chunk size</strong></summary>
```python
from chonkie import SentenceChunker
# Use custom delimiters and a smaller chunk size
chunker = SentenceChunker(
chunk_size=20,
delim=["\n", ". "], # Split on newlines and periods followed by space
include_delim="next" # Include delimiter at the start of the next chunk
)
text = "Sentence one.\nSentence two.\nSentence three is very short."
chunks = chunker(text)
for chunk in chunks:
print(chunk.text)
print(f"Tokens: {chunk.token_count}\n---")
```
</details>
<details>
<summary><strong>3. Using `SentenceChunker.from_recipe`</strong></summary>
```python
from chonkie import SentenceChunker
# Requires "chonkie[hub]" to be installed
# Uses default recipe for English ('en')
chunker = SentenceChunker.from_recipe(lang="en", chunk_size=64)
text = "This demonstrates using a recipe. Recipes define delimiters. They make setup easy."
chunks = chunker(text)
for chunk in chunks:
print(chunk.text)
print(f"Tokens: {chunk.token_count}\n---")
```
</details>
<details>
<summary><strong>4. Visualizing the chunks with `Visualizer`</strong></summary>
```python
# Requires "chonkie[viz]" to be installed
from chonkie import SentenceChunker, Visualizer
chunker = SentenceChunker(chunk_size=30)
text = "Chunk visualization is helpful. It shows how the text is split. Let's see how this looks."
chunks = chunker(text)
viz = Visualizer()
viz(chunks) # Prints colored output to terminal or creates HTML
```
</details>
### `RecursiveChunker`
The `RecursiveChunker` is a more complex type of chunker that uses a recursive approach to chunk the text. It is a good choice for chunking text that is not well-suited for the `TokenChunker`.
### `SemanticChunker`
The `SemanticChunker` splits text into semantically coherent chunks using sentence embeddings. It first splits the text into sentences, embeds them, and then groups sentences based on their semantic similarity. This approach aims to keep related sentences together within the same chunk, leading to more contextually meaningful chunks compared to fixed-size or simple delimiter-based methods. It's particularly useful for processing text where preserving the flow of ideas is important.
There are two main strategies for chunking:
1. **Window Strategy**: This strategy compares each sentence to the previous one (or within a small window) to determine if they are semantically similar. If they are, they are grouped together. Since it only compares a pre-defined window of sentences every time, it is easy to batch embed the (window, sentence) pairs and compare their similarity values.
2. **Cumulative Strategy**: This strategy compares each sentence to the mean embedding of the current group. If the sentence is more similar to the mean than the threshold, it is added to the group. Otherwise, a new group is started. This is much more computationally expensive than the window strategy, but can at times result in better chunks.
For both of the above strategies, in `auto` mode, we determine the `threshold` value based on a binary search over the range of values that keeps the median `chunk_size` below the `chunk_size` parameter and above the `min_chunk_size` parameter. While this may not always result in the ideal chunks, it does provide a good starting point. Hopefully, this will be improved in future versions of Chonkie.
**Parameters:**
- `embedding_model (Union[str, BaseEmbeddings])`: The embedding model to use for semantic chunking. Can be a string identifier (e.g., from Hugging Face Hub like `"minishlab/potion-base-32M"`) or an instantiated `BaseEmbeddings` object. Defaults to `"minishlab/potion-base-32M"`. Requires appropriate extras like `chonkie[semantic]` or specific model providers (`chonkie[st]`, `chonkie[openai]`, etc.).
- `mode (str)`: The strategy for comparing sentence similarity. `"window"` compares adjacent sentences (or within a small window), while `"cumulative"` compares a new sentence to the mean embedding of the current group. Defaults to `"window"`.
- `threshold (Union[str, float, int])`: The similarity threshold for splitting sentences. Can be `"auto"` (uses a binary search to find an optimal threshold based on `chunk_size`), a float between 0.0 and 1.0 (direct cosine similarity threshold), or an int between 1 and 100 (percentile threshold). Defaults to `"auto"`.
- `chunk_size (int)`: The target maximum number of tokens per chunk. Defaults to `512`.
- `similarity_window (int)`: When `mode="window"`, this defines the number of preceding sentences to consider when calculating the similarity of the current sentence. Defaults to `1`.
- `min_sentences (int)`: The minimum number of sentences allowed in a chunk. Defaults to `1`.
- `min_chunk_size (int)`: The minimum number of tokens allowed in a chunk. Also influences the minimum sentence length considered during splitting. Defaults to `2`.
- `min_characters_per_sentence (int)`: Minimum number of characters a sentence must have to be considered valid during the initial sentence splitting phase. Shorter segments might be merged. Defaults to `12`.
- `threshold_step (float)`: Step size used in the binary search when `threshold="auto"`. Defaults to `0.01`.
- `delim (Union[str, list[str]])`: Delimiters used to split the text into initial sentences. Defaults to `[". ", "! ", "? ", "\n"]`.
- `include_delim (Optional[Literal["prev", "next"]])`: Whether to include the delimiter with the preceding sentence (`"prev"`), the succeeding sentence (`"next"`), or not at all (`None`). Defaults to `"prev"`.
**Methods:**
- `chunk(text: str) -> list[SemanticChunk]`: Chunks a single string into a list of `SemanticChunk` objects.
- `chunk_batch(texts: list[str]) -> list[list[SemanticChunk]]`: Chunks a list of strings. (Inherited)
- `from_recipe(name: str, lang: str, **kwargs) -> SemanticChunker`: Creates a `SemanticChunker` using pre-defined recipes (delimiters, etc.) from the [Chonkie Recipe Store](https://huggingface.co/datasets/chonkie-ai/recipes), simplifying setup for specific languages. Requires `chonkie[hub]`.
- `__call__(text: Union[str, list[str]]) -> Union[list[SemanticChunk], list[list[SemanticChunk]]]`: Convenience method calling `chunk` or `chunk_batch` depending on input type. (Inherited)
**Examples:**
Here are a couple of examples on how to use the `SemanticChunker` in practice.
<details>
<summary><strong>1. Basic Usage of `SemanticChunker`</strong></summary>
```python
# Requires "chonkie[semantic]" or relevant embedding model extra (e.g., "chonkie[st]")
from chonkie import SemanticChunker
# Initialize with default settings (potion-base-8M model, auto threshold)
chunker = SemanticChunker()
text = "Semantic chunking groups related ideas. This sentence is related to the first. This one starts a new topic. Exploring different chunking strategies is key."
chunks = chunker(text)
# Print out the chunks (SemanticChunk objects)
for chunk in chunks:
print(f"Text: {chunk.text}")
print(f"Token Count: {chunk.token_count}")
print(f"Start Index: {chunk.start_index}")
print(f"End Index: {chunk.end_index}")
print(f"Number of Sentences: {len(chunk.sentences)}") # SemanticChunk specific attribute
print("-" * 10)
```
</details>
<details>
<summary><strong>2. Using `SemanticChunker` with a specific threshold and different model</strong></summary>
```python
# Requires "chonkie[semantic, st]" for sentence-transformers
from chonkie import SemanticChunker
# Use a different embedding model and a fixed percentile threshold
chunker = SemanticChunker(
embedding_model="all-MiniLM-L6-v2", # From sentence-transformers
threshold=90, # Use 90th percentile for similarity threshold
chunk_size=128
)
text = "Using a percentile threshold can adapt to document density. 90 means splits occur at lower similarity points. This can result in more, smaller chunks potentially. Let's test this."
chunks = chunker(text)
for chunk in chunks:
print(chunk.text)
print(f"Tokens: {chunk.token_count}\n---")
```
</details>
<details>
<summary><strong>3. Using `SemanticChunker.from_recipe`</strong></summary>
```python
# Requires "chonkie[hub, semantic]" or relevant embedding model extra
from chonkie import SemanticChunker
# Uses default recipe for English ('en') delimiters
# Specify embedding model and other parameters as needed
chunker = SemanticChunker.from_recipe(
lang="en",
embedding_model="sentence-transformers/paraphrase-MiniLM-L3-v2", # Example
chunk_size=64,
threshold="auto"
)
text = "Recipes simplify delimiter setup. Semantic logic remains. This is English text."
chunks = chunker(text)
for chunk in chunks:
print(chunk.text)
print(f"Tokens: {chunk.token_count}\n---")
```
</details>
<details>
<summary><strong>4. Visualizing the chunks with `Visualizer`</strong></summary>
```python
# Requires "chonkie[viz, semantic]" or relevant embedding model extra
from chonkie import SemanticChunker, Visualizer
chunker = SemanticChunker(chunk_size=50)
text = "Visualization helps understand semantic breaks. See where the model decided to split the text based on meaning. This is useful for debugging."
chunks = chunker(text)
viz = Visualizer()
viz(chunks) # Prints colored output to terminal or creates HTML
```
</details>
### `SDPMChunker`
The `SDPMChunker` (Semantic Double-Pass Merging Chunker) builds upon the `SemanticChunker` by adding a second merging pass. After the initial semantic grouping of sentences, it attempts to merge nearby groups based on their semantic similarity, even if they are separated by a few other groups (controlled by the `skip_window` parameter). This can help capture broader semantic contexts that might be missed by only looking at immediately adjacent sentences or groups. It inherits most parameters and functionalities from `SemanticChunker`.
**Parameters:**
Inherits all parameters from `SemanticChunker` with the addition of:
- `skip_window (int)`: The number of groups to "skip" when checking for potential merges in the second pass. For example, with `skip_window=1`, the chunker compares group `i` with group `i+2`. Defaults to `1`.
**Methods:**
Inherits all methods from `SemanticChunker`, including:
- `chunk(text: str) -> Union[list[SemanticChunk], list[str]]`: Chunks a single string using the double-pass merging strategy.
- `chunk_batch(texts: list[str]) -> Union[list[list[SemanticChunk]], list[list[str]]]`: Chunks a list of strings. (Inherited)
- `from_recipe(name: str, lang: str, **kwargs) -> SDPMChunker`: Creates an `SDPMChunker` using pre-defined recipes. Requires `chonkie[hub]`.
- `__call__(text: Union[str, list[str]]) -> Union[list[SemanticChunk], list[str], list[list[SemanticChunk]], list[list[str]]]`: Convenience method. (Inherited)
**Examples:**
Here are a couple of examples on how to use the `SDPMChunker` in practice.
<details>
<summary><strong>1. Basic Usage of `SDPMChunker`</strong></summary>
```python
# Requires "chonkie[semantic]" or relevant embedding model extra (e.g., "chonkie[st]")
from chonkie import SDPMChunker
# Initialize with default settings (potion-base-8M model, auto threshold, skip_window=1)
chunker = SDPMChunker()
text = "This is the first topic. It discusses semantic chunking. This is a related sentence. Now we switch to a second topic. This topic is about embeddings. We go back to the first topic now. Double-pass merging helps here."
chunks = chunker(text)
# Print out the chunks (SemanticChunk objects)
for i, chunk in enumerate(chunks):
print(f"--- Chunk {i+1} ---")
print(f"Text: {chunk.text}")
print(f"Token Count: {chunk.token_count}")
print(f"Start Index: {chunk.start_index}")
print(f"End Index: {chunk.end_index}")
print(f"Number of Sentences: {len(chunk.sentences)}")
```
</details>
<details>
<summary><strong>2. Using `SDPMChunker` with a larger `skip_window`</strong></summary>
```python
# Requires "chonkie[semantic, st]" for sentence-transformers
from chonkie import SDPMChunker
# Use a larger skip window and a specific model
chunker = SDPMChunker(
embedding_model="all-MiniLM-L6-v2",
chunk_size=128,
skip_window=2 # Try merging groups i and i+3
)
text = "Topic A, sentence 1. Topic A, sentence 2. Topic B, sentence 1. Topic C, sentence 1. Topic A, sentence 3. Merging across B and C might occur."
chunks = chunker(text)
for chunk in chunks:
print(chunk.text)
print(f"Tokens: {chunk.token_count}\n---")
```
</details>
### `LateChunker`
The `LateChunker` implements a chunking strategy based on "late interaction," similar to the logic used in ColBERT style models. It first chunks the text using the logic inherited from `RecursiveChunker` based on specified delimiters and `chunk_size`. Then, it calculates the mean embedding for the tokens within each generated chunk using a provided `sentence-transformers` model. The final output consists of `LateChunk` objects, each containing the chunk text, metadata, and its corresponding sentence embeddings (from mean-pooled token embeddings).
This chunker requires the `sentence-transformers` library. You can install it with `pip install "chonkie[st]"`.
**Parameters:**
- `embedding_model (Union[str, SentenceTransformerEmbeddings, Any])`: The sentence-transformers embedding model to use for generating token embeddings. Can be a string identifier (e.g., `"sentence-transformers/all-MiniLM-L6-v2"`) or an instantiated `SentenceTransformerEmbeddings` object. Defaults to `"sentence-transformers/all-MiniLM-L6-v2"`. Requires `chonkie[st]`.
- `chunk_size (int)`: The target maximum number of tokens per chunk, used by the underlying `RecursiveChunker`. Defaults to `512`.
- `rules (RecursiveRules)`: The recursive splitting rules to use. Defaults to `RecursiveRules()`. Defines delimiters and priorities for splitting.
- `min_characters_per_chunk (int)`: The minimum number of characters required for a chunk to be considered valid. Defaults to `24`.
- `**kwargs (Any)`: Additional keyword arguments passed to the `SentenceTransformerEmbeddings` constructor if `embedding_model` is provided as a string.
**Methods:**
- `chunk(text: str) -> list[LateChunk]`: Chunks a string into a list of `LateChunk` objects, each containing its text, indices, token count, and calculated embedding.
- `chunk_batch(texts: list[str]) -> list[list[LateChunk]]`: Chunks a list of strings. (Inherited)
- `from_recipe(name: str, lang: str, **kwargs) -> LateChunker`: Creates a `LateChunker` instance using pre-defined recursive splitting rules (`RecursiveRules`) from the [Chonkie Recipe Store](https://huggingface.co/datasets/chonkie-ai/recipes). Allows customization of `embedding_model`, `chunk_size`, etc. Requires `chonkie[hub]`.
- `__call__(text: Union[str, list[str]]) -> Union[list[LateChunk], list[list[LateChunk]]]`: Convenience method calling `chunk` or `chunk_batch` depending on input type. (Inherited)
**Examples:**
Here are a couple of examples on how to use the `LateChunker` in practice.
<details>
<summary><strong>1. Basic Usage of `LateChunker`</strong></summary>
```python
# Requires "chonkie[st]" to be installed
from chonkie import LateChunker
# Initialize with default settings (all-MiniLM-L6-v2 model, chunk_size 512)
chunker = LateChunker()
text = "Late interaction models process queries and documents token by token. This chunker provides token-level embeddings for each chunk. It uses recursive splitting first."
chunks = chunker(text)
# Print out the chunks and their embedding shapes
for chunk in chunks:
print(f"Text: {chunk.text}")
print(f"Token Count: {chunk.token_count}")
print(f"Start Index: {chunk.start_index}")
print(f"End Index: {chunk.end_index}")
# Embedding is a numpy array
print(f"Embedding Shape: {chunk.embedding.shape}")
print("-" * 10)
```
</details>
<details>
<summary><strong>2. Using `LateChunker.from_recipe` with a different model</strong></summary>
```python
# Requires "chonkie[st, hub]" to be installed
from chonkie import LateChunker
# Uses default recipe for English ('en') recursive rules
# Specify a different embedding model and chunk size
chunker = LateChunker.from_recipe(
lang="en",
embedding_model="sentence-transformers/paraphrase-MiniLM-L3-v2", # Example different model
chunk_size=128
)
text = "Using a recipe simplifies rule setup. We can still specify the embedding model. This is useful for different languages or text types."
chunks = chunker(text)
for chunk in chunks:
print(chunk.text)
print(f"Tokens: {chunk.token_count}")
print(f"Embedding Shape: {chunk.embedding.shape}\n---")
```
</details>
<details>
<summary><strong>3. Passing `SentenceTransformerEmbeddings` arguments via `**kwargs`</strong></summary>
```python
# Requires "chonkie[st]" to be installed
from chonkie import LateChunker
# Example: Pass arguments to the underlying SentenceTransformer model,
# like specifying the device.
chunker = LateChunker(
embedding_model="sentence-transformers/all-MiniLM-L6-v2",
chunk_size=256,
device="cpu" # Kwarg passed to SentenceTransformerEmbeddings -> SentenceTransformer
)
text = "Keyword arguments allow fine-tuning the embedding model initialization if needed."
chunks = chunker(text)
for chunk in chunks:
print(chunk.text)
print(f"Tokens: {chunk.token_count}\n---")
```
</details>
## Refinery
The `Refinery` classes are used to refine and add additional context to the chunks, through various means.
### `OverlapRefinery`
### `EmbeddingRefinery`
## Chefs
The `Chef` classes are chonkie's pre-processing classes that are used to find, fetch, clean and process the data, preparing it to be chunked. Since Chonkie's chunkers are designed to be non-destructive in nature, the `Chef` classes consist of steps that involve non-reversible operations like conversion from HTML to text, or cleaning text from unwanted characters.
## Tokenizers
Fundamentally, chunking is a token-based operation. Chunking is done to load chunks into embedding models or LLMs, and limitations around size are often token-based. Chonkie supports a variety of tokenizers and tokenizer engines, through its `Tokenizer` class.
The `Tokenizer` class is a wrapper that holds the `tokenizer` engine object and provides a unified interface to `encode`, `decode` and `count_tokens`.
**Available Tokenizers:**
- `character`: Character tokenizer that encodes characters. **This is the default tokenizer.**
- `word`: Word tokenizer that encodes words.
- `tokenizers`: Allows loading any tokenizer from the Hugging Face `tokenizers` library.
- `tiktoken`: Allows using the `tiktoken` tokenizer from OpenAI.
- `transformers`: Allows loading tokenizers from `AutoTokenizer` within the `transformers` library.
**Usage:**
You can initialize a `Tokenizer` object with a string that maps to the desired tokenizer.
```python
from chonkie import Tokenizer
# Uses character tokenizer by default
tokenizer = Tokenizer()
# Or explicitly specify:
tokenizer = Tokenizer("character")
# Or use a different tokenizer:
tokenizer = Tokenizer("gpt2")
```
You can also pass a `tokenizer` engine object to the `Tokenizer` constructor.
```python
from tiktoken import get_encoding
from chonkie import Tokenizer
# Get the tiktoken encoding for gpt2
encoding = get_encoding("gpt2")
# Initialize the Tokenizer with the encoding
tokenizer = Tokenizer(tokenizer=encoding)
```
**Methods:**
- `encode(text: str) -> list[int]`: Encodes a string into a list of tokens.
- `encode_batch(texts: list[str]) -> list[list[int]]`: Encodes a list of strings into a list of lists of tokens.
- `decode(tokens: list[int]) -> str`: Decodes a list of tokens into a string.
- `decode_batch(tokens: list[list[int]]) -> list[str]`: Decodes a list of lists of tokens into a list of strings.
- `count_tokens(text: str) -> int`: Counts the number of tokens in a string.
- `count_tokens_batch(texts: list[str]) -> list[int]`: Counts the number of tokens in a list of strings.
**Example:**
```python
from chonkie import Tokenizer
# Uses character tokenizer by default
tokenizer = Tokenizer()
tokens = tokenizer.encode("Hello, world!")
print(tokens)
decoded = tokenizer.decode(tokens)
print(decoded)
token_count = tokenizer.count_tokens("Hello, world!")
print(token_count)
```
## Embeddings
Chonkie has quite a few usecases for embeddings —— `SemanticChunker` uses them to embed sentences, `LateChunker` uses them to get token embeddings, and the `EmbeddingsRefinery` uses them to get embeddings for downstream upsertion into vector databases. Chonkie tries to support a variety of different embedding models, and providers so that it can be used by as many people as possible.
**Available Embedding Models:** Chonkie supports the following embedding models (with their aliases):
- `Model2VecEmbeddings` (`model2vec`): Uses the `Model2Vec` model to embed text.
- `SentenceTransformerEmbeddings` (`sentence-transformers`): Uses a `SentenceTransformer` model to embed text.
- `OpenAIEmbeddings` (`openai`): Uses the OpenAI embedding API to embed text.
- `CohereEmbeddings` (`cohere`): Uses Cohere's embedding API to embed text.
- `GeminiEmbeddings` (`gemini`): Uses Google's Gemini embedding API to embed text.
- `JinaEmbeddings` (`jina`): Uses Jina's embedding API to embed text.
- `VoyageAIEmbeddings` (`voyageai`): Uses the Voyage AI embedding API to embed text.
Given that it has a bunch of different embedding models, it becomes challenging to keep track of which `Embeddings` class can load a given model. To make this easier, we built the `AutoEmbeddings` class. With `AutoEmbeddings`, you can pass a URI string of the model you want to load and it will return the appropriate `Embeddings` class. The URI usually takes the form of `alias://model_name` or `alias://provider/model_name`.
```python
from chonkie import AutoEmbeddings
# Since this model is registered with the Registry, we can use the string directly
embeddings = AutoEmbeddings.get_embedding("minishlab/potion-base-32M")
# If it's not registered, we can use the full URI with the provider name
embeddings = AutoEmbeddings.get_embedding("model2vec://minishlab/potion-base-32M")
# You can also load the same model with different providers as long as they support the same model
embeddings = AutoEmbeddings.get_embedding("st://minishlab/potion-base-32M")
```
If you're trying to load a model from a local path, it's recommended to use the `SentenceTransformerEmbeddings` class. With the `AutoEmbeddings` class, you can pass in the `model` object initialized with the `SentenceTransformer` class as well, and it will return chonkie's `SentenceTransformerEmbeddings` object.
> [!NOTE]
> If `AutoEmbeddings` can't find a model, it will try to search the HuggingFace Hub for the model and load it with the `SentenceTransformerEmbeddings` class. If that also fails, it will raise a `ValueError`.
**Methods:**
All `Embeddings` classes have the following methods:
- `embed(text: str) -> list[float]`: Embeds a string into a list of floats.
- `embed_batch(texts: list[str]) -> list[list[float]]`: Embeds a list of strings into a list of lists of floats.
- `get_tokenizer_or_token_counter() -> Any`: Returns the tokenizer or token counter object.
- `__call__(text: Union[str, list[str]]) -> Union[list[float], list[list[float]]]`: Embeds a string or a list of strings into a list of floats.
**Example:**
```python
from chonkie import AutoEmbeddings
# Get the embeddings for a model
embeddings = AutoEmbeddings.get_embedding("minishlab/potion-base-32M")
# Embed a string
embedding = embeddings.embed("Hello, world!")
# Embed a list of strings
embeddings = embeddings.embed_batch(["Hello, world!", "Hello, world!"])
```
### Custom Embeddings
If you're trying to load a model that is not already supported by Chonkie, don't worry! We've got you covered. Just follow the steps below:
1. Check if your provider supports the OpenAI API. If it does, you can use the `OpenAIEmbeddings` class with the `base_url` parameter to point to your provider's API. You're all set!
2. If your provider does not support the OpenAI API, and you're loading a model locally, you can use the `SentenceTransformerEmbeddings` class to load your model. You'll need to pass in the `model` object initialized with your model.
3. Lastly, you can create your own `Embeddings` class by inheriting from the `BaseEmbeddings` class and implementing the `embed`, `embed_batch`, and `get_tokenizer_or_token_counter` methods.
**Example:**
```python
from typing import List, Any
from chonkie import BaseEmbeddings
# Let's say we have a custom embedding model that we want to support
class MyEmbeddings(BaseEmbeddings):
def __init__(self, model, tokenizer):
self.model = model
self.tokenizer = tokenizer
def embed(self, text: str) -> list[float]:
return self.model.embed(text)
def embed_batch(self, texts: list[str]) -> list[list[float]]:
return self.model.embed_batch(texts)
def get_tokenizer_or_token_counter(self) -> Any:
return self.tokenizer
@property
def dimension(self) -> int:
return self.model.dimension
def __repr__(self) -> str:
return f"{self.__class__.__name__}(model={self.model}, tokenizer={self.tokenizer})"
```
Of course the above example is a bit contrived, but you get the idea. Once you're done, you can use the above `Embeddings` class with the `SemanticChunker` or `LateChunker` classes, and it will work as expected!
## Genies
Genies are Chonkie's interface for interacting with Large Language Models (LLMs). They can be integrated into advanced chunking strategies (like the `SlumberChunker`) or used for other LLM-powered tasks within your data processing pipeline. Genies handle the communication with different LLM providers, offering a consistent way to generate text or structured JSON output.
Currently, Chonkie provides Genies for Google's Gemini models and OpenAI's models (including compatible APIs).
### `GeminiGenie`
The `GeminiGenie` class provides an interface to interact with Google's Gemini models via the `google-genai` library.
Requires `pip install "chonkie[genie]"`.
**Parameters:**
- `model (str)`: The specific Gemini model to use. Defaults to `"gemini-2.5-pro-preview-03-25"`.
- `api_key (Optional[str])`: Your Google AI API key. If not provided, it will attempt to read from the `GEMINI_API_KEY` environment variable. Defaults to `None`.
**Methods:**
- `generate(prompt: str) -> str`: Sends the prompt to the specified Gemini model and returns the generated text response.
- `generate_json(prompt: str, schema: BaseModel) -> dict[str, Any]`: Sends the prompt and a Pydantic `BaseModel` schema to the Gemini model, requesting a JSON output that conforms to the schema. Returns the parsed JSON as a Python dictionary.
**Examples:**
<details>
<summary><strong>1. Basic Text Generation with `GeminiGenie`</strong></summary>
```python
# Requires "chonkie[genie]"
# Ensure GEMINI_API_KEY environment variable is set or pass api_key argument.
import os
from chonkie.genie import GeminiGenie
api_key = os.getenv("GEMINI_API_KEY")
if not api_key:
raise ValueError("Please set GEMINI_API_KEY or provide the api_key argument.")
# Initialize the genie
genie = GeminiGenie(api_key=api_key)
# Generate text
prompt = "Explain the concept of chunking in simple terms."
response = genie.generate(prompt)
print(response)
```
</details>
<details>
<summary><strong>2. Generating Structured JSON with `GeminiGenie`</strong></summary>
```python
# Requires "chonkie[genie]"
# Ensure GEMINI_API_KEY environment variable is set or pass api_key argument.
import os
from chonkie.genie import GeminiGenie
from pydantic import BaseModel, Field # Requires pydantic
api_key = os.getenv("GEMINI_API_KEY")
if not api_key:
raise ValueError("Please set GEMINI_API_KEY or provide the api_key argument.")
# Define a Pydantic schema for the desired JSON structure
class SummarySchema(BaseModel):
title: str = Field(description="A concise title for the text.")
key_points: list[str] = Field(description="A list of 3-5 key points.")
sentiment: str = Field(description="Overall sentiment (e.g., positive, negative, neutral).")
# Initialize the genie
genie = GeminiGenie(api_key=api_key, model="gemini-1.5-flash") # Example using a different model
# Generate JSON
text_to_summarize = "Chonkie is a great library for text chunking. It's fast, lightweight, and easy to use. Highly recommended!"
prompt = f"Summarize the following text according to the provided schema:\n\n{text_to_summarize}"
json_response = genie.generate_json(prompt, schema=SummarySchema)
print(json_response)
# Example Output:
# {'title': 'Chonkie Library Review', 'key_points': ["Fast and lightweight", "Easy to use", "Highly recommended"], 'sentiment': 'positive'}
```
</details>
### `OpenAIGenie`
---
The `OpenAIGenie` class provides an interface to interact with OpenAI's models (like GPT-4) or any LLM provider that offers an OpenAI-compatible API endpoint.
**Installation:**
`OpenAIGenie` requires `openai` optional dependency to be installed. You can install it via the following command:
```bash
pip install "chonkie[openai]"
```
**Class Definition:**
```python
class OpenAIGenie(BaseGenie):
# Class Attributes
model: str = "gpt-4.1" # The specific model identifier to use (e.g., "gpt-4o", "gpt-3.5-turbo"). Defaults to "gpt-4.1".
base_url: Optional[str] = None # The base URL for the API endpoint. If None, defaults to OpenAI's standard API URL. Use this to connect to custom or self-hosted OpenAI-compatible APIs. Defaults to None.
api_key: Optional[str] = None # Your API key for the service (OpenAI or the custom provider). If not provided, reads from OPENAI_API_KEY env var. Defaults to None.
client: Optional[OpenAI] = None # The OpenAI client instance. If None, a new client will be created. Defaults to None.
# Class Methods
def generate(self, prompt: str) -> str:
"""Sends the prompt to the specified model via the configured endpoint and returns the generated text response."""
...
def generate_json(self, prompt: str, schema: BaseModel) -> dict[str, Any]:
"""Sends the prompt and a Pydantic BaseModel schema to the model, requesting a JSON output that conforms to the schema."""
...
```
**Examples:**
Here are some examples of how to use the `OpenAIGenie` class.
<details>
<summary><strong>1. Basic Text Generation with `OpenAIGenie` (OpenAI)</strong></summary>
```python