1diff --git a/ios/transcription/AppleTranscriptionImpl.swift b/ios/transcription/AppleTranscriptionImpl.swift
2index 188371a5f55fadae19187108c4a688569d0223e3..3e1cdd77b0bb8ae6c97a40d29c1854200d931eee 100644
3--- a/ios/transcription/AppleTranscriptionImpl.swift
4+++ b/ios/transcription/AppleTranscriptionImpl.swift
5@@ -12,6 +12,11 @@ import UniformTypeIdentifiers
6
7 @objc
8 public class AppleTranscriptionImpl: NSObject {
9+ private struct CollectedSegment: Sendable {
10+ let text: String
11+ let startSecond: Double
12+ let endSecond: Double
13+ }
14
15 @available(iOS 26, *)
16 private func createTranscriber(for locale: Locale) -> SpeechTranscriber {
17@@ -41,7 +46,7 @@ public class AppleTranscriptionImpl: NSObject {
18 let locale = Locale(identifier: language)
19
20 guard let supportedLocale = await SpeechTranscriber.supportedLocale(equivalentTo: locale) else {
21- reject("AppleTranscription", "Locale not supported: \(language)", nil)
22+ reject("AppleTranscriptionUnsupportedLocale", "Locale not supported: \(language)", nil)
23 return
24 }
25
26@@ -51,16 +56,14 @@ public class AppleTranscriptionImpl: NSObject {
27
28 switch status {
29 case .installed:
30- resolve(nil)
31+ resolve(supportedLocale.identifier)
32 case .supported, .downloading:
33- if let request = try? await AssetInventory.assetInstallationRequest(supporting: [transcriber]) {
34+ if let request = try await AssetInventory.assetInstallationRequest(supporting: [transcriber]) {
35 try await request.downloadAndInstall()
36- resolve(nil)
37- } else {
38- resolve(nil)
39 }
40+ resolve(supportedLocale.identifier)
41 case .unsupported:
42- reject("AppleTranscription", "Assets not supported for locale: \(supportedLocale.identifier)", nil)
43+ reject("AppleTranscriptionUnsupportedLocale", "Assets not supported for locale: \(supportedLocale.identifier)", nil)
44 @unknown default:
45 reject ("AppleTranscription", "Unknown asset inventory status", nil)
46 }
47@@ -83,57 +86,77 @@ public class AppleTranscriptionImpl: NSObject {
48 do {
49 try audioData.write(to: fileURL)
50
51- guard let audioFile = try? AVAudioFile(forReading: fileURL) else {
52- reject("AppleTranscription", "Invalid audio data", nil)
53+ let audioFile: AVAudioFile
54+ do {
55+ audioFile = try AVAudioFile(forReading: fileURL)
56+ } catch {
57+ try? FileManager.default.removeItem(at: fileURL)
58+ reject("AppleTranscription", "Invalid audio data", error)
59 return
60 }
61
62 Task {
63+ defer {
64+ try? FileManager.default.removeItem(at: fileURL)
65+ }
66+
67 do {
68 let transcriber = createTranscriber(for: Locale(identifier: language))
69
70 let analyzer = SpeechAnalyzer(modules: [transcriber])
71-
72- defer {
73- try? FileManager.default.removeItem(at: fileURL)
74- }
75-
76- var segments: [[String: Any]] = []
77-
78- Task {
79+
80+ let collectorTask = Task { () throws -> [CollectedSegment] in
81+ var segments: [CollectedSegment] = []
82+
83 for try await result in transcriber.results {
84 if result.isFinal {
85- let segment: [String: Any] = [
86- "text": String(result.text.characters),
87- "startSecond": CMTimeGetSeconds(result.range.start),
88- "endSecond": CMTimeGetSeconds(CMTimeRangeGetEnd(result.range))
89- ]
90- segments.append(segment)
91+ segments.append(
92+ CollectedSegment(
93+ text: String(result.text.characters),
94+ startSecond: CMTimeGetSeconds(result.range.start),
95+ endSecond: CMTimeGetSeconds(CMTimeRangeGetEnd(result.range))
96+ )
97+ )
98 }
99 }
100+
101+ return segments
102 }
103-
104- let lastSampleTime = try await analyzer.analyzeSequence(from: audioFile)
105-
106- if let lastSampleTime {
107- try await analyzer.finalizeAndFinish(through: lastSampleTime)
108- } else {
109+
110+ do {
111+ let lastSampleTime = try await analyzer.analyzeSequence(from: audioFile)
112+
113+ if let lastSampleTime {
114+ try await analyzer.finalizeAndFinish(through: lastSampleTime)
115+ } else {
116+ await analyzer.cancelAndFinishNow()
117+ }
118+
119+ let segments: [[String: Any]] = try await collectorTask.value.map { segment in
120+ [
121+ "text": segment.text,
122+ "startSecond": segment.startSecond,
123+ "endSecond": segment.endSecond
124+ ]
125+ }
126+ let totalDuration = if let lastSampleTime { CMTimeGetSeconds(lastSampleTime) } else { 0.0 }
127+
128+ resolve([
129+ "segments": segments,
130+ "duration": totalDuration
131+ ])
132+ } catch {
133+ collectorTask.cancel()
134 await analyzer.cancelAndFinishNow()
135+ _ = try? await collectorTask.value
136+ throw error
137 }
138-
139- let totalDuration = if let lastSampleTime { CMTimeGetSeconds(lastSampleTime) } else { 0.0 }
140-
141- let result: [String: Any] = [
142- "segments": segments,
143- "duration": totalDuration
144- ]
145-
146- resolve(result)
147 } catch {
148 reject("AppleTranscription", "Transcription failed: \(error.localizedDescription)", error)
149 }
150 }
151 } catch {
152+ try? FileManager.default.removeItem(at: fileURL)
153 reject("AppleTranscription", "Failed to write audio data: \(error.localizedDescription)", error)
154 }
155 } else {
156@@ -141,4 +164,3 @@ public class AppleTranscriptionImpl: NSObject {
157 }
158 }
159 }
160-
161diff --git a/lib/typescript/NativeAppleTranscription.d.ts b/lib/typescript/NativeAppleTranscription.d.ts
162index 985b6b3593a884c41d689346be9d73d86c55eae1..86e7936f23a8673d099f7fe18af9a31abae5a13a 100644
163--- a/lib/typescript/NativeAppleTranscription.d.ts
164+++ b/lib/typescript/NativeAppleTranscription.d.ts
165@@ -10,14 +10,14 @@ export interface TranscriptionResult {
166 }
167 export interface Spec extends TurboModule {
168 isAvailable(language: string): boolean;
169- prepare(language: string): Promise<void>;
170+ prepare(language: string): Promise<string>;
171 }
172 declare global {
173 function __apple__llm__transcribe__(data: ArrayBufferLike, language: string): Promise<TranscriptionResult>;
174 }
175 declare const _default: {
176 transcribe: (data: ArrayBufferLike, language: string) => Promise<TranscriptionResult>;
177- prepare: (language: string) => Promise<void>;
178+ prepare: (language: string) => Promise<string>;
179 isAvailable: (language: string) => boolean;
180 };
181 export default _default;
182diff --git a/src/NativeAppleTranscription.ts b/src/NativeAppleTranscription.ts
183index 13332a0176000b60b6f6f043de681db55a7b4bef..5389fb4b3a53de48721c307d2145b6770624c852 100644
184--- a/src/NativeAppleTranscription.ts
185+++ b/src/NativeAppleTranscription.ts
186@@ -14,7 +14,7 @@ export interface TranscriptionResult {
187
188 export interface Spec extends TurboModule {
189 isAvailable(language: string): boolean
190- prepare(language: string): Promise<void>
191+ prepare(language: string): Promise<string>
192 }
193
194 declare global {