API Reference
This page contains the complete API reference for phrasplit.
spaCy Model Resolver
The stable resolver API is available directly from phrasplit:
from phrasplit import (
SpacyModelResolution,
SpacyModelSize,
SpacyModelAttempt,
SpacyModelResolutionError,
SpacyNotInstalledError,
NoCompatibleSpacyModelError,
ExplicitSpacyModelError,
normalize_spacy_language,
resolve_spacy_model,
)
resolution = resolve_spacy_model(language="en", require=False)
print(resolution.model) # concrete selected package or None
print(resolution.model_size) # sm, md, lg, or trf
print(resolution.attempts) # local loadability diagnostics
Resolution is local-only and never downloads a model. use_spacy=False skips resolution
entirely; use_spacy=True requires a loadable result; use_spacy=None uses spaCy only
when a compatible result exists and otherwise uses regex splitting. Downstream consumers
can use language, language_model, and model_size with the same semantics as the
splitting APIs.
SpacyModelResolutionError is the base class for resolver failures. Forced resolution
raises SpacyNotInstalledError when spaCy is absent or NoCompatibleSpacyModelError
when no compatible installed model loads. An explicit package failure raises
ExplicitSpacyModelError; its resolution field contains attempts and accurate
available/loadable flags. SpacyModelAttempt records each candidate load outcome.
Main Functions
split_sentences
- phrasplit.split_sentences(text: str, language_model: str | None = None, apply_corrections: bool = True, split_on_colon: bool = True, use_spacy: bool | None = None, *, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, nlp: Any | None = None, doc: AnalyzedDocument | None = None) list[str][source]
Split text into sentences.
By default, selects the highest-quality compatible installed and loadable spaCy model for the requested language, otherwise falls back to regex-based splitting. You can force a specific implementation with
use_spacy.- Parameters:
text – Input text
language_model – Language model name (e.g., “en_core_web_sm”, “de_core_news_sm”) For spaCy mode: Name of the spaCy model to use For simple mode: Used to determine language for abbreviation handling
apply_corrections – Whether to apply post-processing corrections for common spaCy errors (URL splitting, abbreviation handling). Default is True. The regex fallback applies the same corrections.
split_on_colon – Deprecated. Kept for API compatibility (currently unused). spaCy’s default colon behavior is used. Default is True.
use_spacy – Choose implementation:
None(default) selects a compatible local model or uses regex.Truerequires spaCy and a compatible loadable model.Falseforces simple regex-based splitting without spaCy.language – Language or locale hint used for model selection and abbreviations.
model_size – Optional exact model tier (
sm,md,lg, ortrf).
- Returns:
List of sentences
- Raises:
SpacyNotInstalledError – If
use_spacy=Trueand spaCy is not installed.NoCompatibleSpacyModelError – If forced spaCy has no compatible loadable model.
ExplicitSpacyModelError – If an explicit model cannot be loaded.
Example:
>>> # Auto-select a compatible local model, otherwise use regex >>> sentences = split_sentences(text) >>> >>> # Force simple mode (even if spaCy is installed) >>> sentences = split_sentences(text, use_spacy=False) >>> >>> # Force spaCy mode (requires a compatible local model) >>> sentences = split_sentences(text, use_spacy=True)
Note
The simple mode (regex-based) is faster and has no ML dependencies, but is less accurate (~85-90% vs ~95%+ for spaCy) on complex text. For best results with complex text, install spaCy:
pip install phrasplit[nlp]
Example:
from phrasplit import split_sentences
text = "Dr. Smith is here. She has a Ph.D. in Chemistry."
sentences = split_sentences(text)
# ['Dr. Smith is here.', 'She has a Ph.D. in Chemistry.']
# Use simple mode (no spaCy required)
sentences = split_sentences(text, use_spacy=False)
# Automatic highest-available selection, exact overrides, and regex forcing
sentences = split_sentences(text, language="en")
sentences = split_sentences(text, language="de")
sentences = split_sentences(text, language_model="en_core_web_sm")
sentences = split_sentences(text, language="en", model_size="lg")
# split_on_colon is deprecated (kept for compatibility only)
text = "Note: This is important."
sentences = split_sentences(text, split_on_colon=False)
split_clauses
- phrasplit.split_clauses(text: str, language_model: str | None = None, use_spacy: bool | None = None, *, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, nlp: Any | None = None, doc: AnalyzedDocument | None = None) list[str][source]
Split text into comma-separated parts for audiobook creation.
Uses sentence detection, then splits each sentence at commas. The comma stays at the end of each part, creating natural pause points for text-to-speech processing.
- Parameters:
text – Input text
language_model – Language model name (e.g., “en_core_web_sm”)
use_spacy – Choose implementation:
None(default) selects a compatible local model or uses regex.Truerequires spaCy and a compatible loadable model.Falseforces simple regex-based splitting.language – Language or locale hint used for model selection and abbreviations.
model_size – Optional exact model tier; it never falls back to another tier.
- Returns:
List of comma-separated parts
- Raises:
SpacyNotInstalledError – If
use_spacy=Trueand spaCy is not installed.NoCompatibleSpacyModelError – If forced spaCy has no compatible loadable model.
ExplicitSpacyModelError – If an explicit model cannot be loaded.
Example:
Input: "I do like coffee, and I like wine." Output: ["I do like coffee,", "and I like wine."]
Example:
from phrasplit import split_clauses
text = "I like coffee, and I like tea."
clauses = split_clauses(text)
# ['I like coffee,', 'and I like tea.']
# Use simple mode for faster processing
clauses = split_clauses(text, use_spacy=False)
detect_clause_boundaries
- phrasplit.detect_clause_boundaries(text: str, *, use_spacy: bool | None = None, language_model: str | None = None, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, nlp: Any | None = None, doc: AnalyzedDocument | None = None) list[ClauseBoundary][source]
Detect high-confidence syntactic comma boundaries in
text.This opt-in API is intentionally independent of
split_clauses(), which continues to split every comma-separated part. Detection requires spaCy-like dependency, subject, and finite-predicate annotations; regex mode never guesses.Supplied documents are inspected directly and supplied pipelines are called once. Neither caller-owned object is retained or mutated.
Detects opt-in clausal_comma boundaries only when both sides of a comma have an
explicit local syntactic subject and conservative finite-predicate evidence. It is
independent of split_clauses(), which continues to return every comma-separated part.
from phrasplit import ClauseBoundary, detect_clause_boundaries
text = "I left, but she stayed."
boundaries = detect_clause_boundaries(text, use_spacy=True)
assert isinstance(boundaries[0], ClauseBoundary)
assert boundaries[0].text == text[boundaries[0].char_start : boundaries[0].char_end]
The function uses token offsets and returns boundaries in source order without
duplicates. use_spacy=False and automatic mode without a compatible local model return
[]; automatic and forced model selection never download models. Forced spaCy preserves
the existing resolver errors. A supplied doc= is validated against text, reused
without another pipeline call, and caller-owned analysis is not mutated or retained. A
supplied nlp= pipeline is called once.
detect_parenthetical_boundaries
- phrasplit.detect_parenthetical_boundaries(text: str, *, language: str | None = None) list[ClauseBoundary][source]
Detect high-confidence balanced round-parenthesis boundaries in
text.
Detects high-confidence balanced round-parenthesis asides without requiring spaCy or a
parsed document. It returns DetectedBoundary values in source order. Each boundary
covers exactly one original source character, so
boundary.text == text[boundary.char_start:boundary.char_end].
from phrasplit import detect_parenthetical_boundaries
text = "They changed clothes (stained with blood) before leaving."
boundaries = detect_parenthetical_boundaries(text)
assert [boundary.kind for boundary in boundaries] == [
"parenthetical_open",
"parenthetical_close",
]
The detector reports semantic source boundaries only. It does not assign pause durations or TTS policy. It scans balanced outer pairs, ignores empty and whitespace-only pairs and obvious attached lexical or function notation, and does not emit an opening boundary at position zero. A closing boundary is omitted when the parenthesis is sentence-final or followed by stronger punctuation such as a comma, colon, semicolon, question mark, exclamation mark, ellipsis, or em dash.
split_paragraphs
- phrasplit.split_paragraphs(text: str) list[str][source]
Split text into paragraphs (separated by double newlines).
Applies preprocessing to fix hyphenated line breaks and normalize whitespace.
- Parameters:
text – Input text
- Returns:
List of paragraphs (non-empty, stripped)
Example:
from phrasplit import split_paragraphs
text = "First paragraph.\n\nSecond paragraph."
paragraphs = split_paragraphs(text)
# ['First paragraph.', 'Second paragraph.']
split_text
- phrasplit.split_text(text: str, mode: str = 'sentence', language_model: str | None = None, apply_corrections: bool = True, split_on_colon: bool = True, use_spacy: bool | None = None, *, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, nlp: Any | None = None, doc: AnalyzedDocument | None = None) list[Segment][source]
Compatibility wrapper returning only segments from a detailed split.
Example:
from phrasplit import split_text, Segment
text = "First sentence. Second sentence.\n\nNew paragraph."
segments = split_text(text, mode="sentence")
for seg in segments:
print(f"P{seg.paragraph} S{seg.sentence}: {seg.text}")
# P0 S0: First sentence.
# P0 S1: Second sentence.
# P1 S0: New paragraph.
# Clause mode for finer granularity
text = "Hello, world.\n\nGoodbye, friend."
segments = split_text(text, mode="clause")
# Returns clauses with paragraph and sentence indices
# Use simple mode (no spaCy)
segments = split_text(text, mode="sentence", use_spacy=False)
split_text_with_diagnostics
- phrasplit.split_text_with_diagnostics(text: str, mode: str = 'sentence', language_model: str | None = None, apply_corrections: bool = True, split_on_colon: bool = True, use_spacy: bool | None = None, *, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, nlp: Any | None = None, doc: AnalyzedDocument | None = None) SplitTextResult[source]
Split text and return segments with the resolution used for the operation.
This function provides a unified interface for text splitting with different granularity levels, preserving paragraph and sentence structure information while exposing backend/model diagnostics without a second resolution pass. Useful for integrations that need to report or map the selected backend. Args:
text: Input text to split mode: Splitting mode. Valid values are
"paragraph","sentence",and
"clause".language_model: Language model name (e.g., “en_core_web_sm”) apply_corrections: Whether to apply post-processing corrections for
common spaCy errors (URL splitting, abbreviation handling). Default is True. Applies to sentence/clause modes for both backends.
- split_on_colon: Deprecated. Kept for API compatibility (currently unused).
spaCy’s default colon behavior is used. Default is True.
- use_spacy: Choose implementation:
None(default) selects a compatible installed/loadable model or regex.Truerequires spaCy and a compatible loadable model.Falseforces simple regex-based splitting.
language: Language or locale hint used for model selection and abbreviations. model_size: Optional exact model tier; it never falls back to another tier.
- Returns:
A SplitTextResult containing the list of Segment objects and SplitDiagnostics from the same backend/model resolution operation.
- Raises:
ValueError: If mode is not one of “paragraph”, “sentence”, “clause” SpacyNotInstalledError: If
use_spacy=Trueand spaCy is not installed. NoCompatibleSpacyModelError: If forced spaCy has no compatible loadable model. ExplicitSpacyModelError: If an explicit model cannot be loaded.
Example:
>>> result = split_text_with_diagnostics( ... "Hello world. How are you?
- New paragraph.”
… ) >>> print(result.diagnostics.backend) spacy >>> for seg in result.segments: … print(f”P{seg.paragraph} S{seg.sentence}: {seg.text}”) P0 S0: Hello world. P0 S1: How are you? P1 S0: New paragraph.
Use this additive API when a caller needs the backend/model chosen by the actual split
operation. It returns a SplitTextResult with segments and frozen SplitDiagnostics:
from phrasplit import split_text_with_diagnostics
result = split_text_with_diagnostics("Hello. World.", language="en")
print(result.diagnostics.backend)
print(result.diagnostics.selected_model)
print(result.diagnostics.selected_model_size)
SplitDiagnostics.backend is "none" for paragraph mode, "regex" for the regex
backend, and "spacy" for spaCy. resolution is None for forced regex and paragraph
mode; automatic fallback retains a resolution whose selected model is None. The
existing split_text() function remains a compatibility wrapper returning
list[Segment].
split_long_lines
- phrasplit.split_long_lines(text: str, max_length: int, language_model: str | None = None, use_spacy: bool | None = None, *, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, nlp: Any | None = None, doc: AnalyzedDocument | None = None) list[str][source]
Split lines exceeding max_length at clause/sentence boundaries.
Strategy: 1. First try to split at sentence boundaries 2. If still too long, split at clause boundaries (commas, semicolons, etc.) 3. If still too long, split at word boundaries
- Parameters:
text – Input text
max_length – Maximum line length in characters (must be positive)
language_model – Language model name (e.g., “en_core_web_sm”)
use_spacy – Choose implementation:
None(default) selects a compatible local model or uses regex.Truerequires spaCy and a compatible loadable model.Falseforces simple regex-based splitting.language – Language or locale hint used for model selection and abbreviations.
model_size – Optional exact model tier; it never falls back to another tier.
- Returns:
List of lines, each within max_length (except single words exceeding limit)
- Raises:
ValueError – If max_length is less than 1
SpacyNotInstalledError – If
use_spacy=Trueand spaCy is not installed.NoCompatibleSpacyModelError – If forced spaCy has no compatible loadable model.
ExplicitSpacyModelError – If an explicit model cannot be loaded.
Example:
from phrasplit import split_long_lines
text = "This is a very long sentence that needs to be split into smaller parts."
lines = split_long_lines(text, max_length=40)
# Use simple mode
lines = split_long_lines(text, max_length=40, use_spacy=False)
Offset APIs
- phrasplit.split_with_offsets_with_diagnostics(text: str, *, mode: str = 'sentence', use_spacy: bool | None = None, language_model: str | None = None, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, apply_corrections: bool = True, max_chars: int | None = None, inline_markup: bool = False, nlp: Any | None = None, doc: AnalyzedDocument | None = None) SplitWithOffsetsResult[source]
Split text into offset-preserving segments with backend diagnostics.
The returned
SplitWithOffsetsResultcontains the exact segments produced by this operation and theSplitDiagnosticsfor its backend/model choice. This is the main API for offset-preserving segmentation, designed for downstream processing where exact character positions are critical.Exact-Slice Policy
This function implements the exact-slice policy. For every returned segment, the following invariant ALWAYS holds:
segment.text == text[segment.char_start:segment.char_end]
This guarantee means:
Offsets map precisely to the original input text
No whitespace normalization or stripping breaks the mapping
Downstream code can reliably use offsets for span slicing
Integration with token alignment and markup slicing is safe
Key features:
Returns segments with precise character offsets (char_start, char_end)
Generates stable, hierarchical IDs (e.g., “p0s1”, “p0s2c3”)
Maintains exact-slice invariant in all modes
Supports both spaCy (accurate) and regex (fast) backends
Optional max_chars safety splitting with deterministic boundaries
- Parameters:
text – Input text to split
mode – Splitting granularity. Valid values are
"paragraph","sentence", and"clause".use_spacy – Backend selection.
None(default) selects a compatible installed/loadable local model or falls back to regex;Trueforces spaCy;Falseforces regex-based splitting.language_model – Language model name (e.g., “en_core_web_sm”, “de_core_news_sm”) Used for both spaCy model selection and abbreviation handling
language – Language or locale hint used for model selection and abbreviations.
model_size – Optional exact model tier; it never falls back to another tier.
apply_corrections – Whether to apply post-processing corrections for common spaCy errors (URL splitting, abbreviation handling, ellipsis). Default is True. Only applies to spaCy mode.
max_chars – Optional maximum segment length. Segments exceeding this will be split further at whitespace/punctuation boundaries while maintaining the exact-slice invariant. Split segments get IDs like “p0s1:m0”, “p0s1:m1”, etc.
inline_markup – Opt-in inline XHTML markup handling (default False). When True, the regex backend keeps inline tags balanced across sentence boundaries: closing tags after punctuation stay in the previous segment and opening tags after whitespace start the next segment. Requires the regex backend; passing
use_spacy=Truewithinline_markup=Trueraises ValueError. Default behavior (plain text) is unchanged when False.
- Returns:
A
SplitWithOffsetsResultwithsegmentscontainingSplitSegmentvalues anddiagnosticsdescribing the backend/model resolution used for this exact operation.- Raises:
ValueError – If mode is invalid or max_chars < 1
SpacyNotInstalledError – If
use_spacy=Trueand spaCy is not installed.NoCompatibleSpacyModelError – If forced spaCy has no compatible loadable model.
ExplicitSpacyModelError – If an explicit model cannot be loaded.
Example:
>>> text = "Hello world. How are you?\n\nNew paragraph." >>> segments = split_with_offsets(text, mode="sentence") >>> for seg in segments: ... # Verify exact-slice invariant ... assert text[seg.char_start:seg.char_end] == seg.text ... print(f"{seg.id}: {seg.text!r}") p0s0: 'Hello world.' p0s1: 'How are you?' p1s0: 'New paragraph.' >>> # With max_chars safety splitting >>> long_text = "word " * 100 >>> segments = split_with_offsets(long_text, max_chars=50) >>> all(len(seg.text) <= 50 for seg in segments) True >>> # Exact-slice invariant still holds >>> all(long_text[s.char_start:s.char_end] == s.text for s in segments) True
Note
Segments may include leading/trailing whitespace from the original text
IDs are stable and deterministic across runs with same input and settings
For SSMD/markup integration, offsets are in the coordinate space of the input text (before or after escaping, depending on your workflow)
- phrasplit.split_with_offsets(text: str, *, mode: str = 'sentence', use_spacy: bool | None = None, language_model: str | None = None, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, apply_corrections: bool = True, max_chars: int | None = None, inline_markup: bool = False, nlp: Any | None = None, doc: AnalyzedDocument | None = None) list[SplitSegment][source]
Compatibility wrapper returning only offset-preserving segments.
- phrasplit.iter_split_with_offsets(text: str, *, mode: str = 'sentence', use_spacy: bool | None = None, language_model: str | None = None, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, apply_corrections: bool = True, max_chars: int | None = None, inline_markup: bool = False, nlp: Any | None = None, doc: AnalyzedDocument | None = None) Iterator[SplitSegment][source]
Iterator facade over
split_with_offsets().The current implementation computes the complete segment list before yielding. It is useful for iterator-oriented integrations, but it does not yet provide incremental parsing, bounded memory, or earlier time-to-first-segment behavior.
- Parameters:
text – Input text to split
mode – Splitting granularity (“paragraph”, “sentence”, or “clause”)
use_spacy – Backend selection (None=auto, True=spaCy, False=regex)
language_model – Language model name for NLP/abbreviations
language – Language or locale hint used for model selection and abbreviations.
model_size – Optional exact model tier.
apply_corrections – Whether to apply post-processing corrections for common spaCy errors (URL splitting, abbreviation handling, ellipsis). Default is True. Only applies to spaCy mode.
max_chars – Optional maximum segment length
- Yields:
SplitSegment objects in document order
Example:
>>> text = "First sentence. Second sentence.\n\nNew paragraph." >>> for segment in iter_split_with_offsets(text, mode="sentence"): ... print(f"{segment.id}: {segment.text}") p0s0: First sentence. p0s1: Second sentence. p1s0: New paragraph.
Note
Segments are yielded in document order
Same offset guarantees as split_with_offsets()
The underlying splitter may use its documented model cache/global diagnostic state; callers must not interpret this facade as a thread-isolated stream.
Use split_with_offsets_with_diagnostics() when an integration needs both exact source
offsets and the backend/model chosen by the operation that produced them. It returns a
SplitWithOffsetsResult containing segments and SplitDiagnostics:
from phrasplit import split_with_offsets_with_diagnostics
text = "Hello. World."
result = split_with_offsets_with_diagnostics(text, language="en")
print(result.diagnostics.backend)
print(result.diagnostics.selected_model)
for segment in result.segments:
assert segment.text == text[segment.char_start:segment.char_end]
split_with_offsets() remains a compatibility wrapper returning list[SplitSegment].
Both APIs preserve the exact-slice invariant. inline_markup=True is regex-only and
raises ValueError when explicitly combined with spaCy. The iterator is currently a
facade over the list API and does not claim incremental or bounded-memory processing.
Data Types
Segment
- class phrasplit.Segment(text: str, paragraph: int, sentence: int | None = None)[source]
Bases:
NamedTupleA text segment with position information.
- - ``text``
The text content of the segment.
- - ``paragraph``
Paragraph index (0-based) within the document.
- - ``sentence``
Sentence index (0-based) within the paragraph.
Nonefor paragraph mode.
- text: str
Alias for field number 0
- paragraph: int
Alias for field number 1
A named tuple representing a text segment with position information.
Fields:
text(str): The text content of the segmentparagraph(int): Paragraph index (0-based) within the documentsentence(int | None): Sentence index (0-based) within the paragraph. None for paragraph mode.
Example:
from phrasplit import split_text, Segment
segments = split_text("Hello world.", mode="sentence")
seg = segments[0]
# Access by name
print(seg.text) # "Hello world."
print(seg.paragraph) # 0
print(seg.sentence) # 0
# Access by index
print(seg[0]) # "Hello world."
print(seg[1]) # 0
print(seg[2]) # 0
# Unpack
text, para, sent = seg
Module Contents
splitter module
Text splitting utilities using spaCy for NLP-based sentence and clause detection.
This module provides two implementations: 1. spaCy-based (default when available): High accuracy, handles complex cases 2. Regex-based (fallback): Faster, simpler, good for common cases
The implementation is selected automatically based on spaCy availability, or can be controlled via the use_spacy parameter.
- class phrasplit.splitter.AnalyzedToken(*args, **kwargs)[source]
Bases:
ProtocolMinimal token surface required from an analyzed document.
- idx: int
- text: str
- class phrasplit.splitter.AnalyzedSpan(*args, **kwargs)[source]
Bases:
ProtocolMinimal sentence-span surface required from an analyzed document.
- start_char: int
- end_char: int
- text: str
- class phrasplit.splitter.AnalyzedDocument(*args, **kwargs)[source]
Bases:
ProtocolProvider-neutral protocol for a pre-analyzed document.
- text: str
- property sents: Iterable[AnalyzedSpan]
- class phrasplit.splitter.Segment(text: str, paragraph: int, sentence: int | None = None)[source]
Bases:
NamedTupleA text segment with position information.
- - ``text``
The text content of the segment.
- - ``paragraph``
Paragraph index (0-based) within the document.
- - ``sentence``
Sentence index (0-based) within the paragraph.
Nonefor paragraph mode.
- text: str
Alias for field number 0
- paragraph: int
Alias for field number 1
- class phrasplit.splitter.SplitDiagnostics(backend: Literal['none', 'regex', 'spacy'], language: str, resolution: SpacyModelResolution | None, analysis_source: Literal['regex', 'resolved-model', 'provided-pipeline', 'provided-document'] = 'regex', model_owned_by_caller: bool = False)[source]
Bases:
objectResolution details produced by one public split operation.
- backend: Literal['none', 'regex', 'spacy']
- language: str
- resolution: SpacyModelResolution | None
- analysis_source: Literal['regex', 'resolved-model', 'provided-pipeline', 'provided-document'] = 'regex'
- model_owned_by_caller: bool = False
- class phrasplit.splitter.SplitTextResult(segments: list[Segment], diagnostics: SplitDiagnostics)[source]
Bases:
objectSegments and backend diagnostics from a detailed split operation.
- diagnostics: SplitDiagnostics
- class phrasplit.splitter.SplitWithOffsetsResult(segments: list[SplitSegment], diagnostics: SplitDiagnostics)[source]
Bases:
objectOffset-preserving segments and diagnostics from one split operation.
- segments: list[SplitSegment]
- diagnostics: SplitDiagnostics
- phrasplit.splitter.detect_parenthetical_boundaries(text: str, *, language: str | None = None) list[ClauseBoundary][source]
Detect high-confidence balanced round-parenthesis boundaries in
text.
- phrasplit.splitter.split_paragraphs(text: str) list[str][source]
Split text into paragraphs (separated by double newlines).
Applies preprocessing to fix hyphenated line breaks and normalize whitespace.
- Parameters:
text – Input text
- Returns:
List of paragraphs (non-empty, stripped)
- phrasplit.splitter.split_sentences(text: str, language_model: str | None = None, apply_corrections: bool = True, split_on_colon: bool = True, use_spacy: bool | None = None, *, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, nlp: Any | None = None, doc: AnalyzedDocument | None = None) list[str][source]
Split text into sentences.
By default, selects the highest-quality compatible installed and loadable spaCy model for the requested language, otherwise falls back to regex-based splitting. You can force a specific implementation with
use_spacy.- Parameters:
text – Input text
language_model – Language model name (e.g., “en_core_web_sm”, “de_core_news_sm”) For spaCy mode: Name of the spaCy model to use For simple mode: Used to determine language for abbreviation handling
apply_corrections – Whether to apply post-processing corrections for common spaCy errors (URL splitting, abbreviation handling). Default is True. The regex fallback applies the same corrections.
split_on_colon – Deprecated. Kept for API compatibility (currently unused). spaCy’s default colon behavior is used. Default is True.
use_spacy – Choose implementation:
None(default) selects a compatible local model or uses regex.Truerequires spaCy and a compatible loadable model.Falseforces simple regex-based splitting without spaCy.language – Language or locale hint used for model selection and abbreviations.
model_size – Optional exact model tier (
sm,md,lg, ortrf).
- Returns:
List of sentences
- Raises:
SpacyNotInstalledError – If
use_spacy=Trueand spaCy is not installed.NoCompatibleSpacyModelError – If forced spaCy has no compatible loadable model.
ExplicitSpacyModelError – If an explicit model cannot be loaded.
Example:
>>> # Auto-select a compatible local model, otherwise use regex >>> sentences = split_sentences(text) >>> >>> # Force simple mode (even if spaCy is installed) >>> sentences = split_sentences(text, use_spacy=False) >>> >>> # Force spaCy mode (requires a compatible local model) >>> sentences = split_sentences(text, use_spacy=True)
Note
The simple mode (regex-based) is faster and has no ML dependencies, but is less accurate (~85-90% vs ~95%+ for spaCy) on complex text. For best results with complex text, install spaCy:
pip install phrasplit[nlp]
- phrasplit.splitter.split_clauses(text: str, language_model: str | None = None, use_spacy: bool | None = None, *, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, nlp: Any | None = None, doc: AnalyzedDocument | None = None) list[str][source]
Split text into comma-separated parts for audiobook creation.
Uses sentence detection, then splits each sentence at commas. The comma stays at the end of each part, creating natural pause points for text-to-speech processing.
- Parameters:
text – Input text
language_model – Language model name (e.g., “en_core_web_sm”)
use_spacy – Choose implementation:
None(default) selects a compatible local model or uses regex.Truerequires spaCy and a compatible loadable model.Falseforces simple regex-based splitting.language – Language or locale hint used for model selection and abbreviations.
model_size – Optional exact model tier; it never falls back to another tier.
- Returns:
List of comma-separated parts
- Raises:
SpacyNotInstalledError – If
use_spacy=Trueand spaCy is not installed.NoCompatibleSpacyModelError – If forced spaCy has no compatible loadable model.
ExplicitSpacyModelError – If an explicit model cannot be loaded.
Example:
Input: "I do like coffee, and I like wine." Output: ["I do like coffee,", "and I like wine."]
- phrasplit.splitter.split_long_lines(text: str, max_length: int, language_model: str | None = None, use_spacy: bool | None = None, *, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, nlp: Any | None = None, doc: AnalyzedDocument | None = None) list[str][source]
Split lines exceeding max_length at clause/sentence boundaries.
Strategy: 1. First try to split at sentence boundaries 2. If still too long, split at clause boundaries (commas, semicolons, etc.) 3. If still too long, split at word boundaries
- Parameters:
text – Input text
max_length – Maximum line length in characters (must be positive)
language_model – Language model name (e.g., “en_core_web_sm”)
use_spacy – Choose implementation:
None(default) selects a compatible local model or uses regex.Truerequires spaCy and a compatible loadable model.Falseforces simple regex-based splitting.language – Language or locale hint used for model selection and abbreviations.
model_size – Optional exact model tier; it never falls back to another tier.
- Returns:
List of lines, each within max_length (except single words exceeding limit)
- Raises:
ValueError – If max_length is less than 1
SpacyNotInstalledError – If
use_spacy=Trueand spaCy is not installed.NoCompatibleSpacyModelError – If forced spaCy has no compatible loadable model.
ExplicitSpacyModelError – If an explicit model cannot be loaded.
- phrasplit.splitter.split_text_with_diagnostics(text: str, mode: str = 'sentence', language_model: str | None = None, apply_corrections: bool = True, split_on_colon: bool = True, use_spacy: bool | None = None, *, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, nlp: Any | None = None, doc: AnalyzedDocument | None = None) SplitTextResult[source]
Split text and return segments with the resolution used for the operation.
This function provides a unified interface for text splitting with different granularity levels, preserving paragraph and sentence structure information while exposing backend/model diagnostics without a second resolution pass. Useful for integrations that need to report or map the selected backend. Args:
text: Input text to split mode: Splitting mode. Valid values are
"paragraph","sentence",and
"clause".language_model: Language model name (e.g., “en_core_web_sm”) apply_corrections: Whether to apply post-processing corrections for
common spaCy errors (URL splitting, abbreviation handling). Default is True. Applies to sentence/clause modes for both backends.
- split_on_colon: Deprecated. Kept for API compatibility (currently unused).
spaCy’s default colon behavior is used. Default is True.
- use_spacy: Choose implementation:
None(default) selects a compatible installed/loadable model or regex.Truerequires spaCy and a compatible loadable model.Falseforces simple regex-based splitting.
language: Language or locale hint used for model selection and abbreviations. model_size: Optional exact model tier; it never falls back to another tier.
- Returns:
A SplitTextResult containing the list of Segment objects and SplitDiagnostics from the same backend/model resolution operation.
- Raises:
ValueError: If mode is not one of “paragraph”, “sentence”, “clause” SpacyNotInstalledError: If
use_spacy=Trueand spaCy is not installed. NoCompatibleSpacyModelError: If forced spaCy has no compatible loadable model. ExplicitSpacyModelError: If an explicit model cannot be loaded.
Example:
>>> result = split_text_with_diagnostics( ... "Hello world. How are you?
- New paragraph.”
… ) >>> print(result.diagnostics.backend) spacy >>> for seg in result.segments: … print(f”P{seg.paragraph} S{seg.sentence}: {seg.text}”) P0 S0: Hello world. P0 S1: How are you? P1 S0: New paragraph.
- phrasplit.splitter.split_text(text: str, mode: str = 'sentence', language_model: str | None = None, apply_corrections: bool = True, split_on_colon: bool = True, use_spacy: bool | None = None, *, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, nlp: Any | None = None, doc: AnalyzedDocument | None = None) list[Segment][source]
Compatibility wrapper returning only segments from a detailed split.
- phrasplit.splitter.split_with_offsets_with_diagnostics(text: str, *, mode: str = 'sentence', use_spacy: bool | None = None, language_model: str | None = None, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, apply_corrections: bool = True, max_chars: int | None = None, inline_markup: bool = False, nlp: Any | None = None, doc: AnalyzedDocument | None = None) SplitWithOffsetsResult[source]
Split text into offset-preserving segments with backend diagnostics.
The returned
SplitWithOffsetsResultcontains the exact segments produced by this operation and theSplitDiagnosticsfor its backend/model choice. This is the main API for offset-preserving segmentation, designed for downstream processing where exact character positions are critical.Exact-Slice Policy
This function implements the exact-slice policy. For every returned segment, the following invariant ALWAYS holds:
segment.text == text[segment.char_start:segment.char_end]
This guarantee means:
Offsets map precisely to the original input text
No whitespace normalization or stripping breaks the mapping
Downstream code can reliably use offsets for span slicing
Integration with token alignment and markup slicing is safe
Key features:
Returns segments with precise character offsets (char_start, char_end)
Generates stable, hierarchical IDs (e.g., “p0s1”, “p0s2c3”)
Maintains exact-slice invariant in all modes
Supports both spaCy (accurate) and regex (fast) backends
Optional max_chars safety splitting with deterministic boundaries
- Parameters:
text – Input text to split
mode – Splitting granularity. Valid values are
"paragraph","sentence", and"clause".use_spacy – Backend selection.
None(default) selects a compatible installed/loadable local model or falls back to regex;Trueforces spaCy;Falseforces regex-based splitting.language_model – Language model name (e.g., “en_core_web_sm”, “de_core_news_sm”) Used for both spaCy model selection and abbreviation handling
language – Language or locale hint used for model selection and abbreviations.
model_size – Optional exact model tier; it never falls back to another tier.
apply_corrections – Whether to apply post-processing corrections for common spaCy errors (URL splitting, abbreviation handling, ellipsis). Default is True. Only applies to spaCy mode.
max_chars – Optional maximum segment length. Segments exceeding this will be split further at whitespace/punctuation boundaries while maintaining the exact-slice invariant. Split segments get IDs like “p0s1:m0”, “p0s1:m1”, etc.
inline_markup – Opt-in inline XHTML markup handling (default False). When True, the regex backend keeps inline tags balanced across sentence boundaries: closing tags after punctuation stay in the previous segment and opening tags after whitespace start the next segment. Requires the regex backend; passing
use_spacy=Truewithinline_markup=Trueraises ValueError. Default behavior (plain text) is unchanged when False.
- Returns:
A
SplitWithOffsetsResultwithsegmentscontainingSplitSegmentvalues anddiagnosticsdescribing the backend/model resolution used for this exact operation.- Raises:
ValueError – If mode is invalid or max_chars < 1
SpacyNotInstalledError – If
use_spacy=Trueand spaCy is not installed.NoCompatibleSpacyModelError – If forced spaCy has no compatible loadable model.
ExplicitSpacyModelError – If an explicit model cannot be loaded.
Example:
>>> text = "Hello world. How are you?\n\nNew paragraph." >>> segments = split_with_offsets(text, mode="sentence") >>> for seg in segments: ... # Verify exact-slice invariant ... assert text[seg.char_start:seg.char_end] == seg.text ... print(f"{seg.id}: {seg.text!r}") p0s0: 'Hello world.' p0s1: 'How are you?' p1s0: 'New paragraph.' >>> # With max_chars safety splitting >>> long_text = "word " * 100 >>> segments = split_with_offsets(long_text, max_chars=50) >>> all(len(seg.text) <= 50 for seg in segments) True >>> # Exact-slice invariant still holds >>> all(long_text[s.char_start:s.char_end] == s.text for s in segments) True
Note
Segments may include leading/trailing whitespace from the original text
IDs are stable and deterministic across runs with same input and settings
For SSMD/markup integration, offsets are in the coordinate space of the input text (before or after escaping, depending on your workflow)
- phrasplit.splitter.detect_clause_boundaries(text: str, *, use_spacy: bool | None = None, language_model: str | None = None, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, nlp: Any | None = None, doc: AnalyzedDocument | None = None) list[ClauseBoundary][source]
Detect high-confidence syntactic comma boundaries in
text.This opt-in API is intentionally independent of
split_clauses(), which continues to split every comma-separated part. Detection requires spaCy-like dependency, subject, and finite-predicate annotations; regex mode never guesses.Supplied documents are inspected directly and supplied pipelines are called once. Neither caller-owned object is retained or mutated.
- phrasplit.splitter.split_with_offsets(text: str, *, mode: str = 'sentence', use_spacy: bool | None = None, language_model: str | None = None, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, apply_corrections: bool = True, max_chars: int | None = None, inline_markup: bool = False, nlp: Any | None = None, doc: AnalyzedDocument | None = None) list[SplitSegment][source]
Compatibility wrapper returning only offset-preserving segments.
- phrasplit.splitter.iter_split_with_offsets(text: str, *, mode: str = 'sentence', use_spacy: bool | None = None, language_model: str | None = None, language: str = 'en', model_size: Literal['sm', 'md', 'lg', 'trf'] | None = None, apply_corrections: bool = True, max_chars: int | None = None, inline_markup: bool = False, nlp: Any | None = None, doc: AnalyzedDocument | None = None) Iterator[SplitSegment][source]
Iterator facade over
split_with_offsets().The current implementation computes the complete segment list before yielding. It is useful for iterator-oriented integrations, but it does not yet provide incremental parsing, bounded memory, or earlier time-to-first-segment behavior.
- Parameters:
text – Input text to split
mode – Splitting granularity (“paragraph”, “sentence”, or “clause”)
use_spacy – Backend selection (None=auto, True=spaCy, False=regex)
language_model – Language model name for NLP/abbreviations
language – Language or locale hint used for model selection and abbreviations.
model_size – Optional exact model tier.
apply_corrections – Whether to apply post-processing corrections for common spaCy errors (URL splitting, abbreviation handling, ellipsis). Default is True. Only applies to spaCy mode.
max_chars – Optional maximum segment length
- Yields:
SplitSegment objects in document order
Example:
>>> text = "First sentence. Second sentence.\n\nNew paragraph." >>> for segment in iter_split_with_offsets(text, mode="sentence"): ... print(f"{segment.id}: {segment.text}") p0s0: First sentence. p0s1: Second sentence. p1s0: New paragraph.
Note
Segments are yielded in document order
Same offset guarantees as split_with_offsets()
The underlying splitter may use its documented model cache/global diagnostic state; callers must not interpret this facade as a thread-isolated stream.
Type Information
phrasplit is fully typed and includes a py.typed marker file for PEP 561 compliance.
You can use it with mypy and other type checkers.
Function signatures:
from typing import NamedTuple
class Segment(NamedTuple):
text: str
paragraph: int
sentence: int | None = None
def split_sentences(
text: str,
language_model: str | None = None,
apply_corrections: bool = True,
split_on_colon: bool = True,
use_spacy: bool | None = None,
*,
language: str = "en",
model_size: str | None = None,
) -> list[str]: ...
def split_clauses(
text: str,
language_model: str | None = None,
use_spacy: bool | None = None,
*,
language: str = "en",
model_size: str | None = None,
) -> list[str]: ...
def split_paragraphs(text: str) -> list[str]: ...
def split_text(
text: str,
mode: str = "sentence",
language_model: str | None = None,
apply_corrections: bool = True,
split_on_colon: bool = True,
use_spacy: bool | None = None,
*,
language: str = "en",
model_size: str | None = None,
) -> list[Segment]: ...
def split_long_lines(
text: str,
max_length: int,
language_model: str | None = None,
use_spacy: bool | None = None,
*,
language: str = "en",
model_size: str | None = None,
) -> list[str]: ...
Injected spaCy analysis
The splitter can consume analysis prepared by an orchestrator. doc must expose text,
sents, and sentence spans with start_char and end_char; it is checked against the
exact input string. nlp is a caller-owned callable pipeline used when doc is not
supplied.
prepared = spokenform.prepare(raw_text)
doc = nlp(prepared.spoken_text)
result = split_with_offsets_with_diagnostics(
prepared.spoken_text, language="de", doc=doc
)
A supplied doc is preferred over nlp, bypasses model resolution and inference, and
cannot be combined with use_spacy=False. Diagnostics report analysis_source as
provided-document or provided-pipeline, set model_owned_by_caller to True, and
leave selected_model unset when no model identity is available. Phrasplit still
applies its corrections and exact-slice offset projection.
Phrasplit only reads injected resources during the call. It does not mutate, cache, close, unload, or take ownership of a supplied document or pipeline.