<!
DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Brenion - Interface Rápida</title>
<link href="[Link]
family=Inter:wght@300;400;600;700&display=swap" rel="stylesheet">
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', sans-serif;
background: linear-gradient(to right, #e0eafc, #cfdef3);
display: flex;
justify-content: center;
padding: 50px 0;
font-size: 18px;
}
.container {
width: 95%;
max-width: 1050px;
}
h1 {
text-align: center;
margin-bottom: 25px;
font-size: 2.4em;
color: #333;
text-shadow: 1px 1px 2px rgba(0,0,0,0.15);
}
.status {
text-align: center;
margin-bottom: 20px;
color: #666;
font-style: italic;
font-size: 1.1em;
}
.session-bar {
display: flex;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.session-button {
padding: 8px 14px;
border-radius: 12px;
border: none;
cursor: pointer;
background: #ddd;
font-size: 1em;
font-weight: 500;
}
.[Link] {
background: #2196F3;
color: white;
}
.chat-container {
background-color: #ffffffcc;
border-radius: 20px;
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
padding: 25px;
height: 550px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 15px;
scroll-behavior: smooth;
font-size: 1.1em;
line-height: 1.75;
}
.message {
padding: 15px 20px;
border-radius: 18px;
max-width: 80%;
word-wrap: break-word;
animation: fadeIn 0.3s ease-in;
white-space: pre-wrap;
}
.user-message {
align-self: flex-end;
background: linear-gradient(135deg, #6dd5ed, #2193b0);
color: white;
font-weight: 600;
box-shadow: 0 4px 10px rgba(33,147,176,0.3);
}
.bot-message {
align-self: flex-start;
background: #f0f0f0;
color: #333;
box-shadow: 0 4px 10px rgba(0,0,0,0.05);
font-weight: 500;
}
.typing {
font-style: italic;
color: #999;
font-size: 1em;
}
.input-area {
display: flex;
gap: 15px;
margin-top: 25px;
flex-wrap: wrap;
align-items: center;
}
#message-input {
flex-grow: 1;
padding: 15px 20px;
border-radius: 25px;
border: 1px solid #ddd;
font-size: 1.1em;
transition: all 0.2s;
}
#message-input:focus {
outline: none;
border-color: #2196F3;
box-shadow: 0 0 10px rgba(33,150,243,0.3);
}
button {
padding: 15px 25px;
border-radius: 25px;
border: none;
cursor: pointer;
font-weight: bold;
font-size: 1.1em;
transition: all 0.2s;
}
#send-button {
background-color: #2196F3;
color: white;
}
#send-button:hover {
background-color: #0b7dda;
}
#clear-button {
background-color: #f44336;
color: white;
}
#clear-button:hover {
background-color: #d32f2f;
}
input[type="file"] {
display: none;
}
#add-button {
background: #2196F3;
color: white;
font-size: 1.6em;
width: 55px;
height: 55px;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
}
#add-button:hover {
background: #0b7dda;
}
#add-menu {
display: none;
position: absolute;
top: 60px;
left: 0;
background: white;
border: 1px solid #ddd;
border-radius: 12px;
box-shadow: 0 4px 15px rgba(0,0,0,0.12);
padding: 10px;
min-width: 230px;
z-index: 10;
font-size: 1.05em;
}
#add-menu label {
display: block;
padding: 8px 12px;
cursor: pointer;
border-radius: 10px;
transition: all 0.2s;
}
#add-menu label:hover {
background: #f5f5f5;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(5px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
</head>
<body>
<div class="container">
<div style="display:flex; justify-content:flex-end; margin-bottom:10px;
gap:10px;">
<button id="toggle-theme">Modo Escuro</button>
<button id="open-settings">Configurações</button>
</div>
<div id="settings-modal" style="display:none; position:fixed; top:0;
left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); justify-
content:center; align-items:center;">
<div style="background:#fff; padding:20px; border-radius:15px; max-
width:400px; width:90%;">
<h2>Configurações</h2>
<label for="nickname-input">Seu apelido:</label>
<input type="text" id="nickname-input" placeholder="Digite seu
apelido" style="width:100%; padding:10px; margin-top:5px; border-radius:10px;
border:1px solid #ddd;">
<div style="margin-top:15px; display:flex; justify-content:flex-
end; gap:10px;">
<button id="save-settings">Salvar</button>
<button id="close-settings">Cancelar</button>
</div>
<small style="color:#666;">Evite palavras ofensivas.</small>
</div>
</div>
<h1>Brenion - Assistente de IA</h1>
<div class="status" id="status">Conectando ao servidor...</div>
<div class="session-bar" id="session-bar"></div>
<div class="chat-container" id="chat-container">
<div class="message bot-message">Olá! Eu sou o Brenion, seu assistente
de IA local. Como posso ajudar?</div>
</div>
<div class="input-area">
<input type="text" id="message-input" placeholder="Digite sua mensagem
aqui..." disabled>
<div style="position:relative; display:inline-block;">
<button id="add-button">+</button>
<div id="add-menu">
<label>
Adicionar imagem e reconhecer
<input type="file" id="image-input" accept="image/*">
</label>
</div>
</div>
<button id="send-button" disabled>Enviar</button>
<button id="clear-button" disabled>Limpar</button>
</div>
</div>
<script>
const chatContainer = [Link]('chat-container');
const messageInput = [Link]('message-input');
const sendButton = [Link]('send-button');
const clearButton = [Link]('clear-button');
const statusElement = [Link]('status');
const sessionBar = [Link]('session-bar');
let sessionId = [Link]().toString(36).substring(2, 15);
let typingIndicator = null;
let sessions = [sessionId];
let darkMode = false;
let nickname = "Você";
let selectedImageBase64 = null;
function addMessage(text, isUser) {
const div = [Link]('div');
[Link] = `message ${isUser ? 'user-message' : 'bot-message'}`;
[Link] = [Link](/\n/g, '<br>');
if (isUser)
[Link] = `<strong>${nickname}:</strong> ` + [Link];
if (darkMode) {
if (isUser) {
[Link] = 'linear-gradient(135deg, #3498db,
#2980b9)';
[Link] = 'white';
} else {
[Link] = '#555555cc';
[Link] = '#eee';
}
}
[Link](div);
[Link] = [Link];
}
function showTypingIndicator() {
if (!typingIndicator) {
typingIndicator = [Link]('div');
[Link] = 'message bot-message typing';
[Link] = 'Brenion está digitando...';
[Link](typingIndicator);
[Link] = [Link];
}
}
function hideTypingIndicator() {
if (typingIndicator) {
[Link](typingIndicator);
typingIndicator = null;
}
}
function renderSessions() {
[Link] = '';
[Link](s => {
const btn = [Link]('button');
[Link] = s;
[Link] = 'session-button';
if (s === sessionId) [Link]('active');
[Link] = () => {
sessionId = s;
loadSession(s);
};
[Link](btn);
});
}
async function loadSession(sid) {
const res = await
fetch(`[Link]
if ([Link]) {
const data = await [Link]();
[Link] = '';
[Link](msg => {
addMessage([Link], [Link] === 'user');
});
} else {
[Link] = '<div class="message bot-message">Nenhum
histórico encontrado.</div>';
}
renderSessions();
}
function sendMessage() {
const message = [Link]();
if (!message && !selectedImageBase64) return;
let finalMessage = message;
if (selectedImageBase64)
finalMessage += '\n[Imagem incluída]';
addMessage(finalMessage, true);
showTypingIndicator();
[Link] = 'Enviando...';
[Link] = 'blue';
[Link]([Link]({
message: message,
image_base64: selectedImageBase64,
session_id: sessionId,
use_persistent_memory: true
}));
[Link] = '';
selectedImageBase64 = null;
[Link]('image-input').value = '';
}
[Link]('click', () => {
[Link] = '<div class="message bot-message">Olá! Eu sou
o Brenion, seu assistente de IA local. Como posso ajudar?</div>';
fetch(`[Link] {
method: 'DELETE'
});
});
[Link]('click', sendMessage);
[Link]('keypress', e => {
if ([Link] === 'Enter') sendMessage();
});
let socket = new WebSocket("[Link]
[Link] = () => {
[Link] = false;
[Link] = false;
[Link] = false;
[Link] = 'Conectado ao servidor via WebSocket';
[Link] = 'green';
renderSessions();
};
[Link] = (event) => {
const data = [Link]([Link]);
if ([Link])
hideTypingIndicator();
else {
if (!typingIndicator)
showTypingIndicator();
if (![Link]) {
[Link] = [Link]('div');
[Link] = 'message bot-message
typing';
[Link] = '';
[Link]([Link]);
}
[Link] += [Link](/\n/g,
'<br>');
[Link] = [Link];
}
};
[Link]('toggle-theme').addEventListener('click', () => {
darkMode = !darkMode;
[Link] = darkMode ?
'linear-gradient(to right, #2c3e50, #34495e)' :
'linear-gradient(to right, #e0eafc, #cfdef3)';
[Link]('.user-message').forEach(msg => {
[Link] = darkMode ?
'linear-gradient(135deg, #3498db, #2980b9)' :
'linear-gradient(135deg, #6dd5ed, #2193b0)';
[Link] = 'white';
});
[Link]('.bot-message').forEach(msg => {
[Link] = darkMode ? '#555555cc' : '#ffffffcc';
[Link] = darkMode ? '#eee' : '#333';
});
});
const settingsModal = [Link]('settings-modal');
[Link]('open-settings').addEventListener('click', () => {
[Link] = 'flex';
});
[Link]('close-settings').addEventListener('click', () => {
[Link] = 'none';
});
[Link]('save-settings').addEventListener('click', () => {
const value = [Link]('nickname-input').[Link]();
if ([Link] > 0 && !/[^a-zA-Z0-9À-ú\s]/.test(value)) {
nickname = value;
[Link] = 'none';
addMessage(`Apelido definido como "${nickname}"`, false);
} else {
alert("Apelido inválido. Use apenas letras e números, sem palavras
ofensivas.");
}
});
const addButton = [Link]('add-button');
const addMenu = [Link]('add-menu');
const imageInputNew = [Link]('image-input');
[Link]('click', () => {
[Link] = [Link] === 'none' ? 'block' :
'none';
});
[Link]('change', () => {
if ([Link]) {
const file = [Link][0];
const reader = new FileReader();
[Link] = function() {
selectedImageBase64 = [Link](',')[1];
};
[Link](file);
} else {
selectedImageBase64 = null;
}
});
[Link]('click', (e) => {
if ( && [Link] !== addButton) {
[Link] = 'none';
}
});
</script>
</body>
</html>