@@ -8,9 +8,18 @@ public protocol ChatGPTServiceType {
88 func mutateSystemPrompt( _ newPrompt: String ) async
99}
1010
11- public enum ChatGPTServiceError : Error {
11+ public enum ChatGPTServiceError : Error , LocalizedError {
1212 case endpointIncorrect
1313 case responseInvalid
14+
15+ public var errorDescription : String ? {
16+ switch self {
17+ case . endpointIncorrect:
18+ return " ChatGPT endpoint is incorrect "
19+ case . responseInvalid:
20+ return " Response is invalid "
21+ }
22+ }
1423}
1524
1625public struct ChatGPTError : Error , Codable , LocalizedError {
@@ -45,12 +54,13 @@ public actor ChatGPTService: ChatGPTServiceType, ObservableObject {
4554 public var apiKey : String
4655 public var systemPrompt : String
4756 public var maxToken : Int
48- public var history : [ ChatGPTMessage ] = [ ] {
57+ public var history : [ ChatMessage ] = [ ] {
4958 didSet { objectWillChange. send ( ) }
5059 }
5160
5261 public internal( set) var isReceivingMessage = false
53- var ongoingTask : URLSessionDataTask ?
62+ var cancelTask : Cancellable ?
63+ var buildCompletionStreamAPI : CompletionStreamAPIBuilder = OpenAICompletionStreamAPI . init
5464
5565 public init (
5666 systemPrompt: String ,
@@ -74,55 +84,29 @@ public actor ChatGPTService: ChatGPTServiceType, ObservableObject {
7484 ) async throws -> AsyncThrowingStream < String , Error > {
7585 guard !isReceivingMessage else { throw CancellationError ( ) }
7686 guard let url = URL ( string: endpoint) else { throw ChatGPTServiceError . endpointIncorrect }
77- let newMessage = ChatGPTMessage ( role: . user, content: content, summary: summary)
87+ let newMessage = ChatMessage ( role: . user, content: content, summary: summary)
7888 history. append ( newMessage)
79- var request = URLRequest ( url: url)
80- request. httpMethod = " POST "
8189
82- let requestBody = ChatGPTRequest (
90+ let requestBody = CompletionRequestBody (
8391 model: model. rawValue,
8492 messages: combineHistoryWithSystemPrompt ( ) ,
8593 temperature: temperature,
8694 stream: true ,
8795 max_tokens: maxToken
8896 )
89-
90- let encoder = JSONEncoder ( )
91- request. httpBody = try encoder. encode ( requestBody)
92- request. setValue ( " application/json " , forHTTPHeaderField: " Content-Type " )
93- request. setValue ( " Bearer \( apiKey) " , forHTTPHeaderField: " Authorization " )
9497
9598 isReceivingMessage = true
9699
97100 do {
98- let ( result, response) = try await URLSession . shared. bytes ( for: request)
99- ongoingTask = result. task
100-
101- guard let response = response as? HTTPURLResponse else {
102- throw ChatGPTServiceError . responseInvalid
103- }
104- guard response. statusCode == 200 else {
105- let text = try await result. lines. reduce ( into: " " ) { partialResult, current in
106- partialResult += current
107- }
108- guard let data = text. data ( using: . utf8)
109- else { throw ChatGPTServiceError . responseInvalid }
110- let decoder = JSONDecoder ( )
111- let error = try ? decoder. decode ( ChatGPTError . self, from: data)
112- throw error ?? ChatGPTServiceError . responseInvalid
113- }
101+ let api = buildCompletionStreamAPI ( apiKey, url, requestBody)
102+ let ( trunks, cancel) = try await api ( )
103+ cancelTask = cancel
114104
115105 return AsyncThrowingStream < String , Error > { continuation in
116106 Task {
117107 do {
118- for try await line in result. lines {
119- let prefix = " data: "
120- guard line. hasPrefix ( prefix) ,
121- let content = line. dropFirst ( prefix. count) . data ( using: . utf8) ,
122- let trunk = try ? JSONDecoder ( )
123- . decode ( ChatGPTDataTrunk . self, from: content) ,
124- let delta = trunk. choices. first? . delta
125- else { continue }
108+ for try await trunk in trunks {
109+ guard let delta = trunk. choices. first? . delta else { continue }
126110
127111 if history. last? . id == trunk. id {
128112 if let role = delta. role {
@@ -158,8 +142,8 @@ public actor ChatGPTService: ChatGPTServiceType, ObservableObject {
158142 }
159143
160144 public func stopReceivingMessage( ) {
161- ongoingTask ? . cancel ( )
162- ongoingTask = nil
145+ cancelTask ? ( )
146+ cancelTask = nil
163147 isReceivingMessage = false
164148 }
165149
@@ -173,7 +157,11 @@ public actor ChatGPTService: ChatGPTServiceType, ObservableObject {
173157}
174158
175159extension ChatGPTService {
176- func combineHistoryWithSystemPrompt( ) -> [ ChatGPTMessage ] {
160+ func changeBuildCompletionStreamAPI( _ builder: @escaping CompletionStreamAPIBuilder ) {
161+ buildCompletionStreamAPI = builder
162+ }
163+
164+ func combineHistoryWithSystemPrompt( ) -> [ ChatMessage ] {
177165 if history. count > 4 {
178166 return [ . init( role: . system, content: systemPrompt) ] +
179167 history[ history. endIndex - 4 ..< history. endIndex]
0 commit comments