mirror of
https://github.com/kjanat/livegraphs-django.git
synced 2026-01-16 12:12:10 +01:00
Initial commit
This commit is contained in:
130
dashboard_project/templates/dashboard/chat_session_detail.html
Normal file
130
dashboard_project/templates/dashboard/chat_session_detail.html
Normal file
@ -0,0 +1,130 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Chat Session {{ session.session_id }} | Chat Analytics{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div
|
||||
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
|
||||
>
|
||||
<h1 class="h2">Chat Session: {{ session.session_id }}</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<a
|
||||
href="{% url 'data_source_detail' session.data_source.id %}"
|
||||
class="btn btn-sm btn-outline-secondary"
|
||||
>
|
||||
<i class="fas fa-arrow-left"></i> Back to Data Source
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Session Information</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<p><strong>Session ID:</strong> {{ session.session_id }}</p>
|
||||
<p><strong>Start Time:</strong> {{ session.start_time|date:"F d, Y H:i" }}</p>
|
||||
<p><strong>End Time:</strong> {{ session.end_time|date:"F d, Y H:i" }}</p>
|
||||
<p><strong>IP Address:</strong> {{ session.ip_address|default:"N/A" }}</p>
|
||||
<p><strong>Country:</strong> {{ session.country|default:"N/A" }}</p>
|
||||
<p><strong>Language:</strong> {{ session.language|default:"N/A" }}</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p><strong>Messages Sent:</strong> {{ session.messages_sent }}</p>
|
||||
<p>
|
||||
<strong>Average Response Time:</strong>
|
||||
{{ session.avg_response_time|floatformat:2 }}s
|
||||
</p>
|
||||
<p><strong>Tokens:</strong> {{ session.tokens }}</p>
|
||||
<p><strong>Token Cost:</strong> €{{ session.tokens_eur|floatformat:2 }}</p>
|
||||
<p><strong>Category:</strong> {{ session.category|default:"N/A" }}</p>
|
||||
<p>
|
||||
<strong>Sentiment:</strong>
|
||||
{% if session.sentiment %}
|
||||
{% if 'positive' in session.sentiment|lower %}
|
||||
<span class="badge bg-success">{{ session.sentiment }}</span>
|
||||
{% elif 'negative' in session.sentiment|lower %}
|
||||
<span class="badge bg-danger">{{ session.sentiment }}</span>
|
||||
{% elif 'neutral' in session.sentiment|lower %}
|
||||
<span class="badge bg-warning">{{ session.sentiment }}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ session.sentiment }}</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="text-muted">N/A</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-3">
|
||||
<div class="col-12">
|
||||
<p class="mb-2"><strong>Initial Message:</strong></p>
|
||||
<div class="card bg-light">
|
||||
<div class="card-body">
|
||||
<p class="mb-0">{{ session.initial_msg|default:"N/A" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Additional Info</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>
|
||||
<strong>Escalated:</strong> {% if session.escalated %}
|
||||
<span class="badge bg-danger">Yes</span>
|
||||
{% else %}
|
||||
<span class="badge bg-success">No</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
<p>
|
||||
<strong>Forwarded to HR:</strong> {% if session.forwarded_hr %}
|
||||
<span class="badge bg-danger">Yes</span>
|
||||
{% else %}
|
||||
<span class="badge bg-success">No</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
<p><strong>User Rating:</strong> {{ session.user_rating|default:"N/A" }}</p>
|
||||
<hr />
|
||||
<p>
|
||||
<strong>Data Source:</strong>
|
||||
<a href="{% url 'data_source_detail' session.data_source.id %}"
|
||||
>{{ session.data_source.name }}</a
|
||||
>
|
||||
</p>
|
||||
<p><strong>Company:</strong> {{ session.data_source.company.name }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Full Transcript</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if session.full_transcript %}
|
||||
<div class="chat-transcript" style="max-height: 500px; overflow-y: auto;">
|
||||
<pre style="white-space: pre-wrap; font-family: inherit;">
|
||||
{{ session.full_transcript }}</pre
|
||||
>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-center text-muted">No transcript available.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
286
dashboard_project/templates/dashboard/dashboard.html
Normal file
286
dashboard_project/templates/dashboard/dashboard.html
Normal file
@ -0,0 +1,286 @@
|
||||
<!-- templates/dashboard/dashboard.html -->
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}Dashboard | Chat Analytics{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div
|
||||
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
|
||||
>
|
||||
<h1 class="h2">{{ selected_dashboard.name }}</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<div class="btn-group me-2">
|
||||
<a
|
||||
href="{% url 'edit_dashboard' selected_dashboard.id %}"
|
||||
class="btn btn-sm btn-outline-secondary"
|
||||
>
|
||||
<i class="fas fa-edit"></i> Edit
|
||||
</a>
|
||||
<a
|
||||
href="{% url 'delete_dashboard' selected_dashboard.id %}"
|
||||
class="btn btn-sm btn-outline-danger"
|
||||
>
|
||||
<i class="fas fa-trash"></i> Delete
|
||||
</a>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn btn-sm btn-outline-primary dropdown-toggle"
|
||||
type="button"
|
||||
id="timeRangeDropdown"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<i class="fas fa-calendar"></i> Time Range
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="timeRangeDropdown">
|
||||
<li>
|
||||
<a class="dropdown-item" href="?dashboard_id={{ selected_dashboard.id }}&time_range=7"
|
||||
>Last 7 days</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="?dashboard_id={{ selected_dashboard.id }}&time_range=30"
|
||||
>Last 30 days</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="?dashboard_id={{ selected_dashboard.id }}&time_range=90"
|
||||
>Last 90 days</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="?dashboard_id={{ selected_dashboard.id }}&time_range=all"
|
||||
>All time</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-3">
|
||||
<div class="card stats-card bg-primary text-white">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">Total Sessions</h6>
|
||||
<h3>{{ dashboard_data.total_sessions }}</h3>
|
||||
<p>Chat conversations</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stats-card bg-success text-white">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">Avg Response Time</h6>
|
||||
<h3>{{ dashboard_data.avg_response_time }}s</h3>
|
||||
<p>Average response</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stats-card bg-info text-white">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">Total Tokens</h6>
|
||||
<h3>{{ dashboard_data.total_tokens }}</h3>
|
||||
<p>Total usage</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stats-card bg-warning text-white">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">Total Cost</h6>
|
||||
<h3>€{{ dashboard_data.total_cost }}</h3>
|
||||
<p>Token cost</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Sessions Over Time</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="sessions-time-chart" class="chart-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Sentiment Analysis</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="sentiment-chart" class="chart-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Top Countries</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="country-chart" class="chart-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Categories</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="category-chart" class="chart-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Parse the dashboard data from JSON
|
||||
const dashboardData = JSON.parse("{{ dashboard_data_json|safe }}");
|
||||
|
||||
// Sessions over time chart
|
||||
const timeSeriesData = dashboardData.time_series_data;
|
||||
const timeSeriesX = timeSeriesData.map((item) => item.date);
|
||||
const timeSeriesY = timeSeriesData.map((item) => item.count);
|
||||
|
||||
Plotly.newPlot(
|
||||
"sessions-time-chart",
|
||||
[
|
||||
{
|
||||
x: timeSeriesX,
|
||||
y: timeSeriesY,
|
||||
type: "scatter",
|
||||
mode: "lines+markers",
|
||||
line: {
|
||||
color: "rgb(75, 192, 192)",
|
||||
width: 2,
|
||||
},
|
||||
marker: {
|
||||
color: "rgb(75, 192, 192)",
|
||||
size: 6,
|
||||
},
|
||||
},
|
||||
],
|
||||
{
|
||||
margin: { t: 10, r: 10, b: 40, l: 40 },
|
||||
xaxis: {
|
||||
title: "Date",
|
||||
},
|
||||
yaxis: {
|
||||
title: "Number of Sessions",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Sentiment analysis chart
|
||||
const sentimentData = dashboardData.sentiment_data;
|
||||
|
||||
if (sentimentData.length > 0) {
|
||||
const sentimentLabels = sentimentData.map((item) => item.sentiment);
|
||||
const sentimentValues = sentimentData.map((item) => item.count);
|
||||
const sentimentColors = sentimentLabels.map((sentiment) => {
|
||||
if (sentiment.toLowerCase().includes("positive")) return "rgb(75, 192, 92)";
|
||||
if (sentiment.toLowerCase().includes("negative")) return "rgb(255, 99, 132)";
|
||||
if (sentiment.toLowerCase().includes("neutral")) return "rgb(255, 205, 86)";
|
||||
return "rgb(201, 203, 207)";
|
||||
});
|
||||
|
||||
Plotly.newPlot(
|
||||
"sentiment-chart",
|
||||
[
|
||||
{
|
||||
values: sentimentValues,
|
||||
labels: sentimentLabels,
|
||||
type: "pie",
|
||||
marker: {
|
||||
colors: sentimentColors,
|
||||
},
|
||||
hole: 0.4,
|
||||
textinfo: "label+percent",
|
||||
insidetextorientation: "radial",
|
||||
},
|
||||
],
|
||||
{
|
||||
margin: { t: 10, r: 10, b: 10, l: 10 },
|
||||
}
|
||||
);
|
||||
} else {
|
||||
document.getElementById("sentiment-chart").innerHTML =
|
||||
'<div class="text-center py-5"><p class="text-muted">No sentiment data available</p></div>';
|
||||
}
|
||||
|
||||
// Country chart
|
||||
const countryData = dashboardData.country_data;
|
||||
|
||||
if (countryData.length > 0) {
|
||||
const countryLabels = countryData.map((item) => item.country);
|
||||
const countryValues = countryData.map((item) => item.count);
|
||||
|
||||
Plotly.newPlot(
|
||||
"country-chart",
|
||||
[
|
||||
{
|
||||
x: countryValues,
|
||||
y: countryLabels,
|
||||
type: "bar",
|
||||
orientation: "h",
|
||||
marker: {
|
||||
color: "rgb(54, 162, 235)",
|
||||
},
|
||||
},
|
||||
],
|
||||
{
|
||||
margin: { t: 10, r: 10, b: 40, l: 100 },
|
||||
xaxis: {
|
||||
title: "Number of Sessions",
|
||||
},
|
||||
}
|
||||
);
|
||||
} else {
|
||||
document.getElementById("country-chart").innerHTML =
|
||||
'<div class="text-center py-5"><p class="text-muted">No country data available</p></div>';
|
||||
}
|
||||
|
||||
// Category chart
|
||||
const categoryData = dashboardData.category_data;
|
||||
|
||||
if (categoryData.length > 0) {
|
||||
const categoryLabels = categoryData.map((item) => item.category);
|
||||
const categoryValues = categoryData.map((item) => item.count);
|
||||
|
||||
Plotly.newPlot(
|
||||
"category-chart",
|
||||
[
|
||||
{
|
||||
labels: categoryLabels,
|
||||
values: categoryValues,
|
||||
type: "pie",
|
||||
textinfo: "label+percent",
|
||||
insidetextorientation: "radial",
|
||||
},
|
||||
],
|
||||
{
|
||||
margin: { t: 10, r: 10, b: 10, l: 10 },
|
||||
}
|
||||
);
|
||||
} else {
|
||||
document.getElementById("category-chart").innerHTML =
|
||||
'<div class="text-center py-5"><p class="text-muted">No category data available</p></div>';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@ -0,0 +1,43 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Delete Dashboard | Chat Analytics{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div
|
||||
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
|
||||
>
|
||||
<h1 class="h2">Delete Dashboard</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<a href="{% url 'dashboard' %}" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card border-danger">
|
||||
<div class="card-header bg-danger text-white">
|
||||
<h5 class="card-title mb-0">Confirm Deletion</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="lead">
|
||||
Are you sure you want to delete the dashboard "<strong>{{ dashboard.name }}</strong>"?
|
||||
</p>
|
||||
<p>
|
||||
This action cannot be undone. The dashboard will be permanently deleted, but the
|
||||
underlying data sources will remain intact.
|
||||
</p>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="d-flex justify-content-between mt-4">
|
||||
<a href="{% url 'dashboard' %}" class="btn btn-secondary">Cancel</a>
|
||||
<button type="submit" class="btn btn-danger">Delete Dashboard</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
43
dashboard_project/templates/dashboard/dashboard_form.html
Normal file
43
dashboard_project/templates/dashboard/dashboard_form.html
Normal file
@ -0,0 +1,43 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block title %}
|
||||
{% if is_create %}Create Dashboard{% else %}Edit Dashboard{% endif %}
|
||||
| Chat Analytics
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div
|
||||
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
|
||||
>
|
||||
<h1 class="h2">{% if is_create %}Create Dashboard{% else %}Edit Dashboard{% endif %}</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<a href="{% url 'dashboard' %}" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
{% if is_create %}Create Dashboard{% else %}Edit Dashboard{% endif %}
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
<div class="d-grid gap-2">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{% if is_create %}Create Dashboard{% else %}Update Dashboard{% endif %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -0,0 +1,50 @@
|
||||
<!-- templates/dashboard/data_source_confirm_delete.html -->
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Delete Data Source | Chat Analytics{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div
|
||||
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
|
||||
>
|
||||
<h1 class="h2">Delete Data Source</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<a
|
||||
href="{% url 'data_source_detail' data_source.id %}"
|
||||
class="btn btn-sm btn-outline-secondary"
|
||||
>
|
||||
<i class="fas fa-arrow-left"></i> Back to Data Source
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card border-danger">
|
||||
<div class="card-header bg-danger text-white">
|
||||
<h5 class="card-title mb-0">Confirm Deletion</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="lead">
|
||||
Are you sure you want to delete the data source
|
||||
"<strong>{{ data_source.name }}</strong>"?
|
||||
</p>
|
||||
<p>
|
||||
This action cannot be undone. The data source and all associated chat sessions
|
||||
({{ data_source.chat_sessions.count }} sessions) will be permanently deleted.
|
||||
</p>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="d-flex justify-content-between mt-4">
|
||||
<a href="{% url 'data_source_detail' data_source.id %}" class="btn btn-secondary"
|
||||
>Cancel</a
|
||||
>
|
||||
<button type="submit" class="btn btn-danger">Delete Data Source</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
216
dashboard_project/templates/dashboard/data_source_detail.html
Normal file
216
dashboard_project/templates/dashboard/data_source_detail.html
Normal file
@ -0,0 +1,216 @@
|
||||
<!-- templates/dashboard/data_source_detail.html -->
|
||||
{% extends 'base.html' %}
|
||||
{% load dashboard_extras %}
|
||||
|
||||
{% block title %}{{ data_source.name }} | Chat Analytics{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div
|
||||
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
|
||||
>
|
||||
<h1 class="h2">{{ data_source.name }}</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<a href="{% url 'upload_data' %}" class="btn btn-sm btn-outline-secondary me-2">
|
||||
<i class="fas fa-arrow-left"></i> Back to Data Sources
|
||||
</a>
|
||||
<a href="{% url 'delete_data_source' data_source.id %}" class="btn btn-sm btn-outline-danger">
|
||||
<i class="fas fa-trash"></i> Delete
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Data Source Details</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<p><strong>Name:</strong> {{ data_source.name }}</p>
|
||||
<p><strong>Uploaded At:</strong> {{ data_source.uploaded_at|date:"F d, Y H:i" }}</p>
|
||||
<p><strong>File:</strong> {{ data_source.file.name|split:"/"|last }}</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p><strong>Company:</strong> {{ data_source.company.name }}</p>
|
||||
<p><strong>Total Sessions:</strong> {{ page_obj.paginator.count }}</p>
|
||||
<p><strong>Description:</strong> {{ data_source.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Filter Sessions</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="get" action="{% url 'search_chat_sessions' %}">
|
||||
<div class="input-group mb-3">
|
||||
<input
|
||||
type="text"
|
||||
name="q"
|
||||
class="form-control"
|
||||
placeholder="Search sessions..."
|
||||
aria-label="Search sessions"
|
||||
/>
|
||||
<input type="hidden" name="data_source_id" value="{{ data_source.id }}" />
|
||||
<button class="btn btn-outline-primary" type="submit">
|
||||
<i class="fas fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Chat Sessions ({{ page_obj.paginator.count }})</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Session ID</th>
|
||||
<th>Start Time</th>
|
||||
<th>Country</th>
|
||||
<th>Language</th>
|
||||
<th>Sentiment</th>
|
||||
<th>Messages</th>
|
||||
<th>Tokens</th>
|
||||
<th>Category</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for session in page_obj %}
|
||||
<tr>
|
||||
<td>{{ session.session_id|truncatechars:10 }}</td>
|
||||
<td>{{ session.start_time|date:"M d, Y H:i" }}</td>
|
||||
<td>{{ session.country }}</td>
|
||||
<td>{{ session.language }}</td>
|
||||
<td>
|
||||
{% if session.sentiment %}
|
||||
{% if 'positive' in session.sentiment|lower %}
|
||||
<span class="badge bg-success">{{ session.sentiment }}</span>
|
||||
{% elif 'negative' in session.sentiment|lower %}
|
||||
<span class="badge bg-danger">{{ session.sentiment }}</span>
|
||||
{% elif 'neutral' in session.sentiment|lower %}
|
||||
<span class="badge bg-warning">{{ session.sentiment }}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ session.sentiment }}</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="text-muted">N/A</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ session.messages_sent }}</td>
|
||||
<td>{{ session.tokens }}</td>
|
||||
<td>{{ session.category|default:"N/A" }}</td>
|
||||
<td>
|
||||
<a
|
||||
href="{% url 'chat_session_detail' session.session_id %}"
|
||||
class="btn btn-sm btn-outline-primary"
|
||||
>
|
||||
<i class="fas fa-eye"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="9" class="text-center">No chat sessions found.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
<nav aria-label="Page navigation" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page=1" aria-label="First">
|
||||
<span aria-hidden="true">««</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a
|
||||
class="page-link"
|
||||
href="?page={{ page_obj.previous_page_number }}"
|
||||
aria-label="Previous"
|
||||
>
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="First">
|
||||
<span aria-hidden="true">««</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if page_obj.number == num %}
|
||||
<li class="page-item active">
|
||||
<a class="page-link" href="?page={{ num }}">{{ num }}</a>
|
||||
</li>
|
||||
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ num }}">{{ num }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a
|
||||
class="page-link"
|
||||
href="?page={{ page_obj.next_page_number }}"
|
||||
aria-label="Next"
|
||||
>
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a
|
||||
class="page-link"
|
||||
href="?page={{ page_obj.paginator.num_pages }}"
|
||||
aria-label="Last"
|
||||
>
|
||||
<span aria-hidden="true">»»</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="Last">
|
||||
<span aria-hidden="true">»»</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
316
dashboard_project/templates/dashboard/data_view.html
Normal file
316
dashboard_project/templates/dashboard/data_view.html
Normal file
@ -0,0 +1,316 @@
|
||||
<!-- templates/dashboard/data_view.html -->
|
||||
{% extends 'base.html' %}
|
||||
{% load dashboard_extras %}
|
||||
|
||||
{% block title %}Data View | Chat Analytics{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div
|
||||
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
|
||||
>
|
||||
<h1 class="h2">Data View</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<div class="btn-group me-2">
|
||||
<a href="{% url 'dashboard' %}" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
{% if selected_data_source %}
|
||||
<a
|
||||
href="{% url 'data_source_detail' selected_data_source.id %}"
|
||||
class="btn btn-sm btn-outline-secondary"
|
||||
>
|
||||
<i class="fas fa-database"></i> View Source
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn btn-sm btn-outline-primary dropdown-toggle"
|
||||
type="button"
|
||||
id="dataViewDropdown"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<i class="fas fa-filter"></i> Filter
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="dataViewDropdown">
|
||||
<li><a class="dropdown-item" href="?view=all">All Sessions</a></li>
|
||||
<li><a class="dropdown-item" href="?view=recent">Recent Sessions</a></li>
|
||||
<li><a class="dropdown-item" href="?view=positive">Positive Sentiment</a></li>
|
||||
<li><a class="dropdown-item" href="?view=negative">Negative Sentiment</a></li>
|
||||
<li><a class="dropdown-item" href="?view=escalated">Escalated Sessions</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Data Source Selection -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Data Source Selection</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="get" class="row g-3 align-items-center">
|
||||
<div class="col-md-6">
|
||||
<select name="data_source_id" class="form-select" aria-label="Select Data Source">
|
||||
<option value="">All Data Sources</option>
|
||||
{% for ds in data_sources %}
|
||||
<option
|
||||
value="{{ ds.id }}"
|
||||
{% if selected_data_source.id == ds.id %}selected{% endif %}
|
||||
>
|
||||
{{ ds.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<select name="view" class="form-select" aria-label="Select View">
|
||||
<option value="all" {% if view == 'all' %}selected{% endif %}>All Sessions</option>
|
||||
<option value="recent" {% if view == 'recent' %}selected{% endif %}>
|
||||
Recent Sessions
|
||||
</option>
|
||||
<option value="positive" {% if view == 'positive' %}selected{% endif %}>
|
||||
Positive Sentiment
|
||||
</option>
|
||||
<option value="negative" {% if view == 'negative' %}selected{% endif %}>
|
||||
Negative Sentiment
|
||||
</option>
|
||||
<option value="escalated" {% if view == 'escalated' %}selected{% endif %}>
|
||||
Escalated Sessions
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="submit" class="btn btn-primary w-100">Apply</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Data Table -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-0">
|
||||
Chat Sessions
|
||||
{% if selected_data_source %}
|
||||
for {{ selected_data_source.name }}
|
||||
{% endif %}
|
||||
{% if view != 'all' %}
|
||||
({{ view|title }})
|
||||
{% endif %}
|
||||
</h5>
|
||||
<span class="badge bg-primary">{{ page_obj.paginator.count }} sessions</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Session ID</th>
|
||||
<th>Start Time</th>
|
||||
<th>Country</th>
|
||||
<th>Language</th>
|
||||
<th>Messages</th>
|
||||
<th>Sentiment</th>
|
||||
<th>Response Time</th>
|
||||
<th>Category</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for session in page_obj %}
|
||||
<tr>
|
||||
<td>{{ session.session_id|truncatechars:10 }}</td>
|
||||
<td>{{ session.start_time|date:"M d, Y H:i" }}</td>
|
||||
<td>{{ session.country|default:"N/A" }}</td>
|
||||
<td>{{ session.language|default:"N/A" }}</td>
|
||||
<td>{{ session.messages_sent }}</td>
|
||||
<td>
|
||||
{% if session.sentiment %}
|
||||
{% if 'positive' in session.sentiment|lower %}
|
||||
<span class="badge bg-success">{{ session.sentiment }}</span>
|
||||
{% elif 'negative' in session.sentiment|lower %}
|
||||
<span class="badge bg-danger">{{ session.sentiment }}</span>
|
||||
{% elif 'neutral' in session.sentiment|lower %}
|
||||
<span class="badge bg-warning">{{ session.sentiment }}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ session.sentiment }}</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="text-muted">N/A</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ session.avg_response_time|floatformat:2 }}s</td>
|
||||
<td>{{ session.category|default:"N/A" }}</td>
|
||||
<td>
|
||||
<a
|
||||
href="{% url 'chat_session_detail' session.session_id %}"
|
||||
class="btn btn-sm btn-outline-primary"
|
||||
>
|
||||
<i class="fas fa-eye"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="9" class="text-center">No chat sessions found.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
<nav aria-label="Page navigation" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item">
|
||||
<a
|
||||
class="page-link"
|
||||
href="?{% if selected_data_source %}data_source_id={{ selected_data_source.id }}&{% endif %}{% if view %}view={{ view }}&{% endif %}page=1"
|
||||
aria-label="First"
|
||||
>
|
||||
<span aria-hidden="true">««</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a
|
||||
class="page-link"
|
||||
href="?{% if selected_data_source %}data_source_id={{ selected_data_source.id }}&{% endif %}{% if view %}view={{ view }}&{% endif %}page={{ page_obj.previous_page_number }}"
|
||||
aria-label="Previous"
|
||||
>
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="First">
|
||||
<span aria-hidden="true">««</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if page_obj.number == num %}
|
||||
<li class="page-item active">
|
||||
<a
|
||||
class="page-link"
|
||||
href="?{% if selected_data_source %}data_source_id={{ selected_data_source.id }}&{% endif %}{% if view %}view={{ view }}&{% endif %}page={{ num }}"
|
||||
>{{ num }}</a
|
||||
>
|
||||
</li>
|
||||
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||
<li class="page-item">
|
||||
<a
|
||||
class="page-link"
|
||||
href="?{% if selected_data_source %}data_source_id={{ selected_data_source.id }}&{% endif %}{% if view %}view={{ view }}&{% endif %}page={{ num }}"
|
||||
>{{ num }}</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a
|
||||
class="page-link"
|
||||
href="?{% if selected_data_source %}data_source_id={{ selected_data_source.id }}&{% endif %}{% if view %}view={{ view }}&{% endif %}page={{ page_obj.next_page_number }}"
|
||||
aria-label="Next"
|
||||
>
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a
|
||||
class="page-link"
|
||||
href="?{% if selected_data_source %}data_source_id={{ selected_data_source.id }}&{% endif %}{% if view %}view={{ view }}&{% endif %}page={{ page_obj.paginator.num_pages }}"
|
||||
aria-label="Last"
|
||||
>
|
||||
<span aria-hidden="true">»»</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="Last">
|
||||
<span aria-hidden="true">»»</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Data Summary -->
|
||||
{% if page_obj %}
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Summary</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="card stats-card bg-light">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">Total Sessions</h6>
|
||||
<h3>{{ page_obj.paginator.count }}</h3>
|
||||
<p>Chat conversations</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stats-card bg-light">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">Avg Response Time</h6>
|
||||
<h3>{{ avg_response_time|floatformat:2 }}s</h3>
|
||||
<p>Average response</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stats-card bg-light">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">Avg Messages</h6>
|
||||
<h3>{{ avg_messages|floatformat:1 }}</h3>
|
||||
<p>Per conversation</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stats-card bg-light">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">Escalation Rate</h6>
|
||||
<h3>{{ escalation_rate|floatformat:1 }}%</h3>
|
||||
<p>Escalated sessions</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
40
dashboard_project/templates/dashboard/no_company.html
Normal file
40
dashboard_project/templates/dashboard/no_company.html
Normal file
@ -0,0 +1,40 @@
|
||||
<!-- templates/dashboard/no_company.html -->
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}No Company | Chat Analytics{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div
|
||||
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
|
||||
>
|
||||
<h1 class="h2">No Company Association</h1>
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header bg-warning text-dark">
|
||||
<h5 class="card-title mb-0">Account Not Associated with a Company</h5>
|
||||
</div>
|
||||
<div class="card-body text-center">
|
||||
<div class="mb-4">
|
||||
<i class="fas fa-building fa-4x text-warning mb-3"></i>
|
||||
<h4>You are not currently associated with any company</h4>
|
||||
<p class="lead">You need to be associated with a company to access the dashboard.</p>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Please contact an administrator to have your account assigned to a company. Once your
|
||||
account is associated with a company, you'll be able to access the dashboard and its
|
||||
features.
|
||||
</p>
|
||||
|
||||
<div class="mt-4">
|
||||
<a href="{% url 'profile' %}" class="btn btn-primary">View Your Profile</a>
|
||||
<a href="{% url 'logout' %}" class="btn btn-outline-secondary ms-2">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
222
dashboard_project/templates/dashboard/search_results.html
Normal file
222
dashboard_project/templates/dashboard/search_results.html
Normal file
@ -0,0 +1,222 @@
|
||||
<!-- templates/dashboard/search_results.html -->
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Search Results | Chat Analytics{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div
|
||||
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
|
||||
>
|
||||
<h1 class="h2">Search Results</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<a href="{% url 'dashboard' %}" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Search Chat Sessions</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="get" action="{% url 'search_chat_sessions' %}">
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text"
|
||||
name="q"
|
||||
class="form-control"
|
||||
placeholder="Search sessions..."
|
||||
value="{{ query }}"
|
||||
aria-label="Search sessions"
|
||||
/>
|
||||
{% if data_source %}
|
||||
<input type="hidden" name="data_source_id" value="{{ data_source.id }}" />
|
||||
{% endif %}
|
||||
<button class="btn btn-outline-primary" type="submit">
|
||||
<i class="fas fa-search"></i> Search
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-2 text-muted">
|
||||
<small
|
||||
>Search by session ID, country, language, sentiment, category, or message
|
||||
content.</small
|
||||
>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
Results {% if query %}for "{{ query }}"{% endif %}
|
||||
{% if data_source %}in {{ data_source.name }}{% endif %}
|
||||
({{ page_obj.paginator.count }})
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Session ID</th>
|
||||
<th>Start Time</th>
|
||||
<th>Data Source</th>
|
||||
<th>Country</th>
|
||||
<th>Language</th>
|
||||
<th>Sentiment</th>
|
||||
<th>Messages</th>
|
||||
<th>Category</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for session in page_obj %}
|
||||
<tr>
|
||||
<td>{{ session.session_id|truncatechars:10 }}</td>
|
||||
<td>{{ session.start_time|date:"M d, Y H:i" }}</td>
|
||||
<td>
|
||||
<a href="{% url 'data_source_detail' session.data_source.id %}"
|
||||
>{{ session.data_source.name|truncatechars:15 }}</a
|
||||
>
|
||||
</td>
|
||||
<td>{{ session.country }}</td>
|
||||
<td>{{ session.language }}</td>
|
||||
<td>
|
||||
{% if session.sentiment %}
|
||||
{% if 'positive' in session.sentiment|lower %}
|
||||
<span class="badge bg-success">{{ session.sentiment }}</span>
|
||||
{% elif 'negative' in session.sentiment|lower %}
|
||||
<span class="badge bg-danger">{{ session.sentiment }}</span>
|
||||
{% elif 'neutral' in session.sentiment|lower %}
|
||||
<span class="badge bg-warning">{{ session.sentiment }}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ session.sentiment }}</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="text-muted">N/A</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ session.messages_sent }}</td>
|
||||
<td>{{ session.category|default:"N/A" }}</td>
|
||||
<td>
|
||||
<a
|
||||
href="{% url 'chat_session_detail' session.session_id %}"
|
||||
class="btn btn-sm btn-outline-primary"
|
||||
>
|
||||
<i class="fas fa-eye"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="9" class="text-center">
|
||||
No chat sessions found matching your criteria.
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
<nav aria-label="Page navigation" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item">
|
||||
<a
|
||||
class="page-link"
|
||||
href="?{% if query %}q={{ query }}&{% endif %}{% if data_source %}data_source_id={{ data_source.id }}&{% endif %}page=1"
|
||||
aria-label="First"
|
||||
>
|
||||
<span aria-hidden="true">««</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a
|
||||
class="page-link"
|
||||
href="?{% if query %}q={{ query }}&{% endif %}{% if data_source %}data_source_id={{ data_source.id }}&{% endif %}page={{ page_obj.previous_page_number }}"
|
||||
aria-label="Previous"
|
||||
>
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="First">
|
||||
<span aria-hidden="true">««</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if page_obj.number == num %}
|
||||
<li class="page-item active">
|
||||
<a
|
||||
class="page-link"
|
||||
href="?{% if query %}q={{ query }}&{% endif %}{% if data_source %}data_source_id={{ data_source.id }}&{% endif %}page={{ num }}"
|
||||
>{{ num }}</a
|
||||
>
|
||||
</li>
|
||||
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||
<li class="page-item">
|
||||
<a
|
||||
class="page-link"
|
||||
href="?{% if query %}q={{ query }}&{% endif %}{% if data_source %}data_source_id={{ data_source.id }}&{% endif %}page={{ num }}"
|
||||
>{{ num }}</a
|
||||
>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a
|
||||
class="page-link"
|
||||
href="?{% if query %}q={{ query }}&{% endif %}{% if data_source %}data_source_id={{ data_source.id }}&{% endif %}page={{ page_obj.next_page_number }}"
|
||||
aria-label="Next"
|
||||
>
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a
|
||||
class="page-link"
|
||||
href="?{% if query %}q={{ query }}&{% endif %}{% if data_source %}data_source_id={{ data_source.id }}&{% endif %}page={{ page_obj.paginator.num_pages }}"
|
||||
aria-label="Last"
|
||||
>
|
||||
<span aria-hidden="true">»»</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="Last">
|
||||
<span aria-hidden="true">»»</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
197
dashboard_project/templates/dashboard/upload.html
Normal file
197
dashboard_project/templates/dashboard/upload.html
Normal file
@ -0,0 +1,197 @@
|
||||
<!-- templates/dashboard/upload.html -->
|
||||
{% extends 'base.html' %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load dashboard_extras %}
|
||||
|
||||
{% block title %}Upload Data | Chat Analytics{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div
|
||||
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
|
||||
>
|
||||
<h1 class="h2">Upload Data</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<a href="{% url 'dashboard' %}" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Upload CSV File</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %} {{ form|crispy }}
|
||||
<div class="d-grid gap-2">
|
||||
<button type="submit" class="btn btn-primary">Upload</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">CSV File Format</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>The CSV file should contain the following columns:</p>
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Column</th>
|
||||
<th>Description</th>
|
||||
<th>Type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>session_id</td>
|
||||
<td>Unique identifier for the chat session</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>start_time</td>
|
||||
<td>When the session started</td>
|
||||
<td>Datetime</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>end_time</td>
|
||||
<td>When the session ended</td>
|
||||
<td>Datetime</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ip_address</td>
|
||||
<td>IP address of the user</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>country</td>
|
||||
<td>Country of the user</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>language</td>
|
||||
<td>Language used in the conversation</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>messages_sent</td>
|
||||
<td>Number of messages in the conversation</td>
|
||||
<td>Integer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>sentiment</td>
|
||||
<td>Sentiment analysis of the conversation</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>escalated</td>
|
||||
<td>Whether the conversation was escalated</td>
|
||||
<td>Boolean</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>forwarded_hr</td>
|
||||
<td>Whether the conversation was forwarded to HR</td>
|
||||
<td>Boolean</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>full_transcript</td>
|
||||
<td>Full transcript of the conversation</td>
|
||||
<td>Text</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>avg_response_time</td>
|
||||
<td>Average response time in seconds</td>
|
||||
<td>Float</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>tokens</td>
|
||||
<td>Total number of tokens used</td>
|
||||
<td>Integer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>tokens_eur</td>
|
||||
<td>Cost of tokens in EUR</td>
|
||||
<td>Float</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>category</td>
|
||||
<td>Category of the conversation</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>initial_msg</td>
|
||||
<td>First message from the user</td>
|
||||
<td>Text</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>user_rating</td>
|
||||
<td>User rating of the conversation</td>
|
||||
<td>String</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if data_sources %}
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Uploaded Data Sources</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Uploaded</th>
|
||||
<th>File</th>
|
||||
<th>Sessions</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for data_source in data_sources %}
|
||||
<tr>
|
||||
<td>{{ data_source.name }}</td>
|
||||
<td>{{ data_source.description|truncatechars:50 }}</td>
|
||||
<td>{{ data_source.uploaded_at|date:"M d, Y H:i" }}</td>
|
||||
<td>{{ data_source.file.name|split:"/"|last }}</td>
|
||||
<td>{{ data_source.chat_sessions.count }}</td>
|
||||
<td>
|
||||
<a
|
||||
href="{% url 'data_source_detail' data_source.id %}"
|
||||
class="btn btn-sm btn-outline-primary"
|
||||
>
|
||||
<i class="fas fa-eye"></i>
|
||||
</a>
|
||||
<a
|
||||
href="{% url 'delete_data_source' data_source.id %}"
|
||||
class="btn btn-sm btn-outline-danger"
|
||||
>
|
||||
<i class="fas fa-trash"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user