hanlp-haystack 1.0.1__tar.gz → 2.1.0__tar.gz
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.
- hanlp_haystack-2.1.0/CHANGELOG.md +44 -0
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.1.0}/LICENSE.txt +1 -1
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.1.0}/PKG-INFO +3 -4
- hanlp_haystack-2.1.0/pydoc/config_docusaurus.yml +28 -0
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.1.0}/pyproject.toml +6 -12
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.1.0}/src/haystack_integrations/components/preprocessors/hanlp/__init__.py +1 -0
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.1.0}/src/haystack_integrations/components/preprocessors/hanlp/chinese_document_splitter.py +49 -34
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.1.0}/tests/test_chinese_document_splitter.py +2 -11
- hanlp_haystack-1.0.1/CHANGELOG.md +0 -9
- hanlp_haystack-1.0.1/pydoc/config.yml +0 -29
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.1.0}/.gitignore +0 -0
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.1.0}/README.md +0 -0
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.1.0}/src/haystack_integrations/components/preprocessors/py.typed +0 -0
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.1.0}/tests/__init__.py +0 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [integrations/hanlp-v2.0.0] - 2026-01-12
|
|
4
|
+
|
|
5
|
+
### 🐛 Bug Fixes
|
|
6
|
+
|
|
7
|
+
- Docs: fix hanlp markdown filenames (#2480)
|
|
8
|
+
|
|
9
|
+
### 📚 Documentation
|
|
10
|
+
|
|
11
|
+
- Add pydoc configurations for Docusaurus (#2411)
|
|
12
|
+
|
|
13
|
+
### ⚙️ CI
|
|
14
|
+
|
|
15
|
+
- Change pytest command (#2475)
|
|
16
|
+
|
|
17
|
+
### 🧹 Chores
|
|
18
|
+
|
|
19
|
+
- Remove Readme API CI workflow and configs (#2573)
|
|
20
|
+
- Make fmt command more forgiving (#2671)
|
|
21
|
+
- [**breaking**] Hanlp - drop Python 3.9 and use X|Y typing (#2707)
|
|
22
|
+
|
|
23
|
+
### 🌀 Miscellaneous
|
|
24
|
+
|
|
25
|
+
- Enhancement: Adopt PEP 585 type hinting (part 4) (#2527)
|
|
26
|
+
|
|
27
|
+
## [integrations/hanlp-v1.0.1] - 2025-10-14
|
|
28
|
+
|
|
29
|
+
### 🐛 Bug Fixes
|
|
30
|
+
|
|
31
|
+
- Missing decorator output for ChineseDocumentSplitter (#2377)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### 🧹 Chores
|
|
35
|
+
|
|
36
|
+
- Standardize readmes - part 2 (#2205)
|
|
37
|
+
|
|
38
|
+
## [integrations/hanlp-v1.0.0] - 2025-07-22
|
|
39
|
+
|
|
40
|
+
### 🚀 Features
|
|
41
|
+
|
|
42
|
+
- Add new HanLP integration with ChineseDocumentSplitter (#1943)
|
|
43
|
+
|
|
44
|
+
<!-- generated by git-cliff -->
|
|
@@ -58,7 +58,7 @@ APPENDIX: How to apply the Apache License to your work.
|
|
|
58
58
|
|
|
59
59
|
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
|
|
60
60
|
|
|
61
|
-
Copyright
|
|
61
|
+
Copyright 2025 deepset GmbH
|
|
62
62
|
|
|
63
63
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
64
64
|
you may not use this file except in compliance with the License.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hanlp-haystack
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: An integration of Han Language Processing - HanLP as a ChineseDocumentSplitter component.
|
|
5
5
|
Project-URL: Documentation, https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/hanlp#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/deepset-ai/haystack-core-integrations/issues
|
|
@@ -11,16 +11,15 @@ License-File: LICENSE.txt
|
|
|
11
11
|
Classifier: Development Status :: 4 - Beta
|
|
12
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
13
|
Classifier: Programming Language :: Python
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
18
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
20
19
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
21
|
-
Requires-Python: >=3.
|
|
20
|
+
Requires-Python: >=3.10
|
|
22
21
|
Requires-Dist: hanlp>=2.1.1
|
|
23
|
-
Requires-Dist: haystack-ai>=2.
|
|
22
|
+
Requires-Dist: haystack-ai>=2.22.0
|
|
24
23
|
Description-Content-Type: text/markdown
|
|
25
24
|
|
|
26
25
|
# hanlp-haystack
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
loaders:
|
|
2
|
+
- ignore_when_discovered:
|
|
3
|
+
- __init__
|
|
4
|
+
modules:
|
|
5
|
+
- haystack_integrations.components.preprocessors.hanlp.chinese_document_splitter
|
|
6
|
+
search_path:
|
|
7
|
+
- ../src
|
|
8
|
+
type: haystack_pydoc_tools.loaders.CustomPythonLoader
|
|
9
|
+
processors:
|
|
10
|
+
- do_not_filter_modules: false
|
|
11
|
+
documented_only: true
|
|
12
|
+
expression: null
|
|
13
|
+
skip_empty_modules: true
|
|
14
|
+
type: filter
|
|
15
|
+
- type: smart
|
|
16
|
+
- type: crossref
|
|
17
|
+
renderer:
|
|
18
|
+
description: HanLP integration for Haystack
|
|
19
|
+
id: integrations-hanlp
|
|
20
|
+
markdown:
|
|
21
|
+
add_member_class_prefix: false
|
|
22
|
+
add_method_class_prefix: true
|
|
23
|
+
classdef_code_block: false
|
|
24
|
+
descriptive_class_title: false
|
|
25
|
+
descriptive_module_title: true
|
|
26
|
+
filename: hanlp.md
|
|
27
|
+
title: HanLP
|
|
28
|
+
type: haystack_pydoc_tools.renderers.DocusaurusRenderer
|
|
@@ -7,7 +7,7 @@ name = "hanlp-haystack"
|
|
|
7
7
|
dynamic = ["version"]
|
|
8
8
|
description = 'An integration of Han Language Processing - HanLP as a ChineseDocumentSplitter component.'
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
keywords = []
|
|
13
13
|
authors = [{ name = "deepset GmbH", email = "info@deepset.ai" }]
|
|
@@ -15,7 +15,6 @@ classifiers = [
|
|
|
15
15
|
"License :: OSI Approved :: Apache Software License",
|
|
16
16
|
"Development Status :: 4 - Beta",
|
|
17
17
|
"Programming Language :: Python",
|
|
18
|
-
"Programming Language :: Python :: 3.9",
|
|
19
18
|
"Programming Language :: Python :: 3.10",
|
|
20
19
|
"Programming Language :: Python :: 3.11",
|
|
21
20
|
"Programming Language :: Python :: 3.12",
|
|
@@ -24,7 +23,7 @@ classifiers = [
|
|
|
24
23
|
"Programming Language :: Python :: Implementation :: PyPy",
|
|
25
24
|
]
|
|
26
25
|
dependencies = [
|
|
27
|
-
"haystack-ai>=2.
|
|
26
|
+
"haystack-ai>=2.22.0",
|
|
28
27
|
"hanlp>=2.1.1"
|
|
29
28
|
]
|
|
30
29
|
|
|
@@ -49,8 +48,8 @@ installer = "uv"
|
|
|
49
48
|
dependencies = ["haystack-pydoc-tools", "ruff"]
|
|
50
49
|
|
|
51
50
|
[tool.hatch.envs.default.scripts]
|
|
52
|
-
docs = ["pydoc-markdown pydoc/
|
|
53
|
-
fmt = "ruff check --fix {args}
|
|
51
|
+
docs = ["pydoc-markdown pydoc/config_docusaurus.yml"]
|
|
52
|
+
fmt = "ruff check --fix {args}; ruff format {args}"
|
|
54
53
|
fmt-check = "ruff check {args} && ruff format --check {args}"
|
|
55
54
|
|
|
56
55
|
[tool.hatch.envs.test]
|
|
@@ -67,7 +66,7 @@ dependencies = [
|
|
|
67
66
|
unit = 'pytest -m "not integration" {args:tests}'
|
|
68
67
|
integration = 'pytest -m "integration" {args:tests}'
|
|
69
68
|
all = 'pytest {args:tests}'
|
|
70
|
-
cov-retry = '
|
|
69
|
+
cov-retry = 'pytest --cov=haystack_integrations --reruns 3 --reruns-delay 30 -x {args:tests}'
|
|
71
70
|
types = """mypy -p haystack_integrations.components.preprocessors.hanlp {args}"""
|
|
72
71
|
|
|
73
72
|
[tool.mypy]
|
|
@@ -83,12 +82,11 @@ module = [
|
|
|
83
82
|
ignore_missing_imports = true
|
|
84
83
|
|
|
85
84
|
[tool.black]
|
|
86
|
-
target-version = ["
|
|
85
|
+
target-version = ["py39"]
|
|
87
86
|
line-length = 120
|
|
88
87
|
skip-string-normalization = true
|
|
89
88
|
|
|
90
89
|
[tool.ruff]
|
|
91
|
-
target-version = "py38"
|
|
92
90
|
line-length = 120
|
|
93
91
|
|
|
94
92
|
[tool.ruff.lint]
|
|
@@ -138,10 +136,6 @@ ignore = [
|
|
|
138
136
|
"RUF001",
|
|
139
137
|
"RUF002",
|
|
140
138
|
]
|
|
141
|
-
unfixable = [
|
|
142
|
-
# Don't touch unused imports
|
|
143
|
-
"F401",
|
|
144
|
-
]
|
|
145
139
|
|
|
146
140
|
[tool.ruff.lint.isort]
|
|
147
141
|
known-first-party = ["haystack_integrations"]
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
|
+
from collections.abc import Callable
|
|
5
6
|
from copy import deepcopy
|
|
6
|
-
from typing import Any,
|
|
7
|
+
from typing import Any, Literal
|
|
7
8
|
|
|
8
9
|
from haystack import Document, component, logging
|
|
9
10
|
from haystack.core.serialization import default_from_dict, default_to_dict
|
|
@@ -11,6 +12,7 @@ from haystack.utils import deserialize_callable, serialize_callable
|
|
|
11
12
|
from more_itertools import windowed
|
|
12
13
|
|
|
13
14
|
import hanlp
|
|
15
|
+
from hanlp.common.component import Component as HanlpComponent
|
|
14
16
|
|
|
15
17
|
logger = logging.getLogger(__name__)
|
|
16
18
|
|
|
@@ -46,7 +48,6 @@ class ChineseDocumentSplitter:
|
|
|
46
48
|
splitter = ChineseDocumentSplitter(
|
|
47
49
|
split_by="word", split_length=10, split_overlap=3, respect_sentence_boundary=True
|
|
48
50
|
)
|
|
49
|
-
splitter.warm_up()
|
|
50
51
|
result = splitter.run(documents=[doc])
|
|
51
52
|
print(result["documents"])
|
|
52
53
|
```
|
|
@@ -59,9 +60,9 @@ class ChineseDocumentSplitter:
|
|
|
59
60
|
split_overlap: int = 200,
|
|
60
61
|
split_threshold: int = 0,
|
|
61
62
|
respect_sentence_boundary: bool = False,
|
|
62
|
-
splitting_function:
|
|
63
|
+
splitting_function: Callable | None = None,
|
|
63
64
|
granularity: Literal["coarse", "fine"] = "coarse",
|
|
64
|
-
):
|
|
65
|
+
) -> None:
|
|
65
66
|
"""
|
|
66
67
|
Initialize the ChineseDocumentSplitter component.
|
|
67
68
|
|
|
@@ -94,6 +95,9 @@ class ChineseDocumentSplitter:
|
|
|
94
95
|
self.respect_sentence_boundary = respect_sentence_boundary
|
|
95
96
|
self.splitting_function = splitting_function
|
|
96
97
|
self.granularity = granularity
|
|
98
|
+
self.chinese_tokenizer: HanlpComponent | None = None
|
|
99
|
+
self.split_sent: HanlpComponent | None = None
|
|
100
|
+
self._is_warmed_up = False
|
|
97
101
|
|
|
98
102
|
@staticmethod
|
|
99
103
|
def _validate_init_parameters(
|
|
@@ -149,7 +153,7 @@ class ChineseDocumentSplitter:
|
|
|
149
153
|
raise ValueError(msg)
|
|
150
154
|
|
|
151
155
|
@component.output_types(documents=list[Document])
|
|
152
|
-
def run(self, documents:
|
|
156
|
+
def run(self, documents: list[Document]) -> dict[str, list[Document]]:
|
|
153
157
|
"""
|
|
154
158
|
Split documents into smaller chunks.
|
|
155
159
|
|
|
@@ -158,9 +162,8 @@ class ChineseDocumentSplitter:
|
|
|
158
162
|
|
|
159
163
|
:raises RuntimeError: If the Chinese word segmentation model is not loaded.
|
|
160
164
|
"""
|
|
161
|
-
if self.
|
|
162
|
-
|
|
163
|
-
raise RuntimeError(msg)
|
|
165
|
+
if not self._is_warmed_up:
|
|
166
|
+
self.warm_up()
|
|
164
167
|
|
|
165
168
|
split_docs = []
|
|
166
169
|
for doc in documents:
|
|
@@ -169,13 +172,17 @@ class ChineseDocumentSplitter:
|
|
|
169
172
|
|
|
170
173
|
def warm_up(self) -> None:
|
|
171
174
|
"""Warm up the component by loading the necessary models."""
|
|
175
|
+
if self._is_warmed_up:
|
|
176
|
+
return
|
|
177
|
+
|
|
172
178
|
if self.granularity == "coarse":
|
|
173
179
|
self.chinese_tokenizer = hanlp.load(hanlp.pretrained.tok.COARSE_ELECTRA_SMALL_ZH)
|
|
174
180
|
if self.granularity == "fine":
|
|
175
181
|
self.chinese_tokenizer = hanlp.load(hanlp.pretrained.tok.FINE_ELECTRA_SMALL_ZH)
|
|
176
182
|
self.split_sent = hanlp.load(hanlp.pretrained.eos.UD_CTB_EOS_MUL)
|
|
183
|
+
self._is_warmed_up = True
|
|
177
184
|
|
|
178
|
-
def _split_by_character(self, doc: Document) ->
|
|
185
|
+
def _split_by_character(self, doc: Document) -> list[Document]:
|
|
179
186
|
"""
|
|
180
187
|
Define a function to handle Chinese clauses
|
|
181
188
|
|
|
@@ -187,7 +194,7 @@ class ChineseDocumentSplitter:
|
|
|
187
194
|
|
|
188
195
|
split_at = _CHARACTER_SPLIT_BY_MAPPING[self.split_by]
|
|
189
196
|
|
|
190
|
-
units = self.chinese_tokenizer(doc.content)
|
|
197
|
+
units = self.chinese_tokenizer(doc.content) # type: ignore[misc]
|
|
191
198
|
|
|
192
199
|
for i in range(len(units) - 1):
|
|
193
200
|
units[i] += split_at
|
|
@@ -202,7 +209,7 @@ class ChineseDocumentSplitter:
|
|
|
202
209
|
)
|
|
203
210
|
|
|
204
211
|
# Define a function to handle Chinese clauses
|
|
205
|
-
def chinese_sentence_split(self, text: str) ->
|
|
212
|
+
def chinese_sentence_split(self, text: str) -> list[dict[str, Any]]:
|
|
206
213
|
"""
|
|
207
214
|
Split Chinese text into sentences.
|
|
208
215
|
|
|
@@ -210,7 +217,7 @@ class ChineseDocumentSplitter:
|
|
|
210
217
|
:return: A list of split sentences.
|
|
211
218
|
"""
|
|
212
219
|
# Split sentences
|
|
213
|
-
sentences = self.split_sent(text)
|
|
220
|
+
sentences = self.split_sent(text) # type: ignore[misc]
|
|
214
221
|
|
|
215
222
|
# Organize the format of segmented sentences
|
|
216
223
|
results = []
|
|
@@ -223,7 +230,7 @@ class ChineseDocumentSplitter:
|
|
|
223
230
|
|
|
224
231
|
return results
|
|
225
232
|
|
|
226
|
-
def _split_document(self, doc: Document) ->
|
|
233
|
+
def _split_document(self, doc: Document) -> list[Document]:
|
|
227
234
|
if self.split_by == "sentence" or self.respect_sentence_boundary:
|
|
228
235
|
return self._split_by_hanlp_sentence(doc)
|
|
229
236
|
|
|
@@ -233,8 +240,8 @@ class ChineseDocumentSplitter:
|
|
|
233
240
|
return self._split_by_character(doc)
|
|
234
241
|
|
|
235
242
|
def _concatenate_sentences_based_on_word_amount(
|
|
236
|
-
self, sentences:
|
|
237
|
-
) ->
|
|
243
|
+
self, sentences: list[str], split_length: int, split_overlap: int, granularity: str
|
|
244
|
+
) -> tuple[list[str], list[int], list[int]]:
|
|
238
245
|
"""
|
|
239
246
|
Groups the sentences into chunks of `split_length` words while respecting sentence boundaries.
|
|
240
247
|
|
|
@@ -251,18 +258,24 @@ class ChineseDocumentSplitter:
|
|
|
251
258
|
chunk_word_count = 0
|
|
252
259
|
chunk_starting_page_number = 1
|
|
253
260
|
chunk_start_idx = 0
|
|
254
|
-
current_chunk:
|
|
261
|
+
current_chunk: list[str] = []
|
|
255
262
|
|
|
256
263
|
# output lists
|
|
257
264
|
split_start_page_numbers = []
|
|
258
|
-
list_of_splits:
|
|
265
|
+
list_of_splits: list[list[str]] = []
|
|
259
266
|
split_start_indices = []
|
|
260
267
|
|
|
261
268
|
for sentence_idx, sentence in enumerate(sentences):
|
|
262
269
|
current_chunk.append(sentence)
|
|
263
|
-
chunk_word_count += len(
|
|
270
|
+
chunk_word_count += len(
|
|
271
|
+
self.chinese_tokenizer(sentence) # type: ignore[misc]
|
|
272
|
+
)
|
|
264
273
|
next_sentence_word_count = (
|
|
265
|
-
len(
|
|
274
|
+
len(
|
|
275
|
+
self.chinese_tokenizer(sentences[sentence_idx + 1]) # type: ignore[misc]
|
|
276
|
+
)
|
|
277
|
+
if sentence_idx < len(sentences) - 1
|
|
278
|
+
else 0
|
|
266
279
|
)
|
|
267
280
|
|
|
268
281
|
# Number of words in the current chunk plus the next sentence is larger than the split_length,
|
|
@@ -305,7 +318,7 @@ class ChineseDocumentSplitter:
|
|
|
305
318
|
|
|
306
319
|
return text_splits, split_start_page_numbers, split_start_indices
|
|
307
320
|
|
|
308
|
-
def _split_by_hanlp_sentence(self, doc: Document) ->
|
|
321
|
+
def _split_by_hanlp_sentence(self, doc: Document) -> list[Document]:
|
|
309
322
|
"""
|
|
310
323
|
Split Chinese text into sentences.
|
|
311
324
|
|
|
@@ -342,8 +355,8 @@ class ChineseDocumentSplitter:
|
|
|
342
355
|
return split_docs
|
|
343
356
|
|
|
344
357
|
def _concatenate_units(
|
|
345
|
-
self, elements:
|
|
346
|
-
) ->
|
|
358
|
+
self, elements: list[str], split_length: int, split_overlap: int, split_threshold: int
|
|
359
|
+
) -> tuple[list[str], list[int], list[int]]:
|
|
347
360
|
"""
|
|
348
361
|
Concatenates the elements into parts of split_length units.
|
|
349
362
|
|
|
@@ -364,9 +377,9 @@ class ChineseDocumentSplitter:
|
|
|
364
377
|
# Otherwise, proceed as before
|
|
365
378
|
step = split_length - split_overlap
|
|
366
379
|
step = max(step, 1)
|
|
367
|
-
text_splits:
|
|
368
|
-
splits_pages:
|
|
369
|
-
splits_start_idxs:
|
|
380
|
+
text_splits: list[str] = []
|
|
381
|
+
splits_pages: list[int] = []
|
|
382
|
+
splits_start_idxs: list[int] = []
|
|
370
383
|
cur_start_idx = 0
|
|
371
384
|
cur_page = 1
|
|
372
385
|
segments = windowed(elements, n=split_length, step=step)
|
|
@@ -399,14 +412,14 @@ class ChineseDocumentSplitter:
|
|
|
399
412
|
return text_splits, splits_pages, splits_start_idxs
|
|
400
413
|
|
|
401
414
|
def _create_docs_from_splits(
|
|
402
|
-
self, text_splits:
|
|
403
|
-
) ->
|
|
415
|
+
self, text_splits: list[str], splits_pages: list[int], splits_start_idxs: list[int], meta: dict[str, Any]
|
|
416
|
+
) -> list[Document]:
|
|
404
417
|
"""
|
|
405
418
|
Creates Document objects from splits enriching them with page number and the metadata of the original document.
|
|
406
419
|
"""
|
|
407
|
-
documents:
|
|
420
|
+
documents: list[Document] = []
|
|
408
421
|
|
|
409
|
-
for i, (txt, split_idx) in enumerate(zip(text_splits, splits_start_idxs)):
|
|
422
|
+
for i, (txt, split_idx) in enumerate(zip(text_splits, splits_start_idxs, strict=True)):
|
|
410
423
|
copied_meta = deepcopy(meta)
|
|
411
424
|
copied_meta["page_number"] = splits_pages[i]
|
|
412
425
|
copied_meta["split_id"] = i
|
|
@@ -460,7 +473,7 @@ class ChineseDocumentSplitter:
|
|
|
460
473
|
overlapping_range = (0, overlapping_range[1] - overlapping_range[0])
|
|
461
474
|
previous_doc.meta["_split_overlap"].append({"doc_id": current_doc.id, "range": overlapping_range})
|
|
462
475
|
|
|
463
|
-
def _number_of_sentences_to_keep(self, sentences:
|
|
476
|
+
def _number_of_sentences_to_keep(self, sentences: list[str], split_length: int, split_overlap: int) -> int:
|
|
464
477
|
"""
|
|
465
478
|
Returns the number of sentences to keep in the next chunk based on the `split_overlap` and `split_length`.
|
|
466
479
|
|
|
@@ -477,7 +490,9 @@ class ChineseDocumentSplitter:
|
|
|
477
490
|
num_words = 0
|
|
478
491
|
|
|
479
492
|
for sent in reversed(sentences[1:]):
|
|
480
|
-
num_words += len(
|
|
493
|
+
num_words += len(
|
|
494
|
+
self.chinese_tokenizer(sent) # type: ignore[misc]
|
|
495
|
+
)
|
|
481
496
|
# If the number of words is larger than the split_length then don't add any more sentences
|
|
482
497
|
if num_words > split_length:
|
|
483
498
|
break
|
|
@@ -486,7 +501,7 @@ class ChineseDocumentSplitter:
|
|
|
486
501
|
break
|
|
487
502
|
return num_sentences_to_keep
|
|
488
503
|
|
|
489
|
-
def _split_by_function(self, doc: Document) ->
|
|
504
|
+
def _split_by_function(self, doc: Document) -> list[Document]:
|
|
490
505
|
"""
|
|
491
506
|
Split a document using a custom splitting function.
|
|
492
507
|
|
|
@@ -515,7 +530,7 @@ class ChineseDocumentSplitter:
|
|
|
515
530
|
meta=metadata,
|
|
516
531
|
)
|
|
517
532
|
|
|
518
|
-
def to_dict(self) ->
|
|
533
|
+
def to_dict(self) -> dict[str, Any]:
|
|
519
534
|
"""
|
|
520
535
|
Serializes the component to a dictionary.
|
|
521
536
|
"""
|
|
@@ -533,7 +548,7 @@ class ChineseDocumentSplitter:
|
|
|
533
548
|
return serialized
|
|
534
549
|
|
|
535
550
|
@classmethod
|
|
536
|
-
def from_dict(cls, data:
|
|
551
|
+
def from_dict(cls, data: dict[str, Any]) -> "ChineseDocumentSplitter":
|
|
537
552
|
"""
|
|
538
553
|
Deserializes the component from a dictionary.
|
|
539
554
|
"""
|
|
@@ -93,7 +93,6 @@ class TestChineseDocumentSplitter:
|
|
|
93
93
|
@pytest.mark.integration
|
|
94
94
|
def test_empty_list(self):
|
|
95
95
|
splitter = ChineseDocumentSplitter()
|
|
96
|
-
splitter.warm_up()
|
|
97
96
|
results = splitter.run(documents=[])
|
|
98
97
|
assert results == {"documents": []}
|
|
99
98
|
|
|
@@ -101,7 +100,6 @@ class TestChineseDocumentSplitter:
|
|
|
101
100
|
def test_empty_document(self):
|
|
102
101
|
splitter = ChineseDocumentSplitter()
|
|
103
102
|
documents = [Document(content="")]
|
|
104
|
-
splitter.warm_up()
|
|
105
103
|
results = splitter.run(documents=documents)
|
|
106
104
|
assert results == {"documents": []}
|
|
107
105
|
|
|
@@ -109,7 +107,6 @@ class TestChineseDocumentSplitter:
|
|
|
109
107
|
def test_whitespace_only_document(self):
|
|
110
108
|
splitter = ChineseDocumentSplitter()
|
|
111
109
|
documents = [Document(content=" ")]
|
|
112
|
-
splitter.warm_up()
|
|
113
110
|
results = splitter.run(documents=documents)
|
|
114
111
|
assert len(results["documents"]) == 0
|
|
115
112
|
|
|
@@ -120,10 +117,9 @@ class TestChineseDocumentSplitter:
|
|
|
120
117
|
Document(content="这是另一个测试文本。", meta={"name": "doc 1"}),
|
|
121
118
|
]
|
|
122
119
|
splitter = ChineseDocumentSplitter(split_by="word", split_length=5, split_overlap=2)
|
|
123
|
-
splitter.warm_up()
|
|
124
120
|
result = splitter.run(documents=documents)
|
|
125
121
|
assert len(result["documents"]) == 2
|
|
126
|
-
for doc, split_doc in zip(documents, result["documents"]):
|
|
122
|
+
for doc, split_doc in zip(documents, result["documents"], strict=True):
|
|
127
123
|
assert doc.meta.items() <= split_doc.meta.items()
|
|
128
124
|
|
|
129
125
|
@pytest.mark.integration
|
|
@@ -133,16 +129,14 @@ class TestChineseDocumentSplitter:
|
|
|
133
129
|
Document(content="这是第二个测试文本。"),
|
|
134
130
|
]
|
|
135
131
|
splitter = ChineseDocumentSplitter(split_by="word", split_length=5, split_overlap=2)
|
|
136
|
-
splitter.warm_up()
|
|
137
132
|
result = splitter.run(documents=documents)
|
|
138
133
|
assert len(result["documents"]) == 2
|
|
139
|
-
for doc, split_doc in zip(documents, result["documents"]):
|
|
134
|
+
for doc, split_doc in zip(documents, result["documents"], strict=True):
|
|
140
135
|
assert doc.id == split_doc.meta["source_id"]
|
|
141
136
|
|
|
142
137
|
@pytest.mark.integration
|
|
143
138
|
def test_split_by_word(self, sample_text):
|
|
144
139
|
splitter = ChineseDocumentSplitter(split_by="word", granularity="coarse", split_length=5, split_overlap=0)
|
|
145
|
-
splitter.warm_up()
|
|
146
140
|
result = splitter.run(documents=[Document(content=sample_text)])
|
|
147
141
|
docs = result["documents"]
|
|
148
142
|
assert all(isinstance(doc, Document) for doc in docs)
|
|
@@ -153,7 +147,6 @@ class TestChineseDocumentSplitter:
|
|
|
153
147
|
@pytest.mark.integration
|
|
154
148
|
def test_split_by_sentence(self, sample_text):
|
|
155
149
|
splitter = ChineseDocumentSplitter(split_by="sentence", granularity="coarse", split_length=10, split_overlap=0)
|
|
156
|
-
splitter.warm_up()
|
|
157
150
|
result = splitter.run(documents=[Document(content=sample_text)])
|
|
158
151
|
docs = result["documents"]
|
|
159
152
|
assert all(isinstance(doc, Document) for doc in docs), "All docs should be instances of Document"
|
|
@@ -170,7 +163,6 @@ class TestChineseDocumentSplitter:
|
|
|
170
163
|
splitter = ChineseDocumentSplitter(
|
|
171
164
|
split_by="word", split_length=10, split_overlap=3, respect_sentence_boundary=True
|
|
172
165
|
)
|
|
173
|
-
splitter.warm_up()
|
|
174
166
|
result = splitter.run(documents=[doc])
|
|
175
167
|
docs = result["documents"]
|
|
176
168
|
|
|
@@ -193,7 +185,6 @@ class TestChineseDocumentSplitter:
|
|
|
193
185
|
)
|
|
194
186
|
|
|
195
187
|
splitter = ChineseDocumentSplitter(split_by="word", split_length=30, split_overlap=10, granularity="coarse")
|
|
196
|
-
splitter.warm_up()
|
|
197
188
|
result = splitter.run(documents=[doc])
|
|
198
189
|
docs = result["documents"]
|
|
199
190
|
assert len(docs) == 6
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
loaders:
|
|
2
|
-
- type: haystack_pydoc_tools.loaders.CustomPythonLoader
|
|
3
|
-
search_path: [../src]
|
|
4
|
-
modules: [
|
|
5
|
-
"haystack_integrations.components.preprocessors.hanlp.chinese_document_splitter",
|
|
6
|
-
]
|
|
7
|
-
ignore_when_discovered: ["__init__"]
|
|
8
|
-
processors:
|
|
9
|
-
- type: filter
|
|
10
|
-
expression:
|
|
11
|
-
documented_only: true
|
|
12
|
-
do_not_filter_modules: false
|
|
13
|
-
skip_empty_modules: true
|
|
14
|
-
- type: smart
|
|
15
|
-
- type: crossref
|
|
16
|
-
renderer:
|
|
17
|
-
type: haystack_pydoc_tools.renderers.ReadmeIntegrationRenderer
|
|
18
|
-
excerpt: HanLP integration for Haystack
|
|
19
|
-
category_slug: integrations-api
|
|
20
|
-
title: HanLP
|
|
21
|
-
slug: integrations-hanlp
|
|
22
|
-
order: 100
|
|
23
|
-
markdown:
|
|
24
|
-
descriptive_class_title: false
|
|
25
|
-
classdef_code_block: false
|
|
26
|
-
descriptive_module_title: true
|
|
27
|
-
add_method_class_prefix: true
|
|
28
|
-
add_member_class_prefix: false
|
|
29
|
-
filename: _readme_github.md
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|