From e6f67be337913ad92d41480ad0ede8f4e58de679 Mon Sep 17 00:00:00 2001 From: Melorise <0d00@0721.hk> Date: Wed, 26 Aug 2026 20:36:16 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E7=BC=93=E5=AD=98=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E5=99=A8=E5=B9=B6=E5=8F=91=E5=B8=83=200.1.14?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AI-assisted-by: Codex AI-model: gpt-5.6-sol AI-reasoning-effort: medium Co-authored-by: Codex --- AGENTS.md | 2 +- CHANGELOG.md | 7 +++++++ CLAUDE.md | 2 +- linux/fcitx5/CMakeLists.txt | 2 +- linux/fcitx5/meloasr.conf.in | 2 +- package-lock.json | 4 ++-- package.json | 2 +- packaging/README.md | 4 ++-- packaging/arch/PKGBUILD | 2 +- packaging/arch/README.md | 2 +- packaging/assets/meloasr.metainfo.xml | 1 + packaging/deb/build-deb.sh | 2 +- packaging/rpm/build-rpm.sh | 2 +- packaging/rpm/meloasr-binary.spec | 3 +++ src/preload/backend.ts | 17 ++++++++++------- 15 files changed, 34 insertions(+), 20 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 987d3d4..8439a64 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ ## 项目范围 -MeloASR 是仅面向 Linux 的 Fcitx5 桌面语音输入工具。项目名为 `MeloASR`,分发包名为 `meloasr`,当前版本为 `0.1.13`。 +MeloASR 是仅面向 Linux 的 Fcitx5 桌面语音输入工具。项目名为 `MeloASR`,分发包名为 `meloasr`,当前版本为 `0.1.14`。 不得恢复 Windows、PowerShell 或 Tauri 输出路径。发行版差异只能存在于依赖说明和打包配置,不能进入语音输入核心逻辑。 diff --git a/CHANGELOG.md b/CHANGELOG.md index 43a4deb..4ea29b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ 本项目遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 的格式。 +## [0.1.14] - 2026-08-26 + +### 性能 + +- 语音会话开始时缓存网页编辑器根元素,后续文本更新直接序列化该元素,避免每次更新重复查询 DOM、计算样式和读取布局。 +- 复用会话启动时的初始文本序列化结果,减少一次重复的完整编辑器遍历。 + ## [0.1.13] - 2026-08-24 ### 变更 diff --git a/CLAUDE.md b/CLAUDE.md index 987d3d4..8439a64 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,7 +2,7 @@ ## 项目范围 -MeloASR 是仅面向 Linux 的 Fcitx5 桌面语音输入工具。项目名为 `MeloASR`,分发包名为 `meloasr`,当前版本为 `0.1.13`。 +MeloASR 是仅面向 Linux 的 Fcitx5 桌面语音输入工具。项目名为 `MeloASR`,分发包名为 `meloasr`,当前版本为 `0.1.14`。 不得恢复 Windows、PowerShell 或 Tauri 输出路径。发行版差异只能存在于依赖说明和打包配置,不能进入语音输入核心逻辑。 diff --git a/linux/fcitx5/CMakeLists.txt b/linux/fcitx5/CMakeLists.txt index 4274dc4..16f10c5 100644 --- a/linux/fcitx5/CMakeLists.txt +++ b/linux/fcitx5/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -project(meloasr-fcitx5 VERSION 0.1.13 LANGUAGES CXX) +project(meloasr-fcitx5 VERSION 0.1.14 LANGUAGES CXX) include(GNUInstallDirs) include(CTest) diff --git a/linux/fcitx5/meloasr.conf.in b/linux/fcitx5/meloasr.conf.in index fffb191..011a574 100644 --- a/linux/fcitx5/meloasr.conf.in +++ b/linux/fcitx5/meloasr.conf.in @@ -6,7 +6,7 @@ Comment[zh_CN]=将 MeloASR 网页后端连接到当前输入上下文 Type=SharedLibrary Library=@MELOASR_LIBRARY_PATH@ Category=Module -Version=0.1.13 +Version=0.1.14 OnDemand=False Configurable=False diff --git a/package-lock.json b/package-lock.json index 48e6803..d32f2d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "meloasr", - "version": "0.1.13", + "version": "0.1.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "meloasr", - "version": "0.1.13", + "version": "0.1.14", "devDependencies": { "@types/node": "^24.0.0", "electron": "42.3.0", diff --git a/package.json b/package.json index 4fd368b..6667685 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "meloasr", "productName": "MeloASR", - "version": "0.1.13", + "version": "0.1.14", "private": true, "author": "MeloASR contributors", "description": "基于网页语音识别后端和 Fcitx5 的 Linux 实时语音输入工具", diff --git a/packaging/README.md b/packaging/README.md index 3851d04..217103a 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -1,6 +1,6 @@ # Linux 分发打包 -MeloASR 0.1.13 的系统包由两部分组成: +MeloASR 0.1.14 的系统包由两部分组成: - Electron 应用安装到 `/opt/meloasr`,命令入口为 `/usr/bin/meloasr`; - Fcitx5 常驻 addon 由目标发行版中的 CMake/Fcitx5 开发包编译,并安装到该环境报告的 addon 目录。 @@ -40,7 +40,7 @@ npm run build:linux:dir packaging/deb/build-deb.sh ``` -产物位于 `packaging/out/meloasr_0.1.13_.deb`。依赖名称按 Debian/Ubuntu 系列填写,但尚未在各发行版完成安装验证。 +产物位于 `packaging/out/meloasr_0.1.14_.deb`。依赖名称按 Debian/Ubuntu 系列填写,但尚未在各发行版完成安装验证。 ## rpm diff --git a/packaging/arch/PKGBUILD b/packaging/arch/PKGBUILD index c07b91e..2c2053a 100644 --- a/packaging/arch/PKGBUILD +++ b/packaging/arch/PKGBUILD @@ -1,5 +1,5 @@ pkgname=meloasr -pkgver=0.1.13 +pkgver=0.1.14 pkgrel=1 pkgdesc='Web-backed voice input for Fcitx5' arch=('x86_64') diff --git a/packaging/arch/README.md b/packaging/arch/README.md index 6e7579d..6634116 100644 --- a/packaging/arch/README.md +++ b/packaging/arch/README.md @@ -1,6 +1,6 @@ # Arch Linux 构建 -发布时把项目源码归档为 `meloasr-0.1.13.tar.gz`,与 `PKGBUILD` 放在同一目录,随后运行: +发布时把项目源码归档为 `meloasr-0.1.14.tar.gz`,与 `PKGBUILD` 放在同一目录,随后运行: ```bash makepkg --syncdeps --cleanbuild diff --git a/packaging/assets/meloasr.metainfo.xml b/packaging/assets/meloasr.metainfo.xml index 6abf1e3..9d08b82 100644 --- a/packaging/assets/meloasr.metainfo.xml +++ b/packaging/assets/meloasr.metainfo.xml @@ -16,6 +16,7 @@ meloasr + diff --git a/packaging/deb/build-deb.sh b/packaging/deb/build-deb.sh index 2104903..9133752 100755 --- a/packaging/deb/build-deb.sh +++ b/packaging/deb/build-deb.sh @@ -2,7 +2,7 @@ set -euo pipefail project_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)" -version="${MELOASR_VERSION:-0.1.13}" +version="${MELOASR_VERSION:-0.1.14}" arch="${MELOASR_DEB_ARCH:-$(dpkg --print-architecture)}" app_dir="${1:-${MELOASR_ELECTRON_APP_DIR:-${project_dir}/release/linux-unpacked}}" work_dir="${project_dir}/packaging/out/deb-root" diff --git a/packaging/rpm/build-rpm.sh b/packaging/rpm/build-rpm.sh index 25cdcf4..792f1d1 100755 --- a/packaging/rpm/build-rpm.sh +++ b/packaging/rpm/build-rpm.sh @@ -2,7 +2,7 @@ set -euo pipefail project_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)" -version="${MELOASR_VERSION:-0.1.13}" +version="${MELOASR_VERSION:-0.1.14}" app_dir="${1:-${MELOASR_ELECTRON_APP_DIR:-${project_dir}/release/linux-unpacked}}" stage_dir="${project_dir}/packaging/out/rpm-root" top_dir="${project_dir}/packaging/out/rpmbuild" diff --git a/packaging/rpm/meloasr-binary.spec b/packaging/rpm/meloasr-binary.spec index aa7d41c..a85b085 100644 --- a/packaging/rpm/meloasr-binary.spec +++ b/packaging/rpm/meloasr-binary.spec @@ -36,6 +36,9 @@ tar -C %{buildroot} -xzf %{SOURCE0} /etc/xdg/autostart/meloasr.desktop %changelog +* Wed Aug 26 2026 MeloASR contributors - 0.1.14-1 +- Cache the active web editor for the duration of each speech session. + * Mon Aug 24 2026 MeloASR contributors - 0.1.13-1 - Create the settings renderer only when it is opened and destroy it on close. diff --git a/src/preload/backend.ts b/src/preload/backend.ts index 78d7490..d002ea2 100644 --- a/src/preload/backend.ts +++ b/src/preload/backend.ts @@ -11,6 +11,7 @@ const adapter = getBackendWebAdapter(backendId); let editorObserver: MutationObserver | undefined; let pageObserver: MutationObserver | undefined; +let activeEditor: HTMLElement | null = null; let active = false; let stopping = false; let lastSpeechText = ''; @@ -68,12 +69,11 @@ function schedulePageStatus(): void { function emitCurrentEditorText(): void { emitScheduled = false; if (!active || !adapter) return; - const editor = adapter.findEditor(document); - if (!editor) { + if (!activeEditor?.isConnected) { fail(`${adapter.definition.label}输入框在录音期间消失,本轮已停止`); return; } - const text = adapter.serialize(editor); + const text = adapter.serialize(activeEditor); if (text === lastSpeechText) return; lastSpeechText = text; transcriptRevision += 1; @@ -119,6 +119,7 @@ function resetSession(): void { stopping = false; lastTranscriptAt = 0; editorObserver?.disconnect(); + activeEditor = null; diagnose('session-reset'); } @@ -147,28 +148,30 @@ function startSpeech(): void { return; } + const initialText = adapter.serialize(editor); diagnose('start-targets', { - editorLength: adapter.serialize(editor).length, + editorLength: initialText.length, microphone: controlSnapshot(microphone) }); clearTimeout(stopTimer); placeCaretAtEnd(editor); - lastSpeechText = adapter.serialize(editor); + lastSpeechText = initialText; transcriptRevision = 0; lastTranscriptAt = Date.now(); active = true; stopping = false; + activeEditor = editor; observeEditor(editor); microphone.click(); diagnose('start-clicked', { microphone: controlSnapshot(adapter.findMicrophone(document)) }); window.setTimeout(() => diagnose('start-after-250ms', { microphone: controlSnapshot(adapter.findMicrophone(document)), - editorLength: adapter.findEditor(document) ? adapter.serialize(adapter.findEditor(document)!).length : null + editorLength: active && editor.isConnected ? adapter.serialize(editor).length : null }), 250); window.setTimeout(() => diagnose('start-after-1000ms', { microphone: controlSnapshot(adapter.findMicrophone(document)), - editorLength: adapter.findEditor(document) ? adapter.serialize(adapter.findEditor(document)!).length : null + editorLength: active && editor.isConnected ? adapter.serialize(editor).length : null }), 1_000); }