Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Modern Chat Widget</title>
- <!-- <link rel="stylesheet" href="styles.css"> -->
- </head>
- <body>
- <!-- Chat Container -->
- <div id="chat-container">
- <div id="chat-header">
- <h2>Chat</h2>
- <button id="close-chat">✕</button>
- </div>
- <div id="chat-messages"></div>
- <div id="chat-input-container">
- <input type="text" id="chat-input" placeholder="Type a message..." />
- <button id="send-button">Send</button>
- </div>
- </div>
- <!-- Expand Chat Button -->
- <button id="expand-chat">
- <svg fill="#ffffff" height="24px" width="24px" viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg">
- <path d="M30,1.5c-16.542,0-30,12.112-30,27c0,5.205,1.647,10.246,4.768,14.604c-0.591,6.537-2.175,11.39-4.475,13.689
- c-0.304,0.304-0.38,0.769-0.188,1.153C0.276,58.289,0.625,58.5,1,58.5c0.046,0,0.093-0.003,0.14-0.01
- c0.405-0.057,9.813-1.412,16.617-5.338C21.622,54.711,25.738,55.5,30,55.5c16.542,0,30-12.112,30-27S46.542,1.5,30,1.5z" />
- </svg>
- </button>
- <!-- Code Snippet Template -->
- <template id="code-snippet-template">
- <div class="code-snippet">
- <button class="copy-button">Copy</button>
- <pre><code></code></pre>
- </div>
- </template>
- <!-- Header and Bold Template -->
- <template id="header-template">
- <strong class="header"></strong>
- </template>
- <template id="bold-black-template">
- <span class="bold-black"></span>
- </template>
- <script>
- document.addEventListener('DOMContentLoaded', () => {
- const chatContainer = document.getElementById('chat-container');
- const chatMessages = document.getElementById('chat-messages');
- const chatInput = document.getElementById('chat-input');
- const chatForm = document.getElementById('chat-form');
- const sendButton = document.getElementById('send-button');
- const expandChatButton = document.getElementById('expand-chat');
- const closeChatButton = document.getElementById('close-chat');
- let lastMessage = '';
- expandChatButton.addEventListener('click', () => {
- chatContainer.classList.add('expanded');
- expandChatButton.classList.add('hidden');
- });
- closeChatButton.addEventListener('click', () => {
- chatContainer.classList.remove('expanded');
- expandChatButton.classList.remove('hidden');
- });
- document.addEventListener('click', (e) => {
- if (e.target.classList.contains('copy-button')) {
- const codeSnippet = e.target.closest('.code-snippet');
- const codeElement = codeSnippet.querySelector('code');
- if (codeElement) {
- const code = codeElement.textContent; // Get the text
- navigator.clipboard.writeText(code).then(() => {
- alert('Code copied to clipboard!');
- }).catch(() => {
- alert('Failed to copy code to clipboard.');
- });
- } else {
- console.error('Code element not found!');
- }
- }
- });
- sendButton.addEventListener('click', async () => {
- const message = chatInput.value.trim();
- if (message) {
- lastMessage = message;
- addMessageToChat('user', message);
- chatInput.value = '';
- addTypingAnimation();
- const MAX_RETRIES = 3; // Maximum number of retries
- let retryCount = 0; // Retry counter
- let timeoutReached = false;
- const showRetryButtons = () => {
- removeTypingAnimation();
- const messageElement = document.createElement('div');
- messageElement.className = 'message bot';
- messageElement.innerHTML = `
- <p>Čas vypršel. Zkusit znovu nebo smazat chat?</p>
- <button id="retry-button">Zkusit znovu</button>
- <button id="clear-button">Smazat</button>
- `;
- chatMessages.appendChild(messageElement);
- chatMessages.scrollTop = chatMessages.scrollHeight;
- document.getElementById('retry-button').addEventListener('click', () => {
- messageElement.remove();
- retryMessage();
- });
- document.getElementById('clear-button').addEventListener('click', () => {
- chatMessages.innerHTML = '';
- });
- };
- const timeoutId = setTimeout(() => {
- timeoutReached = true;
- showRetryButtons();
- }, 20000);
- const warningTimeoutId = setTimeout(() => {
- if (!timeoutReached) {
- addMessageToChat('bot', 'Prosím počkejte, generace zprávy zabrala déle než obvykle.');
- }
- }, 15000);
- while (retryCount < MAX_RETRIES) {
- try {
- const response = await fetch('https://aiceskekraje.vercel.app/chat', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ message }),
- });
- if (timeoutReached) return;
- clearTimeout(timeoutId);
- clearTimeout(warningTimeoutId);
- removeTypingAnimation();
- if (response.ok) {
- const data = await response.json();
- addMessageToChat('bot', data.response);
- return; // Exit on success
- } else {
- console.warn(`Retrying... Attempt ${retryCount + 1}`);
- retryCount++;
- }
- } catch (error) {
- console.error(`Error sending message: ${error}`);
- retryCount++;
- if (retryCount >= MAX_RETRIES) {
- removeTypingAnimation();
- addMessageToChat(
- 'bot',
- 'Došlo k chybě při odesílání zprávy. Prosím zkuste to znovu.'
- );
- }
- }
- }
- }
- });
- function addMessageToChat(role, content) {
- const messageElement = document.createElement('div');
- messageElement.className = `message ${role}`;
- const parsedContent = parseMessageContent(content);
- messageElement.appendChild(parsedContent);
- chatMessages.appendChild(messageElement);
- chatMessages.scrollTop = chatMessages.scrollHeight;
- }
- function parseMessageContent(content) {
- const messageFragment = document.createDocumentFragment();
- // Regex patterns
- const codePattern = /```([\s\S]*?)```/g; // Matches ```...```
- const headerPattern = /##(.+?)##/g; // Matches ###...###
- const boldPattern = /\*\*(.+?)\*\*/g; // Matches ***...***
- let lastIndex = 0;
- // Replace code blocks
- let match;
- while ((match = codePattern.exec(content)) !== null) {
- // Append preceding text
- if (lastIndex < match.index) {
- const text = content.substring(lastIndex, match.index);
- messageFragment.appendChild(document.createTextNode(text));
- }
- // Create a code snippet
- const codeSnippet = document.getElementById('code-snippet-template').content.cloneNode(true);
- codeSnippet.querySelector('code').textContent = match[1]; // Add code content
- messageFragment.appendChild(codeSnippet);
- // Attach copy functionality to the new snippet
- // setTimeout(() => attachCopyFunctionality(), 0); // Ensure DOM updates before attaching
- lastIndex = codePattern.lastIndex;
- }
- // Append remaining content after code blocks
- if (lastIndex < content.length) {
- content = content.substring(lastIndex);
- // Replace headers
- content = content.replace(headerPattern, (_, headerText) => {
- const headerElement = document.getElementById('header-template').content.cloneNode(true);
- headerElement.querySelector('.header').textContent = headerText.trim();
- messageFragment.appendChild(headerElement);
- return '';
- });
- // Replace bold-black text
- content = content.replace(boldPattern, (_, boldText) => {
- const boldElement = document.getElementById('bold-black-template').content.cloneNode(true);
- boldElement.querySelector('.bold-black').textContent = boldText.trim();
- messageFragment.appendChild(boldElement);
- return '';
- });
- // Add any remaining plain text
- if (content.trim()) {
- messageFragment.appendChild(document.createTextNode(content));
- }
- }
- return messageFragment;
- }
- function delay(ms) {
- return new Promise(resolve => setTimeout(resolve, ms));
- }
- async function addTypingAnimation() {
- const typingElement = document.createElement('div');
- typingElement.className = 'message bot typing';
- chatMessages.appendChild(typingElement);
- chatMessages.scrollTop = chatMessages.scrollHeight;
- let keepTyping = true;
- const animateTyping = async () => {
- while (keepTyping) {
- typingElement.textContent = '.';
- await delay(500);
- typingElement.textContent = '..';
- await delay(500);
- typingElement.textContent = '...';
- await delay(500);
- }
- };
- animateTyping();
- typingElement.cleanup = () => {
- keepTyping = false;
- typingElement.remove();
- };
- }
- function removeTypingAnimation() {
- const typingElement = chatMessages.querySelector('.typing');
- if (typingElement && typeof typingElement.cleanup === 'function') {
- typingElement.cleanup();
- }
- }
- function retryMessage() {
- chatInput.value = lastMessage;
- sendButton.click();
- }
- });
- </script>
- <style>
- body {
- font-family: 'Arial', sans-serif;
- background-color: #f9f9f9;
- margin: 0;
- padding: 0;
- }
- .code-snippet {
- position: relative;
- border: 1px solid #ddd;
- background-color: #f8f8f8;
- border-radius: 5px;
- margin: 10px 0;
- padding: 10px;
- overflow: hidden;
- }
- #close-chat {
- position: absolute;
- top: 10px;
- right: 10px;
- background-color: #ffffff;
- color: rgb(0, 0, 0);
- border: none;
- border-radius: 3px;
- padding: 5px 10px;
- font-size: 12px;
- cursor: pointer;
- z-index: 10;
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
- }
- .code-snippet pre {
- margin: 0;
- padding: 10px;
- overflow-x: auto;
- background: transparent;
- }
- .copy-button {
- position: absolute;
- top: 10px;
- right: 10px;
- background-color: #007bff;
- color: white;
- border: none;
- border-radius: 3px;
- padding: 5px 10px;
- font-size: 12px;
- cursor: pointer;
- z-index: 10;
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
- }
- .copy-button:hover {
- background-color: #0056b3;
- }
- #chat-container {
- position: fixed;
- bottom: 20px;
- right: 20px;
- width: 350px;
- height: 500px;
- background-color: #ffffff;
- border-radius: 10px;
- box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
- display: none;
- flex-direction: column;
- overflow: hidden;
- transition: all 0.3s ease;
- z-index: 1000;
- }
- #chat-container.expanded {
- display: flex;
- }
- #chat-header {
- background-color: #007bff;
- color: white;
- padding: 15px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- font-size: 16px;
- }
- #chat-messages {
- flex: 1;
- padding: 10px;
- overflow-y: auto;
- background-color: #f7f7f7;
- }
- .message {
- margin-bottom: 10px;
- padding: 10px;
- border-radius: 15px;
- max-width: 70%;
- word-wrap: break-word;
- }
- .message.user {
- background-color: #007bff;
- color: white;
- align-self: flex-end;
- }
- .message.bot {
- background-color: #e5e5ea;
- color: black;
- align-self: flex-start;
- }
- #chat-input-container {
- display: flex;
- padding: 10px;
- border-top: 1px solid #ddd;
- background-color: #ffffff;
- }
- #chat-input {
- flex-grow: 1;
- padding: 10px;
- border: 1px solid #ccc;
- border-radius: 5px;
- font-size: 14px;
- }
- #send-button {
- margin-left: 10px;
- padding: 10px 15px;
- background-color: #007bff;
- color: white;
- border: none;
- border-radius: 5px;
- font-size: 14px;
- cursor: pointer;
- }
- #expand-chat {
- position: fixed;
- bottom: 20px;
- right: 20px;
- width: 60px;
- height: 60px;
- background-color: #007bff;
- color: white;
- border: none;
- border-radius: 50%;
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
- display: flex;
- justify-content: center;
- align-items: center;
- cursor: pointer;
- z-index: 1000;
- }
- #expand-chat svg {
- width: 24px;
- height: 24px;
- fill: white;
- }
- .hidden {
- display: none;
- }
- #expand-chat.hidden {
- display: none !important;
- }
- .message.bot.typing {
- font-style: italic;
- color: gray;
- }
- </style>
- </body>
- </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement