Transcribe and summarize audio
Turn a recording into timestamped text, typed notes, and optional speech.
Covers Examples/Features/13-SpeechAndTranscription.swift and
23-WorkflowGuides.swift. You end up with a reusable meeting pipeline that
accepts an audio file and returns validated Swift data.
Load and transcribe the recording
Pass the bytes and the real media type. Asynchronous providers such as
AssemblyAI, Rev.ai, and Gladia submit and poll internally, so the call site is
still one await.
let audio = try Data(contentsOf: recordingURL)
let transcript = try await transcribe(
model: OpenAITranscriptionModel("whisper-1"),
audio: audio,
mediaType: "audio/mpeg"
)
print(transcript.text)Use timestamps when available
Providers can return language, duration, and timed segments in addition to the full text:
for segment in transcript.segments {
print("\(segment.startSecond)sā\(segment.endSecond)s", segment.text)
}Some providers return only the complete transcript. Treat segments as an
optional enhancement rather than requiring it for the rest of the pipeline.
Define typed notes
Use structured output so downstream UI does not parse prose.
struct MeetingNotes: Codable, Sendable {
let title: String
let summary: String
let actionItems: [String]
}
let notesSchema: JSONValue = [
"type": "object",
"properties": [
"title": ["type": "string"],
"summary": ["type": "string"],
"actionItems": ["type": "array", "items": ["type": "string"]]
],
"required": ["title", "summary", "actionItems"],
"additionalProperties": false
]Summarize the transcript
let notes = try await generateObject(
model: OpenAIModel("gpt-5.6-sol"),
of: MeetingNotes.self,
schema: notesSchema,
schemaName: "meeting_notes",
prompt: "Summarize this transcript and extract action items:\n\n\(transcript.text)"
).objectLong recordings should be summarized in chunks and then reduced into one final summary instead of placing an unbounded transcript in one request.
Read the summary aloud
Speech generation is optional and uses the same provider-independent shape:
let speech = try await generateSpeech(
model: OpenAISpeechModel("gpt-4o-mini-tts"),
text: notes.summary,
voice: "alloy",
outputFormat: "mp3"
)
try speech.audio.write(to: summaryAudioURL)Final code
import AI
import Foundation
struct MeetingNotes: Codable, Sendable {
let title: String
let summary: String
let actionItems: [String]
}
let notesSchema: JSONValue = [
"type": "object",
"properties": [
"title": ["type": "string"],
"summary": ["type": "string"],
"actionItems": ["type": "array", "items": ["type": "string"]]
],
"required": ["title", "summary", "actionItems"],
"additionalProperties": false
]
func makeMeetingNotes(from recordingURL: URL) async throws -> MeetingNotes {
let transcript = try await transcribe(
model: OpenAITranscriptionModel("whisper-1"),
audio: Data(contentsOf: recordingURL),
mediaType: "audio/mpeg"
)
return try await generateObject(
model: OpenAIModel("gpt-5.6-sol"),
of: MeetingNotes.self,
schema: notesSchema,
schemaName: "meeting_notes",
prompt: "Summarize this transcript and extract action items:\n\n\(transcript.text)"
).object
}See Transcription and Speech generation for provider and model choices.