Files
romfast-website/chatbot_maria.html
2025-08-13 22:47:45 +03:00

842 lines
32 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RomFast - Contact</title>
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
margin: 0;
padding: 0;
color: #333;
background: #444;
}
/* Stiluri pentru butonul mic de generare link */
.link-button-small {
background: transparent !important;
border: none !important;
padding: 0 !important;
margin: 0 0 0 8px !important;
height: 56px !important;
width: 56px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
cursor: pointer !important;
transition: all 0.2s ease !important;
border-radius: 6px !important;
font-size: 18px !important;
color: #3B81F6 !important;
opacity: 0.8 !important;
flex-shrink: 0 !important;
}
.link-button-small:hover {
background-color: rgba(59, 129, 246, 0.1) !important;
opacity: 1 !important;
transform: scale(1.05) !important;
}
.link-button-small:active {
transform: scale(0.95) !important;
}
.link-button-small.success {
color: #10B981 !important;
background-color: rgba(16, 185, 129, 0.1) !important;
}
.toast {
position: fixed;
top: 20px;
right: 20px;
background-color: #10B981;
color: white;
padding: 12px 20px;
border-radius: 6px;
z-index: 10000;
opacity: 0;
transform: translateX(100%);
transition: all 0.3s ease;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
font-size: 14px;
}
.toast.show {
opacity: 1;
transform: translateX(0);
}
.toast.error {
background-color: #EF4444;
}
/* Stiluri pentru mesajele API */
.api-message-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.95);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 9999;
padding: 20px;
box-sizing: border-box;
}
.api-message-box {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
max-width: 600px;
width: 90%;
max-height: 90vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.api-message-header {
display: flex;
align-items: center;
padding: 20px 20px 10px 20px;
border-bottom: 1px solid #eee;
flex-shrink: 0;
}
.api-message-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 15px;
background-color: #1B5B76;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
font-size: 18px;
}
.api-message-title {
font-size: 18px;
font-weight: bold;
color: #333;
}
.api-message-scrollable {
flex: 1;
overflow-y: auto;
padding: 0 20px;
}
.api-message-content {
font-size: 16px;
line-height: 1.6;
color: #333;
white-space: pre-wrap;
word-wrap: break-word;
padding: 15px 0;
}
.api-message-footer {
padding: 20px;
display: flex;
justify-content: flex-end;
border-top: 1px solid #eee;
flex-shrink: 0;
}
.api-message-button {
background-color: #3B81F6;
color: white;
border: none;
border-radius: 4px;
padding: 8px 15px;
font-size: 14px;
cursor: pointer;
transition: background-color 0.2s;
}
.api-message-button:hover {
background-color: #2d6acd;
}
.user-query {
background-color: #f0f0f0;
padding: 10px 15px;
border-radius: 18px;
margin-bottom: 15px;
display: inline-block;
max-width: 100%;
font-size: 15px;
word-wrap: break-word;
}
.api-message-scrollable::-webkit-scrollbar {
width: 8px;
}
.api-message-scrollable::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
.api-message-scrollable::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 4px;
}
.api-message-scrollable::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
</style>
</head>
<body>
<flowise-fullchatbot></flowise-fullchatbot>
<script type="module">
import Chatbot from "https://cdn.jsdelivr.net/npm/flowise-embed/dist/web.js"
// Funcție pentru a obține parametrii din URL
function getUrlParameter(name) {
try {
const urlParams = new URLSearchParams(window.location.search);
const value = urlParams.get(name);
if (value === null) {
return '';
}
return value;
} catch (error) {
console.error("Eroare cu URLSearchParams:", error);
try {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
var results = regex.exec(location.search);
if (results === null) {
return '';
}
let rawValue = results[1];
function safeDecodeURIComponent(str) {
str = str.replace(/\+/g, ' ');
const chunks = str.split('%');
let result = chunks[0];
for (let i = 1; i < chunks.length; i++) {
const chunk = chunks[i];
if (chunk.length >= 2) {
const hexCode = chunk.substring(0, 2);
const rest = chunk.substring(2);
if (/^[0-9A-Fa-f]{2}$/.test(hexCode)) {
try {
result += decodeURIComponent('%' + hexCode) + rest;
} catch (e) {
result += '%' + chunk;
}
} else {
result += '%' + chunk;
}
} else {
result += '%' + chunk;
}
}
return result;
}
const decoded = safeDecodeURIComponent(rawValue);
return decoded;
} catch (fallbackError) {
console.error("Eroare și la fallback sigur:", fallbackError);
return '';
}
}
}
// Obține mesajul inițial din parametrul URL (dacă există)
const initialMessage = getUrlParameter('message');
// Definește prompt-urile inițiale standard
const defaultStarterPrompts = [
'Cum se actualizeaza tokenul eFactura?',
'Cand se completeaza codul de plata pentru declaratia SAFT?',
'Cum se configurează o politică de prețuri? Afișeaza pașii complet',
'Care sunt pasii pentru emiterea unei facturi service auto?',
'Cum se valideaza o comanda service auto?',
'Cum se deschide o comanda service auto?',
'Cum se modifica datele initiale ale unei comenzi service auto (ex: nr. km)?'
];
// Determină dacă să afișeze prompt-urile inițiale sau nu
const starterPrompts = initialMessage ? [] : defaultStarterPrompts;
// Inițializează chatbot-ul
const chatbotInstance = Chatbot.initFull({
chatflowid: "d4911620-07fe-41f8-adb4-f2f52d6ec766",
apiHost: "https://mutual-special-koala.ngrok-free.app",
theme: {
chatWindow: {
showTitle: true,
title: 'Maria ChatBot - Romfast Suport',
titleAvatarSrc: 'https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/svg/google-messages.svg',
showAgentMessages: true,
welcomeMessage: 'Bună! Eu sunt Maria, specialistul dvs. de suport tehnic Romfast. Sunt aici pentru a vă ajuta cu orice întrebări sau probleme tehnice legate de utilizarea sistemului ROA. Cum vă pot ajuta astăzi?',
errorMessage: 'Am o eroare! Revino mai tarziu',
backgroundColor: "#ffffff",
height: 700,
width: 500,
fontSize: 16,
starterPrompts: starterPrompts,
starterPromptFontSize: 15,
clearChatOnReload: true,
botMessage: {
backgroundColor: "#f7f8ff",
textColor: "#303235",
showAvatar: true,
avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png",
},
userMessage: {
backgroundColor: "#3B81F6",
textColor: "#ffffff",
showAvatar: true,
avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/usericon.png",
},
textInput: {
placeholder: 'Scrieți întrebarea dvs.',
backgroundColor: '#ffffff',
textColor: '#303235',
sendButtonColor: '#3B81F6',
maxChars: 2000,
maxCharsWarningMessage: 'Ați depășit limita de caractere. Vă rugăm să introduceți mai puțin de 2000 de caractere.',
autoFocus: true,
sendMessageSound: false,
receiveMessageSound: false,
},
feedback: {
color: '#303235',
},
footer: {
textColor: '#303235',
text: 'Powered by',
company: 'Romfast',
companyLink: 'https://www.romfast.ro',
}
}
}
});
// Funcție pentru a afișa răspunsul API direct în pagină
function displayApiResponse(question, response) {
const container = document.createElement('div');
container.className = 'api-message-container';
const messageBox = document.createElement('div');
messageBox.className = 'api-message-box';
const header = document.createElement('div');
header.className = 'api-message-header';
const avatar = document.createElement('div');
avatar.className = 'api-message-avatar';
avatar.textContent = 'M';
const title = document.createElement('div');
title.className = 'api-message-title';
title.textContent = 'Maria - Asistent Romfast';
header.appendChild(avatar);
header.appendChild(title);
const scrollableArea = document.createElement('div');
scrollableArea.className = 'api-message-scrollable';
const userQuery = document.createElement('div');
userQuery.className = 'user-query';
userQuery.textContent = question;
const content = document.createElement('div');
content.className = 'api-message-content';
content.textContent = response.text || response;
scrollableArea.appendChild(userQuery);
scrollableArea.appendChild(content);
const footer = document.createElement('div');
footer.className = 'api-message-footer';
const button = document.createElement('button');
button.className = 'api-message-button';
button.textContent = 'Continuă conversația';
button.onclick = function() {
container.style.opacity = '0';
setTimeout(() => {
container.remove();
}, 300);
const chatHistory = [{
message: question,
type: 'userMessage'
}, {
message: response.text || response,
type: 'apiMessage'
}];
try {
localStorage.setItem('flowise-chatbot-history', JSON.stringify(chatHistory));
} catch (e) {
console.error('Eroare la salvarea istoricului în localStorage:', e);
}
const url = new URL(window.location.href);
url.searchParams.delete('message');
window.location.href = url.toString();
};
footer.appendChild(button);
messageBox.appendChild(header);
messageBox.appendChild(scrollableArea);
messageBox.appendChild(footer);
container.appendChild(messageBox);
document.body.appendChild(container);
setTimeout(() => {
container.style.opacity = '1';
}, 10);
}
// Funcție pentru a trimite mesajul direct prin API Flowise
async function sendMessageViaAPI(message) {
try {
const apiHost = "https://mutual-special-koala.ngrok-free.app";
const chatflowId = "d4911620-07fe-41f8-adb4-f2f52d6ec766";
const requestBody = {
question: message,
history: []
};
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 30000);
const response = await fetch(`${apiHost}/api/v1/prediction/${chatflowId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody),
signal: controller.signal
});
clearTimeout(timeoutId);
if (response.ok) {
const data = await response.json();
displayApiResponse(message, data);
return data;
} else {
console.error("Eroare la apelul API:", response.status);
displayApiResponse(message, `Ne pare rău, a apărut o eroare în procesarea cererii dumneavoastră (cod: ${response.status}). Vă rugăm să încercați din nou mai târziu.`);
return null;
}
} catch (error) {
console.error("Eroare la trimiterea mesajului prin API:", error);
let errorMessage = "Ne pare rău, a apărut o eroare în conectarea la serviciile noastre. Vă rugăm să verificați conexiunea la internet și să încercați din nou.";
if (error.name === 'AbortError') {
errorMessage = "Request-ul a fost întrerupt din cauza timeout-ului. Vă rugăm să încercați din nou.";
}
displayApiResponse(message, errorMessage);
return null;
}
}
// Funcție pentru a afișa toast-ul
function showToast(message, type = 'success') {
const toast = document.createElement('div');
toast.className = 'toast';
toast.textContent = message;
if (type === 'error') {
toast.classList.add('error');
}
document.body.appendChild(toast);
setTimeout(() => {
toast.classList.add('show');
}, 100);
setTimeout(() => {
toast.classList.remove('show');
setTimeout(() => {
if (document.body.contains(toast)) {
document.body.removeChild(toast);
}
}, 300);
}, 3000);
}
// Funcție pentru a găsi textarea-ul chatbot-ului cu MutationObserver
function waitForChatbotInput() {
return new Promise((resolve) => {
// Mai multe selectori posibili
const selectors = [
'textarea',
'input[type="text"]',
'input',
'textarea[placeholder*="Scrieți întrebarea"]',
'textarea[placeholder*="Type your message"]',
'.text-input',
'[contenteditable="true"]',
'[class*="text-input"]',
'[class*="textarea"]',
'[class*="input"]'
];
// Funcție pentru a căuta în shadow DOM
function searchInShadowDOM() {
const chatbotElement = document.querySelector('flowise-fullchatbot');
if (chatbotElement && chatbotElement.shadowRoot) {
for (const selector of selectors) {
const elements = chatbotElement.shadowRoot.querySelectorAll(selector);
for (const element of elements) {
if (element.offsetParent !== null && !element.disabled && !element.readOnly) {
return element;
}
}
}
}
return null;
}
// Încearcă să găsească textarea-ul imediat
for (const selector of selectors) {
const elements = document.querySelectorAll(selector);
for (const element of elements) {
if (element.offsetParent !== null && !element.disabled && !element.readOnly) {
resolve(element);
return;
}
}
}
// Caută în shadow DOM
const shadowElement = searchInShadowDOM();
if (shadowElement) {
resolve(shadowElement);
return;
}
// Dacă nu îl găsește, folosește MutationObserver
const observer = new MutationObserver((mutations) => {
// Caută în DOM normal
for (const selector of selectors) {
const elements = document.querySelectorAll(selector);
for (const element of elements) {
if (element.offsetParent !== null && !element.disabled && !element.readOnly) {
observer.disconnect();
resolve(element);
return;
}
}
}
// Caută în shadow DOM
const shadowElement = searchInShadowDOM();
if (shadowElement) {
observer.disconnect();
resolve(shadowElement);
return;
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
// Timeout după 15 secunde
setTimeout(() => {
observer.disconnect();
console.error('❌ Nu s-a găsit textarea-ul chatbot-ului în 15 secunde');
resolve(null);
}, 15000);
});
}
// Variabilă globală pentru a urmări dacă butonul a fost adăugat
let linkButtonAdded = false;
let intervalId = null;
// Funcție pentru a adăuga butonul mic lângă butonul de send
async function addLinkButtonToInput() {
// Dacă butonul a fost deja adăugat, nu mai continua
if (linkButtonAdded) {
return;
}
const textarea = await waitForChatbotInput();
if (!textarea) {
console.error('❌ Nu s-a găsit textarea-ul chatbot-ului');
return;
}
// Găsește containerul cu textarea
let inputContainer = textarea.parentElement;
let attempts = 0;
// Caută containerul potrivit mergând în sus prin DOM
while (inputContainer && attempts < 10) {
if (inputContainer.classList.contains('flex') ||
inputContainer.style.display === 'flex' ||
inputContainer.querySelector('button')) {
break;
}
inputContainer = inputContainer.parentElement;
attempts++;
}
if (!inputContainer) {
console.error('❌ Nu s-a găsit containerul input-ului');
return;
}
// Verifică dacă butonul există deja
if (inputContainer.querySelector('.link-button-small')) {
linkButtonAdded = true;
// Oprește intervalul dacă rulează
if (intervalId) {
clearInterval(intervalId);
intervalId = null;
}
return;
}
// Creează butonul mic
const linkButton = document.createElement('button');
linkButton.className = 'link-button-small';
linkButton.innerHTML = '🔗';
linkButton.title = 'Generează link pentru această întrebare';
linkButton.type = 'button';
// Adaugă stiluri inline pentru a fi sigur că se aplică în Shadow DOM
linkButton.style.cssText = `
background: transparent !important;
border: none !important;
padding: 0 !important;
margin: 0 0 0 8px !important;
height: 56px !important;
width: 56px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
cursor: pointer !important;
transition: all 0.2s ease !important;
border-radius: 6px !important;
font-size: 18px !important;
color: #3B81F6 !important;
opacity: 0.8 !important;
flex-shrink: 0 !important;
z-index: 1000 !important;
`;
// Adaugă event listener pentru hover
linkButton.addEventListener('mouseenter', () => {
linkButton.style.backgroundColor = 'rgba(59, 129, 246, 0.1)';
linkButton.style.opacity = '1';
linkButton.style.transform = 'scale(1.05)';
});
linkButton.addEventListener('mouseleave', () => {
linkButton.style.backgroundColor = 'transparent';
linkButton.style.opacity = '0.8';
linkButton.style.transform = 'scale(1)';
});
// Adaugă event listener pentru click
linkButton.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
generateLinkFromInput(textarea, linkButton);
});
// Adaugă butonul în container
inputContainer.appendChild(linkButton);
console.log('✅ Butonul de link a fost adăugat cu succes');
// Marchează că butonul a fost adăugat
linkButtonAdded = true;
// Oprește intervalul dacă rulează
if (intervalId) {
clearInterval(intervalId);
intervalId = null;
}
// Verifică dacă butonul este vizibil (debugging final)
setTimeout(() => {
const rect = linkButton.getBoundingClientRect();
if (rect.width > 0 && rect.height > 0) {
console.log('✅ Butonul este vizibil și funcțional');
} else {
console.warn('⚠️ Butonul a fost adăugat dar nu este vizibil');
}
}, 100);
}
// Funcție pentru generarea linkului din input
function generateLinkFromInput(textarea, button) {
const message = textarea.value.trim();
if (!message) {
showToast('Vă rugăm să introduceți o întrebare în casuta de chat mai întâi!', 'error');
return;
}
// Generează URL-ul
const url = `${window.location.origin}${window.location.pathname}?message=${encodeURIComponent(message)}`;
// Feedback vizual pe buton
const originalHTML = button.innerHTML;
button.innerHTML = '✓';
button.classList.add('success');
// Copiază în clipboard
navigator.clipboard.writeText(url).then(() => {
showToast('Link-ul a fost copiat în clipboard!');
// Resetează butonul după 2 secunde
setTimeout(() => {
button.innerHTML = originalHTML;
button.classList.remove('success');
}, 2000);
}).catch(() => {
// Fallback pentru browsere mai vechi
const textArea = document.createElement('textarea');
textArea.value = url;
textArea.style.position = 'fixed';
textArea.style.opacity = '0';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
document.execCommand('copy');
showToast('Link-ul a fost copiat în clipboard!');
} catch (err) {
showToast('Eroare la copierea linkului. Vă rugăm să încercați din nou.', 'error');
}
document.body.removeChild(textArea);
// Resetează butonul după 2 secunde
setTimeout(() => {
button.innerHTML = originalHTML;
button.classList.remove('success');
}, 2000);
});
}
// Inițializează adăugarea butonului când pagina se încarcă
window.addEventListener('load', () => {
if (linkButtonAdded) return;
// Încearcă imediat
addLinkButtonToInput();
// Încearcă din nou doar dacă butonul nu a fost adăugat
setTimeout(() => {
if (!linkButtonAdded) {
addLinkButtonToInput();
}
}, 2000);
setTimeout(() => {
if (!linkButtonAdded) {
addLinkButtonToInput();
}
}, 5000);
setTimeout(() => {
if (!linkButtonAdded) {
addLinkButtonToInput();
}
}, 10000);
});
// Adaugă și un event listener pentru DOMContentLoaded
document.addEventListener('DOMContentLoaded', () => {
if (linkButtonAdded) return;
setTimeout(() => {
if (!linkButtonAdded) {
addLinkButtonToInput();
}
}, 1000);
});
// Verifică periodic dacă butonul există și îl adaugă dacă lipsește
intervalId = setInterval(() => {
// Oprește intervalul dacă butonul a fost adăugat
if (linkButtonAdded) {
clearInterval(intervalId);
intervalId = null;
return;
}
// Verifică dacă butonul există
const existingButton = document.querySelector('.link-button-small');
if (!existingButton) {
// Verifică dacă textarea-ul există
const textarea = document.querySelector('textarea') ||
document.querySelector('input[type="text"]');
if (textarea && textarea.offsetParent !== null) {
addLinkButtonToInput();
}
} else {
// Dacă butonul există, marchează că a fost adăugat și oprește intervalul
linkButtonAdded = true;
clearInterval(intervalId);
intervalId = null;
}
}, 3000); // Verifică la fiecare 3 secunde
// Dacă există un mesaj inițial, trimite-l direct prin API
if (initialMessage) {
if (initialMessage.trim() !== '') {
const chatbotElement = document.querySelector('flowise-fullchatbot');
if (chatbotElement) {
chatbotElement.style.display = 'none';
}
sendMessageViaAPI(initialMessage);
} else {
console.error("❌ Mesajul initial este gol după decodare");
}
}
</script>
</body>
</html>