jrb16 commited on
Commit
bea970f
·
1 Parent(s): f7762a3

LLM invocation works

Browse files
PersonalGPT.xcodeproj/project.pbxproj CHANGED
@@ -16,6 +16,8 @@
16
  48055F802A0E77B40057C3BE /* ToolTip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48055F7F2A0E77B40057C3BE /* ToolTip.swift */; };
17
  48055F852A0E93A70057C3BE /* ggml-RedPajama-INCITE-Chat-3B-v1-q5_1.bin in Resources */ = {isa = PBXBuildFile; fileRef = 48055F842A0E93A60057C3BE /* ggml-RedPajama-INCITE-Chat-3B-v1-q5_1.bin */; };
18
  48055F8B2A0E99040057C3BE /* ChatBackend.mm in Sources */ = {isa = PBXBuildFile; fileRef = 48055F8A2A0E99040057C3BE /* ChatBackend.mm */; };
 
 
19
  48B929A829ED80EA00607E43 /* PersonalGPTApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B929A729ED80EA00607E43 /* PersonalGPTApp.swift */; };
20
  48B929AA29ED80EA00607E43 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B929A929ED80EA00607E43 /* ContentView.swift */; };
21
  48B929AC29ED80EC00607E43 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 48B929AB29ED80EC00607E43 /* Assets.xcassets */; };
@@ -57,6 +59,8 @@
57
  48055F842A0E93A60057C3BE /* ggml-RedPajama-INCITE-Chat-3B-v1-q5_1.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = "ggml-RedPajama-INCITE-Chat-3B-v1-q5_1.bin"; path = "../../redpajama.cpp/examples/redpajama/models/pythia/ggml-RedPajama-INCITE-Chat-3B-v1-q5_1.bin"; sourceTree = "<group>"; };
58
  48055F892A0E97670057C3BE /* PersonalGPT-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PersonalGPT-Bridging-Header.h"; sourceTree = "<group>"; };
59
  48055F8A2A0E99040057C3BE /* ChatBackend.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ChatBackend.mm; sourceTree = "<group>"; };
 
 
60
  48B929A429ED80EA00607E43 /* PersonalGPT.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PersonalGPT.app; sourceTree = BUILT_PRODUCTS_DIR; };
61
  48B929A729ED80EA00607E43 /* PersonalGPTApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonalGPTApp.swift; sourceTree = "<group>"; };
62
  48B929A929ED80EA00607E43 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@@ -153,6 +157,8 @@
153
  48055F7B2A0D42CB0057C3BE /* ChatState.swift */,
154
  48055F7D2A0D43620057C3BE /* ThreadWorker.swift */,
155
  48055F7F2A0E77B40057C3BE /* ToolTip.swift */,
 
 
156
  );
157
  path = PersonalGPT;
158
  sourceTree = "<group>";
@@ -325,6 +331,8 @@
325
  48055F762A0D2B5C0057C3BE /* common-gptneox.cpp in Sources */,
326
  48B929AA29ED80EA00607E43 /* ContentView.swift in Sources */,
327
  48055F732A0D2B070057C3BE /* ggml.c in Sources */,
 
 
328
  48B929A829ED80EA00607E43 /* PersonalGPTApp.swift in Sources */,
329
  48055F8B2A0E99040057C3BE /* ChatBackend.mm in Sources */,
330
  48055F7E2A0D43620057C3BE /* ThreadWorker.swift in Sources */,
 
16
  48055F802A0E77B40057C3BE /* ToolTip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48055F7F2A0E77B40057C3BE /* ToolTip.swift */; };
17
  48055F852A0E93A70057C3BE /* ggml-RedPajama-INCITE-Chat-3B-v1-q5_1.bin in Resources */ = {isa = PBXBuildFile; fileRef = 48055F842A0E93A60057C3BE /* ggml-RedPajama-INCITE-Chat-3B-v1-q5_1.bin */; };
18
  48055F8B2A0E99040057C3BE /* ChatBackend.mm in Sources */ = {isa = PBXBuildFile; fileRef = 48055F8A2A0E99040057C3BE /* ChatBackend.mm */; };
19
+ 48055F8D2A0F96E10057C3BE /* TypingIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48055F8C2A0F96E10057C3BE /* TypingIndicator.swift */; };
20
+ 48055F8F2A0F998F0057C3BE /* ChatBubble.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48055F8E2A0F998F0057C3BE /* ChatBubble.swift */; };
21
  48B929A829ED80EA00607E43 /* PersonalGPTApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B929A729ED80EA00607E43 /* PersonalGPTApp.swift */; };
22
  48B929AA29ED80EA00607E43 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B929A929ED80EA00607E43 /* ContentView.swift */; };
23
  48B929AC29ED80EC00607E43 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 48B929AB29ED80EC00607E43 /* Assets.xcassets */; };
 
59
  48055F842A0E93A60057C3BE /* ggml-RedPajama-INCITE-Chat-3B-v1-q5_1.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = "ggml-RedPajama-INCITE-Chat-3B-v1-q5_1.bin"; path = "../../redpajama.cpp/examples/redpajama/models/pythia/ggml-RedPajama-INCITE-Chat-3B-v1-q5_1.bin"; sourceTree = "<group>"; };
60
  48055F892A0E97670057C3BE /* PersonalGPT-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PersonalGPT-Bridging-Header.h"; sourceTree = "<group>"; };
61
  48055F8A2A0E99040057C3BE /* ChatBackend.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ChatBackend.mm; sourceTree = "<group>"; };
62
+ 48055F8C2A0F96E10057C3BE /* TypingIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypingIndicator.swift; sourceTree = "<group>"; };
63
+ 48055F8E2A0F998F0057C3BE /* ChatBubble.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatBubble.swift; sourceTree = "<group>"; };
64
  48B929A429ED80EA00607E43 /* PersonalGPT.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PersonalGPT.app; sourceTree = BUILT_PRODUCTS_DIR; };
65
  48B929A729ED80EA00607E43 /* PersonalGPTApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonalGPTApp.swift; sourceTree = "<group>"; };
66
  48B929A929ED80EA00607E43 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
 
157
  48055F7B2A0D42CB0057C3BE /* ChatState.swift */,
158
  48055F7D2A0D43620057C3BE /* ThreadWorker.swift */,
159
  48055F7F2A0E77B40057C3BE /* ToolTip.swift */,
160
+ 48055F8C2A0F96E10057C3BE /* TypingIndicator.swift */,
161
+ 48055F8E2A0F998F0057C3BE /* ChatBubble.swift */,
162
  );
163
  path = PersonalGPT;
164
  sourceTree = "<group>";
 
331
  48055F762A0D2B5C0057C3BE /* common-gptneox.cpp in Sources */,
332
  48B929AA29ED80EA00607E43 /* ContentView.swift in Sources */,
333
  48055F732A0D2B070057C3BE /* ggml.c in Sources */,
334
+ 48055F8F2A0F998F0057C3BE /* ChatBubble.swift in Sources */,
335
+ 48055F8D2A0F96E10057C3BE /* TypingIndicator.swift in Sources */,
336
  48B929A829ED80EA00607E43 /* PersonalGPTApp.swift in Sources */,
337
  48055F8B2A0E99040057C3BE /* ChatBackend.mm in Sources */,
338
  48055F7E2A0D43620057C3BE /* ThreadWorker.swift in Sources */,
PersonalGPT/ChatBubble.swift ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // ChatBubble.swift
3
+ // PrivateAIChat
4
+ //
5
+ // Created by jrb16 on 13/05/2023.
6
+ //
7
+
8
+ import SwiftUI
9
+
10
+ struct ChatBubbleShape: Shape {
11
+ enum Direction {
12
+ case left
13
+ case right
14
+ }
15
+
16
+ let direction: Direction
17
+
18
+ func path(in rect: CGRect) -> Path {
19
+ return (direction == .left) ? leftBubble(in: rect) : rightBubble(in: rect)
20
+ }
21
+
22
+ private func leftBubble(in rect: CGRect) -> Path {
23
+ let width = rect.width
24
+ let height = rect.height
25
+ let path = Path { p in
26
+ p.move(to: CGPoint(x: 25, y: height))
27
+ p.addLine(to: CGPoint(x: width - 20, y: height))
28
+ p.addCurve(to: CGPoint(x: width, y: height - 20),
29
+ control1: CGPoint(x: width - 8, y: height),
30
+ control2: CGPoint(x: width, y: height - 8))
31
+ p.addLine(to: CGPoint(x: width, y: 20))
32
+ p.addCurve(to: CGPoint(x: width - 20, y: 0),
33
+ control1: CGPoint(x: width, y: 8),
34
+ control2: CGPoint(x: width - 8, y: 0))
35
+ p.addLine(to: CGPoint(x: 21, y: 0))
36
+ p.addCurve(to: CGPoint(x: 4, y: 20),
37
+ control1: CGPoint(x: 12, y: 0),
38
+ control2: CGPoint(x: 4, y: 8))
39
+ p.addLine(to: CGPoint(x: 4, y: height - 11))
40
+ p.addCurve(to: CGPoint(x: 0, y: height),
41
+ control1: CGPoint(x: 4, y: height - 1),
42
+ control2: CGPoint(x: 0, y: height))
43
+ p.addLine(to: CGPoint(x: -0.05, y: height - 0.01))
44
+ p.addCurve(to: CGPoint(x: 11.0, y: height - 4.0),
45
+ control1: CGPoint(x: 4.0, y: height + 0.5),
46
+ control2: CGPoint(x: 8, y: height - 1))
47
+ p.addCurve(to: CGPoint(x: 25, y: height),
48
+ control1: CGPoint(x: 16, y: height),
49
+ control2: CGPoint(x: 20, y: height))
50
+ }
51
+ return path
52
+ }
53
+
54
+ private func rightBubble(in rect: CGRect) -> Path {
55
+ let width = rect.width
56
+ let height = rect.height
57
+ let path = Path { p in
58
+ p.move(to: CGPoint(x: 25, y: height))
59
+ p.addLine(to: CGPoint(x: 20, y: height))
60
+ p.addCurve(to: CGPoint(x: 0, y: height - 20),
61
+ control1: CGPoint(x: 8, y: height),
62
+ control2: CGPoint(x: 0, y: height - 8))
63
+ p.addLine(to: CGPoint(x: 0, y: 20))
64
+ p.addCurve(to: CGPoint(x: 20, y: 0),
65
+ control1: CGPoint(x: 0, y: 8),
66
+ control2: CGPoint(x: 8, y: 0))
67
+ p.addLine(to: CGPoint(x: width - 21, y: 0))
68
+ p.addCurve(to: CGPoint(x: width - 4, y: 20),
69
+ control1: CGPoint(x: width - 12, y: 0),
70
+ control2: CGPoint(x: width - 4, y: 8))
71
+ p.addLine(to: CGPoint(x: width - 4, y: height - 11))
72
+ p.addCurve(to: CGPoint(x: width, y: height),
73
+ control1: CGPoint(x: width - 4, y: height - 1),
74
+ control2: CGPoint(x: width, y: height))
75
+ p.addLine(to: CGPoint(x: width + 0.05, y: height - 0.01))
76
+ p.addCurve(to: CGPoint(x: width - 11, y: height - 4),
77
+ control1: CGPoint(x: width - 4, y: height + 0.5),
78
+ control2: CGPoint(x: width - 8, y: height - 1))
79
+ p.addCurve(to: CGPoint(x: width - 25, y: height),
80
+ control1: CGPoint(x: width - 16, y: height),
81
+ control2: CGPoint(x: width - 20, y: height))
82
+ }
83
+ return path
84
+ }
85
+ }
86
+
87
+ struct ChatBubble<Content>: View where Content: View {
88
+ let direction: ChatBubbleShape.Direction
89
+ let content: () -> Content
90
+ init(direction: ChatBubbleShape.Direction, @ViewBuilder content: @escaping () -> Content) {
91
+ self.content = content
92
+ self.direction = direction
93
+ }
94
+
95
+ var body: some View {
96
+ HStack {
97
+ if direction == .right {
98
+ Spacer()
99
+ }
100
+ content()
101
+ .clipShape(ChatBubbleShape(direction: direction))
102
+ if direction == .left {
103
+ Spacer()
104
+ }
105
+ }.padding([(direction == .left) ? .leading : .trailing, .top, .bottom], 20)
106
+ .padding((direction == .right) ? .leading : .trailing, 50)
107
+ }
108
+ }
PersonalGPT/ChatState.swift CHANGED
@@ -10,6 +10,7 @@ import Foundation
10
  enum MessageRole {
11
  case user
12
  case bot
 
13
  }
14
 
15
  struct MessageData: Hashable, Identifiable {
@@ -80,8 +81,6 @@ class ChatState: ObservableObject {
80
  backend.initialize()
81
  if (!backend.initialized) {
82
  self.updateReply(role: MessageRole.bot, message: "[System] Could not initialize")
83
- } else {
84
- self.updateReply(role: MessageRole.bot, message: "[System] Ready to chat")
85
  }
86
  self.commitReply()
87
  self.markFinish()
@@ -147,8 +146,7 @@ class ChatState: ObservableObject {
147
  }
148
  inProgress = true
149
  stopRequested = false
150
- // self.backendGenerate(prompt: prompt)
151
- dummyGenerate(prompt: prompt)
152
  }
153
 
154
  func requestStop() {
@@ -175,12 +173,12 @@ class ChatState: ObservableObject {
175
  requestedReset = true
176
 
177
  threadWorker.push {
178
- // self.backend.reset()
179
  DispatchQueue.main.sync {
 
180
  self.messages = [MessageData]()
181
  self.infoText = ""
182
  self.unfinishedRespondMessage = ""
183
- self.inProgress = false
184
  self.requestedReset = false
185
  }
186
  }
 
10
  enum MessageRole {
11
  case user
12
  case bot
13
+ case typing
14
  }
15
 
16
  struct MessageData: Hashable, Identifiable {
 
81
  backend.initialize()
82
  if (!backend.initialized) {
83
  self.updateReply(role: MessageRole.bot, message: "[System] Could not initialize")
 
 
84
  }
85
  self.commitReply()
86
  self.markFinish()
 
146
  }
147
  inProgress = true
148
  stopRequested = false
149
+ self.backendGenerate(prompt: prompt)
 
150
  }
151
 
152
  func requestStop() {
 
173
  requestedReset = true
174
 
175
  threadWorker.push {
176
+ self.backend.reset()
177
  DispatchQueue.main.sync {
178
+ self.inProgress = false
179
  self.messages = [MessageData]()
180
  self.infoText = ""
181
  self.unfinishedRespondMessage = ""
 
182
  self.requestedReset = false
183
  }
184
  }
PersonalGPT/ContentView.swift CHANGED
@@ -43,6 +43,9 @@ struct ContentView: View {
43
  }
44
  }.rotationEffect(.radians(.pi))
45
  .scaleEffect(x: -1, y: 1, anchor: .center)
 
 
 
46
  }
47
  }
48
  HStack {
 
43
  }
44
  }.rotationEffect(.radians(.pi))
45
  .scaleEffect(x: -1, y: 1, anchor: .center)
46
+ if (state.inProgress && state.unfinishedRespondMessage == "") {
47
+ MessageView(role:.typing)
48
+ }
49
  }
50
  }
51
  HStack {
PersonalGPT/MessageView.swift CHANGED
@@ -7,109 +7,9 @@
7
 
8
  import SwiftUI
9
 
10
- struct ChatBubbleShape: Shape {
11
- enum Direction {
12
- case left
13
- case right
14
- }
15
-
16
- let direction: Direction
17
-
18
- func path(in rect: CGRect) -> Path {
19
- return (direction == .left) ? leftBubble(in: rect) : rightBubble(in: rect)
20
- }
21
-
22
- private func leftBubble(in rect: CGRect) -> Path {
23
- let width = rect.width
24
- let height = rect.height
25
- let path = Path { p in
26
- p.move(to: CGPoint(x: 25, y: height))
27
- p.addLine(to: CGPoint(x: width - 20, y: height))
28
- p.addCurve(to: CGPoint(x: width, y: height - 20),
29
- control1: CGPoint(x: width - 8, y: height),
30
- control2: CGPoint(x: width, y: height - 8))
31
- p.addLine(to: CGPoint(x: width, y: 20))
32
- p.addCurve(to: CGPoint(x: width - 20, y: 0),
33
- control1: CGPoint(x: width, y: 8),
34
- control2: CGPoint(x: width - 8, y: 0))
35
- p.addLine(to: CGPoint(x: 21, y: 0))
36
- p.addCurve(to: CGPoint(x: 4, y: 20),
37
- control1: CGPoint(x: 12, y: 0),
38
- control2: CGPoint(x: 4, y: 8))
39
- p.addLine(to: CGPoint(x: 4, y: height - 11))
40
- p.addCurve(to: CGPoint(x: 0, y: height),
41
- control1: CGPoint(x: 4, y: height - 1),
42
- control2: CGPoint(x: 0, y: height))
43
- p.addLine(to: CGPoint(x: -0.05, y: height - 0.01))
44
- p.addCurve(to: CGPoint(x: 11.0, y: height - 4.0),
45
- control1: CGPoint(x: 4.0, y: height + 0.5),
46
- control2: CGPoint(x: 8, y: height - 1))
47
- p.addCurve(to: CGPoint(x: 25, y: height),
48
- control1: CGPoint(x: 16, y: height),
49
- control2: CGPoint(x: 20, y: height))
50
- }
51
- return path
52
- }
53
-
54
- private func rightBubble(in rect: CGRect) -> Path {
55
- let width = rect.width
56
- let height = rect.height
57
- let path = Path { p in
58
- p.move(to: CGPoint(x: 25, y: height))
59
- p.addLine(to: CGPoint(x: 20, y: height))
60
- p.addCurve(to: CGPoint(x: 0, y: height - 20),
61
- control1: CGPoint(x: 8, y: height),
62
- control2: CGPoint(x: 0, y: height - 8))
63
- p.addLine(to: CGPoint(x: 0, y: 20))
64
- p.addCurve(to: CGPoint(x: 20, y: 0),
65
- control1: CGPoint(x: 0, y: 8),
66
- control2: CGPoint(x: 8, y: 0))
67
- p.addLine(to: CGPoint(x: width - 21, y: 0))
68
- p.addCurve(to: CGPoint(x: width - 4, y: 20),
69
- control1: CGPoint(x: width - 12, y: 0),
70
- control2: CGPoint(x: width - 4, y: 8))
71
- p.addLine(to: CGPoint(x: width - 4, y: height - 11))
72
- p.addCurve(to: CGPoint(x: width, y: height),
73
- control1: CGPoint(x: width - 4, y: height - 1),
74
- control2: CGPoint(x: width, y: height))
75
- p.addLine(to: CGPoint(x: width + 0.05, y: height - 0.01))
76
- p.addCurve(to: CGPoint(x: width - 11, y: height - 4),
77
- control1: CGPoint(x: width - 4, y: height + 0.5),
78
- control2: CGPoint(x: width - 8, y: height - 1))
79
- p.addCurve(to: CGPoint(x: width - 25, y: height),
80
- control1: CGPoint(x: width - 16, y: height),
81
- control2: CGPoint(x: width - 20, y: height))
82
- }
83
- return path
84
- }
85
- }
86
-
87
- struct ChatBubble<Content>: View where Content: View {
88
- let direction: ChatBubbleShape.Direction
89
- let content: () -> Content
90
- init(direction: ChatBubbleShape.Direction, @ViewBuilder content: @escaping () -> Content) {
91
- self.content = content
92
- self.direction = direction
93
- }
94
-
95
- var body: some View {
96
- HStack {
97
- if direction == .right {
98
- Spacer()
99
- }
100
- content()
101
- .clipShape(ChatBubbleShape(direction: direction))
102
- if direction == .left {
103
- Spacer()
104
- }
105
- }.padding([(direction == .left) ? .leading : .trailing, .top, .bottom], 20)
106
- .padding((direction == .right) ? .leading : .trailing, 50)
107
- }
108
- }
109
-
110
  struct MessageView: View {
111
  var role: MessageRole
112
- var message: String
113
 
114
  var body: some View {
115
  #if os(macOS)
@@ -128,11 +28,16 @@ struct MessageView: View {
128
  Spacer()
129
  }
130
  ChatBubble(direction: direction) {
131
- Text(message)
132
- .padding(10)
133
- .foregroundColor(textColor)
134
- .background(backgroundColor)
135
- .textSelection(.enabled)
 
 
 
 
 
136
  }
137
  if role != MessageRole.user {
138
  Spacer()
@@ -151,7 +56,8 @@ struct MessageView_Previews: PreviewProvider {
151
  MessageView(role: MessageRole.bot, message: "Commercial airline flights typically have an altitude between 8,000 and 12,000 feet above sea level.")
152
  MessageView(role: MessageRole.user, message: "Write a haiku about the fear of flying")
153
  MessageView(role: MessageRole.bot, message: "The fear of flying\nThe fear is real\nThe fear takes my breath away\nThe fear is gone")
 
154
  }
155
- }.previewLayout(.fixed(width: 512, height: 512))
156
  }
157
  }
 
7
 
8
  import SwiftUI
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  struct MessageView: View {
11
  var role: MessageRole
12
+ var message: String = ""
13
 
14
  var body: some View {
15
  #if os(macOS)
 
28
  Spacer()
29
  }
30
  ChatBubble(direction: direction) {
31
+ if (role != .typing) {
32
+ Text(message)
33
+ .padding(10)
34
+ .foregroundColor(textColor)
35
+ .background(backgroundColor)
36
+ .textSelection(.enabled)
37
+ } else {
38
+ TypingIndicator()
39
+ .frame(width: 70, height: 30)
40
+ }
41
  }
42
  if role != MessageRole.user {
43
  Spacer()
 
56
  MessageView(role: MessageRole.bot, message: "Commercial airline flights typically have an altitude between 8,000 and 12,000 feet above sea level.")
57
  MessageView(role: MessageRole.user, message: "Write a haiku about the fear of flying")
58
  MessageView(role: MessageRole.bot, message: "The fear of flying\nThe fear is real\nThe fear takes my breath away\nThe fear is gone")
59
+ MessageView(role: MessageRole.typing)
60
  }
61
+ }.previewLayout(.fixed(width: 512, height: 768))
62
  }
63
  }
PersonalGPT/TypingIndicator.swift ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // TypingIndicator.swift
3
+ // PrivateAIChat
4
+ //
5
+ // Created by jrb16 on 13/05/2023.
6
+ //
7
+
8
+ import SwiftUI
9
+
10
+ struct TypingIndicator: View {
11
+ static let animationDelay = 0.2
12
+ let timer = Timer.publish(every: animationDelay, on: .main, in: .common).autoconnect()
13
+
14
+ @State var count: Int = 0
15
+ @State var slowCount: Int = 0
16
+ @State var color1: Color = Color(.gray)
17
+ @State var color2: Color = Color(.gray)
18
+ @State var color3: Color = Color(.gray)
19
+
20
+ var body: some View {
21
+ ZStack {
22
+ HStack(spacing: 5) {
23
+ Circle()
24
+ .offset(y: count == 1 ? 5 : 0)
25
+ .foregroundColor(color1)
26
+ Circle()
27
+ .offset(y: count == 2 ? 5 : 0)
28
+ .foregroundColor(color2)
29
+ Circle()
30
+ .offset(y: count == 3 ? 5 : 0)
31
+ .foregroundColor(color3)
32
+ }
33
+ .padding(10)
34
+ .background(Color.white, in: RoundedRectangle(cornerRadius: 10))
35
+ }
36
+ .onReceive(timer, perform: { _ in
37
+ withAnimation(.easeInOut(duration: TypingIndicator.animationDelay)) {
38
+ count = (count + 1) % 4
39
+ if (count % 2 == 0) {
40
+ slowCount = (slowCount + 1) % 4
41
+ }
42
+ if slowCount == 1 {
43
+ self.color1 = Color(nsColor: .lightGray)
44
+ self.color2 = Color(nsColor: .gray)
45
+ self.color3 = Color(nsColor: .darkGray)
46
+ } else if slowCount == 2 {
47
+ self.color1 = Color(nsColor: .darkGray)
48
+ self.color2 = Color(nsColor: .lightGray)
49
+ self.color3 = Color(nsColor: .gray)
50
+ } else {
51
+ self.color1 = Color(nsColor: .gray)
52
+ self.color2 = Color(nsColor: .darkGray)
53
+ self.color3 = Color(nsColor: .lightGray)
54
+ }
55
+ }
56
+ })
57
+ }
58
+ }
59
+
60
+ struct TypingIndicator_Previews: PreviewProvider {
61
+ static var previews: some View {
62
+ TypingIndicator()
63
+ }
64
+ }
redpajama/ChatBackend.mm CHANGED
@@ -7,10 +7,14 @@
7
 
8
  #import <Foundation/Foundation.h>
9
  #include "PersonalGPT-Bridging-Header.h"
10
- #include "gptneox.h"
 
11
  #include "ggml.h"
 
12
  #include "common-gptneox.h"
13
 
 
 
14
  gptneox_context **g_ctx;
15
 
16
  class CPPChatBackend {
@@ -29,7 +33,7 @@ public:
29
  return instance;
30
  }
31
 
32
- int encode(std::string& prompt) {
33
  // Tokenize prompt with RedPajama special tokens
34
 
35
  auto prompt_embd = ::gptneox_tokenize(ctx, prompt, false);
@@ -52,7 +56,6 @@ public:
52
  past.push_back(embd_inp);
53
 
54
  const int n_ctx = gptneox_n_ctx(ctx);
55
- const int n_vocab = gptneox_n_vocab(ctx);
56
 
57
  // How many tokens to generate - check if there's space in context for at least one token (or batch size tokens?)
58
  auto inp_size = embd_inp.size();
@@ -84,14 +87,227 @@ public:
84
  input_i += n_eval;
85
  n_past += n_eval;
86
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
 
88
  return 0;
89
  }
90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  private:
 
 
 
 
 
 
 
 
 
 
92
  CPPChatBackend(const std::string& model_path, int random_seed) {
93
  params.model = model_path;
94
  params.n_ctx = 2048;
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
  g_ctx = &ctx;
97
 
@@ -117,16 +333,26 @@ private:
117
  ~CPPChatBackend() {
118
  gptneox_free(ctx);
119
  }
 
 
 
 
120
 
121
- gpt_params params;
122
- std::mt19937 rng;
123
- gptneox_context *ctx;
124
- std::vector<std::vector<gptneox_token>> past;
125
- int n_past = 0;
126
- std::vector<gptneox_token> output;
127
- bool output_enabled = true;
128
  };
129
 
 
 
 
 
 
 
 
130
 
131
  @implementation ChatBackendInstance
132
 
@@ -139,31 +365,37 @@ private:
139
  }
140
 
141
  - (void)initialize {
142
- NSString *path = [[NSBundle mainBundle] pathForResource:@"ggml-RedPajama-INCITE-Chat-3B-v1-q5_1" ofType:@"bin"];
143
- auto& instance = CPPChatBackend::getInstance(path.UTF8String, 1337);
144
  if (instance.isInitialized()) {
145
  _initialized = TRUE;
146
  }
147
  }
148
 
149
- - (void)evaluate {
150
- }
151
-
152
  - (void)encode:(NSString*)prompt {
 
 
 
153
  }
154
 
155
  - (void)decode {
 
 
156
  }
157
 
158
  - (NSString*)getMessage {
159
- return @"Nothing to report yet";
 
 
160
  }
161
 
162
  - (bool)stopped {
163
- return FALSE;
 
164
  }
165
 
166
  - (void)reset {
 
 
167
  }
168
 
169
  - (NSString*)runtimeStatsText {
 
7
 
8
  #import <Foundation/Foundation.h>
9
  #include "PersonalGPT-Bridging-Header.h"
10
+
11
+ #define GGML_USE_ACCELERATE
12
  #include "ggml.h"
13
+ #include "gptneox.h"
14
  #include "common-gptneox.h"
15
 
16
+ #include <sstream>
17
+
18
  gptneox_context **g_ctx;
19
 
20
  class CPPChatBackend {
 
33
  return instance;
34
  }
35
 
36
+ int encode(std::string prompt) {
37
  // Tokenize prompt with RedPajama special tokens
38
 
39
  auto prompt_embd = ::gptneox_tokenize(ctx, prompt, false);
 
56
  past.push_back(embd_inp);
57
 
58
  const int n_ctx = gptneox_n_ctx(ctx);
 
59
 
60
  // How many tokens to generate - check if there's space in context for at least one token (or batch size tokens?)
61
  auto inp_size = embd_inp.size();
 
87
  input_i += n_eval;
88
  n_past += n_eval;
89
  }
90
+
91
+ // Clear the output text vector
92
+ output_text_vec.clear();
93
+ output_enabled = true;
94
+
95
+ return 0;
96
+ }
97
+
98
+ int decode() {
99
+ const std::vector<std::string>::size_type output_text_vec_size = output_text_vec.size();
100
+
101
+ const int n_ctx = gptneox_n_ctx(ctx);
102
+ const int n_vocab = gptneox_n_vocab(ctx);
103
+
104
+ const float temp = params.temp;
105
+ const int32_t top_k = params.top_k <= 0 ? gptneox_n_vocab(ctx) : params.top_k;
106
+ const float top_p = params.top_p;
107
+ const float tfs_z = params.tfs_z;
108
+ const float typical_p = params.typical_p;
109
+ const int32_t repeat_last_n = params.repeat_last_n < 0 ? n_ctx : params.repeat_last_n;
110
+ const float repeat_penalty = params.repeat_penalty;
111
+ const float alpha_presence = params.presence_penalty;
112
+ const float alpha_frequency = params.frequency_penalty;
113
+ const int mirostat = params.mirostat;
114
+ const float mirostat_tau = params.mirostat_tau;
115
+ const float mirostat_eta = params.mirostat_eta;
116
+ const bool penalize_nl = params.penalize_nl;
117
+
118
+ // Loop
119
+ while (output_enabled) {
120
+ // Get token
121
+ gptneox_token id = 0;
122
+
123
+ {
124
+ auto logits = gptneox_get_logits(ctx);
125
+
126
+ // Apply params.logit_bias map
127
+ for (auto it = params.logit_bias.begin(); it != params.logit_bias.end(); it++) {
128
+ logits[it->first] += it->second;
129
+ }
130
+
131
+ // Let's add some custom logit biases that will always help
132
+ gptneox_token backslash_token = gptneox_str_to_token(ctx, "\\");
133
+ logits[backslash_token] = -INFINITY;
134
+
135
+ std::vector<gptneox_token_data> candidates;
136
+ candidates.reserve(n_vocab);
137
+ for (gptneox_token token_id = 0; token_id < n_vocab; token_id++) {
138
+ candidates.emplace_back(gptneox_token_data{token_id, logits[token_id], 0.0f});
139
+ }
140
+
141
+ gptneox_token_data_array candidates_p = { candidates.data(), candidates.size(), false };
142
+
143
+ // Apply penalties
144
+ gptneox_token nl_token = gptneox_str_to_token(ctx, "\n");
145
+ float nl_logit = logits[nl_token];
146
+ auto last_n_repeat = std::min(std::min((int)last_n_tokens.size(), repeat_last_n), n_ctx);
147
+ gptneox_sample_repetition_penalty(ctx, &candidates_p,
148
+ last_n_tokens.data() + last_n_tokens.size() - last_n_repeat,
149
+ last_n_repeat, repeat_penalty);
150
+ gptneox_sample_frequency_and_presence_penalties(ctx, &candidates_p,
151
+ last_n_tokens.data() + last_n_tokens.size() - last_n_repeat,
152
+ last_n_repeat, alpha_frequency, alpha_presence);
153
+ if (!penalize_nl) {
154
+ logits[nl_token] = nl_logit;
155
+ }
156
+
157
+ if (temp <= 0) {
158
+ // Greedy sampling
159
+ id = gptneox_sample_token_greedy(ctx, &candidates_p);
160
+ } else {
161
+ if (mirostat == 1) {
162
+ static float mirostat_mu = 2.0f * mirostat_tau;
163
+ const int mirostat_m = 100;
164
+ gptneox_sample_temperature(ctx, &candidates_p, temp);
165
+ id = gptneox_sample_token_mirostat(ctx, &candidates_p, mirostat_tau, mirostat_eta, mirostat_m, &mirostat_mu);
166
+ } else if (mirostat == 2) {
167
+ static float mirostat_mu = 2.0f * mirostat_tau;
168
+ gptneox_sample_temperature(ctx, &candidates_p, temp);
169
+ id = gptneox_sample_token_mirostat_v2(ctx, &candidates_p, mirostat_tau, mirostat_eta, &mirostat_mu);
170
+ } else {
171
+ // Temperature sampling
172
+ gptneox_sample_top_k(ctx, &candidates_p, top_k, 1);
173
+ gptneox_sample_tail_free(ctx, &candidates_p, tfs_z, 1);
174
+ gptneox_sample_typical(ctx, &candidates_p, typical_p, 1);
175
+ gptneox_sample_top_p(ctx, &candidates_p, top_p, 1);
176
+ gptneox_sample_temperature(ctx, &candidates_p, temp);
177
+ id = gptneox_sample_token(ctx, &candidates_p);
178
+ }
179
+ }
180
+ }
181
+
182
+ // Add output to array
183
+ output.push_back(id);
184
+ // Repeat tokens update
185
+ last_n_tokens.push_back(id);
186
+ if (last_n_tokens.size() > (std::vector<int>::size_type)params.repeat_last_n) {
187
+ last_n_tokens.erase(last_n_tokens.begin());
188
+ }
189
+ // Redpajama: check if the interactive is done.
190
+ //std::cout<<" last_n_tokens.size: "<< last_n_tokens[0] <<" "<< last_n_tokens[1] <<" "<< last_n_tokens[2] << std::endl;
191
+ if (last_n_tokens.size()==3 && last_n_tokens[0]==gptneox_str_to_token(ctx, "<")
192
+ && last_n_tokens[1]==gptneox_str_to_token(ctx, "human") && last_n_tokens[2]==gptneox_str_to_token(ctx, ">:")) {
193
+ output_enabled = false;
194
+ continue;
195
+ }
196
+ // Check for eos - end early - check eos before bos in case they are the same
197
+ if (id == gptneox_token_eos()) {
198
+ output_enabled = false;
199
+ continue;
200
+ }
201
+ // Check for bos - skip callback if so
202
+ if (id == gptneox_token_bos()) {
203
+ continue;
204
+ }
205
+ // Convert token to string and display
206
+ // printf("%s(%d)", gptneox_token_to_str(ctx, id), id);
207
+
208
+
209
+ if (last_n_tokens[2]==gptneox_str_to_token(ctx, "<")){
210
+ ;
211
+ }
212
+ else if (last_n_tokens[2]==gptneox_str_to_token(ctx, "human")){
213
+ if (last_n_tokens[1]==gptneox_str_to_token(ctx, "<")){
214
+ ;
215
+ }
216
+ else{
217
+ output_text_vec.push_back(gptneox_token_to_str(ctx, id));
218
+ }
219
+ }
220
+ else if (last_n_tokens[1]==gptneox_str_to_token(ctx, "<")){
221
+ output_text_vec.push_back("<");
222
+ output_text_vec.push_back(gptneox_token_to_str(ctx, id));
223
+ }
224
+ else{
225
+ output_text_vec.push_back(gptneox_token_to_str(ctx, id));
226
+ }
227
+ // Check if we need to run another eval
228
+ if (output_enabled) {
229
+ // Send generated token back into model for next generation
230
+ if (gptneox_eval(ctx, &id, 1, n_past, params.n_threads)) {
231
+ fprintf(stderr, "%s : failed to eval\n", __func__);
232
+ return -1;
233
+ }
234
+ // Increment past count
235
+ n_past += 1;
236
+ // Check if we need to forget
237
+ if (n_past > n_ctx) {
238
+ // Not enough room to predict even a single token so purge oldest from past and kv cache
239
+ // If nothing in past to purge so simply remove tokens from the beginning of the response
240
+ // Remove a batch of 8 or 16 tokens from beginning of response if no past, this helps reduce the frequency of shifts, but will make the model forget quicker if the forget batch size is too high
241
+ // In theory, the model can continue to build a response infinitely
242
+ int n_forget = 16; //8 //1
243
+ if (past.size() > 0) {
244
+ n_forget = past.front().size();
245
+ past.erase(past.begin());
246
+ }
247
+ gptneox_shift_kv_cache(ctx, n_forget);
248
+ n_past -= n_forget;
249
+ //fprintf(stderr, "%s : %d tokens purged from context memory\n", __func__, n_forget);
250
+ }
251
+ }
252
+
253
+ // Return if we've added at least one token to the output text vec
254
+ if (output_text_vec.size() != output_text_vec_size) {
255
+ return 0;
256
+ }
257
+ }
258
+ // Update past with most recent response
259
+ past.push_back(output);
260
 
261
  return 0;
262
  }
263
 
264
+ std::string getMessage() {
265
+ std::stringstream ss;
266
+ for (const auto& str : output_text_vec) {
267
+ ss << str;
268
+ }
269
+ return strip_string(ss.str());
270
+ }
271
+
272
+ void reset(int random_seed) {
273
+ past.clear();
274
+ output.clear();
275
+ output_text_vec.clear();
276
+ last_n_tokens.clear();
277
+ rng.seed(random_seed);
278
+ }
279
+
280
+ bool stopped() {
281
+ return !output_enabled;
282
+ }
283
+
284
  private:
285
+ gpt_params params;
286
+ std::mt19937 rng;
287
+ gptneox_context *ctx;
288
+ std::vector<std::vector<gptneox_token>> past;
289
+ int n_past = 0;
290
+ std::vector<gptneox_token> output;
291
+ bool output_enabled = false;
292
+ std::vector<gptneox_token> last_n_tokens;
293
+ std::vector<std::string> output_text_vec;
294
+
295
  CPPChatBackend(const std::string& model_path, int random_seed) {
296
  params.model = model_path;
297
  params.n_ctx = 2048;
298
+ params.n_batch = 128;
299
+ params.n_predict = 1;
300
+ params.n_threads = 8;
301
+ params.mirostat = 2;
302
+ params.instruct = true;
303
+ params.top_k = 30;
304
+ params.top_p = 0.95;
305
+ params.temp = 0.8;
306
+ params.repeat_last_n = 3;
307
+ params.repeat_penalty = 1.1;
308
+
309
+
310
+ rng.seed(random_seed);
311
 
312
  g_ctx = &ctx;
313
 
 
333
  ~CPPChatBackend() {
334
  gptneox_free(ctx);
335
  }
336
+
337
+ static std::string strip_string(const std::string& s) {
338
+ size_t start = s.find_first_not_of(" \t\n\r\f\v");
339
+ size_t end = s.find_last_not_of(" \t\n\r\f\v");
340
 
341
+ if (start == std::string::npos) { // no non-space characters
342
+ return "";
343
+ }
344
+
345
+ return s.substr(start, end - start + 1);
346
+ }
 
347
  };
348
 
349
+ #define RANDOM_SEED 1337
350
+
351
+ static CPPChatBackend& getBackendInstance() {
352
+ NSString *path = [[NSBundle mainBundle] pathForResource:@"ggml-RedPajama-INCITE-Chat-3B-v1-q5_1" ofType:@"bin"];
353
+ return CPPChatBackend::getInstance(path.UTF8String, RANDOM_SEED);
354
+ }
355
+
356
 
357
  @implementation ChatBackendInstance
358
 
 
365
  }
366
 
367
  - (void)initialize {
368
+ auto& instance = getBackendInstance();
 
369
  if (instance.isInitialized()) {
370
  _initialized = TRUE;
371
  }
372
  }
373
 
 
 
 
374
  - (void)encode:(NSString*)prompt {
375
+ auto& instance = getBackendInstance();
376
+ auto ret = instance.encode(prompt.UTF8String);
377
+ NSAssert(ret >= 0, @"Encode failed");
378
  }
379
 
380
  - (void)decode {
381
+ auto& instance = getBackendInstance();
382
+ instance.decode();
383
  }
384
 
385
  - (NSString*)getMessage {
386
+ auto& instance = getBackendInstance();
387
+ std::string message = instance.getMessage();
388
+ return [NSString stringWithUTF8String:message.c_str()];
389
  }
390
 
391
  - (bool)stopped {
392
+ auto& instance = getBackendInstance();
393
+ return instance.stopped();
394
  }
395
 
396
  - (void)reset {
397
+ auto& instance = getBackendInstance();
398
+ instance.reset(RANDOM_SEED);
399
  }
400
 
401
  - (NSString*)runtimeStatsText {
redpajama/PersonalGPT-Bridging-Header.h CHANGED
@@ -16,13 +16,13 @@
16
  @property (nonatomic, assign) BOOL initialized;
17
 
18
  - (void)initialize;
19
- - (void)evaluate;
20
  - (void)encode:(NSString*)prompt;
21
  - (void)decode;
22
  - (void)reset;
23
  - (NSString*)getMessage;
24
  - (bool)stopped;
25
  - (NSString*)runtimeStatsText;
 
26
  @end
27
 
28
  #endif /* PrivateAIChat_Bridging_Header_h */
 
16
  @property (nonatomic, assign) BOOL initialized;
17
 
18
  - (void)initialize;
 
19
  - (void)encode:(NSString*)prompt;
20
  - (void)decode;
21
  - (void)reset;
22
  - (NSString*)getMessage;
23
  - (bool)stopped;
24
  - (NSString*)runtimeStatsText;
25
+
26
  @end
27
 
28
  #endif /* PrivateAIChat_Bridging_Header_h */