| | {% extends "admin/base.html" %} |
| |
|
| | {% block admin_content %} |
| | <div class="admin-header"> |
| | <div class="admin-title">Dashboard</div> |
| | </div> |
| |
|
| | <div class="admin-stats"> |
| | <div class="stat-card"> |
| | <div class="stat-title">Total Users</div> |
| | <div class="stat-value">{{ stats.total_users }}</div> |
| | </div> |
| | <div class="stat-card"> |
| | <div class="stat-title">Total Votes</div> |
| | <div class="stat-value">{{ stats.total_votes }}</div> |
| | </div> |
| | <div class="stat-card"> |
| | <div class="stat-title">TTS Votes</div> |
| | <div class="stat-value">{{ stats.tts_votes }}</div> |
| | </div> |
| | <div class="stat-card"> |
| | <div class="stat-title">Conversational Votes</div> |
| | <div class="stat-value">{{ stats.conversational_votes }}</div> |
| | </div> |
| | <div class="stat-card"> |
| | <div class="stat-title">TTS Models</div> |
| | <div class="stat-value">{{ stats.tts_models }}</div> |
| | </div> |
| | <div class="stat-card"> |
| | <div class="stat-title">Conversational Models</div> |
| | <div class="stat-value">{{ stats.conversational_models }}</div> |
| | </div> |
| | </div> |
| |
|
| | <div class="admin-card"> |
| | <div class="admin-card-header"> |
| | <div class="admin-card-title">Daily Votes (Last 30 Days)</div> |
| | </div> |
| | <canvas id="votesChart" height="200"></canvas> |
| | </div> |
| |
|
| | <div class="admin-card"> |
| | <div class="admin-card-header"> |
| | <div class="admin-card-title">Top TTS Models</div> |
| | </div> |
| | <div class="table-responsive"> |
| | <table class="admin-table"> |
| | <thead> |
| | <tr> |
| | <th>Rank</th> |
| | <th>Model</th> |
| | <th>ELO Score</th> |
| | <th>Win Rate</th> |
| | <th>Total Matches</th> |
| | </tr> |
| | </thead> |
| | <tbody> |
| | {% for model in top_tts_models %} |
| | <tr> |
| | <td>{{ loop.index }}</td> |
| | <td>{{ model.name }}</td> |
| | <td>{{ model.current_elo|int }}</td> |
| | <td>{{ model.win_rate|round }}%</td> |
| | <td>{{ model.match_count }}</td> |
| | </tr> |
| | {% endfor %} |
| | </tbody> |
| | </table> |
| | </div> |
| | </div> |
| |
|
| | <div class="admin-card"> |
| | <div class="admin-card-header"> |
| | <div class="admin-card-title">Top Conversational Models</div> |
| | </div> |
| | <div class="table-responsive"> |
| | <table class="admin-table"> |
| | <thead> |
| | <tr> |
| | <th>Rank</th> |
| | <th>Model</th> |
| | <th>ELO Score</th> |
| | <th>Win Rate</th> |
| | <th>Total Matches</th> |
| | </tr> |
| | </thead> |
| | <tbody> |
| | {% for model in top_conversational_models %} |
| | <tr> |
| | <td>{{ loop.index }}</td> |
| | <td>{{ model.name }}</td> |
| | <td>{{ model.current_elo|int }}</td> |
| | <td>{{ model.win_rate|round }}%</td> |
| | <td>{{ model.match_count }}</td> |
| | </tr> |
| | {% endfor %} |
| | </tbody> |
| | </table> |
| | </div> |
| | </div> |
| |
|
| | <div class="admin-row"> |
| | <div class="admin-card"> |
| | <div class="admin-card-header"> |
| | <div class="admin-card-title">Recent Votes</div> |
| | <a href="{{ url_for('admin.votes') }}" class="btn-secondary">View All</a> |
| | </div> |
| | <div class="table-responsive"> |
| | <table class="admin-table"> |
| | <thead> |
| | <tr> |
| | <th>Date</th> |
| | <th>Type</th> |
| | <th>User</th> |
| | <th>Chosen Model</th> |
| | <th>Rejected Model</th> |
| | </tr> |
| | </thead> |
| | <tbody> |
| | {% for vote in recent_votes %} |
| | <tr> |
| | <td>{{ vote.vote_date.strftime('%Y-%m-%d %H:%M') }}</td> |
| | <td>{{ vote.model_type }}</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> |
| | </tr> |
| | {% endfor %} |
| | </tbody> |
| | </table> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | <div class="admin-row"> |
| | <div class="admin-card"> |
| | <div class="admin-card-header"> |
| | <div class="admin-card-title">Recent Users</div> |
| | <a href="{{ url_for('admin.users') }}" class="btn-secondary">View All</a> |
| | </div> |
| | <div class="table-responsive"> |
| | <table class="admin-table"> |
| | <thead> |
| | <tr> |
| | <th>Username</th> |
| | <th>Join Date</th> |
| | <th>Actions</th> |
| | </tr> |
| | </thead> |
| | <tbody> |
| | {% for user in recent_users %} |
| | <tr> |
| | <td>{{ user.username }}</td> |
| | <td>{{ user.join_date.strftime('%Y-%m-%d %H:%M') }}</td> |
| | <td> |
| | <a href="{{ url_for('admin.user_detail', user_id=user.id) }}" class="btn-secondary">View Details</a> |
| | </td> |
| | </tr> |
| | {% endfor %} |
| | </tbody> |
| | </table> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | <script> |
| | document.addEventListener('DOMContentLoaded', function() { |
| | const votesData = {{ daily_votes_data|safe }}; |
| | |
| | |
| | const votesCtx = document.getElementById('votesChart').getContext('2d'); |
| | new Chart(votesCtx, { |
| | type: 'line', |
| | data: { |
| | labels: votesData.labels, |
| | datasets: [{ |
| | label: 'Daily Votes', |
| | data: votesData.counts, |
| | backgroundColor: 'rgba(80, 70, 229, 0.1)', |
| | borderColor: 'rgba(80, 70, 229, 1)', |
| | borderWidth: 2, |
| | tension: 0.3, |
| | fill: true, |
| | pointRadius: 3, |
| | pointBackgroundColor: '#5046e5' |
| | }] |
| | }, |
| | options: { |
| | responsive: true, |
| | maintainAspectRatio: false, |
| | scales: { |
| | yAxes: [{ |
| | ticks: { |
| | beginAtZero: true, |
| | precision: 0 |
| | } |
| | }] |
| | }, |
| | tooltips: { |
| | mode: 'index', |
| | intersect: false |
| | } |
| | } |
| | }); |
| | }); |
| | </script> |
| | {% endblock %} |