- TTSBridge.synthesize wraps stdin/stdout request-response in asyncio.Lock;
concurrent calls previously caused 'readuntil() called while another
coroutine is already waiting' and ENOENT (temp dir deleted while bridge
still reading input.txt)
- TTSService.start/stop guarded by lifecycle lock to prevent race from
rapid Start clicks creating duplicate bridge/worker/danmaku connections
- Verified: 20 concurrent synthesize calls all succeed with correct WAV
- Rebuild portable zip (83.8 MB)
Root cause: AquesTalk_Synthe silently drops all text after a space.
English segments previously joined with spaces (word gap), so anything
after the first space was silent. Replace all spaces with 、 (Japanese
comma pause) which AquesTalk supports natively.
- PUNCT_MAP maps space -> 、
- convertEnglishSegment joins words with 、
- synthesize collapses consecutive pauses, strips residual spaces
Verified: 'Actually这个proposal是非常creative的' WAV 19316 -> 79196 bytes
- Add phonemize (MIT) rule-based G2P as second fallback tier
- IPA phoneme -> katakana CV-syllable transcription table
- proposal -> プラポーザル, bilibili -> バイリーバイリー (no more letter-spelling)
- Letter spelling kept as last resort only
- Bridge logs SYNTH IN/OUT to stderr; tts.py drains stderr to Python logs
so conversion results are visible in the server log
- Rebuild portable zip (83.8 MB)