pltobing commited on
Commit
b5ac9cc
·
1 Parent(s): d170c8b

feat: revised the continuous streaming to work

Browse files

- After several testings, the best way is to
append another prefill_embed to the last KV-cache,
while still continuing the length position index.
- This needs to be reset if the start of the next
round of text is equal or greater than position
50 (4 s.). It is the optimum length to not make
the model confused as we append multiple prefill
sequences in between the chunks.
- The next thing is the speaker embedding. Here,
it is revised to use the waveform sequence of the
previous round to make the prosody consistent. As
from our observation, the speaker embedding affects
not only the identity, but also other acoustics,
as well as prosody.
- With factorization of speaker embedding, the previous
point will be better in the performance. However,
for now, this method will work to allow fully
streamable text-to-speech, where you have multiple
rounds of texts.

src/inference/qwen3_tts_inferencer_onnx.py CHANGED
@@ -117,6 +117,10 @@ _LOCAL_MAX_SEQ_LEN = 16
117
  _NUM_CODE_GROUPS = 16
118
 
119
 
 
 
 
 
120
  # ── CPU sampling helpers ──────────────────────────────────────────────────────
121
 
122
 
@@ -208,7 +212,7 @@ def _make_session(
208
  opts.execution_mode = ort.ExecutionMode.ORT_SEQUENTIAL
209
  opts.enable_cpu_mem_arena = True
210
  opts.enable_mem_pattern = True
211
- opts.log_severity_level = 1
212
 
213
  if use_cuda:
214
  cuda_opts = {
@@ -814,6 +818,7 @@ class Qwen3TTSInferencerONNX:
814
  self._last_hidden_states_np: Optional[np.ndarray] = None
815
  self._step_idx = 0
816
  self._talker_seq_len = 0
 
817
 
818
  # ── Streaming text state ──────────────────────────────────────────────
819
  self._text_cache = ""
@@ -821,6 +826,7 @@ class Qwen3TTSInferencerONNX:
821
  self._prefilled = False
822
  self._text_ended = False
823
  self._turn_idx = 0
 
824
 
825
  # ── Audio buffer ──────────────────────────────────────────────────────
826
  self._prev_tail: Optional[np.ndarray] = None
@@ -1314,7 +1320,10 @@ class Qwen3TTSInferencerONNX:
1314
  def _build_assistant_text(self) -> str:
1315
  return "<|im_start|>assistant\n"
1316
 
1317
- def _prefill_embeds(self, audio_ref_path: str, language: str) -> np.ndarray:
 
 
 
1318
  """Build the 9-token prefill embedding for the Talker.
1319
 
1320
  Layout (matches modeling_qwen3_tts.py generate_icl_prompt):
@@ -1330,7 +1339,7 @@ class Qwen3TTSInferencerONNX:
1330
  else:
1331
  language_id = self._codec_language_id[language.lower()]
1332
  log.info(f"_prefill_embeds language_id {language_id}")
1333
- speaker_embed = self.create_voice_clone_spkemb(audio_ref_path) # [B, 1, 512]
1334
  log.info(f"_prefill_embeds speaker_embed {speaker_embed} {speaker_embed.shape}")
1335
 
1336
  codec_prefill_list = np.array(
@@ -1401,18 +1410,115 @@ class Qwen3TTSInferencerONNX:
1401
 
1402
  def prefill(self) -> None:
1403
  """Run the 9-token prefill pass (IOBinding + CUDA graph) and snapshot KV."""
1404
- inputs_embeds = self._prefill_embeds(self._audio_ref_path, self._language)
1405
- cache_position = np.arange(self._step_idx, self._step_idx + _TALKER_PREFILL_LEN, dtype=np.int64)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1406
  causal_rows = self._causal_tril[:, :, cache_position, :] # [1,1,q_len,MAX]
1407
  attn_mask = np.where(causal_rows, 0.0, -np.inf).astype(np.float32) # [1, 1, q_len, MAX_SEQ_LEN]
1408
  cos_rope = self._cos_rope[:, :, cache_position].copy()
1409
  sin_rope = self._sin_rope[:, :, cache_position].copy()
1410
  self._run_talker_prefill(inputs_embeds, cache_position, attn_mask, cos_rope, sin_rope)
1411
- self._talker_seq_len = self._step_idx + _TALKER_PREFILL_LEN
 
 
 
 
1412
  # Snapshot the post-prefill KV state for turn resets
1413
  self._kv_talker_prefill_np = self._snapshot_talker_kv()
1414
  self._prefilled = True
1415
- log.info(f"Prefill done; talker_seq_len={self._talker_seq_len}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1416
 
1417
  # ── Talker prefill execution (IOBinding + CUDA graph) ───────────────────
1418
 
@@ -1563,13 +1669,15 @@ class Qwen3TTSInferencerONNX:
1563
  return self._last_audio_tokens
1564
 
1565
  # ── Build inputs_embeds ───────────────────────────────────────────────
1566
- if self._step_idx > 0:
1567
  codec_embeds = self._last_first_token_embed + self._last_local_tokens_embed
1568
  else:
1569
  codec_embeds = self._talker_codec_embed.run(
1570
  ["codec_emb"],
1571
  {"codec_ids": np.array([[self._codec_bos_id]], dtype=np.int64)},
1572
  )[0]
 
 
1573
 
1574
  if text_token is not None:
1575
  text_ids = np.array([[text_token]], dtype=np.int64)
@@ -1594,7 +1702,6 @@ class Qwen3TTSInferencerONNX:
1594
  # f"step-idx-{self._step_idx} self._last_hidden_states_np {self._last_hidden_states_np} "
1595
  # f"{self._last_hidden_states_np.shape} {self._last_hidden_states_np.dtype}"
1596
  # )
1597
- self._talker_seq_len += 1
1598
 
1599
  # ── Sample first token (CPU) ──────────────────────────────────────────
1600
  history = self._generated_tokens[:, :, 0]
@@ -1603,6 +1710,9 @@ class Qwen3TTSInferencerONNX:
1603
 
1604
  self._last_first_token = first_token
1605
  self._is_stopping = bool(first_token[0] == self._codec_eos_token_id)
 
 
 
1606
  if self.is_finished:
1607
  return None
1608
 
@@ -1616,7 +1726,6 @@ class Qwen3TTSInferencerONNX:
1616
  # ── Run Local Talker (15 steps) ───────────────────────────────────────
1617
  self._generate_local_transformer()
1618
 
1619
- self._step_idx += 1
1620
  return self._last_audio_tokens
1621
 
1622
  # ── Local Talker inner loop ───────────────────────────────────────────────
@@ -1953,13 +2062,18 @@ class Qwen3TTSInferencerONNX:
1953
 
1954
  def _drain_pending_tokens(self) -> List[NDArrayInt]:
1955
  outputs: List[NDArrayInt] = []
 
1956
  if not self._prefilled:
1957
- self.prefill()
1958
- return outputs
1959
- log.info(f"self._pending_tokens {self._pending_tokens}")
 
 
1960
  while self._pending_tokens and not self.is_finished:
1961
  token = self._pending_tokens.pop(0)
1962
- log.info(f"pop token {token} -> pending_tokens {self._pending_tokens}")
 
 
1963
  output = self.step(token)
1964
  if output is not None:
1965
  outputs.append(output)
@@ -1967,18 +2081,24 @@ class Qwen3TTSInferencerONNX:
1967
 
1968
  def push_text(self, text_fragment: str) -> List[NDArrayInt]:
1969
  self._text_cache += text_fragment
1970
- log.info(f"push text_fragment {text_fragment} -> text_cache {self._text_cache}")
1971
  for segment in self._extract_text_segments(force=False):
1972
- self._pending_tokens.extend(self._tokenize_texts([segment]))
1973
- log.info(f"push segment {segment} -> pending_tokens {self._pending_tokens}")
 
 
 
 
1974
  return self._drain_pending_tokens()
1975
 
1976
  def end_text(self) -> List[NDArrayInt]:
1977
  self._text_ended = True
 
1978
  if self._text_cache:
1979
  self._pending_tokens.extend(self._tokenize_texts([self._text_cache]))
1980
  self._text_cache = ""
1981
  self._pending_tokens.extend([np.array([self._tts_eos_token_id], dtype=np.int64)][0])
 
1982
  return self._drain_pending_tokens()
1983
 
1984
  def drain(self, max_steps: Optional[int] = None) -> List[NDArrayInt]:
@@ -2077,6 +2197,10 @@ class Qwen3TTSInferencerONNX:
2077
  )
2078
 
2079
  self._codec_step_idx += self.chunk_frames
 
 
 
 
2080
  return wav
2081
 
2082
  def _overlap_samples(self, wav: NDArrayFloat) -> int:
@@ -2141,7 +2265,7 @@ class Qwen3TTSInferencerONNX:
2141
  self._last_hidden_states_np = None
2142
  self._step_idx = 0
2143
 
2144
- def reset_turn(self, reset_cache: bool = False) -> None:
2145
  """Reset for a new turn. If ``reset_cache=True``, also clears the prefill KV."""
2146
  self._turn_idx += 1
2147
  self._text_cache = ""
@@ -2149,6 +2273,12 @@ class Qwen3TTSInferencerONNX:
2149
  self._prefilled = False
2150
  self._text_ended = False
2151
  self._prev_tail = None
 
2152
  self._buffer = []
2153
  self._buffer_len = 0
2154
- self.reset_generation_state(keep_prefill_cache=not reset_cache)
 
 
 
 
 
 
117
  _NUM_CODE_GROUPS = 16
118
 
119
 
120
+ # For continuous streaming with multi turn texts
121
+ _LENGTH_RESET_LIMIT_FOR_START_OF_MULTI_TURN = 50
122
+
123
+
124
  # ── CPU sampling helpers ──────────────────────────────────────────────────────
125
 
126
 
 
212
  opts.execution_mode = ort.ExecutionMode.ORT_SEQUENTIAL
213
  opts.enable_cpu_mem_arena = True
214
  opts.enable_mem_pattern = True
215
+ opts.log_severity_level = 2
216
 
217
  if use_cuda:
218
  cuda_opts = {
 
818
  self._last_hidden_states_np: Optional[np.ndarray] = None
819
  self._step_idx = 0
820
  self._talker_seq_len = 0
821
+ self._generated_wav = None
822
 
823
  # ── Streaming text state ──────────────────────────────────────────────
824
  self._text_cache = ""
 
826
  self._prefilled = False
827
  self._text_ended = False
828
  self._turn_idx = 0
829
+ self._first_step_next_round = False
830
 
831
  # ── Audio buffer ──────────────────────────────────────────────────────
832
  self._prev_tail: Optional[np.ndarray] = None
 
1320
  def _build_assistant_text(self) -> str:
1321
  return "<|im_start|>assistant\n"
1322
 
1323
+ def _build_ending_assistant_text(self) -> str:
1324
+ return "<|im_end|>\n"
1325
+
1326
+ def _prefill_embeds(self, audio_info: AudioLike, language: str) -> np.ndarray:
1327
  """Build the 9-token prefill embedding for the Talker.
1328
 
1329
  Layout (matches modeling_qwen3_tts.py generate_icl_prompt):
 
1339
  else:
1340
  language_id = self._codec_language_id[language.lower()]
1341
  log.info(f"_prefill_embeds language_id {language_id}")
1342
+ speaker_embed = self.create_voice_clone_spkemb(audio_info) # [B, 1, 512]
1343
  log.info(f"_prefill_embeds speaker_embed {speaker_embed} {speaker_embed.shape}")
1344
 
1345
  codec_prefill_list = np.array(
 
1410
 
1411
  def prefill(self) -> None:
1412
  """Run the 9-token prefill pass (IOBinding + CUDA graph) and snapshot KV."""
1413
+ if self._step_idx == 0:
1414
+ audio_info = self._audio_ref_path
1415
+ else:
1416
+ wav_history = self._generated_wav[0, 0]
1417
+ log.info(f"prefill cont wav_history {wav_history} {wav_history.shape} {wav_history.dtype}")
1418
+ audio_info = (
1419
+ wav_history,
1420
+ 24000,
1421
+ )
1422
+ self._generated_wav = None
1423
+ # use previously generated audio sequence
1424
+ # from previous list of texts with the window limit 50 as reference
1425
+ inputs_embeds = self._prefill_embeds(audio_info, self._language)
1426
+ if self._step_idx == 0:
1427
+ cache_position = np.arange(_TALKER_PREFILL_LEN, dtype=np.int64)
1428
+ else:
1429
+ cache_position = np.arange(
1430
+ self._talker_seq_len, self._talker_seq_len + _TALKER_PREFILL_LEN, dtype=np.int64
1431
+ )
1432
  causal_rows = self._causal_tril[:, :, cache_position, :] # [1,1,q_len,MAX]
1433
  attn_mask = np.where(causal_rows, 0.0, -np.inf).astype(np.float32) # [1, 1, q_len, MAX_SEQ_LEN]
1434
  cos_rope = self._cos_rope[:, :, cache_position].copy()
1435
  sin_rope = self._sin_rope[:, :, cache_position].copy()
1436
  self._run_talker_prefill(inputs_embeds, cache_position, attn_mask, cos_rope, sin_rope)
1437
+ if self._step_idx == 0:
1438
+ self._talker_seq_len = _TALKER_PREFILL_LEN
1439
+ else:
1440
+ self._talker_seq_len = self._talker_seq_len + _TALKER_PREFILL_LEN
1441
+ self._step_idx = self._talker_seq_len
1442
  # Snapshot the post-prefill KV state for turn resets
1443
  self._kv_talker_prefill_np = self._snapshot_talker_kv()
1444
  self._prefilled = True
1445
+ log.info(f"Prefill done; talker_seq_len={self._talker_seq_len}; step_idx={self._step_idx}")
1446
+
1447
+ def prefill_cont(self) -> None:
1448
+ """
1449
+ Run the prefill for continuation pass (IOBinding + CUDA graph) and snapshot KV.
1450
+ [text_pad],[token_ids("<im_end>\n")],[text_bos] -> continue with the first text token
1451
+ [codec_eos],[None],[codec_pad] -> continue with codec_bos and generation
1452
+ """
1453
+
1454
+ # text_ids = np.array([[self._tts_pad_token_id, self._tts_bos_token_id]], dtype=np.int64)
1455
+ # text_ids = np.array([[self._tts_pad_token_id]], dtype=np.int64)
1456
+ # log.info(f"prefill_cont text_ids {text_ids} {text_ids.shape}")
1457
+ # outputs = self._text_embed_proj.run(["text_emb_out"], {"text_ids": text_ids}) # 3
1458
+ # # embeds = outputs[0]
1459
+ # # tts_pad_embed, tts_bos_embed = embeds[:, :1], embeds[:, 1:] # 2 * [1 1 d]
1460
+ # tts_pad_embed = outputs[0]
1461
+ # # log.info(f"prefill_cont tts_bos_embed {tts_bos_embed} {tts_bos_embed.shape} {tts_bos_embed.dtype}")
1462
+ # log.info(f"prefill_cont tts_pad_embed {tts_pad_embed} {tts_pad_embed.shape} {tts_pad_embed.dtype}")
1463
+
1464
+ # # codec_ids = np.array([[self._codec_eos_token_id, self._codec_pad_id]], dtype=np.int64)
1465
+ # codec_ids = np.array([[self._codec_eos_token_id]], dtype=np.int64)
1466
+ # log.info(f"prefill_cont codec_ids {codec_ids} {codec_ids.shape}")
1467
+ # outputs = self._talker_codec_embed.run(["codec_emb"], {"codec_ids": codec_ids})
1468
+ # # embeds = outputs[0]
1469
+ # # codec_eos_embed, codec_pad_embed = embeds[:, :1], embeds[:, 1:] # 2 * [1 1 d]
1470
+ # codec_eos_embed = outputs[0]
1471
+ # log.info(f"prefill_cont codec_eos_embed {codec_eos_embed} {codec_eos_embed.shape} {codec_eos_embed.dtype}")
1472
+ # # log.info(f"prefill_cont codec_pad_embed {codec_pad_embed} {codec_pad_embed.shape} {codec_pad_embed.dtype}")
1473
+
1474
+ # tts_pad_codec_eos_embed = tts_pad_embed + codec_eos_embed
1475
+ # # tts_bos_codec_pad_embed = tts_bos_embed + codec_pad_embed
1476
+
1477
+ # self._tokenize_texts([self._build_ending_assistant_text(), self._build_assistant_text()]),
1478
+ # self._tokenize_texts([self._build_assistant_text()]),
1479
+ # prefix_tokens = np.expand_dims(
1480
+ # np.array(
1481
+ # self._tokenize_texts([self._build_ending_assistant_text()]),
1482
+ # dtype=np.int64,
1483
+ # ),
1484
+ # axis=0,
1485
+ # )
1486
+ # log.info(f"prefill_cont prefix_tokens {prefix_tokens} {prefix_tokens.shape}")
1487
+ # outputs = self._text_embed_proj.run(["text_emb_out"], {"text_ids": prefix_tokens}) # 3
1488
+ # _talker_input_embed_role = outputs[0]
1489
+ # log.info(
1490
+ # f"prefill_cont _talker_input_embed_role {_talker_input_embed_role} {_talker_input_embed_role.shape} {_talker_input_embed_role.dtype}"
1491
+ # )
1492
+
1493
+ # talker_input_embed = _talker_input_embed_role
1494
+ # talker_input_embed = np.concatenate(
1495
+ # (_talker_input_embed_role, tts_bos_codec_pad_embed), axis=1
1496
+ # ) # 6
1497
+ # (tts_pad_codec_eos_embed, _talker_input_embed_role, tts_bos_codec_pad_embed), axis=1
1498
+ # talker_input_embed = np.concatenate((tts_pad_codec_eos_embed, tts_bos_codec_pad_embed), axis=1) # 2
1499
+ # talker_input_embed = np.concatenate((tts_pad_codec_eos_embed, _talker_input_embed_role), axis=1) # 3
1500
+ # log.info(
1501
+ # f"prefill_cont talker_input_embed {talker_input_embed} {talker_input_embed.shape} {talker_input_embed.dtype}"
1502
+ # )
1503
+
1504
+ # log.info(f"prefill_cont talker_seq_len {self._talker_seq_len} step_idx {self._step_idx}")
1505
+ # for i in range(talker_input_embed.shape[1]):
1506
+ # inputs_embeds = talker_input_embed[:, i : i + 1]
1507
+ # cache_position = np.array([self._talker_seq_len], dtype=np.int64)
1508
+ # causal_rows = self._causal_tril[:, :, cache_position, :] # [1,1,q_len,MAX]
1509
+ # attn_mask = np.where(causal_rows, 0.0, -np.inf).astype(np.float32) # [1, 1, q_len, MAX_SEQ_LEN]
1510
+ # cos_rope = self._cos_rope[:, :, cache_position].copy()
1511
+ # sin_rope = self._sin_rope[:, :, cache_position].copy()
1512
+ # self._run_talker_step(inputs_embeds, cache_position, attn_mask, cos_rope, sin_rope)
1513
+ # self._talker_seq_len += 1
1514
+ # self._step_idx += 1
1515
+
1516
+ self.prefill()
1517
+ # Snapshot the post-prefill KV state for turn resets
1518
+ self._kv_talker_prefill_np = self._snapshot_talker_kv()
1519
+ self._prefilled = True
1520
+ self._first_step_next_round = True
1521
+ log.info(f"Prefill cont done; talker_seq_len={self._talker_seq_len}; step_idx={self._step_idx}")
1522
 
1523
  # ── Talker prefill execution (IOBinding + CUDA graph) ───────────────────
1524
 
 
1669
  return self._last_audio_tokens
1670
 
1671
  # ── Build inputs_embeds ───────────────────────────────────────────────
1672
+ if self._step_idx > 0 and not self._first_step_next_round:
1673
  codec_embeds = self._last_first_token_embed + self._last_local_tokens_embed
1674
  else:
1675
  codec_embeds = self._talker_codec_embed.run(
1676
  ["codec_emb"],
1677
  {"codec_ids": np.array([[self._codec_bos_id]], dtype=np.int64)},
1678
  )[0]
1679
+ if self._first_step_next_round:
1680
+ self._first_step_next_round = False
1681
 
1682
  if text_token is not None:
1683
  text_ids = np.array([[text_token]], dtype=np.int64)
 
1702
  # f"step-idx-{self._step_idx} self._last_hidden_states_np {self._last_hidden_states_np} "
1703
  # f"{self._last_hidden_states_np.shape} {self._last_hidden_states_np.dtype}"
1704
  # )
 
1705
 
1706
  # ── Sample first token (CPU) ──────────────────────────────────────────
1707
  history = self._generated_tokens[:, :, 0]
 
1710
 
1711
  self._last_first_token = first_token
1712
  self._is_stopping = bool(first_token[0] == self._codec_eos_token_id)
1713
+
1714
+ self._talker_seq_len += 1
1715
+ self._step_idx += 1
1716
  if self.is_finished:
1717
  return None
1718
 
 
1726
  # ── Run Local Talker (15 steps) ───────────────────────────────────────
1727
  self._generate_local_transformer()
1728
 
 
1729
  return self._last_audio_tokens
1730
 
1731
  # ── Local Talker inner loop ───────────────────────────────────────────────
 
2062
 
2063
  def _drain_pending_tokens(self) -> List[NDArrayInt]:
2064
  outputs: List[NDArrayInt] = []
2065
+ log.info(f"drain_pending_tokens is_prefilled {self._prefilled} is_finished {self.is_finished}")
2066
  if not self._prefilled:
2067
+ if self._step_idx == 0:
2068
+ self.prefill()
2069
+ else:
2070
+ self.prefill_cont()
2071
+ log.info(f"drain_pending_tokens pending_tokens {self._pending_tokens} {len(self._pending_tokens)}")
2072
  while self._pending_tokens and not self.is_finished:
2073
  token = self._pending_tokens.pop(0)
2074
+ log.info(
2075
+ f"drain_pending_tokens token {token} -> pending_tokens {self._pending_tokens} {len(self._pending_tokens)}"
2076
+ )
2077
  output = self.step(token)
2078
  if output is not None:
2079
  outputs.append(output)
 
2081
 
2082
  def push_text(self, text_fragment: str) -> List[NDArrayInt]:
2083
  self._text_cache += text_fragment
2084
+ log.info(f"push_text text_fragment {text_fragment} -> text_cache {self._text_cache}")
2085
  for segment in self._extract_text_segments(force=False):
2086
+ tokenized_segment = self._tokenize_texts([segment])
2087
+ log.info(
2088
+ f"push_text segment {segment} {len(segment)} -> tokenized_segment {tokenized_segment} {len(tokenized_segment)}"
2089
+ )
2090
+ self._pending_tokens.extend(tokenized_segment)
2091
+ log.info(f"push_text pending_tokens {self._pending_tokens}")
2092
  return self._drain_pending_tokens()
2093
 
2094
  def end_text(self) -> List[NDArrayInt]:
2095
  self._text_ended = True
2096
+ log.info(f"end_text text_cache {self._text_cache} {len(self._text_cache)}")
2097
  if self._text_cache:
2098
  self._pending_tokens.extend(self._tokenize_texts([self._text_cache]))
2099
  self._text_cache = ""
2100
  self._pending_tokens.extend([np.array([self._tts_eos_token_id], dtype=np.int64)][0])
2101
+ log.info(f"end_text pending_tokens {self._pending_tokens} {len(self._pending_tokens)}")
2102
  return self._drain_pending_tokens()
2103
 
2104
  def drain(self, max_steps: Optional[int] = None) -> List[NDArrayInt]:
 
2197
  )
2198
 
2199
  self._codec_step_idx += self.chunk_frames
2200
+ if self._generated_wav is not None:
2201
+ self._generated_wav = np.concatenate((self._generated_wav, wav.copy()), axis=-1)
2202
+ else:
2203
+ self._generated_wav = wav.copy()
2204
  return wav
2205
 
2206
  def _overlap_samples(self, wav: NDArrayFloat) -> int:
 
2265
  self._last_hidden_states_np = None
2266
  self._step_idx = 0
2267
 
2268
+ def reset_turn(self, reset_cache: Optional[bool] = None) -> None:
2269
  """Reset for a new turn. If ``reset_cache=True``, also clears the prefill KV."""
2270
  self._turn_idx += 1
2271
  self._text_cache = ""
 
2273
  self._prefilled = False
2274
  self._text_ended = False
2275
  self._prev_tail = None
2276
+ self._is_stopping = False
2277
  self._buffer = []
2278
  self._buffer_len = 0
2279
+ if self._step_idx >= _LENGTH_RESET_LIMIT_FOR_START_OF_MULTI_TURN:
2280
+ log.info(f"reset_turn reset_generation_state step-idx-{self._step_idx}")
2281
+ self._first_step_next_round = False
2282
+ self.reset_generation_state(False)
2283
+ elif reset_cache is not None:
2284
+ self.reset_generation_state(keep_prefill_cache=not reset_cache)
test_qwen3-tts-streaming_onnx.py CHANGED
@@ -102,23 +102,33 @@ _CODEC_CONFIG_PATH = "./configs/speech_tokenizer_config.json"
102
  # _AUDIO_REF_PATH = "./audio_ref/female_shadowheart.flac"
103
  _AUDIO_REF_PATH = "./audio_ref/male_stewie.mp3"
104
  _OUTPUT_WAV_DIR = "./audio_synth/"
105
- _LANGUAGE = "russian"
106
  # _LANGUAGE = "english"
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  # _TEXT = "в зависимости от времени не только точность, но и низкая задержка."
108
  _TEXT = [
109
- "Проверьте, проверьте, тест, один,",
110
- "два Это система непрерывного перевода",
111
- "речи в зависимости от времени не только",
112
- "но не только точность,",
113
- "но и но также важна задержка если это не мгновенн>о",
114
- "тогда то человеческое взаимодействие",
115
- "теряется мы наконец-то достигаем момента,",
116
- "когда техн>ология станет достаточно быстрой для того,"
117
- "чтобы люди могли просто общаться и это огромный с>",
118
- виг для глобального бизнеса"
119
  ]
120
- # _TEXT = ["This is a test, ", "how about this one?", "Is this also?"]
121
- # _TEXT = ["This is not a test.", "How about this one?", "Is this also not?"]
122
  _OUTPUT_SAMPLE_RATE = 24000
123
  _CHUNK_FRAMES = 4
124
  _TEMPERATURE = 0.85
@@ -204,7 +214,7 @@ def run_streaming_tts(
204
  t_start = time.perf_counter()
205
 
206
  for i, text in enumerate(text_list):
207
- inferencer.reset_turn(reset_cache=False)
208
  log.info(f"Synthesising: {text!r}")
209
 
210
  # ── Stream text deltas ────────────────────────────────────────────────────
 
102
  # _AUDIO_REF_PATH = "./audio_ref/female_shadowheart.flac"
103
  _AUDIO_REF_PATH = "./audio_ref/male_stewie.mp3"
104
  _OUTPUT_WAV_DIR = "./audio_synth/"
 
105
  # _LANGUAGE = "english"
106
+ # _TEXT = [
107
+ # "Depending on the time,",
108
+ # "not only accuracy,",
109
+ # "but also low latency is important.",
110
+ # "If it is not instant,",
111
+ # "then, the human interaction is lost",
112
+ # "We are finally reaching a moment",
113
+ # "where the technology is fast enough",
114
+ # "for people to simply communicate.",
115
+ # "And that is a huge shift",
116
+ # "for global business",
117
+ # ]
118
+ _LANGUAGE = "russian"
119
  # _TEXT = "в зависимости от времени не только точность, но и низкая задержка."
120
  _TEXT = [
121
+ "В зависимости от ситуации,",
122
+ "важна не только точность,",
123
+ "но и низкая задержка.",
124
+ "Если это происходит не мгновенно,",
125
+ "то теряется эффект живого общения.",
126
+ "Мы наконец-то достигли момента,",
127
+ "когда технологии стали достаточно быстрыми,",
128
+ "чтобы люди могли просто общаться.",
129
+ "И это огромный сдвиг",
130
+ "для мирового бизнеса.",
131
  ]
 
 
132
  _OUTPUT_SAMPLE_RATE = 24000
133
  _CHUNK_FRAMES = 4
134
  _TEMPERATURE = 0.85
 
214
  t_start = time.perf_counter()
215
 
216
  for i, text in enumerate(text_list):
217
+ inferencer.reset_turn(reset_cache=None)
218
  log.info(f"Synthesising: {text!r}")
219
 
220
  # ── Stream text deltas ────────────────────────────────────────────────────