152 lines
4.7 KiB
Vue
152 lines
4.7 KiB
Vue
<template>
|
||
<n-space vertical>
|
||
<n-card title="进行中的实验" size="medium">
|
||
<template #header-extra>
|
||
<n-button type="primary" @click="fetchExperiments">刷新</n-button>
|
||
<n-button @click="openModal" style="margin-left: 12px;">新建实验</n-button>
|
||
</template>
|
||
|
||
<n-grid :x-gap="12" :y-gap="12" :cols="3">
|
||
<n-grid-item v-for="exp in experiments" :key="exp.id">
|
||
<n-card :title="exp.title" hoverable>
|
||
<template #header-extra>
|
||
<n-tag :type="getStatusType(exp.status)">{{ getStatusLabel(exp.status) }}</n-tag>
|
||
</template>
|
||
<p class="hypothesis-text">{{ exp.hypothesis }}</p>
|
||
<n-space vertical>
|
||
<n-statistic label="当前评分" :value="exp.current_score || '暂无数据'" />
|
||
<n-text depth="3" v-if="exp.linked_context_nodes && exp.linked_context_nodes.length">
|
||
关联认知节点: {{ exp.linked_context_nodes.length }} 个
|
||
</n-text>
|
||
</n-space>
|
||
</n-card>
|
||
</n-grid-item>
|
||
</n-grid>
|
||
</n-card>
|
||
|
||
<n-modal v-model:show="showModal">
|
||
<n-card style="width: 600px" title="设计新实验" :bordered="false" size="huge" role="dialog" aria-modal="true">
|
||
<n-form ref="formRef" :model="formValue">
|
||
<n-form-item label="标题" path="title">
|
||
<n-input v-model:value="formValue.title" placeholder="例如: 测试 DeepSeek-V3 的 SQL 生成能力" />
|
||
</n-form-item>
|
||
<n-form-item label="假设 (Hypothesis)" path="hypothesis">
|
||
<n-input v-model:value="formValue.hypothesis" type="textarea" placeholder="如果我们切换到 DeepSeek-V3,准确率预计提升 5%..." />
|
||
</n-form-item>
|
||
<n-form-item label="目标指标" path="target_metric">
|
||
<n-input v-model:value="formValue.target_metric" placeholder="例如: accuracy, latency" />
|
||
</n-form-item>
|
||
<n-form-item label="关联认知节点 (Context)" path="linked_context_nodes">
|
||
<n-select
|
||
v-model:value="formValue.linked_context_nodes"
|
||
multiple
|
||
:options="contextNodeOptions"
|
||
placeholder="选择此实验试图挑战或验证的认知..."
|
||
/>
|
||
</n-form-item>
|
||
</n-form>
|
||
<template #footer>
|
||
<n-button type="primary" block @click="createExperiment">启动实验</n-button>
|
||
</template>
|
||
</n-card>
|
||
</n-modal>
|
||
</n-space>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, onMounted, computed } from 'vue'
|
||
import { NSpace, NCard, NButton, NGrid, NGridItem, NTag, NStatistic, NModal, NForm, NFormItem, NInput, useMessage, NSelect, NText } from 'naive-ui'
|
||
import axios from 'axios'
|
||
|
||
const message = useMessage()
|
||
const experiments = ref<any[]>([])
|
||
const contextNodes = ref<any[]>([])
|
||
const showModal = ref(false)
|
||
const formValue = ref({
|
||
title: '',
|
||
hypothesis: '',
|
||
target_metric: 'accuracy',
|
||
linked_context_nodes: []
|
||
})
|
||
|
||
const contextNodeOptions = computed(() => {
|
||
return contextNodes.value.map(node => ({
|
||
label: `${node.content.substring(0, 50)}...`,
|
||
value: node.id
|
||
}))
|
||
})
|
||
|
||
const getStatusType = (status: string) => {
|
||
switch (status) {
|
||
case 'success': return 'success'
|
||
case 'failed': return 'error'
|
||
case 'running': return 'info'
|
||
default: return 'default'
|
||
}
|
||
}
|
||
|
||
const getStatusLabel = (status: string) => {
|
||
switch (status) {
|
||
case 'success': return '成功'
|
||
case 'failed': return '失败'
|
||
case 'running': return '进行中'
|
||
case 'draft': return '草稿'
|
||
default: return status
|
||
}
|
||
}
|
||
|
||
const fetchExperiments = async () => {
|
||
try {
|
||
const res = await axios.get('http://127.0.0.1:8000/experiments/')
|
||
experiments.value = res.data
|
||
} catch (error) {
|
||
message.error('获取实验列表失败')
|
||
}
|
||
}
|
||
|
||
const fetchContextNodes = async () => {
|
||
try {
|
||
const res = await axios.get('http://127.0.0.1:8000/context_nodes/')
|
||
contextNodes.value = res.data
|
||
} catch (error) {
|
||
console.error('Failed to fetch context nodes')
|
||
}
|
||
}
|
||
|
||
const openModal = () => {
|
||
fetchContextNodes()
|
||
showModal.value = true
|
||
}
|
||
|
||
const createExperiment = async () => {
|
||
try {
|
||
const res = await axios.post('http://127.0.0.1:8000/experiments/', formValue.value)
|
||
message.success('实验已启动!')
|
||
experiments.value.push(res.data)
|
||
showModal.value = false
|
||
// Reset form
|
||
formValue.value = {
|
||
title: '',
|
||
hypothesis: '',
|
||
target_metric: 'accuracy',
|
||
linked_context_nodes: []
|
||
}
|
||
} catch (error) {
|
||
message.error('创建实验失败')
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
fetchExperiments()
|
||
fetchContextNodes()
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.hypothesis-text {
|
||
min-height: 3em;
|
||
color: #aaa;
|
||
font-size: 0.9em;
|
||
}
|
||
</style>
|