add download buttons & expose llamaState.loadModel
This commit is contained in:
parent
ff87313db8
commit
ce1df8124a
3 changed files with 158 additions and 3 deletions
|
@ -3,21 +3,23 @@ import Foundation
|
||||||
@MainActor
|
@MainActor
|
||||||
class LlamaState: ObservableObject {
|
class LlamaState: ObservableObject {
|
||||||
@Published var messageLog = ""
|
@Published var messageLog = ""
|
||||||
|
@Published var cacheCleared = false
|
||||||
|
|
||||||
private var llamaContext: LlamaContext?
|
private var llamaContext: LlamaContext?
|
||||||
private var modelUrl: URL? {
|
private var defaultModelUrl: URL? {
|
||||||
Bundle.main.url(forResource: "ggml-model", withExtension: "gguf", subdirectory: "models")
|
Bundle.main.url(forResource: "ggml-model", withExtension: "gguf", subdirectory: "models")
|
||||||
// Bundle.main.url(forResource: "llama-2-7b-chat", withExtension: "Q2_K.gguf", subdirectory: "models")
|
// Bundle.main.url(forResource: "llama-2-7b-chat", withExtension: "Q2_K.gguf", subdirectory: "models")
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
do {
|
do {
|
||||||
try loadModel()
|
try loadModel(modelUrl: defaultModelUrl)
|
||||||
} catch {
|
} catch {
|
||||||
messageLog += "Error!\n"
|
messageLog += "Error!\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func loadModel() throws {
|
func loadModel(modelUrl: URL?) throws {
|
||||||
messageLog += "Loading model...\n"
|
messageLog += "Loading model...\n"
|
||||||
if let modelUrl {
|
if let modelUrl {
|
||||||
llamaContext = try LlamaContext.create_context(path: modelUrl.path())
|
llamaContext = try LlamaContext.create_context(path: modelUrl.path())
|
||||||
|
|
|
@ -5,6 +5,22 @@ struct ContentView: View {
|
||||||
|
|
||||||
@State private var multiLineText = ""
|
@State private var multiLineText = ""
|
||||||
|
|
||||||
|
private static func cleanupModelCaches() {
|
||||||
|
// Delete all models (*.gguf)
|
||||||
|
let fileManager = FileManager.default
|
||||||
|
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||||
|
do {
|
||||||
|
let fileURLs = try fileManager.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil)
|
||||||
|
for fileURL in fileURLs {
|
||||||
|
if fileURL.pathExtension == "gguf" {
|
||||||
|
try fileManager.removeItem(at: fileURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print("Error while enumerating files \(documentsUrl.path): \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
// automatically scroll to bottom of text view
|
// automatically scroll to bottom of text view
|
||||||
|
@ -35,6 +51,25 @@ struct ContentView: View {
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
.cornerRadius(8)
|
.cornerRadius(8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VStack {
|
||||||
|
DownloadButton(
|
||||||
|
llamaState: llamaState,
|
||||||
|
modelName: "TheBloke / TinyLlama-1.1B-1T-OpenOrca-GGUF (Q4_0)",
|
||||||
|
modelUrl: "https://huggingface.co/TheBloke/TinyLlama-1.1B-1T-OpenOrca-GGUF/resolve/main/tinyllama-1.1b-1t-openorca.Q4_0.gguf?download=true",
|
||||||
|
filename: "tinyllama-1.1b-1t-openorca.Q4_0.gguf"
|
||||||
|
)
|
||||||
|
DownloadButton(
|
||||||
|
llamaState: llamaState,
|
||||||
|
modelName: "TheBloke / TinyLlama-1.1B-1T-OpenOrca-GGUF (Q8_0)",
|
||||||
|
modelUrl: "https://huggingface.co/TheBloke/TinyLlama-1.1B-1T-OpenOrca-GGUF/resolve/main/tinyllama-1.1b-1t-openorca.Q8_0.gguf?download=true",
|
||||||
|
filename: "tinyllama-1.1b-1t-openorca.Q8_0.gguf"
|
||||||
|
)
|
||||||
|
Button("Clear downloaded models") {
|
||||||
|
ContentView.cleanupModelCaches()
|
||||||
|
llamaState.cacheCleared = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
|
|
118
examples/llama.swiftui/llama.swiftui/UI/DownloadButton.swift
Normal file
118
examples/llama.swiftui/llama.swiftui/UI/DownloadButton.swift
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct DownloadButton: View {
|
||||||
|
@ObservedObject private var llamaState: LlamaState
|
||||||
|
private var modelName: String
|
||||||
|
private var modelUrl: String
|
||||||
|
private var filename: String
|
||||||
|
|
||||||
|
@State private var status: String
|
||||||
|
|
||||||
|
@State private var downloadTask: URLSessionDataTask?
|
||||||
|
@State private var progress = 0.0
|
||||||
|
@State private var observation: NSKeyValueObservation?
|
||||||
|
|
||||||
|
private static func getFileURL(filename: String) -> URL {
|
||||||
|
FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent(filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func checkFileExistenceAndUpdateStatus() {
|
||||||
|
}
|
||||||
|
|
||||||
|
init(llamaState: LlamaState, modelName: String, modelUrl: String, filename: String) {
|
||||||
|
self.llamaState = llamaState
|
||||||
|
self.modelName = modelName
|
||||||
|
self.modelUrl = modelUrl
|
||||||
|
self.filename = filename
|
||||||
|
|
||||||
|
let fileURL = DownloadButton.getFileURL(filename: filename)
|
||||||
|
status = FileManager.default.fileExists(atPath: fileURL.path) ? "downloaded" : "download"
|
||||||
|
}
|
||||||
|
|
||||||
|
private func download() {
|
||||||
|
status = "downloading"
|
||||||
|
downloadTask = URLSession.shared.dataTask(with: URL(string: modelUrl)!) { data, response, error in
|
||||||
|
if let error = error {
|
||||||
|
print("Error: \(error.localizedDescription)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let response = response as? HTTPURLResponse, (200...299).contains(response.statusCode) else {
|
||||||
|
print("Server error!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let data = data {
|
||||||
|
do {
|
||||||
|
let fileURL = DownloadButton.getFileURL(filename: filename)
|
||||||
|
try data.write(to: fileURL)
|
||||||
|
|
||||||
|
llamaState.cacheCleared = false
|
||||||
|
|
||||||
|
print("Downloaded model \(modelName) to \(fileURL)")
|
||||||
|
status = "downloaded"
|
||||||
|
try llamaState.loadModel(modelUrl: fileURL)
|
||||||
|
} catch let err {
|
||||||
|
print("Error: \(err.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
observation = downloadTask?.progress.observe(\.fractionCompleted) { progress, _ in
|
||||||
|
self.progress = progress.fractionCompleted
|
||||||
|
}
|
||||||
|
downloadTask?.resume()
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
if status == "download" {
|
||||||
|
Button(action: download) {
|
||||||
|
Text("Download " + modelName)
|
||||||
|
}
|
||||||
|
} else if status == "downloading" {
|
||||||
|
Button(action: {
|
||||||
|
downloadTask?.cancel()
|
||||||
|
status = "download"
|
||||||
|
}) {
|
||||||
|
Text("\(modelName) (Downloading \(Int(progress * 100))%)")
|
||||||
|
}
|
||||||
|
} else if status == "downloaded" {
|
||||||
|
Button(action: {
|
||||||
|
let fileURL = DownloadButton.getFileURL(filename: filename)
|
||||||
|
if !FileManager.default.fileExists(atPath: fileURL.path) {
|
||||||
|
download()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
try llamaState.loadModel(modelUrl: fileURL)
|
||||||
|
} catch let err {
|
||||||
|
print("Error: \(err.localizedDescription)")
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("\(modelName) (Downloaded)")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Text("Unknown status")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onDisappear() {
|
||||||
|
downloadTask?.cancel()
|
||||||
|
}
|
||||||
|
.onChange(of: llamaState.cacheCleared) { newValue in
|
||||||
|
if newValue {
|
||||||
|
downloadTask?.cancel()
|
||||||
|
let fileURL = DownloadButton.getFileURL(filename: filename)
|
||||||
|
status = FileManager.default.fileExists(atPath: fileURL.path) ? "downloaded" : "download"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
DownloadButton(
|
||||||
|
llamaState: LlamaState(),
|
||||||
|
modelName: "TheBloke / TinyLlama-1.1B-1T-OpenOrca-GGUF (Q4_0)",
|
||||||
|
modelUrl: "https://huggingface.co/TheBloke/TinyLlama-1.1B-1T-OpenOrca-GGUF/resolve/main/tinyllama-1.1b-1t-openorca.Q4_0.gguf?download=true",
|
||||||
|
filename: "tinyllama-1.1b-1t-openorca.Q4_0.gguf"
|
||||||
|
)
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue