Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version: 5.10
// swift-tools-version: 5.9

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

swift-tools-version downgrade 5.10 → 5.9 is unexplained — presumably to support an older Xcode. Worth confirming this is intentional and noting why.


import PackageDescription

Expand All @@ -22,6 +22,9 @@ let package = Package(
resources: [
.copy("Resources/AppIcon/AppIcon-512.png"),
.copy("Resources/silero_vad.onnx"),
],
swiftSettings: [
.define("SUPPORTS_SPEECH_TRANSCRIBER"),

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

SUPPORTS_SPEECH_TRANSCRIBER is defined unconditionally, so the #else (macOS 15 SDK) branches are dead code in the default build and never compiled or tested — you still need the macOS 26 SDK to compile; the deployment-target lowering only helps at runtime. That's a fine design (the flag is meant to be toggled off when building on an older toolchain), but please add a comment here explaining when to disable it, since no CI build exercises the #if !SUPPORTS_SPEECH_TRANSCRIBER path.

]
),
.testTarget(
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ v2s will ask for permissions on first use:

## Requirements

- Speech transcription and translation require macOS 26 or newer
- **Basic speech transcription**: macOS 15 (Sequoia) or newer
- **Full features (SpeechTranscriber / AI Summarization)**: macOS 26 or newer

## Building from Source

Expand Down
3 changes: 2 additions & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ v2s 的输入语言列表仅包含 Apple SpeechAnalyzer/SpeechTranscriber 路径

## 环境要求

- 语音转写和翻译功能需要 macOS 26 或更高版本
- **基础功能(语音转写)**:macOS 15 (Sequoia) 或更高版本
- **完整功能(SpeechTranscriber / AI 摘要)**:macOS 26 或更高版本

## 从源码构建

Expand Down
8 changes: 7 additions & 1 deletion Sources/V2SApp/App/AppModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -899,7 +899,10 @@ final class AppModel: ObservableObject {
private func prepareSpeechRecognitionResourceIfNeeded(
for languageID: String
) async -> LanguageResourceSystemSettingsDestination? {
guard #available(macOS 26.0, *) else {
#if !SUPPORTS_SPEECH_TRANSCRIBER
return nil
#else
guard #available(macOS 26.0, *), SpeechTranscriber.isAvailable else {
return nil
}

Expand Down Expand Up @@ -946,8 +949,10 @@ final class AppModel: ObservableObject {
}

return nil
#endif
}

#if SUPPORTS_SPEECH_TRANSCRIBER
@available(macOS 26.0, *)
private func ensureSpeechAssetsReady(
for modules: [any SpeechModule],
Expand Down Expand Up @@ -1065,6 +1070,7 @@ final class AppModel: ObservableObject {

try await request.downloadAndInstall()
}
#endif

private func prepareTranslationResourceIfNeeded(
from sourceLanguageID: String,
Expand Down
2 changes: 1 addition & 1 deletion Sources/V2SApp/Models/AppSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ struct AppSettings: Codable {
outputLanguageID: "zh-Hans",
interfaceLanguageID: nil,
overlayStyle: .default,
subtitleMode: .balanced,
subtitleMode: .follow,
subtitleDisplayMode: .both,
glossary: [:]
)
Expand Down
10 changes: 10 additions & 0 deletions Sources/V2SApp/Models/InputSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ import Foundation
enum InputSourceCategory: String, CaseIterable, Codable {
case application
case microphone
case systemAudio

func displayName(in languageID: String) -> String {
switch self {
case .application:
return AppLocalization.string(.application, languageID: languageID)
case .microphone:
return AppLocalization.string(.microphone, languageID: languageID)
case .systemAudio:
return "System Audio"

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Hardcoded English string bypasses AppLocalization — every other source uses AppLocalization.string(...). Same for InputSource.systemAudio's name/detail below. The zh-CN UI will show English here.

}
}
}
Expand All @@ -20,6 +23,13 @@ struct InputSource: Identifiable, Hashable, Codable {
let detail: String
let category: InputSourceCategory

static let systemAudio = InputSource(
id: "system:audio",
name: "System Audio",
detail: "system-audio",
category: .systemAudio
)

static let preview = InputSource(
id: "preview",
name: AppLocalization.string(.previewSource, languageID: "en"),
Expand Down
18 changes: 9 additions & 9 deletions Sources/V2SApp/Models/ModeConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,19 +75,19 @@ struct ModeConfig: Sendable {
let minSilenceCommitMs: Int

static let balanced = ModeConfig(
firstTokenTargetMs: 300,
commitSourceTargetMs: 600,
commitTranslationTargetMs: 900,
firstTokenTargetMs: 250,
commitSourceTargetMs: 500,
commitTranslationTargetMs: 750,
maxChunkAudioSec: 3.0,
minSilenceCommitMs: 280
minSilenceCommitMs: 200
)

static let follow = ModeConfig(

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

These timing retunes (plus the default mode change balanced → follow in AppSettings) are a behavior change for all users, unrelated to the deployment-target goal of this PR. Recommend splitting into a separate PR with rationale/validation — the commit message asserts the new numbers but there's no evidence they were tested.

firstTokenTargetMs: 200,
commitSourceTargetMs: 450,
commitTranslationTargetMs: 700,
maxChunkAudioSec: 2.2,
minSilenceCommitMs: 220
firstTokenTargetMs: 150,
commitSourceTargetMs: 350,
commitTranslationTargetMs: 500,
maxChunkAudioSec: 1.8,
minSilenceCommitMs: 150
)

static let reading = ModeConfig(
Expand Down
Loading