forked from quant-speed-AI/Scoring-System
180 lines
8.3 KiB
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 %}
|