stream2sentence 0.2.2__tar.gz → 0.2.3__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: stream2sentence
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Real-time processing and delivery of sentences from a continuous stream of characters or text chunks.
5
5
  Home-page: https://github.com/KoljaB/stream2sentence
6
6
  Author: Kolja Beigel
@@ -76,9 +76,6 @@ The `generate_sentences()` function has the following parameters:
76
76
  - `generator`: Input character generator.
77
77
  Iterator that emits chunks of text. These chunks can be of any size, and they'll be processed one by one to extract sentences from them. It forms the primary source from which the function reads and generates sentences.
78
78
 
79
- - `quick_yield_single_sentence_fragment`: Whether to return a sentence fragment as fast as possible.
80
- This is a feature for realtime speech synthesis. In some use cases you want to audio stream a minimal chunk of text as fast as possible, even when it means to synthesize mid-sentence. In this case you set this flag to True which will yield a synthesizable sentence fragment as early as possible.
81
-
82
79
  - `context_size`: Context size for sentence detection.
83
80
  This controls how much context is looked at to detect sentence boundaries. It determines the number of characters around a potential delimiter (like a period) that are considered when detecting sentence boundaries. A larger context size allows more reliable sentence boundary detection, but requires buffering more characters before emitting a sentence.
84
81
  Default is 12 characters. Increasing this can help detect sentences more accurately, at the cost of added latency.
@@ -103,6 +100,18 @@ The `generate_sentences()` function has the following parameters:
103
100
  If True, any Unicode emoji characters are identified and removed from the emitted output sentences. This can help to clean up the output.
104
101
  Default is False. Set to True if emojis are not required in the output.
105
102
 
103
+ - `tokenize_sentences`: (Optional) Function for sentence tokenization. Default is None.
104
+
105
+ - `tokenizer`: Specifies the tokenizer to use ('nltk' or 'stanza'). Default is 'nltk'.
106
+
107
+ - `language`: Language setting for the tokenizer ('en' or 'multilingual' for stanza). Default is 'en'.
108
+
109
+ - `log_characters`: Logs each processed character to the console for debugging. Default is False.
110
+
111
+ - `sentence_fragment_delimiters`: Characters considered as sentence delimiters for yielding quick fragment.
112
+
113
+ - `force_first_fragment_after_words`: Forces the first sentence fragment to yield after a specified number of words. Default is 10 words.
114
+
106
115
  - `log_characters`: Option to log characters to the console.
107
116
  When enabled, each character processed by the function is printed to the console. This is mainly for debugging purposes to observe the flow of characters through the function.
108
117
  Default is False. Set to True for a visual representation of characters being processed. Example: allows printing llm output to console when using stream2sentence to prepare input generation for text to speech synthesis.
@@ -59,9 +59,6 @@ The `generate_sentences()` function has the following parameters:
59
59
  - `generator`: Input character generator.
60
60
  Iterator that emits chunks of text. These chunks can be of any size, and they'll be processed one by one to extract sentences from them. It forms the primary source from which the function reads and generates sentences.
61
61
 
62
- - `quick_yield_single_sentence_fragment`: Whether to return a sentence fragment as fast as possible.
63
- This is a feature for realtime speech synthesis. In some use cases you want to audio stream a minimal chunk of text as fast as possible, even when it means to synthesize mid-sentence. In this case you set this flag to True which will yield a synthesizable sentence fragment as early as possible.
64
-
65
62
  - `context_size`: Context size for sentence detection.
66
63
  This controls how much context is looked at to detect sentence boundaries. It determines the number of characters around a potential delimiter (like a period) that are considered when detecting sentence boundaries. A larger context size allows more reliable sentence boundary detection, but requires buffering more characters before emitting a sentence.
67
64
  Default is 12 characters. Increasing this can help detect sentences more accurately, at the cost of added latency.
@@ -86,6 +83,18 @@ The `generate_sentences()` function has the following parameters:
86
83
  If True, any Unicode emoji characters are identified and removed from the emitted output sentences. This can help to clean up the output.
87
84
  Default is False. Set to True if emojis are not required in the output.
88
85
 
86
+ - `tokenize_sentences`: (Optional) Function for sentence tokenization. Default is None.
87
+
88
+ - `tokenizer`: Specifies the tokenizer to use ('nltk' or 'stanza'). Default is 'nltk'.
89
+
90
+ - `language`: Language setting for the tokenizer ('en' or 'multilingual' for stanza). Default is 'en'.
91
+
92
+ - `log_characters`: Logs each processed character to the console for debugging. Default is False.
93
+
94
+ - `sentence_fragment_delimiters`: Characters considered as sentence delimiters for yielding quick fragment.
95
+
96
+ - `force_first_fragment_after_words`: Forces the first sentence fragment to yield after a specified number of words. Default is 10 words.
97
+
89
98
  - `log_characters`: Option to log characters to the console.
90
99
  When enabled, each character processed by the function is printed to the console. This is mainly for debugging purposes to observe the flow of characters through the function.
91
100
  Default is False. Set to True for a visual representation of characters being processed. Example: allows printing llm output to console when using stream2sentence to prepare input generation for text to speech synthesis.
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name="stream2sentence",
8
- version="0.2.2",
8
+ version="0.2.3",
9
9
  author="Kolja Beigel",
10
10
  author_email="kolja.beigel@web.de",
11
11
  description="Real-time processing and delivery of sentences from a continuous stream of characters or text chunks.",
@@ -1,5 +1,6 @@
1
1
  """
2
- Real-time processing and delivery of sentences from a continuous stream of characters or text chunks
2
+ Real-time processing and delivery of sentences
3
+ from a continuous stream of characters or text chunks
3
4
  """
4
5
 
5
6
  from typing import Iterator
@@ -13,6 +14,7 @@ stanza_initialized = False
13
14
  nltk_initialized = False
14
15
  nlp = None
15
16
 
17
+
16
18
  def initialize_nltk():
17
19
  """
18
20
  Initializes NLTK by downloading required data for sentence tokenization.
@@ -20,16 +22,17 @@ def initialize_nltk():
20
22
  global nltk_initialized
21
23
  if nltk_initialized:
22
24
  return
23
-
25
+
24
26
  logging.info("Initializing NLTK")
25
27
 
26
28
  import nltk
27
29
  try:
28
- _ = nltk.data.find('tokenizers/punkt')
30
+ _ = nltk.data.find('tokenizers/punkt')
29
31
  except LookupError:
30
32
  nltk.download('punkt')
31
33
  nltk_initialized = True
32
34
 
35
+
33
36
  def initialize_stanza(language: str = "en"):
34
37
  """
35
38
  Initializes Stanza by downloading required data for sentence tokenization.
@@ -37,7 +40,7 @@ def initialize_stanza(language: str = "en"):
37
40
  global nlp, stanza_initialized
38
41
  if stanza_initialized:
39
42
  return
40
-
43
+
41
44
  logging.info("Initializing Stanza")
42
45
 
43
46
  import stanza
@@ -45,6 +48,7 @@ def initialize_stanza(language: str = "en"):
45
48
  nlp = stanza.Pipeline(language)
46
49
  stanza_initialized = True
47
50
 
51
+
48
52
  def _remove_links(text: str) -> str:
49
53
  """
50
54
  Removes any links from the input text.
@@ -55,22 +59,28 @@ def _remove_links(text: str) -> str:
55
59
  Returns:
56
60
  str: Text with links removed
57
61
  """
58
- pattern = r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+'
62
+ pattern = (
63
+ r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|'
64
+ r'[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+'
65
+ )
66
+
59
67
  return re.sub(pattern, '', text)
60
68
 
69
+
61
70
  def _remove_emojis(text: str) -> str:
62
71
  """
63
72
  Removes emojis from the input text.
64
73
 
65
74
  Args:
66
75
  text (str): Input text
67
-
76
+
68
77
  Returns:
69
78
  str: Text with emojis removed
70
79
  """
71
80
  return emoji.replace_emoji(text, u'')
72
81
 
73
- def _generate_characters(generator: Iterator[str],
82
+
83
+ def _generate_characters(generator: Iterator[str],
74
84
  log_characters: bool = False) -> Iterator[str]:
75
85
  """
76
86
  Generates individual characters from a text generator.
@@ -87,9 +97,10 @@ def _generate_characters(generator: Iterator[str],
87
97
  if log_characters:
88
98
  print(char, end="", flush=True)
89
99
  yield char
90
-
91
- def _clean_text(text: str,
92
- cleanup_text_links: bool = False,
100
+
101
+
102
+ def _clean_text(text: str,
103
+ cleanup_text_links: bool = False,
93
104
  cleanup_text_emojis: bool = False,
94
105
  strip_text: bool = True) -> str:
95
106
  """
@@ -97,9 +108,11 @@ def _clean_text(text: str,
97
108
 
98
109
  Args:
99
110
  text (str): Input text
100
- cleanup_text_links (boolean, optional): Remove non-desired links from the stream.
101
- cleanup_text_emojis (boolean, optional): Remove non-desired emojis from the stream.
102
-
111
+ cleanup_text_links (boolean, optional): Remove non-desired links from
112
+ the stream.
113
+ cleanup_text_emojis (boolean, optional): Remove non-desired emojis
114
+ from the stream.
115
+
103
116
  Returns:
104
117
  str: Cleaned text
105
118
  """
@@ -108,19 +121,21 @@ def _clean_text(text: str,
108
121
  if cleanup_text_emojis:
109
122
  text = _remove_emojis(text)
110
123
  if strip_text:
111
- text = text.strip()
124
+ text = text.strip()
112
125
  return text
113
126
 
114
- def _tokenize_sentences(text: str, tokenize_sentences = None) -> Iterator[str]:
127
+
128
+ def _tokenize_sentences(text: str, tokenize_sentences=None) -> Iterator[str]:
115
129
  """
116
130
  Tokenizes sentences from the input text.
117
131
 
118
132
  Args:
119
133
  text (str): Input text
120
- tokenize_sentences (Callable, optional): A function that tokenizes sentences from the input text. Defaults to None.
134
+ tokenize_sentences (Callable, optional): A function that tokenizes
135
+ sentences from the input text. Defaults to None.
121
136
 
122
137
  Yields:
123
- Iterator[str]: An iterator of sentences
138
+ Iterator[str]: An iterator of sentences
124
139
  """
125
140
  if tokenize_sentences:
126
141
  sentences = tokenize_sentences(text)
@@ -136,10 +151,12 @@ def _tokenize_sentences(text: str, tokenize_sentences = None) -> Iterator[str]:
136
151
  sentences = [sentence.text for sentence in doc.sentences]
137
152
  else:
138
153
  raise ValueError(f"Unknown tokenizer: {current_tokenizer}")
139
- nlp_end_time = time.time()
140
- logging.info(f"Time to split sentences: {nlp_end_time - nlp_start_time}")
154
+ nlp_end_time = time.time()
155
+ logging.info("Time to split sentences: "
156
+ f"{nlp_end_time - nlp_start_time}")
141
157
  return sentences
142
158
 
159
+
143
160
  def init_tokenizer(tokenizer: str, language: str = "en"):
144
161
  """
145
162
  Initializes the sentence tokenizer.
@@ -151,34 +168,74 @@ def init_tokenizer(tokenizer: str, language: str = "en"):
151
168
  else:
152
169
  logging.warning(f"Unknown tokenizer: {tokenizer}")
153
170
 
154
- def generate_sentences(generator: Iterator[str],
171
+
172
+ def generate_sentences(generator: Iterator[str],
155
173
  context_size: int = 12,
156
174
  minimum_sentence_length: int = 10,
157
- minimum_first_fragment_length = 10,
175
+ minimum_first_fragment_length=10,
158
176
  quick_yield_single_sentence_fragment: bool = False,
159
177
  cleanup_text_links: bool = False,
160
- cleanup_text_emojis: bool = False,
161
- tokenize_sentences = None,
178
+ cleanup_text_emojis: bool = False,
179
+ tokenize_sentences=None,
162
180
  tokenizer: str = "nltk",
163
181
  language: str = "en",
164
- log_characters: bool = False) -> Iterator[str]:
182
+ log_characters: bool = False,
183
+ sentence_fragment_delimiters: str = ".?!;:,\n…)]}。-",
184
+ force_first_fragment_after_words=15,
185
+ ) -> Iterator[str]:
165
186
  """
166
- Generates well-formed sentences from a stream of characters or text chunks provided by an input generator.
187
+ Generates well-formed sentences from a stream of characters or text chunks
188
+ provided by an input generator.
167
189
 
168
190
  Args:
169
- generator (Iterator[str]): A generator that yields chunks of text as a stream of characters.
170
- context_size (int): The number of characters used to establish context for sentence boundary detection. A larger context improves the accuracy of detecting sentence boundaries. Default is 12 characters.
171
- minimum_sentence_length (int): The minimum number of characters a sentence must have. If a sentence is shorter, it will be concatenated with the following one, improving the overall readability. This parameter does not apply to the first sentence fragment, which is governed by `minimum_first_fragment_length`. Default is 10 characters.
172
- minimum_first_fragment_length (int): The minimum number of characters required for the first sentence fragment before yielding. Default is 10 characters.
173
- quick_yield_single_sentence_fragment (bool): If set to True, the generator will yield the first sentence fragment as quickly as possible. This is particularly useful for real-time applications such as speech synthesis.
174
- cleanup_text_links (bool): If True, removes hyperlinks from the text stream to ensure clean output.
175
- cleanup_text_emojis (bool): If True, filters out emojis from the text stream for clear textual content.
176
- log_characters (bool): If True, logs each character to the console as they are processed.
191
+ generator (Iterator[str]): A generator that yields chunks of text as a
192
+ stream of characters.
193
+ context_size (int): The number of characters used to establish context
194
+ for sentence boundary detection. A larger context improves the
195
+ accuracy of detecting sentence boundaries.
196
+ Default is 12 characters.
197
+ minimum_sentence_length (int): The minimum number of characters a
198
+ sentence must have. If a sentence is shorter, it will be
199
+ concatenated with the following one, improving the overall
200
+ readability. This parameter does not apply to the first sentence
201
+ fragment, which is governed by `minimum_first_fragment_length`.
202
+ Default is 10 characters.
203
+ minimum_first_fragment_length (int): The minimum number of characters
204
+ required for the first sentence fragment before yielding.
205
+ Default is 10 characters.
206
+ quick_yield_single_sentence_fragment (bool): If set to True, the
207
+ generator will yield the first sentence fragment as quickly as
208
+ possible. This is particularly useful for real-time applications
209
+ such as speech synthesis.
210
+ cleanup_text_links (bool): If True, removes hyperlinks from the text
211
+ stream to ensure clean output.
212
+ cleanup_text_emojis (bool): If True, filters out emojis from the text
213
+ stream for clear textual content.
214
+ tokenize_sentences (Callable): A function that tokenizes sentences
215
+ from the input text. Defaults to None.
216
+ tokenizer (str): The tokenizer to use for sentence tokenization.
217
+ Default is "nltk". Can be "nltk" or "stanza".
218
+ language (str): The language to use for sentence tokenization.
219
+ Default is "en". Can be "multilingual" for stanze tokenizer.
220
+ log_characters (bool): If True, logs each character to the console as
221
+ they are processed.
222
+ sentence_fragment_delimiters (str): A string of characters that are
223
+ considered sentence delimiters. Default is ".?!;:,\n…)]}。-".
224
+ force_first_fragment_after_words (int): The number of words after
225
+ which the first sentence fragment is forced to be yielded.
226
+ Default is 15 words.
177
227
 
178
228
  Yields:
179
- Iterator[str]: An iterator of complete sentences constructed from the input text stream. Each yielded sentence meets the specified minimum length requirements and is cleaned up if specified.
180
-
181
- The function maintains a buffer to accumulate text chunks and applies natural language processing to detect sentence boundaries. It employs various heuristics, such as minimum sentence length and sentence delimiters, to ensure the quality of the output sentences. The function also provides options to clean up the text stream, making it versatile for different types of text processing applications.
229
+ Iterator[str]: An iterator of complete sentences constructed from the
230
+ input text stream. Each yielded sentence meets the specified minimum
231
+ length requirements and is cleaned up if specified.
232
+
233
+ The function maintains a buffer to accumulate text chunks and applies
234
+ natural language processing to detect sentence boundaries.
235
+ It employs various heuristics, such as minimum sentence length and
236
+ sentence delimiters, to ensure the quality of the output sentences.
237
+ The function also provides options to clean up the text stream,
238
+ making it versatile for different types of text processing applications.
182
239
  """
183
240
 
184
241
  global current_tokenizer
@@ -187,8 +244,7 @@ def generate_sentences(generator: Iterator[str],
187
244
 
188
245
  buffer = ''
189
246
  is_first_sentence = True
190
-
191
- sentence_delimiters = '.?!;:,\n…)]}。'
247
+ word_count = 0 # Initialize word count
192
248
 
193
249
  for char in _generate_characters(generator, log_characters):
194
250
 
@@ -196,10 +252,21 @@ def generate_sentences(generator: Iterator[str],
196
252
  buffer += char
197
253
  buffer = buffer.lstrip()
198
254
 
199
- if is_first_sentence and len(buffer) > minimum_first_fragment_length and quick_yield_single_sentence_fragment:
255
+ # Update word count
256
+ if char.isspace() or char in sentence_fragment_delimiters:
257
+ word_count += 1
258
+
259
+ if (is_first_sentence
260
+ and len(buffer) > minimum_first_fragment_length
261
+ and quick_yield_single_sentence_fragment):
262
+
263
+ if (buffer[-1] in sentence_fragment_delimiters
264
+ or word_count >= force_first_fragment_after_words):
200
265
 
201
- if buffer[-1] in sentence_delimiters:
202
- yield_text = _clean_text(buffer, cleanup_text_links, cleanup_text_emojis)
266
+ yield_text = _clean_text(
267
+ buffer,
268
+ cleanup_text_links,
269
+ cleanup_text_emojis)
203
270
  yield yield_text
204
271
  buffer = ""
205
272
  is_first_sentence = False
@@ -209,15 +276,19 @@ def generate_sentences(generator: Iterator[str],
209
276
  if len(buffer) <= minimum_sentence_length + context_size:
210
277
  continue
211
278
 
212
- # Potential delimiter character has to be a bit away from the end of the buffer
213
- # For reliable sentence detection the engine needs enough context to work with
279
+ # Potential delimiter character has to be a bit away from the end
280
+ # of the buffer. For reliable sentence detection the engine needs
281
+ # enough context to work with
214
282
  delimiter_char = buffer[-context_size]
215
283
 
216
- if delimiter_char in sentence_delimiters:
284
+ if delimiter_char in sentence_fragment_delimiters:
217
285
  sentences = _tokenize_sentences(buffer, tokenize_sentences)
218
286
  if len(sentences) > 1:
219
287
  if len(sentences[0]) == len(buffer) - context_size + 1:
220
- yield_text = _clean_text(buffer[:-context_size + 1], cleanup_text_links, cleanup_text_emojis)
288
+ yield_text = _clean_text(
289
+ buffer[:-context_size + 1],
290
+ cleanup_text_links,
291
+ cleanup_text_emojis)
221
292
  yield yield_text
222
293
  buffer = buffer[-context_size + 1:]
223
294
  is_first_sentence = False
@@ -232,11 +303,17 @@ def generate_sentences(generator: Iterator[str],
232
303
  if len(sentence_buffer) < minimum_sentence_length:
233
304
  sentence_buffer += " "
234
305
  continue
235
- yield_text = _clean_text(sentence_buffer, cleanup_text_links, cleanup_text_emojis)
306
+ yield_text = _clean_text(
307
+ sentence_buffer,
308
+ cleanup_text_links,
309
+ cleanup_text_emojis)
236
310
  yield yield_text
237
311
 
238
312
  sentence_buffer = ""
239
-
313
+
240
314
  if sentence_buffer:
241
- yield_text = _clean_text(sentence_buffer, cleanup_text_links, cleanup_text_emojis)
242
- yield yield_text
315
+ yield_text = _clean_text(
316
+ sentence_buffer,
317
+ cleanup_text_links,
318
+ cleanup_text_emojis)
319
+ yield yield_text
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: stream2sentence
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Real-time processing and delivery of sentences from a continuous stream of characters or text chunks.
5
5
  Home-page: https://github.com/KoljaB/stream2sentence
6
6
  Author: Kolja Beigel
@@ -76,9 +76,6 @@ The `generate_sentences()` function has the following parameters:
76
76
  - `generator`: Input character generator.
77
77
  Iterator that emits chunks of text. These chunks can be of any size, and they'll be processed one by one to extract sentences from them. It forms the primary source from which the function reads and generates sentences.
78
78
 
79
- - `quick_yield_single_sentence_fragment`: Whether to return a sentence fragment as fast as possible.
80
- This is a feature for realtime speech synthesis. In some use cases you want to audio stream a minimal chunk of text as fast as possible, even when it means to synthesize mid-sentence. In this case you set this flag to True which will yield a synthesizable sentence fragment as early as possible.
81
-
82
79
  - `context_size`: Context size for sentence detection.
83
80
  This controls how much context is looked at to detect sentence boundaries. It determines the number of characters around a potential delimiter (like a period) that are considered when detecting sentence boundaries. A larger context size allows more reliable sentence boundary detection, but requires buffering more characters before emitting a sentence.
84
81
  Default is 12 characters. Increasing this can help detect sentences more accurately, at the cost of added latency.
@@ -103,6 +100,18 @@ The `generate_sentences()` function has the following parameters:
103
100
  If True, any Unicode emoji characters are identified and removed from the emitted output sentences. This can help to clean up the output.
104
101
  Default is False. Set to True if emojis are not required in the output.
105
102
 
103
+ - `tokenize_sentences`: (Optional) Function for sentence tokenization. Default is None.
104
+
105
+ - `tokenizer`: Specifies the tokenizer to use ('nltk' or 'stanza'). Default is 'nltk'.
106
+
107
+ - `language`: Language setting for the tokenizer ('en' or 'multilingual' for stanza). Default is 'en'.
108
+
109
+ - `log_characters`: Logs each processed character to the console for debugging. Default is False.
110
+
111
+ - `sentence_fragment_delimiters`: Characters considered as sentence delimiters for yielding quick fragment.
112
+
113
+ - `force_first_fragment_after_words`: Forces the first sentence fragment to yield after a specified number of words. Default is 10 words.
114
+
106
115
  - `log_characters`: Option to log characters to the console.
107
116
  When enabled, each character processed by the function is printed to the console. This is mainly for debugging purposes to observe the flow of characters through the function.
108
117
  Default is False. Set to True for a visual representation of characters being processed. Example: allows printing llm output to console when using stream2sentence to prepare input generation for text to speech synthesis.