|
<!DOCTYPE html> |
|
<html lang="ar" dir="rtl"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Speedy Chat</title> |
|
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet"> |
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> |
|
<style> |
|
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Arabic:wght@100;200;300;400;500;600;700&display=swap'); |
|
@import url('https://fonts.googleapis.com/css2?family=Noto+Kufi+Arabic:wght@100;200;300;400;500;600;700;800;900&display=swap'); |
|
|
|
body { |
|
font-family: 'IBM Plex Sans Arabic', sans-serif; |
|
line-height: 1.6; |
|
letter-spacing: -0.01em; |
|
transition: background-color 0.3s, color 0.3s; |
|
} |
|
|
|
body.light-mode { |
|
background-color: #fafafa; |
|
color: #374151; |
|
} |
|
|
|
body.dark-mode { |
|
background-color: #1a1a1a; |
|
color: #e5e5e5; |
|
} |
|
|
|
.dark-mode header { |
|
background-color: #2d2d2d; |
|
border-color: #404040; |
|
} |
|
|
|
.dark-mode footer { |
|
background-color: #2d2d2d; |
|
border-color: #404040; |
|
} |
|
|
|
.dark-mode .message-input { |
|
background-color: #363636; |
|
border-color: #404040; |
|
color: #e5e5e5; |
|
} |
|
|
|
.dark-mode .style-select { |
|
background-color: #363636; |
|
border-color: #404040; |
|
color: #e5e5e5; |
|
} |
|
|
|
.dark-mode .bot-message { |
|
background-color: #363636; |
|
} |
|
|
|
.message-actions { |
|
display: flex; |
|
gap: 0.5rem; |
|
margin-top: 0.5rem; |
|
} |
|
|
|
.message-action-button { |
|
padding: 0.25rem 0.75rem; |
|
border-radius: 0.375rem; |
|
font-size: 0.875rem; |
|
display: flex; |
|
align-items: center; |
|
gap: 0.25rem; |
|
transition: all 0.2s; |
|
color: #6B7280; |
|
} |
|
|
|
.message-action-button:hover { |
|
background-color: #F3F4F6; |
|
} |
|
|
|
.dark-mode .message-action-button:hover { |
|
background-color: #404040; |
|
} |
|
|
|
.stop-generating { |
|
display: none; |
|
background-color: #EF4444; |
|
color: white; |
|
padding: 0.5rem 1rem; |
|
border-radius: 0.375rem; |
|
font-weight: 500; |
|
transition: all 0.2s; |
|
} |
|
|
|
.stop-generating:hover { |
|
background-color: #DC2626; |
|
} |
|
|
|
|
|
</style> |
|
</head> |
|
<body class="text-lg light-mode"> |
|
|
|
|
|
<main class="pt-24 pb-24"> |
|
<div class="max-w-3xl mx-auto px-4"> |
|
<div class="welcome-text">سبيدي هنا لمساعدتك</div> |
|
<div id="messagesContainer" class="space-y-4"></div> |
|
</div> |
|
</main> |
|
|
|
<footer class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-100 shadow-sm"> |
|
<div class="max-w-3xl mx-auto px-4 py-4"> |
|
<div class="relative"> |
|
<textarea |
|
id="messageInput" |
|
class="message-input w-full border border-gray-200 rounded-lg px-4 py-3 pl-32 pr-4 resize-none text-lg" |
|
rows="1" |
|
placeholder="اكتب رسالتك هنا..." |
|
></textarea> |
|
<div class="absolute bottom-3 left-2 flex items-center space-x-2 rtl:space-x-reverse"> |
|
<button id="sendMessage" class="bg-indigo-500 hover:bg-indigo-600 text-white rounded-full p-2 transition-colors"> |
|
<svg class="w-6 h-6 transform rotate-90" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 10l7-7m0 0l7 7m-7-7v18"></path> |
|
</svg> |
|
</button> |
|
<button id="stopGenerating" class="stop-generating"> |
|
إيقاف التوليد |
|
</button> |
|
|
|
</div> |
|
</div> |
|
</div> |
|
</footer> |
|
|
|
<script> |
|
|
|
|
|
function createUserMessage(text) { |
|
let prefix = ''; |
|
if (currentStyle === 'short') { |
|
prefix = 'اعطني رد باختصار وسرعة: '; |
|
} else if (currentStyle === 'long') { |
|
prefix = 'اعطني رد مفصل وموسع: '; |
|
} |
|
|
|
return ` |
|
<div class="message flex flex-col"> |
|
<div class="flex justify-end"> |
|
<div class="max-w-[80%]"> |
|
<div class="bg-indigo-500 text-white rounded-lg p-4 shadow-sm"> |
|
<p class="text-lg">${text}</p> |
|
</div> |
|
</div> |
|
</div> |
|
<div class="message-actions justify-end"> |
|
<button class="message-action-button"> |
|
<i class="far fa-thumbs-up"></i> |
|
أعجبني |
|
</button> |
|
<button class="message-action-button"> |
|
<i class="far fa-thumbs-down"></i> |
|
لم يعجبني |
|
</button> |
|
</div> |
|
</div> |
|
`; |
|
} |
|
|
|
function createBotMessage(text, messageId) { |
|
return ` |
|
<div class="message flex flex-col"> |
|
<div class="flex justify-start"> |
|
<div class="flex-shrink-0 w-10 h-10 rounded-full overflow-hidden shadow-sm mt-1"> |
|
<img src="https://ufastpro.com/wp-content/uploads/2024/12/3.png" alt="Bot Avatar" class="w-full h-full object-cover"> |
|
</div> |
|
<div class="max-w-[80%] mr-3"> |
|
<div class="bot-message bg-white rounded-lg p-4 shadow-sm"> |
|
<p id="${messageId}" class="text-gray-700"></p> |
|
</div> |
|
</div> |
|
</div> |
|
<div class="message-actions mr-13"> |
|
<button class="message-action-button copy-message"> |
|
<i class="far fa-copy"></i> |
|
نسخ |
|
</button> |
|
<button class="message-action-button regenerate"> |
|
<i class="fas fa-redo"></i> |
|
إعادة التوليد |
|
</button> |
|
</div> |
|
</div> |
|
`; |
|
} |
|
|
|
let isGenerating = false; |
|
const stopGenerating = document.getElementById('stopGenerating'); |
|
|
|
async function sendMessage() { |
|
const message = messageInput.value.trim(); |
|
if (!message || isGenerating) return; |
|
|
|
messageInput.value = ''; |
|
adjustTextareaHeight(); |
|
isGenerating = true; |
|
stopGenerating.style.display = 'block'; |
|
|
|
const messageId = 'msg-' + Date.now(); |
|
let actualMessage = message; |
|
|
|
if (currentStyle === 'short') { |
|
actualMessage = 'اعطني رد باختصار وسرعة: ' + message; |
|
} else if (currentStyle === 'long') { |
|
actualMessage = 'اعطني رد مفصل وموسع: ' + message; |
|
} |
|
|
|
messagesContainer.insertAdjacentHTML('beforeend', createUserMessage(message)); |
|
messagesContainer.insertAdjacentHTML('beforeend', createBotMessage('', messageId)); |
|
scrollToBottom(); |
|
|
|
try { |
|
const response = await fetch(API_URL, { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
body: JSON.stringify({ |
|
message: actualMessage, |
|
history: chatHistory |
|
}) |
|
}); |
|
|
|
const data = await response.json(); |
|
await typeText(messageId, data.response); |
|
|
|
chatHistory.push({ |
|
human: actualMessage, |
|
assistant: data.response |
|
}); |
|
} catch (error) { |
|
document.getElementById(messageId).textContent = 'عذراً، حدث خطأ في المعالجة.'; |
|
} finally { |
|
isGenerating = false; |
|
stopGenerating.style.display = 'none'; |
|
} |
|
scrollToBottom(); |
|
} |
|
|
|
|
|
document.addEventListener('click', function(e) { |
|
if (e.target.closest('.copy-message')) { |
|
const messageText = e.target.closest('.message').querySelector('.bot-message p').textContent; |
|
navigator.clipboard.writeText(messageText); |
|
|
|
} |
|
|
|
if (e.target.closest('.regenerate')) { |
|
const message = chatHistory[chatHistory.length - 1].human; |
|
messageInput.value = message; |
|
sendMessage(); |
|
} |
|
}); |
|
|
|
stopGenerating.addEventListener('click', () => { |
|
isGenerating = false; |
|
stopGenerating.style.display = 'none'; |
|
|
|
}); |
|
|
|
|
|
|
|
function scrollToBottom() { |
|
window.scrollTo({ |
|
top: document.documentElement.scrollHeight, |
|
behavior: 'smooth' |
|
}); |
|
} |
|
|
|
function adjustTextareaHeight() { |
|
messageInput.style.height = 'auto'; |
|
messageInput.style.height = messageInput.scrollHeight + 'px'; |
|
} |
|
|
|
sendButton.addEventListener('click', sendMessage); |
|
messageInput.addEventListener('keypress', (e) => { |
|
if (e.key === 'Enter' && !e.shiftKey) { |
|
e.preventDefault(); |
|
sendMessage(); |
|
} |
|
}); |
|
messageInput.addEventListener('input', adjustTextareaHeight); |
|
clearButton.addEventListener('click', () => { |
|
messagesContainer.innerHTML = ''; |
|
chatHistory = []; |
|
}); |
|
|
|
|
|
const initialMessageId = 'msg-initial'; |
|
messagesContainer.insertAdjacentHTML('beforeend', createBotMessage('', initialMessageId)); |
|
typeText(initialMessageId, 'مرحباً! كيف يمكنني مساعدتك اليوم؟'); |
|
</script> |
|
</body> |
|
</html> |