Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>AI Video Avatar - Your Digital Guide</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<style> | |
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap'); | |
:root { | |
--primary: #3b82f6; | |
--primary-dark: #2563eb; | |
--secondary: #f43f5e; | |
} | |
body { | |
font-family: 'Poppins', sans-serif; | |
background: #0f172a; | |
color: white; | |
overflow: hidden; | |
height: 100vh; | |
} | |
.video-container { | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
z-index: 0; | |
overflow: hidden; | |
} | |
.video-placeholder { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
object-fit: cover; | |
background-color: #1e293b; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
} | |
.video-placeholder img { | |
max-width: 100%; | |
max-height: 100%; | |
object-fit: contain; | |
} | |
.video-overlay { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background: linear-gradient(to bottom, rgba(15, 23, 42, 0.2) 0%, rgba(15, 23, 42, 0.7) 100%); | |
z-index: 1; | |
} | |
.content-container { | |
position: relative; | |
z-index: 2; | |
height: 100vh; | |
display: flex; | |
flex-direction: column; | |
justify-content: flex-end; | |
padding-bottom: 120px; | |
} | |
.speech-bubble { | |
position: relative; | |
background: rgba(30, 41, 59, 0.9); | |
border-radius: 1rem; | |
animation: pulse 2s infinite; | |
max-width: 800px; | |
margin: 0 auto; | |
} | |
.speech-bubble:after { | |
content: ''; | |
position: absolute; | |
bottom: -10px; | |
left: 50px; | |
border-width: 10px 10px 0; | |
border-style: solid; | |
border-color: rgba(30, 41, 59, 0.9) transparent; | |
} | |
@keyframes pulse { | |
0% { | |
box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4); | |
} | |
70% { | |
box-shadow: 0 0 0 10px rgba(59, 130, 246, 0); | |
} | |
100% { | |
box-shadow: 0 0 0 0 rgba(59, 130, 246, 0); | |
} | |
} | |
.typing-indicator span { | |
display: inline-block; | |
width: 8px; | |
height: 8px; | |
border-radius: 50%; | |
background: white; | |
margin: 0 2px; | |
opacity: 0.4; | |
} | |
.typing-indicator span:nth-child(1) { | |
animation: typing 1s infinite; | |
} | |
.typing-indicator span:nth-child(2) { | |
animation: typing 1s infinite 0.2s; | |
} | |
.typing-indicator span:nth-child(3) { | |
animation: typing 1s infinite 0.4s; | |
} | |
@keyframes typing { | |
0% { | |
opacity: 0.4; | |
transform: translateY(0); | |
} | |
50% { | |
opacity: 1; | |
transform: translateY(-5px); | |
} | |
100% { | |
opacity: 0.4; | |
transform: translateY(0); | |
} | |
} | |
.lip-sync { | |
animation: lip-sync 0.5s infinite alternate; | |
} | |
@keyframes lip-sync { | |
0% { | |
transform: scaleY(1); | |
} | |
100% { | |
transform: scaleY(0.8); | |
} | |
} | |
.news-card { | |
background: linear-gradient(135deg, rgba(30, 41, 59, 0.8) 0%, rgba(15, 23, 42, 0.9) 100%); | |
backdrop-filter: blur(10px); | |
transition: all 0.3s ease; | |
} | |
.news-card:hover { | |
transform: translateY(-5px); | |
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3); | |
} | |
.social-icon { | |
transition: all 0.3s ease; | |
} | |
.social-icon:hover { | |
transform: scale(1.2); | |
} | |
.upload-btn { | |
position: absolute; | |
top: 20px; | |
right: 20px; | |
z-index: 10; | |
background: rgba(30, 41, 59, 0.8); | |
border: 1px solid #3b82f6; | |
color: white; | |
padding: 8px 16px; | |
border-radius: 8px; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
} | |
.upload-btn:hover { | |
background: rgba(59, 130, 246, 0.8); | |
} | |
#file-input { | |
display: none; | |
} | |
.upload-icon { | |
margin-right: 8px; | |
} | |
.avatar-placeholder-text { | |
color: rgba(255, 255, 255, 0.5); | |
font-size: 1.2rem; | |
text-align: center; | |
padding: 20px; | |
} | |
/* Floating action button styles */ | |
.fab-container { | |
position: fixed; | |
bottom: 30px; | |
right: 30px; | |
z-index: 100; | |
display: flex; | |
flex-direction: column; | |
align-items: flex-end; | |
} | |
.fab-main { | |
width: 60px; | |
height: 60px; | |
border-radius: 50%; | |
background: linear-gradient(135deg, #3b82f6, #2563eb); | |
color: white; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
font-size: 24px; | |
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); | |
cursor: pointer; | |
transition: all 0.3s ease; | |
z-index: 101; | |
} | |
.fab-main:hover { | |
transform: scale(1.1); | |
box-shadow: 0 6px 25px rgba(0, 0, 0, 0.4); | |
} | |
.fab-menu { | |
position: absolute; | |
bottom: 70px; | |
right: 0; | |
width: 300px; | |
background: rgba(30, 41, 59, 0.95); | |
border-radius: 16px; | |
padding: 20px; | |
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); | |
transform: translateY(20px); | |
opacity: 0; | |
pointer-events: none; | |
transition: all 0.3s ease; | |
backdrop-filter: blur(10px); | |
} | |
.fab-menu.active { | |
transform: translateY(0); | |
opacity: 1; | |
pointer-events: all; | |
} | |
.fab-menu-header { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
margin-bottom: 15px; | |
} | |
.fab-menu-title { | |
font-weight: 600; | |
color: #3b82f6; | |
} | |
.fab-close-btn { | |
background: none; | |
border: none; | |
color: rgba(255, 255, 255, 0.5); | |
font-size: 20px; | |
cursor: pointer; | |
transition: all 0.2s ease; | |
} | |
.fab-close-btn:hover { | |
color: white; | |
} | |
.fab-menu-content { | |
max-height: 400px; | |
overflow-y: auto; | |
} | |
.fab-menu-tabs { | |
display: flex; | |
margin-bottom: 15px; | |
border-bottom: 1px solid rgba(255, 255, 255, 0.1); | |
} | |
.fab-tab { | |
padding: 8px 16px; | |
cursor: pointer; | |
color: rgba(255, 255, 255, 0.6); | |
font-size: 14px; | |
transition: all 0.2s ease; | |
border-bottom: 2px solid transparent; | |
} | |
.fab-tab.active { | |
color: white; | |
border-bottom: 2px solid #3b82f6; | |
} | |
.fab-tab:hover { | |
color: white; | |
} | |
.fab-tab-content { | |
display: none; | |
} | |
.fab-tab-content.active { | |
display: block; | |
} | |
.fab-chat-input { | |
display: flex; | |
gap: 10px; | |
margin-top: 15px; | |
} | |
.fab-chat-input input { | |
flex: 1; | |
background: rgba(15, 23, 42, 0.7); | |
border: 1px solid rgba(255, 255, 255, 0.1); | |
border-radius: 8px; | |
padding: 10px 15px; | |
color: white; | |
outline: none; | |
} | |
.fab-chat-input button { | |
background: #3b82f6; | |
color: white; | |
border: none; | |
border-radius: 8px; | |
padding: 0 15px; | |
cursor: pointer; | |
transition: all 0.2s ease; | |
} | |
.fab-chat-input button:hover { | |
background: #2563eb; | |
} | |
/* TTS Button Styles */ | |
.tts-container { | |
position: fixed; | |
bottom: 30px; | |
right: 100px; | |
z-index: 100; | |
display: flex; | |
flex-direction: column; | |
align-items: flex-end; | |
} | |
.tts-button { | |
width: 60px; | |
height: 60px; | |
border-radius: 50%; | |
background: linear-gradient(135deg, #f43f5e, #e11d48); | |
color: white; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
font-size: 24px; | |
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); | |
cursor: pointer; | |
transition: all 0.3s ease; | |
z-index: 101; | |
border: none; | |
outline: none; | |
} | |
.tts-button:hover { | |
transform: scale(1.1); | |
box-shadow: 0 6px 25px rgba(0, 0, 0, 0.4); | |
} | |
.tts-button.listening { | |
animation: pulse-red 1.5s infinite; | |
} | |
.tts-panel { | |
position: absolute; | |
bottom: 70px; | |
right: 0; | |
width: 300px; | |
background: rgba(30, 41, 59, 0.95); | |
border-radius: 16px; | |
padding: 20px; | |
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); | |
transform: translateY(20px); | |
opacity: 0; | |
pointer-events: none; | |
transition: all 0.3s ease; | |
backdrop-filter: blur(10px); | |
} | |
.tts-panel.active { | |
transform: translateY(0); | |
opacity: 1; | |
pointer-events: all; | |
} | |
.tts-header { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
margin-bottom: 15px; | |
} | |
.tts-title { | |
font-weight: 600; | |
color: #f43f5e; | |
} | |
.tts-close-btn { | |
background: none; | |
border: none; | |
color: rgba(255, 255, 255, 0.5); | |
font-size: 20px; | |
cursor: pointer; | |
transition: all 0.2s ease; | |
} | |
.tts-close-btn:hover { | |
color: white; | |
} | |
.tts-content { | |
max-height: 300px; | |
overflow-y: auto; | |
margin-bottom: 15px; | |
} | |
.tts-status { | |
font-size: 14px; | |
color: rgba(255, 255, 255, 0.7); | |
margin-bottom: 10px; | |
text-align: center; | |
} | |
.tts-transcript { | |
background: rgba(15, 23, 42, 0.7); | |
border-radius: 8px; | |
padding: 10px; | |
min-height: 60px; | |
margin-bottom: 15px; | |
} | |
.tts-controls { | |
display: flex; | |
justify-content: center; | |
gap: 10px; | |
} | |
.tts-controls button { | |
background: #f43f5e; | |
color: white; | |
border: none; | |
border-radius: 8px; | |
padding: 8px 15px; | |
cursor: pointer; | |
transition: all 0.2s ease; | |
display: flex; | |
align-items: center; | |
gap: 5px; | |
} | |
.tts-controls button:hover { | |
background: #e11d48; | |
} | |
.tts-controls button.secondary { | |
background: rgba(255, 255, 255, 0.1); | |
} | |
.tts-controls button.secondary:hover { | |
background: rgba(255, 255, 255, 0.2); | |
} | |
@keyframes pulse-red { | |
0% { | |
box-shadow: 0 0 0 0 rgba(244, 63, 94, 0.7); | |
} | |
70% { | |
box-shadow: 0 0 0 10px rgba(244, 63, 94, 0); | |
} | |
100% { | |
box-shadow: 0 0 0 0 rgba(244, 63, 94, 0); | |
} | |
} | |
/* Scrollbar styling */ | |
::-webkit-scrollbar { | |
width: 6px; | |
} | |
::-webkit-scrollbar-track { | |
background: rgba(255, 255, 255, 0.05); | |
border-radius: 3px; | |
} | |
::-webkit-scrollbar-thumb { | |
background: rgba(255, 255, 255, 0.2); | |
border-radius: 3px; | |
} | |
::-webkit-scrollbar-thumb:hover { | |
background: rgba(255, 255, 255, 0.3); | |
} | |
</style> | |
</head> | |
<body> | |
<!-- Video Avatar Container --> | |
<div class="video-container"> | |
<div class="video-placeholder" id="video-placeholder"> | |
<div class="avatar-placeholder-text"> | |
<i class="fas fa-user-circle text-6xl mb-4"></i> | |
<p>Upload an image to create your AI video avatar</p> | |
</div> | |
</div> | |
<div class="video-overlay"></div> | |
</div> | |
<!-- Upload Button --> | |
<button class="upload-btn" onclick="document.getElementById('file-input').click()"> | |
<i class="fas fa-upload upload-icon"></i> | |
Upload Avatar Image | |
</button> | |
<input type="file" id="file-input" accept="image/*"> | |
<!-- Content Container --> | |
<div class="content-container"> | |
<!-- Speech Bubble --> | |
<div class="speech-bubble p-6 mb-6 mx-4 relative"> | |
<div id="avatar-message" class="text-lg"> | |
Hello there! I'm your AI Avatar. Upload an image to create your personalized video avatar. | |
</div> | |
<div id="typing-indicator" class="typing-indicator hidden mt-2"> | |
<span></span> | |
<span></span> | |
<span></span> | |
</div> | |
</div> | |
<!-- Social Media & Controls --> | |
<div class="flex justify-center gap-6 mt-8"> | |
<button onclick="shareOnSocial('twitter')" class="social-icon text-blue-400 hover:text-blue-300 text-2xl"> | |
<i class="fab fa-twitter"></i> | |
</button> | |
<button onclick="shareOnSocial('facebook')" class="social-icon text-blue-500 hover:text-blue-400 text-2xl"> | |
<i class="fab fa-facebook"></i> | |
</button> | |
<button onclick="shareOnSocial('linkedin')" class="social-icon text-blue-600 hover:text-blue-500 text-2xl"> | |
<i class="fab fa-linkedin"></i> | |
</button> | |
<button onclick="toggleFullscreen()" class="social-icon text-white hover:text-gray-300 text-2xl ml-4"> | |
<i class="fas fa-expand"></i> | |
</button> | |
<button onclick="toggleMute()" class="social-icon text-white hover:text-gray-300 text-2xl"> | |
<i id="mute-icon" class="fas fa-volume-up"></i> | |
</button> | |
</div> | |
</div> | |
<!-- TTS (Voice Input) Button --> | |
<div class="tts-container"> | |
<div class="tts-panel" id="tts-panel"> | |
<div class="tts-header"> | |
<div class="tts-title">Voice Command</div> | |
<button class="tts-close-btn" onclick="toggleTtsPanel()"> | |
<i class="fas fa-times"></i> | |
</button> | |
</div> | |
<div class="tts-content"> | |
<div class="tts-status" id="tts-status"> | |
Click the microphone to start speaking | |
</div> | |
<div class="tts-transcript" id="tts-transcript"> | |
Your voice input will appear here... | |
</div> | |
</div> | |
<div class="tts-controls"> | |
<button id="tts-start-btn" onclick="startVoiceRecognition()"> | |
<i class="fas fa-microphone"></i> Start | |
</button> | |
<button class="secondary" onclick="clearTranscript()"> | |
<i class="fas fa-trash"></i> Clear | |
</button> | |
<button class="secondary" onclick="submitVoiceCommand()"> | |
<i class="fas fa-paper-plane"></i> Send | |
</button> | |
</div> | |
</div> | |
<button class="tts-button" id="tts-button" onclick="toggleTtsPanel()"> | |
<img src="https://cdn-icons-png.flaticon.com/512/4712/4712139.png" width="30" height="30" alt="Voice Assistant"> | |
</button> | |
</div> | |
<!-- Floating Action Button --> | |
<div class="fab-container"> | |
<div class="fab-menu" id="fab-menu"> | |
<div class="fab-menu-header"> | |
<div class="fab-menu-title">AI Assistant</div> | |
<button class="fab-close-btn" onclick="toggleFabMenu()"> | |
<i class="fas fa-times"></i> | |
</button> | |
</div> | |
<div class="fab-menu-tabs"> | |
<div class="fab-tab active" onclick="switchTab('topics')">Topics</div> | |
<div class="fab-tab" onclick="switchTab('chat')">Chat</div> | |
</div> | |
<div class="fab-menu-content"> | |
<div class="fab-tab-content active" id="topics-tab"> | |
<div class="grid grid-cols-1 gap-3"> | |
<div class="news-card p-4 rounded-xl cursor-pointer" onclick="selectTopic('technology')"> | |
<h3 class="font-bold text-blue-300">Tech Updates</h3> | |
<p class="text-sm">Latest in AI and gadgets</p> | |
</div> | |
<div class="news-card p-4 rounded-xl cursor-pointer" onclick="selectTopic('entertainment')"> | |
<h3 class="font-bold text-pink-300">Entertainment</h3> | |
<p class="text-sm">Movies, music and celebrity news</p> | |
</div> | |
</div> | |
</div> | |
<div class="fab-tab-content" id="chat-tab"> | |
<div class="text-center text-gray-400 py-4"> | |
Ask me anything about technology, entertainment, or current events | |
</div> | |
<div class="fab-chat-input"> | |
<input type="text" id="fab-user-input" placeholder="Type your message..."> | |
<button onclick="sendMessageFromFab()"> | |
<i class="fas fa-paper-plane"></i> | |
</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="fab-main" onclick="toggleFabMenu()"> | |
<i class="fas fa-comment-dots"></i> | |
</div> | |
</div> | |
<script> | |
// Speech Synthesis | |
const synth = window.speechSynthesis; | |
let isSpeaking = false; | |
let isMuted = false; | |
// Voice recognition | |
let recognition; | |
let isListening = false; | |
let finalTranscript = ''; | |
// Sample knowledge base | |
const knowledgeBase = { | |
technology: [ | |
"The latest AI models can now generate realistic video from text prompts. This could revolutionize content creation.", | |
"Quantum computing is making progress with several companies announcing breakthroughs in qubit stability.", | |
"The metaverse continues to evolve with new VR headsets offering higher resolution and better motion tracking." | |
], | |
entertainment: [ | |
"The summer blockbuster season is heating up with several highly anticipated movies releasing this month.", | |
"Streaming platforms are investing heavily in original content, with over 500 new shows announced this year.", | |
"Music festivals are returning in full force after the pandemic, with record ticket sales reported." | |
], | |
default: [ | |
"I'm here to help you stay informed about the latest trends and news.", | |
"Did you know I can summarize complex topics into easy-to-understand explanations?", | |
"Feel free to ask me about technology, entertainment, or current events." | |
] | |
}; | |
// Initialize | |
document.addEventListener('DOMContentLoaded', () => { | |
// Start with a greeting | |
setTimeout(() => { | |
speak("Hello there! I'm your AI guide. Upload an image to create your personalized video avatar."); | |
}, 1000); | |
// Set up image upload | |
document.getElementById('file-input').addEventListener('change', handleImageUpload); | |
// Set up keyboard events for fab input | |
document.getElementById('fab-user-input').addEventListener('keypress', (e) => { | |
if (e.key === 'Enter') { | |
sendMessageFromFab(); | |
} | |
}); | |
// Initialize voice recognition | |
initVoiceRecognition(); | |
}); | |
// Handle image upload | |
function handleImageUpload(event) { | |
const file = event.target.files[0]; | |
if (!file) return; | |
const reader = new FileReader(); | |
reader.onload = function(e) { | |
const placeholder = document.getElementById('video-placeholder'); | |
placeholder.innerHTML = ''; | |
const img = document.createElement('img'); | |
img.src = e.target.result; | |
img.alt = 'AI Avatar'; | |
placeholder.appendChild(img); | |
// Simulate video processing | |
setTimeout(() => { | |
speak("Thank you! Your AI video avatar is being processed. In a real implementation, this would generate a lifelike talking avatar from your image."); | |
}, 1000); | |
}; | |
reader.readAsDataURL(file); | |
} | |
// Speech function | |
function speak(text) { | |
if (isMuted) return; | |
const utterance = new SpeechSynthesisUtterance(text); | |
utterance.voice = synth.getVoices().find(voice => voice.name.includes('English')); | |
utterance.pitch = 1; | |
utterance.rate = 1; | |
utterance.volume = 1; | |
isSpeaking = true; | |
synth.speak(utterance); | |
utterance.onend = () => { | |
isSpeaking = false; | |
}; | |
// Display message | |
document.getElementById('avatar-message').textContent = text; | |
} | |
// Process user input | |
function sendMessage() { | |
const input = document.getElementById('user-input'); | |
const message = input.value.trim(); | |
if (message) { | |
// Show user message temporarily | |
document.getElementById('avatar-message').textContent = `You: ${message}`; | |
input.value = ''; | |
// Show typing indicator | |
document.getElementById('typing-indicator').classList.remove('hidden'); | |
// Process after delay | |
setTimeout(() => { | |
document.getElementById('typing-indicator').classList.add('hidden'); | |
respondToMessage(message); | |
}, 1500); | |
} | |
} | |
// Process user input from FAB | |
function sendMessageFromFab() { | |
const input = document.getElementById('fab-user-input'); | |
const message = input.value.trim(); | |
if (message) { | |
// Show user message temporarily | |
document.getElementById('avatar-message').textContent = `You: ${message}`; | |
input.value = ''; | |
// Show typing indicator | |
document.getElementById('typing-indicator').classList.remove('hidden'); | |
// Process after delay | |
setTimeout(() => { | |
document.getElementById('typing-indicator').classList.add('hidden'); | |
respondToMessage(message); | |
}, 1500); | |
} | |
} | |
// AI response logic | |
function respondToMessage(message) { | |
let response = ""; | |
const lowerMsg = message.toLowerCase(); | |
if (lowerMsg.includes('tech') || lowerMsg.includes('technology')) { | |
const techResponses = knowledgeBase.technology; | |
response = techResponses[Math.floor(Math.random() * techResponses.length)]; | |
} | |
else if (lowerMsg.includes('movie') || lowerMsg.includes('music') || lowerMsg.includes('entertainment')) { | |
const entResponses = knowledgeBase.entertainment; | |
response = entResponses[Math.floor(Math.random() * entResponses.length)]; | |
} | |
else if (lowerMsg.includes('hello') || lowerMsg.includes('hi')) { | |
response = "Hello! It's great to connect with you. How can I assist you today?"; | |
} | |
else if (lowerMsg.includes('how are you')) { | |
response = "I'm an AI, so I don't have feelings, but I'm functioning optimally and ready to help you!"; | |
} | |
else { | |
const defaultResponses = knowledgeBase.default; | |
response = defaultResponses[Math.floor(Math.random() * defaultResponses.length)]; | |
} | |
speak(response); | |
} | |
// Topic selection | |
function selectTopic(topic) { | |
const message = `Tell me about ${topic}`; | |
document.getElementById('avatar-message').textContent = `You: ${message}`; | |
// Show typing indicator | |
document.getElementById('typing-indicator').classList.remove('hidden'); | |
// Process after delay | |
setTimeout(() => { | |
document.getElementById('typing-indicator').classList.add('hidden'); | |
respondToMessage(message); | |
}, 1500); | |
// Close the menu | |
toggleFabMenu(); | |
} | |
// Social sharing | |
function shareOnSocial(platform) { | |
const text = encodeURIComponent("Check out this amazing AI video avatar I'm interacting with!"); | |
const url = encodeURIComponent(window.location.href); | |
let shareUrl = ""; | |
switch(platform) { | |
case 'twitter': | |
shareUrl = `https://twitter.com/intent/tweet?text=${text}&url=${url}`; | |
break; | |
case 'facebook': | |
shareUrl = `https://www.facebook.com/sharer/sharer.php?u=${url}`; | |
break; | |
case 'linkedin': | |
shareUrl = `https://www.linkedin.com/shareArticle?mini=true&url=${url}&title=${text}`; | |
break; | |
} | |
window.open(shareUrl, '_blank', 'width=600,height=400'); | |
} | |
// Fullscreen toggle | |
function toggleFullscreen() { | |
if (!document.fullscreenElement) { | |
document.documentElement.requestFullscreen(); | |
} else { | |
if (document.exitFullscreen) { | |
document.exitFullscreen(); | |
} | |
} | |
} | |
// Mute toggle | |
function toggleMute() { | |
isMuted = !isMuted; | |
const icon = document.getElementById('mute-icon'); | |
if (isMuted) { | |
icon.classList.remove('fa-volume-up'); | |
icon.classList.add('fa-volume-mute'); | |
synth.cancel(); | |
} else { | |
icon.classList.remove('fa-volume-mute'); | |
icon.classList.add('fa-volume-up'); | |
} | |
} | |
// Toggle FAB menu | |
function toggleFabMenu() { | |
const menu = document.getElementById('fab-menu'); | |
menu.classList.toggle('active'); | |
} | |
// Switch between tabs in FAB menu | |
function switchTab(tabName) { | |
// Update active tab | |
document.querySelectorAll('.fab-tab').forEach(tab => { | |
tab.classList.remove('active'); | |
}); | |
event.target.classList.add('active'); | |
// Update active content | |
document.querySelectorAll('.fab-tab-content').forEach(content => { | |
content.classList.remove('active'); | |
}); | |
document.getElementById(`${tabName}-tab`).classList.add('active'); | |
} | |
// Toggle TTS panel | |
function toggleTtsPanel() { | |
const panel = document.getElementById('tts-panel'); | |
panel.classList.toggle('active'); | |
// Close FAB menu if open | |
document.getElementById('fab-menu').classList.remove('active'); | |
} | |
// Initialize voice recognition | |
function initVoiceRecognition() { | |
try { | |
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; | |
recognition = new SpeechRecognition(); | |
recognition.continuous = false; | |
recognition.interimResults = true; | |
recognition.onstart = function() { | |
isListening = true; | |
document.getElementById('tts-button').classList.add('listening'); | |
document.getElementById('tts-status').textContent = 'Listening... Speak now'; | |
}; | |
recognition.onerror = function(event) { | |
console.error('Speech recognition error', event.error); | |
stopVoiceRecognition(); | |
document.getElementById('tts-status').textContent = 'Error: ' + event.error; | |
}; | |
recognition.onend = function() { | |
stopVoiceRecognition(); | |
if (finalTranscript.trim()) { | |
document.getElementById('tts-status').textContent = 'Click send or speak again'; | |
} else { | |
document.getElementById('tts-status').textContent = 'Click the microphone to start speaking'; | |
} | |
}; | |
recognition.onresult = function(event) { | |
let interimTranscript = ''; | |
for (let i = event.resultIndex; i < event.results.length; i++) { | |
const transcript = event.results[i][0].transcript; | |
if (event.results[i].isFinal) { | |
finalTranscript += transcript; | |
} else { | |
interimTranscript += transcript; | |
} | |
} | |
document.getElementById('tts-transcript').innerHTML = | |
`<span class="text-white">${finalTranscript}</span>` + | |
`<span class="text-gray-400">${interimTranscript}</span>`; | |
}; | |
} catch (e) { | |
console.error('Speech recognition not supported', e); | |
document.getElementById('tts-status').textContent = 'Voice recognition not supported in this browser'; | |
document.getElementById('tts-start-btn').disabled = true; | |
} | |
} | |
// Start voice recognition | |
function startVoiceRecognition() { | |
if (!recognition) return; | |
finalTranscript = ''; | |
document.getElementById('tts-transcript').textContent = 'Your voice input will appear here...'; | |
try { | |
recognition.start(); | |
} catch (e) { | |
console.error('Error starting recognition:', e); | |
document.getElementById('tts-status').textContent = 'Error starting voice recognition'; | |
} | |
} | |
// Stop voice recognition | |
function stopVoiceRecognition() { | |
isListening = false; | |
document.getElementById('tts-button').classList.remove('listening'); | |
if (recognition) { | |
recognition.stop(); | |
} | |
} | |
// Clear transcript | |
function clearTranscript() { | |
finalTranscript = ''; | |
document.getElementById('tts-transcript').textContent = 'Your voice input will appear here...'; | |
document.getElementById('tts-status').textContent = 'Click the microphone to start speaking'; | |
} | |
// Submit voice command | |
function submitVoiceCommand() { | |
if (finalTranscript.trim()) { | |
// Close TTS panel | |
toggleTtsPanel(); | |
// Show user message | |
document.getElementById('avatar-message').textContent = `You: ${finalTranscript}`; | |
// Show typing indicator | |
document.getElementById('typing-indicator').classList.remove('hidden'); | |
// Process after delay | |
setTimeout(() => { | |
document.getElementById('typing-indicator').classList.add('hidden'); | |
respondToMessage(finalTranscript); | |
}, 1500); | |
// Clear transcript | |
clearTranscript(); | |
} | |
} | |
// Keyboard support | |
document.getElementById('user-input').addEventListener('keypress', (e) => { | |
if (e.key === 'Enter') { | |
sendMessage(); | |
} | |
}); | |
</script> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=privateuserh/ai-avatar-v1-02" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |