forked from intitni/CopilotForXcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGoogleAICompletionStreamAPI.swift
More file actions
65 lines (60 loc) · 2.27 KB
/
GoogleAICompletionStreamAPI.swift
File metadata and controls
65 lines (60 loc) · 2.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import AIModel
import Foundation
import GoogleGenerativeAI
import Preferences
struct GoogleCompletionStreamAPI: CompletionStreamAPI {
let apiKey: String
let model: ChatModel
var requestBody: CompletionRequestBody
func callAsFunction() async throws -> AsyncThrowingStream<CompletionStreamDataChunk, Error> {
let aiModel = GenerativeModel(
name: model.name,
apiKey: apiKey,
generationConfig: .init(GenerationConfig(
temperature: requestBody.temperature.map(Float.init),
topP: requestBody.top_p.map(Float.init)
))
)
let history = requestBody.messages.map { message in
ModelContent(
ChatMessage(
role: message.role,
content: message.content,
name: message.name,
functionCall: message.function_call.map {
.init(name: $0.name, arguments: $0.arguments ?? "")
}
)
)
}
let stream = AsyncThrowingStream<CompletionStreamDataChunk, Error> { continuation in
let stream = aiModel.generateContentStream(history)
let task = Task {
do {
for try await response in stream {
if Task.isCancelled { break }
let chunk = CompletionStreamDataChunk(
object: "",
model: model.name,
choices: response.candidates.map { candidate in
.init(delta: .init(
role: .assistant,
content: candidate.content.parts
.first(where: { $0.text != nil })?.text ?? ""
))
}
)
continuation.yield(chunk)
}
continuation.finish()
} catch {
continuation.finish(throwing: error)
}
}
continuation.onTermination = { _ in
task.cancel()
}
}
return stream
}
}