Files
YG_FT/frontend/src/views/compare/CompareChatView.vue
caoxiaozhu ab9e87f948 refactor: 推理对比超时与打字机展示改进
抽取 withTimeout 替代 Promise.race 超时控制,对比结果新增打字机逐字渲染与清理,推理聊天参数与列表类型同步收敛。
2026-07-16 11:03:25 +08:00

144 lines
4.3 KiB
Vue
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.
<script setup lang="ts">
import { ref, reactive, computed, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import PageCard from '@/components/PageCard.vue'
import { usePolling } from '@/composables/usePolling'
import { getCompare } from '@/api/modules/compare'
import type { CompareTask, LoadedModel } from '@/types'
const route = useRoute()
const router = useRouter()
const taskId = route.params.id as string
const task = ref<CompareTask | null>(null)
const form = reactive({
systemPrompt: '',
question: '',
temperature: 0.7,
topP: 0.9,
topK: 40,
maxTokens: 2048,
})
const loadedModels = computed<LoadedModel[]>(() => {
if (!task.value?.load_status) return []
try {
const ls =
typeof task.value.load_status === 'string'
? JSON.parse(task.value.load_status)
: task.value.load_status
return ls.loaded_models || []
} catch {
return []
}
})
const allReady = computed(
() => loadedModels.value.length > 0 && loadedModels.value.every((m) => m.status === 'ready' || m.status === 'running'),
)
const isStarting = computed(() => loadedModels.value.some((m) => m.status === 'starting'))
async function loadTask() {
try {
task.value = await getCompare(taskId)
} catch {
// ignore
}
}
function handleSubmit() {
if (!form.question.trim()) {
ElMessage.warning('请输入问题')
return
}
if (isStarting.value) {
ElMessage.warning('模型仍在启动中,请稍候')
return
}
// 在新窗口打开结果页(原项目用 window.open
const params = new URLSearchParams({
taskId,
taskName: task.value?.model_name || task.value?.name || '',
question: form.question,
systemPrompt: form.systemPrompt,
temperature: String(form.temperature),
topP: String(form.topP),
topK: String(form.topK),
maxTokens: String(form.maxTokens),
})
const url = router.resolve(`/model-compare/result?${params.toString()}`).href
window.open(url, '_blank')
}
const { start: startPolling } = usePolling(loadTask, 5000, { immediate: false })
onMounted(async () => {
await loadTask()
startPolling()
})
</script>
<template>
<PageCard title="模型对比配置">
<!-- 已启动模型 -->
<el-divider content-position="left">已启动模型</el-divider>
<div class="model-list">
<el-tag
v-for="(m, idx) in loadedModels"
:key="idx"
:type="m.status === 'ready' || m.status === 'running' ? 'success' : m.status === 'starting' ? 'warning' : 'danger'"
size="large"
>
{{ m.model_name }} ({{ m.status }})
</el-tag>
<span v-if="!loadedModels.length" class="empty-hint">暂无已启动模型</span>
</div>
<!-- 输入配置 -->
<el-divider content-position="left">对话配置</el-divider>
<el-form label-width="120px" style="max-width: 700px">
<el-form-item label="系统提示词">
<el-input v-model="form.systemPrompt" type="textarea" :rows="3" placeholder="可选" />
</el-form-item>
<el-form-item label="问题">
<el-input v-model="form.question" type="textarea" :rows="4" placeholder="请输入要对比的问题" />
</el-form-item>
<el-form-item label="Temperature">
<el-slider v-model="form.temperature" :min="0" :max="2" :step="0.1" show-input style="max-width: 500px" />
</el-form-item>
<el-form-item label="Top-p">
<el-slider v-model="form.topP" :min="0" :max="1" :step="0.05" show-input style="max-width: 500px" />
</el-form-item>
<el-form-item label="Top-k">
<el-slider v-model="form.topK" :min="1" :max="100" :step="1" show-input style="max-width: 500px" />
</el-form-item>
<el-form-item label="Max Tokens">
<el-slider v-model="form.maxTokens" :min="256" :max="4096" :step="128" show-input style="max-width: 500px" />
</el-form-item>
<el-form-item>
<el-button type="primary" :disabled="!allReady || isStarting" @click="handleSubmit">
开始对比
</el-button>
<el-button @click="router.back()">返回</el-button>
</el-form-item>
</el-form>
</PageCard>
</template>
<style scoped>
.model-list {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 12px;
}
.empty-hint {
color: #909399;
}
</style>