Spaces:
Running
Running
| <html><head><base href="https://WhatsApp/ai.com"> | |
| <meta charset="UTF-8"> | |
| <title>AI-Powered WhatsApp Chat with Image Upload</title> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | |
| <meta name="theme-color" content="#075e54"> | |
| <meta name="apple-mobile-web-app-capable" content="yes"> | |
| <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> | |
| <style> | |
| /* Les styles restent identiques */ | |
| body, html { | |
| margin: 0; | |
| padding: 0; | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; | |
| background-color: #e5ddd5; | |
| height: 100%; | |
| overflow: hidden; | |
| } | |
| #chat-container { | |
| max-width: 100%; | |
| height: 100%; | |
| margin: 0 auto; | |
| background-color: #fff; | |
| display: flex; | |
| flex-direction: column; | |
| box-shadow: 0 1px 1px 0 rgba(0,0,0,.06), 0 2px 5px 0 rgba(0,0,0,.2); | |
| } | |
| #chat-header { | |
| background-color: #075e54; | |
| color: #fff; | |
| padding: 10px; | |
| display: flex; | |
| align-items: center; | |
| } | |
| #chat-header img { | |
| width: 40px; | |
| height: 40px; | |
| border-radius: 50%; | |
| margin-right: 10px; | |
| } | |
| #chat-header h1 { | |
| margin: 0; | |
| font-size: 16px; | |
| } | |
| #chat-messages { | |
| flex: 1; | |
| overflow-y: auto; | |
| padding: 20px; | |
| background-image: url('https://web.whatsapp.com/img/bg-chat-tile-dark_a4be512e7195b6b733d9110b408f075d.png'); | |
| background-repeat: repeat; | |
| } | |
| .message { | |
| max-width: 80%; | |
| margin-bottom: 10px; | |
| padding: 8px 12px; | |
| border-radius: 7.5px; | |
| position: relative; | |
| word-wrap: break-word; | |
| overflow-wrap: break-word; | |
| } | |
| .user-message { | |
| background-color: #dcf8c6; | |
| align-self: flex-end; | |
| margin-left: auto; | |
| } | |
| .ai-message { | |
| background-color: #fff; | |
| align-self: flex-start; | |
| } | |
| #chat-input { | |
| display: flex; | |
| padding: 10px; | |
| background-color: #f0f0f0; | |
| } | |
| #user-input { | |
| flex: 1; | |
| border: none; | |
| padding: 10px; | |
| border-radius: 20px; | |
| margin-right: 10px; | |
| font-size: 14px; | |
| } | |
| #send-button, #file-button { | |
| background-color: #075e54; | |
| color: #fff; | |
| border: none; | |
| padding: 10px; | |
| border-radius: 50%; | |
| cursor: pointer; | |
| margin-left: 5px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| #send-button svg, #file-button svg { | |
| width: 24px; | |
| height: 24px; | |
| fill: #fff; | |
| } | |
| #file-input { | |
| display: none; | |
| } | |
| .message img { | |
| max-width: 100%; | |
| height: auto; | |
| border-radius: 7.5px; | |
| margin-top: 5px; | |
| } | |
| .typing-indicator { | |
| padding: 8px 12px; | |
| background-color: #fff; | |
| border-radius: 7.5px; | |
| margin-bottom: 10px; | |
| display: none; | |
| } | |
| .typing-indicator span { | |
| display: inline-block; | |
| width: 8px; | |
| height: 8px; | |
| background-color: #90a4ae; | |
| border-radius: 50%; | |
| margin-right: 5px; | |
| animation: typing 1s infinite; | |
| } | |
| @keyframes typing { | |
| 0%, 100% { transform: translateY(0); } | |
| 50% { transform: translateY(-5px); } | |
| } | |
| @media (min-width: 768px) { | |
| #chat-container { | |
| max-width: 600px; | |
| } | |
| } | |
| /* New styles for appointments and history */ | |
| .appointment-card { | |
| background: #fff; | |
| border-radius: 10px; | |
| padding: 15px; | |
| margin: 10px 0; | |
| box-shadow: 0 2px 5px rgba(0,0,0,0.1); | |
| } | |
| .history-button { | |
| display: none; /* Hide the history button */ | |
| } | |
| .history-panel { | |
| position: fixed; | |
| right: -300px; /* Keep it offscreen by default */ | |
| top: 0; | |
| width: 300px; | |
| height: 100%; | |
| background: white; | |
| box-shadow: -2px 0 5px rgba(0,0,0,0.2); | |
| transition: right 0.3s ease; | |
| z-index: 1000; | |
| padding: 20px; | |
| display: none; /* Hide it completely */ | |
| } | |
| .history-panel.active { | |
| right: 0; | |
| display: block; /* Show only when active */ | |
| } | |
| /* Ajout de styles pour le support des emojis */ | |
| .emoji { | |
| font-family: "Segoe UI Emoji", "Noto Color Emoji", "Apple Color Emoji", "Segoe UI Symbol", sans-serif; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="chat-container"> | |
| <div id="chat-header"> | |
| <img src="https://cdn-icons-png.flaticon.com/512/4712/4712109.png" alt="Logo zone - corporate stylized icon with square background" style="width: 40px; height: 40px; object-fit: cover; border-radius: 5px;"> | |
| <h1> | |
| ASSISTANT AI +226 56888879 | |
| <span style="display: inline-block; margin-left: 5px; background-color: #0099ff; color: white; font-size: 0.6em; padding: 2px 5px; border-radius: 50%; vertical-align: middle; transform: translateY(-0.5mm);" title="Assistant IA Vérifié">✓</span> | |
| </h1> | |
| <button class="history-button" id="history-button"> | |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="white"> | |
| <path d="M13 3c-4.97 0-9 4.03-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42C8.27 19.99 10.51 21 13 21c4.97 0 9-4.03 9-9s-4.03-9-9-9zm-1 5v5l4.25 2.52.77-1.28-3.52-2.09V8z"></path> | |
| </svg> | |
| </button> | |
| </div> | |
| <div id="chat-messages"> | |
| <div class="typing-indicator" id="typing-indicator"> | |
| <span></span><span></span><span></span> | |
| </div> | |
| </div> | |
| <div id="chat-input"> | |
| <input type="text" id="user-input" placeholder="Écrivez votre message"> | |
| <button id="file-button" title="Joindre une image"> | |
| <svg viewBox="0 0 24 24"> | |
| <path d="M16.5 6v11.5c0 2.21-1.79 4-4 4s-4-1.79-4-4V5a2.5 2.5 0 0 1 5 0v10.5c0 .55-.45 1-1 1s-1-.45-1-1V6H10v9.5a2.5 2.5 0 0 0 5 0V5c0-2.21-1.79-4-4-4S7 2.79 7 5v12.5c0 3.04 2.46 5.5 5.5 5.5s5.5-2.46 5.5-5.5V6h-1.5z"></path> | |
| </svg> | |
| </button> | |
| <input type="file" id="file-input" accept="image/*"> | |
| <button id="send-button" title="Envoyer"> | |
| <svg viewBox="0 0 24 24"> | |
| <path d="M1.101 21.757 23.8 12.028 1.101 2.3l.011 7.912 13.623 1.816-13.623 1.817-.011 7.912z"></path> | |
| </svg> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="history-panel" id="history-panel"> | |
| <h2>Historique des conversations</h2> | |
| <div id="conversation-history"></div> | |
| </div> | |
| <script> | |
| const chatMessages = document.getElementById('chat-messages'); | |
| const userInput = document.getElementById('user-input'); | |
| const sendButton = document.getElementById('send-button'); | |
| const fileButton = document.getElementById('file-button'); | |
| const fileInput = document.getElementById('file-input'); | |
| const typingIndicator = document.getElementById('typing-indicator'); | |
| const historyButton = document.getElementById('history-button'); | |
| const historyPanel = document.getElementById('history-panel'); | |
| const BACKEND_URL = 'http://your-backend-url/api'; | |
| // Store conversation history | |
| let conversationHistory = []; | |
| // Welcome messages | |
| const welcomeMessages = [ | |
| "Bonjour! 👋 Je suis votre assistant virtuel. Comment puis-je vous aider aujourd'hui?", | |
| "Je peux vous aider à prendre des rendez-vous, répondre à vos questions, et plus encore!", | |
| "N'hésitez pas à partager des images ou à me poser des questions." | |
| ]; | |
| function saveToHistory(message, isUser) { | |
| const timestamp = new Date().toISOString(); | |
| conversationHistory.push({ | |
| message, | |
| isUser, | |
| timestamp | |
| }); | |
| localStorage.setItem('chatHistory', JSON.stringify(conversationHistory)); | |
| updateHistoryPanel(); | |
| } | |
| function updateHistoryPanel() { | |
| const historyContainer = document.getElementById('conversation-history'); | |
| historyContainer.innerHTML = ''; | |
| conversationHistory.forEach(item => { | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.classList.add('history-message'); | |
| const date = new Date(item.timestamp).toLocaleString(); | |
| messageDiv.innerHTML = ` | |
| <small>${date}</small><br> | |
| <strong>${item.isUser ? 'Vous' : 'Assistant'}</strong>: ${item.message} | |
| `; | |
| historyContainer.appendChild(messageDiv); | |
| }); | |
| } | |
| historyButton.addEventListener('click', () => { | |
| historyPanel.classList.toggle('active'); | |
| }); | |
| function addMessage(content, isUser, imageData = null) { | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.classList.add('message', isUser ? 'user-message' : 'ai-message'); | |
| if (imageData) { | |
| const img = document.createElement('img'); | |
| img.src = imageData; | |
| img.alt = 'Image envoyée'; | |
| messageDiv.appendChild(img); | |
| } else { | |
| messageDiv.textContent = content; | |
| } | |
| chatMessages.appendChild(messageDiv); | |
| chatMessages.scrollTop = chatMessages.scrollHeight; | |
| // Save to history | |
| saveToHistory(imageData ? '[Image]' : content, isUser); | |
| } | |
| // Load history from localStorage | |
| function loadHistory() { | |
| const savedHistory = localStorage.getItem('chatHistory'); | |
| if (savedHistory) { | |
| conversationHistory = JSON.parse(savedHistory); | |
| updateHistoryPanel(); | |
| } | |
| } | |
| // Initialize | |
| window.onload = () => { | |
| loadHistory(); | |
| // Display welcome messages with delay | |
| welcomeMessages.forEach((message, index) => { | |
| setTimeout(() => { | |
| addMessage(message, false); | |
| }, index * 1000); | |
| }); | |
| }; | |
| async function sendMessageToBackend(message, imageData = null) { | |
| try { | |
| showTypingIndicator(); | |
| const formData = new FormData(); | |
| // Encode le message avant l'envoi | |
| formData.append('message', encodeURIComponent(message)); | |
| if (imageData) { | |
| formData.append('image', imageData); | |
| } | |
| const response = await fetch(`${BACKEND_URL}/chat`, { | |
| method: 'POST', | |
| body: formData | |
| }); | |
| if (!response.ok) { | |
| throw new Error('Erreur réseau'); | |
| } | |
| const data = await response.json(); | |
| hideTypingIndicator(); | |
| if (data.response) { | |
| // Décode la réponse du serveur | |
| addMessage(decodeURIComponent(data.response), false); | |
| } | |
| } catch (error) { | |
| console.error('Erreur:', error); | |
| hideTypingIndicator(); | |
| addMessage("Désolé, une erreur s'est produite. Veuillez réessayer.", false); | |
| } | |
| } | |
| async function sendMessage() { | |
| const userMessage = userInput.value.trim(); | |
| if (!userMessage) return; | |
| addMessage(userMessage, true); | |
| userInput.value = ''; | |
| await sendMessageToBackend(userMessage); | |
| } | |
| function handleImageUpload(file) { | |
| if (file) { | |
| const reader = new FileReader(); | |
| reader.onload = async function(e) { | |
| addMessage('', true, e.target.result); | |
| await sendMessageToBackend('', file); | |
| }; | |
| reader.readAsDataURL(file); | |
| } | |
| } | |
| // Event Listeners | |
| sendButton.addEventListener('click', sendMessage); | |
| userInput.addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); | |
| sendMessage(); | |
| } | |
| }); | |
| fileButton.addEventListener('click', () => fileInput.click()); | |
| fileInput.addEventListener('change', (event) => { | |
| handleImageUpload(event.target.files[0]); | |
| }); | |
| // Gestion du drag and drop | |
| chatMessages.addEventListener('dragover', (e) => { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| }); | |
| chatMessages.addEventListener('drop', (e) => { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| const file = e.dataTransfer.files[0]; | |
| if (file && file.type.startsWith('image/')) { | |
| handleImageUpload(file); | |
| } | |
| }); | |
| // Fonction pour encoder correctement les caractères spéciaux | |
| function encodeMessage(message) { | |
| return encodeURIComponent(message); | |
| } | |
| // Fonction pour décoder les caractères spéciaux | |
| function decodeMessage(message) { | |
| return decodeURIComponent(message); | |
| } | |
| function showTypingIndicator() { | |
| typingIndicator.style.display = 'block'; | |
| chatMessages.scrollTop = chatMessages.scrollHeight; | |
| } | |
| function hideTypingIndicator() { | |
| typingIndicator.style.display = 'none'; | |
| } | |
| </script> | |
| </body></html> | |