|
10 | 10 |
|
11 | 11 | from test_unstructured.unit_utils import FixtureRequest, Mock, function_mock, input_path |
12 | 12 | from unstructured.chunking.base import CHUNK_MULTI_PAGE_DEFAULT |
| 13 | +from unstructured.chunking.basic import chunk_elements |
13 | 14 | from unstructured.chunking.title import _ByTitleChunkingOptions, chunk_by_title |
14 | 15 | from unstructured.documents.coordinates import CoordinateSystem |
15 | 16 | from unstructured.documents.elements import ( |
@@ -888,3 +889,42 @@ def it_applies_token_based_overlap_in_split_chunks(self, _tiktoken_installed: No |
888 | 889 | for chunk in chunks: |
889 | 890 | token_count = len(enc.encode(chunk.text)) |
890 | 891 | assert token_count <= 12, f"Chunk exceeded token limit: {token_count} tokens" |
| 892 | + |
| 893 | + def it_fills_the_token_budget_when_combining_short_sections(self, word_token_counter_: Mock): |
| 894 | + """Short sections combine up to `max_tokens`, like `chunk_elements()` does. |
| 895 | +
|
| 896 | + `combine_text_under_n_chars` defaults to `max_tokens` in token mode, so a section had to |
| 897 | + be under that many *tokens* to be combined. Measuring it in characters instead put every |
| 898 | + section over the threshold and suppressed combining altogether, leaving one chunk per |
| 899 | + section at a fraction of the requested chunk size. |
| 900 | + """ |
| 901 | + elements: list[Element] = [] |
| 902 | + for idx in range(12): |
| 903 | + # -- each section is 2 + 8 == 10 tokens, a sixth of the budget -- |
| 904 | + elements.append(Title(f"Section {idx}")) |
| 905 | + elements.append(Text("alpha beta gamma delta epsilon zeta seven eight")) |
| 906 | + |
| 907 | + chunks = chunk_by_title(elements, max_tokens=60, tokenizer="cl100k_base") |
| 908 | + |
| 909 | + assert [len(chunk.text.split()) for chunk in chunks] == [60, 60] |
| 910 | + # -- and the section boundaries cost nothing relative to ignoring them entirely -- |
| 911 | + assert [chunk.text for chunk in chunks] == [ |
| 912 | + chunk.text for chunk in chunk_elements(elements, max_tokens=60, tokenizer="cl100k_base") |
| 913 | + ] |
| 914 | + |
| 915 | + def it_still_measures_the_combine_threshold_in_characters_in_character_mode(self): |
| 916 | + """Character mode is unaffected: `combine_text_under_n_chars` stays a character count.""" |
| 917 | + elements: list[Element] = [ |
| 918 | + Title("Alpha"), |
| 919 | + Text("one two three four five"), # -- 5 tokens but 23 characters -- |
| 920 | + Title("Bravo"), |
| 921 | + Text("six seven eight nine ten"), |
| 922 | + ] |
| 923 | + |
| 924 | + chunks = chunk_by_title(elements, max_characters=200, combine_text_under_n_chars=20) |
| 925 | + |
| 926 | + # -- 29 characters is over the 20-character threshold, so no combining -- |
| 927 | + assert [chunk.text for chunk in chunks] == [ |
| 928 | + "Alpha\n\none two three four five", |
| 929 | + "Bravo\n\nsix seven eight nine ten", |
| 930 | + ] |
0 commit comments