uncloseai.com/public/uncloseai-js.html

577 lines
29 KiB
HTML

<!--
This is free software for the public good of a permacomputer hosted at
permacomputer.com, an always-on computer by the people, for the people.
One which is durable, easy to repair, & distributed like tap water
for machine learning intelligence.
The permacomputer is community-owned infrastructure optimized around
four values:
TRUTH First principles, math & science, open source code freely distributed
FREEDOM Voluntary partnerships, freedom from tyranny & corporate control
HARMONY Minimal waste, self-renewing systems with diverse thriving connections
LOVE Be yourself without hurting others, cooperation through natural law
This software contributes to that vision by making machine learning
accessible to everyone through a free, open, embeddable chat interface.
Code is seeds to sprout on any abandoned technology.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#43a047">
<meta name="color-scheme" content="light dark">
<title>uncloseai.js - Client-Side Machine Learning | uncloseai.com</title>
<!-- PicoCSS -->
<link rel="stylesheet" href="/css/pico.classless.min.css">
<!-- ChunkFive Font -->
<link rel="stylesheet" href="/css/chunkfive/stylesheet.css" type="text/css" charset="utf-8" />
<!-- Sidebar Theme -->
<link rel="stylesheet" href="/css/sidebar-theme.css">
<!-- Highlight.js for syntax highlighting -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/styles/a11y-dark.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script>
<!-- Theme Switcher Script -->
<script>
function switchTheme(theme) {
if (theme === "auto") {
document.documentElement.removeAttribute('data-theme');
} else {
document.documentElement.setAttribute('data-theme', theme);
}
}
// Disable custom styling for uncloseai.js - use PicoCSS instead
window.UNCLOSEAI_CUSTOM_STYLING = false;
</script>
<script src="https://uncloseai.com/uncloseai.js" type="module"></script>
</head>
<body>
<!-- Mobile menu toggle -->
<button class="sidebar-toggle" onclick="document.querySelector('.sidebar').classList.toggle('open')">
</button>
<!-- Left sidebar - Main Navigation -->
<aside class="sidebar">
<div class="table-of-contents">
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/c-examples.html">C Examples</a></li>
<li><a href="/csharp-examples.html">C# Examples</a></li>
<li><a href="/dart-examples.html">Dart Examples</a></li>
<li><a href="/elixir-examples.html">Elixir Examples</a></li>
<li><a href="/go-examples.html">Go Examples</a></li>
<li><a href="/java-examples.html">Java Examples</a></li>
<li><a href="/kotlin-examples.html">Kotlin Examples</a></li>
<li><a href="/nodejs-examples.html">Node.js Examples</a></li>
<li><a href="/php-examples.html">PHP Examples</a></li>
<li><a href="/python-examples.html">Python Examples</a></li>
<li><a href="/ruby-examples.html">Ruby Examples</a></li>
<li><a href="/rust-examples.html">Rust Examples</a></li>
<li><a href="/swift-examples.html">Swift Examples</a></li>
<li><a href="/uncloseai-js.html" class="active">uncloseai.js Docs</a></li>
<li><a href="/uncloseai-js-styleguide.html">Styleguide</a></li>
<li><a href="/cli.html">uncloseai-cli</a></li>
<li><a href="/browser-toys.html">Browser Toys</a></li>
<li><a href="/inference.html">Inference Setup</a></li>
<li><a href="/text-to-speech.html">Text-to-Speech</a></li>
<li><a href="/crawler.html">Our Crawler</a></li>
<li><a href="/reverse-retrieval-augmented-generations-rag.html">Reverse RAG</a></li>
<li><a href="/languages" target="_blank">🔗 All Languages</a></li>
<li><a href="https://shop.unturf.com/p/8486f492-a93e-11f0-b477-02dfe05770ee/uncloseai-machine-learning-reference-guide-to-inference-clients" target="_blank">📚 Book</a></li>
</ul>
</nav>
</div>
</aside>
<!-- Main content -->
<main>
<header>
<hgroup>
<a href="https://uncloseai.com"><h1 class="unturf" style="font-family: 'ChunkFiveRegular';">uncloseai.</h1></a>
<p>uncloseai.js: Add Machine Learning to Any Website</p>
</hgroup>
<nav>
<ul>
<li><a href="#" onclick="switchTheme('auto')">Auto</a></li>
<li><a href="#" onclick="switchTheme('light')">Light</a></li>
<li><a href="#" onclick="switchTheme('dark')">Dark</a></li>
</ul>
</nav>
</header>
<!-- ============================================ -->
<!-- OVERVIEW -->
<!-- ============================================ -->
<h2 id="intro">uncloseai.js</h2>
<p><strong>uncloseai.js</strong> is a single-file JavaScript library that adds a floating chat button to any website. One script tag gives your page a full machine learning interface: streaming chat, text-to-speech, page reading, translation, file upload, encrypted settings, and 19 languages. No server, no backend, no API keys.</p>
<p>The core technique is <strong><a href="/reverse-retrieval-augmented-generations-rag.html">Reverse Retrieval Augmented Generation (Reverse RAG)</a></strong>: instead of a server fetching documents to stuff into a prompt, the client extracts live page content and injects it directly into the conversation context. The model always has the freshest data from the page you're viewing, which lets small models punch way above their weight class. No vector database, no embeddings, no indexing pipeline. Just real-time content from the DOM, straight into the prompt. <a href="/reverse-retrieval-augmented-generations-rag.html">Read the whitepaper.</a></p>
<p>Works with static sites, CDNs, GitHub Pages, and any hosting that serves HTML. Every feature runs client-side against free community inference endpoints.</p>
<!-- ============================================ -->
<!-- INSTALLATION -->
<!-- ============================================ -->
<h2 id="installation">Installation</h2>
<p>Add one script tag to your HTML:</p>
<pre><code class="html">&lt;script src="https://uncloseai.com/uncloseai.js" type="module"&gt;&lt;/script&gt;</code></pre>
<p>A floating <strong>uncloseai.</strong> button appears in the bottom-right corner. Click it to open the modal.</p>
<!-- ============================================ -->
<!-- FEATURES -->
<!-- ============================================ -->
<h2 id="features">Features</h2>
<h3 id="chat">Streaming Chat</h3>
<ul>
<li>Real-time streaming responses via Server-Sent Events (SSE)</li>
<li>Markdown rendering with full syntax support</li>
<li>Code blocks with syntax highlighting (highlight.js, 200+ languages)</li>
<li>Copy-to-clipboard button on every code block</li>
<li>Per-page conversation history, encrypted and persisted</li>
<li>Multi-model support with dynamic model discovery from endpoints</li>
<li>Reverse RAG: live page content extracted and injected into every conversation for context-aware responses</li>
</ul>
<h3 id="tts">Text-to-Speech</h3>
<ul>
<li>42+ voices across multiple TTS models (standard, HD, cloned)</li>
<li>Speak any message, paste arbitrary text, or read the whole page aloud</li>
<li>Adjustable playback speed</li>
<li>Buffered or streaming audio modes</li>
<li>Download generated audio as MP3 or WebM+Opus (auto-detected per browser)</li>
<li>Per-message speak and download buttons on every chat bubble</li>
</ul>
<h3 id="translation">Translation</h3>
<ul>
<li>Translate the current page to any of 19 supported languages</li>
<li>Translate arbitrary text or remote URIs</li>
<li>Smart Translate widget: one-click dropdown with language picker</li>
<li>Opens translated content in a new browser tab</li>
</ul>
<h3 id="page-reading">Page Reading (Reverse RAG)</h3>
<ul>
<li>Extracts main content from any webpage intelligently, straight from the live DOM</li>
<li>Injects page content directly into the conversation context (Reverse RAG): no server-side retrieval, no vector store, no embeddings</li>
<li>Small models get the full picture of whatever page you're on, producing answers that rival much larger models</li>
<li>Synthesizes a short summary with the machine learning model</li>
<li>Reads the summary aloud with selected voice</li>
<li>Play, pause, and download the audio</li>
</ul>
<h3 id="vault">Vault Encryption</h3>
<ul>
<li>All settings and conversations encrypted with AES-256 behind a user-chosen password</li>
<li>Per-device cryptographic salt for additional security</li>
<li>Per-origin vaults: each subdomain gets its own encrypted store with its own password</li>
<li>Session persistence: stays unlocked across page navigations until you lock</li>
<li>Encrypts: conversation history, model/voice preferences, custom API keys, language settings</li>
<li>Explicit lock button clears all decrypted data from memory and DOM</li>
</ul>
<h3 id="file-upload">File Upload</h3>
<ul>
<li>Upload files for machine learning analysis</li>
<li>Progress indicator during processing</li>
<li>Results displayed inline in the chat</li>
</ul>
<h3 id="code-execution">Code Execution</h3>
<ul>
<li>Optional integration with <a href="https://unsandbox.com">unsandbox.com</a> for running code</li>
<li>Configure with your unsandbox API keys in settings</li>
<li>Execute machine learning generated code in a sandboxed environment</li>
</ul>
<h3 id="i18n">19 Languages</h3>
<p>The entire UI (buttons, labels, prompts, errors, placeholders) is translated into 19 languages. The model also responds in the selected language.</p>
<p>Arabic, Bengali, Chinese (Simplified), Chinese (Traditional), English, French, German, Hindi, Indonesian, Japanese, Korean, Marathi, Portuguese, Russian, Spanish, Swahili, Telugu, Turkish, Urdu.</p>
<h3 id="themes">Theme Support</h3>
<ul>
<li>Automatic dark/light detection from OS preference</li>
<li>Dynamic color adaptation to host page</li>
<li>Works with PicoCSS, or ships its own built-in stylesheet</li>
<li>Mobile-responsive layout with media queries</li>
</ul>
<h3 id="message-actions">Message Actions</h3>
<p>Every chat message (user and model) has action buttons:</p>
<ul>
<li><strong>📋 Copy Raw</strong>: copy as plain markdown</li>
<li><strong>📄 Copy HTML</strong>: copy as rendered HTML</li>
<li><strong>🔊 Speak</strong>: synthesize the message as audio</li>
<li><strong>💾 Download</strong>: save the audio file</li>
<li><strong>🗑️ Delete</strong>: remove the message from history</li>
</ul>
<!-- ============================================ -->
<!-- SETTINGS -->
<!-- ============================================ -->
<h2 id="settings">Settings Panel</h2>
<p>Click the gear icon (⚙️) in the modal header to open settings. All settings are encrypted in your vault.</p>
<h3 id="settings-model">Model Selection</h3>
<p>Choose from dynamically discovered models. The dropdown shows the endpoint and model name. Models are auto-discovered by querying <code>/v1/models</code> on each configured endpoint.</p>
<h3 id="settings-voice">Voice Selection</h3>
<p>42+ voices organized by TTS model. Voices are discovered dynamically from the speech endpoint. Includes standard, HD, and cloned voice options.</p>
<h3 id="settings-language">Language</h3>
<p>Switch the UI and model response language. Changes take effect immediately across all text.</p>
<h3 id="settings-api">Custom API Endpoint</h3>
<p>Point uncloseai.js at your own OpenAI-compatible endpoint (vLLM, Ollama, or any compatible server). Configure a base URI and API key. Built-in models remain available alongside your custom endpoint.</p>
<h3 id="settings-unsandbox">Code Execution (Unsandbox)</h3>
<p>Enable code execution by providing your unsandbox.com API keys. When enabled, machine learning generated code can be executed in a sandboxed environment.</p>
<!-- ============================================ -->
<!-- CONFIGURATION -->
<!-- ============================================ -->
<h2 id="configuration">Configuration</h2>
<p>Customize behavior by setting <code>window</code> variables before loading the script:</p>
<pre><code class="html">&lt;script&gt;
// Disable built-in styling to use your own CSS framework
window.UNCLOSEAI_CUSTOM_STYLING = false;
// Hide the floating button (use the JS API instead)
window.UNCLOSEAI_FLOATING_BUTTON = false;
// Force the UI to a specific language
window.UNCLOSEAI_LANGUAGE = "es";
// Add custom instructions to the system prompt
window.UNCLOSEAI_SYSTEM_PROMPT = "You are a helpful coding assistant.";
// Replace the default system prompt entirely
window.UNCLOSEAI_SYSTEM_PROMPT_REPLACE = true;
// Skip full initialization (floating button only, for preview iframes)
window.UNCLOSEAI_SKIP_INIT = true;
&lt;/script&gt;
&lt;script src="https://uncloseai.com/uncloseai.js" type="module"&gt;&lt;/script&gt;</code></pre>
<h3 id="config-reference">Configuration Reference</h3>
<table>
<thead>
<tr>
<th>Variable</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>UNCLOSEAI_CUSTOM_STYLING</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Enable built-in CSS. Set <code>false</code> to use your own CSS framework (PicoCSS, Tailwind, etc.).</td>
</tr>
<tr>
<td><code>UNCLOSEAI_FLOATING_BUTTON</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Show the floating button. Set <code>false</code> to hide it and trigger the modal programmatically.</td>
</tr>
<tr>
<td><code>UNCLOSEAI_LANGUAGE</code></td>
<td>String</td>
<td><code>null</code></td>
<td>Force the UI and model responses to a specific language. Overrides user preference. Examples: <code>"en"</code>, <code>"es"</code>, <code>"ja"</code>, <code>"zh"</code>.</td>
</tr>
<tr>
<td><code>UNCLOSEAI_SYSTEM_PROMPT</code></td>
<td>String</td>
<td><code>null</code></td>
<td>Custom instructions for the model. Appended to the default prompt, or replaces it if <code>SYSTEM_PROMPT_REPLACE</code> is <code>true</code>.</td>
</tr>
<tr>
<td><code>UNCLOSEAI_SYSTEM_PROMPT_REPLACE</code></td>
<td>Boolean</td>
<td><code>false</code></td>
<td>When <code>true</code>, the custom prompt completely replaces the default system prompt instead of appending.</td>
</tr>
<tr>
<td><code>UNCLOSEAI_SKIP_INIT</code></td>
<td>Boolean</td>
<td><code>false</code></td>
<td>Skip full initialization. Creates the floating button only, skipping model loading and vault init. Used for preview iframes.</td>
</tr>
</tbody>
</table>
<!-- ============================================ -->
<!-- JAVASCRIPT API -->
<!-- ============================================ -->
<h2 id="api">JavaScript API</h2>
<p>All functions are available on the <code>window.uncloseai</code> namespace and as ES module exports.</p>
<h3 id="api-modal">Modal Control</h3>
<pre><code class="javascript">// Toggle the chat modal open/closed
await window.uncloseai.toggleUncloseaiEmbeddedModal();
// Open the TTS modal directly
window.uncloseai.openTTSModal();
// Open the translation modal directly
window.uncloseai.openTranslateModal();</code></pre>
<h3 id="api-chat">Chat</h3>
<pre><code class="javascript">// Send a message and stream the response
for await (const chunk of window.uncloseai.sendMessage("Hello")) {
process.stdout.write(chunk); // each chunk is a text fragment
}
// Get the currently selected model
const model = window.uncloseai.getSelectedModel();
// Get the endpoint for the current model
const endpoint = window.uncloseai.getSelectedModelEndpoint();</code></pre>
<h3 id="api-tts">Text-to-Speech</h3>
<pre><code class="javascript">// Speak text with the default voice
await window.uncloseai.speakText("Hello world");
// Speak text from a DOM element
window.uncloseai.handleTTSFromElement(document.querySelector('.content'));</code></pre>
<h3 id="api-page">Page Reading</h3>
<pre><code class="javascript">// Extract and read the current page content
await window.uncloseai.readPageWithHermes();
// Extract page content as structured text
const content = window.uncloseai.extractWebpageContent();</code></pre>
<h3 id="api-translate">Translation</h3>
<pre><code class="javascript">// Trigger smart translate on the page
window.uncloseai.handleSmartTranslate();</code></pre>
<h3 id="api-vault">Vault</h3>
<pre><code class="javascript">// Check if vault is unlocked
window.uncloseai.UncloseVault.isUnlocked();
// Check if a vault exists for this origin
window.uncloseai.UncloseVault.hasVault();
// Get a setting from the vault
window.uncloseai.UncloseVault.get("selectedModel");
// Lock the vault (clears decrypted data from memory)
window.uncloseai.UncloseVault.lock();</code></pre>
<!-- ============================================ -->
<!-- WIDGET LIBRARY -->
<!-- ============================================ -->
<h2 id="widgets">Widget Library</h2>
<p>Create embedded interfaces inside your page instead of using the floating button.</p>
<h3 id="widgets-full">Full Interface</h3>
<p>Embed a complete chat interface with all features into any container:</p>
<pre><code class="html">&lt;div class="uncloseai" data-type="full"&gt;&lt;/div&gt;</code></pre>
<h3 id="widgets-custom">Custom Interface</h3>
<p>Pick specific features to include:</p>
<pre><code class="html">&lt;div class="uncloseai"
data-type="custom"
data-features="chat,tts,translate,smart-translate,upload,read"&gt;
&lt;/div&gt;</code></pre>
<p>Available features for <code>data-features</code>:</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>chat</code></td>
<td>Chat input and message display</td>
</tr>
<tr>
<td><code>tts</code></td>
<td>Text-to-speech button</td>
</tr>
<tr>
<td><code>translate</code></td>
<td>Translation button</td>
</tr>
<tr>
<td><code>smart-translate</code></td>
<td>One-click smart translate dropdown</td>
</tr>
<tr>
<td><code>upload</code></td>
<td>File upload for analysis</td>
</tr>
<tr>
<td><code>read</code></td>
<td>Read page aloud button</td>
</tr>
</tbody>
</table>
<!-- ============================================ -->
<!-- BROWSER TOYS -->
<!-- ============================================ -->
<h2 id="browser-toys">Browser Toys</h2>
<p>Don't own the site? Install a <a href="/browser-toys.html">browser toy</a> to get the uncloseai. button on every page you visit. Lightweight extensions that inject this same script tag into every page. No server, no accounts. Chat history stays in your browser's localStorage, scoped per domain.</p>
<p>Available for Chrome, Edge, Firefox, Safari, Brave, Vivaldi, and Arc.</p>
<p><a href="/browser-toys.html"><strong>Get Browser Toys</strong></a></p>
<!-- ============================================ -->
<!-- TECHNICAL -->
<!-- ============================================ -->
<h2 id="technical">Technical Details</h2>
<ul>
<li><strong>ES6 Modules</strong>: loaded with <code>type="module"</code>, tree-shakeable exports</li>
<li><strong>Fetch API + ReadableStream</strong>: for SSE streaming responses</li>
<li><strong>CryptoJS</strong>: AES-256 encryption for vault (loaded dynamically)</li>
<li><strong>marked.js</strong>: markdown rendering</li>
<li><strong>highlight.js</strong>: code syntax highlighting</li>
<li><strong>CSS Custom Properties</strong>: theme adaptation</li>
<li><strong>Duplicate Load Guard</strong>: safe to include multiple times (browser toy + native)</li>
<li><strong>Namespace Isolation</strong>: all globals under <code>window.uncloseai</code> to avoid clobbering host page functions</li>
</ul>
<h3 id="token-management">Token and Context Management</h3>
<p>uncloseai.js handles token budgets automatically. It reads <code>max_model_len</code> from each endpoint's <code>/v1/models</code> response, estimates input tokens (~4 chars per token for English), and reserves appropriate context buffers. Large models (32k+ tokens) get a 10% buffer, smaller models get a fixed reserve.</p>
<h3 id="battery">Battery-Powered Devices</h3>
<p>uncloseai.js offloads all inference to community GPU servers. Battery-powered devices (phones, tablets, laptops) get full machine learning capabilities without draining power or running models locally. No API keys to manage, no credentials to secure on the client side.</p>
<!-- ============================================ -->
<!-- SOURCE -->
<!-- ============================================ -->
<h2 id="source">Open Source</h2>
<p>uncloseai.js is <strong>public domain software</strong>. Free to use, modify, and distribute for any purpose.</p>
<p>Source: <a href="https://git.unturf.com/engineering/unturf/uncloseai.com" target="_blank">git.unturf.com/engineering/unturf/uncloseai.com</a></p>
<!-- ============================================ -->
<!-- TRY IT -->
<!-- ============================================ -->
<h2 id="try-it">Try It</h2>
<p>This page has uncloseai.js installed. Click the floating <strong>uncloseai.</strong> button in the bottom-right corner to open the full modal with all features described above.</p>
<script>hljs.highlightAll();</script>
<footer>
<small>&copy; uncloseai. 2026</small>
<br>
<small>Stylesheets by <a href="https://picocss.com" target="_blank">PicoCSS</a></small>
<small>& <a href="https://highlightjs.org/" target="_blank">highlight.js</a></small>
<br>
<small><a href="/privacy-policy.html">Privacy Policy</a> | <a href="/terms-of-use.html">Terms of Use</a></small>
</footer>
<script>
// Simple active link highlighting
document.querySelectorAll('.table-of-contents a').forEach(link => {
link.addEventListener('click', function() {
document.querySelectorAll('.table-of-contents a').forEach(a => a.classList.remove('active'));
this.classList.add('active');
});
});
// Highlight current section on scroll
const sections = document.querySelectorAll('h2[id], h3[id]');
const navLinks = document.querySelectorAll('.sidebar-right .table-of-contents a');
window.addEventListener('scroll', () => {
let current = '';
sections.forEach(section => {
const sectionTop = section.offsetTop;
if (window.scrollY >= sectionTop - 100) {
current = section.getAttribute('id');
}
});
navLinks.forEach(link => {
link.classList.remove('active');
if (link.getAttribute('href') === '#' + current) {
link.classList.add('active');
}
});
});
</script>
</main>
<!-- Right sidebar - Page TOC -->
<aside class="sidebar-right">
<div class="table-of-contents">
<nav>
<ul>
<li><a href="#intro" class="active">Overview</a></li>
<li><a href="#installation">Installation</a></li>
<li><a href="#features">Features</a>
<ul>
<li><a href="#chat">Chat</a></li>
<li><a href="#tts">TTS</a></li>
<li><a href="#translation">Translation</a></li>
<li><a href="#page-reading">Page Reading (Reverse RAG)</a></li>
<li><a href="#vault">Vault</a></li>
<li><a href="#file-upload">File Upload</a></li>
<li><a href="#code-execution">Code Execution</a></li>
<li><a href="#i18n">Languages</a></li>
<li><a href="#themes">Themes</a></li>
<li><a href="#message-actions">Message Actions</a></li>
</ul>
</li>
<li><a href="#settings">Settings</a>
<ul>
<li><a href="#settings-model">Model</a></li>
<li><a href="#settings-voice">Voice</a></li>
<li><a href="#settings-language">Language</a></li>
<li><a href="#settings-api">Custom API</a></li>
<li><a href="#settings-unsandbox">Code Execution</a></li>
</ul>
</li>
<li><a href="#configuration">Configuration</a>
<ul>
<li><a href="#config-reference">Reference Table</a></li>
</ul>
</li>
<li><a href="#api">JavaScript API</a>
<ul>
<li><a href="#api-modal">Modal</a></li>
<li><a href="#api-chat">Chat</a></li>
<li><a href="#api-tts">TTS</a></li>
<li><a href="#api-page">Page</a></li>
<li><a href="#api-translate">Translate</a></li>
<li><a href="#api-vault">Vault</a></li>
</ul>
</li>
<li><a href="#widgets">Widgets</a>
<ul>
<li><a href="#widgets-full">Full</a></li>
<li><a href="#widgets-custom">Custom</a></li>
</ul>
</li>
<li><a href="#browser-toys">Browser Toys</a></li>
<li><a href="#technical">Technical</a></li>
<li><a href="#source">Source</a></li>
<li><a href="#try-it">Try It</a></li>
</ul>
</nav>
</div>
</aside>
</body>
</html>