Skip to content

Commit 69fd8ee

Browse files
committed
Add Speech to text support
1 parent 63806c9 commit 69fd8ee

File tree

16 files changed

+666
-16
lines changed

16 files changed

+666
-16
lines changed

Package.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ let package = Package(
3434
resources: [
3535
.copy("Resources/logo.png"),
3636
.copy("Resources/example.jsonl"),
37+
.copy("Resources/9000.mp3"),
38+
.copy("Resources/cena.mp3"),
3739
]
3840
),
3941
]

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ let completion = try await openAIClient.completions.create(
7070
* [x] [Files](https://beta.openai.com/docs/api-reference/files)
7171
* [x] [Moderations](https://beta.openai.com/docs/api-reference/moderations)
7272
* [ ] [Fine-tunes](https://beta.openai.com/docs/api-reference/fine-tunes)
73-
* [ ] [Speech to text](https://platform.openai.com/docs/guides/speech-to-text)
73+
* [x] [Speech to text](https://platform.openai.com/docs/guides/speech-to-text)
7474

7575

7676
## Error handling

Sources/OpenAIKit/Audio/Audio.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//
2+
// Audio.swift
3+
//
4+
//
5+
// Created by Dylan Shine on 3/19/23.
6+
//
7+
8+
9+
import Foundation
10+
11+
/**
12+
Audio
13+
Learn how to turn audio into text.
14+
15+
Related guide: https://platform.openai.com/docs/guides/speech-to-text
16+
*/
17+
18+
public struct Audio {
19+
public let text: String
20+
}
21+
22+
extension Audio: Codable {}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//
2+
// AudioProvider.swift
3+
//
4+
//
5+
// Created by Dylan Shine on 3/19/23.
6+
//
7+
8+
import Foundation
9+
10+
public struct AudioProvider {
11+
12+
private let requestHandler: RequestHandler
13+
14+
init(requestHandler: RequestHandler) {
15+
self.requestHandler = requestHandler
16+
}
17+
18+
/**
19+
Create transcription BETA
20+
POST
21+
22+
https://api.openai.com/v1/audio/transcriptions
23+
24+
Transcribes audio into the input language.
25+
*/
26+
public func transcribe(
27+
file: Data,
28+
fileName: String,
29+
mimeType: MIMEType.Audio,
30+
model: ModelID = Model.Whisper.whisper1,
31+
prompt: String? = nil,
32+
responseFormat: String? = nil,
33+
temperature: Double? = nil,
34+
language: Language? = nil
35+
) async throws -> Audio {
36+
37+
let request = CreateTranscriptionRequest(
38+
file: file,
39+
fileName: fileName,
40+
mimeType: mimeType,
41+
model: model,
42+
prompt: prompt,
43+
responseFormat: responseFormat,
44+
temperature: temperature,
45+
language: language
46+
)
47+
48+
return try await requestHandler.perform(request: request)
49+
}
50+
51+
/**
52+
Create translation BETA
53+
POST
54+
55+
https://api.openai.com/v1/audio/translations
56+
57+
Translates audio into into English.
58+
*/
59+
public func translate(
60+
file: Data,
61+
fileName: String,
62+
mimeType: MIMEType.Audio,
63+
model: ModelID = Model.Whisper.whisper1,
64+
prompt: String? = nil,
65+
responseFormat: String? = nil,
66+
temperature: Double? = nil
67+
) async throws -> Audio {
68+
69+
let request = CreateTranslationRequest(
70+
file: file,
71+
fileName: fileName,
72+
mimeType: mimeType,
73+
model: model,
74+
prompt: prompt,
75+
responseFormat: responseFormat,
76+
temperature: temperature
77+
)
78+
79+
return try await requestHandler.perform(request: request)
80+
}
81+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//
2+
// CreateTranscriptionRequest.swift
3+
//
4+
//
5+
// Created by Dylan Shine on 3/19/23.
6+
//
7+
8+
import NIOHTTP1
9+
import Foundation
10+
import AsyncHTTPClient
11+
12+
struct CreateTranscriptionRequest: Request {
13+
let method: HTTPMethod = .POST
14+
let path = "/v1/audio/transcriptions"
15+
let body: HTTPClient.Body?
16+
private let boundary = UUID().uuidString
17+
18+
var headers: HTTPHeaders {
19+
var headers = HTTPHeaders()
20+
headers.add(name: "Content-Type", value: "multipart/form-data; boundary=\(boundary)")
21+
return headers
22+
}
23+
24+
init(
25+
file: Data,
26+
fileName: String,
27+
mimeType: MIMEType.Audio,
28+
model: ModelID,
29+
prompt: String?,
30+
responseFormat: String?,
31+
temperature: Double?,
32+
language: Language?
33+
) {
34+
let builder = MultipartFormDataBuilder(boundary: boundary)
35+
36+
builder.addDataField(
37+
fieldName: "file",
38+
fileName: fileName,
39+
data: file,
40+
mimeType: mimeType.rawValue
41+
)
42+
43+
builder.addTextField(named: "model", value: model.id)
44+
45+
if let prompt = prompt {
46+
builder.addTextField(named: "prompt", value: prompt)
47+
}
48+
49+
if let responseFormat = responseFormat {
50+
builder.addTextField(named: "response_format", value: responseFormat)
51+
}
52+
53+
if let temperature = temperature {
54+
builder.addTextField(named: "temperature", value: String(temperature))
55+
}
56+
57+
if let language = language {
58+
builder.addTextField(named: "language", value: language.rawValue)
59+
}
60+
61+
self.body = .data(builder.build())
62+
}
63+
}
64+
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//
2+
// CreateTranslationRequest.swift
3+
//
4+
//
5+
// Created by Dylan Shine on 3/19/23.
6+
//
7+
8+
import NIOHTTP1
9+
import Foundation
10+
import AsyncHTTPClient
11+
12+
struct CreateTranslationRequest: Request {
13+
let method: HTTPMethod = .POST
14+
let path = "/v1/audio/translations"
15+
let body: HTTPClient.Body?
16+
private let boundary = UUID().uuidString
17+
18+
var headers: HTTPHeaders {
19+
var headers = HTTPHeaders()
20+
headers.add(name: "Content-Type", value: "multipart/form-data; boundary=\(boundary)")
21+
return headers
22+
}
23+
24+
init(
25+
file: Data,
26+
fileName: String,
27+
mimeType: MIMEType.Audio,
28+
model: ModelID,
29+
prompt: String?,
30+
responseFormat: String?,
31+
temperature: Double?
32+
) {
33+
let builder = MultipartFormDataBuilder(boundary: boundary)
34+
35+
builder.addDataField(
36+
fieldName: "file",
37+
fileName: fileName,
38+
data: file,
39+
mimeType: mimeType.rawValue
40+
)
41+
42+
builder.addTextField(named: "model", value: model.id)
43+
44+
if let prompt = prompt {
45+
builder.addTextField(named: "prompt", value: prompt)
46+
}
47+
48+
if let responseFormat = responseFormat {
49+
builder.addTextField(named: "response_format", value: responseFormat)
50+
}
51+
52+
if let temperature = temperature {
53+
builder.addTextField(named: "temperature", value: String(temperature))
54+
}
55+
56+
self.body = .data(builder.build())
57+
}
58+
}

Sources/OpenAIKit/Client/Client.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ import Foundation
55

66
public struct Client {
77

8-
public let models: ModelProvider
9-
public let completions: CompletionProvider
8+
public let audio: AudioProvider
109
public let chats: ChatProvider
10+
public let completions: CompletionProvider
1111
public let edits: EditProvider
12-
public let images: ImageProvider
1312
public let embeddings: EmbeddingProvider
1413
public let files: FileProvider
14+
public let images: ImageProvider
15+
public let models: ModelProvider
1516
public let moderations: ModerationProvider
1617

1718
public init(
@@ -23,7 +24,8 @@ public struct Client {
2324
httpClient: httpClient,
2425
configuration: configuration
2526
)
26-
27+
28+
self.audio = AudioProvider(requestHandler: requestHandler)
2729
self.models = ModelProvider(requestHandler: requestHandler)
2830
self.completions = CompletionProvider(requestHandler: requestHandler)
2931
self.chats = ChatProvider(requestHandler: requestHandler)

Sources/OpenAIKit/File/FileProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public struct FileProvider {
3838
purpose: File.Purpose
3939
) async throws -> File {
4040

41-
let request = try UploadFileRequest(
41+
let request = UploadFileRequest(
4242
file: file,
4343
fileName: fileName,
4444
purpose: purpose

Sources/OpenAIKit/File/Request/UploadFileRequest.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ struct UploadFileRequest: Request {
1818
file: Data,
1919
fileName: String,
2020
purpose: File.Purpose
21-
) throws {
21+
) {
2222
let builder = MultipartFormDataBuilder(boundary: boundary)
2323

2424
builder.addDataField(
2525
fieldName: "file",
2626
fileName: fileName,
2727
data: file,
28-
mimeType: "application/json"
28+
mimeType: MIMEType.File.json.rawValue
2929
)
3030

3131
builder.addTextField(named: "purpose", value: purpose.rawValue)

0 commit comments

Comments
 (0)