All skills

Core ML, Create ML, Vision framework, Natural Language framework, on-device ML integration. Use when user wants image classification, text analysis, object detection, sound classification, model optimization, or custom model integration. Covers Core ML vs Foundation Models decision.

Use this Skill: https://skilld.dev/gh/rshankras/claude-code-apple-skills/core-ml

This session only. Nothing lands on disk.

templates.md

≈8.1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Core ML Swift Code Templates

Production-ready Swift templates for Core ML, Vision, and NaturalLanguage integration. All code uses modern Swift patterns: actors, async/await, structured concurrency, and protocol-based architecture.

1. MLModelManager.swift — Central Model Management

import CoreML
import os

/// Actor-based model manager for safe concurrent model loading and caching.
/// Provides lazy loading, memory management, and error handling for Core ML models.
actor MLModelManager {
    static let shared = MLModelManager()

    private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? "app", category: "MLModelManager")
    private var loadedModels: [String: MLModel] = [:]

    /// Load a compiled Core ML model from the app bundle, caching it for reuse.
    /// - Parameters:
    ///   - name: The model filename without extension (e.g., "ImageClassifier")
    ///   - computeUnits: Hardware to use for inference. Defaults to `.all` (system chooses best).
    /// - Returns: The loaded MLModel instance.
    func model(named name: String, computeUnits: MLComputeUnits = .all) async throws -> MLModel {
        if let cached = loadedModels[name] {
            return cached
        }

        guard let url = Bundle.main.url(forResource: name, withExtension: "mlmodelc") else {
            logger.error("Model not found in bundle: \(name)")
            throw MLModelManagerError.modelNotFound(name)
        }

        let config = MLModelConfiguration()
        config.computeUnits = computeUnits

        logger.info("Loading model: \(name) with compute units: \(String(describing: computeUnits))")

        do {
            let model = try await MLModel.load(contentsOf: url, configuration: config)
            loadedModels[name] = model
            logger.info("Model loaded successfully: \(name)")
            return model
        } catch {
            logger.error("Failed to load model \(name): \(error.localizedDescription)")
            throw MLModelManagerError.loadFailed(name, error)
        }
    }

    /// Load a model from an arbitrary URL (e.g., downloaded model in Application Support).
    func model(at url: URL, name: String, computeUnits: MLComputeUnits = .all) async throws -> MLModel {
        if let cached = loadedModels[name] {
            return cached
        }

        let config = MLModelConfiguration()
        config.computeUnits = computeUnits

        let model = try await MLModel.load(contentsOf: url, configuration: config)
        loadedModels[name] = model
        return model
    }

    /// Unload a specific model to free memory.
    func unloadModel(named name: String) {
        loadedModels.removeValue(forKey: name)
        logger.info("Model unloaded: \(name)")
    }

    /// Unload all models. Call on memory warning.
    func unloadAll() {
        let count = loadedModels.count
        loadedModels.removeAll()
        logger.info("All models unloaded (\(count) models)")
    }

    /// Compile a raw .mlmodel file and return the compiled URL.
    /// Use this for models downloaded at runtime.
    func compileAndCache(modelAt sourceURL: URL, name: String) async throws -> URL {
        let compiledURL = try MLModel.compileModel(at: sourceURL)

        let cacheDir = try modelsCacheDirectory()
        let destination = cacheDir.appendingPathComponent("\(name).mlmodelc")

        let fm = FileManager.default
        if fm.fileExists(atPath: destination.path) {
            try fm.removeItem(at: destination)
        }
        try fm.moveItem(at: compiledURL, to: destination)

        return destination
    }

    private func modelsCacheDirectory() throws -> URL {
        let appSupport = try FileManager.default.url(
            for: .applicationSupportDirectory,
            in: .userDomainMask,
            appropriateFor: nil,
            create: true
        )
        let dir = appSupport.appendingPathComponent("MLModels")
        if !FileManager.default.fileExists(atPath: dir.path) {
            try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
        }
        return dir
    }
}

enum MLModelManagerError: Error, LocalizedError {
    case modelNotFound(String)
    case loadFailed(String, Error)
    case compileFailed(Error)
    case predictionFailed(Error)

    var errorDescription: String? {
        switch self {
        case .modelNotFound(let name):
            return "ML model '\(name)' not found in app bundle"
        case .loadFailed(let name, let error):
            return "Failed to load model '\(name)': \(error.localizedDescription)"
        case .compileFailed(let error):
            return "Model compilation failed: \(error.localizedDescription)"
        case .predictionFailed(let error):
            return "Prediction failed: \(error.localizedDescription)"
        }
    }
}

2. ImageClassifier.swift — Vision-Based Image Classification

import Vision
import UIKit
import os

/// Classifies images using Vision framework's built-in model.
/// No custom Core ML model required — uses Apple's on-device classification.
struct ImageClassifier {
    private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? "app", category: "ImageClassifier")

    /// Classification result with label and confidence score.
    struct Classification: Sendable {
        let label: String
        let confidence: Float

        /// Confidence as a percentage string (e.g., "94.2%").
        var confidencePercent: String {
            String(format: "%.1f%%", confidence * 100)
        }
    }

    /// Classify an image using Vision's built-in image classifier.
    /// - Parameters:
    ///   - image: The UIImage to classify.
    ///   - maxResults: Maximum number of classifications to return (sorted by confidence).
    ///   - minimumConfidence: Minimum confidence threshold. Results below this are filtered out.
    /// - Returns: Array of classifications sorted by confidence (highest first).
    func classify(
        _ image: UIImage,
        maxResults: Int = 5,
        minimumConfidence: Float = 0.1
    ) async throws -> [Classification] {
        guard let cgImage = image.cgImage else {
            throw ImageClassifierError.invalidImage
        }

        let orientation = CGImagePropertyOrientation(image.imageOrientation)

        return try await withCheckedThrowingContinuation { continuation in
            let request = VNClassifyImageRequest { request, error in
                if let error {
                    continuation.resume(throwing: ImageClassifierError.visionError(error))
                    return
                }

                let results = (request.results as? [VNClassificationObservation] ?? [])
                    .filter { $0.confidence >= minimumConfidence }
                    .prefix(maxResults)
                    .map { Classification(label: $0.identifier, confidence: $0.confidence) }

                continuation.resume(returning: Array(results))
            }

            let handler = VNImageRequestHandler(
                cgImage: cgImage,
                orientation: orientation,
                options: [:]
            )

            do {
                try handler.perform([request])
            } catch {
                continuation.resume(throwing: ImageClassifierError.visionError(error))
            }
        }
    }

    /// Classify an image using a custom Core ML model via Vision.
    /// - Parameters:
    ///   - image: The UIImage to classify.
    ///   - modelURL: URL to the compiled .mlmodelc file.
    ///   - maxResults: Maximum number of results.
    /// - Returns: Array of classifications.
    func classify(
        _ image: UIImage,
        using modelURL: URL,
        maxResults: Int = 5
    ) async throws -> [Classification] {
        guard let cgImage = image.cgImage else {
            throw ImageClassifierError.invalidImage
        }

        let orientation = CGImagePropertyOrientation(image.imageOrientation)
        let vnModel = try VNCoreMLModel(for: MLModel(contentsOf: modelURL))

        return try await withCheckedThrowingContinuation { continuation in
            let request = VNCoreMLRequest(model: vnModel) { request, error in
                if let error {
                    continuation.resume(throwing: ImageClassifierError.visionError(error))
                    return
                }

                let results = (request.results as? [VNClassificationObservation] ?? [])
                    .prefix(maxResults)
                    .map { Classification(label: $0.identifier, confidence: $0.confidence) }

                continuation.resume(returning: Array(results))
            }

            // Let Vision handle image scaling
            request.imageCropAndScaleOption = .centerCrop

            let handler = VNImageRequestHandler(
                cgImage: cgImage,
                orientation: orientation,
                options: [:]
            )

            do {
                try handler.perform([request])
            } catch {
                continuation.resume(throwing: ImageClassifierError.visionError(error))
            }
        }
    }
}

enum ImageClassifierError: Error, LocalizedError {
    case invalidImage
    case visionError(Error)
    case noResults

    var errorDescription: String? {
        switch self {
        case .invalidImage:
            return "Could not extract image data for classification"
        case .visionError(let error):
            return "Vision framework error: \(error.localizedDescription)"
        case .noResults:
            return "No classification results returned"
        }
    }
}

// MARK: - CGImagePropertyOrientation Helper

extension CGImagePropertyOrientation {
    init(_ uiOrientation: UIImage.Orientation) {
        switch uiOrientation {
        case .up:            self = .up
        case .upMirrored:    self = .upMirrored
        case .down:          self = .down
        case .downMirrored:  self = .downMirrored
        case .left:          self = .left
        case .leftMirrored:  self = .leftMirrored
        case .right:         self = .right
        case .rightMirrored: self = .rightMirrored
        @unknown default:    self = .up
        }
    }
}

3. TextAnalyzer.swift — NaturalLanguage Framework Wrapper

import NaturalLanguage
import os

/// Wrapper around Apple's NaturalLanguage framework for text analysis.
/// Provides sentiment analysis, language detection, tokenization, and entity recognition.
struct TextAnalyzer {
    private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? "app", category: "TextAnalyzer")

    // MARK: - Sentiment Analysis

    /// Analyze sentiment of text.
    /// - Parameter text: The text to analyze.
    /// - Returns: Score from -1.0 (very negative) to +1.0 (very positive). 0.0 is neutral.
    func detectSentiment(_ text: String) -> Double {
        guard !text.isEmpty else { return 0.0 }

        let tagger = NLTagger(tagSchemes: [.sentimentScore])
        tagger.string = text

        let (tag, _) = tagger.tag(at: text.startIndex, unit: .paragraph, scheme: .sentimentScore)
        return Double(tag?.rawValue ?? "0") ?? 0.0
    }

    /// Sentiment category based on score thresholds.
    enum Sentiment: String, Sendable {
        case positive, neutral, negative

        init(score: Double) {
            if score > 0.1 { self = .positive }
            else if score < -0.1 { self = .negative }
            else { self = .neutral }
        }
    }

    /// Detect sentiment as a category.
    func sentimentCategory(_ text: String) -> Sentiment {
        Sentiment(score: detectSentiment(text))
    }

    // MARK: - Language Detection

    /// Detect the dominant language of text.
    /// - Parameter text: The text to analyze (best results with 20+ characters).
    /// - Returns: The detected language, or nil if undetermined.
    func detectLanguage(_ text: String) -> NLLanguage? {
        NLLanguageRecognizer.dominantLanguage(for: text)
    }

    /// Detect multiple possible languages with confidence scores.
    /// - Parameters:
    ///   - text: The text to analyze.
    ///   - maxResults: Maximum number of language hypotheses.
    /// - Returns: Dictionary mapping languages to confidence scores (0.0 to 1.0).
    func detectLanguages(_ text: String, maxResults: Int = 5) -> [(NLLanguage, Double)] {
        let recognizer = NLLanguageRecognizer()
        recognizer.processString(text)
        return recognizer.languageHypotheses(withMaximum: maxResults)
            .sorted { $0.value > $1.value }
            .map { ($0.key, $0.value) }
    }

    // MARK: - Tokenization

    /// Tokenize text into units (words, sentences, or paragraphs).
    /// - Parameters:
    ///   - text: The text to tokenize.
    ///   - unit: The tokenization unit (.word, .sentence, .paragraph).
    /// - Returns: Array of token strings.
    func tokenize(_ text: String, unit: NLTokenUnit = .word) -> [String] {
        guard !text.isEmpty else { return [] }

        let tokenizer = NLTokenizer(unit: unit)
        tokenizer.string = text

        return tokenizer.tokens(for: text.startIndex..<text.endIndex).map { range in
            String(text[range])
        }
    }

    /// Count words in text (language-aware, handles CJK and other scripts correctly).
    func wordCount(_ text: String) -> Int {
        tokenize(text, unit: .word).count
    }

    // MARK: - Named Entity Recognition

    /// Recognized entity with its text and type.
    struct Entity: Sendable {
        let text: String
        let type: EntityType
    }

    enum EntityType: String, Sendable {
        case person
        case place
        case organization
        case other

        init(tag: NLTag) {
            switch tag {
            case .personalName:      self = .person
            case .placeName:         self = .place
            case .organizationName:  self = .organization
            default:                 self = .other
            }
        }
    }

    /// Recognize named entities (people, places, organizations) in text.
    /// - Parameter text: The text to analyze.
    /// - Returns: Array of recognized entities with their types.
    func recognizeEntities(_ text: String) -> [Entity] {
        guard !text.isEmpty else { return [] }

        let tagger = NLTagger(tagSchemes: [.nameType])
        tagger.string = text

        var entities: [Entity] = []
        let range = text.startIndex..<text.endIndex

        tagger.enumerateTags(in: range, unit: .word, scheme: .nameType, options: [.omitWhitespace, .omitPunctuation, .joinNames]) { tag, tokenRange in
            if let tag, tag != .other {
                entities.append(Entity(
                    text: String(text[tokenRange]),
                    type: EntityType(tag: tag)
                ))
            }
            return true
        }

        return entities
    }

    // MARK: - Part of Speech

    /// Tagged word with its part-of-speech tag.
    struct TaggedWord: Sendable {
        let word: String
        let tag: NLTag
    }

    /// Tag each word with its part of speech (noun, verb, adjective, etc.).
    func tagPartsOfSpeech(_ text: String) -> [TaggedWord] {
        guard !text.isEmpty else { return [] }

        let tagger = NLTagger(tagSchemes: [.lexicalClass])
        tagger.string = text

        var tagged: [TaggedWord] = []
        let range = text.startIndex..<text.endIndex

        tagger.enumerateTags(in: range, unit: .word, scheme: .lexicalClass, options: [.omitWhitespace, .omitPunctuation]) { tag, tokenRange in
            if let tag {
                tagged.append(TaggedWord(word: String(text[tokenRange]), tag: tag))
            }
            return true
        }

        return tagged
    }

    // MARK: - Word Embedding / Similarity

    /// Compute cosine distance between two words using Apple's word embedding.
    /// - Parameters:
    ///   - word1: First word.
    ///   - word2: Second word.
    ///   - language: Language for the embedding model.
    /// - Returns: Distance from 0.0 (identical) to 2.0 (maximally different), or nil if embedding unavailable.
    func wordDistance(_ word1: String, _ word2: String, language: NLLanguage = .english) -> Double? {
        guard let embedding = NLEmbedding.wordEmbedding(for: language) else { return nil }
        return embedding.distance(between: word1, and: word2)
    }

    /// Find words similar to the given word.
    /// - Parameters:
    ///   - word: The reference word.
    ///   - maxResults: Maximum similar words to return.
    ///   - language: Language for the embedding model.
    /// - Returns: Array of (word, distance) tuples sorted by similarity.
    func similarWords(to word: String, maxResults: Int = 10, language: NLLanguage = .english) -> [(String, Double)] {
        guard let embedding = NLEmbedding.wordEmbedding(for: language) else { return [] }

        var results: [(String, Double)] = []
        embedding.enumerateNeighbors(for: word, maximumCount: maxResults) { neighbor, distance in
            results.append((neighbor, distance))
            return true
        }
        return results
    }
}

4. ModelConfiguration.swift — Configuration and Compute Unit Selection

import CoreML

/// Configuration presets for Core ML model inference.
/// Choose based on your app's performance and power requirements.
struct ModelConfig {
    let computeUnits: MLComputeUnits
    let maxPredictionBatchSize: Int
    let allowLowPrecision: Bool

    /// Maximum performance. Uses CPU, GPU, and Neural Engine.
    /// Best for: real-time camera processing, time-critical predictions.
    static let highPerformance = ModelConfig(
        computeUnits: .all,
        maxPredictionBatchSize: 10,
        allowLowPrecision: true
    )

    /// CPU only. Predictable latency, no GPU contention with UI rendering.
    /// Best for: background processing, when GPU is busy with rendering.
    static let lowPower = ModelConfig(
        computeUnits: .cpuOnly,
        maxPredictionBatchSize: 1,
        allowLowPrecision: false
    )

    /// CPU + Neural Engine. Good balance of speed and efficiency.
    /// Best for: most apps. Avoids GPU contention while using Neural Engine acceleration.
    static let balanced = ModelConfig(
        computeUnits: .cpuAndNeuralEngine,
        maxPredictionBatchSize: 5,
        allowLowPrecision: true
    )

    /// CPU + GPU. For devices without Neural Engine or when NE is unavailable.
    /// Best for: older devices, GPU-optimized models.
    static let gpuAccelerated = ModelConfig(
        computeUnits: .cpuAndGPU,
        maxPredictionBatchSize: 5,
        allowLowPrecision: true
    )

    /// Create an MLModelConfiguration from this config.
    func mlConfiguration() -> MLModelConfiguration {
        let config = MLModelConfiguration()
        config.computeUnits = computeUnits
        config.allowLowPrecisionAccumulationOnGPU = allowLowPrecision
        return config
    }
}

5. VisionService.swift — Vision Request Pipeline

import Vision
import UIKit
import os

/// Service for executing Vision framework requests with proper error handling
/// and image orientation support.
struct VisionService {
    private let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? "app", category: "VisionService")

    // MARK: - Text Recognition (OCR)

    /// Recognize text in an image.
    /// - Parameters:
    ///   - image: The image to scan.
    ///   - level: Recognition accuracy level. `.accurate` is slower but better.
    ///   - languages: Languages to recognize (e.g., ["en-US", "fr-FR"]). Nil for automatic.
    /// - Returns: Array of recognized text strings, ordered top-to-bottom.
    func recognizeText(
        in image: UIImage,
        level: VNRequestTextRecognitionLevel = .accurate,
        languages: [String]? = nil
    ) async throws -> [String] {
        guard let cgImage = image.cgImage else {
            throw VisionServiceError.invalidImage
        }

        let orientation = CGImagePropertyOrientation(image.imageOrientation)

        return try await withCheckedThrowingContinuation { continuation in
            let request = VNRecognizeTextRequest { request, error in
                if let error {
                    continuation.resume(throwing: VisionServiceError.requestFailed(error))
                    return
                }

                let results = (request.results ?? [])
                    .compactMap { $0.topCandidates(1).first?.string }
                continuation.resume(returning: results)
            }

            request.recognitionLevel = level
            if let languages {
                request.recognitionLanguages = languages
            }

            performRequest(request, on: cgImage, orientation: orientation, continuation: continuation)
        }
    }

    // MARK: - Face Detection

    /// Detected face with bounding box and optional landmarks.
    struct DetectedFace: Sendable {
        /// Bounding box in normalized coordinates (0.0 to 1.0, origin at bottom-left).
        let boundingBox: CGRect
        let landmarks: VNFaceLandmarks2D?
    }

    /// Detect faces in an image.
    /// - Parameters:
    ///   - image: The image to scan.
    ///   - includeLandmarks: Whether to detect facial landmarks (eyes, nose, mouth, etc.).
    /// - Returns: Array of detected faces.
    func detectFaces(
        in image: UIImage,
        includeLandmarks: Bool = false
    ) async throws -> [DetectedFace] {
        guard let cgImage = image.cgImage else {
            throw VisionServiceError.invalidImage
        }

        let orientation = CGImagePropertyOrientation(image.imageOrientation)

        return try await withCheckedThrowingContinuation { continuation in
            if includeLandmarks {
                let request = VNDetectFaceLandmarksRequest { request, error in
                    if let error {
                        continuation.resume(throwing: VisionServiceError.requestFailed(error))
                        return
                    }

                    let results = (request.results ?? []).map { face in
                        DetectedFace(boundingBox: face.boundingBox, landmarks: face.landmarks)
                    }
                    continuation.resume(returning: results)
                }
                performRequest(request, on: cgImage, orientation: orientation, continuation: continuation)
            } else {
                let request = VNDetectFaceRectanglesRequest { request, error in
                    if let error {
                        continuation.resume(throwing: VisionServiceError.requestFailed(error))
                        return
                    }

                    let results = (request.results ?? []).map { face in
                        DetectedFace(boundingBox: face.boundingBox, landmarks: nil)
                    }
                    continuation.resume(returning: results)
                }
                performRequest(request, on: cgImage, orientation: orientation, continuation: continuation)
            }
        }
    }

    // MARK: - Barcode Detection

    /// Detected barcode with payload and symbology.
    struct DetectedBarcode: Sendable {
        let payload: String
        let symbology: VNBarcodeSymbology
        let boundingBox: CGRect
    }

    /// Detect barcodes and QR codes in an image.
    /// - Parameters:
    ///   - image: The image to scan.
    ///   - symbologies: Specific barcode types to look for. Nil for all supported types.
    /// - Returns: Array of detected barcodes.
    func detectBarcodes(
        in image: UIImage,
        symbologies: [VNBarcodeSymbology]? = nil
    ) async throws -> [DetectedBarcode] {
        guard let cgImage = image.cgImage else {
            throw VisionServiceError.invalidImage
        }

        let orientation = CGImagePropertyOrientation(image.imageOrientation)

        return try await withCheckedThrowingContinuation { continuation in
            let request = VNDetectBarcodesRequest { request, error in
                if let error {
                    continuation.resume(throwing: VisionServiceError.requestFailed(error))
                    return
                }

                let results = (request.results ?? []).compactMap { barcode -> DetectedBarcode? in
                    guard let payload = barcode.payloadStringValue else { return nil }
                    return DetectedBarcode(
                        payload: payload,
                        symbology: barcode.symbology,
                        boundingBox: barcode.boundingBox
                    )
                }
                continuation.resume(returning: results)
            }

            if let symbologies {
                request.symbologies = symbologies
            }

            performRequest(request, on: cgImage, orientation: orientation, continuation: continuation)
        }
    }

    // MARK: - Body Pose Detection

    /// Detected body pose with joint positions.
    struct BodyPose: Sendable {
        let joints: [VNHumanBodyPoseObservation.JointName: CGPoint]
        let confidence: Float
    }

    /// Detect human body poses in an image.
    /// - Parameter image: The image to analyze.
    /// - Returns: Array of detected body poses with joint positions.
    func detectBodyPose(in image: UIImage) async throws -> [BodyPose] {
        guard let cgImage = image.cgImage else {
            throw VisionServiceError.invalidImage
        }

        let orientation = CGImagePropertyOrientation(image.imageOrientation)

        return try await withCheckedThrowingContinuation { continuation in
            let request = VNDetectHumanBodyPoseRequest { request, error in
                if let error {
                    continuation.resume(throwing: VisionServiceError.requestFailed(error))
                    return
                }

                let results = (request.results ?? []).compactMap { observation -> BodyPose? in
                    guard let points = try? observation.recognizedPoints(.all) else { return nil }
                    let joints = points.reduce(into: [VNHumanBodyPoseObservation.JointName: CGPoint]()) { dict, pair in
                        if pair.value.confidence > 0.3 {
                            dict[pair.key] = pair.value.location
                        }
                    }
                    return BodyPose(joints: joints, confidence: observation.confidence)
                }
                continuation.resume(returning: results)
            }

            performRequest(request, on: cgImage, orientation: orientation, continuation: continuation)
        }
    }

    // MARK: - Private Helpers

    private func performRequest<T>(
        _ request: VNRequest,
        on cgImage: CGImage,
        orientation: CGImagePropertyOrientation,
        continuation: CheckedContinuation<T, Error>
    ) {
        let handler = VNImageRequestHandler(
            cgImage: cgImage,
            orientation: orientation,
            options: [:]
        )

        do {
            try handler.perform([request])
        } catch {
            continuation.resume(throwing: VisionServiceError.requestFailed(error))
        }
    }
}

enum VisionServiceError: Error, LocalizedError {
    case invalidImage
    case requestFailed(Error)

    var errorDescription: String? {
        switch self {
        case .invalidImage:
            return "Could not extract image data for Vision processing"
        case .requestFailed(let error):
            return "Vision request failed: \(error.localizedDescription)"
        }
    }
}

6. SwiftUI Integration Examples

Image Classification View

import SwiftUI

struct ClassifierView: View {
    @State private var selectedImage: UIImage?
    @State private var classifications: [ImageClassifier.Classification] = []
    @State private var isClassifying = false
    @State private var error: String?
    @State private var showingImagePicker = false

    private let classifier = ImageClassifier()

    var body: some View {
        NavigationStack {
            VStack(spacing: 20) {
                if let image = selectedImage {
                    Image(uiImage: image)
                        .resizable()
                        .scaledToFit()
                        .frame(maxHeight: 300)
                        .clipShape(RoundedRectangle(cornerRadius: 12))
                }

                if isClassifying {
                    ProgressView("Classifying...")
                }

                if !classifications.isEmpty {
                    List(classifications, id: \.label) { item in
                        HStack {
                            Text(item.label)
                            Spacer()
                            Text(item.confidencePercent)
                                .foregroundStyle(.secondary)
                        }
                    }
                    .listStyle(.plain)
                }

                if let error {
                    Text(error)
                        .foregroundStyle(.red)
                        .font(.caption)
                }
            }
            .padding()
            .navigationTitle("Image Classifier")
            .toolbar {
                Button("Choose Photo") { showingImagePicker = true }
            }
            .sheet(isPresented: $showingImagePicker) {
                // Use your image picker implementation
            }
            .onChange(of: selectedImage) { _, newImage in
                guard let newImage else { return }
                Task { await classifyImage(newImage) }
            }
        }
    }

    private func classifyImage(_ image: UIImage) async {
        isClassifying = true
        error = nil
        defer { isClassifying = false }

        do {
            classifications = try await classifier.classify(image, maxResults: 5, minimumConfidence: 0.05)
        } catch {
            self.error = error.localizedDescription
        }
    }
}

Text Analysis View

import SwiftUI

struct TextAnalysisView: View {
    @State private var inputText = ""
    @State private var sentiment: Double = 0
    @State private var language: String = ""
    @State private var entities: [TextAnalyzer.Entity] = []
    @State private var wordCount: Int = 0

    private let analyzer = TextAnalyzer()

    var body: some View {
        NavigationStack {
            Form {
                Section("Input") {
                    TextEditor(text: $inputText)
                        .frame(minHeight: 100)
                }

                if !inputText.isEmpty {
                    Section("Analysis") {
                        LabeledContent("Sentiment") {
                            HStack {
                                Text(sentimentEmoji)
                                Text(String(format: "%.2f", sentiment))
                                    .foregroundStyle(.secondary)
                            }
                        }

                        LabeledContent("Language", value: language)
                        LabeledContent("Word Count", value: "\(wordCount)")
                    }

                    if !entities.isEmpty {
                        Section("Entities") {
                            ForEach(entities, id: \.text) { entity in
                                LabeledContent(entity.text, value: entity.type.rawValue)
                            }
                        }
                    }
                }
            }
            .navigationTitle("Text Analysis")
            .onChange(of: inputText) { _, newText in
                analyzeText(newText)
            }
        }
    }

    private func analyzeText(_ text: String) {
        sentiment = analyzer.detectSentiment(text)
        language = analyzer.detectLanguage(text)?.rawValue ?? "Unknown"
        entities = analyzer.recognizeEntities(text)
        wordCount = analyzer.wordCount(text)
    }

    private var sentimentEmoji: String {
        if sentiment > 0.1 { return "+" }
        else if sentiment < -0.1 { return "-" }
        else { return "~" }
    }
}

Source: SKILL.md on GitHub

No alerts16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill provides comprehensive and well-architected patterns for integrating Apple's Core ML, Vision, and Natural Language frameworks. It includes standard templates for model management, real-time processing, and remote model updates using official Apple APIs.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    2/3 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 1361023. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 3 months ago
What it can do
Reads files Edits files Runs commands
last_verified
2026-07-16
review_by
2027-06-22
os_version
iOS 27 / macOS 27
All 7 allowed tools
ReadWriteEditGlobGrepBashAskUserQuestion

README badge

README badge for rshankras/claude-code-apple-skills/core-ml