|
{% extends "admin/base.html" %} |
|
|
|
{% block admin_content %} |
|
<div class="admin-header"> |
|
<div class="admin-title">Activity Monitoring</div> |
|
</div> |
|
|
|
<div class="admin-stats"> |
|
<div class="stat-card"> |
|
<div class="stat-title">Active TTS Sessions</div> |
|
<div class="stat-value">{{ tts_session_count }}</div> |
|
</div> |
|
<div class="stat-card"> |
|
<div class="stat-title">Active Conversational Sessions</div> |
|
<div class="stat-value">{{ conversational_session_count }}</div> |
|
</div> |
|
</div> |
|
|
|
<div class="admin-card"> |
|
<div class="admin-card-header"> |
|
<div class="admin-card-title">Activity Past 24 Hours</div> |
|
</div> |
|
<canvas id="hourlyActivityChart" height="250"></canvas> |
|
</div> |
|
|
|
<div class="admin-card"> |
|
<div class="admin-card-header"> |
|
<div class="admin-card-title">Recent TTS Votes</div> |
|
</div> |
|
<div class="table-responsive"> |
|
<table class="admin-table"> |
|
<thead> |
|
<tr> |
|
<th>Time</th> |
|
<th>User</th> |
|
<th>Chosen Model</th> |
|
<th>Rejected Model</th> |
|
<th>Text</th> |
|
</tr> |
|
</thead> |
|
<tbody> |
|
{% for vote in recent_tts_votes %} |
|
<tr> |
|
<td>{{ vote.vote_date.strftime('%Y-%m-%d %H:%M') }}</td> |
|
<td> |
|
{% if vote.user %} |
|
<a href="{{ url_for('admin.user_detail', user_id=vote.user.id) }}">{{ vote.user.username }}</a> |
|
{% else %} |
|
Anonymous |
|
{% endif %} |
|
</td> |
|
<td>{{ vote.chosen.name }}</td> |
|
<td>{{ vote.rejected.name }}</td> |
|
<td> |
|
<div class="text-truncate" title="{{ vote.text }}"> |
|
{{ vote.text }} |
|
</div> |
|
</td> |
|
</tr> |
|
{% endfor %} |
|
</tbody> |
|
</table> |
|
</div> |
|
</div> |
|
|
|
<div class="admin-card"> |
|
<div class="admin-card-header"> |
|
<div class="admin-card-title">Recent Conversational Votes</div> |
|
</div> |
|
<div class="table-responsive"> |
|
<table class="admin-table"> |
|
<thead> |
|
<tr> |
|
<th>Time</th> |
|
<th>User</th> |
|
<th>Chosen Model</th> |
|
<th>Rejected Model</th> |
|
<th>Text Preview</th> |
|
</tr> |
|
</thead> |
|
<tbody> |
|
{% for vote in recent_conv_votes %} |
|
<tr> |
|
<td>{{ vote.vote_date.strftime('%Y-%m-%d %H:%M') }}</td> |
|
<td> |
|
{% if vote.user %} |
|
<a href="{{ url_for('admin.user_detail', user_id=vote.user.id) }}">{{ vote.user.username }}</a> |
|
{% else %} |
|
Anonymous |
|
{% endif %} |
|
</td> |
|
<td>{{ vote.chosen.name }}</td> |
|
<td>{{ vote.rejected.name }}</td> |
|
<td> |
|
<div class="text-truncate" title="{{ vote.text }}"> |
|
{{ vote.text }} |
|
</div> |
|
</td> |
|
</tr> |
|
{% endfor %} |
|
</tbody> |
|
</table> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
document.addEventListener('DOMContentLoaded', function() { |
|
const hourlyData = {{ hourly_data|safe }}; |
|
|
|
|
|
const hourlyActivityCtx = document.getElementById('hourlyActivityChart').getContext('2d'); |
|
new Chart(hourlyActivityCtx, { |
|
type: 'bar', |
|
data: { |
|
labels: hourlyData.labels, |
|
datasets: [{ |
|
label: 'Votes per Hour', |
|
data: hourlyData.counts, |
|
backgroundColor: 'rgba(80, 70, 229, 0.7)', |
|
borderColor: 'rgba(80, 70, 229, 1)', |
|
borderWidth: 1 |
|
}] |
|
}, |
|
options: { |
|
responsive: true, |
|
maintainAspectRatio: false, |
|
scales: { |
|
yAxes: [{ |
|
ticks: { |
|
beginAtZero: true, |
|
precision: 0 |
|
} |
|
}] |
|
} |
|
} |
|
}); |
|
}); |
|
</script> |
|
{% endblock %} |