Improve chat output and formatting
This commit is contained in:
@@ -614,3 +614,146 @@ body {
|
|||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enhanced Chat Message Formatting */
|
||||||
|
.message-text {
|
||||||
|
line-height: 1.6;
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-text h3,
|
||||||
|
.message-text h4,
|
||||||
|
.message-text h5 {
|
||||||
|
color: inherit;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-text h3 {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
border-bottom: 1px solid rgba(0,0,0,0.1);
|
||||||
|
padding-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-text h4 {
|
||||||
|
font-size: 1.05rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-text h5 {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code formatting */
|
||||||
|
.message-text .code-block {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border: 1px solid #e9ecef;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
padding: 0.75rem;
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
overflow-x: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-text .inline-code {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border: 1px solid #e9ecef;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
padding: 0.125rem 0.25rem;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: #d63384;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* List formatting */
|
||||||
|
.message-text .formatted-list {
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-text .formatted-list li {
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-text ul.formatted-list {
|
||||||
|
list-style-type: disc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-text ol.formatted-list {
|
||||||
|
list-style-type: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-text .bullet-item,
|
||||||
|
.message-text .list-item {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bold and italic text */
|
||||||
|
.message-text strong {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-text em {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Paragraph spacing */
|
||||||
|
.message-text br + br {
|
||||||
|
display: block;
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Special styling for bot messages */
|
||||||
|
.bot-message .message-text .code-block {
|
||||||
|
background-color: #f1f3f4;
|
||||||
|
border-color: #dadce0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bot-message .message-text .inline-code {
|
||||||
|
background-color: #f1f3f4;
|
||||||
|
border-color: #dadce0;
|
||||||
|
color: #1a73e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Special styling for user messages */
|
||||||
|
.user-message .message-text .code-block {
|
||||||
|
background-color: rgba(255,255,255,0.1);
|
||||||
|
border-color: rgba(255,255,255,0.2);
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-message .message-text .inline-code {
|
||||||
|
background-color: rgba(255,255,255,0.1);
|
||||||
|
border-color: rgba(255,255,255,0.2);
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-message .message-text h3,
|
||||||
|
.user-message .message-text h4,
|
||||||
|
.user-message .message-text h5 {
|
||||||
|
color: #ffffff;
|
||||||
|
border-color: rgba(255,255,255,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive adjustments for mobile */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.message-text .code-block {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-text .formatted-list {
|
||||||
|
padding-left: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-text h3,
|
||||||
|
.message-text h4,
|
||||||
|
.message-text h5 {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -94,6 +94,22 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
function addWelcomeMessage() {
|
function addWelcomeMessage() {
|
||||||
const messageDiv = document.createElement('div');
|
const messageDiv = document.createElement('div');
|
||||||
messageDiv.className = 'chat-message bot-message mb-3';
|
messageDiv.className = 'chat-message bot-message mb-3';
|
||||||
|
const welcomeText = `Hello! I'm **EduCat AI**, your study assistant. I can help you with:
|
||||||
|
|
||||||
|
• Questions about your notes and study materials
|
||||||
|
• Study techniques and academic strategies
|
||||||
|
• Explanations of complex concepts
|
||||||
|
• Creating study plans and schedules
|
||||||
|
|
||||||
|
I support **rich formatting** in my responses including:
|
||||||
|
- **Bold text** and *italic text*
|
||||||
|
- \`Code snippets\` and code blocks
|
||||||
|
- Numbered lists and bullet points
|
||||||
|
- Headers and structured content
|
||||||
|
|
||||||
|
How can I assist you today?`;
|
||||||
|
const formattedWelcome = formatMessage(welcomeText, true);
|
||||||
|
|
||||||
messageDiv.innerHTML = `
|
messageDiv.innerHTML = `
|
||||||
<div class="d-flex align-items-start">
|
<div class="d-flex align-items-start">
|
||||||
<div class="avatar bg-primary text-white rounded-circle d-flex align-items-center justify-content-center me-3 flex-shrink-0" style="width: 45px; height: 45px; min-width: 45px;">
|
<div class="avatar bg-primary text-white rounded-circle d-flex align-items-center justify-content-center me-3 flex-shrink-0" style="width: 45px; height: 45px; min-width: 45px;">
|
||||||
@@ -101,7 +117,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
</div>
|
</div>
|
||||||
<div class="message-content flex-grow-1">
|
<div class="message-content flex-grow-1">
|
||||||
<div class="message-bubble bg-light p-3 rounded-3 shadow-sm border">
|
<div class="message-bubble bg-light p-3 rounded-3 shadow-sm border">
|
||||||
<p class="mb-0">Hello! I'm EduCat AI, your study assistant. I can help you with questions about your notes, study techniques, and academic topics. How can I assist you today?</p>
|
<div class="message-text">${formattedWelcome}</div>
|
||||||
</div>
|
</div>
|
||||||
<small class="text-muted d-block mt-1">Just now</small>
|
<small class="text-muted d-block mt-1">Just now</small>
|
||||||
</div>
|
</div>
|
||||||
@@ -125,18 +141,81 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
sendToAI(message);
|
sendToAI(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatMessage(text, isBot = false) {
|
||||||
|
if (!isBot) {
|
||||||
|
// For user messages, just escape HTML and preserve basic formatting
|
||||||
|
return text.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/\n/g, '<br>');
|
||||||
|
}
|
||||||
|
|
||||||
|
// For bot messages, apply rich formatting
|
||||||
|
let formatted = text
|
||||||
|
// Escape HTML first
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>');
|
||||||
|
|
||||||
|
// Convert markdown-style formatting
|
||||||
|
// Bold text **text** or __text__
|
||||||
|
formatted = formatted.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
|
||||||
|
formatted = formatted.replace(/__(.*?)__/g, '<strong>$1</strong>');
|
||||||
|
|
||||||
|
// Italic text *text* or _text_
|
||||||
|
formatted = formatted.replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, '<em>$1</em>');
|
||||||
|
formatted = formatted.replace(/(?<!_)_([^_]+)_(?!_)/g, '<em>$1</em>');
|
||||||
|
|
||||||
|
// Code blocks ```code```
|
||||||
|
formatted = formatted.replace(/```([\s\S]*?)```/g, '<pre class="code-block"><code>$1</code></pre>');
|
||||||
|
|
||||||
|
// Inline code `code`
|
||||||
|
formatted = formatted.replace(/`([^`]+)`/g, '<code class="inline-code">$1</code>');
|
||||||
|
|
||||||
|
// Headers
|
||||||
|
formatted = formatted.replace(/^### (.*$)/gm, '<h5 class="mt-3 mb-2">$1</h5>');
|
||||||
|
formatted = formatted.replace(/^## (.*$)/gm, '<h4 class="mt-3 mb-2">$1</h4>');
|
||||||
|
formatted = formatted.replace(/^# (.*$)/gm, '<h3 class="mt-3 mb-2">$1</h3>');
|
||||||
|
|
||||||
|
// Convert bullet points and numbered lists
|
||||||
|
// Handle bullet points: - item, * item, • item
|
||||||
|
formatted = formatted.replace(/^[\s]*[-*•]\s+(.+)$/gm, '<li class="bullet-item">$1</li>');
|
||||||
|
|
||||||
|
// Handle numbered lists: 1. item, 2. item, etc.
|
||||||
|
formatted = formatted.replace(/^[\s]*\d+\.\s+(.+)$/gm, '<li class="numbered-item">$1</li>');
|
||||||
|
|
||||||
|
// Wrap consecutive list items in proper list containers
|
||||||
|
formatted = formatted.replace(/(<li class="bullet-item">.*?<\/li>)(?:\s*<li class="bullet-item">.*?<\/li>)*/gs, function(match) {
|
||||||
|
return '<ul class="formatted-list">' + match + '</ul>';
|
||||||
|
});
|
||||||
|
|
||||||
|
formatted = formatted.replace(/(<li class="numbered-item">.*?<\/li>)(?:\s*<li class="numbered-item">.*?<\/li>)*/gs, function(match) {
|
||||||
|
return '<ol class="formatted-list">' + match.replace(/class="numbered-item"/g, 'class="list-item"') + '</ol>';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert line breaks to <br> but not inside <pre> or list tags
|
||||||
|
let parts = formatted.split(/(<pre[\s\S]*?<\/pre>|<ul[\s\S]*?<\/ul>|<ol[\s\S]*?<\/ol>)/);
|
||||||
|
for (let i = 0; i < parts.length; i += 2) {
|
||||||
|
parts[i] = parts[i].replace(/\n\s*\n/g, '<br><br>').replace(/\n/g, '<br>');
|
||||||
|
}
|
||||||
|
formatted = parts.join('');
|
||||||
|
|
||||||
|
return formatted;
|
||||||
|
}
|
||||||
|
|
||||||
function addMessageToChat(sender, message, withScroll = true) {
|
function addMessageToChat(sender, message, withScroll = true) {
|
||||||
const messageDiv = document.createElement('div');
|
const messageDiv = document.createElement('div');
|
||||||
messageDiv.className = `chat-message ${sender}-message mb-3`;
|
messageDiv.className = `chat-message ${sender}-message mb-3`;
|
||||||
|
|
||||||
const time = new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
|
const time = new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
|
||||||
|
const formattedMessage = formatMessage(message, sender === 'bot');
|
||||||
|
|
||||||
if (sender === 'user') {
|
if (sender === 'user') {
|
||||||
messageDiv.innerHTML = `
|
messageDiv.innerHTML = `
|
||||||
<div class="d-flex align-items-start justify-content-end">
|
<div class="d-flex align-items-start justify-content-end">
|
||||||
<div class="message-content me-3 flex-grow-1" style="max-width: 70%;">
|
<div class="message-content me-3 flex-grow-1" style="max-width: 70%;">
|
||||||
<div class="message-bubble bg-primary text-white p-3 rounded-3 shadow-sm">
|
<div class="message-bubble bg-primary text-white p-3 rounded-3 shadow-sm">
|
||||||
<p class="mb-0">${message}</p>
|
<div class="message-text">${formattedMessage}</div>
|
||||||
</div>
|
</div>
|
||||||
<small class="text-muted d-block text-end mt-1">${time}</small>
|
<small class="text-muted d-block text-end mt-1">${time}</small>
|
||||||
</div>
|
</div>
|
||||||
@@ -153,7 +232,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
</div>
|
</div>
|
||||||
<div class="message-content flex-grow-1" style="max-width: 70%;">
|
<div class="message-content flex-grow-1" style="max-width: 70%;">
|
||||||
<div class="message-bubble bg-light p-3 rounded-3 shadow-sm border">
|
<div class="message-bubble bg-light p-3 rounded-3 shadow-sm border">
|
||||||
<p class="mb-0">${message}</p>
|
<div class="message-text">${formattedMessage}</div>
|
||||||
</div>
|
</div>
|
||||||
<small class="text-muted d-block mt-1">${time}</small>
|
<small class="text-muted d-block mt-1">${time}</small>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user