OneAIFW Documentation

repository·main·Indexed 18 days ago

https://github.com/funstory-ai/aifw

A local, lightweight AI firewall designed to anonymize sensitive data (PII, secrets, crypto keys) before it is sent to LLMs and automatically restore it upon receiving the response. The project includes a JavaScript library (@oneaifw/aifw-js), a web application demo, a browser extension, and a Python backend (py-origin) utilizing Presidio and LiteLLM.

Tokens
30.6K
Snippets
117
Records
138
Agent score
63%

What's inside OneAIFW

  1. OneAIFW Backend Service API Overview

    main

    The OneAIFW backend service provides HTTP APIs for text anonymization, LLM calls with integrated privacy protection, and dynamic masking configuration.

    Default Service Address: http://127.0.0.1:8844

    Authentication: If API key authentication is enabled on the server, include the Authorization header in your requests. The value can be either <key> or Bearer <key>.

    General Specifications:

    • Character Encoding: UTF-8
    • Error Responses:
      • 401 Unauthorized: Missing or invalid Authorization header.
      • 400 Bad Request: Invalid request content.
  2. How OneAIFW Browser Extension handles models and WASM

    main

    The extension uses a hybrid approach for performance and compliance:

    • WASM Runtimes: To comply with browser store policies (Chrome Web Store/Firefox AMO), all ORT/AIFW WASM files are packaged within the extension under vendor/aifw-js/wasm/ and declared in web_accessible_resources. They are not downloaded at runtime.
    • Model Files: Because models are large and dynamic, they are downloaded from the remoteBase upon first installation and cached in IndexedDB using ensureModelCached.
    • Network Interception: The extension overrides env.fetch so that requests directed at modelsBase are served directly from IndexedDB instead of making network requests.
  3. Understand Managed Asset Loading in @oneaifw/aifw-js

    main

    When calling await init(), @oneaifw/aifw-js uses managed mode by default.

    How it works:

    1. Download: On the first run, it fetches NER models and ORT wasm from GitHub-hosted assets (hosted on Huggingface).
    2. Verify: It verifies the integrity of the downloaded files using SHA3-256.
    3. Cache: It warms up the browser's Cache Storage to ensure faster subsequent loads.

    This mode allows the library to manage heavy binary assets without requiring them to be bundled directly into your application's initial payload.

  4. Conflict Resolution and Sorting for Overlapping Addresses

    main

    When multiple address spans overlap, the following priority rules are applied to select the correct span:

    1. Depth Priority: The address containing 'deeper' (lower) hierarchical bits (e.g., L1, L2, or L3) is preferred over shallower ones.
    2. Span Length: The longer span is preferred.
    3. Start Position: The span with the earlier starting position is preferred.
    4. NER Confidence: The span with the higher NER confidence score is preferred.
  5. How OneAIFW architecture works

    main

    OneAIFW is a layered, cross-platform stack built around a single core engine. It uses a mask/restore pipeline to anonymize sensitive data before LLM calls and reconstruct it afterward.

    Core Components:

    • aifw core library (Zig + Rust): The engine implementing masking/restoring and regex/NER span fusion. It compiles to Native libraries (for Python/CLIs) and WASM (for browsers/JS).
    • Language Bindings:
      • @oneaifw/aifw-js: Uses Transformers.js for NER, converts spans to byte offsets, and calls the WASM core.
      • aifw-py: Loads the native core to provide mask_text and restore_text functions.
    • Applications:
      • Web Demo: Vite-based frontend using aifw-js.
      • Browser Extension: Injects OneAIFW into pages to protect prompts.
      • Python Services: HTTP APIs and CLIs built on aifw-py or py-origin (Presidio-based).
  6. Design of Chinese Address Recognition (Priority and Bitmap Driven)

    main

    The Chinese address recognition system uses a priority-based, bitmap-driven approach to identify and reconstruct complete Chinese addresses from NER (Named Entity Recognition) seeds.

    Core Logic:

    • Tokenization: Addresses are decomposed into ordered hierarchical levels (from macro to micro).
    • Bitmap Representation: A u32 bitset (addr_priorities) tracks which hierarchical levels are covered in an address fragment.
    • Expansion Rules: The system expands address fragments using 'Left Expansion' (macro-direction) and 'Right Expansion' (micro-direction) based on 'adjacent level' rules.
    • Privacy Threshold: An address is considered a 'private address' (eligible for masking) if its lowest covered level reaches or falls below the privacy threshold (typically L5: House Number or below).
    • Language Gating: This logic is only activated for Chinese languages (zh, zh_cn, zh_tw, zh_hk, zh_hans, zh_hant).
  7. How Anonymization and De-anonymization Work Together

    main

    To process sensitive text (e.g., translating it via an LLM) while maintaining privacy, you must use the Anonymization and De-anonymization APIs as a pair.

    The Workflow:

    1. Anonymize: Call /api/mask_text with the original text. It returns a masked_text (containing placeholders) and a maskMeta string.
    2. Process: Send the masked_text to your external service (like an LLM).
    3. De-anonymize: Call /api/restore_text using the processed text and the exact same maskMeta received in step 1.

    Critical Requirements:

    • Pairing: Every anonymization call must have a corresponding de-anonymization call to prevent memory leaks.
    • maskMeta: This is a Base64 encoded string representing the placeholdersMap. The client should treat it as an opaque string and pass it back to the server exactly as received.

    Example (Python):

    import requests
    
    base = "http://127.0.0.1:8844"
    
    # 1. Anonymize
    r = requests.post(f"{base}/api/mask_text", json={"text": "张三电话13812345678", "language": "zh"})
    output = r.json()["output"]
    masked_text = output["text"]
    mask_meta_b64 = output["maskMeta"]
    
    # 2. Restore
    r2 = requests.post(f"{base}/api/restore_text", json={"text": masked_text, "maskMeta": mask_meta_b64})
    print("restored:", r2.json()["output"]["text"])
  8. How the Mask and Restore workflow works

    main

    To process text while protecting privacy, use the Mask and Restore interfaces as a pair.

    1. Masking: Call /api/mask_text with raw text. The server returns a version of the text where sensitive data is replaced by placeholders (e.g., __PII_EMAIL_ADDRESS_00000001__) and a maskMeta string.
    2. Processing: Send the masked text to your external service (e.g., an LLM or translation engine).
    3. Restoration: Call /api/restore_text using the masked text from the LLM and the exact same maskMeta received in step 1. This replaces placeholders with the original values.

    CRITICAL: You must use the same maskMeta for both calls. maskMeta is a base64-encoded JSON string representing the placeholdersMap. Failure to pair calls correctly may lead to memory leaks in the backend service.

    # Python workflow example
    # 1. Mask
    r = requests.post(f"{base}/api/mask_text", json={"text": "张三电话13812345678", "language": "zh"})
    output = r.json()["output"]
    masked_text = output["text"]
    mask_meta_b64 = output["maskMeta"]
    
    # 2. Restore
    r2 = requests.post(f"{base}/api/restore_text", json={"text": masked_text, "maskMeta": mask_meta_b64})
    print(r2.json()["output"]["text"])
  9. Configure parameter precedence

    main

    OneAIFW resolves configuration parameters (such as API keys, ports, and logging options) using the following order of precedence:

    1. Command-line arguments (e.g., --api-key-file)
    2. Environment variables (e.g., AIFW_API_KEY_FILE)
    3. Config file (aifw.yaml, e.g., api_key_file)

    This hierarchy ensures that explicit CLI flags always override environment settings and file-based configurations.

  10. Install and set up the py-origin Python backend

    main

    The py-origin sub-project provides the OneAIFW Python backend and CLI, which uses Presidio and LiteLLM to anonymize sensitive data before LLM calls and restore it afterward.

    To set up a local environment:

    1. Clone the repository and navigate to py-origin.
    2. Create and activate a virtual environment.
    3. Install dependencies for both the service and the CLI.
    4. Download the required spaCy language models (en_core_web_sm, zh_core_web_sm, and xx_ent_wiki_sm).
    5. Configure the global ~/.aifw/aifw.yaml file by copying the asset and setting the api_key_file path to your LLM API key JSON.
    # Clone and setup venv
    git clone https://github.com/funstory-ai/aifw.git
    cd aifw/py-origin
    python -m venv .venv
    source .venv/bin/activate
    
    # Install dependencies
    pip install -r services/requirements.txt
    pip install -r cli/requirements.txt
    
    # Download spaCy models
    python -m spacy download en_core_web_sm
    python -m spacy download zh_core_web_sm
    python -m spacy download xx_ent_wiki_sm
    
    # Configure aifw.yaml
    mkdir -p ~/.aifw
    cp assets/aifw.yaml ~/.aifw/aifw.yaml
    # Note: Edit ~/.aifw/aifw.yaml to set api_key_file to your LLM API key JSON
  11. Use the OneAIFW CLI for PII masking and LLM calls

    main

    The CLI provides several ways to interact with the anonymization service:

    1. HTTP-based calls (via the server)

    These commands call the running HTTP server. If an API key is required, use --http-api-key.

    • python -m aifw call "<text>": Masks PII, calls an LLM, and restores the text.
    • python -m aifw mask_restore "<text>": A single pipeline for masking and then restoring a single text.
    • python -m aifw mask_restore_batch "<text1>" "<text2>": Batch processing for multiple texts.
    • python -m aifw multi_mask_one_restore "<text1>" "<text2>": Masks multiple items individually, then restores them all in one batch.

    2. Direct in-process calls (no HTTP server required)

    • python -m aifw direct_call "<text>": Performs the mask/LLM/restore cycle directly in-process.

    3. Overriding API keys

    You can override the LLM API key file for any call using the --api-key-file flag.

    # Call via HTTP server
    python -m aifw call "My email is test@example.com" --http-api-key 8H234B
    
    # Batch mask/restore via HTTP
    python -m aifw mask_restore_batch "text 1" "text 2" --http-api-key 8H234B
    
    # Direct in-process call
    python -m aifw direct_call "My email is test@example.com"
    
    # Call with specific API key file
    python -m aifw call --api-key-file /path/to/key.json "..."
  12. Run the Offline Demo with COOP/COEP for full performance

    main

    To enable ORT threads and SIMD, the browser requires cross-origin isolation (COOP/COEP). Use the following steps to prepare and serve the offline demo page (aifw-offline.html).

    1. Prepare assets: Copy the @oneaifw/aifw-js distribution and the offline HTML file into the public/ directory.
    2. Serve with COOP/COEP: Start the local static server.
    cd apps/webapp
    pnpm run offline      # copies assets to public/vendor/aifw-js and aifw-offline.html to public/
    pnpm run serve:coi    # starts local server on port 5500

    Access the demo at: http://127.0.0.1:5500/aifw-offline.html

    Troubleshooting: If you encounter a 404, ensure you are using the filename aifw-offline.html and that pnpm run offline was executed successfully.

    cd apps/webapp
    pnpm run offline
    pnpm run serve:coi