Ariver
2026-06-07 90dfe73f1a1b6815cfba08ec165394719005e4cf
Fix X-ASR CJK spacing
5 files modified
1 files added
60 ■■■■■ changed files
CHANGELOG.md 2 ●●● patch | view | raw | blame | history
privatevoice.src/app.go 2 ●●● patch | view | raw | blame | history
privatevoice.src/build/darwin/Info.plist 2 ●●● patch | view | raw | blame | history
privatevoice.src/frontend/src/components/settings/AboutPage.svelte 2 ●●● patch | view | raw | blame | history
privatevoice.src/internal/textproc/textproc.go 25 ●●●●● patch | view | raw | blame | history
privatevoice.src/internal/textproc/textproc_test.go 27 ●●●●● patch | view | raw | blame | history
CHANGELOG.md
@@ -11,7 +11,7 @@
### 构建
- build: `20260607.0141`
- build: `20260607.0147`
- 说明: 本版本为 X-ASR 技术实验候选包,不是 App Store 正式上传包。
---
privatevoice.src/app.go
@@ -28,7 +28,7 @@
const (
    appVersion        = "2.1.29"
    appBuild          = "20260607.0141"
    appBuild          = "20260607.0147"
    appDisplayVersion = appVersion + " (build " + appBuild + ")"
    appName           = "PrivateVoice Dictation"
privatevoice.src/build/darwin/Info.plist
@@ -19,7 +19,7 @@
    <key>CFBundleShortVersionString</key>
    <string>2.1.29</string>
    <key>CFBundleVersion</key>
    <string>20260607.0141</string>
    <string>20260607.0147</string>
    <key>LSApplicationCategoryType</key>
    <string>public.app-category.productivity</string>
    <key>ITSAppUsesNonExemptEncryption</key>
privatevoice.src/frontend/src/components/settings/AboutPage.svelte
@@ -3,7 +3,7 @@
  import { t } from '../../lib/i18n'
  import AppIcon from '../shared/AppIcon.svelte'
  let version = $state('2.1.29 (build 20260607.0141)')
  let version = $state('2.1.29 (build 20260607.0147)')
  const currentYear = new Date().getFullYear().toString()
  const aboutLinks = [
    { labelKey: 'about.sourceProjectLabel', urlKey: 'about.sourceUrl' },
privatevoice.src/internal/textproc/textproc.go
@@ -59,8 +59,31 @@
    return strings.TrimSpace(text)
}
func removeSpacesBetweenCJK(text string) string {
    runes := []rune(text)
    buf := make([]rune, 0, len(runes))
    for i := 0; i < len(runes); i++ {
        r := runes[i]
        if unicode.IsSpace(r) {
            j := i
            for j < len(runes) && unicode.IsSpace(runes[j]) {
                j++
            }
            if len(buf) > 0 && j < len(runes) && isCJK(buf[len(buf)-1]) && isCJK(runes[j]) {
                i = j - 1
                continue
            }
        }
        buf = append(buf, r)
    }
    return string(buf)
}
// PostProcess cleans up mixed Chinese-English text from SenseVoice:
//   - Strips special tokens (<|zh|>, <|NEUTRAL|>, etc.)
//   - Removes model-added spaces between CJK characters
//   - Inserts spaces between CJK characters and ASCII letters/digits
//   - Capitalizes the first letter and letters after sentence-ending punctuation
//   - Collapses multiple spaces
@@ -78,6 +101,8 @@
        return text
    }
    text = removeSpacesBetweenCJK(text)
    // Insert spaces at CJK ↔ ASCII alphanumeric boundaries
    runes := []rune(text)
    buf := make([]rune, 0, len(runes)+16)
privatevoice.src/internal/textproc/textproc_test.go
New file
@@ -0,0 +1,27 @@
package textproc
import "testing"
func TestPostProcessRemovesSpacesBetweenCJK(t *testing.T) {
    got := PostProcess("请 你 根 据 官 网")
    want := "请你根据官网"
    if got != want {
        t.Fatalf("PostProcess() = %q, want %q", got, want)
    }
}
func TestPostProcessKeepsSpaceBetweenCJKAndEnglish(t *testing.T) {
    got := PostProcess("请 你 open AI")
    want := "请你 open AI"
    if got != want {
        t.Fatalf("PostProcess() = %q, want %q", got, want)
    }
}
func TestPostProcessKeepsEnglishWordSpaces(t *testing.T) {
    got := PostProcess("open source speech recognition")
    want := "Open source speech recognition"
    if got != want {
        t.Fatalf("PostProcess() = %q, want %q", got, want)
    }
}