3
3
4
4
import SwiftUI
5
5
6
-
7
6
struct Message : Identifiable {
8
- let id = UUID ( )
9
- var text : String
10
- let isUser : Bool
7
+ let id = UUID ( )
8
+ var text : String
9
+ let isUser : Bool
11
10
}
12
11
13
12
struct ContentView : View {
@@ -18,140 +17,165 @@ struct ContentView: View {
18
17
@State private var showAlert : Bool = false
19
18
@State private var errorMessage : String = " "
20
19
21
- private let generator = GenAIGenerator ( )
22
-
23
- var body : some View {
24
- VStack {
25
- // ChatBubbles
26
- ScrollView {
27
- VStack ( alignment: . leading, spacing: 20 ) {
28
- ForEach ( messages) { message in
29
- ChatBubble ( text: message. text, isUser: message. isUser)
30
- . padding ( . horizontal, 20 )
31
- }
32
- if !stats. isEmpty {
33
- Text ( stats)
34
- . font ( . footnote)
35
- . foregroundColor ( . gray)
36
- . padding ( . horizontal, 20 )
37
- . padding ( . top, 5 )
38
- . multilineTextAlignment ( . center)
39
- }
40
- }
41
- . padding ( . top, 20 )
42
- }
20
+ private let generator = GenAIGenerator ( )
43
21
44
-
45
- // User input
46
- HStack {
47
- TextField ( " Type your message... " , text: $userInput)
48
- . padding ( )
49
- . background ( Color ( . systemGray6) )
50
- . cornerRadius ( 20 )
51
- . padding ( . horizontal)
52
-
53
- Button ( action: {
54
- // Check for non-empty input
55
- guard !userInput. trimmingCharacters ( in: . whitespaces) . isEmpty else { return }
56
-
57
- messages. append ( Message ( text: userInput, isUser: true ) )
58
- messages. append ( Message ( text: " " , isUser: false ) ) // Placeholder for AI response
59
-
60
-
61
- // clear previously generated tokens
62
- SharedTokenUpdater . shared. clearTokens ( )
63
-
64
- let prompt = userInput
65
- userInput = " "
66
- isGenerating = true
67
-
68
-
69
- DispatchQueue . global ( qos: . background) . async {
70
- generator. generate ( prompt)
71
- }
72
- } ) {
73
- Image ( systemName: " paperplane.fill " )
74
- . foregroundColor ( . white)
75
- . padding ( )
76
- . background ( isGenerating ? Color . gray : Color . pastelGreen)
77
- . clipShape ( Circle ( ) )
78
- . padding ( . trailing, 10 )
79
- }
80
- . disabled ( isGenerating)
81
- }
82
- . padding ( . bottom, 20 )
83
- }
84
- . background ( Color ( . systemGroupedBackground) )
85
- . edgesIgnoringSafeArea ( . bottom)
86
- . onReceive ( NotificationCenter . default. publisher ( for: NSNotification . Name ( " TokenGenerationCompleted " ) ) ) { _ in
87
- isGenerating = false // Re-enable the button when token generation is complete
22
+ var body : some View {
23
+ VStack {
24
+ // ChatBubbles
25
+ ScrollView {
26
+ VStack ( alignment: . leading, spacing: 20 ) {
27
+ ForEach ( messages) { message in
28
+ ChatBubble ( text: message. text, isUser: message. isUser)
29
+ . padding ( . horizontal, 20 )
30
+ }
31
+ if !stats. isEmpty {
32
+ Text ( stats)
33
+ . font ( . footnote)
34
+ . foregroundColor ( . gray)
35
+ . padding ( . horizontal, 20 )
36
+ . padding ( . top, 5 )
37
+ . multilineTextAlignment ( . center)
38
+ }
88
39
}
89
- . onReceive ( SharedTokenUpdater . shared. $decodedTokens) { tokens in
90
- // update model response
91
- if let lastIndex = messages. lastIndex ( where: { !$0. isUser } ) {
92
- let combinedText = tokens. joined ( separator: " " )
93
- messages [ lastIndex] . text = combinedText
94
- }
95
- }
96
- . onReceive ( NotificationCenter . default. publisher ( for: NSNotification . Name ( " TokenGenerationStats " ) ) ) { notification in
97
- if let userInfo = notification. userInfo,
98
- let promptProcRate = userInfo [ " promptProcRate " ] as? Double ,
99
- let tokenGenRate = userInfo [ " tokenGenRate " ] as? Double {
100
- stats = String ( format: " Token generation rate: %.2f tokens/s. Prompt processing rate: %.2f tokens/s " , tokenGenRate, promptProcRate)
101
- }
40
+ . padding ( . top, 20 )
41
+ }
42
+
43
+ HStack {
44
+ Button ( action: {
45
+ showFolderPicker = true
46
+ } ) {
47
+ HStack {
48
+ Image ( systemName: " folder " )
49
+ . resizable ( )
50
+ . scaledToFit ( )
51
+ . frame ( width: 20 , height: 20 )
52
+ }
53
+ . padding ( )
54
+ . background ( Color . pastelGreen)
55
+ . cornerRadius ( 10 )
56
+ . shadow ( radius: 2 )
57
+ . padding ( . leading, 10 )
102
58
}
103
- . onReceive ( NotificationCenter . default. publisher ( for: NSNotification . Name ( " TokenGenerationError " ) ) ) { notification in
104
- if let userInfo = notification. userInfo, let error = userInfo [ " error " ] as? String {
105
- errorMessage = error
106
- isGenerating = false
107
- showAlert = true
59
+ . sheet ( isPresented: $showFolderPicker) {
60
+ FolderPicker { folderURL in
61
+ if let folderURL = folderURL {
62
+ let folderPath = folderURL. path
63
+ print ( " Selected folder: \( folderPath) " )
64
+ DispatchQueue . global ( qos: . background) . async {
65
+ generator. setModelFolderPath ( folderPath)
66
+ }
108
67
}
68
+ }
69
+ } . help ( " Select a folder to set the model path " )
70
+
71
+ TextField ( " Type your message... " , text: $userInput)
72
+ . padding ( )
73
+ . background ( Color ( . systemGray6) )
74
+ . cornerRadius ( 20 )
75
+ . padding ( . horizontal)
76
+
77
+ Button ( action: {
78
+ // Check for non-empty input
79
+ guard !userInput. trimmingCharacters ( in: . whitespaces) . isEmpty else { return }
80
+
81
+ messages. append ( Message ( text: userInput, isUser: true ) )
82
+ messages. append ( Message ( text: " " , isUser: false ) ) // Placeholder for AI response
83
+
84
+ // clear previously generated tokens
85
+ SharedTokenUpdater . shared. clearTokens ( )
86
+
87
+ let prompt = userInput
88
+ userInput = " "
89
+ isGenerating = true
90
+
91
+ DispatchQueue . global ( qos: . background) . async {
92
+ generator. generate ( prompt)
93
+ }
94
+ } ) {
95
+ Image ( systemName: " paperplane.fill " )
96
+ . foregroundColor ( . white)
97
+ . padding ( )
98
+ . background ( isGenerating ? Color . gray : Color . pastelGreen)
99
+ . clipShape ( Circle ( ) )
109
100
}
110
- . alert ( isPresented: $showAlert) {
111
- Alert (
112
- title: Text ( " Error " ) ,
113
- message: Text ( errorMessage) ,
114
- dismissButton: . default( Text ( " OK " ) )
115
- )
116
- }
117
-
101
+ . disabled ( isGenerating)
102
+ }
103
+ . padding ( . bottom, 20 )
104
+ }
105
+ . background ( Color ( . systemGroupedBackground) )
106
+ . edgesIgnoringSafeArea ( . bottom)
107
+ . onReceive ( NotificationCenter . default. publisher ( for: NSNotification . Name ( " TokenGenerationCompleted " ) ) ) { _ in
108
+ isGenerating = false // Re-enable the button when token generation is complete
109
+ }
110
+ . onReceive ( SharedTokenUpdater . shared. $decodedTokens) { tokens in
111
+ // update model response
112
+ if let lastIndex = messages. lastIndex ( where: { !$0. isUser } ) {
113
+ let combinedText = tokens. joined ( separator: " " )
114
+ messages [ lastIndex] . text = combinedText
115
+ }
116
+ }
117
+ . onReceive ( NotificationCenter . default. publisher ( for: NSNotification . Name ( " TokenGenerationStats " ) ) ) { notification in
118
+ if let userInfo = notification. userInfo,
119
+ let promptProcRate = userInfo [ " promptProcRate " ] as? Double ,
120
+ let tokenGenRate = userInfo [ " tokenGenRate " ] as? Double
121
+ {
122
+ stats = String (
123
+ format: " Token generation rate: %.2f tokens/s. Prompt processing rate: %.2f tokens/s " , tokenGenRate,
124
+ promptProcRate)
125
+ }
126
+ }
127
+ . onReceive ( NotificationCenter . default. publisher ( for: NSNotification . Name ( " TokenGenerationError " ) ) ) { notification in
128
+ if let userInfo = notification. userInfo, let error = userInfo [ " error " ] as? String {
129
+ errorMessage = error
130
+ isGenerating = false
131
+ showAlert = true
132
+ }
118
133
}
134
+ . alert ( isPresented: $showAlert) {
135
+ Alert (
136
+ title: Text ( " Error " ) ,
137
+ message: Text ( errorMessage) ,
138
+ dismissButton: . default( Text ( " OK " ) )
139
+ )
140
+ }
141
+
142
+ }
119
143
}
120
144
121
145
struct ChatBubble : View {
122
- var text : String
123
- var isUser : Bool
124
-
125
- var body : some View {
126
- HStack {
127
- if isUser {
128
- Spacer ( )
129
- Text ( text)
130
- . padding ( )
131
- . background ( Color . pastelGreen)
132
- . foregroundColor ( . white)
133
- . cornerRadius ( 25 )
134
- . padding ( . horizontal, 10 )
135
- } else {
136
- Text ( text)
137
- . padding ( )
138
- . background ( Color ( . systemGray5) )
139
- . foregroundColor ( . black)
140
- . cornerRadius ( 25 )
141
- . padding ( . horizontal, 10 )
142
- Spacer ( )
143
- }
144
- }
146
+ var text : String
147
+ var isUser : Bool
148
+
149
+ var body : some View {
150
+ HStack {
151
+ if isUser {
152
+ Spacer ( )
153
+ Text ( text)
154
+ . padding ( )
155
+ . background ( Color . pastelGreen)
156
+ . foregroundColor ( . white)
157
+ . cornerRadius ( 25 )
158
+ . padding ( . horizontal, 10 )
159
+ } else {
160
+ Text ( text)
161
+ . padding ( )
162
+ . background ( Color ( . systemGray5) )
163
+ . foregroundColor ( . black)
164
+ . cornerRadius ( 25 )
165
+ . padding ( . horizontal, 10 )
166
+ Spacer ( )
167
+ }
145
168
}
169
+ }
146
170
}
147
171
148
172
struct ContentView_Previews : PreviewProvider {
149
- static var previews : some View {
150
- ContentView ( )
151
- }
173
+ static var previews : some View {
174
+ ContentView ( )
175
+ }
152
176
}
153
177
154
178
// Extension for a pastel green color
155
179
extension Color {
156
- static let pastelGreen = Color ( red: 0.6 , green: 0.9 , blue: 0.6 )
180
+ static let pastelGreen = Color ( red: 0.6 , green: 0.9 , blue: 0.6 )
157
181
}
0 commit comments