@annadata/pack-it-pkc
v1.3.0
Published
Convert documents to Study PKC v3 + offline KYC. On-device chat via Apple Intelligence / Gemini Nano (BGE embeddings, SmolLM fallback).
Maintainers
Readme
pack-it-pkc
Installable TypeScript library: convert documents to Markdown, edit PDF blocks, pack Study PKC v3 (RAG + flash + MCQ), and run offline KYC verification with QR proof.
What's new in v1.3.0
@annadata/pack-it-pkc/inference/local-llm—createHybridCapacitorProvider()uses Apple Intelligence (iOS) or Gemini Nano (Android) for chat when available; BGE-micro GGUF for embeddings; SmolLM2 GGUF only as last-resort chat on web or unsupported devices.@annadata/pack-it-pkc/kyc— fully client-side KYC: OCR, PAN/Aadhaar parsing, ONNX face match, background removal, confidence scoring, masked QR artifact.- Optional peer
@capacitor/local-llm(CapacitorLABS experimental plugin).
On-device inference
| Role | Primary | Fallback |
|------|---------|----------|
| Chat (study RAG, flashcards, math/chem assist) | Apple Intelligence / Gemini Nano via @capacitor/local-llm | SmolLM2-135M GGUF via llama-cpp-pro |
| Embeddings (hybrid BM25 + vector retrieval) | BGE-micro GGUF via llama-cpp-pro | — (required for vector search) |
Recommended host wiring:
import { createHybridCapacitorProvider } from "@annadata/pack-it-pkc/inference/local-llm";
const llm = await createHybridCapacitorProvider();
// Pass to generateStudyPkc, answerStudyQuestion, MarkItDown, PdfCanvasEditor, etc.GGUF-only hosts can keep using CapacitorGgufProvider from @annadata/pack-it-pkc/inference/capacitor.
Platform notes (Capacitor Local LLM):
- iOS text LLM requires iOS 26+ with Apple Intelligence enabled.
- Android requires a Gemini Nano–capable device (e.g. Pixel 9+); call
systemAvailability()/download()before first prompt. - Web/PWA: system LLM unavailable → SmolLM GGUF fallback automatically.
- Android caps
maximumOutputTokensat 256; study RAG clamps accordingly on that path.
Install
npm install @annadata/pack-it-pkc
# Optional peers (host app)
npm install llama-cpp-pro # BGE embeddings + SmolLM chat fallback
npm install @capacitor/local-llm # Apple Intelligence / Gemini Nano chat
npm install @capacitor/filesystem # native model download (iOS/Android/desktop Capacitor)Local link while developing the host app:
npm install ../pack-it-pkcPublic API
| Import | Use |
|--------|-----|
| @annadata/pack-it-pkc | MarkItDown, converters, PDF extract, generateStudyPkc, packToPkc / packStudyPkc, model catalog/download |
| @annadata/pack-it-pkc/inference/local-llm | createHybridCapacitorProvider (recommended on Capacitor native) |
| @annadata/pack-it-pkc/inference/capacitor | CapacitorGgufProvider (GGUF only) |
| @annadata/pack-it-pkc/pdf/editor | PdfCanvasEditor (DOM) |
| @annadata/pack-it-pkc/pdf/editor.css | Editor styles |
| @annadata/pack-it-pkc/kyc | runKycVerification, KYC PKC pack/unpack, QR sign/generate/scan |
| @annadata/pack-it-pkc/assets/manifest | KaTeX + language font path helpers |
Convert + pack
import { MarkItDown, packToPkc, generateStudyPkc } from "@annadata/pack-it-pkc";
import { createHybridCapacitorProvider } from "@annadata/pack-it-pkc/inference/local-llm";
const llm = await createHybridCapacitorProvider();
const md = new MarkItDown({ llmProvider: llm });
// Browser / Capacitor / PWA — pass bytes (not filesystem paths)
const result = await md.convertBytes(pdfBytes, { filename: "doc.pdf", extension: ".pdf" });
const pkc = packToPkc(result.markdown, { title: result.title, source: "doc.pdf" });convertLocal("/path") is Node-only. In browser/Capacitor use convertBytes / convert(Uint8Array).
Study PKC v3 (RAG + flash + MCQ + binary assets)
import { generateStudyPkc, unpackStudyPkc, answerStudyQuestion } from "@annadata/pack-it-pkc";
const { document, pkc, warnings } = await generateStudyPkc(pdfBlocks, {
llmProvider: llm,
onProgress: console.log,
});
// Study v3: text chunks + binary image assets (no packed embeddings).
// Host runs BGE lazily at chat time (optional durable StudyEmbeddingCache).
const loaded = unpackStudyPkc(pkc); // container PKC\x02
await answerStudyQuestion({
doc: loaded,
query: "…",
provider: llm,
embeddingCache, // e.g. IndexedDB Float32 cache in the PKC app
});Breaking vs ≤1.2.x: Study schema is v3; packs use container PKC\x02 with raw assets. Legacy Study v2 packs are not readable — re-generate.
PDF canvas editor
import { PdfCanvasEditor } from "@annadata/pack-it-pkc/pdf/editor";
import "@annadata/pack-it-pkc/pdf/editor.css";
import "@annadata/pack-it-pkc/assets/katex/katex.css";
const editor = new PdfCanvasEditor({
container,
fileName: "doc.pdf",
pdfBytes,
doc: pdfBlocks,
llmProvider: llm,
onChange: (doc) => { /* persist */ },
});Models
With createHybridCapacitorProvider(), chat may skip SmolLM download when the system LLM is ready (skipChatGgufDownload). Embeddings always use BGE:
import {
downloadModel,
ensureModelReady,
ensureEmbeddingModelReady,
DEFAULT_OFFLINE_MODEL_ID,
SMOL_CHAT_MODEL_ID,
SYSTEM_LOCAL_LLM_CHAT_ID,
} from "@annadata/pack-it-pkc";
// BGE (~17 MB) — required for hybrid vector retrieval
await ensureEmbeddingModelReady(llm, DEFAULT_OFFLINE_MODEL_ID);
// Chat — skips SmolLM when Apple Intelligence / Gemini Nano is available
await ensureModelReady(llm); // may resolve to SYSTEM_LOCAL_LLM_CHAT_ID
// Force GGUF chat path (web / fallback)
await downloadModel(SMOL_CHAT_MODEL_ID);
await ensureModelReady(llm, SMOL_CHAT_MODEL_ID);Storage: PWA → OPFS; native Capacitor → @capacitor/filesystem Data dir; Node → ~/.cache/pack-it-pkc/models. ONNX KYC models use the same download machinery (runtime: "onnx" in catalog).
Offline KYC verification + QR proof
import { runKycVerification, createHmacSigner, scanKycQrCode } from "@annadata/pack-it-pkc/kyc";
const signer = createHmacSigner(hostSuppliedKey); // host-injected — never a baked-in default
const result = await runKycVerification(
{ documentBytes: idPhotoOrPdfBytes, filename: "id.jpg", selfieBytes },
{ sign: signer, onStatus: console.log },
);
result.record.confidence.status; // "verified" | "needs_review" | "rejected"
result.pkc; // full unmasked record (PKC\x02 container) — local archival only
result.qrPayload; // masked fields + optional photo thumbnail
result.qrCodeImage?.dataUrl;
const scanned = await scanKycQrCode(scannedQrImageBytes, { verify: signer });
scanned.status; // "valid" | "tampered" | "unsigned" | "unparseable"Supports PAN and Aadhaar (Verhoeff checksum) with generic-ID fallback. Face match (SCRFD + MobileFaceNet-class embed) and background removal (U2Netp) are pluggable. Out of scope: liveness, live registry lookups, asymmetric signing.
Architecture
assets/ # Static KaTeX + language fonts (copied to dist/assets)
src/
assets/ # Path helpers (manifest.ts)
detect/ # Magic-byte format detection
convert/ # MarkItDown + format converters
inference/ # Catalog, download, session, CapacitorGgufProvider, hybrid local-llm
pdf/ # Block extract + PdfCanvasEditor
pkc/ # Markdown PKC v1 + Study PKC v3 + RAG chat
kyc/ # Offline KYC + QR (separate subpath entry)
types/ utils/Host requirements
| Dependency | Purpose |
|------------|---------|
| mupdf | PDF extraction (AGPL-3.0) |
| llama-cpp-pro | BGE embeddings; SmolLM chat fallback |
| @capacitor/local-llm | Apple Intelligence / Gemini Nano chat (optional; native Capacitor) |
| @capacitor/filesystem | Native model storage (optional; PWA uses OPFS) |
| tesseract.js / onnxruntime-web / @zxing/library | Only when importing @annadata/pack-it-pkc/kyc |
Scripts
| Command | Description |
|---------|-------------|
| npm run build | Build dist/ (+ copy KaTeX/assets) |
| npm test | Vitest |
| npm run test:manual | Local Vite harness |
| npm run prepublishOnly | Build + test before publish |
Publish
npm run build && npm test
npm publish --access publicScoped package: @annadata/pack-it-pkc.
License
MIT — Mr. Yakub Mohammad <[email protected]>
PDF conversion uses MuPDF.js (AGPL-3.0). Distributing this library with PDF support requires complying with the AGPL.
