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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@netless/window-manager-ai-extend

v0.0.5

Published

一个为 Netless Window Manager 提供的 AI 对话扩展插件,基于 OpenRouter API 实现,支持多模态输入、流式响应、截图功能和思维导图导出。

Readme

@netless/window-manager-ai-extend

一个为 Netless Window Manager 提供的 AI 对话扩展插件,基于 OpenRouter API 实现,支持多模态输入、流式响应、截图功能和思维导图导出。

✨ 核心特性

  • 🤖 AI 对话功能 - 基于 OpenRouter API,支持多种 AI 模型,可自动获取免费模型列表
  • 🖼️ 多模态输入 - 支持文本和图片输入,可同时发送图片和文字内容
  • 📸 截图功能 - 支持手动截图、自动截图和快照三种方式,截图可直接发送给 AI
  • 💬 流式响应 - 实时显示 AI 响应内容,支持推理过程(reasoning)和最终输出分离显示
  • 📝 Markdown 渲染 - 自动识别并渲染 Markdown 格式内容,支持代码高亮
  • 🗺️ 思维导图导出 - 支持将 Markdown 内容导出为思维导图并添加到白板
  • 💾 本地存储 - 使用 IndexedDB 持久化存储聊天记录,支持多会话管理
  • 🏷️ 多标签页 - 支持创建多个独立的对话会话,可随时切换或删除
  • 🌐 多语言支持 - 内置中文和英文界面,可自由切换

📦 安装

npm install @netless/window-manager-ai-extend
# 或
pnpm add @netless/window-manager-ai-extend
# 或
yarn add @netless/window-manager-ai-extend

🚀 快速开始

基本使用

import { ExtendAIPlugin } from '@netless/window-manager-ai-extend';
import { createFastboard } from '@netless/fastboard';

// 1. 创建 Fastboard 实例
const fastboard = await createFastboard({
  sdkConfig: {
    appIdentifier: 'your-app-identifier',
    region: 'cn-hz',
  },
  joinRoom: {
    uid: 'user-id',
    uuid: 'room-uuid',
    roomToken: 'room-token',
    isWritable: true,
  },
  managerConfig: {
    cursor: true,
    supportAppliancePlugin: true, // 启用此选项以支持思维导图功能
  },
});

// 2. 实现文件上传函数
const uploadFile = async (file: File): Promise<string | null> => {
  try {
    const formData = new FormData();
    formData.append('file', file);
    
    const response = await fetch('/api/upload', {
      method: 'POST',
      body: formData,
    });
    
    const data = await response.json();
    return data.url; // 返回图片 URL,失败返回 null
  } catch (error) {
    console.error('上传失败:', error);
    return null;
  }
};

// 3. 创建 AI 插件实例
const aiPlugin = new ExtendAIPlugin({
  // 必需:文件上传函数,将文件转换为可访问的 URL
  uploadFile,
  
  // 必需:OpenRouter API 密钥
  // 获取方式:https://openrouter.ai/keys
  apiKey: 'sk-or-v1-your-api-key',
  
  // 可选:指定使用的模型
  // - 字符串:单个模型 ID
  // - 数组:多个模型 ID(用户可在界面中选择)
  // - 未指定:自动获取支持图片输入且免费的模型列表
  models: ['nvidia/nemotron-nano-12b-v2-vl:free'],
  
  // 可选:语言设置,默认为 'zh-CN'
  language: 'zh-CN', // 或 'en'
  
  // 可选:自定义容器元素,默认添加到主白板容器
  // container: document.getElementById('ai-panel-container'),
  
  // 可选:回调函数
  callbacks: {
    onShow: () => {
      console.log('AI 面板已显示');
    },
    onHide: () => {
      console.log('AI 面板已隐藏');
    },
    onSwitchAiChat: (aiChatId: string) => {
      console.log('切换到聊天:', aiChatId);
    },
  },
});

// 4. 注册插件到 Window Manager
fastboard.manager.useExtendPlugin(aiPlugin);

// 5. 显示 AI 面板
aiPlugin.active();

// 隐藏 AI 面板
// aiPlugin.cancel();

自动获取免费模型

如果不指定 models 参数,插件会自动从 OpenRouter 获取支持图片输入且免费的模型列表:

const aiPlugin = new ExtendAIPlugin({
  uploadFile: uploadImage,
  apiKey: 'sk-or-v1-your-api-key',
  // 不指定 models,将自动获取免费模型列表
  // 用户可以在界面中选择不同的模型
});

💡 提示:自动获取的模型列表会根据 OpenRouter 的可用模型动态更新,确保始终使用最新的免费模型。

📖 API 文档

ExtendAIPlugin

AI 插件的主类,继承自 ExtendPlugin

构造函数选项

interface ExtendAIOptions {
  /** 
   * 文件上传函数,将文件转换为可访问的 URL
   * @param file 要上传的文件
   * @returns 返回图片 URL,上传失败返回 null
   */
  uploadFile: (file: File) => Promise<string | null>;
  
  /** 
   * OpenRouter API 密钥
   * 获取方式:https://openrouter.ai/keys
   */
  apiKey: string;
  
  /** 
   * 模型列表配置
   * - 字符串:单个模型 ID(如 'nvidia/nemotron-nano-12b-v2-vl:free')
   * - 数组:多个模型 ID,用户可在界面中选择
   * - 未指定:自动获取支持图片输入且免费的模型列表
   * 
   * @example
   * models: 'nvidia/nemotron-nano-12b-v2-vl:free'
   * models: ['model-1', 'model-2']
   */
  models?: string[] | string;
  
  /** 
   * 是否使用默认 UI,默认为 true
   * 如果设置为 false,需要自行实现 UI
   */
  useDefaultUI?: boolean;
  
  /** 
   * 指定 AI 面板容器元素
   * 默认添加到主白板容器
   */
  container?: HTMLElement;
  
  /** 
   * 语言设置
   * - 'zh-CN': 中文界面
   * - 'en': 英文界面
   * 默认为 'zh-CN'
   */
  language?: 'en' | 'zh-CN';
  
  /** 
   * 回调函数集合
   */
  callbacks?: {
    /** 面板显示时触发 */
    onShow: () => void;
    /** 面板隐藏时触发 */
    onHide: () => void;
    /** 切换 AI 聊天时触发,参数为当前聊天 ID */
    onSwitchAiChat: (aiChatId: string) => void;
  };
}

实例方法

| 方法 | 说明 | 返回值 | |------|------|--------| | active() | 显示 AI 面板 | void | | cancel() | 隐藏 AI 面板 | void |

属性

| 属性 | 说明 | 类型 | |------|------|------| | panelController | 面板控制器实例,用于高级操作 | AIPanelController \| undefined | | windowManager | Window Manager 实例 | WindowManager |

AIPanelController

插件内部使用的控制器,可通过 aiPlugin.panelController 访问。主要用于高级操作和自定义功能。

⚠️ 注意:这些方法主要用于高级场景,一般使用场景不需要直接调用。

主要方法

// 激活截图功能(手动截图模式)
aiPlugin.panelController?.activeCaptureView();

// 取消截图功能
aiPlugin.panelController?.cancalCaptureView();

// 激活自动截图功能(自动捕获白板变化)
aiPlugin.panelController?.activeAutoSnapshot();

// 取消自动截图功能
aiPlugin.panelController?.cancelAutoSnapshot();

// 手动创建快照
// @param filename 文件名(可选)
// @returns Promise<File | null> 返回快照文件
const snapshotFile = await aiPlugin.panelController?.snapshot('filename.png');

// 更新数据库中的聊天记录
// @param chatId 聊天 ID
// @param messages 消息列表
await aiPlugin.panelController?.updateDbRecord(chatId, messages);

// 获取数据库中的聊天记录
// @param chatId 聊天 ID
// @returns Promise<AiChatRecordItem | null> 返回聊天记录
const record = await aiPlugin.panelController?.getDbRecord(chatId);

🎯 功能详解

多模态输入

插件支持同时发送文本和图片内容,实现真正的多模态交互:

  1. 文本输入 - 在输入框中直接输入文本内容
  2. 图片输入 - 通过截图功能或自动截图功能添加图片
  3. 组合发送 - 可以同时发送文本和图片,AI 会同时理解两种输入

💡 使用场景:可以发送白板截图并配上问题,让 AI 理解白板内容并回答问题。

截图功能

插件提供三种截图方式,满足不同使用场景:

  1. 手动截图 (clip) - 点击按钮后手动选择截图区域,适合精确选择需要的内容
  2. 自动截图 (auto clip) - 自动捕获白板变化并截图,适合需要持续监控白板变化的场景
  3. 快照 (snapshot) - 直接对当前视图进行快照,快速捕获整个白板内容

截图后会自动添加到当前对话的输入中,可以直接发送给 AI。

流式响应

插件支持流式显示 AI 响应,提供更好的交互体验:

  • 推理过程 - 如果模型支持(如支持 reasoning 的模型),会单独显示推理过程,可折叠查看
  • 最终输出 - 实时显示模型的最终回答内容
  • Markdown 渲染 - 自动识别并渲染 Markdown 格式,支持代码高亮、表格、列表等

思维导图导出

如果 AI 返回的内容是 Markdown 格式,可以点击导出按钮将其转换为思维导图并添加到白板中:

  • 自动解析 Markdown 结构
  • 生成交互式思维导图
  • 支持在白板中编辑和调整

⚠️ 注意:需要启用 supportAppliancePlugin 选项才能使用此功能。

多标签页管理

  • 支持创建多个独立的对话会话,每个会话互不干扰
  • 每个会话的数据独立存储在 IndexedDB 中
  • 可以随时切换、重命名或删除会话
  • 支持会话持久化,刷新页面后数据不丢失

🔧 配置说明

模型配置

插件支持通过 OpenRouter 使用多种 AI 模型。推荐使用支持多模态(图片+文本)的模型:

// 方式 1:单个模型
models: 'nvidia/nemotron-nano-12b-v2-vl:free'

// 方式 2:多个模型(用户可在界面中选择)
models: [
  'nvidia/nemotron-nano-12b-v2-vl:free',
  'google/gemini-pro-vision',
  'openai/gpt-4-vision-preview'
]

// 方式 3:不指定,自动获取免费模型
// models: undefined

📚 模型选择建议

  • 查看支持的模型列表:https://openrouter.ai/models
  • 推荐使用支持 visionmultimodal 的模型
  • 免费模型推荐:nvidia/nemotron-nano-12b-v2-vl:free

文件上传配置

uploadFile 函数需要实现文件上传逻辑,将文件上传到服务器并返回可访问的 URL:

const uploadFile = async (file: File): Promise<string | null> => {
  try {
    const formData = new FormData();
    formData.append('file', file);
    
    const response = await fetch('/api/upload', {
      method: 'POST',
      body: formData,
    });
    
    if (!response.ok) {
      throw new Error('上传失败');
    }
    
    const data = await response.json();
    return data.url; // 返回图片 URL,确保 URL 可以被 AI 模型访问
  } catch (error) {
    console.error('上传失败:', error);
    return null; // 失败返回 null,插件会处理错误提示
  }
};

⚠️ 重要提示

  • 返回的 URL 必须可以被 OpenRouter API 访问(公开可访问)
  • 如果使用私有存储,需要确保 OpenRouter 能够访问
  • 建议使用 HTTPS URL
  • 支持常见图片格式:PNG、JPEG、GIF、WebP 等

📋 依赖要求

必需依赖(Peer Dependencies)

这些依赖需要在使用该插件的项目中安装:

  • @netless/window-manager >= 1.0.10 - Window Manager 核心库
  • white-web-sdk >= 2.16.53 - 白板 SDK
  • react >= 17.0.2 - React 框架
  • react-dom >= 17.0.2 - React DOM 渲染

可选依赖(用于思维导图功能)

  • @netless/appliance-plugin >= 1.1.30 - 用于思维导图导出功能

自动安装的依赖

插件会自动安装以下依赖(无需手动安装):

  • @openrouter/sdk ^0.3.10 - OpenRouter API SDK
  • antd ^5.29.2 - Ant Design UI 组件库
  • @ant-design/icons ^5.5.1 - Ant Design 图标库
  • markdown ^0.5.0 - Markdown 解析库
  • markmap-common ^0.18.0 - 思维导图核心库
  • markmap-lib ^0.18.0 - 思维导图库
  • markmap-toolbar ^0.18.0 - 思维导图工具栏
  • markmap-view ^0.18.0 - 思维导图视图
  • lodash ^4.17.21 - 工具函数库
  • d3 ^7.9.0 - 数据可视化库(用于思维导图)

🛠️ 开发指南

环境要求

  • Node.js >= 16
  • pnpm >= 7(推荐使用 pnpm)

开发流程

# 1. 克隆仓库
git clone <repository-url>

# 2. 进入项目目录
cd packages/ai

# 3. 安装依赖
pnpm install

# 4. 开发模式(监听文件变化并自动构建)
pnpm dev

# 5. 构建生产版本
pnpm build

# 6. 代码检查
pnpm lint

项目结构

packages/ai/
├── src/
│   ├── component/        # React 组件
│   │   ├── chat.tsx      # 聊天组件
│   │   └── panel.tsx     # 面板组件
│   ├── controller.tsx    # 控制器
│   ├── index.ts          # 入口文件
│   ├── locale.ts         # 国际化
│   ├── types.ts          # 类型定义
│   ├── server-api/       # API 相关
│   │   ├── iconify-api.ts
│   │   └── openRuter-api.ts
│   └── utils/            # 工具函数
│       ├── autoSnapshot.ts
│       ├── indexDB.ts
│       ├── ObserverMap.ts
│       └── snapshot.ts
├── build.mjs            # 构建脚本
├── tsconfig.json        # TypeScript 配置
└── package.json         # 项目配置

📝 注意事项

安全相关

  1. API 密钥安全 ⚠️

    • 请妥善保管 OpenRouter API 密钥,不要提交到代码仓库
    • 建议使用环境变量或配置服务管理密钥
    • 不要在客户端代码中硬编码密钥
  2. 文件上传安全

    • 确保上传的文件经过验证和过滤
    • 限制文件大小和类型
    • 使用 HTTPS 传输

功能限制

  1. 模型兼容性

    • 不同模型对图片格式和大小可能有不同要求
    • 建议使用 PNG 或 JPEG 格式,大小控制在 10MB 以内
    • 某些模型可能不支持多模态输入
  2. 存储限制

    • IndexedDB 有存储限制(通常为浏览器存储的 50%)
    • 大量聊天记录可能需要定期清理
    • 建议实现数据清理机制
  3. 网络要求

    • 需要能够访问 OpenRouter API 的网络环境
    • 某些地区可能需要代理或 VPN
    • API 调用可能产生费用(取决于使用的模型)

最佳实践

  1. 错误处理

    • 实现完善的错误处理机制
    • 对上传失败、API 调用失败等情况进行友好提示
  2. 性能优化

    • 大量聊天记录可能影响性能
    • 考虑实现虚拟滚动或分页加载
    • 定期清理旧的聊天记录

❓ 常见问题

Q: 如何获取 OpenRouter API 密钥?

A: 访问 https://openrouter.ai/keys 注册账号并创建 API 密钥。

Q: 支持哪些图片格式?

A: 支持常见的图片格式,包括 PNG、JPEG、GIF、WebP 等。建议使用 PNG 或 JPEG 格式以获得最佳兼容性。

Q: 如何实现文件上传?

A: 需要实现 uploadFile 函数,将文件上传到你的服务器或云存储服务(如 OSS、S3 等),并返回可公开访问的 URL。

Q: 为什么思维导图功能不工作?

A: 确保在创建 Fastboard 实例时启用了 supportAppliancePlugin: true 选项。

Q: 聊天记录存储在哪里?

A: 聊天记录存储在浏览器的 IndexedDB 中,数据库名称为 __WINDOW_MANAGER_EXTEND_AI_DB

Q: 如何清理聊天记录?

A: 可以在界面中删除单个会话,或通过 panelController.clearDb() 方法清空所有数据。

🤝 贡献

欢迎提交 Issue 和 Pull Request!

在提交代码前,请确保:

  • 代码通过 pnpm lint 检查
  • 已添加必要的测试
  • 更新了相关文档

📄 许可证

MIT License

🔗 相关链接