| {% 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 %} |