Skip to content

Dean151/swift-embeddings

Repository files navigation

swift-embeddings

Text embeddings and reranking for Swift: two small protocols, multiple provider clients, pure HTTP. No FoundationModels dependency.

  • One module. import Embeddings gives you the protocols, the transport, and every provider.
  • Direct constructors. Each model is a concrete public struct you build with an API key — no provider factory or registry.
  • Dependency-light. Only swift-http-types.
  • Swift 6, fully Sendable. Platforms floor: iOS 15 / macOS 12 / tvOS 15 / watchOS 8 / visionOS 1, plus Linux and Android.

Installation

.package(url: "https://github.com/tdurand/swift-embeddings.git", from: "0.1.0"),
.target(name: "App", dependencies: [
    .product(name: "Embeddings", package: "swift-embeddings"),
])

Embedding

import Embeddings

let model = VoyageEmbeddingModel(model: .voyage3, apiKey: key)
let embeddings = try await model.embed("how does Swift manage memory?")
print(embeddings.vectors) // [[Double]]

Batch inputs and provider-specific options are supported:

let model = JinaEmbeddingModel(model: .embeddingsV3, apiKey: key)
let embeddings = try await model.embed(
    ["query one", "query two"],
    options: .jina(task: .retrievalQuery, dimensions: 256)
)

Reranking

Reranking is a second-stage refinement for retrieval: fetch a broad candidate set cheaply (for example by embedding similarity), then score each candidate against the query for a sharper final ordering.

let reranker = CohereRerankModel(model: .rerankV35, apiKey: key)
let ranking = try await reranker.rerank(
    "best fruit for a smoothie",
    documents: ["apple pie", "ripe mango", "car engine"],
    options: .init(topN: 2)
)
for ranked in ranking.results {
    print(ranked.index, ranked.relevanceScore)
}

On-device embeddings (NaturalLanguage)

On Apple platforms you can embed text entirely on-device — no API key and no network request — using NaturalLanguageEmbeddingModel, backed by Apple's NaturalLanguage framework.

let model = NaturalLanguageEmbeddingModel() // .automatic
let embeddings = try await model.embed("how does Swift manage memory?")
print(embeddings.vectors) // [[Double]]

By default (.automatic) it uses the transformer-based NLContextualEmbedding on iOS 17 / macOS 14 and later — mean-pooling its per-token vectors into one vector per input — and falls back to NLEmbedding's sentence embeddings on earlier systems or when no contextual asset is available for the input's language. Use .contextual or .sentence to pin a backend. The language is auto-detected per input; pass it explicitly to skip detection:

try await model.embed("bonjour le monde", options: .naturalLanguage(language: .french))

The result's model reports the backend used (e.g. "contextual:en", "sentence:fr"), and usage is always nil since there is no token billing on-device.

Providers

Provider Embedding Reranking
Voyage VoyageEmbeddingModel VoyageRerankModel
Jina JinaEmbeddingModel JinaRerankModel
Cohere CohereEmbeddingModel CohereRerankModel
OpenAI OpenAIEmbeddingModel
Apple NaturalLanguage (on-device) NaturalLanguageEmbeddingModel

Each model takes a typed model identifier (e.g. .voyage3, with string-literal fallback for unlisted models), an apiKey, and optionally a custom transport and baseURL — handy for OpenAI-compatible gateways or tests.

Custom transport

Every model issues requests through an HTTPClientTransport. The default is URLSessionTransport; conform your own type to plug in a different HTTP client or a mock for offline tests:

struct MyTransport: HTTPClientTransport {
    func execute(_ request: HTTPRequest, body: HTTPRequestBody?) async throws -> HTTPResponseData {
        // ...
    }
}

let model = OpenAIEmbeddingModel(
    model: .textEmbedding3Small,
    apiKey: key,
    transport: MyTransport()
)

License

MIT © 2026 Thomas Durand

About

Text embeddings and reranking for Swift — one protocol, providers for Voyage, Jina, Cohere, OpenAI and on-device NaturalLanguage. Back-deploys to iOS 15.

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Sponsor this project

 

Contributors

Languages