78 lines
2.4 KiB
HTML

{% extends "base.html" %}
{% block title %}AI Coach{% endblock %}
{% block content %}
<h1>AI Coach</h1>
<div class="chat-messages" id="chat-messages">
{% for m in messages %}
<div class="chat-message {{ m.role }}">
<small>{{ m.role }} · {{ m.created_at[:10] if m.created_at else '' }}</small>
<p>{{ m.content }}</p>
</div>
{% endfor %}
</div>
<form class="chat-input" id="chat-form" onsubmit="sendMessage(event)">
<input type="text" id="chat-input" placeholder="Ask your coach..." required autocomplete="off">
<button type="submit">Send</button>
</form>
<script>
function sendMessage(event) {
event.preventDefault();
const input = document.getElementById('chat-input');
const messages = document.getElementById('chat-messages');
const text = input.value;
if (!text.trim()) return;
const userDiv = document.createElement('div');
userDiv.className = 'chat-message user';
userDiv.innerHTML = `<small>user</small><p>${text}</p>`;
messages.appendChild(userDiv);
const assistantDiv = document.createElement('div');
assistantDiv.className = 'chat-message assistant';
assistantDiv.innerHTML = '<small>assistant</small><p><em>Thinking...</em></p>';
messages.appendChild(assistantDiv);
messages.scrollTop = messages.scrollHeight;
input.disabled = true;
const formData = new FormData();
formData.append('message', text);
fetch('/chat', {
method: 'POST',
body: formData,
}).then(async response => {
const reader = response.body.getReader();
const decoder = new TextDecoder();
const p = assistantDiv.querySelector('p');
p.innerHTML = '';
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (line.startsWith('data: ')) {
p.innerHTML += line.slice(6);
}
}
messages.scrollTop = messages.scrollHeight;
}
input.disabled = false;
input.value = '';
input.focus();
}).catch(() => {
assistantDiv.querySelector('p').innerHTML = 'Error connecting to coach.';
input.disabled = false;
});
}
</script>
{% endblock %}