npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

ngx-web-llm

v0.0.2

Published

**Bringing the power of Large Language Models (LLMs) directly to your Angular applications with WebLLM.**

Readme

ngx-web-llm

Bringing the power of Large Language Models (LLMs) directly to your Angular applications with WebLLM.

ngx-web-llm is an Angular library that wraps the WebLLM JavaScript library, allowing you to run LLM inference entirely in the browser. This enables privacy-preserving, offline-capable AI features with no server-side dependencies for inference.

Current Version: 0.0.1

Features

  • Easy Integration: Seamlessly integrate WebLLM into your Angular projects.
  • Service-Based: Core functionalities exposed via the WebLlmService.
  • Reactive: Uses RxJS Observables for model status, initialization progress, and streaming chat responses.
  • Chat Completions: Supports both single-shot and streaming chat completions.
  • Model Management: Load, reload, and unload models. Get a list of available prebuilt models.
  • Configurable: Configure default models, engine settings, and preloading.
  • Caching: Optional configuration for persistent model caching.
  • (Optional) Web Worker Support: Can offload model inference to a Web Worker (requires manual setup of the worker script by the application).

Installation

Install the library and its peer dependencies:

npm install ngx-web-llm @mlc-ai/web-llm
# or
yarn add ngx-web-llm @mlc-ai/web-llm

Basic Usage

  1. Import and Configure the Module:

    Import NgxWebLlmModule into your Angular application. For standalone applications, use importProvidersFrom. For NgModule-based applications, import into your desired module.

    For Standalone Applications (app.config.ts):

    import { ApplicationConfig, importProvidersFrom } from "@angular/core";
    import { provideRouter } from "@angular/router";
    import { NgxWebLlmModule } from "ngx-web-llm"; // Ensure this path is correct
    import { routes } from "./app.routes";
    
    export const appConfig: ApplicationConfig = {
      providers: [
        provideRouter(routes),
        importProvidersFrom(
          NgxWebLlmModule.forRoot({
            // Optional: Configure default model, preloading, caching etc.
            defaultModelId: "Llama-3.1-8B-Instruct-q4f32_1-MLC", // Example
            preload: true,
            // workerScriptUrl: 'path/to/your/web-llm.worker.js', // Only if using Web Worker
          })
        ),
      ],
    };

    For NgModule-based Applications (app.module.ts or feature module):

    import { NgModule } from "@angular/core";
    import { BrowserModule } from "@angular/platform-browser";
    import { NgxWebLlmModule } from "ngx-web-llm"; // Ensure this path is correct
    import { AppComponent } from "./app.component";
    
    @NgModule({
      declarations: [AppComponent],
      imports: [
        BrowserModule,
        NgxWebLlmModule.forRoot({
          // Optional: Configure default model, preloading, caching etc.
          defaultModelId: "Llama-3.1-8B-Instruct-q4f32_1-MLC", // Example
          preload: true,
          // workerScriptUrl: 'path/to/your/web-llm.worker.js', // Only if using Web Worker
        }),
      ],
      providers: [],
      bootstrap: [AppComponent],
    })
    export class AppModule {}
  2. Inject and Use WebLlmService:

    import { Component, OnInit } from "@angular/core";
    import { FormsModule } from "@angular/forms"; // Needed for ngModel
    import { CommonModule } from "@angular/common"; // Needed for async pipe and new control flow
    import { WebLlmService, NgxMessage } from "ngx-web-llm"; // Ensure path is correct
    
    @Component({
      selector: "app-chat",
      standalone: true, // Assuming standalone component for modern Angular
      imports: [CommonModule, FormsModule], // Import necessary modules
      template: `
        <div>
          @if (webLlm.isLoading$ | async; as isLoading) {
          <div>Loading model... {{ (webLlm.initializationProgress$ | async)?.text }}</div>
          } @else if (webLlm.engineReady$ | async) {
          <div>Model Ready: {{ webLlm.currentModelId }}</div>
          } @else {
          <div>Engine not ready and not loading. Please initialize.</div>
          } @for (message of messages; track $index) {
          <div>
            <strong>{{ message.role }}:</strong> {{ message.content }}
          </div>
          } @empty {
          <div>No messages yet. Send one to start the chat!</div>
          }
    
          <input [(ngModel)]="userInput" placeholder="Type your message" (keyup.enter)="sendMessage()" />
          <button (click)="sendMessage()" [disabled]="isGenerating || !(webLlm.engineReady$ | async)">Send</button>
    
          @if (isGenerating) {
          <div>Generating response...</div>
          }
        </div>
      `,
    })
    export class ChatComponent implements OnInit {
      messages: NgxMessage[] = [];
      userInput: string = "";
      isGenerating: boolean = false;
    
      constructor(public webLlm: WebLlmService) {}
    
      async ngOnInit() {
        // Example: Explicit initialization if not relying on preload
        // if (!this.webLlm.isEngineReady && !(await (this.webLlm.isLoading$ | async))) { // Check isLoading correctly
        //   try {
        //     // Initialize with the default model (or specify one)
        //     // Set useWebWorker to false if not using a worker, or true if workerScriptUrl is configured
        //     await this.webLlm.initializeEngine(undefined, undefined, false);
        //     console.log('Engine initialized successfully!');
        //   } catch (e) {
        //     console.error('Engine initialization failed:', e);
        //   }
        // }
      }
    
      sendMessage(): void {
        if (!this.userInput.trim() || !this.webLlm.isEngineReady || this.isGenerating) return;
    
        const userMessage: NgxMessage = { role: "user", content: this.userInput };
        this.messages = [...this.messages, userMessage];
        const currentInput = this.userInput;
        this.userInput = "";
        this.isGenerating = true;
    
        let assistantResponse = "";
        const assistantMessagePlaceholder: NgxMessage = { role: "assistant", content: "..." };
        this.messages = [...this.messages, assistantMessagePlaceholder];
    
        this.webLlm.streamChatDeltas({ messages: [{ role: "user", content: currentInput }] }).subscribe({
          next: (deltaContent) => {
            assistantResponse += deltaContent;
            this.messages = this.messages.map((msg, index) => (index === this.messages.length - 1 ? { ...msg, content: assistantResponse } : msg));
          },
          error: (err) => {
            console.error("Error during chat streaming:", err);
            this.messages = this.messages.map((msg, index) => (index === this.messages.length - 1 ? { ...msg, content: "Error generating response." } : msg));
            this.isGenerating = false;
          },
          complete: () => {
            this.isGenerating = false;
          },
        });
      }
    }

Configuration (NgxWebLlmConfig)

When calling NgxWebLlmModule.forRoot(config), you can provide an NgxWebLlmConfig object:

export interface NgxWebLlmConfig {
  defaultModelId?: string; // e.g., 'Llama-3.1-8B-Instruct-q4f32_1-MLC'
  defaultEngineConfig?: webllm.MLCEngineConfig; // Advanced engine settings from WebLLM
  preload?: boolean; // If true, initializes with defaultModelId on service creation
  workerScriptUrl?: string; // Optional: Path to web-llm.worker.js if choosing to use Web Worker.
  // The application is responsible for serving this worker script.
  caching?: {
    usePersistentStorage?: boolean; // Request persistent storage for models
    storageQuotaBytes?: number; // (Currently informational) Desired quota
  };
}

WebLlmService API Highlights

  • Properties & Observables:

    • currentModelId$: Observable<string | null>
    • engineReady$: Observable<boolean>
    • initializationProgress$: Observable<NgxInitProgressReport | null>
    • isLoading$: Observable<boolean>
    • get prebuiltAppConfig(): webllm.AppConfig
  • Core Methods:

    • async initializeEngine(modelId?: string, config?: webllm.MLCEngineConfig, useWebWorker?: boolean): Promise<void>: Initializes the WebLLM engine. useWebWorker is false by default; set to true and provide workerScriptUrl in config if using a worker.
    • chatCompletions(request: NgxChatCompletionRequest): Observable<NgxChatCompletionChunk | NgxChatCompletion>
    • streamChatDeltas(request: Omit<NgxChatCompletionRequest, 'stream'>): Observable<string>
    • async reloadModel(modelId: string, chatOpts?: webllm.ChatOptions): Promise<void>
    • async unloadEngine(): Promise<void>
    • getAvailableModels(): NgxModelRecord[]
    • async interruptGeneration(): Promise<void>
    • async getRuntimeStats(): Promise<string>
    • async resetChat(keepSystemPrompt?: boolean): Promise<void>

Troubleshooting

  • Ensure @mlc-ai/web-llm is correctly installed as a peer dependency.
  • Model downloads can be large; ensure a stable internet connection during first initialization for a model. Check browser console for download progress.

Contributing

Contributions, issues, and feature requests are welcome! Please feel free to check the issues page (Update this link!).

License

This project is licensed under the MIT License. See the LICENSE file for details. (You'll need to create a LICENSE file).