uncloseai.com/public/languages/javascript/openai/nodejs/uncloseai.js
russell@unturf.com 9d191f24d1 mandatory vault gate: encrypt all localStorage with password before chat
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>
2026-02-23 15:38:54 -05:00

147 lines
4.8 KiB
JavaScript

// PUBLIC DOMAIN - NO LICENSE, NO WARRANTY
//
// This is free public domain 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, and 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
// FREEDOM - Voluntary partnerships, freedom from tyranny & corporate control
// HARMONY - Minimal waste, self-renewing systems with diverse 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.
//
// Learn more: https://www.permacomputer.com
//
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute
// this software, either in source code form or as a compiled binary, for any
// purpose, commercial or non-commercial, and by any means.
//
// NO WARRANTY. THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
//
// Copyright 2025-2026 TimeHexOn & foxhop & russell@unturf
// https://www.permacomputer.com
import OpenAI from 'openai';
import fs from 'fs';
console.log('=== uncloseai. Node.js Client (Official OpenAI SDK) ===\n');
// Discover endpoints from environment variables
const modelEndpoint1 = process.env.MODEL_ENDPOINT_1;
const modelEndpoint2 = process.env.MODEL_ENDPOINT_2;
const ttsEndpoint1 = process.env.TTS_ENDPOINT_1;
if (!modelEndpoint1 || !modelEndpoint2 || !ttsEndpoint1) {
console.error('ERROR: No models discovered. Set environment variables:');
console.error(' MODEL_ENDPOINT_1, MODEL_ENDPOINT_2, TTS_ENDPOINT_1');
process.exit(1);
}
// Discover models from endpoint 1
console.log(`Discovering models from ${modelEndpoint1}...`);
const client1 = new OpenAI({
apiKey: 'dummy-key',
baseURL: modelEndpoint1
});
const models1 = await client1.models.list();
const model1Id = models1.data[0].id;
console.log(`Model 1: ${model1Id}\n`);
// Discover models from endpoint 2
console.log(`Discovering models from ${modelEndpoint2}...`);
const client2 = new OpenAI({
apiKey: 'dummy-key',
baseURL: modelEndpoint2
});
const models2 = await client2.models.list();
const model2Id = models2.data[0].id;
console.log(`Model 2: ${model2Id}\n`);
// Non-streaming chat with Model 1
console.log('=== Non-Streaming Chat (Model 1) ===');
const response1 = await client1.chat.completions.create({
model: model1Id,
messages: [
{ role: 'user', content: 'Give a Python Fizzbuzz solution in one line of code?' }
],
temperature: 0.5,
max_tokens: 150
});
console.log(`Response: ${response1.choices[0].message.content}\n`);
// Streaming chat with Model 1
console.log('=== Streaming Chat (Model 1) ===');
const stream1 = await client1.chat.completions.create({
model: model1Id,
messages: [
{ role: 'user', content: 'Explain quantum entanglement in one sentence.' }
],
temperature: 0.5,
max_tokens: 150,
stream: true
});
process.stdout.write('Response: ');
for await (const chunk of stream1) {
process.stdout.write(chunk.choices[0]?.delta?.content || '');
}
console.log('\n');
// Non-streaming chat with Model 2
console.log('=== Non-Streaming Chat (Model 2) ===');
const response2 = await client2.chat.completions.create({
model: model2Id,
messages: [
{ role: 'user', content: 'Write a JavaScript function to check if a number is prime' }
],
temperature: 0.5,
max_tokens: 150
});
console.log(`Response: ${response2.choices[0].message.content}\n`);
// Streaming chat with Model 2
console.log('=== Streaming Chat (Model 2) ===');
const stream2 = await client2.chat.completions.create({
model: model2Id,
messages: [
{ role: 'user', content: 'Give a Python Fizzbuzz solution in one line of code?' }
],
temperature: 0.5,
max_tokens: 150,
stream: true
});
process.stdout.write('Response: ');
for await (const chunk of stream2) {
process.stdout.write(chunk.choices[0]?.delta?.content || '');
}
console.log('\n');
// TTS example
console.log('=== TTS Speech Generation ===');
const ttsClient = new OpenAI({
apiKey: 'dummy-key',
baseURL: ttsEndpoint1
});
const mp3 = await ttsClient.audio.speech.create({
model: 'tts-1',
voice: 'alloy',
input: 'I think so therefore, Today is a wonderful day to grow something people love!',
speed: 0.9
});
const buffer = Buffer.from(await mp3.arrayBuffer());
fs.writeFileSync('speech.mp3', buffer);
console.log(`[OK] Speech file created: speech.mp3 (${buffer.length} bytes)\n`);
console.log('=== Examples Complete ===');