Skip to content

Commit

Permalink
add download buttons & expose llamaState.loadModel
Browse files Browse the repository at this point in the history
  • Loading branch information
jhen0409 committed Dec 17, 2023
1 parent ff87313 commit d993be7
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 3 deletions.
8 changes: 5 additions & 3 deletions examples/llama.swiftui/llama.swiftui/Models/LlamaState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@ import Foundation
@MainActor
class LlamaState: ObservableObject {
@Published var messageLog = ""
@Published var cacheCleared = false

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: "llama-2-7b-chat", withExtension: "Q2_K.gguf", subdirectory: "models")
}

init() {
do {
try loadModel()
try loadModel(modelUrl: defaultModelUrl)
} catch {
messageLog += "Error!\n"
}
}

private func loadModel() throws {
func loadModel(modelUrl: URL?) throws {
messageLog += "Loading model...\n"
if let modelUrl {
llamaContext = try LlamaContext.create_context(path: modelUrl.path())
Expand Down
36 changes: 36 additions & 0 deletions examples/llama.swiftui/llama.swiftui/UI/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@ struct ContentView: View {
@StateObject var llamaState = LlamaState()

@State private var multiLineText = ""
@State private var updater: Bool = false

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 {
VStack {
Expand Down Expand Up @@ -35,6 +52,25 @@ struct ContentView: View {
.foregroundColor(.white)
.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()
}
Expand Down
118 changes: 118 additions & 0 deletions examples/llama.swiftui/llama.swiftui/UI/DownloadButton.swift
Original file line number Diff line number Diff line change
@@ -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",
)
}

0 comments on commit d993be7

Please sign in to comment.