UNPKG

woolball-client

Version:

Client-side library for Woolball enabling secure browser resource sharing for distributed AI task processing

190 lines (189 loc) 8.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.registerWebMcpTools = registerWebMcpTools; exports.unregisterWebMcpTools = unregisterWebMcpTools; exports.isWebMcpAvailable = isWebMcpAvailable; exports.isWebMcpRegistered = isWebMcpRegistered; require("@mcp-b/global"); const index_js_1 = require("../utils/tasks/index.js"); function toMcpResult(result) { if (result.error) { return { content: [{ type: 'text', text: String(result.error) }], isError: true, }; } return { content: [{ type: 'text', text: JSON.stringify(result) }], }; } function buildToolDefinitions() { return [ { name: 'automatic-speech-recognition', description: 'Transcribe audio to text using Whisper models. Runs entirely in your browser via WebGPU/WASM.', inputSchema: { type: 'object', properties: { input: { type: 'string', description: 'Base64-encoded WAV audio' }, model: { type: 'string', description: 'HuggingFace model ID' }, dtype: { type: 'string', description: 'Quantization type' }, return_timestamps: { type: 'string', description: 'Return word-level timestamps' }, }, required: ['input'], }, annotations: { readOnlyHint: true }, async execute(args) { const data = { input: args.input, model: args.model || 'onnx-community/whisper-large-v3-turbo_timestamped', dtype: args.dtype || 'q8', return_timestamps: args.return_timestamps === 'true' || args.return_timestamps === true, }; const result = await index_js_1.taskProcessors['automatic-speech-recognition'](data); return toMcpResult(result); }, }, { name: 'text-to-speech', description: 'Convert text to speech audio. Supports Transformers.js (MMS) and Kokoro providers with multiple voices.', inputSchema: { type: 'object', properties: { input: { type: 'string', description: 'Text to synthesize' }, model: { type: 'string', description: 'HuggingFace model ID' }, dtype: { type: 'string', description: 'Quantization type' }, provider: { type: 'string', description: 'TTS provider' }, voice: { type: 'string', description: 'Voice name (Kokoro provider only)' }, }, required: ['input'], }, annotations: { readOnlyHint: true }, async execute(args) { const data = { input: args.input, model: args.model || 'facebook/mms-tts-eng', dtype: args.dtype || 'q8', provider: args.provider || 'transformers', voice: args.voice, }; const result = await index_js_1.taskProcessors['text-to-speech'](data); if (result.audio) { return { content: [{ type: 'resource', data: result.audio, mimeType: 'audio/wav' }] }; } return toMcpResult(result); }, }, { name: 'translation', description: 'Translate text between 200+ languages using NLLB. Runs entirely in your browser.', inputSchema: { type: 'object', properties: { input: { type: 'string', description: 'Text to translate' }, model: { type: 'string', description: 'HuggingFace model ID' }, srcLang: { type: 'string', description: 'Source language code (FLORES200 format, e.g. eng_Latn)' }, tgtLang: { type: 'string', description: 'Target language code (FLORES200 format, e.g. por_Latn)' }, dtype: { type: 'string', description: 'Quantization type' }, }, required: ['input', 'srcLang', 'tgtLang'], }, annotations: { readOnlyHint: true }, async execute(args) { const data = { input: args.input, model: args.model || 'Xenova/nllb-200-distilled-600M', srcLang: args.srcLang, tgtLang: args.tgtLang, dtype: args.dtype || 'q8', }; const result = await index_js_1.taskProcessors['translation'](data); return toMcpResult(result); }, }, { name: 'text-generation', description: 'Generate text using LLMs (SmolLM2, Qwen2.5, DeepSeek R1, Llama). Supports Transformers.js, WebLLM, and MediaPipe.', inputSchema: { type: 'object', properties: { input: { type: 'string', description: 'JSON array of messages [{role, content}]' }, model: { type: 'string', description: 'Model ID' }, dtype: { type: 'string', description: 'Quantization type' }, provider: { type: 'string', description: 'LLM provider' }, max_new_tokens: { type: 'string', description: 'Maximum tokens to generate' }, temperature: { type: 'string', description: 'Sampling temperature' }, do_sample: { type: 'string', description: 'Enable sampling' }, }, required: ['input'], }, annotations: { readOnlyHint: true }, async execute(args) { const data = { input: args.input, model: args.model || 'HuggingFaceTB/SmolLM2-135M-Instruct', dtype: args.dtype || 'q4f16', provider: args.provider || 'transformers', max_new_tokens: Number(args.max_new_tokens) || 250, temperature: Number(args.temperature) || 1.0, do_sample: args.do_sample === 'true' || args.do_sample === true, }; const result = await index_js_1.taskProcessors['text-generation'](data); return toMcpResult(result); }, }, { name: 'image-text-to-text', description: 'Describe or answer questions about images using multimodal vision models. Runs in your browser.', inputSchema: { type: 'object', properties: { input: { type: 'string', description: 'JSON string of {image: base64, text: question}' }, model: { type: 'string', description: 'Model ID' }, dtype: { type: 'string', description: 'Quantization type' }, max_new_tokens: { type: 'string', description: 'Maximum tokens to generate' }, do_sample: { type: 'string', description: 'Enable sampling' }, }, required: ['input'], }, annotations: { readOnlyHint: true }, async execute(args) { const data = { input: args.input, model: args.model || 'llava-hf/llava-onevision-qwen2-0.5b-ov-hf', dtype: args.dtype || 'q4f16', max_new_tokens: Number(args.max_new_tokens) || 64, do_sample: args.do_sample === 'true' || args.do_sample === true, }; const result = await index_js_1.taskProcessors['image-text-to-text'](data); return toMcpResult(result); }, }, ]; } let registered = false; function registerWebMcpTools() { if (registered) return true; if (!navigator.modelContext) return false; for (const tool of buildToolDefinitions()) { navigator.modelContext.registerTool(tool); } registered = true; return true; } function unregisterWebMcpTools() { if (!registered || !navigator.modelContext) return; for (const tool of buildToolDefinitions()) { navigator.modelContext.unregisterTool(tool.name); } registered = false; } function isWebMcpAvailable() { return !!navigator.modelContext; } function isWebMcpRegistered() { return registered; }