phrasplit 0.2.0__tar.gz → 0.2.2__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.
Files changed (66) hide show
  1. {phrasplit-0.2.0 → phrasplit-0.2.2}/PKG-INFO +123 -27
  2. {phrasplit-0.2.0 → phrasplit-0.2.2}/README.md +119 -25
  3. phrasplit-0.2.2/benchmarks/benchmark_simple_vs_spacy.py +116 -0
  4. {phrasplit-0.2.0 → phrasplit-0.2.2}/benchmarks/phrasplit_segmenter.py +8 -0
  5. {phrasplit-0.2.0 → phrasplit-0.2.2}/benchmarks/runbatcheval.py +23 -7
  6. {phrasplit-0.2.0 → phrasplit-0.2.2}/docs/api.rst +16 -0
  7. {phrasplit-0.2.0 → phrasplit-0.2.2}/docs/cli.rst +42 -7
  8. {phrasplit-0.2.0 → phrasplit-0.2.2}/docs/index.rst +33 -6
  9. phrasplit-0.2.2/docs/installation.rst +127 -0
  10. {phrasplit-0.2.0 → phrasplit-0.2.2}/docs/usage.rst +55 -3
  11. phrasplit-0.2.2/examples/simple_vs_spacy.py +44 -0
  12. {phrasplit-0.2.0 → phrasplit-0.2.2}/phrasplit/_version.py +3 -3
  13. {phrasplit-0.2.0 → phrasplit-0.2.2}/phrasplit/cli.py +62 -3
  14. {phrasplit-0.2.0 → phrasplit-0.2.2}/phrasplit/splitter.py +270 -46
  15. phrasplit-0.2.2/phrasplit/splitter_without_spacy.py +494 -0
  16. {phrasplit-0.2.0 → phrasplit-0.2.2}/phrasplit.egg-info/PKG-INFO +123 -27
  17. {phrasplit-0.2.0 → phrasplit-0.2.2}/phrasplit.egg-info/SOURCES.txt +6 -1
  18. {phrasplit-0.2.0 → phrasplit-0.2.2}/phrasplit.egg-info/requires.txt +4 -1
  19. {phrasplit-0.2.0 → phrasplit-0.2.2}/pyproject.toml +4 -1
  20. phrasplit-0.2.2/tests/test_comparison.py +139 -0
  21. phrasplit-0.2.2/tests/test_splitter_without_spacy.py +682 -0
  22. phrasplit-0.2.0/docs/installation.rst +0 -73
  23. {phrasplit-0.2.0 → phrasplit-0.2.2}/.github/pytest.ini +0 -0
  24. {phrasplit-0.2.0 → phrasplit-0.2.2}/.github/workflows/codecov.yml +0 -0
  25. {phrasplit-0.2.0 → phrasplit-0.2.2}/.github/workflows/pre-commit.yml +0 -0
  26. {phrasplit-0.2.0 → phrasplit-0.2.2}/.github/workflows/python-publish.yml +0 -0
  27. {phrasplit-0.2.0 → phrasplit-0.2.2}/.github/workflows/tests.yml +0 -0
  28. {phrasplit-0.2.0 → phrasplit-0.2.2}/.gitignore +0 -0
  29. {phrasplit-0.2.0 → phrasplit-0.2.2}/.pre-commit-config.yaml +0 -0
  30. {phrasplit-0.2.0 → phrasplit-0.2.2}/.prettierrc.yml +0 -0
  31. {phrasplit-0.2.0 → phrasplit-0.2.2}/.readthedocs.yaml +0 -0
  32. {phrasplit-0.2.0 → phrasplit-0.2.2}/.ruff.toml +0 -0
  33. {phrasplit-0.2.0 → phrasplit-0.2.2}/LICENSE +0 -0
  34. {phrasplit-0.2.0 → phrasplit-0.2.2}/benchmarks/.gitignore +0 -0
  35. {phrasplit-0.2.0 → phrasplit-0.2.2}/benchmarks/README.md +0 -0
  36. {phrasplit-0.2.0 → phrasplit-0.2.2}/benchmarks/build-testset.py +0 -0
  37. {phrasplit-0.2.0 → phrasplit-0.2.2}/benchmarks/cleanup.py +0 -0
  38. {phrasplit-0.2.0 → phrasplit-0.2.2}/benchmarks/compare_segmenters.py +0 -0
  39. {phrasplit-0.2.0 → phrasplit-0.2.2}/benchmarks/debug_sentence.py +0 -0
  40. {phrasplit-0.2.0 → phrasplit-0.2.2}/benchmarks/runeverything.py +0 -0
  41. {phrasplit-0.2.0 → phrasplit-0.2.2}/benchmarks/segmenteval.py +0 -0
  42. {phrasplit-0.2.0 → phrasplit-0.2.2}/benchmarks/sentencizer_segmenter.py +0 -0
  43. {phrasplit-0.2.0 → phrasplit-0.2.2}/benchmarks/spacy_segmenter.py +0 -0
  44. {phrasplit-0.2.0 → phrasplit-0.2.2}/docs/conf.py +0 -0
  45. {phrasplit-0.2.0 → phrasplit-0.2.2}/docs/examples.rst +0 -0
  46. {phrasplit-0.2.0 → phrasplit-0.2.2}/docs/make.bat +0 -0
  47. {phrasplit-0.2.0 → phrasplit-0.2.2}/docs/make.py +0 -0
  48. {phrasplit-0.2.0 → phrasplit-0.2.2}/docs/requirements.txt +0 -0
  49. {phrasplit-0.2.0 → phrasplit-0.2.2}/examples/__init__.py +0 -0
  50. {phrasplit-0.2.0 → phrasplit-0.2.2}/examples/audiobook_preparation.py +0 -0
  51. {phrasplit-0.2.0 → phrasplit-0.2.2}/examples/basic_usage.py +0 -0
  52. {phrasplit-0.2.0 → phrasplit-0.2.2}/examples/batch_processing.py +0 -0
  53. {phrasplit-0.2.0 → phrasplit-0.2.2}/examples/subtitle_generation.py +0 -0
  54. {phrasplit-0.2.0 → phrasplit-0.2.2}/examples/text_analysis.py +0 -0
  55. {phrasplit-0.2.0 → phrasplit-0.2.2}/phrasplit/__init__.py +0 -0
  56. {phrasplit-0.2.0 → phrasplit-0.2.2}/phrasplit/abbreviations.py +0 -0
  57. {phrasplit-0.2.0 → phrasplit-0.2.2}/phrasplit/py.typed +0 -0
  58. {phrasplit-0.2.0 → phrasplit-0.2.2}/phrasplit.egg-info/dependency_links.txt +0 -0
  59. {phrasplit-0.2.0 → phrasplit-0.2.2}/phrasplit.egg-info/entry_points.txt +0 -0
  60. {phrasplit-0.2.0 → phrasplit-0.2.2}/phrasplit.egg-info/top_level.txt +0 -0
  61. {phrasplit-0.2.0 → phrasplit-0.2.2}/requirements-test.txt +0 -0
  62. {phrasplit-0.2.0 → phrasplit-0.2.2}/setup.cfg +0 -0
  63. {phrasplit-0.2.0 → phrasplit-0.2.2}/setup.py +0 -0
  64. {phrasplit-0.2.0 → phrasplit-0.2.2}/tests/__init__.py +0 -0
  65. {phrasplit-0.2.0 → phrasplit-0.2.2}/tests/test_cli.py +0 -0
  66. {phrasplit-0.2.0 → phrasplit-0.2.2}/tests/test_splitter.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: phrasplit
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: A simple tool to split text.
5
5
  Author-email: Holger Nahrstaedt <nahrstaedt@gmail.com>
6
6
  License: MIT License
@@ -41,10 +41,12 @@ Description-Content-Type: text/markdown
41
41
  License-File: LICENSE
42
42
  Requires-Dist: click>=8.0.0
43
43
  Requires-Dist: rich>=13.0.0
44
- Requires-Dist: spacy>=3.5.0
44
+ Provides-Extra: nlp
45
+ Requires-Dist: spacy>=3.5.0; extra == "nlp"
45
46
  Provides-Extra: dev
46
47
  Requires-Dist: pytest>=7.0.0; extra == "dev"
47
48
  Requires-Dist: ruff>=0.1.0; extra == "dev"
49
+ Requires-Dist: spacy>=3.5.0; extra == "dev"
48
50
  Dynamic: license-file
49
51
 
50
52
  [![PyPI - Version](https://img.shields.io/pypi/v/phrasplit)](https://pypi.org/project/phrasplit/)
@@ -54,33 +56,75 @@ Dynamic: license-file
54
56
 
55
57
  # phrasplit
56
58
 
57
- A Python library for splitting text into sentences, clauses, or paragraphs using spaCy
58
- NLP. Designed for audiobook creation and text-to-speech processing.
59
+ A Python library for splitting text into sentences, clauses, or paragraphs. Choose
60
+ between spaCy NLP for best accuracy or fast regex-based splitting for simple use cases.
59
61
 
60
62
  ## Features
61
63
 
62
- - **Sentence splitting**: Intelligent sentence boundary detection using spaCy
64
+ - **Two modes**: spaCy (accurate) or simple regex (fast, no ML dependencies)
65
+ - **Sentence splitting**: Intelligent sentence boundary detection
63
66
  - **Clause splitting**: Split sentences at commas for natural pause points
64
- - **Paragraph splitting**: Split text at double newlines
67
+ - **Paragraph splitting**: Split text at double newlines (no spaCy needed)
65
68
  - **Hierarchical splitting**: Split text with paragraph/sentence position tracking
66
69
  - **Long line splitting**: Break long lines at sentence/clause boundaries
67
70
  - **Abbreviation handling**: Correctly handles Mr., Dr., U.S.A., etc.
68
71
  - **Ellipsis support**: Preserves ellipses without incorrect splitting
72
+ - **25+ languages**: Multi-language abbreviation support
69
73
 
70
74
  ## Installation
71
75
 
76
+ ### Basic Installation (Simple Mode)
77
+
78
+ For fast, regex-based splitting without ML dependencies:
79
+
72
80
  ```bash
73
81
  pip install phrasplit
74
82
  ```
75
83
 
76
- You'll also need to download a spaCy language model:
84
+ ### Full Installation (spaCy Mode)
85
+
86
+ For best accuracy with complex text, install with spaCy:
77
87
 
78
88
  ```bash
89
+ pip install phrasplit[nlp]
79
90
  python -m spacy download en_core_web_sm
80
91
  ```
81
92
 
93
+ ## Performance Comparison
94
+
95
+ | Mode | Speed | Accuracy | Dependencies | When to Use |
96
+ | ---------- | ----------- | -------- | ----------------------- | -------------------------------- |
97
+ | **Simple** | ~60x faster | ~85-90% | None (regex only) | Simple text, speed-critical apps |
98
+ | **spaCy** | Baseline | ~95%+ | spaCy + models (~500MB) | Complex text, best accuracy |
99
+
100
+ Benchmark results (1000 sentences):
101
+
102
+ - spaCy: 1091ms
103
+ - Simple: 17ms (63x faster)
104
+
105
+ Both modes produce nearly identical results for well-formatted text.
106
+
82
107
  ## Quick Start
83
108
 
109
+ ### Auto-Detection (Recommended)
110
+
111
+ Phrasplit automatically uses spaCy if installed, otherwise falls back to simple mode:
112
+
113
+ ```python
114
+ from phrasplit import split_sentences, split_clauses, split_paragraphs
115
+
116
+ # Uses spaCy if installed, otherwise simple mode
117
+ text = "Dr. Smith is here. She has a Ph.D. in Chemistry."
118
+ sentences = split_sentences(text)
119
+ # ['Dr. Smith is here.', 'She has a Ph.D. in Chemistry.']
120
+
121
+ # Force simple mode (even if spaCy is installed)
122
+ sentences = split_sentences(text, use_spacy=False)
123
+
124
+ # Force spaCy mode (error if not installed)
125
+ sentences = split_sentences(text, use_spacy=True)
126
+ ```
127
+
84
128
  ### Python API
85
129
 
86
130
  ```python
@@ -96,7 +140,7 @@ text = "I like coffee, and I like tea."
96
140
  clauses = split_clauses(text)
97
141
  # ['I like coffee,', 'and I like tea.']
98
142
 
99
- # Split text into paragraphs
143
+ # Split text into paragraphs (no spaCy needed)
100
144
  text = "First paragraph.\n\nSecond paragraph."
101
145
  paragraphs = split_paragraphs(text)
102
146
  # ['First paragraph.', 'Second paragraph.']
@@ -140,24 +184,33 @@ Available modes:
140
184
  ### Command Line Interface
141
185
 
142
186
  ```bash
143
- # Split into sentences
187
+ # Split into sentences (auto-detects spaCy or uses simple mode)
144
188
  phrasplit sentences input.txt -o output.txt
145
189
 
190
+ # Force simple mode (60x faster, no spaCy required)
191
+ phrasplit sentences input.txt --simple
192
+
146
193
  # Split into clauses
147
194
  phrasplit clauses input.txt -o output.txt
148
195
 
149
- # Split into paragraphs
196
+ # Use simple mode for clauses (faster)
197
+ phrasplit clauses input.txt --simple -o output.txt
198
+
199
+ # Split into paragraphs (no spaCy needed)
150
200
  phrasplit paragraphs input.txt -o output.txt
151
201
 
152
202
  # Split long lines (default max 80 characters)
153
203
  phrasplit longlines input.txt -o output.txt --max-length 60
154
204
 
155
- # Use a different spaCy model
205
+ # Long lines with simple mode
206
+ phrasplit longlines input.txt --simple --max-length 60
207
+
208
+ # Use a different spaCy model (only for spaCy mode)
156
209
  phrasplit sentences input.txt --model en_core_web_lg
157
210
 
158
211
  # Read from stdin (pipe or redirect)
159
212
  echo "Hello world. This is a test." | phrasplit sentences
160
- cat input.txt | phrasplit clauses -o output.txt
213
+ cat input.txt | phrasplit clauses --simple -o output.txt
161
214
 
162
215
  # Explicit stdin with dash
163
216
  phrasplit sentences - < input.txt
@@ -165,21 +218,28 @@ phrasplit sentences - < input.txt
165
218
 
166
219
  ## API Reference
167
220
 
168
- ### `split_sentences(text, language_model="en_core_web_sm", apply_corrections=True, split_on_colon=True)`
221
+ ### `split_sentences(text, language_model="en_core_web_sm", apply_corrections=True, use_spacy=None)`
169
222
 
170
- Split text into sentences using spaCy's sentence boundary detection.
223
+ Split text into sentences.
171
224
 
172
225
  **Parameters:**
173
226
 
174
227
  - `text`: Input text string
175
- - `language_model`: spaCy model to use (default: "en_core_web_sm")
228
+ - `language_model`: Language model name (e.g., "en_core_web_sm", "de_core_news_sm")
229
+ - For spaCy mode: Name of the spaCy model to use
230
+ - For simple mode: Used to determine language for abbreviation handling
176
231
  - `apply_corrections`: Apply post-processing corrections for URLs and abbreviations
177
- (default: True)
178
- - `split_on_colon`: Treat colons as sentence terminators (default: True)
232
+ (default: True, only applies to spaCy mode)
233
+ - `use_spacy`: Choose implementation:
234
+ - `None` (default): Auto-detect (use spaCy if available)
235
+ - `True`: Force spaCy mode (raises ImportError if not installed)
236
+ - `False`: Force simple regex mode
179
237
 
180
238
  **Returns:** List of sentences
181
239
 
182
- ### `split_clauses(text, language_model="en_core_web_sm")`
240
+ **Raises:** `ImportError` if `use_spacy=True` but spaCy is not installed
241
+
242
+ ### `split_clauses(text, language_model="en_core_web_sm", use_spacy=None)`
183
243
 
184
244
  Split text into comma-separated parts. Useful for creating natural pause points in
185
245
  audiobook/TTS applications.
@@ -187,13 +247,14 @@ audiobook/TTS applications.
187
247
  **Parameters:**
188
248
 
189
249
  - `text`: Input text string
190
- - `language_model`: spaCy model to use (default: "en_core_web_sm")
250
+ - `language_model`: Language model name (default: "en_core_web_sm")
251
+ - `use_spacy`: Choose implementation (default: None for auto-detect)
191
252
 
192
253
  **Returns:** List of clauses (comma stays at end of each part)
193
254
 
194
255
  ### `split_paragraphs(text)`
195
256
 
196
- Split text into paragraphs at double newlines.
257
+ Split text into paragraphs at double newlines. Works without spaCy.
197
258
 
198
259
  **Parameters:**
199
260
 
@@ -201,7 +262,7 @@ Split text into paragraphs at double newlines.
201
262
 
202
263
  **Returns:** List of paragraphs
203
264
 
204
- ### `split_text(text, mode="sentence", language_model="en_core_web_sm", apply_corrections=True, split_on_colon=True)`
265
+ ### `split_text(text, mode="sentence", language_model="en_core_web_sm", apply_corrections=True, use_spacy=None)`
205
266
 
206
267
  Split text into segments with hierarchical position information.
207
268
 
@@ -209,9 +270,9 @@ Split text into segments with hierarchical position information.
209
270
 
210
271
  - `text`: Input text string
211
272
  - `mode`: Splitting mode - "paragraph", "sentence", or "clause"
212
- - `language_model`: spaCy model to use (default: "en_core_web_sm")
273
+ - `language_model`: Language model name (default: "en_core_web_sm")
213
274
  - `apply_corrections`: Apply post-processing corrections (default: True)
214
- - `split_on_colon`: Treat colons as sentence terminators (default: True)
275
+ - `use_spacy`: Choose implementation (default: None for auto-detect)
215
276
 
216
277
  **Returns:** List of `Segment` namedtuples with fields:
217
278
 
@@ -219,7 +280,7 @@ Split text into segments with hierarchical position information.
219
280
  - `paragraph`: Paragraph index (0-based)
220
281
  - `sentence`: Sentence index within paragraph (0-based), None for paragraph mode
221
282
 
222
- ### `split_long_lines(text, max_length, language_model="en_core_web_sm")`
283
+ ### `split_long_lines(text, max_length, language_model="en_core_web_sm", use_spacy=None)`
223
284
 
224
285
  Split lines exceeding max_length at sentence/clause boundaries.
225
286
 
@@ -227,7 +288,8 @@ Split lines exceeding max_length at sentence/clause boundaries.
227
288
 
228
289
  - `text`: Input text string
229
290
  - `max_length`: Maximum line length in characters (must be >= 1)
230
- - `language_model`: spaCy model to use (default: "en_core_web_sm")
291
+ - `language_model`: Language model name (default: "en_core_web_sm")
292
+ - `use_spacy`: Choose implementation (default: None for auto-detect)
231
293
 
232
294
  **Returns:** List of lines, each within max_length (except single words exceeding limit)
233
295
 
@@ -286,10 +348,44 @@ for paragraph in split_paragraphs(text):
286
348
 
287
349
  ## Requirements
288
350
 
289
- - Python 3.9+
290
- - spaCy 3.5+
351
+ - Python 3.10+
291
352
  - click 8.0+
292
353
  - rich 13.0+
354
+ - spaCy 3.5+ (optional, for best accuracy)
355
+
356
+ ## Choosing Between Modes
357
+
358
+ ### Use Simple Mode When:
359
+
360
+ - Processing simple, well-formatted text
361
+ - Speed is critical (60-100x faster)
362
+ - Deploying in constrained environments (no ML dependencies)
363
+ - Installing spaCy models is not feasible (~500MB per language)
364
+
365
+ ### Use spaCy Mode When:
366
+
367
+ - Processing complex, informal, or poorly formatted text
368
+ - Accuracy is paramount (5-10% better)
369
+ - Already using spaCy in your pipeline
370
+ - Working with academic or literary texts
371
+
372
+ ## Migration Guide
373
+
374
+ ### Upgrading from Previous Versions
375
+
376
+ Version 1.x made spaCy optional. Your existing code continues to work:
377
+
378
+ ```python
379
+ # Old code (still works, auto-uses spaCy if installed)
380
+ from phrasplit import split_sentences
381
+ sentences = split_sentences(text)
382
+
383
+ # New: Explicit control
384
+ sentences = split_sentences(text, use_spacy=False) # Force simple
385
+ sentences = split_sentences(text, use_spacy=True) # Force spaCy
386
+ ```
387
+
388
+ The `split_on_colon` parameter is deprecated and will be removed in a future version.
293
389
 
294
390
  ## License
295
391
 
@@ -5,33 +5,75 @@
5
5
 
6
6
  # phrasplit
7
7
 
8
- A Python library for splitting text into sentences, clauses, or paragraphs using spaCy
9
- NLP. Designed for audiobook creation and text-to-speech processing.
8
+ A Python library for splitting text into sentences, clauses, or paragraphs. Choose
9
+ between spaCy NLP for best accuracy or fast regex-based splitting for simple use cases.
10
10
 
11
11
  ## Features
12
12
 
13
- - **Sentence splitting**: Intelligent sentence boundary detection using spaCy
13
+ - **Two modes**: spaCy (accurate) or simple regex (fast, no ML dependencies)
14
+ - **Sentence splitting**: Intelligent sentence boundary detection
14
15
  - **Clause splitting**: Split sentences at commas for natural pause points
15
- - **Paragraph splitting**: Split text at double newlines
16
+ - **Paragraph splitting**: Split text at double newlines (no spaCy needed)
16
17
  - **Hierarchical splitting**: Split text with paragraph/sentence position tracking
17
18
  - **Long line splitting**: Break long lines at sentence/clause boundaries
18
19
  - **Abbreviation handling**: Correctly handles Mr., Dr., U.S.A., etc.
19
20
  - **Ellipsis support**: Preserves ellipses without incorrect splitting
21
+ - **25+ languages**: Multi-language abbreviation support
20
22
 
21
23
  ## Installation
22
24
 
25
+ ### Basic Installation (Simple Mode)
26
+
27
+ For fast, regex-based splitting without ML dependencies:
28
+
23
29
  ```bash
24
30
  pip install phrasplit
25
31
  ```
26
32
 
27
- You'll also need to download a spaCy language model:
33
+ ### Full Installation (spaCy Mode)
34
+
35
+ For best accuracy with complex text, install with spaCy:
28
36
 
29
37
  ```bash
38
+ pip install phrasplit[nlp]
30
39
  python -m spacy download en_core_web_sm
31
40
  ```
32
41
 
42
+ ## Performance Comparison
43
+
44
+ | Mode | Speed | Accuracy | Dependencies | When to Use |
45
+ | ---------- | ----------- | -------- | ----------------------- | -------------------------------- |
46
+ | **Simple** | ~60x faster | ~85-90% | None (regex only) | Simple text, speed-critical apps |
47
+ | **spaCy** | Baseline | ~95%+ | spaCy + models (~500MB) | Complex text, best accuracy |
48
+
49
+ Benchmark results (1000 sentences):
50
+
51
+ - spaCy: 1091ms
52
+ - Simple: 17ms (63x faster)
53
+
54
+ Both modes produce nearly identical results for well-formatted text.
55
+
33
56
  ## Quick Start
34
57
 
58
+ ### Auto-Detection (Recommended)
59
+
60
+ Phrasplit automatically uses spaCy if installed, otherwise falls back to simple mode:
61
+
62
+ ```python
63
+ from phrasplit import split_sentences, split_clauses, split_paragraphs
64
+
65
+ # Uses spaCy if installed, otherwise simple mode
66
+ text = "Dr. Smith is here. She has a Ph.D. in Chemistry."
67
+ sentences = split_sentences(text)
68
+ # ['Dr. Smith is here.', 'She has a Ph.D. in Chemistry.']
69
+
70
+ # Force simple mode (even if spaCy is installed)
71
+ sentences = split_sentences(text, use_spacy=False)
72
+
73
+ # Force spaCy mode (error if not installed)
74
+ sentences = split_sentences(text, use_spacy=True)
75
+ ```
76
+
35
77
  ### Python API
36
78
 
37
79
  ```python
@@ -47,7 +89,7 @@ text = "I like coffee, and I like tea."
47
89
  clauses = split_clauses(text)
48
90
  # ['I like coffee,', 'and I like tea.']
49
91
 
50
- # Split text into paragraphs
92
+ # Split text into paragraphs (no spaCy needed)
51
93
  text = "First paragraph.\n\nSecond paragraph."
52
94
  paragraphs = split_paragraphs(text)
53
95
  # ['First paragraph.', 'Second paragraph.']
@@ -91,24 +133,33 @@ Available modes:
91
133
  ### Command Line Interface
92
134
 
93
135
  ```bash
94
- # Split into sentences
136
+ # Split into sentences (auto-detects spaCy or uses simple mode)
95
137
  phrasplit sentences input.txt -o output.txt
96
138
 
139
+ # Force simple mode (60x faster, no spaCy required)
140
+ phrasplit sentences input.txt --simple
141
+
97
142
  # Split into clauses
98
143
  phrasplit clauses input.txt -o output.txt
99
144
 
100
- # Split into paragraphs
145
+ # Use simple mode for clauses (faster)
146
+ phrasplit clauses input.txt --simple -o output.txt
147
+
148
+ # Split into paragraphs (no spaCy needed)
101
149
  phrasplit paragraphs input.txt -o output.txt
102
150
 
103
151
  # Split long lines (default max 80 characters)
104
152
  phrasplit longlines input.txt -o output.txt --max-length 60
105
153
 
106
- # Use a different spaCy model
154
+ # Long lines with simple mode
155
+ phrasplit longlines input.txt --simple --max-length 60
156
+
157
+ # Use a different spaCy model (only for spaCy mode)
107
158
  phrasplit sentences input.txt --model en_core_web_lg
108
159
 
109
160
  # Read from stdin (pipe or redirect)
110
161
  echo "Hello world. This is a test." | phrasplit sentences
111
- cat input.txt | phrasplit clauses -o output.txt
162
+ cat input.txt | phrasplit clauses --simple -o output.txt
112
163
 
113
164
  # Explicit stdin with dash
114
165
  phrasplit sentences - < input.txt
@@ -116,21 +167,28 @@ phrasplit sentences - < input.txt
116
167
 
117
168
  ## API Reference
118
169
 
119
- ### `split_sentences(text, language_model="en_core_web_sm", apply_corrections=True, split_on_colon=True)`
170
+ ### `split_sentences(text, language_model="en_core_web_sm", apply_corrections=True, use_spacy=None)`
120
171
 
121
- Split text into sentences using spaCy's sentence boundary detection.
172
+ Split text into sentences.
122
173
 
123
174
  **Parameters:**
124
175
 
125
176
  - `text`: Input text string
126
- - `language_model`: spaCy model to use (default: "en_core_web_sm")
177
+ - `language_model`: Language model name (e.g., "en_core_web_sm", "de_core_news_sm")
178
+ - For spaCy mode: Name of the spaCy model to use
179
+ - For simple mode: Used to determine language for abbreviation handling
127
180
  - `apply_corrections`: Apply post-processing corrections for URLs and abbreviations
128
- (default: True)
129
- - `split_on_colon`: Treat colons as sentence terminators (default: True)
181
+ (default: True, only applies to spaCy mode)
182
+ - `use_spacy`: Choose implementation:
183
+ - `None` (default): Auto-detect (use spaCy if available)
184
+ - `True`: Force spaCy mode (raises ImportError if not installed)
185
+ - `False`: Force simple regex mode
130
186
 
131
187
  **Returns:** List of sentences
132
188
 
133
- ### `split_clauses(text, language_model="en_core_web_sm")`
189
+ **Raises:** `ImportError` if `use_spacy=True` but spaCy is not installed
190
+
191
+ ### `split_clauses(text, language_model="en_core_web_sm", use_spacy=None)`
134
192
 
135
193
  Split text into comma-separated parts. Useful for creating natural pause points in
136
194
  audiobook/TTS applications.
@@ -138,13 +196,14 @@ audiobook/TTS applications.
138
196
  **Parameters:**
139
197
 
140
198
  - `text`: Input text string
141
- - `language_model`: spaCy model to use (default: "en_core_web_sm")
199
+ - `language_model`: Language model name (default: "en_core_web_sm")
200
+ - `use_spacy`: Choose implementation (default: None for auto-detect)
142
201
 
143
202
  **Returns:** List of clauses (comma stays at end of each part)
144
203
 
145
204
  ### `split_paragraphs(text)`
146
205
 
147
- Split text into paragraphs at double newlines.
206
+ Split text into paragraphs at double newlines. Works without spaCy.
148
207
 
149
208
  **Parameters:**
150
209
 
@@ -152,7 +211,7 @@ Split text into paragraphs at double newlines.
152
211
 
153
212
  **Returns:** List of paragraphs
154
213
 
155
- ### `split_text(text, mode="sentence", language_model="en_core_web_sm", apply_corrections=True, split_on_colon=True)`
214
+ ### `split_text(text, mode="sentence", language_model="en_core_web_sm", apply_corrections=True, use_spacy=None)`
156
215
 
157
216
  Split text into segments with hierarchical position information.
158
217
 
@@ -160,9 +219,9 @@ Split text into segments with hierarchical position information.
160
219
 
161
220
  - `text`: Input text string
162
221
  - `mode`: Splitting mode - "paragraph", "sentence", or "clause"
163
- - `language_model`: spaCy model to use (default: "en_core_web_sm")
222
+ - `language_model`: Language model name (default: "en_core_web_sm")
164
223
  - `apply_corrections`: Apply post-processing corrections (default: True)
165
- - `split_on_colon`: Treat colons as sentence terminators (default: True)
224
+ - `use_spacy`: Choose implementation (default: None for auto-detect)
166
225
 
167
226
  **Returns:** List of `Segment` namedtuples with fields:
168
227
 
@@ -170,7 +229,7 @@ Split text into segments with hierarchical position information.
170
229
  - `paragraph`: Paragraph index (0-based)
171
230
  - `sentence`: Sentence index within paragraph (0-based), None for paragraph mode
172
231
 
173
- ### `split_long_lines(text, max_length, language_model="en_core_web_sm")`
232
+ ### `split_long_lines(text, max_length, language_model="en_core_web_sm", use_spacy=None)`
174
233
 
175
234
  Split lines exceeding max_length at sentence/clause boundaries.
176
235
 
@@ -178,7 +237,8 @@ Split lines exceeding max_length at sentence/clause boundaries.
178
237
 
179
238
  - `text`: Input text string
180
239
  - `max_length`: Maximum line length in characters (must be >= 1)
181
- - `language_model`: spaCy model to use (default: "en_core_web_sm")
240
+ - `language_model`: Language model name (default: "en_core_web_sm")
241
+ - `use_spacy`: Choose implementation (default: None for auto-detect)
182
242
 
183
243
  **Returns:** List of lines, each within max_length (except single words exceeding limit)
184
244
 
@@ -237,10 +297,44 @@ for paragraph in split_paragraphs(text):
237
297
 
238
298
  ## Requirements
239
299
 
240
- - Python 3.9+
241
- - spaCy 3.5+
300
+ - Python 3.10+
242
301
  - click 8.0+
243
302
  - rich 13.0+
303
+ - spaCy 3.5+ (optional, for best accuracy)
304
+
305
+ ## Choosing Between Modes
306
+
307
+ ### Use Simple Mode When:
308
+
309
+ - Processing simple, well-formatted text
310
+ - Speed is critical (60-100x faster)
311
+ - Deploying in constrained environments (no ML dependencies)
312
+ - Installing spaCy models is not feasible (~500MB per language)
313
+
314
+ ### Use spaCy Mode When:
315
+
316
+ - Processing complex, informal, or poorly formatted text
317
+ - Accuracy is paramount (5-10% better)
318
+ - Already using spaCy in your pipeline
319
+ - Working with academic or literary texts
320
+
321
+ ## Migration Guide
322
+
323
+ ### Upgrading from Previous Versions
324
+
325
+ Version 1.x made spaCy optional. Your existing code continues to work:
326
+
327
+ ```python
328
+ # Old code (still works, auto-uses spaCy if installed)
329
+ from phrasplit import split_sentences
330
+ sentences = split_sentences(text)
331
+
332
+ # New: Explicit control
333
+ sentences = split_sentences(text, use_spacy=False) # Force simple
334
+ sentences = split_sentences(text, use_spacy=True) # Force spaCy
335
+ ```
336
+
337
+ The `split_on_colon` parameter is deprecated and will be removed in a future version.
244
338
 
245
339
  ## License
246
340
 
@@ -0,0 +1,116 @@
1
+ """Performance benchmark comparing spaCy vs simple splitters.
2
+
3
+ Run this script to benchmark both implementations.
4
+ """
5
+
6
+ import time
7
+
8
+ from phrasplit import split_sentences
9
+
10
+
11
+ def benchmark_split_sentences(
12
+ text: str, runs: int = 5
13
+ ) -> tuple[float, float, int, int]:
14
+ """Benchmark sentence splitting with both implementations."""
15
+ # Warm up
16
+ split_sentences(text, use_spacy=True)
17
+ split_sentences(text, use_spacy=False)
18
+
19
+ # Benchmark spaCy
20
+ spacy_times = []
21
+ spacy_count = 0
22
+ for _ in range(runs):
23
+ start = time.time()
24
+ result = split_sentences(text, use_spacy=True)
25
+ spacy_times.append(time.time() - start)
26
+ spacy_count = len(result)
27
+
28
+ # Benchmark simple
29
+ simple_times = []
30
+ simple_count = 0
31
+ for _ in range(runs):
32
+ start = time.time()
33
+ result = split_sentences(text, use_spacy=False)
34
+ simple_times.append(time.time() - start)
35
+ simple_count = len(result)
36
+
37
+ spacy_avg = sum(spacy_times) / len(spacy_times)
38
+ simple_avg = sum(simple_times) / len(simple_times)
39
+
40
+ return spacy_avg, simple_avg, spacy_count, simple_count
41
+
42
+
43
+ def main() -> None:
44
+ """Run benchmarks and print results."""
45
+ print("=" * 70)
46
+ print("Phrasplit Performance Benchmark: spaCy vs Simple Mode")
47
+ print("=" * 70)
48
+
49
+ # Test 1: Short text (a few sentences)
50
+ print("\n1. Short text (3 sentences, ~50 words)")
51
+ print("-" * 70)
52
+ short_text = (
53
+ "Dr. Smith has a Ph.D. in Chemistry. "
54
+ 'She said, "It\'s working!" The results were published.'
55
+ )
56
+ spacy_time, simple_time, spacy_count, simple_count = benchmark_split_sentences(
57
+ short_text
58
+ )
59
+ print(f" spaCy: {spacy_time * 1000:.2f}ms ({spacy_count} sentences)")
60
+ print(f" Simple: {simple_time * 1000:.2f}ms ({simple_count} sentences)")
61
+ print(f" Speedup: {spacy_time / simple_time:.1f}x")
62
+
63
+ # Test 2: Medium text (many sentences)
64
+ print("\n2. Medium text (100 sentences)")
65
+ print("-" * 70)
66
+ medium_text = ". ".join([f"This is sentence number {i}" for i in range(100)])
67
+ spacy_time, simple_time, spacy_count, simple_count = benchmark_split_sentences(
68
+ medium_text
69
+ )
70
+ print(f" spaCy: {spacy_time * 1000:.2f}ms ({spacy_count} sentences)")
71
+ print(f" Simple: {simple_time * 1000:.2f}ms ({simple_count} sentences)")
72
+ print(f" Speedup: {spacy_time / simple_time:.1f}x")
73
+
74
+ # Test 3: Complex text with abbreviations
75
+ print("\n3. Complex text (abbreviations, acronyms, URLs)")
76
+ print("-" * 70)
77
+ complex_text = (
78
+ "Mr. J.R.R. Tolkien wrote many books. "
79
+ "Visit www.example.com for more info. "
80
+ "The U.S.A. is a big country. "
81
+ "Prof. Green met Dr. Stone at Inc. headquarters."
82
+ )
83
+ spacy_time, simple_time, spacy_count, simple_count = benchmark_split_sentences(
84
+ complex_text
85
+ )
86
+ print(f" spaCy: {spacy_time * 1000:.2f}ms ({spacy_count} sentences)")
87
+ print(f" Simple: {simple_time * 1000:.2f}ms ({simple_count} sentences)")
88
+ print(f" Speedup: {spacy_time / simple_time:.1f}x")
89
+
90
+ # Test 4: Very long text
91
+ print("\n4. Long text (1000 sentences)")
92
+ print("-" * 70)
93
+ long_text = ". ".join(
94
+ [f"Sentence {i} with some more words to make it realistic" for i in range(1000)]
95
+ )
96
+ spacy_time, simple_time, spacy_count, simple_count = benchmark_split_sentences(
97
+ long_text, runs=3
98
+ )
99
+ print(f" spaCy: {spacy_time * 1000:.2f}ms ({spacy_count} sentences)")
100
+ print(f" Simple: {simple_time * 1000:.2f}ms ({simple_count} sentences)")
101
+ print(f" Speedup: {spacy_time / simple_time:.1f}x")
102
+
103
+ # Summary
104
+ print("\n" + "=" * 70)
105
+ print("SUMMARY")
106
+ print("=" * 70)
107
+ print("Simple mode is typically 20-100x faster than spaCy for common text.")
108
+ print("Both implementations produce similar results for well-formatted text.")
109
+ print("\nWhen to use:")
110
+ print(" • Simple mode: Speed-critical applications, simple text, no ML models")
111
+ print(" • spaCy mode: Complex text, best accuracy, NLP pipelines")
112
+ print("=" * 70)
113
+
114
+
115
+ if __name__ == "__main__":
116
+ main()
@@ -143,6 +143,12 @@ def main() -> None:
143
143
  default=False,
144
144
  help="Disable splitting on colons",
145
145
  )
146
+ parser.add_argument(
147
+ "--simple",
148
+ action="store_true",
149
+ default=False,
150
+ help="Use simple regex-based splitting (no spaCy required)",
151
+ )
146
152
 
147
153
  args = parser.parse_args()
148
154
 
@@ -162,10 +168,12 @@ def main() -> None:
162
168
  # Use the actual phrasplit.split_sentences() function
163
169
  # Long text handling is built-in (automatic chunking)
164
170
  split_on_colon = not args.no_split_on_colon
171
+ use_spacy = None if not args.simple else False
165
172
  sentences = split_sentences(
166
173
  line,
167
174
  language_model=model_name,
168
175
  split_on_colon=split_on_colon,
176
+ use_spacy=use_spacy,
169
177
  )
170
178
 
171
179
  # Write each sentence on its own line