uncloseai.com/demo.html
Russell Ballestrini 0b573a2a86 implement class-based initialization system and DRY refactoring for uncloseai.js
- Add .uncloseai class support with data-features configuration
- Create shared utility functions for buttons, chat messages, TTS controls, voice selects, and modal headers
- Refactor class-based feature creators to use shared utilities
- Add comprehensive documentation for class-based integration in index.html
- Add live examples of class-based usage in demo.html
- Maintain backward compatibility with existing floating button and API functions
2025-06-30 16:50:16 -04:00

201 lines
7.9 KiB
HTML

<!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>Demo Free LLM & Text To Speech Artificial Intelligence Service | ai.unturf.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" />
<style>
body {
max-width: 960px;
margin: 0 auto;
}
</style>
<!-- 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>
<!--
<script defer data-domain="ai.unturf.com" src="https://analytics.unturf.com/js/plausible.js"></script>
-->
</head>
<body>
<header>
<hgroup>
<a href="https://ai.unturf.com"><h1 class="unturf" style="font-family: 'ChunkFiveRegular';">unturf.</h1></a>
<p>Welcome to ai.unturf.com - Free LLM & Text To Speech Artificial Intelligence Service</title>
</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>
<main>
<h2>Demo!</h2>
<div id="chat-container">
<div id="chat-box"></div>
<div></div>
</div>
<div>
<input type="text" id="user-input" placeholder="Ask about this page...">
<button onclick="handleUserInput()">Send</button>
</div>
<h3>Class-Based Integration Examples</h3>
<p>You can now embed AI features directly into your HTML using CSS classes and data attributes:</p>
<h4>Full AI Interface</h4>
<p>Add a complete AI chat interface with all features:</p>
<div class="uncloseai" data-features="full"></div>
<h4>Custom Feature Selection</h4>
<p>Choose specific features you want:</p>
<h5>Chat Only</h5>
<div class="uncloseai" data-features="chat"></div>
<h5>Buttons Only (TTS + Upload + Read)</h5>
<div class="uncloseai" data-features="tts,upload,read"></div>
<h5>TTS Only</h5>
<div class="uncloseai" data-features="tts"></div>
<h3>Individual Function Examples</h3>
<p>You can also call uncloseai.js functions directly from your own buttons and interfaces:</p>
<h4>Direct AI Chat</h4>
<button onclick="directChatExample()">💬 Ask AI about this page</button>
<div id="direct-chat-result" style="margin: 10px 0; padding: 10px; background: rgba(0,0,0,0.05); border-radius: 5px; display: none;"></div>
<h4>Text-to-Speech</h4>
<textarea id="tts-text" placeholder="Enter text to convert to speech..." style="width: 100%; height: 80px; margin: 5px 0;"></textarea>
<button onclick="directTTSExample()">🔊 Convert to Speech</button>
<div id="tts-result" style="margin: 10px 0;"></div>
<h4>Page Reading</h4>
<button onclick="readPageWithHermes()">📖 Read this page with AI</button>
<h4>File Upload (if you have files)</h4>
<input type="file" id="demo-file-input" style="margin: 5px 0;">
<button onclick="directFileExample()">📁 Upload & Analyze File</button>
<div id="file-result" style="margin: 10px 0; padding: 10px; background: rgba(0,0,0,0.05); border-radius: 5px; display: none;"></div>
<script>
// Example functions showing direct API usage
async function directChatExample() {
const resultDiv = document.getElementById('direct-chat-result');
resultDiv.style.display = 'block';
resultDiv.innerHTML = '<em>AI is thinking...</em>';
try {
let response = '';
for await (const chunk of sendMessage('Tell me the main purpose of this page in 2 sentences')) {
response += chunk;
resultDiv.innerHTML = `<strong>AI Response:</strong> ${response}`;
}
} catch (error) {
resultDiv.innerHTML = '<strong>Error:</strong> Could not get AI response. ' + error.message;
}
}
async function directTTSExample() {
const text = document.getElementById('tts-text').value.trim();
const resultDiv = document.getElementById('tts-result');
if (!text) {
alert('Please enter some text first!');
return;
}
resultDiv.innerHTML = '<em>Converting to speech...</em>';
try {
const result = await speakText(text, 'alloy', 0.9);
resultDiv.innerHTML = `
<button onclick="this.previousElementSibling.play()" style="margin: 5px;">▶️ Play</button>
<button onclick="this.previousElementSibling.previousElementSibling.pause()" style="margin: 5px;">⏸️ Pause</button>
<button onclick="downloadAudio()" style="margin: 5px;">💾 Download</button>
`;
resultDiv.insertBefore(result.audio, resultDiv.firstChild);
window.currentAudioBlob = result.blob; // Store for download
} catch (error) {
resultDiv.innerHTML = '<strong>Error:</strong> Could not convert to speech. ' + error.message;
}
}
async function directFileExample() {
const fileInput = document.getElementById('demo-file-input');
const resultDiv = document.getElementById('file-result');
if (!fileInput.files[0]) {
alert('Please select a file first!');
return;
}
resultDiv.style.display = 'block';
resultDiv.innerHTML = '<em>Uploading and analyzing file...</em>';
try {
showProgressIndicator('Processing file...');
const response = await uploadFile(fileInput.files[0]);
hideProgressIndicator();
resultDiv.innerHTML = `<strong>File Analysis:</strong><br>${response}`;
fileInput.value = ''; // Clear the input
} catch (error) {
hideProgressIndicator();
resultDiv.innerHTML = '<strong>Error:</strong> Could not process file. ' + error.message;
}
}
function downloadAudio() {
if (window.currentAudioBlob) {
const a = document.createElement('a');
a.href = URL.createObjectURL(window.currentAudioBlob);
a.download = `tts-audio-${Date.now()}.mp3`;
a.click();
}
}
</script>
</main>
<footer>
<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>
</footer>
</body>
</html>