Skip to content

Commit 37ce051

Browse files
committed
Feat Is base URL with full path toggle in ChatModelEditView
1 parent 647ea5d commit 37ce051

File tree

9 files changed

+83
-32
lines changed

9 files changed

+83
-32
lines changed

Core/Sources/HostApp/AccountSettings/ChatModelManagement/ChatModelEdit.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ struct ChatModelEdit: ReducerProtocol {
1616
@BindingState var modelName: String = ""
1717
var apiKeyName: String { apiKeySelection.apiKeyName }
1818
var baseURL: String { baseURLSelection.baseURL }
19+
var isFullURL: Bool { baseURLSelection.isFullURL }
1920
var availableModelNames: [String] = []
2021
var availableAPIKeys: [String] = []
2122
var isTesting = false
@@ -76,6 +77,7 @@ struct ChatModelEdit: ReducerProtocol {
7677
info: .init(
7778
apiKeyName: state.apiKeyName,
7879
baseURL: state.baseURL,
80+
isFullURL: state.isFullURL,
7981
maxTokens: state.maxTokens,
8082
supportsFunctionCalling: state.supportsFunctionCalling,
8183
modelName: state.modelName
@@ -171,7 +173,7 @@ extension ChatModelEdit.State {
171173
apiKeyName: model.info.apiKeyName,
172174
apiKeyManagement: .init(availableAPIKeyNames: [model.info.apiKeyName])
173175
),
174-
baseURLSelection: .init(baseURL: model.info.baseURL)
176+
baseURLSelection: .init(baseURL: model.info.baseURL, isFullURL: model.info.isFullURL)
175177
)
176178
}
177179
}
@@ -185,6 +187,7 @@ extension ChatModel {
185187
info: .init(
186188
apiKeyName: state.apiKeyName,
187189
baseURL: state.baseURL.trimmingCharacters(in: .whitespacesAndNewlines),
190+
isFullURL: state.isFullURL,
188191
maxTokens: state.maxTokens,
189192
supportsFunctionCalling: {
190193
if case .googleAI = state.format {

Core/Sources/HostApp/AccountSettings/ChatModelManagement/ChatModelEditView.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,10 @@ struct ChatModelEditView: View {
101101
}
102102
}
103103

104-
func baseURLTextField(prompt: Text?) -> some View {
104+
func baseURLTextField(prompt: Text?, showIsFullURL: Bool = false) -> some View {
105105
BaseURLPicker(
106106
prompt: prompt,
107+
showIsFullURL: showIsFullURL,
107108
store: store.scope(
108109
state: \.baseURLSelection,
109110
action: ChatModelEdit.Action.baseURLSelection
@@ -260,7 +261,10 @@ struct ChatModelEditView: View {
260261

261262
@ViewBuilder
262263
var openAICompatible: some View {
263-
baseURLTextField(prompt: Text("https://"))
264+
baseURLTextField(
265+
prompt: Text("https://"),
266+
showIsFullURL: true
267+
)
264268
apiKeyNamePicker
265269

266270
WithViewStore(
@@ -334,6 +338,7 @@ struct ChatModelEditView: View {
334338
info: .init(
335339
apiKeyName: "key",
336340
baseURL: "apple.com",
341+
isFullURL: false,
337342
maxTokens: 3000,
338343
supportsFunctionCalling: false,
339344
modelName: "gpt-3.5-turbo"

Core/Sources/HostApp/AccountSettings/EmbeddingModelManagement/EmbeddingModelEdit.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ struct EmbeddingModelEdit: ReducerProtocol {
1515
@BindingState var modelName: String = ""
1616
var apiKeyName: String { apiKeySelection.apiKeyName }
1717
var baseURL: String { baseURLSelection.baseURL }
18+
var isFullURL: Bool { baseURLSelection.isFullURL }
1819
var availableModelNames: [String] = []
1920
var availableAPIKeys: [String] = []
2021
var isTesting = false
@@ -75,6 +76,7 @@ struct EmbeddingModelEdit: ReducerProtocol {
7576
info: .init(
7677
apiKeyName: state.apiKeyName,
7778
baseURL: state.baseURL,
79+
isFullURL: state.isFullURL,
7880
maxTokens: state.maxTokens,
7981
modelName: state.modelName
8082
)
@@ -157,7 +159,7 @@ extension EmbeddingModelEdit.State {
157159
apiKeyName: model.info.apiKeyName,
158160
apiKeyManagement: .init(availableAPIKeyNames: [model.info.apiKeyName])
159161
),
160-
baseURLSelection: .init(baseURL: model.info.baseURL)
162+
baseURLSelection: .init(baseURL: model.info.baseURL, isFullURL: model.info.isFullURL)
161163
)
162164
}
163165
}
@@ -171,6 +173,7 @@ extension EmbeddingModel {
171173
info: .init(
172174
apiKeyName: state.apiKeyName,
173175
baseURL: state.baseURL.trimmingCharacters(in: .whitespacesAndNewlines),
176+
isFullURL: state.isFullURL,
174177
maxTokens: state.maxTokens,
175178
modelName: state.modelName.trimmingCharacters(in: .whitespacesAndNewlines)
176179
)

Core/Sources/HostApp/AccountSettings/EmbeddingModelManagement/EmbeddingModelEditView.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,10 @@ struct EmbeddingModelEditView: View {
9696
}
9797
}
9898

99-
func baseURLTextField(prompt: Text?) -> some View {
99+
func baseURLTextField(prompt: Text?, showIsFullURL: Bool = false) -> some View {
100100
BaseURLPicker(
101101
prompt: prompt,
102+
showIsFullURL: showIsFullURL,
102103
store: store.scope(
103104
state: \.baseURLSelection,
104105
action: EmbeddingModelEdit.Action.baseURLSelection
@@ -223,7 +224,10 @@ struct EmbeddingModelEditView: View {
223224

224225
@ViewBuilder
225226
var openAICompatible: some View {
226-
baseURLTextField(prompt: Text("https://"))
227+
baseURLTextField(
228+
prompt: Text("https://"),
229+
showIsFullURL: true
230+
)
227231
apiKeyNamePicker
228232

229233
WithViewStore(

Core/Sources/HostApp/AccountSettings/SharedModelManagement/BaseURLPicker.swift

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,51 @@ import SwiftUI
33

44
struct BaseURLPicker: View {
55
let prompt: Text?
6+
let showIsFullURL: Bool
67
let store: StoreOf<BaseURLSelection>
7-
8+
89
var body: some View {
910
WithViewStore(store) { viewStore in
10-
TextField("Base URL", text: viewStore.$baseURL, prompt: prompt)
11-
.overlay(alignment: .trailing) {
12-
Picker(
13-
"",
14-
selection: viewStore.$baseURL,
15-
content: {
16-
if !viewStore.state.availableBaseURLs
17-
.contains(viewStore.state.baseURL),
18-
!viewStore.state.baseURL.isEmpty
19-
{
20-
Text("Custom Value").tag(viewStore.state.baseURL)
21-
}
22-
23-
Text("Empty (Default Value)").tag("")
24-
25-
ForEach(viewStore.state.availableBaseURLs, id: \.self) { baseURL in
26-
Text(baseURL).tag(baseURL)
11+
Group {
12+
TextField("Base URL", text: viewStore.$baseURL, prompt: prompt)
13+
.overlay(alignment: .trailing) {
14+
Picker(
15+
"",
16+
selection: viewStore.$baseURL,
17+
content: {
18+
if !viewStore.state.availableBaseURLs
19+
.contains(viewStore.state.baseURL),
20+
!viewStore.state.baseURL.isEmpty
21+
{
22+
Text("Custom Value").tag(viewStore.state.baseURL)
23+
}
24+
25+
Text("Empty (Default Value)").tag("")
26+
27+
ForEach(viewStore.state.availableBaseURLs, id: \.self) { baseURL in
28+
Text(baseURL).tag(baseURL)
29+
}
2730
}
28-
}
31+
)
32+
.frame(width: 20)
33+
}
34+
if showIsFullURL {
35+
Toggle(
36+
"Is base URL with full path",
37+
isOn: viewStore.$isFullURL
2938
)
30-
.frame(width: 20)
31-
}
32-
.onAppear {
33-
viewStore.send(.appear)
39+
40+
Text(
41+
"Add compatibility API's distinct endpoint structure. For example Perplexity.ai API's URL is https://api.perplexity.ai/chat/completions"
42+
)
43+
.foregroundColor(.secondary)
44+
.font(.callout)
45+
.dynamicHeightTextInFormWorkaround()
3446
}
47+
}
48+
.onAppear {
49+
viewStore.send(.appear)
50+
}
3551
}
3652
}
3753
}

Core/Sources/HostApp/AccountSettings/SharedModelManagement/BaseURLSelection.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import SwiftUI
66
struct BaseURLSelection: ReducerProtocol {
77
struct State: Equatable {
88
@BindingState var baseURL: String = ""
9+
@BindingState var isFullURL: Bool = false
910
var availableBaseURLs: [String] = []
1011
}
1112

Tool/Sources/AIModel/ChatModel.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public struct ChatModel: Codable, Equatable, Identifiable {
2828
public var apiKeyName: String
2929
@FallbackDecoding<EmptyString>
3030
public var baseURL: String
31+
@FallbackDecoding<EmptyBool>
32+
public var isFullURL: Bool
3133
@FallbackDecoding<EmptyInt>
3234
public var maxTokens: Int
3335
@FallbackDecoding<EmptyBool>
@@ -44,13 +46,15 @@ public struct ChatModel: Codable, Equatable, Identifiable {
4446
public init(
4547
apiKeyName: String = "",
4648
baseURL: String = "",
49+
isFullURL: Bool = false,
4750
maxTokens: Int = 4000,
4851
supportsFunctionCalling: Bool = true,
4952
supportsOpenAIAPI2023_11: Bool = false,
5053
modelName: String = ""
5154
) {
5255
self.apiKeyName = apiKeyName
5356
self.baseURL = baseURL
57+
self.isFullURL = isFullURL
5458
self.maxTokens = maxTokens
5559
self.supportsFunctionCalling = supportsFunctionCalling
5660
self.supportsOpenAIAPI2023_11 = supportsOpenAIAPI2023_11
@@ -60,10 +64,15 @@ public struct ChatModel: Codable, Equatable, Identifiable {
6064

6165
public var endpoint: String {
6266
switch format {
63-
case .openAI, .openAICompatible:
67+
case .openAI:
6468
let baseURL = info.baseURL
6569
if baseURL.isEmpty { return "https://api.openai.com/v1/chat/completions" }
66-
return baseURL
70+
return "\(baseURL)/v1/chat/completions"
71+
case .openAICompatible:
72+
let baseURL = info.baseURL
73+
if baseURL.isEmpty { return "https://api.openai.com/v1/chat/completions" }
74+
if info.isFullURL { return baseURL }
75+
return "\(baseURL)/v1/chat/completions"
6776
case .azureOpenAI:
6877
let baseURL = info.baseURL
6978
let deployment = info.azureOpenAIDeploymentName

Tool/Sources/AIModel/EmbeddingModel.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ public struct EmbeddingModel: Codable, Equatable, Identifiable {
2727
public var apiKeyName: String
2828
@FallbackDecoding<EmptyString>
2929
public var baseURL: String
30+
@FallbackDecoding<EmptyBool>
31+
public var isFullURL: Bool
3032
@FallbackDecoding<EmptyInt>
3133
public var maxTokens: Int
3234
@FallbackDecoding<EmptyInt>
@@ -41,12 +43,14 @@ public struct EmbeddingModel: Codable, Equatable, Identifiable {
4143
public init(
4244
apiKeyName: String = "",
4345
baseURL: String = "",
46+
isFullURL: Bool = false,
4447
maxTokens: Int = 8192,
4548
dimensions: Int = 1536,
4649
modelName: String = ""
4750
) {
4851
self.apiKeyName = apiKeyName
4952
self.baseURL = baseURL
53+
self.isFullURL = isFullURL
5054
self.maxTokens = maxTokens
5155
self.dimensions = dimensions
5256
self.modelName = modelName
@@ -55,10 +59,15 @@ public struct EmbeddingModel: Codable, Equatable, Identifiable {
5559

5660
public var endpoint: String {
5761
switch format {
58-
case .openAI, .openAICompatible:
62+
case .openAI:
5963
let baseURL = info.baseURL
6064
if baseURL.isEmpty { return "https://api.openai.com/v1/embeddings" }
6165
return "\(baseURL)/v1/embeddings"
66+
case .openAICompatible:
67+
let baseURL = info.baseURL
68+
if baseURL.isEmpty { return "https://api.openai.com/v1/embeddings" }
69+
if info.isFullURL { return baseURL }
70+
return "\(baseURL)/v1/embeddings"
6271
case .azureOpenAI:
6372
let baseURL = info.baseURL
6473
let deployment = info.azureOpenAIDeploymentName

Tool/Sources/Preferences/Keys.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ public extension UserDefaultPreferenceKeys {
214214
info: .init(
215215
apiKeyName: "",
216216
baseURL: "",
217+
isFullURL: false,
217218
maxTokens: ChatGPTModel.gpt35Turbo.maxToken,
218219
supportsFunctionCalling: true,
219220
modelName: ChatGPTModel.gpt35Turbo.rawValue

0 commit comments

Comments
 (0)