feat: merge split meeting continuations

This commit is contained in:
2026-08-26 10:09:21 +02:00
parent f6f518b0a9
commit 79b2f61dfe
6 changed files with 216 additions and 20 deletions
+45 -11
View File
@@ -133,17 +133,29 @@ final class AudioManager: NSObject, ObservableObject {
isProcessing = true
defer { isProcessing = false }
let model = UserDefaultsManager.shared.transcriptionModel
let micURL = recoveryFiles.first(where: { $0.source == .mic })?.url
let systemURL = recoveryFiles.first(where: { $0.source == .system })?.url
async let micResult = transcribe(micURL, model: model, diarization: false)
async let systemResult = transcribe(systemURL, model: model, diarization: true)
let (micTranscription, systemTranscription) = await (micResult, systemResult)
let results = [micTranscription, systemTranscription]
let (chunks, failures) = buildTranscriptChunks(
from: results,
captureStartedAt: captureStartedAt,
existingChunks: []
)
let sessions = Dictionary(grouping: recoveryFiles) { recoverySessionKey(for: $0.url) }
.values
.map { files in
(files: files, startedAt: recoveryCaptureStartedAt(for: files, fallback: captureStartedAt))
}
.sorted { $0.startedAt < $1.startedAt }
var chunks: [TranscriptChunk] = []
var failures: [String] = []
for session in sessions {
let micURL = session.files.first(where: { $0.source == .mic })?.url
let systemURL = session.files.first(where: { $0.source == .system })?.url
async let micResult = transcribe(micURL, model: model, diarization: false)
async let systemResult = transcribe(systemURL, model: model, diarization: true)
let (micTranscription, systemTranscription) = await (micResult, systemResult)
let result = buildTranscriptChunks(
from: [micTranscription, systemTranscription],
captureStartedAt: session.startedAt,
existingChunks: chunks
)
chunks = result.0
failures.append(contentsOf: result.1)
}
if !failures.isEmpty {
throw RecoveryTranscriptionError.requestFailed(failures.joined(separator: "; "))
@@ -154,6 +166,28 @@ final class AudioManager: NSObject, ObservableObject {
return chunks
}
private func recoverySessionKey(for url: URL) -> String {
let name = url.deletingPathExtension().lastPathComponent
if name.hasSuffix("-mic") { return String(name.dropLast(4)) }
if name.hasSuffix("-system") { return String(name.dropLast(7)) }
return name
}
private func recoveryCaptureStartedAt(
for files: [(url: URL, source: AudioSource)],
fallback: Date
) -> Date {
let estimatedStarts = files.compactMap { file -> Date? in
guard let duration = audioDuration(at: file.url),
let values = try? file.url.resourceValues(forKeys: [.contentModificationDateKey, .creationDateKey]),
let finishedAt = values.contentModificationDate ?? values.creationDate else {
return nil
}
return finishedAt.addingTimeInterval(-duration)
}
return estimatedStarts.min() ?? fallback
}
func cancelRecording() {
cancelCapture(removeFiles: true)
lastRecoveryAudioFolderName = nil