Remove classifier version from database
This commit is contained in:
parent
0e2b0b42ff
commit
344d926b9b
@ -357,6 +357,7 @@ struct ContentView: View {
|
||||
private func downloadClassifier() {
|
||||
Task {
|
||||
await database.downloadClassifier()
|
||||
await database.downloadClassifierClasses()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,6 @@ struct Cap {
|
||||
/// The index of the main image for the cap
|
||||
var mainImage: Int
|
||||
|
||||
/// The version of the first classifier capable of recognizing the cap
|
||||
var classifierVersion: Int?
|
||||
|
||||
var color: Color?
|
||||
|
||||
/// The subpath to the main image on the server
|
||||
@ -44,13 +41,12 @@ struct Cap {
|
||||
- Parameter id: The unique id of the cap
|
||||
- Parameter name: The name associated with the cap
|
||||
*/
|
||||
init(id: Int, name: String, classifier: Int? = nil) {
|
||||
init(id: Int, name: String) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.cleanName = name.clean
|
||||
self.imageCount = 0
|
||||
self.mainImage = 0
|
||||
self.classifierVersion = classifier
|
||||
}
|
||||
|
||||
init(data: CapData) {
|
||||
@ -59,7 +55,6 @@ struct Cap {
|
||||
self.cleanName = data.name.clean
|
||||
self.imageCount = data.count
|
||||
self.mainImage = data.mainImage
|
||||
self.classifierVersion = data.classifierVersion
|
||||
}
|
||||
|
||||
var data: CapData {
|
||||
@ -67,7 +62,6 @@ struct Cap {
|
||||
name: name,
|
||||
count: imageCount,
|
||||
mainImage: mainImage,
|
||||
classifierVersion: classifierVersion,
|
||||
color: color)
|
||||
}
|
||||
|
||||
@ -76,30 +70,18 @@ struct Cap {
|
||||
self.cleanName = data.name.clean
|
||||
self.imageCount = data.count
|
||||
self.mainImage = data.mainImage
|
||||
self.classifierVersion = data.classifierVersion
|
||||
}
|
||||
|
||||
static func ==(lhs: Cap, rhs: CapData) -> Bool {
|
||||
lhs.id == rhs.id &&
|
||||
lhs.name == rhs.name &&
|
||||
lhs.imageCount == rhs.count &&
|
||||
lhs.mainImage == rhs.mainImage &&
|
||||
lhs.classifierVersion == rhs.classifierVersion
|
||||
lhs.mainImage == rhs.mainImage
|
||||
}
|
||||
|
||||
static func !=(lhs: Cap, rhs: CapData) -> Bool {
|
||||
!(lhs == rhs)
|
||||
}
|
||||
|
||||
func classifiable(by classifierVersion: Int?) -> Bool {
|
||||
guard let version = classifierVersion else {
|
||||
return false
|
||||
}
|
||||
guard let own = self.classifierVersion else {
|
||||
return false
|
||||
}
|
||||
return version >= own
|
||||
}
|
||||
}
|
||||
|
||||
extension Cap {
|
||||
@ -130,7 +112,6 @@ extension Cap: Codable {
|
||||
case cleanName = "c"
|
||||
case imageCount = "i"
|
||||
case mainImage = "m"
|
||||
case classifierVersion = "v"
|
||||
case color = "f"
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,6 @@ struct CapData: Codable {
|
||||
|
||||
var mainImage: Int
|
||||
|
||||
var classifierVersion: Int?
|
||||
|
||||
var color: Cap.Color?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
@ -19,7 +17,6 @@ struct CapData: Codable {
|
||||
case name = "n"
|
||||
case count = "c"
|
||||
case mainImage = "m"
|
||||
case classifierVersion = "v"
|
||||
case color = "f"
|
||||
}
|
||||
}
|
||||
|
@ -106,6 +106,35 @@ final class Database: ObservableObject {
|
||||
|
||||
@Published
|
||||
var isUploading = false
|
||||
|
||||
@AppStorage("classifierClasses")
|
||||
private var _classifierClassesString: String = ""
|
||||
|
||||
private var _classifierClassesCache: Set<Int>?
|
||||
|
||||
private var classifierClasses: Set<Int> {
|
||||
get {
|
||||
_classifierClassesCache ?? loadClassifierClasses()
|
||||
}
|
||||
set {
|
||||
_classifierClassesCache = newValue
|
||||
DispatchQueue.main.async {
|
||||
self._classifierClassesString = newValue.map { "\($0)" }.joined(separator: ",")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func loadClassifierClasses() -> Set<Int> {
|
||||
let elements: [Int] = _classifierClassesString.components(separatedBy: ",").compactMap {
|
||||
guard let id = Int($0) else {
|
||||
log("Failed to load classifier class from '\($0)'")
|
||||
return nil
|
||||
}
|
||||
return id
|
||||
}
|
||||
_classifierClassesCache = Set(elements)
|
||||
return _classifierClassesCache!
|
||||
}
|
||||
|
||||
init(server: URL, folder: URL = FileManager.default.documentDirectory) {
|
||||
self.serverUrl = server
|
||||
@ -151,6 +180,10 @@ final class Database: ObservableObject {
|
||||
private var serverClassifierUrl: URL {
|
||||
serverUrl.appendingPathComponent("classifier.mlmodel")
|
||||
}
|
||||
|
||||
private var serverClassifierClassesUrl: URL {
|
||||
serverUrl.appendingPathComponent("classifier.classes")
|
||||
}
|
||||
|
||||
private var serverClassifierVersionUrl: URL {
|
||||
serverUrl.appendingPathComponent("version")
|
||||
@ -359,6 +392,48 @@ final class Database: ObservableObject {
|
||||
log("Downloaded classifier \(classifierVersion)")
|
||||
return true
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func downloadClassifierClasses() async -> Bool {
|
||||
log("Downloading classifier classes")
|
||||
let data: Data
|
||||
let response: URLResponse
|
||||
do {
|
||||
(data, response) = try await URLSession.shared.data(from: serverClassifierClassesUrl)
|
||||
} catch {
|
||||
log("Failed to download classifier classes: \(error)")
|
||||
return false
|
||||
}
|
||||
guard (response as? HTTPURLResponse)?.statusCode == 200 else {
|
||||
return false
|
||||
}
|
||||
|
||||
guard let string = String(data: data, encoding: .utf8) else {
|
||||
log("Classifier classes is invalid data (not a string)")
|
||||
return false
|
||||
}
|
||||
let classes = string.components(separatedBy: ",")
|
||||
|
||||
// Validate input
|
||||
var isValid = true
|
||||
let ids: [Int] = classes.compactMap { s in
|
||||
guard let id = Int(s) else {
|
||||
log("Invalid id '\(s)' in downloaded classes list")
|
||||
isValid = false
|
||||
return nil
|
||||
}
|
||||
if caps[id] == nil {
|
||||
// Caps which are deleted may still be recognized
|
||||
return nil
|
||||
}
|
||||
return id
|
||||
}
|
||||
guard isValid else {
|
||||
return false
|
||||
}
|
||||
self.classifierClasses = Set(ids)
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
Indicate that the cap has pending operations, such as determining the color or a thumbnail
|
||||
@ -374,7 +449,7 @@ final class Database: ObservableObject {
|
||||
// MARK: Adding new data
|
||||
|
||||
func save(newCap name: String) -> Cap {
|
||||
let cap = Cap(id: nextCapId, name: name, classifier: nil)
|
||||
let cap = Cap(id: nextCapId, name: name)
|
||||
caps[cap.id] = cap
|
||||
DispatchQueue.main.async {
|
||||
self.changedCaps.insert(cap.id)
|
||||
@ -745,6 +820,10 @@ final class Database: ObservableObject {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func canClassify(cap id: Int) -> Bool {
|
||||
classifierClasses.contains(id)
|
||||
}
|
||||
|
||||
private func getClassifier() -> Classifier? {
|
||||
if let classifier = classifier {
|
||||
@ -847,8 +926,7 @@ final class Database: ObservableObject {
|
||||
}
|
||||
|
||||
var classifierClassCount: Int {
|
||||
let version = classifierVersion
|
||||
return caps.values.filter { $0.classifiable(by: version) }.count
|
||||
classifierClasses.count
|
||||
}
|
||||
|
||||
func imageCacheSize() async -> Int {
|
||||
@ -883,7 +961,7 @@ extension Database {
|
||||
static var largeMock: Database {
|
||||
let db = Database(server: URL(string: "https://christophhagen.de/caps")!)
|
||||
db.caps = (1..<500)
|
||||
.map { Cap(id: $0, name: "Cap \($0)", classifier: nil)}
|
||||
.map { Cap(id: $0, name: "Cap \($0)") }
|
||||
.reduce(into: [:]) { $0[$1.id] = $1 }
|
||||
db.image = UIImage(systemSymbol: .photo)
|
||||
return db
|
||||
|
Loading…
Reference in New Issue
Block a user