@@ -7,6 +7,7 @@ struct GoogleCompletionAPI: CompletionAPI {
77 let apiKey : String
88 let model : ChatModel
99 var requestBody : CompletionRequestBody
10+ let prompt : ChatGPTPrompt
1011
1112 func callAsFunction( ) async throws -> CompletionResponseBody {
1213 let aiModel = GenerativeModel (
@@ -17,22 +18,22 @@ struct GoogleCompletionAPI: CompletionAPI {
1718 topP: requestBody. top_p. map ( Float . init)
1819 ) )
1920 )
20- let history = requestBody . messages . map { message in
21+ let history = prompt . googleAICompatible . history . map { message in
2122 ModelContent (
2223 ChatMessage (
2324 role: message. role,
2425 content: message. content,
2526 name: message. name,
26- functionCall: message. function_call . map {
27- . init( name: $0. name, arguments: $0. arguments ?? " " )
27+ functionCall: message. functionCall . map {
28+ . init( name: $0. name, arguments: $0. arguments)
2829 }
2930 )
3031 )
3132 }
3233
3334 do {
3435 let response = try await aiModel. generateContent ( history)
35-
36+
3637 return . init(
3738 object: " chat.completion " ,
3839 model: model. info. modelName,
@@ -64,7 +65,7 @@ struct GoogleCompletionAPI: CompletionAPI {
6465 return " Internal Error: \( s) "
6566 }
6667 }
67-
68+
6869 switch error {
6970 case let . internalError( underlying) :
7071 throw ErrorWrapper ( error: underlying)
@@ -79,3 +80,119 @@ struct GoogleCompletionAPI: CompletionAPI {
7980 }
8081}
8182
83+ extension ChatGPTPrompt {
84+ var googleAICompatible : ChatGPTPrompt {
85+ var history = self . history
86+ var reformattedHistory = [ ChatMessage] ( )
87+
88+ // We don't want to combine the new user message with others.
89+ let newUserMessage : ChatMessage ? = if history. last? . role == . user {
90+ history. removeLast ( )
91+ } else {
92+ nil
93+ }
94+
95+ for message in history {
96+ let lastIndex = reformattedHistory. endIndex - 1
97+ guard lastIndex >= 0 else { // first message
98+ if message. role == . system {
99+ reformattedHistory. append ( . init(
100+ id: message. id,
101+ role: . user,
102+ content: ModelContent . convertContent ( of: message)
103+ ) )
104+ reformattedHistory. append ( . init(
105+ role: . assistant,
106+ content: " Got it. Let's start our conversation. "
107+ ) )
108+ continue
109+ }
110+
111+ reformattedHistory. append ( message)
112+ continue
113+ }
114+
115+ let lastMessage = reformattedHistory [ lastIndex]
116+
117+ if ModelContent . convertRole ( lastMessage. role) == ModelContent
118+ . convertRole ( message. role)
119+ {
120+ let newMessage = ChatMessage (
121+ id: message. id,
122+ role: message. role == . assistant ? . assistant : . user,
123+ content: """
124+ \( ModelContent . convertContent ( of: lastMessage) )
125+
126+ ======
127+
128+ \( ModelContent . convertContent ( of: message) )
129+ """
130+ )
131+ reformattedHistory [ lastIndex] = newMessage
132+ } else {
133+ reformattedHistory. append ( message)
134+ }
135+ }
136+
137+ if let newUserMessage {
138+ if let last = reformattedHistory. last,
139+ ModelContent . convertRole ( last. role) == ModelContent
140+ . convertRole ( newUserMessage. role)
141+ {
142+ // Add dummy message
143+ let dummyMessage = ChatMessage (
144+ role: . assistant,
145+ content: " OK "
146+ )
147+ reformattedHistory. append ( dummyMessage)
148+ }
149+ reformattedHistory. append ( newUserMessage)
150+ }
151+
152+ return . init(
153+ history: reformattedHistory,
154+ references: references,
155+ remainingTokenCount: remainingTokenCount
156+ )
157+ }
158+ }
159+
160+ extension ModelContent {
161+ static func convertRole( _ role: ChatMessage . Role ) -> String {
162+ switch role {
163+ case . user, . system, . function:
164+ return " user "
165+ case . assistant:
166+ return " model "
167+ }
168+ }
169+
170+ static func convertContent( of message: ChatMessage ) -> String {
171+ switch message. role {
172+ case . system:
173+ return " System Prompt: \n \( message. content ?? " " ) "
174+ case . user:
175+ return message. content ?? " "
176+ case . function:
177+ return """
178+ Result of \( message. name ?? " function " ) : \( message. content ?? " N/A " )
179+ """
180+ case . assistant:
181+ if let functionCall = message. functionCall {
182+ return """
183+ Call function: \( functionCall. name)
184+ Arguments: \( functionCall. arguments)
185+ """
186+ } else {
187+ return message. content ?? " "
188+ }
189+ }
190+ }
191+
192+ init ( _ message: ChatMessage ) {
193+ let role = Self . convertRole ( message. role)
194+ let parts = [ ModelContent . Part. text ( Self . convertContent ( of: message) ) ]
195+ self = . init( role: role, parts: parts)
196+ }
197+ }
198+
0 commit comments