@@ -3,7 +3,20 @@ import AsyncAlgorithms
33import Foundation
44import Preferences
55
6- struct OpenAICompletionStreamAPI : ChatCompletionsStreamAPI {
6+ actor OpenAIService : ChatCompletionsStreamAPI , ChatCompletionsAPI {
7+ struct CompletionAPIError : Error , Codable , LocalizedError {
8+ struct E : Codable {
9+ var message : String
10+ var type : String
11+ var param : String
12+ var code : String
13+ }
14+
15+ var error : E
16+
17+ var errorDescription : String ? { error. message }
18+ }
19+
720 var apiKey : String
821 var endpoint : URL
922 var requestBody : ChatCompletionsRequestBody
@@ -18,11 +31,13 @@ struct OpenAICompletionStreamAPI: ChatCompletionsStreamAPI {
1831 self . apiKey = apiKey
1932 self . endpoint = endpoint
2033 self . requestBody = requestBody
21- self . requestBody. stream = true
2234 self . model = model
2335 }
2436
25- func callAsFunction( ) async throws -> AsyncThrowingStream < ChatCompletionsStreamDataChunk , Error > {
37+ func callAsFunction( ) async throws
38+ -> AsyncThrowingStream < ChatCompletionsStreamDataChunk , Error >
39+ {
40+ requestBody. stream = true
2641 var request = URLRequest ( url: endpoint)
2742 request. httpMethod = " POST "
2843 let encoder = JSONEncoder ( )
@@ -81,5 +96,42 @@ struct OpenAICompletionStreamAPI: ChatCompletionsStreamAPI {
8196
8297 return stream
8398 }
99+
100+ func callAsFunction( ) async throws -> ChatCompletionResponseBody {
101+ requestBody. stream = false
102+ var request = URLRequest ( url: endpoint)
103+ request. httpMethod = " POST "
104+ let encoder = JSONEncoder ( )
105+ request. httpBody = try encoder. encode ( requestBody)
106+ request. setValue ( " application/json " , forHTTPHeaderField: " Content-Type " )
107+ if !apiKey. isEmpty {
108+ switch model. format {
109+ case . openAI, . openAICompatible:
110+ request. setValue ( " Bearer \( apiKey) " , forHTTPHeaderField: " Authorization " )
111+ case . azureOpenAI:
112+ request. setValue ( apiKey, forHTTPHeaderField: " api-key " )
113+ case . googleAI:
114+ assertionFailure ( " Unsupported " )
115+ }
116+ }
117+
118+ let ( result, response) = try await URLSession . shared. data ( for: request)
119+ guard let response = response as? HTTPURLResponse else {
120+ throw ChatGPTServiceError . responseInvalid
121+ }
122+
123+ guard response. statusCode == 200 else {
124+ let error = try ? JSONDecoder ( ) . decode ( CompletionAPIError . self, from: result)
125+ throw error ?? ChatGPTServiceError
126+ . otherError ( String ( data: result, encoding: . utf8) ?? " Unknown Error " )
127+ }
128+
129+ do {
130+ return try JSONDecoder ( ) . decode ( ChatCompletionResponseBody . self, from: result)
131+ } catch {
132+ dump ( error)
133+ throw error
134+ }
135+ }
84136}
85137
0 commit comments