Skip to content

Commit 30b556d

Browse files
committed
Support changing temperature and model from chat tab
1 parent cc0d5d3 commit 30b556d

File tree

4 files changed

+138
-9
lines changed

4 files changed

+138
-9
lines changed

Core/Sources/ChatGPTChatTab/ChatContextMenu.swift

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import SwiftUI
44

55
struct ChatTabItemView: View {
66
@ObservedObject var chat: ChatProvider
7-
7+
88
var body: some View {
99
Text(chat.title)
1010
}
@@ -13,6 +13,9 @@ struct ChatTabItemView: View {
1313
struct ChatContextMenu: View {
1414
@ObservedObject var chat: ChatProvider
1515
@AppStorage(\.customCommands) var customCommands
16+
@AppStorage(\.chatModels) var chatModels
17+
@AppStorage(\.defaultChatFeatureChatModelId) var defaultChatModelId
18+
@AppStorage(\.chatGPTTemperature) var defaultTemperature
1619

1720
var body: some View {
1821
currentSystemPrompt
@@ -21,6 +24,11 @@ struct ChatContextMenu: View {
2124

2225
Divider()
2326

27+
chatModel
28+
temperature
29+
30+
Divider()
31+
2432
customCommandMenu
2533
}
2634

@@ -52,6 +60,89 @@ struct ChatContextMenu: View {
5260
}
5361
}
5462

63+
@ViewBuilder
64+
var chatModel: some View {
65+
Menu("Chat Model") {
66+
Button(action: {
67+
chat.chatModelId = nil
68+
}) {
69+
HStack {
70+
if let defaultModel = chatModels.first(where: { $0.id == defaultChatModelId }) {
71+
Text("Default (\(defaultModel.name))")
72+
if chat.chatModelId == nil {
73+
Image(systemName: "checkmark")
74+
}
75+
} else {
76+
Text("No Model Available")
77+
}
78+
}
79+
}
80+
81+
if let id = chat.chatModelId,
82+
!chatModels.map(\.id).contains(id)
83+
{
84+
Button(action: {
85+
chat.chatModelId = nil
86+
chat.objectWillChange.send()
87+
}) {
88+
HStack {
89+
Text("Default (Selected Model Not Found)")
90+
Image(systemName: "checkmark")
91+
}
92+
}
93+
}
94+
95+
Divider()
96+
97+
ForEach(chatModels, id: \.id) { model in
98+
Button(action: {
99+
chat.chatModelId = model.id
100+
chat.objectWillChange.send()
101+
}) {
102+
HStack {
103+
Text(model.name)
104+
if model.id == chat.chatModelId {
105+
Image(systemName: "checkmark")
106+
}
107+
}
108+
}
109+
}
110+
}
111+
}
112+
113+
@ViewBuilder
114+
var temperature: some View {
115+
Menu("Temperature") {
116+
Button(action: {
117+
chat.temperature = nil
118+
}) {
119+
HStack {
120+
Text(
121+
"Default (\(defaultTemperature.formatted(.number.precision(.fractionLength(1)))))"
122+
)
123+
if chat.temperature == nil {
124+
Image(systemName: "checkmark")
125+
}
126+
}
127+
}
128+
129+
Divider()
130+
131+
ForEach(Array(stride(from: 0.0, through: 2.0, by: 0.1)), id: \.self) { value in
132+
Button(action: {
133+
chat.temperature = value
134+
}) {
135+
HStack {
136+
Text("\(value.formatted(.number.precision(.fractionLength(1))))")
137+
if value == chat.temperature {
138+
Image(systemName: "checkmark")
139+
}
140+
}
141+
}
142+
}
143+
}
144+
}
145+
55146
var customCommandMenu: some View {
56147
Menu("Custom Commands") {
57148
ForEach(
@@ -73,3 +164,4 @@ struct ChatContextMenu: View {
73164
}
74165
}
75166
}
167+

Core/Sources/ChatGPTChatTab/ChatGPTChatTab.swift

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public class ChatGPTChatTab: ChatTab {
4444
public func buildTabItem() -> any View {
4545
ChatTabItemView(chat: provider)
4646
}
47-
47+
4848
public func buildMenu() -> any View {
4949
ChatContextMenu(chat: provider)
5050
}
@@ -95,33 +95,42 @@ public class ChatGPTChatTab: ChatTab {
9595

9696
public func start() {
9797
chatTabViewStore.send(.updateTitle("Chat"))
98-
98+
9999
service.$systemPrompt.removeDuplicates().sink { _ in
100100
Task { @MainActor [weak self] in
101101
self?.chatTabViewStore.send(.tabContentUpdated)
102102
}
103103
}.store(in: &cancellable)
104-
104+
105105
service.$extraSystemPrompt.removeDuplicates().sink { _ in
106106
Task { @MainActor [weak self] in
107107
self?.chatTabViewStore.send(.tabContentUpdated)
108108
}
109109
}.store(in: &cancellable)
110-
110+
111111
provider.$history.sink { [weak self] _ in
112112
Task { @MainActor [weak self] in
113113
if let title = self?.provider.title {
114114
self?.chatTabViewStore.send(.updateTitle(title))
115115
}
116-
self?.chatTabViewStore.send(.tabContentUpdated)
117116
}
118117
}.store(in: &cancellable)
118+
119+
provider.objectWillChange.debounce(for: .seconds(1), scheduler: DispatchQueue.main)
120+
.sink { [weak self] _ in
121+
Task { @MainActor [weak self] in
122+
self?.chatTabViewStore.send(.tabContentUpdated)
123+
}
124+
}.store(in: &cancellable)
119125
}
120126
}
121127

122128
extension ChatProvider {
123129
convenience init(service: ChatService) {
124-
self.init(pluginIdentifiers: service.allPluginCommands)
130+
self.init(
131+
configuration: service.configuration,
132+
pluginIdentifiers: service.allPluginCommands
133+
)
125134

126135
let cancellable = service.objectWillChange.sink { [weak self] in
127136
guard let self else { return }

Core/Sources/ChatGPTChatTab/ChatPanel.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import AppKit
2+
import OpenAIService
23
import MarkdownUI
34
import SharedUIComponents
45
import SwiftUI
@@ -112,7 +113,7 @@ private struct Instruction: View {
112113
Markdown(
113114
"""
114115
Hello, I am your AI programming assistant. I can identify issues, explain and even improve code.
115-
116+
116117
\(
117118
useCodeScopeByDefaultInChatContext
118119
? "Scope **`@code`** is enabled by default."
@@ -398,7 +399,7 @@ struct ChatPanelInputArea: View {
398399
EmptyView()
399400
}
400401
.keyboardShortcut(KeyEquivalent.return, modifiers: [.shift])
401-
402+
402403
Button(action: {
403404
isInputAreaFocused = true
404405
}) {
@@ -580,6 +581,7 @@ struct ChatPanel_Preview: PreviewProvider {
580581

581582
static var previews: some View {
582583
ChatPanel(chat: .init(
584+
configuration: UserPreferenceChatGPTConfiguration().overriding(.init()),
583585
history: ChatPanel_Preview.history,
584586
isReceivingMessage: true
585587
))
@@ -591,6 +593,7 @@ struct ChatPanel_Preview: PreviewProvider {
591593
struct ChatPanel_EmptyChat_Preview: PreviewProvider {
592594
static var previews: some View {
593595
ChatPanel(chat: .init(
596+
configuration: UserPreferenceChatGPTConfiguration().overriding(.init()),
594597
history: [],
595598
isReceivingMessage: false
596599
))
@@ -623,6 +626,7 @@ struct ChatCodeSyntaxHighlighter: CodeSyntaxHighlighter {
623626
struct ChatPanel_InputText_Preview: PreviewProvider {
624627
static var previews: some View {
625628
ChatPanel(chat: .init(
629+
configuration: UserPreferenceChatGPTConfiguration().overriding(.init()),
626630
history: ChatPanel_Preview.history,
627631
isReceivingMessage: false
628632
))
@@ -636,6 +640,7 @@ struct ChatPanel_InputMultilineText_Preview: PreviewProvider {
636640
static var previews: some View {
637641
ChatPanel(
638642
chat: .init(
643+
configuration: UserPreferenceChatGPTConfiguration().overriding(.init()),
639644
history: ChatPanel_Preview.history,
640645
isReceivingMessage: false
641646
),
@@ -650,6 +655,7 @@ struct ChatPanel_InputMultilineText_Preview: PreviewProvider {
650655
struct ChatPanel_Light_Preview: PreviewProvider {
651656
static var previews: some View {
652657
ChatPanel(chat: .init(
658+
configuration: UserPreferenceChatGPTConfiguration().overriding(.init()),
653659
history: ChatPanel_Preview.history,
654660
isReceivingMessage: true
655661
))

Core/Sources/ChatGPTChatTab/ChatProvider.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,28 @@ public final class ChatProvider: ObservableObject {
88
public let id = UUID()
99
@Published public var history: [ChatMessage] = []
1010
@Published public var isReceivingMessage = false
11+
public var temperature: Double? {
12+
get {
13+
configuration.overriding.temperature
14+
}
15+
set {
16+
configuration.overriding.temperature = newValue
17+
objectWillChange.send()
18+
}
19+
}
20+
public var chatModelId: String? {
21+
get {
22+
configuration.overriding.modelId
23+
}
24+
set {
25+
configuration.overriding.modelId = newValue
26+
objectWillChange.send()
27+
}
28+
}
29+
private let configuration: OverridingChatGPTConfiguration
1130
public var pluginIdentifiers: [String] = []
1231
public var systemPrompt = ""
32+
1333
public var title: String {
1434
let defaultTitle = "Chat"
1535
guard let lastMessageText = history
@@ -38,6 +58,7 @@ public final class ChatProvider: ObservableObject {
3858
public var onSetAsExtraPrompt: (MessageID) -> Void
3959

4060
public init(
61+
configuration: OverridingChatGPTConfiguration,
4162
history: [ChatMessage] = [],
4263
isReceivingMessage: Bool = false,
4364
pluginIdentifiers: [String] = [],
@@ -50,6 +71,7 @@ public final class ChatProvider: ObservableObject {
5071
onRunCustomCommand: @escaping (CustomCommand) -> Void = { _ in },
5172
onSetAsExtraPrompt: @escaping (MessageID) -> Void = { _ in }
5273
) {
74+
self.configuration = configuration
5375
self.history = history
5476
self.isReceivingMessage = isReceivingMessage
5577
self.pluginIdentifiers = pluginIdentifiers

0 commit comments

Comments
 (0)