# Integrating OpenMedKit Swift Library in macOS Applications: Clinical NLP On-Device

> Integrate OpenMedKit Swift library into your macOS app for on-device clinical NLP. Leverage MLX or CoreML backends for PII extraction and NER offline.

- Repository: [Maziyar Panahi/openmed](https://github.com/maziyarpanahi/openmed)
- Tags: how-to-guide
- Published: 2026-06-12

---

**OpenMedKit enables on-device clinical NLP for macOS apps via Swift Package Manager, supporting both MLX (Apple Silicon-accelerated) and CoreML backends to perform PII extraction and named entity recognition completely offline.**

OpenMedKit is a Swift package developed in the `maziyarpanahi/openmed` repository that brings clinical NLP capabilities—specifically named entity recognition (NER) and PII de-identification—directly to macOS applications. According to the source code in `swift/OpenMedKit/`, the library abstracts complex model runtime logic behind a single `OpenMedBackend` enum, allowing developers to run Hugging Face MLX models or CoreML bundles locally without network dependencies after initial setup.

## Installing the Swift Package

Add OpenMedKit to your macOS project using Swift Package Manager (SPM). The package manifest lives in [[`swift/OpenMedKit/Package.swift`](https://github.com/maziyarpanahi/openmed/blob/main/swift/OpenMedKit/Package.swift)](https://github.com/maziyarpanahi/openmed/blob/master/swift/OpenMedKit/Package.swift) and defines dependencies on MLX, Transformers, and ZIPFoundation.

**Via Xcode:**

1. Open your macOS project and select **File > Add Packages…**.
2. Enter the repository URL: `https://github.com/maziyarpanahi/openmed`.
3. Select the **OpenMedKit** product and add it to your app target.

**Or via [`Package.swift`](https://github.com/maziyarpanahi/openmed/blob/main/Package.swift):**

```swift
// swift-tools-version:5.9
import PackageDescription

let package = Package(
    name: "YourMacApp",
    platforms: [.macOS(.v14)],
    dependencies: [
        .package(url: "https://github.com/maziyarpanahi/openmed.git", from: "1.5.5")
    ],
    targets: [
        .executableTarget(
            name: "YourMacApp",
            dependencies: [
                .product(name: "OpenMedKit", package: "openmed")
            ]
        )
    ]
)

```

## Choosing a Runtime Backend

OpenMedKit supports two backends defined in [[`OpenMedBackend.swift`](https://github.com/maziyarpanahi/openmed/blob/main/OpenMedBackend.swift)](https://github.com/maziyarpanahi/openmed/blob/master/swift/OpenMedKit/Sources/OpenMedKit/OpenMedBackend.swift). Your choice depends on whether you target Apple Silicon Macs exclusively or need broader compatibility.

### MLX Backend (Recommended for Apple Silicon)

The **MLX** backend downloads and caches Hugging Face MLX artifacts locally, running inference with Apple Silicon acceleration. This is the optimal path for production macOS apps running on physical Apple Silicon hardware.

Use `OpenMedModelStore.downloadMLXModel(repoID:)` defined in [[`OpenMedModelStore.swift`](https://github.com/maziyarpanahi/openmed/blob/main/OpenMedModelStore.swift)](https://github.com/maziyarpanahi/openmed/blob/master/swift/OpenMedKit/Sources/OpenMedKit/OpenMedModelStore.swift) to fetch the model:

```swift
import OpenMedKit

// Download and cache the MLX model (async, one-time download)
let modelDirectory = try await OpenMedModelStore.downloadMLXModel(
    repoID: "OpenMed/OpenMed-PII-ClinicalE5-Small-33M-v1-mlx"
)

// Initialize with MLX backend
let openmed = try OpenMed(
    backend: .mlx(modelDirectoryURL: modelDirectory)
)

// Extract PII entities
let entities = try openmed.extractPII(
    "Patient John Doe, DOB 1990-05-15, SSN 123-45-6789",
    confidenceThreshold: 0.85
)

```

### CoreML Backend (Bundled Models)

The **CoreML** backend uses pre-converted `.mlmodelc` or `.mlpackage` bundles shipped with your app bundle. This approach works on both Intel and Apple Silicon Macs and is required for macOS Simulator testing.

```swift
import OpenMedKit

// Locate bundled CoreML resources
let modelURL = Bundle.main.url(forResource: "OpenMedPII", withExtension: "mlmodelc")!
let labelURL = Bundle.main.url(forResource: "id2label", withExtension: "json")!

// Initialize with CoreML backend
let openmed = try OpenMed(
    backend: .coreML(
        modelURL: modelURL,
        id2labelURL: labelURL,
        tokenizerName: "OpenMed/OpenMed-PII-ClinicalE5-Small-33M-v1"
    )
)

// Run analysis
let entities = try openmed.extractPII("Medical record number: MR123456")

```

The convenience initializers for both backends are implemented in [[`OpenMedKit.swift`](https://github.com/maziyarpanahi/openmed/blob/main/OpenMedKit.swift)](https://github.com/maziyarpanahi/openmed/blob/master/swift/OpenMedKit/Sources/OpenMedKit/OpenMedKit.swift).

## Calling the Analysis API

Once initialized, the `OpenMed` class exposes two primary methods defined in the high-level API:

- **`extractPII(_:confidenceThreshold:)`** – Returns `[EntityPrediction]` containing detected PII spans with labels and confidence scores.
- **`analyzeText(_:confidenceThreshold:)`** – General NER analysis for clinical entities.

Both methods perform tokenization, inference, and post-processing (including smart span repair and entity merging logic found in [[`PostProcessing.swift`](https://github.com/maziyarpanahi/openmed/blob/main/PostProcessing.swift)](https://github.com/maziyarpanahi/openmed/blob/master/swift/OpenMedKit/Sources/OpenMedKit/PostProcessing.swift)).

```swift
// Process clinical text
let clinicalText = """
Patient: Jane Doe
Date of Birth: 01/15/1970
Insurance ID: INS-987654321
"""

do {
    let predictions = try openmed.extractPII(clinicalText, confidenceThreshold: 0.8)
    
    for entity in predictions {
        print("[\(entity.label)] \(entity.text) (confidence: \(entity.confidence))")
    }
} catch {
    print("Inference failed: \(error.localizedDescription)")
}

```

## SwiftUI Integration Example

For macOS applications using SwiftUI, implement an async task to handle model downloading and inference. The following pattern mirrors the implementation in the demo app's [[`ContentView.swift`](https://github.com/maziyarpanahi/openmed/blob/main/ContentView.swift)](https://github.com/maziyarpanahi/openmed/blob/master/swift/OpenMedScanDemo/OpenMedScanDemo/OpenMedScanDemo/ContentView.swift):

```swift
import SwiftUI
import OpenMedKit

struct ClinicalAnalyzerView: View {
    @State private var inputText = "Patient: Robert Smith, MRN: 123456, DOB: 03/22/1965"
    @State private var entities: [EntityPrediction] = []
    @State private var isProcessing = false
    @State private var errorMessage: String?
    
    var body: some View {
        VStack(spacing: 16) {
            TextEditor(text: $inputText)
                .font(.body)
                .border(Color.gray)
                .frame(minHeight: 100)
            
            Button(action: { Task { await analyze() } }) {
                if isProcessing {
                    ProgressView()
                        .scaleEffect(0.8)
                } else {
                    Text("Extract PII")
                }
            }
            .disabled(isProcessing)
            
            if let error = errorMessage {
                Text(error)
                    .foregroundColor(.red)
                    .font(.caption)
            }
            
            List(entities) { entity in
                VStack(alignment: .leading, spacing: 4) {
                    Text("[\(entity.label)] \(entity.text)")
                        .font(.headline)
                    Text(String(format: "Confidence: %.2f", entity.confidence))
                        .font(.caption)
                        .foregroundColor(.secondary)
                }
            }
        }
        .padding()
        .frame(minWidth: 600, minHeight: 400)
    }
    
    private func analyze() async {
        isProcessing = true
        errorMessage = nil
        
        do {
            // Use MLX path for Apple Silicon Macs
            let modelDir = try await OpenMedModelStore.downloadMLXModel(
                repoID: "OpenMed/OpenMed-PII-ClinicalE5-Small-33M-v1-mlx"
            )
            let analyzer = try OpenMed(backend: .mlx(modelDirectoryURL: modelDir))
            entities = try analyzer.extractPII(inputText)
        } catch {
            errorMessage = error.localizedDescription
        }
        
        isProcessing = false
    }
}

```

## Summary

- **OpenMedKit** integrates via Swift Package Manager using the repository URL `https://github.com/maziyarpanahi/openmed`.
- **Two backends** are available: **MLX** (Apple Silicon accelerated, downloads from Hugging Face) and **CoreML** (bundled offline models).
- **Key source files** include [`OpenMedBackend.swift`](https://github.com/maziyarpanahi/openmed/blob/main/OpenMedBackend.swift) for runtime selection, [`OpenMedModelStore.swift`](https://github.com/maziyarpanahi/openmed/blob/main/OpenMedModelStore.swift) for MLX downloads, and [`OpenMedKit.swift`](https://github.com/maziyarpanahi/openmed/blob/main/OpenMedKit.swift) for the public API.
- **Primary methods** are `extractPII(_:confidenceThreshold:)` and `analyzeText(_:confidenceThreshold:)`, returning `[EntityPrediction]` arrays.
- **Post-processing** logic in [`PostProcessing.swift`](https://github.com/maziyarpanahi/openmed/blob/main/PostProcessing.swift) handles entity merging and span repair automatically.

## Frequently Asked Questions

### Does OpenMedKit support Intel-based Macs?

**Yes, but only with the CoreML backend.** The MLX backend requires Apple Silicon for acceleration. For Intel Macs or macOS Simulator testing, bundle a CoreML model (`.mlmodelc`) and initialize using `OpenMed(backend: .coreML(modelURL:id2labelURL:tokenizerName:))`.

### How large are the MLX model downloads?

The MLX artifacts are downloaded once per model and cached locally by `OpenMedModelStore.downloadMLXModel(repoID:)`. The specific size depends on the Hugging Face repository (e.g., OpenMed-PII-ClinicalE5-Small-33M-v1), but typical clinical NLP models range from 100MB to 300MB compressed. Subsequent app launches use the cached local copy.

### Can I use OpenMedKit for general NER beyond PII extraction?

**Yes.** While `extractPII(_:)` is optimized for personally identifiable information, the `analyzeText(_:confidenceThreshold:)` method performs general clinical named entity recognition. The underlying tokenizer and model configuration in [`OpenMedKit.swift`](https://github.com/maziyarpanahi/openmed/blob/main/OpenMedKit.swift) support any token-classification model compatible with the OpenMed architecture.

### Is internet connectivity required after model download?

**No.** Once the MLX model is cached locally or a CoreML model is bundled, all inference runs completely offline on-device. The library performs tokenization, model inference, and post-processing (span repair and entity merging) without network calls, ensuring HIPAA-compliant on-device processing for sensitive clinical text.