Files
Lu Fan(SonnyCalcr) 1b875267db refactor: 移除 WebView2,界面只保留 Direct2D (#1013)
* refactor(engine): 语音独立工具改用原生托盘菜单,移除 WebView2

托盘菜单改用 Win32 弹出菜单,设置项改为用关联编辑器打开 config.toml,关于页改为消息框。删除 window_webview2 与两份 HTML 资源,windows-app 特性不再依赖 webview2 端口。

* refactor(server): 移除 WebView2,候选窗、工具栏、托盘菜单与设置窗口只保留 Direct2D

删除 src/webview2 与 webview_utils,小窗口的置顶、皮肤重载和工具栏状态缓存移到 window/small_windows,presenter 成为唯一路径,D2D 下的置顶时序与 cloak 行为保持不变。设置进程去掉 WebView2 宿主、鼠标转发与启动图,只构建原生窗口;旧快捷方式传入的 --d2d / --webview2 被忽略。删除 appearance.ui_backend 与 appearance.settings_ui_backend(读取、写入、设置页下拉框与两份配置模板),升级时由模板合并丢弃旧值。设置窗口的图片资源移到 server/assets/settings,安装到数据目录的 assets\settings。不再链接 WebView2Loader,vcpkg 去掉 webview2 端口。

* build(installer): 打包与 CI 不再处理 WebView2 页面和运行时

Prepare-PackageFiles 去掉 -UiHtmlDirectory 与 html 暂存,改为暂存 server/assets/settings;安装器不再检查 WebView2 Runtime、不再创建 ProgramData 下的 WebView2 用户数据目录,升级和卸载时清理旧版留下的 webview2 / webview2-settings 与数据目录里的 html。CI 删除设置页构建、契约同步检查和候选窗 DOM 测试,release 的打包任务不再依赖网页产物;dependabot 去掉 npm。第三方声明去掉 WebView2Loader。

* refactor(ui-html): 删除 WebView2 页面与设置页前端工程

候选窗、工具栏、托盘菜单、设置页、主题和契约副本都已没有使用者;设置窗口用到的图片资源已移到 server/assets/settings。sync-contracts.py 与 pnpm/Vite/TypeScript 工程一并删除,契约仍以 engine/contracts/webview 为唯一来源。

* docs(server): 文档改为只描述 Direct2D 界面

仓库地图去掉 ui-html,组件边界、uiAccess 与置顶时序、设置窗口和配置读写的说明改写为 Direct2D 唯一界面;安装说明去掉 WebView2 Runtime 检查,打包命令去掉 -UiHtmlDirectory;engine/contracts/webview 的说明改为设置窗口是唯一使用者,名字是历史遗留。

* docs(skins): 皮肤说明不再区分 WebView2 与 D2D 渲染器

v2 字段去掉「仅 WebView2」,改为说明由 Direct2D 原生渲染、部分字段仍在补全;颜色必须带 # 改为清单格式约定。随包的 skins/niya-demo/skin.toml 不改,免得用户机器上的同名皮肤在升级时被当成已修改而改名备份。

* docs(ui): demo 说明文字不再提 WebView2
2026-10-17 02:48:02 +08:00
..

Shared VoiceInput(水杉公共语音模块)

VoiceInput is part of the engine. A host links this C++17 library without linking the keyboard engine or copying recognition code.

Target Responsibility Dependencies
MetasequoiaIme::Voice Mono PCM/WAV, RMS voice segmentation, configurable HTTP transcription and optional text cleanup libcurl, nlohmann-json
MetasequoiaIme::VoiceCapture Per-instance microphone capture, converted to mono 16 kHz float PCM vendored miniaudio

Local Whisper recognition (MetasequoiaIme::VoiceWhisper) was removed when the engine was vendored into this repository; this product transcribes through a cloud provider. See UPSTREAM.md.

UI, microphone permissions, hotkeys, token storage and committing text belong to the host. The library returns UTF-8 text and does not simulate keys. Root engine builds have METASEQUOIA_IME_BUILD_VOICE=OFF by default. For a root vcpkg build with voice enabled, add VCPKG_MANIFEST_FEATURES=voice. Voice can also be built independently, so a host that only needs speech does not acquire Boost, SQLite or dictionary dependencies.

Build

miniaudio is vendored in-tree at voice/third_party/miniaudio, so a plain checkout is enough. From engine/, Windows uses the manifest in voice/vcpkg.json. Select the same MSVC runtime as the dependency triplet; the static triplet below requires /MT (and /MTd for Debug). When embedding Voice in a root/host build, set this at the host level so all linked C++ targets agree:

cmake -S voice -B build-voice -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" -DVCPKG_TARGET_TRIPLET=x64-windows-static '-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded$<$<CONFIG:Debug>:Debug>'
cmake --build build-voice --config Release --parallel
ctest --test-dir build-voice -C Release --output-on-failure

Set MSIME_VOICE_CAPTURE=OFF if the host already supplies PCM. The library downloads no models. Imported Silero/ONNX code is built only by the standalone Windows host below, outside the supported public targets; the supported VAD here is RMS-based.

Call from a host

# After adding the engine with METASEQUOIA_IME_BUILD_VOICE=ON, or independently:
add_subdirectory(engine/voice voice)
target_link_libraries(MyHost PRIVATE MetasequoiaIme::Voice MetasequoiaIme::VoiceCapture)
#include <msime/voice/cloud_stt_worker.h>
using namespace metasequoia::voice;
RequestOptions options{endpoint, model, token, 10000, cancellationFlag};
CloudSttWorker recognizer(options);
std::string text = recognizer.recognize(pcm); // worker queue, mono 16 kHz floats
// Host dispatches text to its UI/input-method thread and commits it.

CloudSttWorker supports multipart file + model with JSON text, transcription or result.text responses. This is a protocol adapter, not a claim that every provider supports that protocol. Endpoints/models are host configuration; the token-only constructor retains the old SiliconFlow defaults for the imported Windows host. The WebSocket/Doubao transport lives in server/; the codecs here support a host that keeps its own transport.

Streaming scope

Streaming recognition is implemented by server/, not here. This API intentionally provides bounded, one-shot HTTP recognition; it exposes no streaming transport and no partial-text commit semantics. Do not reach for it expecting the server's incremental transcription behaviour — moving streaming down into this library would be an API and frontend change, not a provider swap.

provider_protocol.h exposes the same multipart and JSON codecs to hosts with an existing HTTP transport. make_transcription_request takes an encoded WAV (up to 20 MiB), preserves binary bytes and accepts an optional language field; omit language for services that reject it. make_polish_request sends the supplied user message verbatim, so hosts retain their prompt/delimiter policy. Response parsers reject malformed, missing, empty or oversized text responses with VoiceError. Hosts retain endpoint validation, credentials, timeouts, cancellation, status checks and stricter upload/response limits. The PCM recognizer still enforces the 60-second contract below.

Each request has a timeout and optional shared atomic cancellation flag. Set that flag to abort an in-flight request; a cancelled flag stays cancelled until the host supplies a new one. Recognition errors throw VoiceError. TextPolisher returns the original text on failure, timeout, cancellation or an empty result. It never logs tokens, audio or response bodies. Redirects are rejected, HTTP status is checked and responses are capped at 1 MiB.

Input PCM must be finite mono 16 kHz float samples, at most 60 seconds per request. WAV encoding clips samples to [-1,1]. WavWriter::create_wav accepts an explicit sample limit for hosts with a different bounded upload duration, such as Windows clips with provider padding; omitting it retains the 60-second limit. RIFF size overflow is always rejected. Hosts serialize capture start/stop/destruction, keep callback work short, and never stop or destroy capture from its callback. stop() is idempotent and waits for callbacks. A callback exception is contained and reported by callback_failed(). VAD callers drain take_audio() when appropriate; oversized unconsumed blocks throw rather than growing without limit.

Portability

The sources still carry the if(APPLE) branches and Objective-C++ entry points from when this was a cross-platform library. They are kept rather than stripped: they are working code, they cost nothing in a Windows build, and rewriting them out would be a large untested change. The macOS example host that exercised them was removed — see UPSTREAM.md — so treat those branches as unverified here.

Imported Windows host

The original standalone UI and hotkeys remain under platforms/windows/. Build it with MSIME_VOICE_WINDOWS_APP=ON and VCPKG_MANIFEST_FEATURES=windows-app. It links the shared targets and is off by default; the shipped product's voice input is server/, not this. See the imported usage guide for the asset/config layout.

Common capture, WAV and provider codecs belong here; server/ keeps its evolved provider transport, native interaction and streaming behaviour.

Original VoiceInput history and GPL-3.0 LICENSE are preserved; third-party libraries retain their own licenses. Import source: 413f734e1d4694748d3cf88b8df95f37528e8a97 in metasequoiaime/MetasequoiaVoiceInput.