{"id":29873191,"url":"https://github.com/ferranpons/llamatik","last_synced_at":"2026-04-17T09:02:11.184Z","repository":{"id":305109590,"uuid":"1021360304","full_name":"ferranpons/Llamatik","owner":"ferranpons","description":"True on-device AI for Kotlin Multiplatform (Android, iOS, Desktop, JVM, WASM). LLM, Speech-to-Text and Image Generation — powered by llama.cpp, whisper.cpp and stable-diffusion.cpp.","archived":false,"fork":false,"pushed_at":"2026-04-16T18:00:59.000Z","size":201109,"stargazers_count":98,"open_issues_count":16,"forks_count":18,"subscribers_count":6,"default_branch":"main","last_synced_at":"2026-04-16T19:25:30.175Z","etag":null,"topics":["ai","android","desktop","edge-ai","ggml","inference","ios","kmp","kmp-library","kotlin","ktor","llama","llama-cpp","llm","mobile-ai","multiplatform","offline-ai","on-device-ai","privacy","rag"],"latest_commit_sha":null,"homepage":"https://www.llamatik.com","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ferranpons.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"ferranpons"}},"created_at":"2025-07-17T09:27:56.000Z","updated_at":"2026-04-16T17:35:28.000Z","dependencies_parsed_at":"2025-09-19T16:18:43.042Z","dependency_job_id":"d33e4b7d-e141-403c-9aa9-d6e4c3bf832c","html_url":"https://github.com/ferranpons/Llamatik","commit_stats":null,"previous_names":["ferranpons/llamatik"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/ferranpons/Llamatik","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferranpons%2FLlamatik","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferranpons%2FLlamatik/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferranpons%2FLlamatik/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferranpons%2FLlamatik/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ferranpons","download_url":"https://codeload.github.com/ferranpons/Llamatik/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ferranpons%2FLlamatik/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31922399,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-16T18:22:33.417Z","status":"online","status_checked_at":"2026-04-17T02:00:06.879Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","android","desktop","edge-ai","ggml","inference","ios","kmp","kmp-library","kotlin","ktor","llama","llama-cpp","llm","mobile-ai","multiplatform","offline-ai","on-device-ai","privacy","rag"],"created_at":"2025-07-30T22:16:17.912Z","updated_at":"2026-04-17T09:02:11.177Z","avatar_url":"https://github.com/ferranpons.png","language":"HTML","funding_links":["https://github.com/sponsors/ferranpons"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/ferranpons/llamatik/main/assets/llamatik-new-logo.png\" alt=\"Llamatik Logo\" width=\"150\"/\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eLlamatik\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cb\u003eRun AI locally on Android, iOS, Desktop and WASM — using a single Kotlin API.\u003c/b\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  Offline-first · Privacy-preserving · True Kotlin Multiplatform\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://central.sonatype.com/artifact/com.llamatik/library\"\u003e\u003cimg src=\"https://img.shields.io/maven-central/v/com.llamatik/library.svg\" alt=\"maven central badge\"/\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Kotlin-Multiplatform-blueviolet\" alt=\"kmp badge\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Platforms-Android%20%7C%20iOS%20%7C%20Desktop%20%7C%20WASM-green\" alt=\"platforms badge\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/LLM-llama.cpp-orange\" alt=\"llama.cpp badge\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/STT-whisper.cpp-blue\" alt=\"whisper.cpp badge\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Image-stablediffusion.cpp-purple\" alt=\"stablediffusion badge\"/\u003e\n  \u003cimg src=\"https://img.shields.io/badge/License-MIT-lightgrey\" alt=\"license badge\"/\u003e\n\u003c/p\u003e\n\n---\n\n## ✨ What is Llamatik?\n\n**Llamatik** is a true Kotlin Multiplatform AI library that lets you run:\n\n- 🧠 **Large Language Models (LLMs)** via `llama.cpp`\n- 🎙 **Speech-to-Text (STT)** via `whisper.cpp`\n- 🎨 **Image Generation** via `stable-diffusion.cpp`\n\nFully **on-device**, optionally remote — all behind a **unified Kotlin API**.\n\nNo Python.  \nNo required servers.  \nYour models, your data, your device.\n\nDesigned for **privacy-first**, **offline-capable**, and **cross-platform** AI applications.\n\n---\n\n## 🚀 Features\n\n\u003cimg align=\"right\" width=\"0\" height=\"368px\" hspace=\"20\"/\u003e\n\u003cimg src=\"assets/androidScreenshots/phoneScreenshot3.png\" height=\"368px\" align=\"right\" /\u003e\n\n### 🔐 On-device \u0026 Private\n- ✅ Fully offline inference via **llama.cpp**\n- ✅ On-device speech recognition via **whisper.cpp**\n- ✅ No network required\n- ✅ No data exfiltration\n- ✅ Works with **GGUF** (LLMs) and **BIN** (Whisper) models\n\n### 🧠 LLM (llama.cpp)\n- ✅ Text generation (non-streaming \u0026 streaming)\n- ✅ Context-aware generation (system + history)\n- ✅ **Schema-constrained JSON generation**\n- ✅ Embeddings for vector search \u0026 RAG\n- ✅ Configurable context length, threads, mmap, Flash Attention\n- ✅ KV cache session save / load / continue\n- ✅ Fine-grained sampling controls (temperature, top-k, top-p, repeat penalty, max tokens)\n\n### 🎙 Speech-to-Text (whisper.cpp)\n- ✅ On-device transcription\n- ✅ Works fully offline\n- ✅ 16kHz mono WAV support\n- ✅ Selectable Whisper models\n- ✅ Integrated model download + management\n\n### 🎨 Image Generation (stable-diffusion.cpp)\n\n- ✅ On-device Stable Diffusion inference\n- ✅ Text-to-image generation\n- ✅ Fully offline\n- ✅ Works with optimized SD models\n- ✅ Native C++ integration\n\n### 🧩 Kotlin Multiplatform\n- ✅ Shared API across **Android, iOS, Desktop**\n- ✅ Native C++ integration via Kotlin/Native\n- ✅ Static frameworks for iOS\n- ✅ JNI for Desktop\n\n### 🌐 Hybrid \u0026 Remote\n- ✅ Optional HTTP client for remote inference\n- ✅ Drop-in backend server (`llamatik-backend`)\n- ✅ Seamlessly switch between local and remote inference\n\n---\n\n## 📱 Try it now (No setup required)\n\nWant to see Llamatik in action before integrating it?\n\nThe **Llamatik App** showcases:\n- On-device inference\n- Streaming generation\n- Speech-to-text (Whisper)\n- Privacy-first AI (no cloud required)\n- Downloadable models\n\n\u003ca href=\"https://play.google.com/store/apps/details?id=com.llamatik.app.android\"\u003e\u003cimg src=\"assets/google-play-button.png\" width=\"200px\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://apple.co/3Md7EIh\"\u003e\u003cimg src=\"assets/app-store-button.png\" width=\"200px\"/\u003e\u003c/a\u003e\n\n---\n\n## 🔧 Use Cases\n\n- 🧠 On-device chatbots \u0026 assistants\n- 📚 Local RAG systems\n- 🛰️ Hybrid AI apps (offline-first, online fallback)\n- 🎮 Game AI \u0026 procedural dialogue\n\n---\n\n## 🧱 Architecture (WIP)\n\n```\nYour App\n│\n▼\nLlamaBridge (shared Kotlin API)\n│\n├─ llamatik-core     → Native llama.cpp, whisper.cpp and stablediffusion.cpp (on-device)\n├─ llamatik-client   → Remote HTTP inference\n└─ llamatik-backend  → llama.cpp-compatible server\n```\n\nSwitching between **local and remote inference requires no API changes** —\nonly configuration.\n\n---\n\n## 🔧 Requirements\n\n- iOS Deployment Target: **16.6+**\n- Android MinSDK API: **26**\n- Desktop: JVM 21+\n- WASM: Modern browser with WebAssembly support\n\n## 📦 Current Versions\n\n- llama.cpp version: [b8816](https://github.com/ggml-org/llama.cpp/releases/tag/b8816)\n- whisper.cpp version [v1.8.4](https://github.com/ggml-org/whisper.cpp/releases/tag/v1.8.4)\n- stablediffusion.cpp version [master-572-1b4e9be](https://github.com/leejet/stable-diffusion.cpp/releases/tag/master-572-1b4e9be)\n\n---\n\n## 📦 Installation\n\nLlamatik is published on **Maven Central** and follows **semantic versioning**.\n\n- No custom Gradle plugins\n- No manual native toolchain setup\n- Works with standard Kotlin Multiplatform projects\n\n### Repository setup\n\n```kotlin\ndependencyResolutionManagement {\n    repositories {\n        google()\n        mavenCentral()\n    }\n}\n\ncommonMain.dependencies {\n    implementation(\"com.llamatik:library:1.0.0\")\n}\n```\n\n---\n\n## ⚡ Quick Start\n\n```kotlin\n// Resolve model path (place GGUF in assets / bundle)\nval modelPath = LlamaBridge.getModelPath(\"phi-2.Q4_0.gguf\")\n\n// (Optional) tune parameters before loading — contextLength/useMmap/flashAttention\n// take effect at model init time; the others can be changed at any time\nLlamaBridge.updateGenerateParams(\n    temperature    = 0.7f,\n    maxTokens      = 512,\n    topP           = 0.95f,\n    topK           = 40,\n    repeatPenalty  = 1.1f,\n    contextLength  = 4096,\n    numThreads     = 4,\n    useMmap        = true,\n    flashAttention = false,\n)\n\n// Load model\nLlamaBridge.initGenerateModel(modelPath)\n\n// Generate text\nval output = LlamaBridge.generate(\n    \"Explain Kotlin Multiplatform in one sentence.\"\n)\n```\n\n---\n\n## 🧑‍💻 Library Usage\n\nThe public Kotlin API is defined in `LlamaBridge` (an `expect object` with platform-specific `actual` implementations).\n\n### API surface (LlamaBridge)\n\n```kotlin\n@Suppress(\"EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING\")\nexpect object LlamaBridge {\n    // Utilities\n    fun getModelPath(modelFileName: String): String   // copy asset/bundle model to app files dir and return absolute path\n    fun shutdown()                                    // free native resources\n\n    // Embeddings\n    fun initEmbedModel(modelPath: String): Boolean    // load embeddings model\n    fun embed(input: String): FloatArray              // return embedding vector\n\n    // Text generation (non-streaming)\n    fun initGenerateModel(modelPath: String): Boolean // load generation model\n    fun generate(prompt: String): String\n    fun generateWithContext(\n        systemPrompt: String,\n        contextBlock: String,\n        userPrompt: String\n    ): String\n\n    // Text generation (streaming)\n    fun generateStream(prompt: String, callback: GenStream)\n    fun generateStreamWithContext(\n        systemPrompt: String,\n        contextBlock: String,\n        userPrompt: String,\n        callback: GenStream\n    )\n\n    // Convenience streaming overload (lambda callbacks)\n    fun generateWithContextStream(\n        system: String,\n        context: String,\n        user: String,\n        onDelta: (String) -\u003e Unit,\n        onDone: () -\u003e Unit,\n        onError: (String) -\u003e Unit\n    )\n\n    // Text generation with JSON schema (non-streaming)\n    fun generateJson(prompt: String, jsonSchema: String? = null): String\n    fun generateJsonWithContext(\n        systemPrompt: String,\n        contextBlock: String,\n        userPrompt: String,\n        jsonSchema: String? = null\n    ): String\n\n    // Text generation with JSON schema (streaming)\n    fun generateJsonStream(prompt: String, jsonSchema: String? = null, callback: GenStream)\n    fun generateJsonStreamWithContext(\n        systemPrompt: String,\n        contextBlock: String,\n        userPrompt: String,\n        jsonSchema: String? = null,\n        callback: GenStream\n    )\n\n    // KV cache session support\n    fun sessionReset(): Boolean                       // clear KV state, keep model loaded\n    fun sessionSave(path: String): Boolean            // persist KV state to file\n    fun sessionLoad(path: String): Boolean            // restore KV state from file\n    fun generateContinue(prompt: String): String      // generate using existing KV cache\n\n    // Generation parameters (applied on next generate call)\n    fun updateGenerateParams(\n        temperature: Float,       // randomness (0.0–2.0)\n        maxTokens: Int,           // max output tokens\n        topP: Float,              // nucleus sampling threshold\n        topK: Int,                // top-k sampling\n        repeatPenalty: Float,     // penalty for repeated tokens\n        contextLength: Int,       // KV context window size (requires model reload)\n        numThreads: Int,          // CPU threads for inference\n        useMmap: Boolean,         // memory-map model weights (requires model reload)\n        flashAttention: Boolean,  // enable Flash Attention (requires model reload)\n        batchSize: Int,           // token batch size for prompt processing (requires model reload)\n    )\n\n    fun nativeCancelGenerate()                        // cancel ongoing generation\n}\n\ninterface GenStream {\n    fun onDelta(text: String)\n    fun onComplete()\n    fun onError(message: String)\n}\n```\n\n### Generation Parameters\n\nAll sampling and hardware parameters are set via `updateGenerateParams`. Parameters that affect model loading (`contextLength`, `useMmap`, `flashAttention`, `numThreads`) must be set **before** calling `initGenerateModel` to take effect — the others can be updated at any time.\n\n| Parameter | Default | Description |\n|---|---|---|\n| `temperature` | `0.7` | Randomness of outputs (0 = deterministic, 2 = very random) |\n| `maxTokens` | `256` | Maximum number of tokens to generate |\n| `topP` | `0.95` | Nucleus sampling: keep tokens covering this probability mass |\n| `topK` | `40` | Only sample from the top-K most likely tokens |\n| `repeatPenalty` | `1.1` | Penalty multiplier for recently generated tokens |\n| `contextLength` | `4096` | KV cache window size in tokens *(reload required)* |\n| `numThreads` | `4` | CPU threads used for inference *(reload required)* |\n| `useMmap` | `true` | Memory-map model weights instead of loading into RAM *(reload required)* |\n| `flashAttention` | `false` | Enable Flash Attention for faster, more memory-efficient attention *(reload required)* |\n| `batchSize` | `512` | Token batch size for prompt processing — larger = faster prefill, more RAM *(reload required)* |\n\n### KV Cache Sessions\n\nUse the session API to persist and resume conversation state across calls without re-feeding the full prompt:\n\n```kotlin\n// Generate and keep the KV state in memory\nLlamaBridge.generate(\"Tell me about Kotlin.\")\n\n// Save the KV state to disk\nLlamaBridge.sessionSave(\"/path/to/session.bin\")\n\n// ... later or in a new process ...\n\n// Restore state and continue from where you left off\nLlamaBridge.sessionLoad(\"/path/to/session.bin\")\nval continuation = LlamaBridge.generateContinue(\"What about multiplatform support?\")\n\n// Reset state without unloading the model\nLlamaBridge.sessionReset()\n```\n\n### Speech-to-Text (WhisperBridge)\n\nWhisperBridge exposes a small, platform-friendly wrapper around whisper.cpp for on-device speech-to-text.\n\nThe workflow is:\n1.\tDownload a Whisper ggml model (e.g. ggml-tiny-q8_0.bin) to local storage (the app does this for you).\n2.\tInitialize Whisper once with the local model path.\n3.\tRecord audio to a WAV file and transcribe it.\n\n### Whisper API surface\n\n```kotlin\nobject WhisperBridge {\n    /** Returns a platform-specific absolute path for the model filename. */\n    fun getModelPath(modelFileName: String): String\n\n    /** Loads the model at [modelPath]. Returns true if loaded. */\n    fun initModel(modelPath: String): Boolean\n\n    /**\n     * Transcribes a WAV file and returns text.\n     * Tip: record WAV as 16 kHz, mono, 16-bit PCM for best compatibility.\n     *\n     * @param initialPrompt Optional text prepended to the decoder input (up to 224 tokens).\n     *   Use it to bias transcription toward domain-specific vocabulary (e.g. medical terms).\n     */\n    fun transcribeWav(wavPath: String, language: String? = null, initialPrompt: String? = null): String\n\n    /** Frees native resources. */\n    fun release()\n}\n```\n\n#### Example\n\n```kotlin\nimport com.llamatik.library.platform.WhisperBridge\n\nval modelPath = WhisperBridge.getModelPath(\"ggml-tiny-q8_0.bin\")\n\n// 1) Init once (e.g. app start)\nWhisperBridge.initModel(modelPath)\n\n// 2) Record to a WAV file (16kHz mono PCM16) using your own recorder\nval wavPath: String = \"/path/to/recording.wav\"\n\n// 3) Transcribe\nval text = WhisperBridge.transcribeWav(wavPath, language = null).trim()\nprintln(text)\n\n// 4) Optional: release on app shutdown\nWhisperBridge.release()\n```\n\n**Note**: WhisperBridge expects a WAV file path. Llamatik’s app uses AudioRecorder + AudioPaths.tempWavPath() to generate the WAV before calling transcribeWav(...).\n\n\n### 🎨 Image Generation (StableDiffusionBridge)\n\nLlamatik exposes Stable Diffusion through StableDiffusionBridge.\n\nWorkflow\n1.\tDownload or bundle a Stable Diffusion model.\n2.\tInitialize once.\n3.\tGenerate images from text prompts.\n\n### Stable-Diffusion API surface\n\n```kotlin\nobject StableDiffusionBridge {\n\n    /** Returns absolute model path (copied from assets/bundle if needed). */\n    fun getModelPath(modelFileName: String): String\n\n    /** Loads the Stable Diffusion model. */\n    fun initModel(modelPath: String): Boolean\n\n    /**\n     * Generates an image from a prompt.\n     *\n     * @param prompt Text prompt\n     * @param width Output width\n     * @param height Output height\n     * @param steps Inference steps\n     * @param cfgScale Guidance scale\n     * @return PNG image as ByteArray\n     */\n    fun generateImage(\n        prompt: String,\n        width: Int = 512,\n        height: Int = 512,\n        steps: Int = 20,\n        cfgScale: Float = 7.5f\n    ): ByteArray\n\n    /** Releases native resources */\n    fun release()\n}\n```\n\n#### Example\n\n```kotlin\nimport com.llamatik.library.platform.StableDiffusionBridge\n\nval modelPath = StableDiffusionBridge.getModelPath(\"sd-model.bin\")\n\nStableDiffusionBridge.initModel(modelPath)\n\nval imageBytes = StableDiffusionBridge.generateImage(\n    prompt = \"A cyberpunk llama in neon Tokyo\",\n    width = 512,\n    height = 512\n)\n\n// Save imageBytes as PNG file\n```\n\n### 👁️ Vision / Multimodal (MultimodalBridge)\n\nMultimodalBridge wraps llama.cpp's multimodal (VLM) support for on-device image analysis using vision-language models such as SmolVLM.\n\nThe workflow is:\n1. Download a VLM GGUF model and its matching mmproj GGUF file to local storage.\n2. Initialize the bridge once with both file paths.\n3. Pass image bytes (JPEG/PNG/BMP) and a text prompt to receive a streamed response.\n\n### MultimodalBridge API surface\n\n```kotlin\nobject MultimodalBridge {\n    /**\n     * Load the vision model and its multimodal projector (mmproj) side-by-side.\n     * Both files must be available on disk before calling this.\n     *\n     * @param modelPath  Absolute path to the GGUF vision model.\n     * @param mmprojPath Absolute path to the GGUF mmproj file.\n     * @return true on success.\n     */\n    fun initModel(modelPath: String, mmprojPath: String): Boolean\n\n    /**\n     * Analyze an image given as raw bytes (JPEG/PNG/BMP), streaming the response\n     * token by token via [callback].\n     *\n     * Must be called from a background thread/coroutine; blocks until generation completes.\n     */\n    fun analyzeImageBytesStream(imageBytes: ByteArray, prompt: String, callback: GenStream)\n\n    /** Cancel an in-progress analyzeImageBytesStream call. */\n    fun cancelAnalysis()\n\n    /** Free all native resources (model, mmproj context, llama context). */\n    fun release()\n}\n```\n\n#### Example\n\n```kotlin\nimport com.llamatik.library.platform.MultimodalBridge\n\n// 1) Init once — both model and mmproj must be downloaded first\nval loaded = MultimodalBridge.initModel(\n    modelPath  = \"/path/to/SmolVLM-256M-Instruct-Q8_0.gguf\",\n    mmprojPath = \"/path/to/mmproj-SmolVLM-256M-Instruct-f16.gguf\"\n)\n\n// 2) Analyze an image (e.g. loaded from disk or camera)\nval imageBytes: ByteArray = File(\"/path/to/photo.jpg\").readBytes()\n\nMultimodalBridge.analyzeImageBytesStream(\n    imageBytes = imageBytes,\n    prompt     = \"Describe what you see in this image.\",\n    callback   = object : GenStream {\n        override fun onDelta(text: String)   { print(text) }\n        override fun onComplete()            { println(\"\\n[done]\") }\n        override fun onError(message: String){ println(\"Error: $message\") }\n    }\n)\n\n// 3) Optional: cancel mid-stream\nMultimodalBridge.cancelAnalysis()\n\n// 4) Optional: release on app shutdown\nMultimodalBridge.release()\n```\n\n**Note**: MultimodalBridge requires both a vision model GGUF **and** a matching mmproj GGUF. Llamatik's app downloads both automatically when you select a VLM model.\n\n---\n\n## 🧑‍💻 Backend Usage\n\nThe Llamatik backend server is now maintained in a dedicated repository.\n\n👉 Llamatik Server Repository\n[https://github.com/ferranpons/Llamatik-Server](https://github.com/ferranpons/Llamatik-Server)\n\nVisit the repository for full setup instructions, configuration options, and usage details.\n\n---\n\n## 🔍 Why Llamatik?\n\n- ✅ Built directly on llama.cpp, whisper.cpp and stable-diffusion.cpp\n- ✅ Offline-first \u0026 privacy-preserving\n- ✅ No runtime dependencies\n- ✅ Open-source (MIT)\n- ✅ Used by real Android \u0026 iOS apps\n- ✅ Designed for long-term Kotlin Multiplatform support\n\n---\n\n## 📦 Apps using Llamatik\n\nLlamatik is already used in production apps on Google Play and App Store.\n\nWant to showcase your app here?\nOpen a PR and add it to the list 🚀\n\n---\n\n## 🤝 Contributing\n\nLlamatik is 100% open-source and actively developed.\n- Bug reports\n- Feature requests\n- Documentation improvements\n- Platform extensions\n\nAll contributions are welcome!\n\n---\n\n## 📜 License\n\nThis project is licensed under the MIT License.\u003cbr\u003e\nSee [LICENSE](./LICENSE) for details.\n\n---\n\nBuilt with ❤️ for the Kotlin community.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fferranpons%2Fllamatik","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fferranpons%2Fllamatik","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fferranpons%2Fllamatik/lists"}