UNPKG

nekoai-js

Version:

A lightweight JavaScript/TypeScript API for NovelAI image generation and director tools

600 lines (462 loc) 18.9 kB
# 🐾 NekoAI-JS <div align="center"> <img src="https://raw.githubusercontent.com/Nya-Foundation/NekoAI-JS/main/assets/banner.png" alt="NekoAI-JS Banner" width="800" /> <h3>🎨 A lightweight JavaScript/TypeScript API for NovelAI image generation and director tools.</h3> <div> <a href="https://github.com/Nya-Foundation/NekoAI-JS/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Nya-Foundation/nekoai-js.svg" alt="License"/></a> <a href="https://github.com/Nya-Foundation/NekoAI-JS/actions/workflows/release.yml"><img src="https://github.com/Nya-Foundation/NekoAI-JS/actions/workflows/release.yml/badge.svg" alt="Builds & Release"/></a> <a href="https://www.npmjs.com/package/nekoai-js"><img src="https://img.shields.io/npm/v/nekoai-js.svg" alt="npm version"/></a> <a href="https://deepwiki.com/Nya-Foundation/NekoAI-JS"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"/></a> </div> </div> ## 🌈 Introduction > 🐾 **NekoAI-JS** is a **lightweight** and **easy-to-use** JavaScript/TypeScript wrapper for NovelAI's image generation capabilities. This package makes it simple to integrate NovelAI's powerful image generation and manipulation tools into your JavaScript applications with minimal code overhead. > > Built with modern JavaScript/TypeScript features for both browser and Node.js environments, it provides full access to NovelAI's latest models (V3, V4, V4.5) and Director tools while maintaining a clean interface. This project is based on the [NekoAI-API](https://github.com/Nya-Foundation/NekoAI-API) Python package. ### 📄 License Change Notice > **Important**: This project has transitioned from MIT to **AGPL-3.0** license to ensure better compliance and alignment with our inspiration source. As this work builds significantly upon concepts and approaches from NekoAI-API, we've adopted a more appropriate license that better reflects the collaborative nature of open-source development and provides stronger copyleft protections for the community. ## 🌟 Core Capabilities | Feature | Description | | --------------------------- | ------------------------------------------------------------------------------------------------------ | | 🚀 **Lightweight** | Focuses on image generation and Director tools, providing a simple and easy-to-use interface. | | ⚙️ **Parameterized** | Provides strongly typed interfaces to easily set up generation parameters with validation. | | 🔑 **Token Authentication** | Supports direct token authentication for API access. | | 🎬 **Real-time Streaming** | Stream V4/V4.5 generation progress in real-time, watching each denoising step as it happens. | | 🌐 **Cross-Platform** | Works in both browser and Node.js environments. | | ✨ **Latest Models** | Full support for V3, V4, and V4.5 models including multi-character generation. | | 🛠️ **Director Tools** | Complete support for all NovelAI Director tools like line art, background removal, and emotion change. | | 🔄 **TypeScript Support** | Full TypeScript definitions for all API parameters and responses. | | 🔁 **Automatic Retries** | Built-in retry mechanism for handling rate limits and temporary API failures. | ## 📦 Installation ```sh # Using npm npm install nekoai-js # Using yarn yarn add nekoai-js # Using pnpm pnpm add nekoai-js ``` For Node.js environments, you may need to install the optional canvas dependency for image processing: ```sh # Using npm npm install canvas # Using yarn yarn add canvas # Using pnpm pnpm add canvas ``` This is not required for browser environments, as they use the native Canvas API. ## 🚀 Usage ### 🔑 Initialization Import the package and initialize a client with your NovelAI access token. ```javascript // ESM import { NovelAI } from "nekoai-js"; // CommonJS const { NovelAI } = require("nekoai-js"); // Initialize with token const client = new NovelAI({ token: "your_access_token", }); ``` ### 🖼️ Image Generation Generate images with the `generateImage` method. The method takes parameters directly or as a `Metadata` object. ```javascript import { NovelAI, Model, Resolution, Sampler } from "nekoai-js"; // Initialize client const client = new NovelAI({ token: "your_access_token", }); // Generate using parameters directly const images = await client.generateImage({ prompt: "1girl, cute, anime style, detailed", model: Model.V4_5, resPreset: Resolution.NORMAL_PORTRAIT, n_samples: 1, seed: 1234567890, // Fixed seed for reproducibility }); // Save images (Node.js environment) for (const image of images) { await image.save("./output"); console.log(`Image saved: ${image.filename}`); } // Get image data URL (browser environment) for (const image of images) { const dataUrl = image.toDataURL(); console.log(`Image data URL: ${dataUrl.substring(0, 50)}...`); } ``` ### Streaming Generation (V4/V4.5 Models) V4 and V4.5 models support real-time streaming, allowing you to watch the generation process as it happens. Enable streaming by passing `true` as the second parameter to `generateImage()`. ```javascript import { NovelAI, Model, Resolution, EventType } from "nekoai-js"; // Initialize client const client = new NovelAI({ token: "your_access_token", }); // Generate with streaming enabled const response = await client.generateImage( { prompt: "1girl, cute, anime style", model: Model.V4_5, resPreset: Resolution.NORMAL_PORTRAIT, steps: 28, seed: 3417044607, }, true, // Enable streaming ); // Handle streaming response if (response && typeof response[Symbol.asyncIterator] === "function") { console.log("Streaming generation steps..."); for await (const event of response) { if (event.event_type === EventType.INTERMEDIATE) { // Save intermediate steps await event.image.save(`./output/step_${event.step_ix}.jpg`); console.log(`Step ${event.step_ix} completed`); } else if (event.event_type === EventType.FINAL) { // Save final result await event.image.save(`./output/final_result.png`); console.log("Generation complete!"); } } } ``` ### Multi-Character Generation (V4.5) V4.5 models support generating multiple characters with character-specific prompts and positioning. ```javascript import { NovelAI, Model, Resolution } from "nekoai-js"; // Initialize client const client = new NovelAI({ token: "your_access_token", }); // Create character prompts with positioning const characterPrompts = [ { prompt: "girl, red hair, red dress", uc: "bad hands, bad anatomy", center: { x: 0.3, y: 0.3 }, }, { prompt: "boy, blue hair, blue uniform", uc: "bad hands, bad anatomy", center: { x: 0.7, y: 0.7 }, }, ]; // Generate image with multiple characters const images = await client.generateImage({ prompt: "two people standing together, park background", model: Model.V4_5, resPreset: Resolution.NORMAL_LANDSCAPE, characterPrompts, }); // Process the resulting images for (const image of images) { // Browser const dataUrl = image.toDataURL(); // Node.js await image.save("./output"); } ``` ### Image to Image To perform `img2img` action, set `action` parameter to `Action.IMG2IMG`, and provide a source image. Use the `parseImage` utility to handle multiple image formats seamlessly. ```javascript import { NovelAI, Action, parseImage } from "nekoai-js"; // Initialize client const client = new NovelAI({ token: "your_access_token", }); // Parse image using the utility (supports multiple formats) const sourceImage = await parseImage("./input/image.png"); const images = await client.generateImage({ prompt: "1girl, fantasy outfit", action: Action.IMG2IMG, width: sourceImage.width, height: sourceImage.height, image: sourceImage.base64, strength: 0.5, // Lower = more similar to original noise: 0.1, }); for (const image of images) { await image.save("./output"); } ``` ### Inpainting (V4.5) V4.5 supports advanced inpainting for selective image editing. Use `Model.V4_5_INP` for optimal inpainting results. ```javascript import { NovelAI, Model, Action, parseImage } from "nekoai-js"; // Initialize client const client = new NovelAI({ token: "your_access_token", }); // Parse images using the utility function const sourceImage = await parseImage("./input/source.png"); const maskImage = await parseImage("./input/mask.png"); const images = await client.generateImage({ prompt: "beautiful flower garden", model: Model.V4_5_INP, // Use inpainting model action: Action.INPAINT, image: sourceImage.base64, mask: maskImage.base64, steps: 28, seed: 3417044607, }); for (const image of images) { await image.save("./output"); } ``` ### Streaming Inpainting Combine streaming with inpainting to watch the inpainting process in real-time. ```javascript import { NovelAI, Model, Action, EventType, parseImage } from "nekoai-js"; // Initialize client const client = new NovelAI({ token: "your_access_token", }); // Parse images const sourceImage = await parseImage("./input/source.png"); const maskImage = await parseImage("./input/mask.png"); // Generate with streaming inpainting const response = await client.generateImage( { prompt: "1girl, cute", model: Model.V4_5_INP, action: Action.INPAINT, image: sourceImage.base64, mask: maskImage.base64, steps: 28, }, true, // Enable streaming ); // Process streaming results for await (const event of response) { if (event.event_type === EventType.INTERMEDIATE) { await event.image.save(`./output/inpaint_step_${event.step_ix}.jpg`); } else if (event.event_type === EventType.FINAL) { await event.image.save(`./output/inpaint_final.png`); } } ``` ### Director Tools NovelAI offers several Director tools for image manipulation, all accessible through dedicated methods. These tools automatically handle various image input formats through the built-in `parseImage` utility. ```javascript import { NovelAI } from "nekoai-js"; // Initialize client const client = new NovelAI({ token: "your_access_token", }); // Line Art - supports file paths, Blobs, Files, URLs, etc. const lineArtResult = await client.lineArt("./input/image.png"); await lineArtResult.save("./output"); // Background Removal const bgRemovalResult = await client.backgroundRemoval("./input/image.png"); await bgRemovalResult.save("./output"); // Change Emotion const emotionResult = await client.changeEmotion( "./input/image.png", "happy", // Target emotion "neutral", // Additional prompt 0, // Emotion level (0-5) ); await emotionResult.save("./output"); // Other Director Tools const declutterResult = await client.declutter("./input/image.png", "dreamy", 0); const colorizeResult = await client.colorize("./input/image.png","dream, mirror",1,); ``` All Director Tool methods automatically handle ZIP-compressed responses from the API, extracting the image data for you. This works across both Node.js and browser environments. ### Image Input Support NekoAI-JS provides comprehensive image input support through the `parseImage` utility function, which automatically handles format detection and conversion across different environments. #### Supported Image Formats The `parseImage` function supports multiple input types for maximum flexibility: ```javascript import { NovelAI, parseImage } from "nekoai-js"; const client = new NovelAI({ token: "your_access_token", }); // 1. File paths (Node.js only) const image1 = await parseImage("./input/photo.png"); const image2 = await parseImage("./input/drawing.jpg"); // 2. Uint8Array / ArrayBuffer (both environments) const imageData = new Uint8Array(/* image bytes */); const image3 = await parseImage(imageData); // 3. Base64 strings (both environments) const base64String = "iVBORw0KGgoAAAANSUhEUgAA..."; const image4 = await parseImage(`data:image/png;base64,${base64String}`); // 4. URLs (browser only) const image5 = await parseImage("https://example.com/image.png"); const image6 = await parseImage("data:image/jpeg;base64,/9j/4AAQ..."); // 5. File objects from input elements (browser only) const fileInput = document.getElementById("imageInput"); const file = fileInput.files[0]; const image7 = await parseImage(file); // 6. Blob objects (browser only) const response = await fetch("https://example.com/image.png"); const blob = await response.blob(); const image8 = await parseImage(blob); // 7. Canvas elements (browser only) const canvas = document.getElementById("myCanvas"); const image9 = await parseImage(canvas); // 8. Image elements (browser only) const imgElement = document.getElementById("myImage"); const image10 = await parseImage(imgElement); // The parseImage function returns { width, height, base64 } console.log(`Image dimensions: ${image1.width}x${image1.height}`); // Use with generation or director tools const images = await client.generateImage({ prompt: "enhance this image", action: Action.IMG2IMG, image: image1.base64, width: image1.width, height: image1.height, }); ``` #### Cross-Platform Compatibility - **Node.js**: Supports file paths, Uint8Array, ArrayBuffer, and URLs - **Browser**: Supports File, Blob, Canvas, Image elements, Data URLs, and remote URLs - **Both**: Supports Uint8Array, ArrayBuffer, and base64 data #### Automatic Format Detection The utility automatically: - Detects image dimensions - Converts to base64 format for API compatibility - Handles JPEG, PNG, and other common formats - Preserves image quality during conversion - Works seamlessly across different environments ### Advanced Usage Examples Here are practical examples showing how to use `parseImage` with various input formats and director tools: #### Node.js Environment ```javascript import { NovelAI, parseImage } from "nekoai-js"; const client = new NovelAI({ token: "your_access_token", }); // Example 1: Processing multiple image formats const imageFormats = [ "./input/photo.png", "./input/sketch.jpg", "./input/artwork.webp" ]; for (const imagePath of imageFormats) { const parsedImage = await parseImage(imagePath); console.log(`Processing ${imagePath}: ${parsedImage.width}x${parsedImage.height}`); const result = await client.lineArt(imagePath); await result.save(`./output/lineart_${Date.now()}.png`); } // Example 2: Using with binary data const fs = require("fs"); const imageBuffer = fs.readFileSync("./input/photo.png"); const result = await client.backgroundRemoval(imageBuffer); await result.save("./output"); ``` #### Browser Environment ```javascript import { NovelAI, parseImage } from "nekoai-js"; const client = new NovelAI({ token: "your_access_token", }); // Example 1: File upload with preview const fileInput = document.getElementById("fileInput"); fileInput.addEventListener("change", async (e) => { const file = e.target.files[0]; if (!file) return; // Parse the image to get dimensions const parsedImage = await parseImage(file); console.log(`Uploaded image: ${parsedImage.width}x${parsedImage.height}`); // Process with director tool const result = await client.lineArt(file); // Display result const img = document.createElement("img"); img.src = result.toDataURL(); img.style.maxWidth = "500px"; document.body.appendChild(img); }); // Example 2: Canvas processing const canvas = document.getElementById("drawingCanvas"); const processCanvas = async () => { const result = await client.sketch(canvas); // Create download link const link = document.createElement("a"); link.download = "sketch_result.png"; link.href = result.toDataURL(); link.click(); }; // Example 3: URL processing with error handling const processImageUrl = async (url) => { try { const result = await client.colorize(url); return result.toDataURL(); } catch (error) { console.error("Failed to process image:", error); return null; } }; ``` ### Using Custom Hosts NekoAI-JS supports using custom hosts for API requests. This is useful if you need to use a different endpoint or if you're using a proxy server. ```javascript import { NovelAI, Model, Host } from "nekoai-js"; // Method 1: Use predefined hosts const client1 = new NovelAI({ token: "your_access_token", host: Host.API, // Use API host instead of default WEB host }); const images1 = await client1.generateImage({ prompt: "1girl, cute, anime style", model: Model.V3, }); // Method 2: Use a custom host URL const client2 = new NovelAI({ token: "your_access_token", host: "https://your-custom-host.com", // Direct URL string }); const images2 = await client2.generateImage({ prompt: "1girl, cute, anime style", model: Model.V4, }); // Custom hosts work with all other client methods const lineArtResult = await client2.lineArt("./input/image.png"); ``` You can use custom hosts for: 1. Connection to third-party API providers 2. Working with proxies 3. Connecting to local NovelAI servers 4. Load balancing between multiple endpoints ### Custom Retry Configuration NekoAI-JS includes a built-in retry mechanism for handling rate limits and temporary API failures. By default, retries are enabled with reasonable defaults, but you can customize this behavior: ```javascript import { NovelAI, Model } from "nekoai-js"; // Initialize client with custom retry settings const client = new NovelAI({ token: "your_access_token", retry: { enabled: true, // Enable retries maxRetries: 5, // Maximum 5 retry attempts baseDelay: 2000, // Start with 2 second delay maxDelay: 60000, // Maximum delay of 1 minute retryStatusCodes: [429], // Only retry on rate limit errors }, }); // Generate image with retry try { const images = await client.generateImage({ prompt: "1girl, cute, anime style", model: Model.V4_5, }); console.log("Success after potential retries!"); } catch (error) { console.error("Failed even after retries:", error); } ``` You can also disable retries completely if needed: ```javascript const client = new NovelAI({ token: "your_access_token", retry: { enabled: false, // Disable retries }, }); ``` The retry mechanism uses exponential backoff with jitter to prevent overwhelming the API service when it's under stress. ## References [NovelAI Documentation](https://docs.novelai.net/) [NovelAI Backend API](https://api.novelai.net/docs) [NovelAI Unofficial Knowledgebase](https://naidb.miraheze.org/wiki/Using_the_API) [NekoAI-API Python Package](https://github.com/Nya-Foundation/NekoAI-API)