Skip to content

feat(macos): quick language switching per lane and session export (P2) - #18

Merged
PCcoding666 merged 10 commits into
masterfrom
integrate/p2
Oct 10, 2026
Merged

PCcoding666 merged 10 commits into
masterfrom
integrate/p2

Conversation

@PCcoding666

Copy link
Copy Markdown
Owner

Summary

P2: quick per-lane language switching (F9) and session export (F10).

F9 — language menu

  • The top-bar ZH → EN label is now a menu: System Audio language, Microphone language (default "Same as System Audio"), Translate To. Label shows SYS ZH · MIC EN → EN when the lanes differ.
  • Only languages the engine can recognize on-device are listed; ones that need a model download are marked (download).
  • While capturing, changing a lane's language restarts only that lane (SpeechRecognitionEngine.restartLane); the other lane keeps running. Changing the translation language restarts nothing. Settings / ⌘, language changes apply live too (no "restart needed" notice).
  • New setting microphoneSourceLanguage (nil = follow system audio), backward-compatible decoding.

F10 — export this session

  • SessionTranscript: an untrimmed record of the session (on-screen cards are trimmed to 5), begun at Start, kept after Stop, updated with final translations and ASR rollbacks.
  • SessionExporter: Markdown, plain text and SRT. SRT timing is estimated (end = finalize time, duration from text length, no overlap within a lane) because the pipeline has no utterance start times.
  • Export from the top-bar share button and File menu (⌘E = Markdown), through NSSavePanel; independent of the history setting. Logs record only line count and format.

Integration fixes (Claude)

  • Merge conflicts in TranscriptionVM; F9 engine methods added to the F10 test fake; export header shows per-lane languages; a Sendable capture warning in the export test.
  • The "hearing audio but recognizing nothing" warning is now retracted once that lane recognizes again (found in GUI testing).

Test results

  • ./Scripts/run_tests.sh: 504 tests, 0 failures, no new warnings. Tests use fake engines/stubs — no real recognition, downloads, permissions or network.
  • GUI (macOS 27, while capturing):
    • Menu showed the three groups with checkmarks and (download) markers. Microphone → English (US): label became SYS ZH · MIC EN → EN, log showed only the microphone lane restarted (0.33 s). A Chinese clip on the system lane and an English clip on the microphone lane were both recognized correctly.
    • Translate To → Japanese: no lane restart; the next Chinese line was translated into Japanese.
    • Export: Markdown / Text / SRT each exported all 22 lines of the session (header SYS ZH · MIC EN → JA, duration); the SRT parsed with sequential indices, valid timestamps and start < end for every cue.
  • Not exercised in GUI: choosing a (download) language (model download during a live switch); the legacy-engine path (macOS < 26).

Code by Qoder (Kimi-K3) from two parallel task briefs; integration, one UX fix, review and GUI verification by Claude.

🤖 Generated with Claude Code

PCcoding666 and others added 10 commits October 11, 2026 00:13
SessionTranscript is an untrimmed value-type record of finalized
segments and their translations, independent of the 5-card display
limit. SessionExporter renders it as Markdown, aligned plain text,
or SRT subtitles with per-lane non-overlapping cue timings estimated
from finalization offsets.
TranscriptionVM now begins a SessionTranscript on capture start,
appends finalized segments, writes back completed translations (even
after segments scroll off screen), drops rolled-back entries, and
exposes exportSession(_:) which renders the record and saves it via
NSSavePanel. The HUD gains a share menu next to History/Settings and
the File menu gains matching commands (Markdown bound to Cmd-E)
routed through a new .exportSession notification.
microphoneSourceLanguage (nil = follow the system-audio lane) plus
AppSettings.language(for:) give each capture lane its own effective
recognition language; older settings JSON decodes the missing key as nil.
SpeechRecognitionEngine gains restartLane(_:language:) and
languageAvailability(). The SpeechTranscriber engine tears down and
rebuilds only the affected lane (finalizing its in-flight utterance,
downloading the on-device model when needed) while per-lane generation
counters keep overlapping restarts and stop() from resurrecting stale
lanes; the legacy engine falls back to stop+start of its single lane.
RecognitionStallDetector can reset one lane so a new language gets a
fresh stall budget.
updateSettings no longer demands a stop/start for language changes:
each lane whose effective language changed restarts its own
recognition, the lane's uncommitted draft is kept as a caption (the
same flush semantics as a finished ASR task), and the translation
target applies to new translations without any restart. A capture
session id keeps a restart that outlives its session — e.g. during an
on-device model download — from touching the next session's lanes.
The HUD language label becomes a menu with System Audio, Microphone
(new engine only) and Translate To sections; languages the device
cannot recognize on-device are hidden and downloadable ones are
annotated. Settings mirrors this with a renamed System Audio Language
picker and a Microphone Language picker defaulting to Same as System
Audio.
A fake engine records lane restarts while view-model tests verify lane
routing (follow vs override, reset to follow, idle save-only,
not-running lanes skipped), the draft flush on a live switch, the
restart-free translation-target change, and that language edits drop
the needs-restart warning; pure tests cover the HUD label formats and
the language-availability mapping.
Resolve TranscriptionVM conflicts (keep language availability and session
transcript; begin the session and a new capture session id together), add
the F9 engine methods to the F10 test fake, export per-lane languages in
the session header, and fix a Sendable capture warning in the export test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gnizes again

Found in GUI testing: after switching the microphone lane to the right
language it recognized normally, but the warning stayed on screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 10, 2026 13:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@PCcoding666
PCcoding666 merged commit 4f7b9c3 into master Oct 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants