Skip to content

Commit

Permalink
feat: allows to cancel generation (kevinhermawan#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinhermawan authored Nov 21, 2023
1 parent 16136c9 commit b67195e
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 34 deletions.
2 changes: 1 addition & 1 deletion Ollamac.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@
repositoryURL = "https://github.com/kevinhermawan/OllamaKit";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.0.0;
minimumVersion = 2.0.0;
};
};
/* End XCRemoteSwiftPackageReference section */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/kevinhermawan/OllamaKit",
"state" : {
"revision" : "10d467cfa4f0484754bebf3726e59ab8312f545f",
"version" : "1.0.1"
"revision" : "6f3258eb91145bbf26a263123ff88dbbb95208c2",
"version" : "2.0.0"
}
},
{
Expand Down
65 changes: 37 additions & 28 deletions Ollamac/ViewModels/MessageViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
// Created by Kevin Hermawan on 04/11/23.
//

import Combine
import Foundation
import OllamaKit
import SwiftData
import ViewState

@Observable
final class MessageViewModel {
private var generation: AnyCancellable?

private var modelContext: ModelContext
private var ollamaKit: OllamaKit

Expand All @@ -23,6 +26,10 @@ final class MessageViewModel {
self.ollamaKit = ollamaKit
}

deinit {
self.stopGenerate()
}

func fetch(for chat: Chat) throws {
let chatId = chat.id
let predicate = #Predicate<Message>{ $0.chat?.id == chatId }
Expand All @@ -41,21 +48,19 @@ final class MessageViewModel {
try? modelContext.saveChanges()

if await ollamaKit.reachable() {
ollamaKit.generate(data: message.convertToOKGenerateRequestData()) { [weak self] stream in
guard let self = self else { return }

switch stream.event {
case let .stream(result):
switch result {
case .success(let response):
self.handleSuccess(response)
let data = message.convertToOKGenerateRequestData()

generation = ollamaKit.generate(data: data)
.sink(receiveCompletion: { [weak self] completion in
switch completion {
case .finished:
self?.handleComplete()
case .failure(let error):
self.handleError(error.localizedDescription)
self?.handleError(error.localizedDescription)
}
case .complete:
self.handleComplete()
}
}
}, receiveValue: { [weak self] response in
self?.handleReceive(response)
})
} else {
self.handleError(AppMessages.ollamaServerUnreachable)
}
Expand All @@ -69,27 +74,31 @@ final class MessageViewModel {
try? modelContext.saveChanges()

if await ollamaKit.reachable() {
ollamaKit.generate(data: message.convertToOKGenerateRequestData()) { [weak self] stream in
guard let self = self else { return }

switch stream.event {
case let .stream(result):
switch result {
case .success(let response):
self.handleSuccess(response)
let data = message.convertToOKGenerateRequestData()

generation = ollamaKit.generate(data: data)
.sink(receiveCompletion: { [weak self] completion in
switch completion {
case .finished:
self?.handleComplete()
case .failure(let error):
self.handleError(error.localizedDescription)
self?.handleError(error.localizedDescription)
}
case .complete:
self.handleComplete()
}
}
}, receiveValue: { [weak self] response in
self?.handleReceive(response)
})
} else {
self.handleError(AppMessages.ollamaServerUnreachable)
}
}

private func handleSuccess(_ response: OKGenerateResponse) {
func stopGenerate() {
self.sendViewState = nil
self.generation?.cancel()
try? self.modelContext.saveChanges()
}

private func handleReceive(_ response: OKGenerateResponse) {
if self.messages.isEmpty { return }

let lastIndex = self.messages.count - 1
Expand Down Expand Up @@ -117,7 +126,7 @@ final class MessageViewModel {
let lastIndex = self.messages.count - 1
self.messages[lastIndex].error = false
self.messages[lastIndex].done = true

try? self.modelContext.saveChanges()
self.sendViewState = nil
}
Expand Down
14 changes: 11 additions & 3 deletions Ollamac/Views/MessageViews/MessageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,21 @@ struct MessageView: View {
.focused($isEditorFocused)
.onSubmit(sendAction)

Button(action: messageViewModel.stopGenerate) {
Image(systemName: "stop.circle.fill")
.padding(8)
.help("Stop generate")
}
.buttonStyle(.borderedProminent)
.visible(if: isGenerating, removeCompletely: true)

Button(action: sendAction) {
Label("Send", systemImage: "paperplane.fill")
Image(systemName: "paperplane.fill")
.padding(8)
.foregroundStyle(.white)
.help("Send message (Return)")
.help("Send message")
}
.buttonStyle(.borderedProminent)
.hide(if: isGenerating, removeCompletely: true)
}
.padding(.horizontal)
}
Expand Down

0 comments on commit b67195e

Please sign in to comment.