Add dictation-locale transcription (incl. Russian), rework list capture UI
- TranscriptionSettings/Service route per-locale to SpeechTranscriber or DictationTranscriber (union of both supported sets, speech preferred); neutral-confidence ranking fallback keeps mixed-engine auto-pick working - NotesListView: text + voice capture buttons above the list (glassProminent), search moved to the iOS 26 toolbar search accessory (.minimize) - Changelog entries for languages, capture buttons, search placement
This commit is contained in:
@@ -20,6 +20,15 @@ struct LanguageCandidate: Equatable {
|
||||
/// side-effect-free is what makes the (undocumented, cross-locale) confidence
|
||||
/// calibration unit-testable.
|
||||
enum LanguagePicker {
|
||||
/// The confidence assigned to a transcript that carried text but no
|
||||
/// `transcriptionConfidence` attribute at all — the graceful-degradation case
|
||||
/// for `DictationTranscriber`, which need not emit per-run confidence. A
|
||||
/// mid-scale value so such a candidate is ranked by transcript length against
|
||||
/// its peers rather than being zeroed out and always losing to a confidence-
|
||||
/// reporting engine. Two confidence-less candidates then tie here and fall
|
||||
/// through to the length tie-break in `pick`.
|
||||
static let neutralConfidence = 0.5
|
||||
|
||||
/// Character-count-weighted mean confidence over an attributed transcript.
|
||||
/// Only runs that actually carry a `transcriptionConfidence` attribute
|
||||
/// contribute, weighted by their character length; a transcript with no
|
||||
@@ -37,6 +46,22 @@ enum LanguagePicker {
|
||||
return totalCharacters > 0 ? weighted / Double(totalCharacters) : 0
|
||||
}
|
||||
|
||||
/// Whether any run in the transcript carries a `transcriptionConfidence`
|
||||
/// attribute — i.e. whether `meanConfidence` measured anything real.
|
||||
static func hasConfidence(of attributed: AttributedString) -> Bool {
|
||||
attributed.runs.contains { $0.transcriptionConfidence != nil }
|
||||
}
|
||||
|
||||
/// The confidence used to *rank* a candidate. Prefers the real weighted mean;
|
||||
/// when the transcript has text but no confidence attribute anywhere (an engine
|
||||
/// that doesn't emit it), falls back to `neutralConfidence` so the candidate
|
||||
/// competes on length instead of being zeroed. An empty transcript scores 0 —
|
||||
/// it can never win against real text.
|
||||
static func rankingConfidence(of attributed: AttributedString) -> Double {
|
||||
if hasConfidence(of: attributed) { return meanConfidence(of: attributed) }
|
||||
return attributed.characters.isEmpty ? 0 : neutralConfidence
|
||||
}
|
||||
|
||||
/// The best candidate, or nil when given nothing. Argmax on `meanConfidence`;
|
||||
/// a zero-length transcript can only win if every candidate is empty. Ties
|
||||
/// break deterministically — higher confidence, then longer transcript, then
|
||||
|
||||
Reference in New Issue
Block a user