import CoreGraphics import CoreML import Foundation import ImageIO import SuryaCoreMLRuntime struct Arguments { let modelDirectory: URL let imageURL: URL? let pixelValuesURL: URL? let dumpPixelValuesURL: URL? let maxTokens: Int let useInt8Vision: Bool } func parseArguments() throws -> Arguments { var modelDirectory: URL? var imageURL: URL? var pixelValuesURL: URL? var dumpPixelValuesURL: URL? var maxTokens = 32 var useInt8Vision = true var iterator = CommandLine.arguments.dropFirst().makeIterator() while let arg = iterator.next() { switch arg { case "--model-dir": guard let value = iterator.next() else { throw SuryaRuntimeError.malformedConstants("Missing --model-dir value") } modelDirectory = URL(fileURLWithPath: value) case "--image": guard let value = iterator.next() else { throw SuryaRuntimeError.malformedConstants("Missing --image value") } imageURL = URL(fileURLWithPath: value) case "--pixel-values-fp16": guard let value = iterator.next() else { throw SuryaRuntimeError.malformedConstants("Missing --pixel-values-fp16 value") } pixelValuesURL = URL(fileURLWithPath: value) case "--dump-pixel-values-fp16": guard let value = iterator.next() else { throw SuryaRuntimeError.malformedConstants("Missing --dump-pixel-values-fp16 value") } dumpPixelValuesURL = URL(fileURLWithPath: value) case "--max-tokens": guard let value = iterator.next(), let parsed = Int(value) else { throw SuryaRuntimeError.malformedConstants("Bad --max-tokens value") } maxTokens = parsed case "--vision": guard let value = iterator.next() else { throw SuryaRuntimeError.malformedConstants("Missing --vision value") } useInt8Vision = value.lowercased() != "fp16" default: throw SuryaRuntimeError.malformedConstants("Unknown argument \(arg)") } } guard let modelDirectory else { throw SuryaRuntimeError.malformedConstants("Usage: surya-coreml-smoke --model-dir /path/to/repo --image /path/to/image [--max-tokens 32] [--vision int8|fp16]") } if imageURL == nil && pixelValuesURL == nil { throw SuryaRuntimeError.malformedConstants("Pass either --image or --pixel-values-fp16") } return Arguments( modelDirectory: modelDirectory, imageURL: imageURL, pixelValuesURL: pixelValuesURL, dumpPixelValuesURL: dumpPixelValuesURL, maxTokens: maxTokens, useInt8Vision: useInt8Vision ) } func loadImage(_ url: URL) throws -> CGImage { guard let source = CGImageSourceCreateWithURL(url as CFURL, nil), let image = CGImageSourceCreateImageAtIndex(source, 0, nil) else { throw SuryaRuntimeError.missingFile(url) } return image } func loadPixelValues(_ url: URL) throws -> MLMultiArray { let data = try Data(contentsOf: url, options: [.mappedIfSafe]) let shape = [1024, 1536] let expected = shape.reduce(1, *) * MemoryLayout.size guard data.count == expected else { throw SuryaRuntimeError.invalidShape("Expected \(expected) bytes, got \(data.count)") } let array = try MLMultiArray(shape: shape.map(NSNumber.init(value:)), dataType: .float32) let dst = array.dataPointer.bindMemory(to: Float.self, capacity: shape.reduce(1, *)) data.withUnsafeBytes { raw in let src = raw.bindMemory(to: UInt16.self) for i in 0...size) for index in 0..