Files
Scoring-System/backend/competition/templates/judge/ai_manage.html

180 lines
8.3 KiB
HTML

{% extends 'judge/base.html' %}
{% block title %}AI 服务管理 - 评委系统{% endblock %}
{% block content %}
<div class="mb-8">
<h2 class="text-3xl font-bold text-gray-900 tracking-tight">AI 服务管理</h2>
<p class="mt-1 text-sm text-gray-500">查看和管理音频转录及 AI 评分任务</p>
</div>
<div class="bg-white shadow overflow-hidden sm:rounded-lg border border-gray-200">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
项目
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
文件名
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
状态
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
AI 评分
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
操作
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
{% for task in tasks %}
<tr class="hover:bg-gray-50 transition-colors">
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">{{ task.project.title }}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<a href="{{ task.file_url }}" target="_blank" class="text-sm text-blue-600 hover:text-blue-900 flex items-center">
<i class="fas fa-file-audio mr-1"></i> {{ task.file_name|default:"查看文件"|truncatechars:20 }}
</a>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full {{ task.status_class }}">
{{ task.get_status_display }}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{% if task.ai_score %}
<span class="font-bold text-gray-900">{{ task.ai_score }}</span>
{% else %}
<span class="text-gray-400">-</span>
{% endif %}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium space-x-2">
<button onclick="refreshStatus('{{ task.id }}')" class="text-indigo-600 hover:text-indigo-900 transition-colors" title="刷新状态">
<i class="fas fa-sync-alt"></i>
</button>
{% if task.status == 'SUCCEEDED' %}
<button onclick="viewResult('{{ task.id }}')" class="text-green-600 hover:text-green-900 transition-colors" title="查看结果">
<i class="fas fa-eye"></i>
</button>
{% endif %}
<button onclick="deleteTask('{{ task.id }}')" class="text-red-600 hover:text-red-900 transition-colors" title="删除任务">
<i class="fas fa-trash-alt"></i>
</button>
</td>
</tr>
{% empty %}
<tr>
<td colspan="5" class="px-6 py-10 text-center text-gray-500">
<div class="flex flex-col items-center">
<i class="fas fa-inbox text-4xl text-gray-300 mb-2"></i>
<p>暂无 AI 任务</p>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- AI Result Modal -->
<div id="aiResultModal" class="modal fixed inset-0 z-50 flex items-center justify-center p-4 sm:p-6" style="background-color: rgba(0,0,0,0.5);">
<div class="bg-white rounded-xl shadow-2xl w-full max-w-4xl max-h-[90vh] overflow-hidden flex flex-col relative animate-fade-in">
<button class="absolute top-4 right-4 text-gray-400 hover:text-gray-600 z-10" onclick="closeModal('aiResultModal')">
<i class="fas fa-times text-xl"></i>
</button>
<div class="px-6 py-4 border-b border-gray-100 bg-gray-50">
<h3 class="text-lg font-bold text-gray-900 flex items-center">
<i class="fas fa-robot text-blue-500 mr-2"></i> AI 分析详情
</h3>
</div>
<div class="p-6 overflow-y-auto space-y-6" id="aiResultContent">
<div>
<h4 class="text-sm font-bold text-gray-900 uppercase tracking-wide mb-2 flex items-center">
<i class="fas fa-align-left mr-2 text-gray-400"></i> 逐字稿
</h4>
<div id="transcriptionText" class="bg-gray-50 p-4 rounded-lg text-sm text-gray-700 leading-relaxed border border-gray-200 max-h-60 overflow-y-auto"></div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h4 class="text-sm font-bold text-gray-900 uppercase tracking-wide mb-2 flex items-center">
<i class="fas fa-lightbulb mr-2 text-yellow-500"></i> AI 总结
</h4>
<div id="summaryText" class="bg-yellow-50 p-4 rounded-lg text-sm text-gray-800 border border-yellow-100 h-40 overflow-y-auto"></div>
</div>
<div>
<h4 class="text-sm font-bold text-gray-900 uppercase tracking-wide mb-2 flex items-center">
<i class="fas fa-comment-dots mr-2 text-green-500"></i> AI 评语
</h4>
<div id="evaluationText" class="bg-green-50 p-4 rounded-lg text-sm text-gray-800 border border-green-100 h-40 overflow-y-auto"></div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
function closeModal(id) {
document.getElementById(id).classList.remove('active');
}
async function refreshStatus(taskId) {
try {
const res = await apiCall(`/api/ai/transcriptions/${taskId}/refresh_status/`, 'GET');
if (res.status === 'SUCCEEDED' || res.status === 'FAILED') {
alert('状态已更新: ' + res.status);
location.reload();
} else {
alert('当前状态: ' + res.status);
}
} catch (e) {
alert('刷新失败');
}
}
async function viewResult(taskId) {
try {
const res = await apiCall(`/api/ai/transcriptions/${taskId}/`, 'GET');
document.getElementById('transcriptionText').innerText = res.transcription || '无逐字稿';
document.getElementById('summaryText').innerText = res.summary || '无总结';
// Handle Evaluation (might be separate API or included)
// Assuming simple structure for now, adjust based on actual API
let evalText = '暂无评语';
if (res.ai_evaluations && res.ai_evaluations.length > 0) {
evalText = res.ai_evaluations[0].evaluation || '无内容';
}
document.getElementById('evaluationText').innerText = evalText;
document.getElementById('aiResultModal').classList.add('active');
} catch (e) {
console.error(e);
alert('获取结果失败');
}
}
async function deleteTask(taskId) {
if(!confirm('确定要删除此任务吗?')) return;
try {
await apiCall(`/judge/api/ai/${taskId}/delete/`, 'POST');
alert('删除成功');
location.reload();
} catch (e) {
alert('删除失败');
}
}
</script>
{% endblock %}