Skip to content

Commit 9e5bb77

Browse files
committed
Add ChatService
1 parent a075ca3 commit 9e5bb77

3 files changed

Lines changed: 83 additions & 1 deletion

File tree

Core/Package.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ let package = Package(
8686
"SuggestionWidget",
8787
"AXExtension",
8888
"Logger",
89+
"ChatService",
8990
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms"),
9091
]
9192
),
@@ -149,5 +150,6 @@ let package = Package(
149150
.target(name: "Preferences"),
150151
.target(name: "ChatPlugins", dependencies: ["OpenAIService", "Environment"]),
151152
.target(name: "Terminal"),
153+
.target(name: "ChatService", dependencies: ["OpenAIService", "ChatPlugins", "Environment"]),
152154
]
153155
)
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import ChatPlugins
2+
import Foundation
3+
import OpenAIService
4+
5+
public final class ChatService: ObservableObject {
6+
let chatGPTService: ChatGPTServiceType
7+
let plugins = registerPlugins(
8+
TerminalChatPlugin.self
9+
)
10+
var runningPlugin: ChatPlugin?
11+
12+
public init(chatGPTService: ChatGPTServiceType) {
13+
self.chatGPTService = chatGPTService
14+
}
15+
16+
deinit {
17+
print("deinit")
18+
}
19+
20+
public func send(content: String) async throws {
21+
// look for the prefix of content, see if there is something like /command.
22+
// If there is, then we need to find the plugin that can handle this command.
23+
// If there is no such plugin, then we just send the message to the GPT service.
24+
let regex = try NSRegularExpression(pattern: #"^\/([a-zA-Z0-9]+)"#)
25+
let matches = regex.matches(in: content, range: NSRange(content.startIndex..., in: content))
26+
if let match = matches.first {
27+
let command = String(content[Range(match.range(at: 1), in: content)!])
28+
if let pluginType = plugins[command] {
29+
let plugin = pluginType.init(inside: chatGPTService, delegate: self)
30+
await plugin.send(content: String(content.dropFirst(command.count + 1)))
31+
}
32+
} else {
33+
_ = try await chatGPTService.send(content: content, summary: nil)
34+
}
35+
}
36+
37+
public func stopReceivingMessage() async {
38+
if let runningPlugin {
39+
await runningPlugin.cancel()
40+
}
41+
await chatGPTService.stopReceivingMessage()
42+
}
43+
44+
public func clearHistory() async {
45+
if let runningPlugin {
46+
await runningPlugin.cancel()
47+
}
48+
await chatGPTService.clearHistory()
49+
}
50+
}
51+
52+
extension ChatService: ChatPluginDelegate {
53+
public func pluginDidStart(_ plugin: ChatPlugin) {
54+
Task {
55+
await chatGPTService.markReceivingMessage(true)
56+
}
57+
runningPlugin = plugin
58+
}
59+
60+
public func pluginDidEnd(_ plugin: ChatPlugin) {
61+
Task {
62+
await chatGPTService.markReceivingMessage(false)
63+
}
64+
runningPlugin = nil
65+
}
66+
}
67+
68+
func registerPlugins(_ plugins: ChatPlugin.Type...) -> [String: ChatPlugin.Type] {
69+
var all = [String: ChatPlugin.Type]()
70+
for plugin in plugins {
71+
all[plugin.command] = plugin
72+
}
73+
return all
74+
}

Core/Sources/OpenAIService/ChatGPTService.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public protocol ChatGPTServiceType {
77
func clearHistory() async
88
func mutateSystemPrompt(_ newPrompt: String) async
99
func mutateHistory(_ mutate: (inout [ChatMessage]) -> Void) async
10+
func markReceivingMessage(_ receiving: Bool) async
1011
}
1112

1213
public enum ChatGPTServiceError: Error, LocalizedError {
@@ -166,6 +167,7 @@ public actor ChatGPTService: ChatGPTServiceType, ObservableObject {
166167
}
167168

168169
public func clearHistory() {
170+
stopReceivingMessage()
169171
history = []
170172
}
171173

@@ -176,13 +178,17 @@ public actor ChatGPTService: ChatGPTServiceType, ObservableObject {
176178
public func mutateHistory(_ mutate: (inout [ChatMessage]) -> Void) async {
177179
mutate(&history)
178180
}
181+
182+
public func markReceivingMessage(_ receiving: Bool) {
183+
isReceivingMessage = receiving
184+
}
179185
}
180186

181187
extension ChatGPTService {
182188
func changeBuildCompletionStreamAPI(_ builder: @escaping CompletionStreamAPIBuilder) {
183189
buildCompletionStreamAPI = builder
184190
}
185-
191+
186192
func changeUUIDGenerator(_ generator: @escaping () -> String) {
187193
uuidGenerator = generator
188194
}

0 commit comments

Comments
 (0)