Vault password prompt is now the first thing shown when opening uncloseai. No chat, no greeting, no data written until the user creates or unlocks their vault. Each site has its own vault with AES-256 encryption using password + device-specific salt. - Add vault gate overlay blocking modal until password entered - Remove plaintext conversation fallback from storage.js - Route TTS mode, selected voice, language through vault - Route custom API config reads through vault in models.js - Add vault gate i18n strings (26 languages) explaining per-site encryption of chat history, API keys, and settings - Add missing keys to migration (voice, TTS mode) - Re-show vault gate on lock from settings - Permacomputer headers across all source files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| Dockerfile | ||
| package.json | ||
| README.md | ||
| uncloseai.js | ||
uncloseai. Node.js Client
A Node.js client library for interacting with vLLM, Ollama, and OpenAI-compatible APIs.
Features
- 🔍 Automatic Model Discovery - Discovers available models from configured endpoints
- 💬 Chat Completions - Both streaming and non-streaming modes
- 🎙️ Text-to-Speech - Generate audio from text with multiple voice options
- 🔄 Multiple Endpoints - Support for multiple model and TTS endpoints
- 🛡️ Error Handling - Comprehensive error handling with custom exceptions
- 📦 Zero Dependencies - Uses only Node.js built-in modules (https, http, fs)
Installation
No external dependencies required! Just copy uncloseai_lib.js to your project:
# Copy the library file
cp uncloseai_lib.js your-project/
# Or use it directly
node examples.js
Quick Start
const { uncloseai } = require('./uncloseai_lib');
// Initialize client (auto-discovers from environment variables)
const client = new uncloseai();
// Non-streaming chat
const response = await client.chat({
model: 'auto',
messages: [{ role: 'user', content: 'Hello!' }]
});
console.log(response.choices[0].message.content);
// Streaming chat
for await (const chunk of client.chatStream({
model: 'auto',
messages: [{ role: 'user', content: 'Write a story' }]
})) {
const content = chunk.choices?.[0]?.delta?.content || '';
process.stdout.write(content);
}
Configuration
Environment Variables
# Model endpoints (numbered 1-9999)
export MODEL_ENDPOINT_1="https://hermes.ai.unturf.com/v1"
export MODEL_ENDPOINT_2="https://qwen.ai.unturf.com/v1"
# TTS endpoints (numbered 1-9999)
export TTS_ENDPOINT_1="https://speech.ai.unturf.com/v1"
Programmatic Configuration
const client = new uncloseai({
endpoints: ['https://api.example.com/v1'],
ttsEndpoints: ['https://tts.example.com/v1'],
apiKey: 'your-api-key', // Optional
timeout: 30000, // Request timeout in milliseconds
debug: true // Enable debug logging
});
API Reference
uncloseai. Client
Main client class for interacting with AI APIs.
constructor(options)
Initialize the client.
Parameters:
endpoints(Array, optional): Model endpoints (auto-discovers from env if not provided)ttsEndpoints(Array, optional): TTS endpoints (auto-discovers from env if not provided)apiKey(String, optional): API key for authenticationtimeout(Number): Request timeout in milliseconds (default: 30000)debug(Boolean): Enable debug logging (default: false)
async listModels()
List all discovered models with their metadata.
Returns:
- Array of objects with
id,endpoint, andmax_tokens
Example:
const models = await client.listModels();
console.log(models);
// [{ id: 'model-name', endpoint: 'https://...', max_tokens: 8192 }, ...]
async chat(options)
Send a non-streaming chat completion request.
Parameters:
messages(Array): Array of message objects with 'role' and 'content'model(String): Model ID or 'auto' for first available (default: 'auto')maxTokens(Number, optional): Maximum tokens to generatetemperature(Number): Sampling temperature 0-2 (default: 0.7)topP(Number): Nucleus sampling parameter (default: 1.0)- Additional parameters passed to API
Returns:
- Chat completion response object
Throws:
ModelNotFoundError: If model not foundConnectionError: If request fails
Example:
const response = await client.chat({
model: 'auto',
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: 'What is AI?' }
],
maxTokens: 100
});
console.log(response.choices[0].message.content);
async *chatStream(options)
Send a streaming chat completion request.
Parameters:
- Same as
chat()
Yields:
- Chat completion chunk objects
Throws:
ModelNotFoundError: If model not foundStreamingError: If streaming fails
Example:
for await (const chunk of client.chatStream({
model: 'auto',
messages: [{ role: 'user', content: 'Write a haiku' }]
})) {
const content = chunk.choices?.[0]?.delta?.content || '';
if (content) {
process.stdout.write(content);
}
}
async tts(options)
Generate speech from text.
Parameters:
text(String): Text to convert to speechvoice(String): Voice to use - alloy, echo, fable, onyx, nova, shimmer (default: 'alloy')model(String): TTS model - tts-1 or tts-1-hd (default: 'tts-1')- Additional parameters passed to API
Returns:
- Buffer containing audio data (MP3 format)
Throws:
ConnectionError: If request failsuncloseaiError: If no TTS endpoints available
Example:
const audioData = await client.tts({
text: 'Hello from uncloseai.!',
voice: 'alloy',
model: 'tts-1'
});
fs.writeFileSync('output.mp3', audioData);
Usage Examples
Basic Chat
const { uncloseai } = require('./uncloseai_lib');
const client = new uncloseai();
const response = await client.chat({
model: 'auto',
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: 'What is JavaScript?' }
],
maxTokens: 100
});
console.log(response.choices[0].message.content);
Streaming Chat
for await (const chunk of client.chatStream({
model: 'auto',
messages: [{ role: 'user', content: 'Write a haiku about code' }],
maxTokens: 100
})) {
const content = chunk.choices?.[0]?.delta?.content || '';
if (content) {
process.stdout.write(content);
}
}
console.log(); // newline
Multi-Turn Conversation
const messages = [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: 'What is AI?' }
];
// First response
const response1 = await client.chat({ model: 'auto', messages });
const assistantMsg = response1.choices[0].message.content;
messages.push({ role: 'assistant', content: assistantMsg });
// Follow-up question
messages.push({ role: 'user', content: 'Can you explain more?' });
const response2 = await client.chat({ model: 'auto', messages });
Text-to-Speech
const fs = require('fs');
const audioData = await client.tts({
text: 'Hello from uncloseai.!',
voice: 'alloy',
model: 'tts-1'
});
fs.writeFileSync('output.mp3', audioData);
Using Specific Models
// List available models
const models = await client.listModels();
for (const model of models) {
console.log(`${model.id} - Max tokens: ${model.max_tokens}`);
}
// Use specific model
const response = await client.chat({
model: models[0].id,
messages: [{ role: 'user', content: 'Hello' }]
});
Error Handling
const { uncloseai, uncloseaiError, ModelNotFoundError } = require('./uncloseai_lib');
const client = new uncloseai();
try {
const response = await client.chat({
model: 'non-existent-model',
messages: [{ role: 'user', content: 'Hello' }]
});
} catch (error) {
if (error instanceof ModelNotFoundError) {
console.log(`Model error: ${error.message}`);
} else if (error instanceof uncloseaiError) {
console.log(`API error: ${error.message}`);
} else {
throw error;
}
}
Running Examples
# Set environment variables
export MODEL_ENDPOINT_1="https://hermes.ai.unturf.com/v1"
export MODEL_ENDPOINT_2="https://qwen.ai.unturf.com/v1"
export TTS_ENDPOINT_1="https://speech.ai.unturf.com/v1"
# Run example script
node examples.js
Docker Usage
# Build
docker build -t uncloseai-nodejs .
# Run examples
docker run -e MODEL_ENDPOINT_1="https://..." uncloseai-nodejs node examples.js
Compatibility
Tested with:
- ✅ vLLM (v0.5.0+)
- ✅ Ollama (v0.1.0+)
- ✅ OpenAI API (compatible endpoints)
Error Types
uncloseaiError- Base error class for all library errorsConnectionError- Network connection errorsModelNotFoundError- Requested model not availableStreamingError- Errors during streaming requests
License
MIT License - See LICENSE file for details
Contributing
Contributions welcome! Please submit pull requests or open issues.
Support
For issues, questions, or contributions, please visit: https://github.com/yourusername/uncloseai
Changelog
v1.0.0 (2025-10-13)
- Initial release
- Streaming and non-streaming chat support
- Text-to-speech generation
- Automatic model discovery
- Zero external dependencies
- Comprehensive error handling