bugfix speech-to-text and implement avatar and personal greeting
All checks were successful
Deploy FluentGerman.ai / deploy (push) Successful in 53s
All checks were successful
Deploy FluentGerman.ai / deploy (push) Successful in 53s
This commit is contained in:
@@ -14,11 +14,32 @@ function renderMarkdown(text) {
|
||||
return DOMPurify.sanitize(raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date as a friendly relative time string.
|
||||
*/
|
||||
function relativeTime(dateStr) {
|
||||
if (!dateStr) return null;
|
||||
const date = new Date(dateStr);
|
||||
const now = new Date();
|
||||
const diffMs = now - date;
|
||||
const diffMins = Math.floor(diffMs / 60000);
|
||||
const diffHours = Math.floor(diffMs / 3600000);
|
||||
const diffDays = Math.floor(diffMs / 86400000);
|
||||
|
||||
if (diffMins < 1) return 'just now';
|
||||
if (diffMins < 60) return `${diffMins} minute${diffMins !== 1 ? 's' : ''} ago`;
|
||||
if (diffHours < 24) return `${diffHours} hour${diffHours !== 1 ? 's' : ''} ago`;
|
||||
if (diffDays === 1) return 'yesterday';
|
||||
if (diffDays < 30) return `${diffDays} days ago`;
|
||||
return date.toLocaleDateString('en-GB', { day: 'numeric', month: 'short', year: 'numeric' });
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
if (!requireAuth()) return;
|
||||
|
||||
const user = getUser();
|
||||
document.getElementById('user-name').textContent = user?.username || 'User';
|
||||
const displayName = user?.username || 'User';
|
||||
document.getElementById('user-name').textContent = displayName;
|
||||
|
||||
const messagesEl = document.getElementById('chat-messages');
|
||||
const inputEl = document.getElementById('chat-input');
|
||||
@@ -27,7 +48,36 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
let history = [];
|
||||
|
||||
// Init voice
|
||||
// ── Personalised welcome ──────────────────────────────────────────
|
||||
const greetingEl = document.getElementById('welcome-greeting');
|
||||
const subtitleEl = document.getElementById('welcome-subtitle');
|
||||
const metaEl = document.getElementById('welcome-meta');
|
||||
|
||||
// Immediately show the username we already have from localStorage
|
||||
greetingEl.textContent = `Hallo, ${displayName}! 👋`;
|
||||
|
||||
// Fetch dashboard info for latest instruction data
|
||||
try {
|
||||
const resp = await api('/chat/dashboard');
|
||||
if (resp?.ok) {
|
||||
const data = await resp.json();
|
||||
// Use server username (authoritative)
|
||||
greetingEl.textContent = `Hallo, ${data.username}! 👋`;
|
||||
|
||||
if (data.latest_instruction_at) {
|
||||
const ago = relativeTime(data.latest_instruction_at);
|
||||
metaEl.innerHTML = `<span class="meta-dot"></span> Lessons last updated <strong>${ago}</strong>`;
|
||||
metaEl.classList.add('visible');
|
||||
} else {
|
||||
metaEl.textContent = 'No custom lessons configured yet';
|
||||
metaEl.classList.add('visible');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[Chat] Could not fetch dashboard info:', e);
|
||||
}
|
||||
|
||||
// ── Voice ─────────────────────────────────────────────────────────
|
||||
const voice = new VoiceManager();
|
||||
await voice.init();
|
||||
|
||||
@@ -44,7 +94,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
|
||||
voiceBtn.addEventListener('click', () => voice.toggleRecording());
|
||||
|
||||
// Chat
|
||||
// ── Chat ──────────────────────────────────────────────────────────
|
||||
function appendMessage(role, content) {
|
||||
const div = document.createElement('div');
|
||||
div.className = `message message-${role}`;
|
||||
|
||||
Reference in New Issue
Block a user