159 lines
5.8 KiB
HTML
159 lines
5.8 KiB
HTML
{% extends 'portal/base_portal.html' %}
|
|
{% load static %}
|
|
{% block title %}AI Chat - IXG Buyer Portal{% endblock %}
|
|
{% block content %}
|
|
|
|
<div class="page-header d-flex justify-content-between align-items-center">
|
|
<h2>AI Assistant</h2>
|
|
<div>
|
|
<select id="agent-select" class="form-select form-select-sm d-inline-block" style="width:auto;">
|
|
{% for a in agents %}
|
|
<option value="{{ a.id }}"{% if a.is_default %} selected{% endif %}>{{ a.name }}{% if a.is_default %} (default){% endif %}</option>
|
|
{% empty %}
|
|
<option value="">No agents configured</option>
|
|
{% endfor %}
|
|
</select>
|
|
<button class="btn btn-sm btn-outline-secondary" onclick="clearChat()">New Chat</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-8">
|
|
<div class="stat-card d-flex flex-column" style="height: calc(100vh - 260px);">
|
|
<div id="chat-messages" class="flex-grow-1 overflow-auto mb-3" style="min-height: 300px;">
|
|
<div class="text-center text-muted py-5" id="welcome-msg">
|
|
<i class="bi bi-robot fs-1"></i>
|
|
<p class="mt-2">Select an agent and start a conversation.</p>
|
|
</div>
|
|
</div>
|
|
<form id="chat-form" class="d-flex gap-2">
|
|
<input type="text" id="chat-input" class="form-control" placeholder="Type your message..." autofocus>
|
|
<button type="submit" class="btn btn-primary"><i class="bi bi-send"></i></button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="stat-card" style="height: calc(100vh - 260px); overflow-y: auto;">
|
|
<h6 class="mb-3">Chat Sessions</h6>
|
|
<div id="session-list">
|
|
<p class="text-muted small">No previous sessions</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
<script>
|
|
var currentSessionId = "";
|
|
var currentAgentId = document.getElementById("agent-select").value;
|
|
|
|
document.getElementById("agent-select").addEventListener("change", function() {
|
|
currentAgentId = this.value;
|
|
});
|
|
|
|
async function loadSessions() {
|
|
try {
|
|
var resp = await fetch("/api/ai-interactions/sessions/");
|
|
var sessions = await resp.json();
|
|
var container = document.getElementById("session-list");
|
|
if (sessions.length === 0) {
|
|
container.innerHTML = '<p class="text-muted small">No previous sessions</p>';
|
|
return;
|
|
}
|
|
container.innerHTML = "<ul class="list-unstyled mb-0">" +
|
|
sessions.map(function(s) { return "<li class="border-bottom py-1"><a href="#" onclick="loadSession('" + s + "');return false;" class="text-decoration-none small">" + s.substring(0, 8) + "...</a></li>"; }).join("") +
|
|
"</ul>";
|
|
} catch(e) {
|
|
console.log("Sessions unavailable:", e);
|
|
}
|
|
}
|
|
|
|
async function loadSession(sessionId) {
|
|
currentSessionId = sessionId;
|
|
try {
|
|
var resp = await fetch("/api/ai-interactions/?session_id=" + sessionId);
|
|
var msgs = await resp.json();
|
|
var container = document.getElementById("chat-messages");
|
|
container.innerHTML = "";
|
|
document.getElementById("welcome-msg").style.display = "none";
|
|
msgs.forEach(function(m) {
|
|
addMessage(m.message_role, m.message_content);
|
|
});
|
|
container.scrollTop = container.scrollHeight;
|
|
} catch(e) {
|
|
console.log("Session load error:", e);
|
|
}
|
|
}
|
|
|
|
function addMessage(role, content) {
|
|
var container = document.getElementById("chat-messages");
|
|
document.getElementById("welcome-msg").style.display = "none";
|
|
var div = document.createElement("div");
|
|
div.className = "mb-3 " + (role === "user" ? "text-end" : "");
|
|
var bubble = document.createElement("div");
|
|
bubble.className = "d-inline-block p-3 rounded-3 " +
|
|
(role === "user" ? "bg-primary text-white" : "bg-light");
|
|
bubble.style.maxWidth = "80%";
|
|
bubble.style.textAlign = "left";
|
|
if (role === "assistant") {
|
|
bubble.innerHTML = marked.parse(content);
|
|
} else {
|
|
bubble.textContent = content;
|
|
}
|
|
div.appendChild(bubble);
|
|
container.appendChild(div);
|
|
container.scrollTop = container.scrollHeight;
|
|
}
|
|
|
|
document.getElementById("chat-form").addEventListener("submit", async function(e) {
|
|
e.preventDefault();
|
|
var input = document.getElementById("chat-input");
|
|
var message = input.value.trim();
|
|
if (!message || !currentAgentId) return;
|
|
input.value = "";
|
|
addMessage("user", message);
|
|
|
|
var historyDivs = document.querySelectorAll("#chat-messages > div");
|
|
var history = [];
|
|
historyDivs.forEach(function(d) {
|
|
var bubble = d.querySelector(".d-inline-block");
|
|
if (!bubble) return;
|
|
var role = d.classList.contains("text-end") ? "user" : "assistant";
|
|
history.push({ role: role, content: bubble.textContent });
|
|
});
|
|
|
|
try {
|
|
var resp = await fetch("/api/ai-interactions/chat/", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ agent_id: parseInt(currentAgentId), message: message, session_id: currentSessionId, history: history.slice(-20) }),
|
|
});
|
|
var data = await resp.json();
|
|
if (data.session_id) currentSessionId = data.session_id;
|
|
if (data.response) {
|
|
addMessage("assistant", data.response);
|
|
} else if (data.error) {
|
|
addMessage("assistant", "Error: " + data.error);
|
|
}
|
|
} catch(e) {
|
|
addMessage("assistant", "Connection error. Please try again.");
|
|
}
|
|
loadSessions();
|
|
});
|
|
|
|
function clearChat() {
|
|
currentSessionId = "";
|
|
document.getElementById("chat-messages").innerHTML = '<div class="text-center text-muted py-5" id="welcome-msg"><i class="bi bi-robot fs-1"></i><p class="mt-2">Select an agent and start a conversation.</p></div>';
|
|
document.getElementById("session-list").innerHTML = '<p class="text-muted small">No previous sessions</p>';
|
|
loadSessions();
|
|
}
|
|
|
|
loadSessions();
|
|
</script>
|
|
|
|
<style>
|
|
#chat-messages { scroll-behavior: smooth; }
|
|
#chat-messages .bg-light { background: #f0fdf4 !important; border: 1px solid #d1fae5; }
|
|
#chat-messages .bg-primary { background: #065f46 !important; }
|
|
</style>
|
|
{% endblock %}
|