github Fangyuan025/Chaty v2.1.4

3 hours ago

Chinese speech, and a picture that stops costing the conversation

Chaty listens and answers in Chinese. Speech recognition was
English-only and text-to-speech had no Chinese voice at all, so the
whole voice section was hidden outside the English UI. Recognition
now runs multilingual Whisper when Chinese is in play, and a Chinese
reply is spoken by a local VITS voice while English keeps Kokoro,
decided per utterance. English speech did not get worse to make room
for it: multilingual Whisper is a real accuracy drop on English, so
English stays on base.en — the model already on disk, no
re-download and nothing orphaned — and the multilingual model is
fetched only when the UI is Chinese or the Chinese-voice switch is
on. Its files are pinned to a revision rather than to a moving
branch, so a size check can no longer pass on bytes that changed
underneath it. (#8, by @wisetwo)

Around that: a voice model left half-downloaded now repairs itself
one file at a time instead of being fetched again from the start,
files land in a staging directory and are moved into place
atomically, the preview plays — WKWebView applies Safari's
user-activation rules, so the audio context is unlocked on the first
gesture rather than after the synthesis round-trip — and a preview
or transcription that fails says why. Live Mode stops racing the
microphone: the capture thread signals when it has actually released
the device and the next start waits for that, instead of guessing at
a delay.

A picture stopped throwing the conversation away. Through MLX, any
prompt carrying an image was evaluated from the very beginning — the
whole transcript, every turn, on the screenshot round and on every
round after it. Measured across seven local models in both thinking
modes: 0% of the window reused from the moment a screenshot entered
a conversation until the end of it. Two causes, both fixed. The chat
template rewrites a stored turn's reasoning when pixels force it to
render the history, and re-encoding a turn's text is not the inverse
of generating it — on Qwen3.5 2B the word "Chaty" comes back as a
different pair of tokens than the model emitted, and one pair is
enough to end the match. Chaty now replays the exact tokens each
turn occupies in the cache. Same sweep afterwards: 99-100% on every
round after a picture, all fourteen combinations.

A second screenshot resumes the conversation instead of re-reading
it. That round used to start over, because a call carrying pixels
was assumed to be positionable only from the beginning. It is not —
the model takes its positions from the cache — so only the new
picture is read now and the conversation beneath it is kept. The
older screenshot also stays visible instead of being dropped to save
an encode that no longer happens.

And a screenshot in a long conversation stopped taking minutes. The
span a vision model reads in one pass ran from the start of the
prompt to the last picture in it, so a screenshot's cost was set by
the transcript underneath: 12.3k tokens took 187 seconds on a 35B,
and a real 50k round had produced nothing after ninety minutes with
20 GB of swap churning. The text below a picture is ordinary text
and now goes in chunks like any other; only the picture's own span
is one pass. A 48k-token conversation with a four-tile screenshot
reads in 13 seconds against a warm cache and 131 cold.

A turn that stops saying anything is now cut. Not a runaway thought
— the think budget is the only ceiling on how much a model may
reason, and that stays. This is the other failure: output carrying
no information at all. A 35B step ran to 31,416 tokens of "!" at 1.1
tokens a second, twenty minutes of it, because the only ceiling was
the token cap. Four hundred characters of one repeated character now
ends the step, the wreckage is kept out of the transcript rather
than handed back as a pattern to continue, and twice in a row pauses
instead of grinding. Separately, when the window tightens, the file
bodies inside earlier write_file calls are replaced by a line
naming the file — in one session four such turns were 82% of the
transcript, and the file is on disk if the model wants it back.

A PDF the text extractor cannot read no longer kills the read. The
extractor asserts, rather than errors, on font encodings it has not
implemented — the encoding most Chinese-authored PDFs use is one of
them. The whole document is still tried first, and where it gives
out the pages are read one at a time, keeping every page that parses
and saying how many it could not: one textbook went from nothing at
all to 38,295 characters. The same guard covers attachments, browser
downloads, and knowledge-base indexing, where one bad file used to
be able to end a whole run. A PDF with no text in it — a scan — now
says that, instead of coming back as an empty document.

Install

Platform File
Windows x64 Chaty_*_x64-setup.exe — per-user installer, no admin
macOS (Apple Silicon) Chaty_*_aarch64.dmg
Linux x64 (beta) Chaty_*_amd64.AppImagechmod +x and run. First Linux release — please report anything odd

⚠️ macOS first launch — "Apple could not verify…" / "damaged"

Chaty is ad-hoc signed but not notarized (no paid Apple Developer
account), so Gatekeeper flags it on first launch. The app is safe —
everything runs locally. Clear the download quarantine once, in Terminal:

xattr -dr com.apple.quarantine /Applications/Chaty.app

Then open Chaty normally. (Alternatively: try to open it once, then go to
System Settings → Privacy & Security → Open Anyway.)


What's Changed

  • voice: add reliable bilingual speech support by @wisetwo in #8

New Contributors

Full Changelog: v2.1.3...v2.1.4

Don't miss a new Chaty release

NewReleases is sending notifications on new releases.