我最终创建了一个小函数来创建多部分表单数据。我找不到任何关于Vapor的MultiPartKit库的文档。
请求的构造方式如下:
func makeSpeechToTextRequest(
client: Client,
audio: Data
) async throws -> SpeechToTextResponse {
let result = try await client.post(
"https://api.openai.com/v1/audio/transcriptions",
headers: [
"Authorization": "Bearer \(memoKey)"
],
beforeSend: { req in
let (body, contentType) = createMultipartFormData(from: [
.file(fileName: "speech.mp3", fileType: "audio/mp3", fileData: audio),
.string(name: "model", value: "whisper-1"),
.string(name: "response_format", value: "verbose_json"),
.string(name: "timestamp_granularities[]", value: "word")
])
req.body = body
req.headers.contentType = contentType
}
)
return try result.content.decode(SpeechToTextResponse.self)
}
下面是辅助函数:
private enum MultipartField {
case string(name: String, value: String)
case file(fileName: String, fileType: String, fileData: Data)
}
private func createMultipartFormData(from fields: [MultipartField]) -> (ByteBuffer, HTTPMediaType) {
let boundary = UUID().uuidString
var buffer = ByteBuffer()
for field in fields {
switch field {
case let .file(fileName, fileType, fileData):
buffer.writeString("--\(boundary)\r\n")
buffer.writeString("Content-Disposition: form-data; name=\"file\"; filename=\"\(fileName)\"\r\n")
buffer.writeString("Content-Type: \(fileType)\r\n\r\n")
buffer.writeData(fileData)
buffer.writeString("\r\n")
case let .string(name, value):
buffer.writeString("--\(boundary)\r\n")
buffer.writeString("Content-Disposition: form-data; name=\"\(name)\"\r\n\r\n")
buffer.writeString("\(value)\r\n")
}
}
buffer.writeString("--\(boundary)--\r\n")
let mediaType = HTTPMediaType(
type: "multipart",
subType: "form-data",
parameters: ["boundary": boundary]
)
return (buffer, mediaType)
}