| {% extends "layouts/dashboard.html" %} |
|
|
| {% block title %}Chat: {{ session.title }}{% endblock %} |
|
|
| {% block dashboard_content %} |
|
|
| {# βββ Chat Container βββββββββββββββββββββββββββββββββββββββββββββββ #} |
| <div class="flex flex-col h-[calc(100vh-12rem)]"> |
|
|
| {# βββ Chat Header ββββββββββββββββββββββββββββββββββββββββββββββββ #} |
| <div class="flex items-center justify-between pb-4 border-b border-[--border] mb-4"> |
| <div class="flex items-center gap-3"> |
| <a href="{{ url('intelligence:chat-sessions') }}" class="p-2 rounded-lg text-[--muted-foreground] hover:bg-[--muted] hover:text-[--foreground] transition-colors"> |
| <svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/></svg> |
| </a> |
| <div> |
| <h2 class="text-lg font-bold text-[--foreground]">{{ session.title or 'Chat' }}</h2> |
| <p class="text-xs text-[--muted-foreground]"> |
| Started {{ session.created_at|date("M d, Y H:i") }} |
| {% if session.model %} Β· {{ session.model.name }}{% endif %} |
| </p> |
| </div> |
| </div> |
| <a href="{{ url('intelligence:chat-start') }}" class="inline-flex items-center gap-1.5 rounded-lg px-3 py-2 text-xs font-medium text-[--muted-foreground] border border-[--border] hover:bg-[--muted] hover:text-[--foreground] transition-colors"> |
| <svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/></svg> |
| New Chat |
| </a> |
| </div> |
|
|
| {# βββ Messages Area ββββββββββββββββββββββββββββββββββββββββββββββ #} |
| <div id="chat-messages" class="flex-1 overflow-y-auto space-y-4 pr-2 scroll-smooth"> |
| {% if messages %} |
| {% for msg in messages %} |
| {% if msg.role == 'user' %} |
| <div class="flex justify-end"> |
| <div class="max-w-[70%] rounded-2xl rounded-tr-md bg-[--primary] px-4 py-3 text-sm text-[--primary-foreground] shadow-sm"> |
| {{ msg.content }} |
| </div> |
| </div> |
| {% elif msg.role == 'assistant' %} |
| <div class="flex justify-start"> |
| <div class="flex gap-3 max-w-[70%]"> |
| <div class="flex-shrink-0 mt-1"> |
| <div class="h-7 w-7 rounded-lg bg-gradient-to-br from-purple-500 to-indigo-600 flex items-center justify-center shadow-sm"> |
| <svg class="h-4 w-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/></svg> |
| </div> |
| </div> |
| <div class="rounded-2xl rounded-tl-md bg-[--card] border border-[--border] px-4 py-3 text-sm text-[--foreground] shadow-sm"> |
| {{ msg.content }} |
| </div> |
| </div> |
| </div> |
| {% elif msg.role == 'system' %} |
| <div class="flex justify-center"> |
| <span class="text-xs text-[--muted-foreground] bg-[--muted]/30 px-3 py-1 rounded-full">{{ msg.content }}</span> |
| </div> |
| {% endif %} |
| {% endfor %} |
| {% else %} |
| <div class="flex flex-col items-center justify-center h-full text-center"> |
| <div class="h-16 w-16 rounded-2xl bg-gradient-to-br from-purple-500 to-indigo-600 flex items-center justify-center shadow-xl shadow-purple-500/20 mb-6"> |
| <svg class="h-8 w-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"/></svg> |
| </div> |
| <p class="text-lg font-semibold text-[--foreground] mb-1">Start the conversation</p> |
| <p class="text-sm text-[--muted-foreground]">Type a message below to chat with the AI assistant.</p> |
| </div> |
| {% endif %} |
| </div> |
|
|
| {# βββ Input Area βββββββββββββββββββββββββββββββββββββββββββββββββ #} |
| <div class="pt-4 border-t border-[--border] mt-4"> |
| <form hx-post="{{ url('intelligence:chat-message-create', session_id=session.pk) }}" |
| hx-target="#chat-messages" |
| hx-swap="beforeend scroll:#chat-messages:bottom" |
| class="flex items-end gap-3"> |
| <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}"> |
| <div class="flex-1"> |
| <textarea id="chat-input" name="content" rows="1" required |
| placeholder="Type a message..." |
| class="block w-full resize-none rounded-xl bg-[--card] px-4 py-3 text-sm text-[--foreground] border border-[--border] placeholder:text-[--muted-foreground] focus:outline-none focus:ring-2 focus:ring-[--primary]/50 focus:border-[--primary]/50" |
| onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();this.form.requestSubmit()}" |
| oninput="this.style.height='auto';this.style.height=this.scrollHeight+'px'"></textarea> |
| </div> |
| <button type="submit" class="flex-shrink-0 inline-flex items-center justify-center h-11 w-11 rounded-xl bg-[--primary] text-[--primary-foreground] shadow-sm hover:bg-[--primary]/90 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[--primary]"> |
| <svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"/></svg> |
| </button> |
| </form> |
| </div> |
|
|
| </div> |
|
|
| <script> |
| |
| (function() { |
| const el = document.getElementById('chat-messages'); |
| if (el) el.scrollTop = el.scrollHeight; |
| })(); |
| |
| |
| document.body.addEventListener('htmx:afterRequest', function(e) { |
| const input = document.getElementById('chat-input'); |
| if (input) { input.value = ''; input.style.height = 'auto'; } |
| }); |
| </script> |
|
|
| {% endblock %} |
|
|