Skip to content

Commit d403314

Browse files
committed
Add settings for OpenAI in the host app
1 parent f6d9d45 commit d403314

File tree

5 files changed

+205
-1
lines changed

5 files changed

+205
-1
lines changed

Copilot for Xcode.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
C882175A294187E100A22FD3 /* Client in Frameworks */ = {isa = PBXBuildFile; productRef = C8821759294187E100A22FD3 /* Client */; };
4747
C882175C294187EF00A22FD3 /* Client in Frameworks */ = {isa = PBXBuildFile; productRef = C882175B294187EF00A22FD3 /* Client */; };
4848
C8C8B60929AFA35F00034BEE /* CopilotForXcodeExtensionService.app in Embed XPCService */ = {isa = PBXBuildFile; fileRef = C861E60E2994F6070056CB02 /* CopilotForXcodeExtensionService.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
49+
C8EE079D29CC21300043B6D9 /* AccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8EE079C29CC21300043B6D9 /* AccountView.swift */; };
50+
C8EE079F29CC25C20043B6D9 /* OpenAIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8EE079E29CC25C20043B6D9 /* OpenAIView.swift */; };
4951
/* End PBXBuildFile section */
5052

5153
/* Begin PBXContainerItemProxy section */
@@ -188,6 +190,8 @@
188190
C87F3E61293DD004008523E8 /* Styles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Styles.swift; sourceTree = "<group>"; };
189191
C887BC832965D96000931567 /* DEVELOPMENT.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = DEVELOPMENT.md; sourceTree = "<group>"; };
190192
C8CD828229B88006008D044D /* TestPlan.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = TestPlan.xctestplan; sourceTree = "<group>"; };
193+
C8EE079C29CC21300043B6D9 /* AccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountView.swift; sourceTree = "<group>"; };
194+
C8EE079E29CC25C20043B6D9 /* OpenAIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenAIView.swift; sourceTree = "<group>"; };
191195
/* End PBXFileReference section */
192196

193197
/* Begin PBXFrameworksBuildPhase section */
@@ -298,6 +302,8 @@
298302
C83B2B81293DC38400C5ACCD /* LaunchAgentView.swift */,
299303
C83B2B7B293D9FB400C5ACCD /* CopilotView.swift */,
300304
C83B2B7D293DA0CA00C5ACCD /* AppInfoView.swift */,
305+
C8EE079C29CC21300043B6D9 /* AccountView.swift */,
306+
C8EE079E29CC25C20043B6D9 /* OpenAIView.swift */,
301307
C83B2B7F293DA1B600C5ACCD /* InstructionView.swift */,
302308
C841BB232994CAD400B0B336 /* SettingsView.swift */,
303309
C87F3E61293DD004008523E8 /* Styles.swift */,
@@ -531,7 +537,9 @@
531537
C87F3E60293DC600008523E8 /* Section.swift in Sources */,
532538
C87F3E62293DD004008523E8 /* Styles.swift in Sources */,
533539
C83B2B82293DC38400C5ACCD /* LaunchAgentView.swift in Sources */,
540+
C8EE079D29CC21300043B6D9 /* AccountView.swift in Sources */,
534541
C83B2B7E293DA0CA00C5ACCD /* AppInfoView.swift in Sources */,
542+
C8EE079F29CC25C20043B6D9 /* OpenAIView.swift in Sources */,
535543
C841BB242994CAD400B0B336 /* SettingsView.swift in Sources */,
536544
C83B2B80293DA1B600C5ACCD /* InstructionView.swift in Sources */,
537545
C83B2B7C293D9FB400C5ACCD /* CopilotView.swift in Sources */,
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import AppKit
2+
import Client
3+
import CopilotModel
4+
import SwiftUI
5+
6+
struct AccountView: View {
7+
enum Location {
8+
case account
9+
case gitHubCopilot
10+
case openAI
11+
}
12+
13+
@State var location: Location = .account
14+
15+
func navigate(to: Location) {
16+
withAnimation(.easeInOut(duration: 0.2)) {
17+
location = to
18+
}
19+
}
20+
21+
var body: some View {
22+
Section {
23+
switch location {
24+
case .account:
25+
VStack(alignment: .leading, spacing: 8) {
26+
Text("Accounts")
27+
.font(.title)
28+
.padding(.bottom, 12)
29+
30+
HStack {
31+
Button {
32+
navigate(to: .gitHubCopilot)
33+
} label: {
34+
Text("GitHub Copilot")
35+
}.buttonStyle(CopilotButtonStyle())
36+
37+
Button {
38+
navigate(to: .openAI)
39+
} label: {
40+
Text("OpenAI")
41+
}.buttonStyle(CopilotButtonStyle())
42+
43+
Spacer()
44+
}
45+
}
46+
case .gitHubCopilot:
47+
ChildPage(content: {
48+
CopilotView()
49+
}, onBackButtonClick: {
50+
navigate(to: .account)
51+
})
52+
case .openAI:
53+
ChildPage(content: {
54+
OpenAIView()
55+
}, onBackButtonClick: {
56+
navigate(to: .account)
57+
})
58+
}
59+
}
60+
}
61+
62+
struct ChildPage<V: View>: View {
63+
var content: () -> V
64+
var onBackButtonClick: () -> Void
65+
var body: some View {
66+
VStack(alignment: .leading) {
67+
Button(action: onBackButtonClick) {
68+
HStack {
69+
Image(systemName: "chevron.left")
70+
Text("Accounts")
71+
}
72+
.font(.title3)
73+
}
74+
.buttonStyle(.plain)
75+
content()
76+
}
77+
}
78+
}
79+
}
80+
81+
struct AccountView_Previews: PreviewProvider {
82+
static var previews: some View {
83+
VStack(alignment: .leading, spacing: 8) {
84+
AccountView()
85+
86+
AccountView(location: .gitHubCopilot)
87+
88+
AccountView(location: .openAI)
89+
}
90+
.frame(height: 800)
91+
.padding(.all, 8)
92+
.background(Color.black)
93+
}
94+
}

Copilot for Xcode/ContentView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ struct ContentView: View {
1414
VStack(alignment: .leading, spacing: 8) {
1515
AppInfoView()
1616
LaunchAgentView()
17-
CopilotView()
17+
AccountView()
1818
SettingsView()
1919
InstructionView()
2020
Spacer()

Copilot for Xcode/OpenAIView.swift

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import AppKit
2+
import Client
3+
import CopilotModel
4+
import Preferences
5+
import SwiftUI
6+
7+
final class OpenAIViewSettings: ObservableObject {
8+
@AppStorage(\.openAIAPIKey) var openAIAPIKey: String
9+
@AppStorage(\.chatGPTModel) var chatGPTModel: String
10+
@AppStorage(\.chatGPTEndpoint) var chatGPTEndpoint: String
11+
init() {}
12+
}
13+
14+
struct OpenAIView: View {
15+
let apiKeyURL = URL(string: "https://platform.openai.com/account/api-keys")!
16+
let modelURL = URL(
17+
string: "https://platform.openai.com/docs/models/model-endpoint-compatibility"
18+
)!
19+
@Environment(\.openURL) var openURL
20+
@StateObject var settings = OpenAIViewSettings()
21+
22+
var body: some View {
23+
Section {
24+
VStack(alignment: .leading, spacing: 8) {
25+
Text("OpenAI")
26+
.font(.title)
27+
.padding(.bottom, 12)
28+
29+
Form {
30+
HStack {
31+
Text("OpenAI API Key")
32+
TextField(text: $settings.openAIAPIKey, prompt: Text("sk-*")) {
33+
EmptyView()
34+
}.textFieldStyle(.copilot)
35+
Button(action: {
36+
openURL(apiKeyURL)
37+
}) {
38+
Image(systemName: "questionmark.circle.fill")
39+
}
40+
.buttonStyle(.plain)
41+
}
42+
43+
HStack {
44+
Text("ChatGPT Model")
45+
TextField(text: $settings.chatGPTModel, prompt: Text("gpt-3.5-turbo")) {
46+
EmptyView()
47+
}.textFieldStyle(.copilot)
48+
49+
Button(action: {
50+
openURL(modelURL)
51+
}) {
52+
Image(systemName: "questionmark.circle.fill")
53+
}
54+
.buttonStyle(.plain)
55+
}
56+
57+
HStack {
58+
Text("ChatGPT Endpoint")
59+
TextField(
60+
text: $settings.chatGPTEndpoint,
61+
prompt: Text("https://api.openai.com/v1/chat/completions")
62+
) {
63+
EmptyView()
64+
}.textFieldStyle(.copilot)
65+
}
66+
}
67+
}
68+
}
69+
}
70+
}
71+
72+
struct OpenAIView_Previews: PreviewProvider {
73+
static var previews: some View {
74+
VStack(alignment: .leading, spacing: 8) {
75+
OpenAIView()
76+
}
77+
.frame(height: 800)
78+
.padding(.all, 8)
79+
.background(Color.black)
80+
}
81+
}

Core/Sources/Preferences/Keys.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,25 @@ public struct UserDefaultPreferenceKeys {
6464
}
6565

6666
public var widgetColorScheme: WidgetColorSchemeKey { .init() }
67+
68+
public struct OpenAIAPIKey: UserDefaultPreferenceKey {
69+
public let defaultValue = ""
70+
public let key = "OpenAIAPIKey"
71+
}
72+
73+
public var openAIAPIKey: OpenAIAPIKey { .init() }
74+
75+
public struct ChatGPTEndpoint: UserDefaultPreferenceKey {
76+
public let defaultValue = ""
77+
public let key = "ChatGPTEndpoint"
78+
}
79+
80+
public var chatGPTEndpoint: ChatGPTEndpoint { .init() }
81+
82+
public struct ChatGPTModel: UserDefaultPreferenceKey {
83+
public let defaultValue = ""
84+
public let key = "ChatGPTModel"
85+
}
86+
87+
public var chatGPTModel: ChatGPTModel { .init() }
6788
}

0 commit comments

Comments
 (0)