Improve CLI
This commit is contained in:
parent
6aa1026478
commit
f67a9a2de7
@ -1,6 +1,6 @@
|
||||
{
|
||||
"contentDirectory": "../Public",
|
||||
"trainingIterations": 20,
|
||||
"serverPath": "https://mydomain.com/caps",
|
||||
"authenticationToken": "mysecretkey",
|
||||
}
|
||||
"folder": "../Public",
|
||||
"iterations": 20,
|
||||
"server": "https://mydomain.com/caps",
|
||||
"authentication": "mysecretkey",
|
||||
}
|
||||
|
@ -4,49 +4,54 @@ import Foundation
|
||||
@main
|
||||
struct CapTrain: AsyncParsableCommand {
|
||||
|
||||
private static let defaultIterations = 10
|
||||
|
||||
@Flag(name: .shortAndLong, help: "Resume the previous training session (default: false)")
|
||||
var resume: Bool = false
|
||||
|
||||
@Argument(help: "The path to the configuration file")
|
||||
var configPath: String?
|
||||
@Option(name: .shortAndLong, help: "The path to the configuration file. The file must be a json object containing command line arguments. Command line options take precedence over configuration file options")
|
||||
var configuration: String?
|
||||
|
||||
@Option(name: .shortAndLong, help: "The number of iterations to train")
|
||||
@Option(name: .shortAndLong, help: "The number of iterations to train (default: 10)")
|
||||
var iterations: Int?
|
||||
|
||||
@Option(name: .shortAndLong, help: "The url of the caps server")
|
||||
var serverPath: String?
|
||||
@Option(name: .shortAndLong, help: "The url of the caps server to retrieve images and upload the classifier")
|
||||
var server: String?
|
||||
|
||||
@Option(name: .shortAndLong, help: "The authentication token for the server")
|
||||
var authentication: String?
|
||||
|
||||
@Option(name: .shortAndLong, help: "The folder where the content (images, classifier, thumbnails) is stored")
|
||||
@Option(name: .shortAndLong, help: "The path to the folder where the content (images, classifier, thumbnails) is stored")
|
||||
var folder: String?
|
||||
|
||||
func run() async throws {
|
||||
let configurationFile = try configurationFile()
|
||||
guard let contentFolder = folder ?? configurationFile?.contentFolder,
|
||||
let trainingIterations = iterations ?? configurationFile?.trainingIterations,
|
||||
let serverPath = serverPath ?? configurationFile?.serverPath,
|
||||
let authenticationToken = authentication ?? configurationFile?.authenticationToken
|
||||
else {
|
||||
throw TrainingError.missingArguments
|
||||
let iterations = iterations ?? configurationFile?.iterations ?? CapTrain.defaultIterations
|
||||
guard let contentFolder = folder ?? configurationFile?.folder else {
|
||||
throw TrainingError.missingArguments("folder")
|
||||
}
|
||||
guard let serverPath = server ?? configurationFile?.server else {
|
||||
throw TrainingError.missingArguments("server")
|
||||
}
|
||||
guard let authentication = authentication ?? configurationFile?.authentication else {
|
||||
throw TrainingError.missingArguments("authentication")
|
||||
}
|
||||
|
||||
let configuration = Configuration(
|
||||
contentFolder: contentFolder,
|
||||
trainingIterations: trainingIterations,
|
||||
trainingIterations: iterations,
|
||||
serverPath: serverPath,
|
||||
authenticationToken: authenticationToken)
|
||||
authenticationToken: authentication)
|
||||
|
||||
let creator = try ClassifierCreator(configuration: configuration, resume: resume)
|
||||
try await creator.run()
|
||||
}
|
||||
|
||||
private func configurationFile() throws -> ConfigurationFile? {
|
||||
guard let configPath else {
|
||||
guard let configuration else {
|
||||
return nil
|
||||
}
|
||||
let configurationFileUrl = URL(fileURLWithPath: configPath)
|
||||
let configurationFileUrl = URL(fileURLWithPath: configuration)
|
||||
return try ConfigurationFile(at: configurationFileUrl)
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,13 @@ import Foundation
|
||||
|
||||
struct ConfigurationFile {
|
||||
|
||||
let contentFolder: String?
|
||||
let folder: String?
|
||||
|
||||
let trainingIterations: Int?
|
||||
let iterations: Int?
|
||||
|
||||
let serverPath: String?
|
||||
let server: String?
|
||||
|
||||
let authenticationToken: String?
|
||||
let authentication: String?
|
||||
}
|
||||
|
||||
extension ConfigurationFile: Decodable {
|
||||
|
@ -4,7 +4,7 @@ enum TrainingError: Error {
|
||||
case invalidGetResponseData(Int)
|
||||
case invalidResponse(URL, Int)
|
||||
|
||||
case missingArguments
|
||||
case missingArguments(String)
|
||||
|
||||
case configurationFileMissing(URL)
|
||||
case configurationFileUnreadable(URL, Error)
|
||||
@ -54,8 +54,8 @@ extension TrainingError: CustomStringConvertible {
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .missingArguments:
|
||||
return "Missing arguments"
|
||||
case .missingArguments(let argument):
|
||||
return "Missing argument '\(argument)'"
|
||||
case .configurationFileMissing(let url):
|
||||
return "No configuration at \(url.absoluteURL.path)"
|
||||
case .configurationFileUnreadable(let url, let error):
|
||||
|
Loading…
Reference in New Issue
Block a user