- 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
201 lines
7.9 KiB
HTML
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>
|