From 90dfe73f1a1b6815cfba08ec165394719005e4cf Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Sun, 07 Jun 2026 01:48:32 +0800
Subject: [PATCH] Fix X-ASR CJK spacing

---
 privatevoice.src/app.go                                            |    2 +-
 privatevoice.src/internal/textproc/textproc_test.go                |   27 +++++++++++++++++++++++++++
 CHANGELOG.md                                                       |    2 +-
 privatevoice.src/frontend/src/components/settings/AboutPage.svelte |    2 +-
 privatevoice.src/internal/textproc/textproc.go                     |   25 +++++++++++++++++++++++++
 privatevoice.src/build/darwin/Info.plist                           |    2 +-
 6 files changed, 56 insertions(+), 4 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 736069d..1a3f527 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,7 +11,7 @@
 
 ### 构建
 
-- build: `20260607.0141`
+- build: `20260607.0147`
 - 说明: 本版本为 X-ASR 技术实验候选包,不是 App Store 正式上传包。
 
 ---
diff --git a/privatevoice.src/app.go b/privatevoice.src/app.go
index 9e06899..d4e1ccd 100755
--- a/privatevoice.src/app.go
+++ b/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"
 
diff --git a/privatevoice.src/build/darwin/Info.plist b/privatevoice.src/build/darwin/Info.plist
index 14cae8f..4ea4a40 100755
--- a/privatevoice.src/build/darwin/Info.plist
+++ b/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>
diff --git a/privatevoice.src/frontend/src/components/settings/AboutPage.svelte b/privatevoice.src/frontend/src/components/settings/AboutPage.svelte
index 252385b..f541db4 100644
--- a/privatevoice.src/frontend/src/components/settings/AboutPage.svelte
+++ b/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' },
diff --git a/privatevoice.src/internal/textproc/textproc.go b/privatevoice.src/internal/textproc/textproc.go
index 44d9cdb..60683de 100755
--- a/privatevoice.src/internal/textproc/textproc.go
+++ b/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)
diff --git a/privatevoice.src/internal/textproc/textproc_test.go b/privatevoice.src/internal/textproc/textproc_test.go
new file mode 100644
index 0000000..aaa0be7
--- /dev/null
+++ b/privatevoice.src/internal/textproc/textproc_test.go
@@ -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)
+	}
+}

--
Gitblit v1.9.3