hanlp-haystack 1.0.1__tar.gz → 2.0.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.0.0/CHANGELOG.md +20 -0
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.0.0}/PKG-INFO +3 -4
- hanlp_haystack-2.0.0/pydoc/config_docusaurus.yml +28 -0
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.0.0}/pyproject.toml +6 -12
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.0.0}/src/haystack_integrations/components/preprocessors/hanlp/chinese_document_splitter.py +25 -24
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.0.0}/tests/test_chinese_document_splitter.py +2 -2
- 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.0.0}/.gitignore +0 -0
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.0.0}/LICENSE.txt +0 -0
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.0.0}/README.md +0 -0
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.0.0}/src/haystack_integrations/components/preprocessors/hanlp/__init__.py +0 -0
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.0.0}/src/haystack_integrations/components/preprocessors/py.typed +0 -0
- {hanlp_haystack-1.0.1 → hanlp_haystack-2.0.0}/tests/__init__.py +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [integrations/hanlp-v1.0.1] - 2025-10-14
|
|
4
|
+
|
|
5
|
+
### 🐛 Bug Fixes
|
|
6
|
+
|
|
7
|
+
- Missing decorator output for ChineseDocumentSplitter (#2377)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### 🧹 Chores
|
|
11
|
+
|
|
12
|
+
- Standardize readmes - part 2 (#2205)
|
|
13
|
+
|
|
14
|
+
## [integrations/hanlp-v1.0.0] - 2025-07-22
|
|
15
|
+
|
|
16
|
+
### 🚀 Features
|
|
17
|
+
|
|
18
|
+
- Add new HanLP integration with ChineseDocumentSplitter (#1943)
|
|
19
|
+
|
|
20
|
+
<!-- generated by git-cliff -->
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hanlp-haystack
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.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
|
|
@@ -59,7 +60,7 @@ 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
|
):
|
|
65
66
|
"""
|
|
@@ -149,7 +150,7 @@ class ChineseDocumentSplitter:
|
|
|
149
150
|
raise ValueError(msg)
|
|
150
151
|
|
|
151
152
|
@component.output_types(documents=list[Document])
|
|
152
|
-
def run(self, documents:
|
|
153
|
+
def run(self, documents: list[Document]) -> dict[str, list[Document]]:
|
|
153
154
|
"""
|
|
154
155
|
Split documents into smaller chunks.
|
|
155
156
|
|
|
@@ -175,7 +176,7 @@ class ChineseDocumentSplitter:
|
|
|
175
176
|
self.chinese_tokenizer = hanlp.load(hanlp.pretrained.tok.FINE_ELECTRA_SMALL_ZH)
|
|
176
177
|
self.split_sent = hanlp.load(hanlp.pretrained.eos.UD_CTB_EOS_MUL)
|
|
177
178
|
|
|
178
|
-
def _split_by_character(self, doc: Document) ->
|
|
179
|
+
def _split_by_character(self, doc: Document) -> list[Document]:
|
|
179
180
|
"""
|
|
180
181
|
Define a function to handle Chinese clauses
|
|
181
182
|
|
|
@@ -202,7 +203,7 @@ class ChineseDocumentSplitter:
|
|
|
202
203
|
)
|
|
203
204
|
|
|
204
205
|
# Define a function to handle Chinese clauses
|
|
205
|
-
def chinese_sentence_split(self, text: str) ->
|
|
206
|
+
def chinese_sentence_split(self, text: str) -> list[dict[str, Any]]:
|
|
206
207
|
"""
|
|
207
208
|
Split Chinese text into sentences.
|
|
208
209
|
|
|
@@ -223,7 +224,7 @@ class ChineseDocumentSplitter:
|
|
|
223
224
|
|
|
224
225
|
return results
|
|
225
226
|
|
|
226
|
-
def _split_document(self, doc: Document) ->
|
|
227
|
+
def _split_document(self, doc: Document) -> list[Document]:
|
|
227
228
|
if self.split_by == "sentence" or self.respect_sentence_boundary:
|
|
228
229
|
return self._split_by_hanlp_sentence(doc)
|
|
229
230
|
|
|
@@ -233,8 +234,8 @@ class ChineseDocumentSplitter:
|
|
|
233
234
|
return self._split_by_character(doc)
|
|
234
235
|
|
|
235
236
|
def _concatenate_sentences_based_on_word_amount(
|
|
236
|
-
self, sentences:
|
|
237
|
-
) ->
|
|
237
|
+
self, sentences: list[str], split_length: int, split_overlap: int, granularity: str
|
|
238
|
+
) -> tuple[list[str], list[int], list[int]]:
|
|
238
239
|
"""
|
|
239
240
|
Groups the sentences into chunks of `split_length` words while respecting sentence boundaries.
|
|
240
241
|
|
|
@@ -251,11 +252,11 @@ class ChineseDocumentSplitter:
|
|
|
251
252
|
chunk_word_count = 0
|
|
252
253
|
chunk_starting_page_number = 1
|
|
253
254
|
chunk_start_idx = 0
|
|
254
|
-
current_chunk:
|
|
255
|
+
current_chunk: list[str] = []
|
|
255
256
|
|
|
256
257
|
# output lists
|
|
257
258
|
split_start_page_numbers = []
|
|
258
|
-
list_of_splits:
|
|
259
|
+
list_of_splits: list[list[str]] = []
|
|
259
260
|
split_start_indices = []
|
|
260
261
|
|
|
261
262
|
for sentence_idx, sentence in enumerate(sentences):
|
|
@@ -305,7 +306,7 @@ class ChineseDocumentSplitter:
|
|
|
305
306
|
|
|
306
307
|
return text_splits, split_start_page_numbers, split_start_indices
|
|
307
308
|
|
|
308
|
-
def _split_by_hanlp_sentence(self, doc: Document) ->
|
|
309
|
+
def _split_by_hanlp_sentence(self, doc: Document) -> list[Document]:
|
|
309
310
|
"""
|
|
310
311
|
Split Chinese text into sentences.
|
|
311
312
|
|
|
@@ -342,8 +343,8 @@ class ChineseDocumentSplitter:
|
|
|
342
343
|
return split_docs
|
|
343
344
|
|
|
344
345
|
def _concatenate_units(
|
|
345
|
-
self, elements:
|
|
346
|
-
) ->
|
|
346
|
+
self, elements: list[str], split_length: int, split_overlap: int, split_threshold: int
|
|
347
|
+
) -> tuple[list[str], list[int], list[int]]:
|
|
347
348
|
"""
|
|
348
349
|
Concatenates the elements into parts of split_length units.
|
|
349
350
|
|
|
@@ -364,9 +365,9 @@ class ChineseDocumentSplitter:
|
|
|
364
365
|
# Otherwise, proceed as before
|
|
365
366
|
step = split_length - split_overlap
|
|
366
367
|
step = max(step, 1)
|
|
367
|
-
text_splits:
|
|
368
|
-
splits_pages:
|
|
369
|
-
splits_start_idxs:
|
|
368
|
+
text_splits: list[str] = []
|
|
369
|
+
splits_pages: list[int] = []
|
|
370
|
+
splits_start_idxs: list[int] = []
|
|
370
371
|
cur_start_idx = 0
|
|
371
372
|
cur_page = 1
|
|
372
373
|
segments = windowed(elements, n=split_length, step=step)
|
|
@@ -399,14 +400,14 @@ class ChineseDocumentSplitter:
|
|
|
399
400
|
return text_splits, splits_pages, splits_start_idxs
|
|
400
401
|
|
|
401
402
|
def _create_docs_from_splits(
|
|
402
|
-
self, text_splits:
|
|
403
|
-
) ->
|
|
403
|
+
self, text_splits: list[str], splits_pages: list[int], splits_start_idxs: list[int], meta: dict[str, Any]
|
|
404
|
+
) -> list[Document]:
|
|
404
405
|
"""
|
|
405
406
|
Creates Document objects from splits enriching them with page number and the metadata of the original document.
|
|
406
407
|
"""
|
|
407
|
-
documents:
|
|
408
|
+
documents: list[Document] = []
|
|
408
409
|
|
|
409
|
-
for i, (txt, split_idx) in enumerate(zip(text_splits, splits_start_idxs)):
|
|
410
|
+
for i, (txt, split_idx) in enumerate(zip(text_splits, splits_start_idxs, strict=True)):
|
|
410
411
|
copied_meta = deepcopy(meta)
|
|
411
412
|
copied_meta["page_number"] = splits_pages[i]
|
|
412
413
|
copied_meta["split_id"] = i
|
|
@@ -460,7 +461,7 @@ class ChineseDocumentSplitter:
|
|
|
460
461
|
overlapping_range = (0, overlapping_range[1] - overlapping_range[0])
|
|
461
462
|
previous_doc.meta["_split_overlap"].append({"doc_id": current_doc.id, "range": overlapping_range})
|
|
462
463
|
|
|
463
|
-
def _number_of_sentences_to_keep(self, sentences:
|
|
464
|
+
def _number_of_sentences_to_keep(self, sentences: list[str], split_length: int, split_overlap: int) -> int:
|
|
464
465
|
"""
|
|
465
466
|
Returns the number of sentences to keep in the next chunk based on the `split_overlap` and `split_length`.
|
|
466
467
|
|
|
@@ -486,7 +487,7 @@ class ChineseDocumentSplitter:
|
|
|
486
487
|
break
|
|
487
488
|
return num_sentences_to_keep
|
|
488
489
|
|
|
489
|
-
def _split_by_function(self, doc: Document) ->
|
|
490
|
+
def _split_by_function(self, doc: Document) -> list[Document]:
|
|
490
491
|
"""
|
|
491
492
|
Split a document using a custom splitting function.
|
|
492
493
|
|
|
@@ -515,7 +516,7 @@ class ChineseDocumentSplitter:
|
|
|
515
516
|
meta=metadata,
|
|
516
517
|
)
|
|
517
518
|
|
|
518
|
-
def to_dict(self) ->
|
|
519
|
+
def to_dict(self) -> dict[str, Any]:
|
|
519
520
|
"""
|
|
520
521
|
Serializes the component to a dictionary.
|
|
521
522
|
"""
|
|
@@ -533,7 +534,7 @@ class ChineseDocumentSplitter:
|
|
|
533
534
|
return serialized
|
|
534
535
|
|
|
535
536
|
@classmethod
|
|
536
|
-
def from_dict(cls, data:
|
|
537
|
+
def from_dict(cls, data: dict[str, Any]) -> "ChineseDocumentSplitter":
|
|
537
538
|
"""
|
|
538
539
|
Deserializes the component from a dictionary.
|
|
539
540
|
"""
|
|
@@ -123,7 +123,7 @@ class TestChineseDocumentSplitter:
|
|
|
123
123
|
splitter.warm_up()
|
|
124
124
|
result = splitter.run(documents=documents)
|
|
125
125
|
assert len(result["documents"]) == 2
|
|
126
|
-
for doc, split_doc in zip(documents, result["documents"]):
|
|
126
|
+
for doc, split_doc in zip(documents, result["documents"], strict=True):
|
|
127
127
|
assert doc.meta.items() <= split_doc.meta.items()
|
|
128
128
|
|
|
129
129
|
@pytest.mark.integration
|
|
@@ -136,7 +136,7 @@ class TestChineseDocumentSplitter:
|
|
|
136
136
|
splitter.warm_up()
|
|
137
137
|
result = splitter.run(documents=documents)
|
|
138
138
|
assert len(result["documents"]) == 2
|
|
139
|
-
for doc, split_doc in zip(documents, result["documents"]):
|
|
139
|
+
for doc, split_doc in zip(documents, result["documents"], strict=True):
|
|
140
140
|
assert doc.id == split_doc.meta["source_id"]
|
|
141
141
|
|
|
142
142
|
@pytest.mark.integration
|
|
@@ -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
|
|
File without changes
|
|
File without changes
|