# Desert Ant Labs Desert Ant Labs is a frontier AI lab for on-device models and inference. We're building lightning-fast specialized models and native SDKs for Apple, Android, and the web, to add intelligence to your products in a few lines of code. Pricing: Each model is free up to 100k monthly active devices. Inference is unlimited. ## Redact: PII redaction (available) URL: https://desertant.com/models/redact/ A support transcript is full of names, addresses and card numbers you are not allowed to keep. Redact masks them in the browser or on the phone, before the text is ever sent, so your systems store `[GIVEN_NAME_1]` where the customer's name was. Redact also puts the values back. Mask a prompt before sending it to an external model, then restore the real names and numbers in the answer. Keep the placeholder map and the result is pseudonymized; delete the map and the masked copy is anonymized. Microsoft Presidio, AWS Comprehend and Google Cloud DLP cover the same ground, and all of them want the text on their servers. Redact catches 88.8% of personal data across 27 languages from 23M parameters, so the same masking runs in a browser tab, on a phone, or in a Node backend. Cards, IBANs, national IDs and VAT numbers are checked against their real checksums, Luhn and ISO-13616 and per-country, so a random 16-digit string is never masked as a card number. ### Use cases - Scrub a web form before it submits: Mask what someone typed in the browser, so the personal data never reaches your backend and your backend never has to be in scope for it. The same code runs client-side that runs on the phone. - Safe LLM round-trips: Mask a prompt before it leaves for an external model, then restore the real values in the answer. Numbered placeholders like `[GIVEN_NAME_1]` and `[EMAIL_1]` keep the round-trip lossless, so the user still reads a normal reply. - Scrub at ingest, without a DLP bill: Run Redact in Node over transcripts, logs and uploads as they arrive. No per-call charge and no data leaving your infrastructure, unlike a cloud DLP service that bills for every document. - Support and chat on mobile: Strip names, emails, cards and IBANs out of a conversation on the phone before it syncs, so raw personal data never reaches your servers or your logging vendor's. - Redact in 27 languages: A single model covers 27 languages across Latin, Greek and Cyrillic scripts: every official EU language, plus Norwegian and Icelandic. A form filled in Athens and one filled in Helsinki go through the same code path. ### Capabilities - 20 detection categories. Names, street addresses, cities, ZIP codes, emails, phone numbers, credit cards, bank accounts and IBANs, routing numbers, IP addresses, URLs, passports, driving licenses, tax IDs, SSNs, and government IDs. - Deterministic validation layer: Luhn card checks, ISO-13616 IBANs, checksummed national IDs for all 24 EU countries, all 27 EU VAT formats, IMEI, and per-country driving licenses. - Reversible redaction with unique numbered placeholders for LLM round-trips. - Filter by category and inspect every detection with its exact character span. - Company names are detected as their own category and left in place by default, because a company is not a person. Ask for them and they get masked with everything else. ### Specs - Languages: 27 languages: every official EU language, plus Norwegian and Icelandic (full list on the model card) - On-device size: 11.6MB Core ML (Apple, 4-bit); 24.5MB LiteRT (Android, web, int8) - Model: Token classifier with a deterministic layer for structured IDs, 23M params - Privacy: Runs fully on device. Text is never sent anywhere. Platforms: Swift (https://github.com/Desert-Ant-Labs/desert-ant-core), Kotlin (https://github.com/Desert-Ant-Labs/desert-ant-core), JS (https://github.com/Desert-Ant-Labs/desert-ant-core) Weights: https://huggingface.co/desert-ant-labs/redact Demo: https://huggingface.co/spaces/desert-ant-labs/redact-demo ## Emo: Emoji suggestions (available) URL: https://desertant.com/models/emo/ Type "Dentist appointment" and get 🦷 🪥 🏥 🩺. Type "Pay my bills" and get 💰 💳 🧾. Emo is tuned for how people write in a task list or a chat, not how they write an essay, and every suggestion carries its skin-tone variants. A picker shows you a grid to browse. Emo reads the text and proposes the emoji that fit, the way a predictive keyboard proposes the next word. Emo is small and fast enough to run on every keystroke, and never calls a server. ### Use cases - Suggest as they type: Offer emoji in the suggestion strip while someone is still typing, the way a predictive keyboard offers words, on the device and with no network round-trip. - Label an event as it is created: Tuned for short entries: "Dentist appointment" gets 🦷 🪥 🏥 🩺, so a calendar or task app can tag an item the moment someone saves it. - Emoji for a draft message: Suggest the emoji that fit a message as someone writes, in any of 22 languages, without sending the draft anywhere. - Keep your picker, add suggestions: Emo fills the suggestion strip above the keyboard, so a user who knows what they want still browses the grid, and everyone else gets the right emoji first. ### Capabilities - Curated vocabulary of 812 everyday emoji, with skin-tone variants. - Multilingual: 22 languages, including CJK, Arabic, Thai, and Hindi. - Well under 2ms per suggestion on device. - 5MB on Apple, 11MB on LiteRT. No server call. ### Specs - Languages: 22, including English, Spanish, French, German, Portuguese, and Japanese - On-device size: 5MB on Apple via Core ML, 11MB via LiteRT elsewhere (model + tokenizer) - Speed: Under 2ms per suggestion - Model: Two-stream text classifier: lexical n-grams plus a multilingual embedding Platforms: Swift (https://github.com/Desert-Ant-Labs/desert-ant-core), Kotlin (https://github.com/Desert-Ant-Labs/desert-ant-core), JS (https://github.com/Desert-Ant-Labs/desert-ant-core) Weights: https://huggingface.co/desert-ant-labs/emo Demo: https://huggingface.co/spaces/desert-ant-labs/emo-demo ## Gist: Content topic tagging (available) URL: https://desertant.com/models/gist/ A post called "How to film a two-person podcast with two iPhones" is tagged technology and creator economy. "Cómo invertir en fondos indexados" is tagged finance. The same 36 topics apply in all 101 languages, so shipping into a second market needs no second setup. The right topic is in the top three 91% of the time, and most items land on two or three topics. That is enough for a feed to sort, filter or route without a classification API. Two cheap passes over the words do the work, so a browser tab tags a post without warming up a language model. Scores add up across a collection, so a whole podcast feed or channel gets its own topics. An English-only build drops the model to 15MB. ### Use cases - Route a post without a server call: Tag posts, articles or videos by topic on the device, so a feed can sort, filter or route them without a classification API in the path. - Describe a channel from its posts: Add up an account's posts into channel-level topics. A directory or a recommender can then say what a podcast, a newsletter, or a feed is about without anyone writing a description. - A topic per item for the ranker: Give a recommendation feed or a moderation queue a cheap, private topic signal for every item, with no per-call cost as the feed grows. - On-device organization: Group a user's own notes, bookmarks, or library by topic on the device, so a personal archive becomes searchable without a single file leaving the device. ### Capabilities - 36 topics, from technology and finance to the creator economy; most items carry two or three. - 101 languages from one model, with no language setting to pass in. - Two-stream classifier with no transformer, so scoring costs CPU time and nothing else. - Compact English-only variant (15MB) for English-only apps, selectable from the Swift SDK today with `Gist(variant: .english)`. ### Specs - Languages: 101 - Topics: 36, multi-label - On-device size: 74MB multilingual, or 15MB English-only - Model: Two-stream classifier: a multilingual static embedding plus hashed n-grams Platforms: Swift (https://github.com/Desert-Ant-Labs/desert-ant-core), Kotlin (https://github.com/Desert-Ant-Labs/desert-ant-core), JS (https://github.com/Desert-Ant-Labs/desert-ant-core) Weights: https://huggingface.co/desert-ant-labs/gist Demo: https://huggingface.co/spaces/desert-ant-labs/gist-demo ## Shapes: Shape recognition (available) URL: https://desertant.com/models/shapes/ Draw a rough circle and Shapes snaps it to a clean one. Shapes fits precise vector geometry, snaps to axes, circles, squares and 15-degree rotations, and rejects scribbles that are not shapes. On Apple, one call adds Notes-style smart-shape snapping to a PencilKit canvas, and the live preview stays. Apple's own "Snap to Shape" is private API that third-party apps cannot call, so Shapes does the same job in one line. The model is small enough to ship inside the app, with no download. In the browser, Shapes runs through LiteRT.js. ### Use cases - Notes-style smart shapes: Add snap-to-shape to a PencilKit canvas with `canvasView.enableShapeSnapping()`. Live preview, undo and redo preserved, filling the gap left by Apple's private Snap to Shape API. - Clean up a freehand diagram: Turn rough strokes into precise geometry in a diagram or whiteboard tool. Works with tldraw and Excalidraw stroke data. - Cross-platform drawing: One recognizer covers iOS, Android, and the web, so you write the snapping code once. - Ships in the app, not as a download: On Apple the recognizer is 0.2MB and ships inside the binary, and the Android package bundles it by default. In the browser the SDK fetches 1.3MB once and caches it. ### Capabilities - One stroke at a time, passed as its `[x, y]` points, from PencilKit, tldraw, Excalidraw, or your own canvas. - Recognizes rectangle, ellipse, triangle, star, and line, and rejects non-shapes. - Snaps to axes, circles, squares, and 15-degree rotations. - PencilKit live snapping via one call: `canvasView.enableShapeSnapping()`. - Runs through LiteRT.js in the browser. Node uses prebuilt native libraries. ### Specs - Shape classes: Rectangle, ellipse, triangle, star, line - On-device size: 0.2MB Core ML (Apple); 1.3MB LiteRT (Android, web) - Speed: <10ms - Web runtime: LiteRT.js in the browser, native libraries on Node Platforms: Swift (https://github.com/Desert-Ant-Labs/desert-ant-core), Kotlin (https://github.com/Desert-Ant-Labs/desert-ant-core), JS (https://github.com/Desert-Ant-Labs/desert-ant-core) Weights: https://huggingface.co/desert-ant-labs/shapes Demo: https://huggingface.co/spaces/desert-ant-labs/shapes-demo ## Clear: Speech enhancement (available) URL: https://desertant.com/models/clear/ Adobe Podcast, Dolby and Auphonic bill by the minute and require audio or video to be uploaded to their servers. Clear runs a 5-minute clip in 1s on an iPhone 16 Pro, on the device. Record on a laptop or phone mic in an untreated room with traffic outside, and the result sounds close-miked: warm low-mids, the voice forward, no background noise. With output presets for Spotify, Apple Podcasts, and YouTube loudness. Clear is available in two variants: `clear-studio` and `clear-natural`. Studio, the default, cleans down to near silence. Natural keeps room tone, breath and lip texture for treated rooms and intentional voiceover. ### Use cases - Podcast and video mastering: Clean a laptop-mic or untreated-room recording in one pass. Pick Apple Podcasts, Spotify, YouTube, or EBU R128, and Clear automatically normalizes the volume to their specification. - Kill the room, not only the hiss: Most denoisers stop at the hiss. Clear removes the reflections too, so a podcast, video or meeting recorded at home or in a conference room sounds close-miked instead of boxy. - No upload, no per-minute bill: Studio cleanup as a feature has no metered pricing for users. Enhancement runs on-device, so there is no cloud audio bill that grows with every minute of audio processing. - Rescue a recording from a bad room: Clean up voice notes and recorded calls before they go to transcription or into an archive, so a call taken in a kitchen still transcribes cleanly. - Fix an hour-long recording on a phone: The file path streams chunk by chunk when writing to disk, so a one-hour recording uses the same memory as a ten-second clip. The enhanced file lands next to the original. ### Capabilities - Trained for a rich, present, close-miked podcast sound: low-mids forward, no thin or distant voice. - Denoise plus dereverb from a fine-tuned DeepFilterNet 3 model. An untreated bedroom or hotel room comes out closer to a treated studio, with no reverberation added back. - Sibilance-safe and artifact-free: no harsh peaks on S, T and F, and no pumping or musical noise. Breaths and plosives stay intact. - Volume presets: Apple Podcasts, Spotify, YouTube, EBU R128 (LUFS / EBU R128 normalization). Output is 48kHz. - Decodes any audio file AVFoundation can read, and the output extension picks the encoding: `.wav` for 16-bit PCM, `.m4a`, `.mp4`, or `.aac` for AAC, `.caf` or `.aiff` for PCM. Without a filesystem, `enhance(bytes:)` returns WAV bytes. - Two variants: `clear-studio` for a quiet studio cleanup, `clear-natural` to keep room tone. The weights are fetched from the Hub on first use and cached. `Strength` and `Mastering` controls on both to adjust to taste. ### Specs - Speed: 302x realtime on an iPhone 16 Pro - Model: Fine-tuned DeepFilterNet 3 - On-device size: 9.0MB Core ML, 24MB ONNX, per variant - Platforms: iOS 18+, macOS 15+, tvOS 18+, visionOS 2+ (Core ML); Android 7+ (LiteRT); the browser (WebAssembly and LiteRT.js); Node Platforms: Swift (https://github.com/Desert-Ant-Labs/desert-ant-core), Kotlin (https://github.com/Desert-Ant-Labs/desert-ant-core), JS (https://github.com/Desert-Ant-Labs/desert-ant-core) Weights: https://huggingface.co/desert-ant-labs/clear Demo: https://huggingface.co/spaces/desert-ant-labs/clear-demo ## Uhm: Filler-word detection (available) URL: https://desertant.com/models/uhm/ An hour-long episode is analyzed in 12s on an iPhone 17 Pro. A back catalog is a batch job you run locally, not a cloud invoice. Uhm gets there by skipping the transcript step. The usual way to find an "um" is to transcribe the whole file and search the text. A transcript would not help anyway: models like Whisper leave fillers out of their output, so the ums never appear in the text to find. Uhm reads the waveform instead and marks every filler it hears, so an editor can cut them or a one-click cleanup can tighten the whole take. Open an audio or video file and every filler word is listed with its time, so you click one and land on it. Apple runs the 45MB Core ML build. The browser demo and a Python backend run the same model as 51MB of ONNX, so a web editor and a batch job behave identically. ### Use cases - Clean a back catalog overnight: At 296x realtime a hundred hours of archive is 20 minutes of local compute on an iPhone. Batch the whole library instead of paying a cloud speech service per minute for audio you already own. - Cut every filler on the timeline: Mark every "um" and "uh" so an editor, or a one-click cleanup, can tighten a recording without running a transcription pass first. - A filler timeline in the browser: In a web editor, every filler in an audio or video file is listed with a click-to-seek time, computed client-side, with no upload and no worker queue behind it. - Drop the ums before they reach the text: Flag disfluencies in the audio and leave them out of the words that reach your transcript, so the finished text reads the way the speaker meant to say the line. - Speaking practice and coaching: Count how often a speaker reaches for a filler across a recorded talk and show them the pattern, in a practice app that never uploads their voice. ### Capabilities - Frame-precise: accurate to 20ms. - Acoustic detection: works directly on the waveform, no transcript required. - `Bias` preset: precision, balanced, or recall. - Trained on English, transfers to Spanish, French, German, and Dutch without retraining. ### Specs - Resolution: 20ms frame resolution - Model: Acoustic, transcript-free - On-device size: 45MB Core ML (Apple); 51MB ONNX (browser, server) - Languages: English; transfers to Spanish, French, German, and Dutch - Speed: 296x realtime on an iPhone 17 Pro Platforms: Swift (https://github.com/Desert-Ant-Labs/desert-ant-core), Kotlin (coming soon), JS (coming soon) Weights: https://huggingface.co/desert-ant-labs/uhm Demo: https://huggingface.co/spaces/desert-ant-labs/uhm-demo ## Tongue: Language identification (available) URL: https://desertant.com/models/tongue/ "kann ich das haben" is German. "안녕하세요" is Korean. Three words is the hard case, and three words is what a search box gives you. From three words, Tongue scores 0.933 where a 293MB detector scores 0.887. Tongue is 2MB, and works in two stages: some scripts belong to one language only, so Hangul is Korean and Thai is Thai, settled with no model involved. The rest go to the model. Tongue needs no tokenizer, vocabulary file, or inference runtime, which is how the whole package fits in 2MB. When the input is too short to call, Tongue reports a tie. ### Use cases - Route text by language: Pick the right translation model, analyzer, or support queue from the first few words a user types, entirely on device. - Keyboards and input: Detect the language mid-sentence to switch autocorrect, suggestions, or layouts, at a cost of tens of microseconds per keystroke. - Search and content pipelines: Tag short strings with a language before indexing or moderation, without a network round-trip or a per-request service. - Ask for more text instead of guessing: "la casa" is Italian and Spanish in equal measure. Tongue reports the tie, so your product waits for another word rather than switching the keyboard by mistake. ### Capabilities - 84 languages: 59 decoded by the model, 25 settled by script alone. - 2MB int8 weights, bundled in the package; nothing is downloaded. - Tens of microseconds per detection, on the main thread. - Identical answers on Swift, Kotlin, and JavaScript, held to shared golden vectors. - Reports a reliability score and marks every tie. ### Specs - Languages: 84, across 31 scripts - On-device size: 2MB int8 weights, inside the package - Speed: Tens of microseconds per detection - Model: Script router plus hashed character n-grams into an int8 linear head Platforms: Swift (https://github.com/Desert-Ant-Labs/desert-ant-core), Kotlin (https://github.com/Desert-Ant-Labs/desert-ant-core), JS (https://github.com/Desert-Ant-Labs/desert-ant-core) Weights: https://huggingface.co/desert-ant-labs/tongue Demo: https://huggingface.co/spaces/desert-ant-labs/tongue-demo ## Moderator: Content moderation (available) URL: https://desertant.com/models/moderator/ Questionable uploads never reach your servers, your CDN or a moderator's queue. Five separate detections (exposed nipples, genitals, buttocks, nudity and sexual activity) feed the score, and your policy decides which of them count. Every image Moderator trained on is licensed or synthetic, so it goes into a commercial product with no copyright exposure. The whole model is 9.7MB on Apple and 9.2MB elsewhere, so the check runs on the phone before the upload starts. ### Use cases - Pre-upload filtering: Screen a user's image on the phone before it uploads. Nothing questionable reaches your servers, and no one on your team has to look at the image to find out. - A policy you control: The `.standard` policy counts all five detections. `.allowTopless` leaves exposed nipples out of the score, for platforms whose rules permit them. - Warn at the picker, not after the post: Score an image the moment a user picks it, and warn them on the spot. An hour-later takedown costs you a support thread. ### Capabilities - Trained only on permissively licensed and synthetic images, with nothing scraped. - Scores any image or video frame for nudity on the device, before upload. - Five detection heads: exposed nipples, genitals, buttocks, nudity, and sexual activity. - A policy decides what counts toward the NSFW score, from `.standard` (all five) to `.allowTopless` (excludes exposed nipples). ### Specs - Accuracy: Recall 87.8%, specificity 93.7% at threshold 0.50 - Model: On-device image classifier - On-device size: 9.7MB on Apple (Core ML), 9.2MB elsewhere (LiteRT) - Platforms: iOS, macOS, tvOS, visionOS, Android, Linux, Windows, browser, and Node Platforms: Swift (https://github.com/Desert-Ant-Labs/desert-ant-core), Kotlin (https://github.com/Desert-Ant-Labs/desert-ant-core), JS (https://github.com/Desert-Ant-Labs/desert-ant-core) Weights: https://huggingface.co/desert-ant-labs/moderator ## Schemer: Structured extraction (closed beta) URL: https://desertant.com/models/schemer/ Write "Lunch with Priya next Thursday at 1" and the event is typed: the date resolved against the device clock, the duration a number, the title a string. No parsing step, no schema validation, no retry loop. Nothing is invented either. Schemer leaves a missing field empty 91% of the time; prompted LLMs manage 18-43%. Extracted strings are verbatim substrings of the input with character offsets, so auditing is a substring check. Schemer works from plain JSON Schema, the shape OpenAI and Gemini accept, in any of 13 languages. ### Use cases - Natural language to calendar entry: Turn "Lunch with Priya next Thursday at 1, about an hour" into a typed event: title, start datetime, duration, and recurrence. Runs in a keyboard or notes app, on device and offline. - Messages into structured records: Turn a chat message, email, or scanned note into a CRM lead, order, or invoice. Names, emails, amounts, and dates arrive decoded to their real type, a missing field arrives as null, and the record is ready to save without a parsing step. - On-device agents and form-fill: Give a local agent a JSON Schema and free text, and the typed JSON it gets triggers an action or prefills a form. No cloud LLM, no per-call cost. ### Capabilities - Works from plain JSON Schema, the one OpenAI and Gemini accept, and writes typed JSON that matches it. - Decodes strings, numbers, booleans, datetimes, labels, and arrays to their real types. - Explicit absence detection: reports a field as missing instead of inventing a value. - Works across 13 languages from a single model, with no per-language setup. ### Specs - Model: 211M parameters - Accuracy: 0.800 (int8), 0.911 absence detection - On-device size: 230MB per platform (int8) - Formats: Core ML and LiteRT, cross-platform Platforms: Swift (coming soon) Weights: https://huggingface.co/desert-ant-labs/schemer Demo: https://huggingface.co/spaces/desert-ant-labs/schemer-demo ## Eye: Image classification (available) URL: https://desertant.com/models/eye/ Find the screenshots, receipts and selfies in a camera roll, the shots where someone's eyes are closed, and the photos too sensitive to show. Eye tags every photo on the device, so no image is uploaded. Eye groups near-duplicate shots and picks the keeper from each burst, with no one's eyes closed and the best faces. A camera roll of forty takes of the same moment becomes one photo to look at. A photo takes 5.5ms on the Neural Engine of a Mac with an M6, so 10,000 photos take under a minute. In Chrome with WebGPU, a photo takes 41ms. ### Use cases - Sort the camera roll: Separate screenshots, receipts, documents and whiteboards from the photos people took, so a gallery app can file them away or offer to clear them out. - Keep the best of a burst: Collapse near-duplicate shots into one group and show the keeper first, with no one's eyes closed. The rest can go in one tap. - Hide sensitive photos: Blur explicit, violent or medical photos before anyone sees them, in a shared family album or a browser upload form. Use the strict cutoff to hide a photo automatically. - Search photos by what's in them: Find every photo of the dog, the beach or a receipt across 558 scenes and the photo types. It works in a web app or a Node backend, with no cloud vision API. - Crop a cover image: Pick the best frame of a video or the best square or widescreen crop of a photo for a thumbnail or a share card. Eye also turns sideways photos the right way up. ### Capabilities - One `analyze` call gives tags with a confidence, three scores (aesthetic, keeper and cover), and the people, pets and faces in the photo. The same call finds the best crop for any aspect ratio, a rotation fix and an embedding. - Tags cover the photo type (screenshot, receipt, document, ID card, whiteboard and more), quality (sharp, blurry, bokeh) and people (group shot, portrait, everyone smiling). Others cover keep or delete reasons, sensitive content and 558 scenes. - Every tag is calibrated so 0.5 is the recommended cutoff and 0.9 a strict one. At 0.5, a screenshot tag is right 98% of the time, a receipt tag 100%, people 95% and eyes closed 92%. - Scene tags are right 88% of the time at the median. The keep or delete reasons, such as forgettable or bad framing, are the least reliable, so use them for suggestions. - Each face gets its own tags: eyes closed, smiling, looking at the camera or away, happy, surprised. Eye analyzes up to 20 faces per photo by default. - `Eye.duplicates`, `Eye.best` and `Eye.similar` work across a library: near-duplicate groups, optionally only for photos taken seconds apart, the keeper of a set, and photos ranked by similarity. - Analyses save as the same JSON in Swift, Kotlin and JavaScript, so an app can store them and filter later without loading the model. - `parts` chooses what to compute: `photo`, `layout`, `faces` and `sharpness`. Each part is one or more model runs, so leave out what you don't need. - 48MB as Core ML for Apple platforms, on the Neural Engine, and 66MB as LiteRT for Android, Linux, Windows, Node and the browser. The SDK downloads the model on first use and caches it. - In the browser, Eye runs on the GPU through WebGPU where the browser has it, and on the CPU through WebAssembly otherwise. ### Specs - Speed: 5.5ms a photo on the Neural Engine (M6 Mac); 41ms with WebGPU in Chrome - Accuracy: At the 0.5 cutoff: screenshots 98% precise, receipts 100%, scenes 88% at the median - Tags: Photo type, keep or delete, quality, people, faces, sensitive content, and 558 scenes - On-device size: 48MB Core ML (Apple); 66MB LiteRT (Android, Linux, Windows, Node, the browser) - Platforms: iOS 18+, macOS 15+, tvOS 18+, visionOS 2+ (Core ML); Android, Linux, Windows (LiteRT); the browser and Node (LiteRT.js) Platforms: Swift (https://github.com/Desert-Ant-Labs/desert-ant-core), Kotlin (https://github.com/Desert-Ant-Labs/desert-ant-core), JS (https://github.com/Desert-Ant-Labs/desert-ant-core) Weights: https://huggingface.co/desert-ant-labs/eye ## Who: Who said what (available) URL: https://desertant.com/models/who/ Who is made for podcasts, interviews, calls and meetings, and handles recordings of any length. A 50-minute interview takes 3s on a MacBook Pro, entirely on the device. Use the timestamps to label a transcript by speaker, jump to the next time a guest talks, or cut every time the speaker changes. Who numbers the speakers in the order they first speak, and when two people talk at once, Who marks both of them. Who processes each five-minute section in one pass and matches voices across sections. On AMI meeting recordings, Who labels speakers with a 12.6% error rate, lower than 13.1% for pyannote on a server GPU and 19.4% for FluidAudio on the same Mac. Who also runs twice as fast as FluidAudio. ### Use cases - Label a transcript by speaker: Pair Who with Voz, and each line of the transcript shows who said it. A reader follows the conversation instead of one block of anonymous text. - Jump to the next time a guest talks: Filter a two-hour interview or meeting to one speaker and go straight to their turns instead of scrubbing the timeline. The recording stays on the device. - Cut every time the speaker changes: Switch camera angles in a two-camera interview or a video podcast wherever the speaker changes. Every turn has a start and an end time, so each change of speaker is a cut point. - Leave out the laughter: Drop the audience laughter and the voice that said one line from across the room. Who leaves out every speaker under the share of the recording you set and renumbers the rest. ### Capabilities - Who labels up to four speakers in each five-minute section, and more across a whole recording, by matching voices across sections. - Each turn is one stretch of one speaker's speech, with a speaker number and start and end times in seconds, to the nearest 10ms. Turns of different speakers overlap when people talk over each other. - Who numbers speakers in the SDK from zero, in the order they first speak, and doesn't identify anyone by name. - Two Core ML graphs on the Neural Engine read each section, an encoder and a query graph. A third graph makes a voice print of each speaker from the moments they speak alone, and Who matches every speaker across the whole recording at once. - A speaker with under a second of solo speech has no voice print of their own and joins the nearest speaker in time. A second of laughter inside someone else's turn goes to that speaker. - 950x realtime on a MacBook Pro with the M5 Pro, through the SDK: 544 minutes of AMI meetings in 34s. The 8-bit build runs at 953x. - Memory through the SDK: 275MB with the model loaded, and a peak of 336MB on an 8-minute recording, 437MB on a 34-minute recording, and 927MB on a 2.65-hour recording. - The Core ML download is 81MB as float16 or 42MB with 8-bit weights, and both builds have the same error rate on AMI meetings, 12.6%. The 8-bit build saves no memory, since the Neural Engine decompresses the weights at load. - Who also comes as a 49MB LiteRT build, which the SDK runs on Android, Linux and Windows, and a 99MB ONNX build, which the SDKs don't run yet. On CPU alone, the LiteRT build runs 544 minutes of audio in 87s on the M5 Pro and in 191s on a 24-core AMD EPYC server, measured outside the SDK. - `keepingSpeakers(minimumShare:)` drops every speaker under a share of the recording and renumbers the rest, so laughter, applause, and jingles drop out. At 5%, the filter cleared the laughter and audience on the podcasts we tried. For a news program with many brief speakers, keep the share low or off. - Diarize an audio file by URL or path, or pass mono samples at any sample rate. The SDK converts the sample rate for you. - The SDK downloads the weights from Hugging Face on first use and caches them. `download(progress:)` fetches them ahead of time, and `Who(directory:)` runs offline from a folder you manage. ### Specs - Speed: 950x realtime on a MacBook Pro (M5 Pro), a 50-minute interview in 3s - Accuracy: 12.6% diarization error rate on AMI meetings; 8.4% on VoxConverse with up to 4 speakers - Speakers: Up to 4 in each five-minute section, more across a recording of any length - Output: Per-speaker turns with start and end times in seconds, to the nearest 10ms; overlapping speech kept - On-device size: 81MB Core ML (float16, default); 42MB with 8-bit weights - Memory: 275MB with the model loaded; 927MB peak on a 2.65-hour recording - Platforms: iOS 18+, macOS 15+, tvOS 18+, visionOS 2+ (Core ML); Android, Linux and Windows (LiteRT, on the CPU) Platforms: Swift (https://github.com/Desert-Ant-Labs/desert-ant-core), Kotlin (https://github.com/Desert-Ant-Labs/desert-ant-core) Weights: https://huggingface.co/desert-ant-labs/who ## Face: Face matching (closed beta) URL: https://desertant.com/models/face/ Open a photo library with Face and the pictures are grouped by person, so you find everyone in one tap. Pick one photo and Face finds every other photo and video moment that person appears in, so search by example needs no name. All of the matching happens on the device. The photos stay where they are, nothing is uploaded, and there is no face infrastructure on your side to run or secure. Face is on Apple platforms first, in closed beta. ### Use cases - Group a library by person: Sort a user's photos into people the way the system photo app does, in your own app, with no image leaving the device to be matched. - Search by example: Pick one face and Face returns every photo that person appears in, across a library or a shared album, in one pass. - Find a person across a clip: Match the same face frame after frame through a video, so an app can jump to every moment one person is on screen. Check whether the person in a clip is the person in a photo, without the footage leaving the device. ### Capabilities - Match a face against a set, group a library by person, or search by example. - Runs fully on device; images and face data never leave the device. ### Specs - Platforms: Apple (Swift) - Status: Closed beta Platforms: Swift (coming soon) Weights: https://huggingface.co/desert-ant-labs/face ## Toxic: Hate speech triage (closed beta) URL: https://desertant.com/models/toxic/ Toxic scores three things separately, so a product can treat them differently. Hate speech means public incitement to violence or hatred against a protected group. Abuse means insults, ranked by how severe they are. A threat means violence against a person or group. On Multilingual HateCheck, a public suite of hand-written examples, Toxic gets 85 out of 100 across the seven EU languages. Mistral's Shieldstral gets 79 and wants a 16GB GPU; the guard models sized for a phone get 65. ### Use cases - Warn before the message is sent: Score outgoing messages on the device before they are sent, so hateful, abusive or threatening content can trigger an inline warning or a review path without ever reaching your servers. - Comment triage without infrastructure: Run every incoming comment through Toxic locally in the client and send only the likely hate speech to a moderator queue. The rest never needs a human, and no comment costs a cloud call. - Moderate in 23 European languages: One model file covers 23 languages, from English, Spanish, and Polish through Bulgarian, Estonian, and Irish. No per-language model, and no separate language-detection step. ### Capabilities - Three scores per text: hateful, abusive, threat. - Ten target signals under the hate score: race, color, religion, descent, national or ethnic origin, sexual orientation, gender, disability, age, other. - 23 languages from one model file, with a recommended setting per language in the model metadata. - Runs fully on device. No text leaves the device to be scored. ### Specs - Languages: 23, from English, German, and French through Greek, Lithuanian, and Irish - On-device size: 80MB Core ML (4-bit); 91MB LiteRT (int4); 100MB ONNX (browser) - Model: XLM-R-base, 12 layers, 159.6M params - Accuracy: 0.847 macro F1 on the 7 EU languages in Multilingual HateCheck, shipped weights; 23 languages supported - Platforms: iOS and macOS (Core ML), Android (LiteRT), browser (ONNX); weights on Hugging Face, not in the SDK yet Platforms: Weights: https://huggingface.co/desert-ant-labs/toxic Demo: https://huggingface.co/spaces/desert-ant-labs/toxic-demo ## Align: Word timestamps (available) URL: https://desertant.com/models/align/ Apple says "world" runs from 2.61 to 3.04 seconds. Align says 2.57 to 2.98. Cut there and the cut is clean, the caption lights up on the word, and the highlight starts where the speaker did. You keep Apple's transcriber. Align reads the same audio SpeechAnalyzer already gets and returns the same words with tighter start and end times, in a few milliseconds, from a 0.7MB download. On clean audio that takes Apple's average miss from 113ms to 45ms. A word Align can't improve keeps Apple's timing, so a correction can only help or leave the word alone. Nine languages, and a locale outside them passes through with Apple's timings untouched. ### Use cases - Word-by-word captions that keep up: Light up each word as it is said in a captions view, a karaoke-style lyric screen, or a language-learning app, from Apple's transcript. The timings land on the word instead of a tenth of a second off it. - Cut a clip on a word: Trim a recording to a quote in a podcast editor or a video app and have the cut start where the word starts. No frame of the previous word, no clipped consonant, and no manual nudge on the timeline. - Highlight the spoken word in a transcript: Scroll a transcript in step with playback in a meeting recorder or a lecture app, with the highlight moving on the word rather than drifting ahead of the audio. - Search that lands on the moment: Jump to the second a word was said in an archive of recordings, on the device. The timings are tight enough that the playhead starts on the word and not in the middle of the previous one. ### Capabilities - Corrects the word-level timings Apple's `SpeechTranscriber` and `SpeechAnalyzer` return, without replacing them: same words, same result surface, tighter `audioTimeRange` values. - Mean timing error from 124.2ms to 43.9ms, macro-averaged across all nine languages so no single language carries the figure. On English it goes further: 106.4ms to 20.2ms. - On a 500-clip sample of LibriSpeech test-clean, 95% of words land within 50ms of the reference, up from 37%. The worst tenth improves most: from 230.7ms to 33.0ms, about one frame of 30fps video. - A structural fallback keeps Apple's original timestamp whenever a correction would be invalid, hits the search window's edge, or lacks streaming context. - Nine languages: English, Spanish, French, Italian, Portuguese, German, Japanese, Korean, and Chinese. Other locales pass through unchanged. - About 0.7MB of compiled Core ML in two stages, run on the CPU and Neural Engine; a typical result is refined in a few milliseconds. ### Specs - Accuracy: 20.2ms mean error on LibriSpeech test-clean against Apple's 106.4ms, and 43.9ms across all nine languages against Apple's 124.2ms - On-device size: About 0.7MB compiled Core ML (two 0.3MB stages plus the filter bank and calibrator) - Languages: English, Spanish, French, Italian, Portuguese, German, Japanese, Korean, Chinese - Model: Two-stage coarse-to-fine cascade over a log-mel spectrogram, with a gradient-boosted calibrator - Platforms: iOS 26, macOS 26, tvOS 26, visionOS 26 on Core ML, plus Linux, Windows, and Node on LiteRT Platforms: Swift (https://github.com/Desert-Ant-Labs/desert-ant-core), JS (https://github.com/Desert-Ant-Labs/desert-ant-core) Weights: https://huggingface.co/desert-ant-labs/align ## Clips: Clip selection (available) URL: https://desertant.com/models/clips/ From a 25-minute recording, Clips ranks 12 clips in 9s on an iPhone 17 Pro. Create a ranked selection of clips to share instantly. Clips analyzes a transcript to find the best moments and stories, and returns a ranked list of clips. Use the ranked selection to create highlight reels or a summary video. Build your own clipping engine or auto-edit, with no inference cost. Nothing is uploaded, so clipping a back catalog costs the same as clipping one video. There's no length limit or maximum context size. Use Clips on short videos or audio files to get a summary in seconds, or churn through hour-long recordings without limitations. ### Use cases - Shorts from a podcast episode: Post the five best moments of an hour-long episode as shorts, ranked, before the export finishes, in just a few seconds directly on-device. - Auto edit a long take: Turn a rambling 25-minute take into a tight cut in a video editor. Get a highlight reel with the most important insights from a video, ready to review or publish. - Clip the back catalog: Run a library of recorded talks or streams through Clips on a Mac overnight. Nothing is uploaded and nothing is billed per video, so a thousand videos cost the same as one. - Highlights in a hundred languages: A creator app that ships in Spanish, Portuguese, and German gets the same clip selection in all three: one model covers a hundred languages, from the transcript, on the device. ### Capabilities - Ranks a transcript's best non-overlapping moments: each clip gets scored and ranked. Build strong selections or unique editing features to pick the best sentences in video or audio recordings. - Control the selection. Threshold on `percentile`, not the raw score: a 0.8 cut averages 5 clips covering 17% of the video (highlights), a 0.3 cut averages 32 clips covering 74% (auto edit). - No context window: sentences run through the selector in batches and each candidate is scored on its own, so there's no context limit to work around. Create clips from long video or audio transcripts without any issues. - Faster, better, cheaper. A 404-sentence, 25-minute transcript returns 12 clips in 9.19s on an iPhone 17 Pro and 10.22s on an iPhone 15 Pro; 2.78ms per candidate on the encoder alone. - Multi-language support. 100 languages in a single 284MB int8 Core ML package on Apple. - Pair Clips with our Title model to generate titles and descriptions and build a fully local clipping engine, that runs fully local. ### Specs - Speed: A 25-minute transcript in 9.19s on an iPhone 17 Pro, 10.22s on an iPhone 15 Pro - On-device size: 284MB int8 Core ML (Apple); two 283MB LiteRT files for Android, Linux, and Windows - Languages: 100 - Model: Four heads: saliency, start, end, and clip score - Platforms: iOS 18, macOS 15, tvOS 18, visionOS 2 (Core ML). Android, Linux, and Windows LiteRT files are published but not supported in our SDK yet. Platforms: Swift (https://github.com/Desert-Ant-Labs/desert-ant-core), Kotlin (coming soon) Weights: https://huggingface.co/desert-ant-labs/clips ## Ear: Spoken language detection (available) URL: https://desertant.com/models/ear/ A voice note comes in and the transcriber is set to English. 30 seconds in, Ear says Portuguese, and the transcriber that runs next is the Portuguese one instead of an English one returning nonsense with confidence. Ear doesn't listen to the whole file. Ear finds the three thirty-second stretches that sound most like speech, skips the jingle and the silence, and names the language in 250ms. The answer comes with a confidence and a flag that says whether to trust it. When the top two candidates are too close to separate, Ear says so. You ask the user or fall back to a general model instead of transcribing in the wrong language. One SDK, every platform: Swift on Apple, Kotlin on Android, JavaScript in the browser and Node. Nothing is uploaded. ### Use cases - Pick the right transcriber first: A transcriber pointed at the wrong language returns nonsense with confidence. In a meeting recorder or a voice-notes app, run Ear on the first 30 seconds and start the transcriber, the captions, and the translation in the language actually spoken. - Sort an archive of recordings: Run Ear over a library of voice notes, calls, or episodes in a Node script or a Mac app overnight, and every file has its language by morning. Nothing is uploaded and nothing is billed per file. - Route a call or a voicemail: In a support app or a messaging product, name the language of an incoming call or a voicemail before it reaches a person. The call lands with someone who speaks it, or with the right speech model. - Caption in the browser: A web video tool identifies the spoken language client-side, with the same SDK in the browser and in Node, and picks the caption language so the uploader never has to. ### Capabilities - 99 languages, from Afrikaans to Yoruba, including the major European, Asian, and African languages. - Picks the three thirty-second windows that sound most like speech rather than reading by position, so a music intro or a silent stretch doesn't fool it. Choosing by position finds the language 4% of the time on a five-minute recording with speech in a tenth of it. - Returns the language, a confidence, the ranked candidates, and an `isReliable` flag. The flag is false when the top two are too close to call, and false for Norwegian, Swedish, and Danish, which the model confuses with each other. - Already-decoded audio at any sample rate works; a file URL works on Apple. - The weights download on first use and are cached; construction does no work and starts no download. ### Specs - Languages: 99 - Input: Three thirty-second windows of the recording; any sample rate - Speed: 250ms per identification, three windows - Platforms: iOS, macOS, tvOS, visionOS (Core ML); Android, Linux, Windows (LiteRT); browser (WebAssembly and LiteRT.js); Node Platforms: Swift (https://github.com/Desert-Ant-Labs/desert-ant-core), Kotlin (https://github.com/Desert-Ant-Labs/desert-ant-core), JS (https://github.com/Desert-Ant-Labs/desert-ant-core) Weights: https://huggingface.co/desert-ant-labs/ear ## Title: Titles and descriptions (available) URL: https://desertant.com/models/title/ A clip about shooting a podcast on two phones gets the title "Filming a two-person podcast on iPhone", three to eight words, with a one-line description under it. Nobody typed either one. The register is deliberately plain: no emoji, no hashtags, no clickbait, and the description says what this passage is, not what its subject is. Fine-tuned on transcript clips, and it holds up on a news paragraph, a product description, or an email. Title runs on Apple silicon only, through MLX. Load it once and reuse it; pair it with Clips and every clip leaves with a name. ### Use cases - Name every clip: Clips finds the moments in a recording; Title names them. A creator app posts each short with a title of three to eight words and a one-line description, written on the phone, with nothing sent anywhere. - Title a note as it's saved: A notes app or a voice memo app names the entry from its own text the moment it is saved. The list reads like a list instead of a column of first lines and timestamps. - Describe a recording for the library: A podcast or lecture app writes the episode title and the two-sentence description from the transcript on a Mac, ready to edit. The field is never blank until someone gets to it. ### Capabilities - A title of three to eight words with no final punctuation, and a description of one or two sentences, from one call. - Plain register on purpose: no emoji, no hashtags, no clickbait. The description identifies this passage rather than its topic. - Fine-tuned on transcript clips; works on general prose (news paragraphs, product descriptions, emails). - Names a `Clip` from Clips directly; one card per clip, in the same order. - Nothing is downloaded. Ship the model files in a folder with the app and pass that folder to Titles; the other models fetch their weights on first use, this one doesn't. - MLX rather than Core ML: short generation measured 5.7-8.3x faster on the GPU than on the Neural Engine. A 350M-parameter model quantized to 6-bit, behind the `MLX` package trait, loaded once and reused. ### Specs - Output: A 3 to 8 word title and a 1 to 2 sentence description - Model: Fine-tuned from granite-4.0-350m, 6-bit quantized, MLX - Platforms: iOS, macOS, tvOS, visionOS on Apple silicon (MLX); no Android, Linux, or Windows build Platforms: Swift (https://github.com/Desert-Ant-Labs/desert-ant-core) Weights: https://huggingface.co/desert-ant-labs/title ## Voz: Speech recognition (available) URL: https://desertant.com/models/voz/ Transcribe an audio or video file with Voz and get accurate start and end times for every word. 10 minutes takes 2s on an iPhone, on the device, so nothing is uploaded and nothing is billed per minute. On Apple silicon, the model runs on the Neural Engine, so transcribing is lightning fast and consumes less power. On a Mac a back catalog of podcasts, interviews, and lectures runs through in one pass, and nothing is uploaded. The timestamps are precise enough to edit on. Word starts land within 83ms of a forced aligner and word ends within 95ms, for precise transcript-based editing. Voz is an Apple Neural Engine optimized version of NVIDIA's Parakeet TDT 0.6B v3, with accuracy comparable to Whisper large-v3-turbo on most audio, with a download size of only 467MB. ### Use cases - Transcribe any audio or video file: Record a podcast or a video and the full transcript is ready before the export finishes. Searchable text with a timestamp on every word, in any of 25 languages, without leaving the device. - Churn through a backlog: An archive of interviews, lectures, or meeting recordings becomes searchable in one pass on a Mac. A hundred hours runs through in 20 minutes, and nothing is uploaded. - Cut on a word: Every word carries a start and an end, so a selected range in the transcript is a cut in a video editor. Pair it with Clips for the shorts and Title to name them. ### Capabilities - Word starts within 83ms and word ends within 95ms of a forced aligner, on average, at 80ms frame resolution. - 10 minutes of audio in 2s on an iPhone 17 Pro, 1.2s on an iPhone 18 Pro, and 2.1s on an iPhone 15 Pro. On an M3 Ultra, 0.8s at 762x realtime. Single short clips run 50-62x, because every clip pays for a full 15s window. - 7.40% word error rate averaged over six Open ASR Leaderboard sets (Whisper large-v3-turbo: 7.00%), 2.83% on half an hour of narration (Whisper: 2.72%), 11.84% on AMI meetings (Whisper: 13.87%). - The whole graph runs on the Neural Engine with no CPU or GPU fallback; peak memory doesn't grow with the length of the recording. - 25 languages: Bulgarian, Croatian, Czech, Danish, Dutch, English, Estonian, Finnish, French, German, Greek, Hungarian, Italian, Latvian, Lithuanian, Maltese, Polish, Portuguese, Romanian, Russian, Slovak, Slovenian, Spanish, Swedish, and Ukrainian. - 467MB on disk, downloaded on demand and cached; the first load after a download takes 20s once while Core ML specializes, then 0.2s. Download during onboarding. - Mono audio at any sample rate; the SDK resamples and downmixes. Longer audio is cut into 15s windows at pauses and joined on the words neighboring windows agree on. - Built on NVIDIA's Parakeet TDT 0.6B v3, released under CC BY 4.0. The weights are unchanged; the conversion, compression, and the Neural Engine runtime are ours. ### Specs - Speed: 10 minutes of audio in 0.8s to 2.4s across Mac and iPhone, 251x to 762x realtime; per-device times in Performance. - Accuracy: 7.40% WER over six Open ASR Leaderboard sets; 2.83% long-form; word starts 83ms, ends 95ms mean error - On-device size: 467MB compiled Core ML, downloaded on demand - Languages: 25 European languages; accuracy from 3.31% (Italian) to 39.46% (Greek) on read speech - Model: NVIDIA Parakeet TDT 0.6B v3 (CC BY 4.0), converted to Core ML and compressed by Desert Ant Labs: log-mel frontend, conformer encoder, transducer decoder, all on the Neural Engine - Platforms: iOS, iPadOS, macOS, tvOS, visionOS (Core ML); browser and Node (WebAssembly, ONNX Runtime) Platforms: Swift (https://github.com/Desert-Ant-Labs/desert-ant-core), Kotlin (https://github.com/Desert-Ant-Labs/desert-ant-core), JS (https://github.com/Desert-Ant-Labs/desert-ant-core) Weights: https://huggingface.co/desert-ant-labs/voz