Skip to content

Commit dde2a99

Browse files
committed
Merge branch 'feature/title-field-for-openrouter' into develop
2 parents da8e49e + b120f38 commit dde2a99

2 files changed

Lines changed: 99 additions & 81 deletions

File tree

Tool/Sources/OpenAIService/APIs/OpenAIChatCompletionsService.swift

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -233,28 +233,9 @@ actor OpenAIChatCompletionsService: ChatCompletionsStreamAPI, ChatCompletionsAPI
233233
let encoder = JSONEncoder()
234234
request.httpBody = try encoder.encode(requestBody)
235235
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
236-
if !apiKey.isEmpty {
237-
switch model.format {
238-
case .openAI:
239-
if !model.info.openAIInfo.organizationID.isEmpty {
240-
request.setValue(
241-
model.info.openAIInfo.organizationID,
242-
forHTTPHeaderField: "OpenAI-Organization"
243-
)
244-
}
245-
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
246-
case .openAICompatible:
247-
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
248-
case .azureOpenAI:
249-
request.setValue(apiKey, forHTTPHeaderField: "api-key")
250-
case .googleAI:
251-
assertionFailure("Unsupported")
252-
case .ollama:
253-
assertionFailure("Unsupported")
254-
case .claude:
255-
assertionFailure("Unsupported")
256-
}
257-
}
236+
237+
Self.setupAppInformation(&request)
238+
Self.setupAPIKey(&request, model: model, apiKey: apiKey)
258239

259240
let (result, response) = try await URLSession.shared.bytes(for: request)
260241
guard let response = response as? HTTPURLResponse else {
@@ -303,13 +284,58 @@ actor OpenAIChatCompletionsService: ChatCompletionsStreamAPI, ChatCompletionsAPI
303284
let encoder = JSONEncoder()
304285
request.httpBody = try encoder.encode(requestBody)
305286
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
287+
288+
Self.setupAppInformation(&request)
289+
Self.setupAPIKey(&request, model: model, apiKey: apiKey)
290+
291+
let (result, response) = try await URLSession.shared.data(for: request)
292+
guard let response = response as? HTTPURLResponse else {
293+
throw ChatGPTServiceError.responseInvalid
294+
}
295+
296+
guard response.statusCode == 200 else {
297+
let error = try? JSONDecoder().decode(CompletionAPIError.self, from: result)
298+
throw error ?? ChatGPTServiceError
299+
.otherError(String(data: result, encoding: .utf8) ?? "Unknown Error")
300+
}
301+
302+
do {
303+
let body = try JSONDecoder().decode(ResponseBody.self, from: result)
304+
return body.formalized()
305+
} catch {
306+
dump(error)
307+
throw error
308+
}
309+
}
310+
311+
static func setupAppInformation(_ request: inout URLRequest) {
312+
if #available(macOS 13.0, *) {
313+
if request.url?.host == "openrouter.ai" {
314+
request.setValue("Copilot for Xcode", forHTTPHeaderField: "X-Title")
315+
request.setValue(
316+
"https://github.com/intitni/CopilotForXcode",
317+
forHTTPHeaderField: "HTTP-Referer"
318+
)
319+
}
320+
} else {
321+
if request.url?.host == "openrouter.ai" {
322+
request.setValue("Copilot for Xcode", forHTTPHeaderField: "X-Title")
323+
request.setValue(
324+
"https://github.com/intitni/CopilotForXcode",
325+
forHTTPHeaderField: "HTTP-Referer"
326+
)
327+
}
328+
}
329+
}
330+
331+
static func setupAPIKey(_ request: inout URLRequest, model: ChatModel, apiKey: String) {
306332
if !apiKey.isEmpty {
307333
switch model.format {
308334
case .openAI:
309335
if !model.info.openAIInfo.organizationID.isEmpty {
310336
request.setValue(
311-
"OpenAI-Organization",
312-
forHTTPHeaderField: model.info.openAIInfo.organizationID
337+
model.info.openAIInfo.organizationID,
338+
forHTTPHeaderField: "OpenAI-Organization"
313339
)
314340
}
315341
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
@@ -325,25 +351,6 @@ actor OpenAIChatCompletionsService: ChatCompletionsStreamAPI, ChatCompletionsAPI
325351
assertionFailure("Unsupported")
326352
}
327353
}
328-
329-
let (result, response) = try await URLSession.shared.data(for: request)
330-
guard let response = response as? HTTPURLResponse else {
331-
throw ChatGPTServiceError.responseInvalid
332-
}
333-
334-
guard response.statusCode == 200 else {
335-
let error = try? JSONDecoder().decode(CompletionAPIError.self, from: result)
336-
throw error ?? ChatGPTServiceError
337-
.otherError(String(data: result, encoding: .utf8) ?? "Unknown Error")
338-
}
339-
340-
do {
341-
let body = try JSONDecoder().decode(ResponseBody.self, from: result)
342-
return body.formalized()
343-
} catch {
344-
dump(error)
345-
throw error
346-
}
347354
}
348355
}
349356

Tool/Sources/OpenAIService/APIs/OpenAIEmbeddingService.swift

Lines changed: 49 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ struct OpenAIEmbeddingService: EmbeddingAPI {
1212
var input: [[Int]]
1313
var model: String
1414
}
15-
15+
1616
let apiKey: String
1717
let model: EmbeddingModel
1818
let endpoint: String
19-
19+
2020
public func embed(text: String) async throws -> EmbeddingResponse {
2121
return try await embed(texts: [text])
2222
}
@@ -31,24 +31,9 @@ struct OpenAIEmbeddingService: EmbeddingAPI {
3131
model: model.info.modelName
3232
))
3333
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
34-
if !apiKey.isEmpty {
35-
switch model.format {
36-
case .openAI:
37-
if model.info.openAIInfo.organizationID.isEmpty {
38-
request.setValue(
39-
"OpenAI-Organization",
40-
forHTTPHeaderField: model.info.openAIInfo.organizationID
41-
)
42-
}
43-
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
44-
case .openAICompatible:
45-
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
46-
case .azureOpenAI:
47-
request.setValue(apiKey, forHTTPHeaderField: "api-key")
48-
case .ollama:
49-
assertionFailure("Unsupported")
50-
}
51-
}
34+
35+
Self.setupAppInformation(&request)
36+
Self.setupAPIKey(&request, model: model, apiKey: apiKey)
5237

5338
let (result, response) = try await URLSession.shared.data(for: request)
5439
guard let response = response as? HTTPURLResponse else {
@@ -87,24 +72,9 @@ struct OpenAIEmbeddingService: EmbeddingAPI {
8772
model: model.info.modelName
8873
))
8974
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
90-
if !apiKey.isEmpty {
91-
switch model.format {
92-
case .openAI:
93-
if model.info.openAIInfo.organizationID.isEmpty {
94-
request.setValue(
95-
"OpenAI-Organization",
96-
forHTTPHeaderField: model.info.openAIInfo.organizationID
97-
)
98-
}
99-
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
100-
case .openAICompatible:
101-
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
102-
case .azureOpenAI:
103-
request.setValue(apiKey, forHTTPHeaderField: "api-key")
104-
case .ollama:
105-
assertionFailure("Unsupported")
106-
}
107-
}
75+
76+
Self.setupAppInformation(&request)
77+
Self.setupAPIKey(&request, model: model, apiKey: apiKey)
10878

10979
let (result, response) = try await URLSession.shared.data(for: request)
11080
guard let response = response as? HTTPURLResponse else {
@@ -132,5 +102,46 @@ struct OpenAIEmbeddingService: EmbeddingAPI {
132102
#endif
133103
return embeddingResponse
134104
}
105+
106+
static func setupAppInformation(_ request: inout URLRequest) {
107+
if #available(macOS 13.0, *) {
108+
if request.url?.host == "openrouter.ai" {
109+
request.setValue("Copilot for Xcode", forHTTPHeaderField: "X-Title")
110+
request.setValue(
111+
"https://github.com/intitni/CopilotForXcode",
112+
forHTTPHeaderField: "HTTP-Referer"
113+
)
114+
}
115+
} else {
116+
if request.url?.host == "openrouter.ai" {
117+
request.setValue("Copilot for Xcode", forHTTPHeaderField: "X-Title")
118+
request.setValue(
119+
"https://github.com/intitni/CopilotForXcode",
120+
forHTTPHeaderField: "HTTP-Referer"
121+
)
122+
}
123+
}
124+
}
125+
126+
static func setupAPIKey(_ request: inout URLRequest, model: EmbeddingModel, apiKey: String) {
127+
if !apiKey.isEmpty {
128+
switch model.format {
129+
case .openAI:
130+
if model.info.openAIInfo.organizationID.isEmpty {
131+
request.setValue(
132+
model.info.openAIInfo.organizationID,
133+
forHTTPHeaderField: "OpenAI-Organization"
134+
)
135+
}
136+
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
137+
case .openAICompatible:
138+
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
139+
case .azureOpenAI:
140+
request.setValue(apiKey, forHTTPHeaderField: "api-key")
141+
case .ollama:
142+
assertionFailure("Unsupported")
143+
}
144+
}
145+
}
135146
}
136147

0 commit comments

Comments
 (0)