feat:mac os

This commit is contained in:
intelligence committed 2026-08-29 19:58:33 +02:00
1 parent 136bf7cfa3
commit 3400e2b465
18 files changed
+1129

No files matched your search

@@ -0,0 +1,110 @@
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
enum TranscriptionError: LocalizedError {
case invalidEndpoint
case invalidResponse
case http(Int)
var errorDescription: String? {
switch self {
case .invalidEndpoint: "The transcription endpoint is invalid."
case .invalidResponse: "The server response did not contain a transcript."
case .http(let status): "The server returned HTTP \(status)."
}
}
}
struct TranscriptionClient {
static func endpointURL(from value: String) -> URL? {
var endpoint = value.trimmingCharacters(in: .whitespacesAndNewlines)
while endpoint.hasSuffix("/") { endpoint.removeLast() }
if !endpoint.contains("/v1/audio/transcriptions") {
endpoint += "/v1/audio/transcriptions"
}
guard let url = URL(string: endpoint),
let scheme = url.scheme?.lowercased(),
scheme == "http" || scheme == "https",
url.host != nil
else { return nil }
return url
}
func transcribe(
recording: URL,
endpoint: String,
model: String,
key: String,
prompt: String
) async throws -> String {
guard let url = Self.endpointURL(from: endpoint) else {
throw TranscriptionError.invalidEndpoint
}
let boundary = "transui-\(UUID().uuidString)"
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.timeoutInterval = 300
request.setValue(
"multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
if !key.isEmpty {
request.setValue("Bearer \(key)", forHTTPHeaderField: "Authorization")
}
request.httpBody = try multipartBody(
boundary: boundary,
recording: recording,
model: model,
prompt: prompt
)
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse else {
throw TranscriptionError.invalidResponse
}
guard (200..<300).contains(http.statusCode) else {
throw TranscriptionError.http(http.statusCode)
}
guard data.count <= 1_048_576 else {
throw TranscriptionError.invalidResponse
}
guard let object = try JSONSerialization.jsonObject(with: data) as? [String: Any],
let text = object["text"] as? String
else {
throw TranscriptionError.invalidResponse
}
return TranscriptCleaner.clean(text)
}
private func multipartBody(
boundary: String,
recording: URL,
model: String,
prompt: String
) throws -> Data {
var data = Data()
func field(_ name: String, _ value: String) {
data.append("--\(boundary)\r\n")
data.append("Content-Disposition: form-data; name=\"\(name)\"\r\n\r\n")
data.append("\(value)\r\n")
}
field("response_format", "json")
if !model.isEmpty { field("model", model) }
if !prompt.isEmpty { field("prompt", prompt) }
data.append("--\(boundary)\r\n")
data.append("Content-Disposition: form-data; name=\"file\"; filename=\"recording.wav\"\r\n")
data.append("Content-Type: audio/wav\r\n\r\n")
data.append(try Data(contentsOf: recording))
data.append("\r\n--\(boundary)--\r\n")
return data
}
}
extension Data {
fileprivate mutating func append(_ string: String) {
append(contentsOf: string.utf8)
}
}