Skip to content

Commit d413bbf

Browse files
committed
feature: add completions sample
1 parent 025f32c commit d413bbf

File tree

6 files changed

+228
-2
lines changed

6 files changed

+228
-2
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//
2+
// CompletionsView.swift
3+
// Y-Chat
4+
//
5+
// Created by Koji Osugi on 11/04/23.
6+
// Copyright © 2023 orgName. All rights reserved.
7+
//
8+
9+
import SwiftUI
10+
11+
struct CompletionsView: View {
12+
@ObservedObject
13+
private var viewModel: CompletionsViewModel
14+
15+
init(viewModel: CompletionsViewModel = .init()) {
16+
self.viewModel = viewModel
17+
}
18+
19+
var body: some View {
20+
VStack(spacing: 0) {
21+
TextField(text: $viewModel.input) {
22+
Text("Write a tagline for an ice cream shop.")
23+
.foregroundColor(.text3)
24+
.style(.mediumBody)
25+
}
26+
.textFieldStyle(DefaultTextFieldStyle())
27+
.disabled(viewModel.isLoading)
28+
.opacity(viewModel.isLoading ? 0.4 : 1)
29+
ButtonContained(
30+
"Submit",
31+
isEnabled: !viewModel.input.isEmpty
32+
)
33+
.padding(.top, 16)
34+
.padding(.bottom, 24)
35+
OutputBox(states: [])
36+
}
37+
.padding(16)
38+
.fullScreen()
39+
}
40+
}
41+
42+
struct CompletionsView_Previews: PreviewProvider {
43+
static var previews: some View {
44+
CompletionsView()
45+
}
46+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//
2+
// CompletionsViewModel.swift
3+
// Y-Chat
4+
//
5+
// Created by Koji Osugi on 11/04/23.
6+
// Copyright © 2023 orgName. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import YChat
11+
12+
internal class CompletionsViewModel: ObservableObject {
13+
@Published
14+
var input: String = ""
15+
16+
@Published
17+
var isLoading: Bool = false
18+
19+
@Published
20+
var outputBoxStates: [OutputState] = []
21+
22+
private var yChat: YChat {
23+
YChatCompanion.shared.create(apiKey: Config.apiKey)
24+
}
25+
26+
@MainActor
27+
func fetchListModels() {
28+
let completions = yChat.completion()
29+
.setInput(input: input)
30+
outputBoxStates = []
31+
outputBoxStates.append(OutputState.text(text: input))
32+
Task.init {
33+
34+
do {
35+
let result = try await completions.execute()
36+
37+
} catch {
38+
39+
}
40+
}
41+
}
42+
}

sample/ios/YChatApp/UI/Component/Button/ButtonContained.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,33 @@ import SwiftUI
1111
struct ButtonContained: View {
1212
private var text: String
1313
private var onAction: () -> Void
14+
private var isEnabled: Bool
15+
private var backgroundColor: Color {
16+
if isEnabled { return Color.accent } else { return Color.primary5 }
17+
}
18+
private var foregroundColor: Color {
19+
if isEnabled { return Color.onAccent } else { return Color.primary4 }
20+
}
1421

1522
init(
1623
_ text: String,
24+
isEnabled: Bool = true,
1725
onAction: @escaping () -> Void = {}
1826
) {
1927
self.text = text
28+
self.isEnabled = isEnabled
2029
self.onAction = onAction
2130
}
2231

2332
var body: some View {
2433
Button(action: { onAction() }) {
2534
Text(text.capitalized)
26-
.foregroundColor(.onAccent)
35+
.foregroundColor(foregroundColor)
2736
.style(.smallTitle)
2837
.frame(minWidth: 0, maxWidth: .infinity)
2938
.padding()
3039
}
31-
.background(Color.accent)
40+
.background(backgroundColor)
3241
.cornerRadius(8)
3342
}
3443
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//
2+
// OutputBox.swift
3+
// Y-Chat
4+
//
5+
// Created by Koji Osugi on 11/04/23.
6+
// Copyright © 2023 orgName. All rights reserved.
7+
//
8+
9+
import SwiftUI
10+
11+
enum OutputState: Hashable {
12+
case text(text: String, isMarked: Bool = false)
13+
case error
14+
case loading
15+
}
16+
17+
struct OutputBox: View {
18+
var states: [OutputState]
19+
20+
var body: some View {
21+
VStack(alignment: .leading, spacing: 16) {
22+
ForEach(states, id: \.self) {
23+
switch $0 {
24+
case .error:
25+
errorState()
26+
case .loading:
27+
TypingLoading()
28+
case .text(let text, let isMarked):
29+
textRow(text: text, isMarked: isMarked)
30+
}
31+
}
32+
}
33+
.frame(minHeight: 200, alignment: .top)
34+
.frame(maxWidth: .infinity, alignment: .leading)
35+
.padding(.horizontal, 16)
36+
.padding(.vertical, 20)
37+
.background(Color.primary5)
38+
.cornerRadius(8)
39+
.overlay(
40+
RoundedRectangle(cornerRadius: 8)
41+
.stroke(Color.primary4, lineWidth: 1)
42+
)
43+
}
44+
45+
@ViewBuilder
46+
private func textRow(text: String, isMarked: Bool) -> some View {
47+
if isMarked {
48+
Text(text)
49+
.foregroundColor(Color.black)
50+
.style(.mediumBody)
51+
.background(Color.green2)
52+
} else {
53+
Text(text)
54+
.foregroundColor(Color.text1)
55+
.style(.mediumBody)
56+
}
57+
}
58+
59+
@ViewBuilder
60+
private func errorState() -> some View {
61+
HStack(spacing: 8) {
62+
Icon.warning.image(.red, size: 16)
63+
Text("Something went wrong. Try again.")
64+
.style(.mediumBody)
65+
}
66+
}
67+
}
68+
69+
struct OutputBox_Previews: PreviewProvider {
70+
static var previews: some View {
71+
let states = [
72+
OutputState.text(
73+
text: "Write a tagline for an ice cream shop."
74+
),
75+
OutputState.loading,
76+
OutputState.text(
77+
text: "We serve up smiles with every scoop!",
78+
isMarked: true
79+
),
80+
OutputState.error
81+
]
82+
OutputBox(states: states)
83+
.padding(.horizontal, 16)
84+
}
85+
}

sample/ios/YChatApp/UI/Theme/Color.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@
99
import SwiftUI
1010

1111
extension Color {
12+
static var green1: Color {
13+
Color("Green1")
14+
}
15+
16+
static var green2: Color {
17+
Color("Green2")
18+
}
19+
1220
static var text1: Color {
1321
Color("Text1")
1422
}

sample/ios/ychat-ios.xcodeproj/project.pbxproj

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
486C6F8A29E612D0006E427E /* ItemMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 486C6F8929E612D0006E427E /* ItemMenu.swift */; };
2222
486C6F8D29E61520006E427E /* ModelsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 486C6F8C29E61520006E427E /* ModelsView.swift */; };
2323
486C6F9029E615A6006E427E /* ModelsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 486C6F8F29E615A6006E427E /* ModelsViewModel.swift */; };
24+
486C6F9429E61D4E006E427E /* OutputBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 486C6F9329E61D4E006E427E /* OutputBox.swift */; };
25+
486C6F9729E6544E006E427E /* CompletionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 486C6F9629E6544E006E427E /* CompletionsView.swift */; };
26+
486C6F9A29E655D1006E427E /* CompletionsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 486C6F9929E655D1006E427E /* CompletionsViewModel.swift */; };
2427
488448D9297B8419005B8A24 /* ChatCompletionsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 488448D8297B8419005B8A24 /* ChatCompletionsViewModel.swift */; };
2528
488448DD297B8DD2005B8A24 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 488448DC297B8DD2005B8A24 /* Color.swift */; };
2629
488448DF297B8DF6005B8A24 /* Typography.swift in Sources */ = {isa = PBXBuildFile; fileRef = 488448DE297B8DF6005B8A24 /* Typography.swift */; };
@@ -69,6 +72,9 @@
6972
486C6F8929E612D0006E427E /* ItemMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemMenu.swift; sourceTree = "<group>"; };
7073
486C6F8C29E61520006E427E /* ModelsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelsView.swift; sourceTree = "<group>"; };
7174
486C6F8F29E615A6006E427E /* ModelsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelsViewModel.swift; sourceTree = "<group>"; };
75+
486C6F9329E61D4E006E427E /* OutputBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutputBox.swift; sourceTree = "<group>"; };
76+
486C6F9629E6544E006E427E /* CompletionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletionsView.swift; sourceTree = "<group>"; };
77+
486C6F9929E655D1006E427E /* CompletionsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletionsViewModel.swift; sourceTree = "<group>"; };
7278
488448D8297B8419005B8A24 /* ChatCompletionsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatCompletionsViewModel.swift; sourceTree = "<group>"; };
7379
488448DC297B8DD2005B8A24 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = "<group>"; };
7480
488448DE297B8DF6005B8A24 /* Typography.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Typography.swift; sourceTree = "<group>"; };
@@ -171,6 +177,31 @@
171177
path = ViewModel;
172178
sourceTree = "<group>";
173179
};
180+
486C6F9229E61D3F006E427E /* Output */ = {
181+
isa = PBXGroup;
182+
children = (
183+
486C6F9329E61D4E006E427E /* OutputBox.swift */,
184+
);
185+
path = Output;
186+
sourceTree = "<group>";
187+
};
188+
486C6F9529E6543B006E427E /* Completions */ = {
189+
isa = PBXGroup;
190+
children = (
191+
486C6F9829E655C4006E427E /* ViewModel */,
192+
486C6F9629E6544E006E427E /* CompletionsView.swift */,
193+
);
194+
path = Completions;
195+
sourceTree = "<group>";
196+
};
197+
486C6F9829E655C4006E427E /* ViewModel */ = {
198+
isa = PBXGroup;
199+
children = (
200+
486C6F9929E655D1006E427E /* CompletionsViewModel.swift */,
201+
);
202+
path = ViewModel;
203+
sourceTree = "<group>";
204+
};
174205
488448DA297B8D19005B8A24 /* App */ = {
175206
isa = PBXGroup;
176207
children = (
@@ -204,6 +235,7 @@
204235
488448E1297B8EF9005B8A24 /* Component */ = {
205236
isa = PBXGroup;
206237
children = (
238+
486C6F9229E61D3F006E427E /* Output */,
207239
486C6F8829E612C4006E427E /* ItemMenu */,
208240
486C6F8129E11309006E427E /* BallonMessage */,
209241
486C6F7E29E08D39006E427E /* Loading */,
@@ -265,6 +297,7 @@
265297
488448F7297CDFB1005B8A24 /* Features */ = {
266298
isa = PBXGroup;
267299
children = (
300+
486C6F9529E6543B006E427E /* Completions */,
268301
486C6F8B29E61515006E427E /* Models */,
269302
488448EB297CAC28005B8A24 /* ChatCompletions */,
270303
);
@@ -523,7 +556,10 @@
523556
488448FF297CE035005B8A24 /* AppRouter.swift in Sources */,
524557
488448F6297CDF67005B8A24 /* SideMenu.swift in Sources */,
525558
2152FB042600AC8F00CF470E /* YChatApp.swift in Sources */,
559+
486C6F9429E61D4E006E427E /* OutputBox.swift in Sources */,
560+
486C6F9729E6544E006E427E /* CompletionsView.swift in Sources */,
526561
488448E8297B9198005B8A24 /* ViewModifer.swift in Sources */,
562+
486C6F9A29E655D1006E427E /* CompletionsViewModel.swift in Sources */,
527563
7555FF83242A565900829871 /* ChatCompletionsView.swift in Sources */,
528564
488448E6297B9116005B8A24 /* RoundedCorner.swift in Sources */,
529565
489A546D297F93F700A6532C /* Config.swift in Sources */,

0 commit comments

Comments
 (0)