Files
YG_FT_Platform/web/pages/model-compare-result.html

278 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>模型对比结果 - 远光软件微调平台</title>
<script src="../lib/tailwindcss/tailwind.js"></script>
<link href="../lib/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<style>
.bg-primary { background-color: #1890ff; }
.text-primary { color: #1890ff; }
:root { --primary: #1890ff; }
/* 流式输出光标 */
.typing-cursor::after {
content: '|';
animation: blink 1s infinite;
color: var(--primary);
}
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
</style>
</head>
<body class="antialiased bg-gray-50 h-screen flex flex-col">
<!-- 顶部操作栏 -->
<div class="bg-white border-b border-gray-200 px-6 py-2 flex items-center justify-end flex-shrink-0">
<button id="restartBtn" class="px-3 py-1 bg-primary text-white rounded text-sm hover:bg-primary/90 transition-colors">
<i class="fa fa-refresh mr-1"></i>重新提问
</button>
</div>
<!-- 用户提问显示区 -->
<div class="px-6 py-4 flex-shrink-0">
<div class="flex items-start">
<div class="flex-shrink-0 bg-green-500 rounded-full px-3 py-1 mr-3">
<span class="text-white text-xs font-medium">用户问题</span>
</div>
<div class="bg-green-100 rounded-2xl rounded-tl-sm px-5 py-3 max-w-3xl shadow-sm">
<span class="text-green-800 text-base leading-relaxed" id="questionText"></span>
</div>
</div>
</div>
<!-- 模型输出网格2x2 -->
<div id="outputGrid" class="grid grid-cols-2 gap-4 flex-1 min-h-0">
<!-- 输出卡片将通过JS动态生成 -->
</div>
<script>
// 动态获取 API 基础地址
const getApiBase = () => {
const protocol = window.location.protocol;
const hostname = window.location.hostname;
return `${protocol}//${hostname}:8080/api`;
};
const API_BASE = getApiBase();
// 模拟模型数据(用于演示)
const mockModels = [
{ id: 1, name: 'GPT-4', type: 'LLM', description: 'OpenAI GPT-4 大语言模型' },
{ id: 2, name: 'Claude-3', type: 'LLM', description: 'Anthropic Claude-3 模型' },
{ id: 3, name: '文心一言', type: 'LLM', description: '百度文心一言大模型' },
{ id: 4, name: '通义千问', type: 'LLM', description: '阿里通义千问大模型' },
{ id: 5, name: 'ChatGLM', type: 'LLM', description: '智谱ChatGLM对话模型' },
{ id: 6, name: '星火认知', type: 'LLM', description: '讯飞星火认知大模型' }
];
let allModels = [];
let selectedModelIds = [];
let currentStreamingIntervals = [];
let compareTaskId = null;
let taskName = '';
let userQuestion = '';
// 模拟回复内容
const mockResponses = [
"这是一个基于深度学习的自然语言处理模型回答。我可以处理各种复杂的问题,包括代码编写、文本分析、知识问答等多种任务。我的训练数据涵盖了广泛的领域知识,能够提供准确和有用的信息。",
"您好!我是一个人工智能语言模型,很高兴为您服务。我可以帮助您解答问题、提供建议、进行创意写作等。如果您有任何需要,请随时告诉我,我会尽力提供帮助。",
"这是一个很有趣的问题!从技术角度来看,我们需要考虑多个因素:数据质量、模型架构、训练策略等。深度学习在近年来取得了巨大进展,但仍然存在一些挑战需要解决。",
"根据我的理解,这个问题涉及到以下几个方面:首先,需要明确问题的具体背景;其次,要分析相关的技术方案;最后,需要评估实施的成本和收益。建议您先收集更多信息再做决定。"
];
// 页面初始化
async function initPage() {
const urlParams = new URLSearchParams(window.location.search);
compareTaskId = urlParams.get('taskId');
taskName = urlParams.get('taskName') || '对比任务';
userQuestion = decodeURIComponent(urlParams.get('question') || '');
// 设置用户提问
document.getElementById('questionText').textContent = userQuestion;
// 加载模型列表
await loadModels();
// 加载任务数据获取模型列表
await loadCompareTask();
// 初始化输出卡片并开始模拟流式输出
initializeOutputCards();
simulateStreaming();
}
// 加载对比任务数据
async function loadCompareTask() {
if (!compareTaskId) return;
try {
const response = await fetch(`${API_BASE}/model-compare/${compareTaskId}`);
const result = await response.json();
if (result.code === 0) {
const taskData = Array.isArray(result.data)
? result.data.find(item => item && item.id == compareTaskId)
: result.data;
if (taskData) {
const modelsField = taskData.models;
if (modelsField) {
try {
if (typeof modelsField === 'string') {
selectedModelIds = JSON.parse(modelsField);
} else if (Array.isArray(modelsField)) {
selectedModelIds = modelsField;
}
} catch (e) {
console.error('解析模型列表失败:', e);
}
}
}
}
} catch (error) {
console.error('加载对比任务失败:', error);
}
}
// 加载模型列表
async function loadModels() {
try {
const response = await fetch(`${API_BASE}/model-manage`);
const result = await response.json();
if (result.code === 0) {
allModels = result.data || [];
}
} catch (error) {
console.error('加载模型失败:', error);
allModels = mockModels;
}
}
// 初始化输出卡片
function initializeOutputCards() {
const grid = document.getElementById('outputGrid');
const allAvailableModels = [...allModels, ...mockModels];
// 如果没有选择模型使用前4个演示模型
const displayModelIds = selectedModelIds.length > 0
? selectedModelIds.slice(0, 4)
: [1, 2, 3, 4];
grid.innerHTML = displayModelIds.map((modelId, index) => {
const model = allAvailableModels.find(m => m.id === modelId) || { name: `模型 ${modelId}` };
const colors = ['bg-blue-100 text-blue-700', 'bg-green-100 text-green-700', 'bg-purple-100 text-purple-700', 'bg-orange-100 text-orange-700'];
const colorClass = colors[index % colors.length];
return `
<div class="bg-white rounded-lg shadow-sm flex flex-col h-full" id="output-${modelId}">
<div class="flex items-center justify-between px-5 py-3 border-b border-gray-100">
<span class="px-3 py-1 rounded text-sm font-medium ${colorClass}">${model.name}</span>
<span id="status-${modelId}" class="text-xs text-gray-400 flex items-center">
<i class="fa fa-clock-o mr-1"></i>
等待中
</span>
</div>
<div id="content-${modelId}" class="flex-1 overflow-y-auto p-8 text-base text-gray-600 leading-relaxed min-h-[300px]">
<span class="text-gray-300">模型即将开始生成回答...</span>
</div>
</div>
`;
}).join('');
}
// 模拟流式输出
function simulateStreaming() {
currentStreamingIntervals.forEach(interval => clearInterval(interval));
currentStreamingIntervals = [];
// 禁用重新提问按钮
const btn = document.getElementById('restartBtn');
if (btn) {
btn.disabled = true;
btn.classList.add('opacity-50', 'cursor-not-allowed');
}
const displayModelIds = selectedModelIds.length > 0
? selectedModelIds.slice(0, 4)
: [1, 2, 3, 4];
displayModelIds.forEach((modelId, index) => {
setTimeout(() => {
streamModelResponse(modelId, index);
}, index * 500);
});
}
// 流式输出单个模型
function streamModelResponse(modelId, responseIndex) {
const contentEl = document.getElementById(`content-${modelId}`);
const statusEl = document.getElementById(`status-${modelId}`);
if (!contentEl || !statusEl) return;
statusEl.innerHTML = '<i class="fa fa-spinner fa-spin mr-1"></i> 生成中...';
statusEl.classList.remove('text-gray-400');
statusEl.classList.add('text-primary');
contentEl.innerHTML = '';
contentEl.classList.add('typing-cursor');
const response = mockResponses[responseIndex % mockResponses.length];
let charIndex = 0;
const interval = setInterval(() => {
if (charIndex < response.length) {
contentEl.textContent = response.substring(0, charIndex + 1);
charIndex++;
contentEl.scrollTop = contentEl.scrollHeight;
} else {
clearInterval(interval);
const idx = currentStreamingIntervals.indexOf(interval);
if (idx > -1) currentStreamingIntervals.splice(idx, 1);
statusEl.innerHTML = '<i class="fa fa-check-circle text-green-500 mr-1"></i> 完成';
statusEl.classList.remove('text-primary');
statusEl.classList.add('text-green-500');
contentEl.classList.remove('typing-cursor');
// 所有模型完成时启用按钮
if (currentStreamingIntervals.length === 0) {
const btn = document.getElementById('restartBtn');
if (btn) {
btn.disabled = false;
btn.classList.remove('opacity-50', 'cursor-not-allowed');
}
}
}
}, 30 + Math.random() * 40);
currentStreamingIntervals.push(interval);
}
// 重新提问
function restartQuestion() {
window.location.href = `main.html?page=model-compare-chat&id=${compareTaskId}`;
}
// 绑定重新提问按钮点击事件
function bindRestartBtn() {
const restartBtn = document.getElementById('restartBtn');
if (restartBtn) {
restartBtn.onclick = restartQuestion;
}
}
// 页面加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initPage);
document.addEventListener('DOMContentLoaded', bindRestartBtn);
} else {
// 通过 main.html fetch 加载时,直接绑定
setTimeout(bindRestartBtn, 0);
setTimeout(initPage, 0);
}
</script>
</body>
</html>