Migrate to web/index.html and OpenAI client
- Load index.html from web/index.html instead of templates/static - Initialize OpenAIClient with an empty key and local endpoint - Remove the old static/index.html file
This commit is contained in:
parent
386b55bf34
commit
e14908fc0b
3 changed files with 426 additions and 164 deletions
|
|
@ -686,8 +686,7 @@ async fn set_mode_handler(
|
|||
|
||||
#[actix_web::get("/")]
|
||||
async fn index() -> Result<HttpResponse> {
|
||||
let html = fs::read_to_string("templates/index.html")
|
||||
.unwrap_or_else(|_| include_str!("../../static/index.html").to_string());
|
||||
let html = fs::read_to_string("web/index.html").unwrap();
|
||||
Ok(HttpResponse::Ok().content_type("text/html").body(html))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,10 @@ async fn main() -> std::io::Result<()> {
|
|||
};
|
||||
|
||||
let tool_manager = Arc::new(tools::ToolManager::new());
|
||||
let llm_provider = Arc::new(llm::MockLLMProvider::new());
|
||||
let llm_provider = Arc::new(llm::OpenAIClient::new(
|
||||
"empty".to_string(),
|
||||
Some("http://localhost:8081".to_string()),
|
||||
));
|
||||
|
||||
let web_adapter = Arc::new(WebChannelAdapter::new());
|
||||
let voice_adapter = Arc::new(VoiceAdapter::new(
|
||||
|
|
|
|||
|
|
@ -1,122 +1,162 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<html lang="pt-br">
|
||||
<head>
|
||||
<title>General Bots</title>
|
||||
<meta charset="utf-8" />
|
||||
<title>General Bots 2400</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.2/anime.min.js"></script>
|
||||
<script src="https://unpkg.com/livekit-client@latest/dist/livekit-client.js"></script>
|
||||
<style>
|
||||
* {
|
||||
@import url("https://fonts.googleapis.com/css2?family=Orbitron:wght@400;600;800&family=Inter:wght@400;600&display=swap");
|
||||
|
||||
:root {
|
||||
--dante-blue: #000a1f;
|
||||
--dante-blue2: #001a3d;
|
||||
--dante-gold: #ffd700;
|
||||
--dante-gold2: #ffed4e;
|
||||
--dante-glow: rgba(255, 215, 0, 0.8);
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
font-family: "Inter", sans-serif;
|
||||
background: radial-gradient(
|
||||
circle at 20% 30%,
|
||||
rgba(0, 48, 135, 0.4),
|
||||
rgba(0, 26, 77, 0.7)
|
||||
);
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
body {
|
||||
font-family:
|
||||
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
sans-serif;
|
||||
background: #343541;
|
||||
color: white;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
|
||||
.neon-text {
|
||||
color: var(--dante-gold);
|
||||
text-shadow:
|
||||
0 0 15px var(--dante-glow),
|
||||
0 0 30px var(--dante-glow),
|
||||
0 0 60px var(--dante-glow),
|
||||
0 0 90px rgba(255, 215, 0, 0.5);
|
||||
font-weight: 700;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
.sidebar {
|
||||
width: 260px;
|
||||
background: #202123;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.neon-border {
|
||||
border: 3px solid var(--dante-gold);
|
||||
box-shadow:
|
||||
0 0 40px var(--dante-glow),
|
||||
0 0 60px rgba(255, 215, 0, 0.6),
|
||||
inset 0 0 30px rgba(255, 215, 0, 0.15);
|
||||
}
|
||||
.new-chat {
|
||||
background: transparent;
|
||||
border: 1px solid #4d4d4f;
|
||||
color: white;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
|
||||
.glass {
|
||||
background: rgba(0, 20, 60, 0.4);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(253, 185, 19, 0.2);
|
||||
}
|
||||
.voice-toggle {
|
||||
background: #19c37d;
|
||||
border: 1px solid #19c37d;
|
||||
color: white;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
|
||||
.background-animated {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
background: conic-gradient(
|
||||
from 90deg,
|
||||
#001a4d,
|
||||
#003087,
|
||||
#00509e,
|
||||
#003087,
|
||||
#001a4d
|
||||
);
|
||||
animation: rotate-bg 20s linear infinite;
|
||||
opacity: 0.5;
|
||||
z-index: 0;
|
||||
filter: blur(120px);
|
||||
}
|
||||
.voice-toggle.recording {
|
||||
background: #ef4444;
|
||||
border: 1px solid #ef4444;
|
||||
|
||||
@keyframes rotate-bg {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
.history {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.history-item {
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.history-item:hover {
|
||||
background: #2a2b32;
|
||||
}
|
||||
.main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.messages {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.message {
|
||||
max-width: 800px;
|
||||
margin: 0 auto 20px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.user-message {
|
||||
color: #d1d5db;
|
||||
}
|
||||
.assistant-message {
|
||||
color: #ececf1;
|
||||
}
|
||||
.voice-message {
|
||||
color: #19c37d;
|
||||
font-style: italic;
|
||||
}
|
||||
.input-area {
|
||||
max-width: 800px;
|
||||
margin: 0 auto 20px;
|
||||
position: relative;
|
||||
}
|
||||
.input-area input {
|
||||
width: 100%;
|
||||
background: #40414f;
|
||||
border: none;
|
||||
padding: 12px 45px 12px 15px;
|
||||
border-radius: 12px;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
}
|
||||
.input-area button {
|
||||
|
||||
.shine::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
background: #19c37d;
|
||||
border: none;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
rgba(253, 185, 19, 0.4),
|
||||
transparent
|
||||
);
|
||||
animation: shine 3s infinite;
|
||||
}
|
||||
|
||||
@keyframes shine {
|
||||
0% {
|
||||
left: -100%;
|
||||
}
|
||||
100% {
|
||||
left: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.typing-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--dante-gold);
|
||||
animation: typing-bounce 1.2s infinite;
|
||||
box-shadow: 0 0 10px var(--dante-glow);
|
||||
}
|
||||
|
||||
.typing-dot:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.typing-dot:nth-child(3) {
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
@keyframes typing-bounce {
|
||||
0%,
|
||||
60%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
30% {
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.voice-status {
|
||||
text-align: center;
|
||||
margin: 10px 0;
|
||||
color: #19c37d;
|
||||
font-family: "Orbitron", monospace;
|
||||
}
|
||||
|
||||
.pulse {
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
opacity: 1;
|
||||
|
|
@ -128,40 +168,227 @@
|
|||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.voice-message {
|
||||
color: #19c37d;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.history-item {
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 5px;
|
||||
cursor: pointer;
|
||||
color: #d1d5db;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.history-item:hover {
|
||||
background: rgba(255, 215, 0, 0.1);
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 260px;
|
||||
background: rgba(0, 10, 31, 0.8);
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
backdrop-filter: blur(20px);
|
||||
border-right: 1px solid rgba(255, 215, 0, 0.2);
|
||||
}
|
||||
|
||||
.voice-toggle {
|
||||
background: rgba(25, 195, 125, 0.2);
|
||||
border: 1px solid rgba(25, 195, 125, 0.5);
|
||||
color: #19c37d;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
font-family: "Orbitron", monospace;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.voice-toggle.recording {
|
||||
background: rgba(239, 68, 68, 0.2);
|
||||
border: 1px solid rgba(239, 68, 68, 0.5);
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
.new-chat {
|
||||
background: transparent;
|
||||
border: 1px solid rgba(255, 215, 0, 0.3);
|
||||
color: var(--dante-gold);
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
font-family: "Orbitron", monospace;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.new-chat:hover,
|
||||
.voice-toggle:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.history {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.messages {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.message {
|
||||
max-width: 800px;
|
||||
margin: 0 auto 20px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.user-message {
|
||||
color: #d1d5db;
|
||||
}
|
||||
|
||||
.assistant-message {
|
||||
color: #ececf1;
|
||||
}
|
||||
|
||||
.input-area {
|
||||
max-width: 800px;
|
||||
margin: 0 auto 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.input-area input {
|
||||
width: 100%;
|
||||
background: rgba(64, 65, 79, 0.5);
|
||||
border: none;
|
||||
padding: 12px 45px 12px 15px;
|
||||
border-radius: 12px;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.input-area button {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
background: rgba(25, 195, 125, 0.3);
|
||||
border: 1px solid rgba(25, 195, 125, 0.5);
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
color: #19c37d;
|
||||
cursor: pointer;
|
||||
font-family: "Orbitron", monospace;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<body class="relative overflow-hidden flex">
|
||||
<div class="background-animated"></div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div class="sidebar">
|
||||
<button class="new-chat" onclick="createNewSession()">
|
||||
+ New chat
|
||||
+ Novo Chat
|
||||
</button>
|
||||
<button
|
||||
class="voice-toggle"
|
||||
id="voiceToggle"
|
||||
onclick="toggleVoiceMode()"
|
||||
>
|
||||
🎤 Voice Mode
|
||||
🎤 Modo Voz
|
||||
</button>
|
||||
<div class="history" id="history"></div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="main">
|
||||
<header
|
||||
class="glass border-b border-yellow-400/40 relative z-20 flex items-center justify-between px-10 py-6 shadow-2xl"
|
||||
>
|
||||
<div class="flex items-center gap-4">
|
||||
<div
|
||||
class="w-14 h-14 rounded-2xl neon-border flex items-center justify-center relative shine"
|
||||
>
|
||||
<span class="text-3xl font-extrabold neon-text">D</span>
|
||||
</div>
|
||||
<h1 class="text-4xl font-extrabold neon-text">
|
||||
General Bots
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<button
|
||||
id="newChatBtn"
|
||||
class="px-8 py-3 rounded-xl glass neon-border text-yellow-300 font-semibold hover:scale-105 transition-all"
|
||||
>
|
||||
Novo Chat
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<div class="voice-status" id="voiceStatus" style="display: none">
|
||||
<div class="pulse">🎤 Listening... Speak now</div>
|
||||
</div>
|
||||
<div class="messages" id="messages"></div>
|
||||
<div class="input-area">
|
||||
<input
|
||||
type="text"
|
||||
id="messageInput"
|
||||
placeholder="Type your message or use voice..."
|
||||
onkeypress="handleKeyPress(event)"
|
||||
/>
|
||||
<button onclick="sendMessage()">Send</button>
|
||||
<div class="pulse">🎤 Ouvindo... Fale agora</div>
|
||||
</div>
|
||||
|
||||
<main
|
||||
id="messages"
|
||||
class="relative z-10 overflow-y-auto h-[calc(100vh-170px)] px-10 py-8"
|
||||
>
|
||||
<div
|
||||
id="emptyState"
|
||||
class="text-center pt-40 flex flex-col items-center justify-center"
|
||||
>
|
||||
<div
|
||||
class="w-36 h-36 rounded-3xl neon-border flex items-center justify-center shine mb-6"
|
||||
>
|
||||
<span class="text-7xl neon-text font-extrabold">D</span>
|
||||
</div>
|
||||
<h2 class="text-4xl neon-text font-bold">
|
||||
Bem-vindo ao General Bots
|
||||
</h2>
|
||||
<p class="text-blue-200 mt-3 opacity-80 text-lg">
|
||||
Seu assistente de IA avançado
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer
|
||||
class="glass border-t border-yellow-400/30 px-10 py-6 relative z-20 backdrop-blur-lg"
|
||||
>
|
||||
<div class="flex items-center gap-4">
|
||||
<input
|
||||
id="messageInput"
|
||||
type="text"
|
||||
placeholder="Fale com General Bots..."
|
||||
class="flex-1 rounded-2xl px-8 py-4 glass border border-yellow-400/40 text-lg text-white placeholder-yellow-200/40 focus:outline-none focus:border-yellow-300 transition-all"
|
||||
/>
|
||||
<button
|
||||
id="sendBtn"
|
||||
class="rounded-2xl px-10 py-4 neon-border hover:scale-105 transition-all text-yellow-300 font-bold tracking-wide"
|
||||
>
|
||||
Enviar
|
||||
</button>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/livekit-client@latest/dist/livekit-client.js"></script>
|
||||
<script>
|
||||
let ws = null;
|
||||
let currentSessionId = null;
|
||||
|
|
@ -170,6 +397,15 @@
|
|||
let isVoiceMode = false;
|
||||
let mediaRecorder = null;
|
||||
let audioChunks = [];
|
||||
let streamingMessageId = null;
|
||||
|
||||
const messagesDiv = document.getElementById("messages");
|
||||
const input = document.getElementById("messageInput");
|
||||
const sendBtn = document.getElementById("sendBtn");
|
||||
const newChatBtn = document.getElementById("newChatBtn");
|
||||
|
||||
// Initialize
|
||||
createNewSession();
|
||||
|
||||
async function loadSessions() {
|
||||
const response = await fetch("/api/sessions");
|
||||
|
|
@ -223,7 +459,7 @@
|
|||
? "assistant-message"
|
||||
: "voice-message";
|
||||
addMessage(
|
||||
role === "user" ? "You" : "Assistant",
|
||||
role === "user" ? "Você" : "Assistente",
|
||||
content,
|
||||
className,
|
||||
);
|
||||
|
|
@ -240,17 +476,19 @@
|
|||
if (!response.is_complete) {
|
||||
if (!isStreaming) {
|
||||
isStreaming = true;
|
||||
streamingMessageId = "streaming-" + Date.now();
|
||||
addMessage(
|
||||
"Assistant",
|
||||
"assistant",
|
||||
response.content,
|
||||
"assistant-message",
|
||||
true,
|
||||
streamingMessageId,
|
||||
);
|
||||
} else {
|
||||
updateLastMessage(response.content);
|
||||
}
|
||||
} else {
|
||||
isStreaming = false;
|
||||
streamingMessageId = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -260,46 +498,64 @@
|
|||
}
|
||||
|
||||
function addMessage(
|
||||
sender,
|
||||
role,
|
||||
content,
|
||||
className,
|
||||
isStreaming = false,
|
||||
streaming = false,
|
||||
msgId = null,
|
||||
) {
|
||||
const messages = document.getElementById("messages");
|
||||
const messageDiv = document.createElement("div");
|
||||
messageDiv.className = `message ${className}`;
|
||||
messageDiv.id = isStreaming ? "streaming-message" : null;
|
||||
messageDiv.innerHTML = `<strong>${sender}:</strong> ${content}`;
|
||||
messages.appendChild(messageDiv);
|
||||
messages.scrollTop = messages.scrollHeight;
|
||||
const emptyState = document.getElementById("emptyState");
|
||||
if (emptyState) emptyState.remove();
|
||||
|
||||
const msg = document.createElement("div");
|
||||
msg.className = "mb-8";
|
||||
|
||||
if (role === "user") {
|
||||
msg.innerHTML = `<div class="flex justify-end"><div class="glass neon-border rounded-2xl px-6 py-4 max-w-3xl text-lg text-yellow-100 font-semibold shadow-2xl">${content}</div></div>`;
|
||||
} else if (role === "assistant") {
|
||||
msg.innerHTML = `<div class="flex justify-start"><div class="flex gap-4 max-w-3xl"><div class="w-12 h-12 rounded-xl neon-border flex items-center justify-center flex-shrink-0 shine shadow-2xl"><span class="text-2xl neon-text font-extrabold">D</span></div><div class="glass border-2 border-yellow-400/30 rounded-2xl px-6 py-4 flex-1 text-blue-50 font-medium text-lg shadow-2xl" id="${streaming ? msgId : ""}">${streaming ? "" : content}</div></div></div>`;
|
||||
} else {
|
||||
// Voice message
|
||||
msg.innerHTML = `<div class="flex justify-start"><div class="flex gap-4 max-w-3xl"><div class="w-12 h-12 rounded-xl neon-border flex items-center justify-center flex-shrink-0 shine shadow-2xl"><span class="text-2xl neon-text font-extrabold">D</span></div><div class="glass border-2 border-green-400/30 rounded-2xl px-6 py-4 flex-1 text-green-100 font-medium text-lg shadow-2xl">${content}</div></div></div>`;
|
||||
}
|
||||
|
||||
messagesDiv.appendChild(msg);
|
||||
gsap.from(msg, {
|
||||
opacity: 0,
|
||||
y: 30,
|
||||
duration: 0.6,
|
||||
ease: "power3.out",
|
||||
});
|
||||
messagesDiv.scrollTop = messagesDiv.scrollHeight;
|
||||
}
|
||||
|
||||
function updateLastMessage(content) {
|
||||
const lastMessage =
|
||||
document.getElementById("streaming-message");
|
||||
if (lastMessage) {
|
||||
lastMessage.innerHTML = `<strong>Assistant:</strong> ${lastMessage.textContent.replace("Assistant:", "").trim() + content}`;
|
||||
document.getElementById("messages").scrollTop =
|
||||
document.getElementById("messages").scrollHeight;
|
||||
const m = document.getElementById(streamingMessageId);
|
||||
if (m) {
|
||||
m.textContent += content;
|
||||
messagesDiv.scrollTop = messagesDiv.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
function sendMessage() {
|
||||
const input = document.getElementById("messageInput");
|
||||
const message = input.value.trim();
|
||||
|
||||
if (message && ws && ws.readyState === WebSocket.OPEN) {
|
||||
addMessage("You", message, "user-message");
|
||||
ws.send(message);
|
||||
input.value = "";
|
||||
}
|
||||
if (!message || !ws || ws.readyState !== WebSocket.OPEN) return;
|
||||
addMessage("user", message);
|
||||
ws.send(message);
|
||||
input.value = "";
|
||||
anime({
|
||||
targets: sendBtn,
|
||||
scale: [1, 0.85, 1],
|
||||
duration: 300,
|
||||
easing: "easeInOutQuad",
|
||||
});
|
||||
}
|
||||
|
||||
function handleKeyPress(event) {
|
||||
if (event.key === "Enter") {
|
||||
sendMessage();
|
||||
}
|
||||
}
|
||||
sendBtn.onclick = sendMessage;
|
||||
input.addEventListener("keypress", (e) => {
|
||||
if (e.key === "Enter") sendMessage();
|
||||
});
|
||||
|
||||
newChatBtn.onclick = () => createNewSession();
|
||||
|
||||
async function toggleVoiceMode() {
|
||||
isVoiceMode = !isVoiceMode;
|
||||
|
|
@ -307,12 +563,12 @@
|
|||
const voiceStatus = document.getElementById("voiceStatus");
|
||||
|
||||
if (isVoiceMode) {
|
||||
voiceToggle.textContent = "🔴 Stop Voice";
|
||||
voiceToggle.textContent = "🔴 Parar Voz";
|
||||
voiceToggle.classList.add("recording");
|
||||
voiceStatus.style.display = "block";
|
||||
await startVoiceSession();
|
||||
} else {
|
||||
voiceToggle.textContent = "🎤 Voice Mode";
|
||||
voiceToggle.textContent = "🎤 Modo Voz";
|
||||
voiceToggle.classList.remove("recording");
|
||||
voiceStatus.style.display = "none";
|
||||
await stopVoiceSession();
|
||||
|
|
@ -379,11 +635,7 @@
|
|||
try {
|
||||
const parsed = JSON.parse(message);
|
||||
if (parsed.type === "voice_response") {
|
||||
addMessage(
|
||||
"Assistant",
|
||||
parsed.text,
|
||||
"assistant-message",
|
||||
);
|
||||
addMessage("assistant", parsed.text);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Voice data:", message);
|
||||
|
|
@ -449,14 +701,14 @@
|
|||
|
||||
function simulateVoiceTranscription() {
|
||||
const phrases = [
|
||||
"Hello, how can I help you today?",
|
||||
"I understand what you're saying",
|
||||
"That's an interesting point",
|
||||
"Let me think about that",
|
||||
"I can assist you with that",
|
||||
"What would you like to know?",
|
||||
"That sounds great",
|
||||
"I'm listening to your voice",
|
||||
"Olá, como posso ajudá-lo hoje?",
|
||||
"Entendo o que você está dizendo",
|
||||
"Esse é um ponto interessante",
|
||||
"Deixe-me pensar sobre isso",
|
||||
"Posso ajudá-lo com isso",
|
||||
"O que você gostaria de saber?",
|
||||
"Isso parece ótimo",
|
||||
"Estou ouvindo sua voz",
|
||||
];
|
||||
|
||||
const randomPhrase =
|
||||
|
|
@ -475,10 +727,18 @@
|
|||
);
|
||||
}
|
||||
|
||||
addMessage("You", `🎤 ${randomPhrase}`, "voice-message");
|
||||
addMessage("voice", `🎤 ${randomPhrase}`);
|
||||
}
|
||||
|
||||
createNewSession();
|
||||
// Neon text animation
|
||||
gsap.to(".neon-text", {
|
||||
textShadow:
|
||||
"0 0 25px var(--gb-glow),0 0 50px var(--gb-glow),0 0 100px rgba(255,215,0,0.8)",
|
||||
repeat: -1,
|
||||
yoyo: true,
|
||||
duration: 1.8,
|
||||
ease: "power1.inOut",
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Reference in a new issue