Skip to content

Commit 3b691c6

Browse files
authored
Add customizable base url support for several services (#111)
1 parent 07ee2f9 commit 3b691c6

File tree

6 files changed

+55
-32
lines changed

6 files changed

+55
-32
lines changed

Sources/AIProxy/AIProxy.swift

+20-10
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,12 @@ public struct AIProxy {
108108
/// - unprotectedAPIKey: Your OpenAI API key
109109
/// - Returns: An instance of OpenAIService configured and ready to make requests
110110
public static func openAIDirectService(
111-
unprotectedAPIKey: String
111+
unprotectedAPIKey: String,
112+
baseURL: String? = nil
112113
) -> OpenAIService {
113114
return OpenAIDirectService(
114-
unprotectedAPIKey: unprotectedAPIKey
115+
unprotectedAPIKey: unprotectedAPIKey,
116+
baseURL: baseURL
115117
)
116118
}
117119

@@ -196,10 +198,12 @@ public struct AIProxy {
196198
/// - unprotectedAPIKey: Your Anthropic API key
197199
/// - Returns: An instance of AnthropicService configured and ready to make requests
198200
public static func anthropicDirectService(
199-
unprotectedAPIKey: String
201+
unprotectedAPIKey: String,
202+
baseURL: String? = nil
200203
) -> AnthropicService {
201204
return AnthropicDirectService(
202-
unprotectedAPIKey: unprotectedAPIKey
205+
unprotectedAPIKey: unprotectedAPIKey,
206+
baseURL: baseURL
203207
)
204208
}
205209

@@ -509,10 +513,12 @@ public struct AIProxy {
509513
/// - unprotectedAPIKey: Your Groq API key
510514
/// - Returns: An instance of GroqService configured and ready to make requests
511515
public static func groqDirectService(
512-
unprotectedAPIKey: String
516+
unprotectedAPIKey: String,
517+
baseURL: String? = nil
513518
) -> GroqService {
514519
return GroqDirectService(
515-
unprotectedAPIKey: unprotectedAPIKey
520+
unprotectedAPIKey: unprotectedAPIKey,
521+
baseURL: baseURL
516522
)
517523
}
518524

@@ -685,10 +691,12 @@ public struct AIProxy {
685691
/// - unprotectedAPIKey: Your OpenRouter API key
686692
/// - Returns: An instance of OpenRouter configured and ready to make requests
687693
public static func openRouterDirectService(
688-
unprotectedAPIKey: String
694+
unprotectedAPIKey: String,
695+
baseURL: String? = nil
689696
) -> OpenRouterService {
690697
return OpenRouterDirectService(
691-
unprotectedAPIKey: unprotectedAPIKey
698+
unprotectedAPIKey: unprotectedAPIKey,
699+
baseURL: baseURL
692700
)
693701
}
694702

@@ -729,10 +737,12 @@ public struct AIProxy {
729737
/// - unprotectedAPIKey: Your DeepSeek API key
730738
/// - Returns: An instance of DeepSeek configured and ready to make requests
731739
public static func deepSeekDirectService(
732-
unprotectedAPIKey: String
740+
unprotectedAPIKey: String,
741+
baseURL: String? = nil
733742
) -> DeepSeekService {
734743
return DeepSeekDirectService(
735-
unprotectedAPIKey: unprotectedAPIKey
744+
unprotectedAPIKey: unprotectedAPIKey,
745+
baseURL: baseURL
736746
)
737747
}
738748

Sources/AIProxy/Anthropic/AnthropicDirectService.swift

+5-3
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ import Foundation
99

1010
open class AnthropicDirectService: AnthropicService, DirectService {
1111
private let unprotectedAPIKey: String
12+
private let baseURL: String
1213

1314
/// This initializer is not public on purpose.
1415
/// Customers are expected to use the factory `AIProxy.directAnthropicService` defined in AIProxy.swift
15-
internal init(unprotectedAPIKey: String) {
16+
internal init(unprotectedAPIKey: String, baseURL: String? = nil) {
1617
self.unprotectedAPIKey = unprotectedAPIKey
18+
self.baseURL = baseURL ?? "https://api.anthropic.com"
1719
}
1820

1921
/// Initiates a non-streaming request to /v1/messages.
@@ -36,7 +38,7 @@ open class AnthropicDirectService: AnthropicService, DirectService {
3638
additionalHeaders["anthropic-beta"] = "pdfs-2024-09-25"
3739
}
3840
let request = try AIProxyURLRequest.createDirect(
39-
baseURL: "https://api.anthropic.com",
41+
baseURL: self.baseURL,
4042
path: "/v1/messages",
4143
body: try body.serialize(),
4244
verb: .post,
@@ -66,7 +68,7 @@ open class AnthropicDirectService: AnthropicService, DirectService {
6668
additionalHeaders["anthropic-beta"] = "pdfs-2024-09-25"
6769
}
6870
let request = try AIProxyURLRequest.createDirect(
69-
baseURL: "https://api.anthropic.com",
71+
baseURL: self.baseURL,
7072
path: "/v1/messages",
7173
body: try body.serialize(),
7274
verb: .post,

Sources/AIProxy/DeepSeek/DeepSeekDirectService.swift

+6-3
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@ import Foundation
99

1010
open class DeepSeekDirectService: DeepSeekService, DirectService {
1111
private let unprotectedAPIKey: String
12+
private let baseURL: String
1213

1314
/// This initializer is not public on purpose.
1415
/// Customers are expected to use the factory `AIProxy.directDeepSeekService` defined in AIProxy.swift
1516
internal init(
16-
unprotectedAPIKey: String
17+
unprotectedAPIKey: String,
18+
baseURL: String? = nil
1719
) {
1820
self.unprotectedAPIKey = unprotectedAPIKey
21+
self.baseURL = baseURL ?? "https://api.deepseek.com"
1922
}
2023

2124
/// Initiates a non-streaming chat completion request to /chat/completions.
@@ -34,7 +37,7 @@ open class DeepSeekDirectService: DeepSeekService, DirectService {
3437
body.stream = false
3538
body.streamOptions = nil
3639
var request = try AIProxyURLRequest.createDirect(
37-
baseURL: "https://api.deepseek.com",
40+
baseURL: self.baseURL,
3841
path: "/chat/completions",
3942
body: try body.serialize(),
4043
verb: .post,
@@ -64,7 +67,7 @@ open class DeepSeekDirectService: DeepSeekService, DirectService {
6467
body.stream = true
6568
body.streamOptions = .init(includeUsage: true)
6669
var request = try AIProxyURLRequest.createDirect(
67-
baseURL: "https://api.deepseek.com",
70+
baseURL: self.baseURL,
6871
path: "/chat/completions",
6972
body: try body.serialize(),
7073
verb: .post,

Sources/AIProxy/Groq/GroqDirectService.swift

+7-4
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@ import Foundation
99

1010
open class GroqDirectService: GroqService, DirectService {
1111
private let unprotectedAPIKey: String
12+
private let baseURL: String
1213

1314
/// This initializer is not public on purpose.
1415
/// Customers are expected to use the factory `AIProxy.groqDirectService` defined in AIProxy.swift
1516
internal init(
16-
unprotectedAPIKey: String
17+
unprotectedAPIKey: String,
18+
baseURL: String? = nil
1719
) {
1820
self.unprotectedAPIKey = unprotectedAPIKey
21+
self.baseURL = baseURL ?? "https://api.groq.com"
1922
}
2023

2124
/// Initiates a non-streaming chat completion request to Groq
@@ -31,7 +34,7 @@ open class GroqDirectService: GroqService, DirectService {
3134
var body = body
3235
body.stream = false
3336
let request = try AIProxyURLRequest.createDirect(
34-
baseURL: "https://api.groq.com",
37+
baseURL: self.baseURL,
3538
path: "/openai/v1/chat/completions",
3639
body: try body.serialize(),
3740
verb: .post,
@@ -56,7 +59,7 @@ open class GroqDirectService: GroqService, DirectService {
5659
var body = body
5760
body.stream = true
5861
let request = try AIProxyURLRequest.createDirect(
59-
baseURL: "https://api.groq.com",
62+
baseURL: self.baseURL,
6063
path: "/openai/v1/chat/completions",
6164
body: try body.serialize(),
6265
verb: .post,
@@ -80,7 +83,7 @@ open class GroqDirectService: GroqService, DirectService {
8083
) async throws -> GroqTranscriptionResponseBody {
8184
let boundary = UUID().uuidString
8285
let request = try AIProxyURLRequest.createDirect(
83-
baseURL: "https://api.groq.com",
86+
baseURL: self.baseURL,
8487
path: "/openai/v1/audio/transcriptions",
8588
body: formEncode(body, boundary),
8689
verb: .post,

Sources/AIProxy/OpenAI/OpenAIDirectService.swift

+12-9
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,18 @@ import Foundation
1010
open class OpenAIDirectService: OpenAIService, DirectService {
1111
private let unprotectedAPIKey: String
1212
private let requestFormat: OpenAIRequestFormat
13+
private let baseURL: String
1314

1415
/// This initializer is not public on purpose.
1516
/// Customers are expected to use the factory `AIProxy.directOpenAIService` defined in AIProxy.swift
1617
internal init(
1718
unprotectedAPIKey: String,
18-
requestFormat: OpenAIRequestFormat = .standard
19+
requestFormat: OpenAIRequestFormat = .standard,
20+
baseURL: String? = nil
1921
) {
2022
self.unprotectedAPIKey = unprotectedAPIKey
2123
self.requestFormat = requestFormat
24+
self.baseURL = baseURL ?? "https://api.openai.com"
2225
}
2326

2427
/// Initiates a non-streaming chat completion request to /v1/chat/completions.
@@ -37,7 +40,7 @@ open class OpenAIDirectService: OpenAIService, DirectService {
3740
body.stream = false
3841
body.streamOptions = nil
3942
var request = try AIProxyURLRequest.createDirect(
40-
baseURL: "https://api.openai.com",
43+
baseURL: self.baseURL,
4144
path: self.resolvedPath("chat/completions"),
4245
body: try body.serialize(),
4346
verb: .post,
@@ -66,7 +69,7 @@ open class OpenAIDirectService: OpenAIService, DirectService {
6669
body.stream = true
6770
body.streamOptions = .init(includeUsage: true)
6871
var request = try AIProxyURLRequest.createDirect(
69-
baseURL: "https://api.openai.com",
72+
baseURL: self.baseURL,
7073
path: self.resolvedPath("chat/completions"),
7174
body: try body.serialize(),
7275
verb: .post,
@@ -90,7 +93,7 @@ open class OpenAIDirectService: OpenAIService, DirectService {
9093
body: OpenAICreateImageRequestBody
9194
) async throws -> OpenAICreateImageResponseBody {
9295
let request = try AIProxyURLRequest.createDirect(
93-
baseURL: "https://api.openai.com",
96+
baseURL: self.baseURL,
9497
path: self.resolvedPath("images/generations"),
9598
body: try body.serialize(),
9699
verb: .post,
@@ -114,7 +117,7 @@ open class OpenAIDirectService: OpenAIService, DirectService {
114117
) async throws -> OpenAICreateTranscriptionResponseBody {
115118
let boundary = UUID().uuidString
116119
let request = try AIProxyURLRequest.createDirect(
117-
baseURL: "https://api.openai.com",
120+
baseURL: self.baseURL,
118121
path: self.resolvedPath("audio/transcriptions"),
119122
body: formEncode(body, boundary),
120123
verb: .post,
@@ -148,7 +151,7 @@ open class OpenAIDirectService: OpenAIService, DirectService {
148151
body: OpenAITextToSpeechRequestBody
149152
) async throws -> Data {
150153
let request = try AIProxyURLRequest.createDirect(
151-
baseURL: "https://api.openai.com",
154+
baseURL: self.baseURL,
152155
path: self.resolvedPath("audio/speech"),
153156
body: try body.serialize(),
154157
verb: .post,
@@ -175,7 +178,7 @@ open class OpenAIDirectService: OpenAIService, DirectService {
175178
body: OpenAIModerationRequestBody
176179
) async throws -> OpenAIModerationResponseBody {
177180
let request = try AIProxyURLRequest.createDirect(
178-
baseURL: "https://api.openai.com",
181+
baseURL: self.baseURL,
179182
path: self.resolvedPath("moderations"),
180183
body: try body.serialize(),
181184
verb: .post,
@@ -198,7 +201,7 @@ open class OpenAIDirectService: OpenAIService, DirectService {
198201
body: OpenAIEmbeddingRequestBody
199202
) async throws -> OpenAIEmbeddingResponseBody {
200203
let request = try AIProxyURLRequest.createDirect(
201-
baseURL: "https://api.openai.com",
204+
baseURL: self.baseURL,
202205
path: self.resolvedPath("embeddings"),
203206
body: try body.serialize(),
204207
verb: .post,
@@ -228,7 +231,7 @@ open class OpenAIDirectService: OpenAIService, DirectService {
228231
) async throws -> OpenAIRealtimeSession {
229232
aiproxyCallerDesiredLogLevel = logLevel
230233
let request = try AIProxyURLRequest.createDirect(
231-
baseURL: "https://api.openai.com",
234+
baseURL: self.baseURL,
232235
path: "/v1/realtime?model=\(model)",
233236
body: nil,
234237
verb: .get,

Sources/AIProxy/OpenRouter/OpenRouterDirectService.swift

+5-3
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ import Foundation
99

1010
open class OpenRouterDirectService: OpenRouterService, DirectService {
1111
private let unprotectedAPIKey: String
12+
private let baseURL: String
1213

1314
/// This initializer is not public on purpose.
1415
/// Customers are expected to use the factory `AIProxy.openRouterDirectService` defined in AIProxy.swift
15-
internal init(unprotectedAPIKey: String) {
16+
internal init(unprotectedAPIKey: String, baseURL: String? = nil) {
1617
self.unprotectedAPIKey = unprotectedAPIKey
18+
self.baseURL = baseURL ?? "https://openrouter.ai"
1719
}
1820

1921
/// Initiates a non-streaming chat completion request to /api/v1/chat/completions.
@@ -33,7 +35,7 @@ open class OpenRouterDirectService: OpenRouterService, DirectService {
3335
body.stream = false
3436
body.streamOptions = nil
3537
var request = try AIProxyURLRequest.createDirect(
36-
baseURL: "https://openrouter.ai",
38+
baseURL: self.baseURL,
3739
path: "/api/v1/chat/completions",
3840
body: body.serialize(),
3941
verb: .post,
@@ -63,7 +65,7 @@ open class OpenRouterDirectService: OpenRouterService, DirectService {
6365
body.stream = true
6466
body.streamOptions = .init(includeUsage: true)
6567
var request = try AIProxyURLRequest.createDirect(
66-
baseURL: "https://openrouter.ai",
68+
baseURL: self.baseURL,
6769
path: "/api/v1/chat/completions",
6870
body: try body.serialize(),
6971
verb: .post,

0 commit comments

Comments
 (0)