33
44import SwiftUI
55
6-
76struct 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
1110}
1211
1312struct ContentView : View {
@@ -18,140 +17,165 @@ struct ContentView: View {
1817 @State private var showAlert : Bool = false
1918 @State private var errorMessage : String = " "
2019
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 ( )
4321
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+ }
8839 }
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 )
10258 }
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+ }
10867 }
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 ( ) )
109100 }
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+ }
118133 }
134+ . alert ( isPresented: $showAlert) {
135+ Alert (
136+ title: Text ( " Error " ) ,
137+ message: Text ( errorMessage) ,
138+ dismissButton: . default( Text ( " OK " ) )
139+ )
140+ }
141+
142+ }
119143}
120144
121145struct 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+ }
145168 }
169+ }
146170}
147171
148172struct ContentView_Previews : PreviewProvider {
149- static var previews : some View {
150- ContentView ( )
151- }
173+ static var previews : some View {
174+ ContentView ( )
175+ }
152176}
153177
154178// Extension for a pastel green color
155179extension 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 )
157181}
0 commit comments