Skip to content

Commit 99dbf8f

Browse files
committed
Move definitions to CompletionsAPIDefinition
1 parent 9de4774 commit 99dbf8f

3 files changed

Lines changed: 210 additions & 200 deletions

File tree

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
import AIModel
2+
import Foundation
3+
import Preferences
4+
5+
/// https://platform.openai.com/docs/api-reference/chat/create
6+
struct CompletionRequestBody: Codable, Equatable {
7+
struct Message: Codable, Equatable {
8+
/// The role of the message.
9+
var role: ChatMessage.Role
10+
/// The content of the message.
11+
var content: String
12+
/// When we want to reply to a function call with the result, we have to provide the
13+
/// name of the function call, and include the result in `content`.
14+
///
15+
/// - important: It's required when the role is `function`.
16+
var name: String?
17+
/// When the bot wants to call a function, it will reply with a function call in format:
18+
/// ```json
19+
/// {
20+
/// "name": "weather",
21+
/// "arguments": "{ \"location\": \"earth\" }"
22+
/// }
23+
/// ```
24+
var function_call: CompletionRequestBody.MessageFunctionCall?
25+
}
26+
27+
struct MessageFunctionCall: Codable, Equatable {
28+
/// The name of the
29+
var name: String
30+
/// A JSON string.
31+
var arguments: String?
32+
}
33+
34+
struct Function: Codable {
35+
var name: String
36+
var description: String
37+
/// JSON schema.
38+
var arguments: String
39+
}
40+
41+
var model: String
42+
var messages: [Message]
43+
var temperature: Double?
44+
var top_p: Double?
45+
var n: Double?
46+
var stream: Bool?
47+
var stop: [String]?
48+
var max_tokens: Int?
49+
var presence_penalty: Double?
50+
var frequency_penalty: Double?
51+
var logit_bias: [String: Double]?
52+
var user: String?
53+
/// Pass nil to let the bot decide.
54+
var function_call: FunctionCallStrategy?
55+
var functions: [ChatGPTFunctionSchema]?
56+
57+
init(
58+
model: String,
59+
messages: [Message],
60+
temperature: Double? = nil,
61+
top_p: Double? = nil,
62+
n: Double? = nil,
63+
stream: Bool? = nil,
64+
stop: [String]? = nil,
65+
max_tokens: Int? = nil,
66+
presence_penalty: Double? = nil,
67+
frequency_penalty: Double? = nil,
68+
logit_bias: [String: Double]? = nil,
69+
user: String? = nil,
70+
function_call: FunctionCallStrategy? = nil,
71+
functions: [ChatGPTFunctionSchema] = []
72+
) {
73+
self.model = model
74+
self.messages = messages
75+
self.temperature = temperature
76+
self.top_p = top_p
77+
self.n = n
78+
self.stream = stream
79+
self.stop = stop
80+
self.max_tokens = max_tokens
81+
self.presence_penalty = presence_penalty
82+
self.frequency_penalty = frequency_penalty
83+
self.logit_bias = logit_bias
84+
self.user = user
85+
if UserDefaults.shared.value(for: \.disableFunctionCalling) {
86+
self.function_call = nil
87+
self.functions = nil
88+
} else {
89+
self.function_call = function_call
90+
self.functions = functions.isEmpty ? nil : functions
91+
}
92+
}
93+
}
94+
95+
public enum FunctionCallStrategy: Codable, Equatable {
96+
/// Forbid the bot to call any function.
97+
case none
98+
/// Let the bot choose what function to call.
99+
case auto
100+
/// Force the bot to call a function with the given name.
101+
case name(String)
102+
103+
struct CallFunctionNamed: Codable {
104+
var name: String
105+
}
106+
107+
public func encode(to encoder: Encoder) throws {
108+
var container = encoder.singleValueContainer()
109+
switch self {
110+
case .none:
111+
try container.encode("none")
112+
case .auto:
113+
try container.encode("auto")
114+
case let .name(name):
115+
try container.encode(CallFunctionNamed(name: name))
116+
}
117+
}
118+
}
119+
120+
// MARK: - Stream API
121+
122+
typealias CompletionStreamAPIBuilder = (
123+
String,
124+
ChatModel,
125+
URL,
126+
CompletionRequestBody,
127+
ChatGPTPrompt
128+
) -> any CompletionStreamAPI
129+
130+
protocol CompletionStreamAPI {
131+
associatedtype CompletionSequence: AsyncSequence
132+
where CompletionSequence.Element == CompletionStreamDataChunk
133+
func callAsFunction() async throws -> CompletionSequence
134+
}
135+
136+
struct CompletionStreamDataChunk: Codable {
137+
var id: String?
138+
var object: String?
139+
var model: String?
140+
var choices: [Choice]?
141+
142+
struct Choice: Codable {
143+
var delta: Delta?
144+
var index: Int?
145+
var finish_reason: String?
146+
147+
struct Delta: Codable {
148+
struct FunctionCall: Codable {
149+
var name: String?
150+
var arguments: String?
151+
}
152+
153+
var role: ChatMessage.Role?
154+
var content: String?
155+
var function_call: FunctionCall?
156+
}
157+
}
158+
}
159+
160+
// MARK: - Non Stream API
161+
162+
typealias CompletionAPIBuilder = (String, ChatModel, URL, CompletionRequestBody, ChatGPTPrompt)
163+
-> any CompletionAPI
164+
165+
protocol CompletionAPI {
166+
func callAsFunction() async throws -> CompletionResponseBody
167+
}
168+
169+
/// https://platform.openai.com/docs/api-reference/chat/create
170+
struct CompletionResponseBody: Codable, Equatable {
171+
struct Message: Codable, Equatable {
172+
/// The role of the message.
173+
var role: ChatMessage.Role
174+
/// The content of the message.
175+
var content: String?
176+
/// When we want to reply to a function call with the result, we have to provide the
177+
/// name of the function call, and include the result in `content`.
178+
///
179+
/// - important: It's required when the role is `function`.
180+
var name: String?
181+
/// When the bot wants to call a function, it will reply with a function call in format:
182+
/// ```json
183+
/// {
184+
/// "name": "weather",
185+
/// "arguments": "{ \"location\": \"earth\" }"
186+
/// }
187+
/// ```
188+
var function_call: CompletionRequestBody.MessageFunctionCall?
189+
}
190+
191+
struct Choice: Codable, Equatable {
192+
var message: Message
193+
var index: Int
194+
var finish_reason: String
195+
}
196+
197+
struct Usage: Codable, Equatable {
198+
var prompt_tokens: Int
199+
var completion_tokens: Int
200+
var total_tokens: Int
201+
}
202+
203+
var id: String?
204+
var object: String
205+
var model: String
206+
var usage: Usage
207+
var choices: [Choice]
208+
}
209+

Tool/Sources/OpenAIService/APIs/OpenAICompletionAPI.swift

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,54 +2,6 @@ import AIModel
22
import Foundation
33
import Preferences
44

5-
typealias CompletionAPIBuilder = (String, ChatModel, URL, CompletionRequestBody, ChatGPTPrompt)
6-
-> CompletionAPI
7-
8-
protocol CompletionAPI {
9-
func callAsFunction() async throws -> CompletionResponseBody
10-
}
11-
12-
/// https://platform.openai.com/docs/api-reference/chat/create
13-
struct CompletionResponseBody: Codable, Equatable {
14-
struct Message: Codable, Equatable {
15-
/// The role of the message.
16-
var role: ChatMessage.Role
17-
/// The content of the message.
18-
var content: String?
19-
/// When we want to reply to a function call with the result, we have to provide the
20-
/// name of the function call, and include the result in `content`.
21-
///
22-
/// - important: It's required when the role is `function`.
23-
var name: String?
24-
/// When the bot wants to call a function, it will reply with a function call in format:
25-
/// ```json
26-
/// {
27-
/// "name": "weather",
28-
/// "arguments": "{ \"location\": \"earth\" }"
29-
/// }
30-
/// ```
31-
var function_call: CompletionRequestBody.MessageFunctionCall?
32-
}
33-
34-
struct Choice: Codable, Equatable {
35-
var message: Message
36-
var index: Int
37-
var finish_reason: String
38-
}
39-
40-
struct Usage: Codable, Equatable {
41-
var prompt_tokens: Int
42-
var completion_tokens: Int
43-
var total_tokens: Int
44-
}
45-
46-
var id: String?
47-
var object: String
48-
var model: String
49-
var usage: Usage
50-
var choices: [Choice]
51-
}
52-
535
struct CompletionAPIError: Error, Codable, LocalizedError {
546
struct E: Codable {
557
var message: String
@@ -95,7 +47,7 @@ struct OpenAICompletionAPI: CompletionAPI {
9547
case .azureOpenAI:
9648
request.setValue(apiKey, forHTTPHeaderField: "api-key")
9749
case .googleAI:
98-
assert(false, "Unsupported")
50+
assertionFailure("Unsupported")
9951
}
10052
}
10153

0 commit comments

Comments
 (0)