276 lines
8.0 KiB
Vue
276 lines
8.0 KiB
Vue
<template>
|
||
<div class="ai-models">
|
||
<el-card>
|
||
<template #header>
|
||
<div class="card-header">
|
||
<span>AI 模型配置</span>
|
||
<el-button type="primary" @click="showAddDialog = true">
|
||
<el-icon><Plus /></el-icon>
|
||
添加模型
|
||
</el-button>
|
||
</div>
|
||
</template>
|
||
|
||
<el-table :data="modelList" v-loading="loading">
|
||
<el-table-column prop="id" label="ID" width="80" />
|
||
<el-table-column prop="display_name" label="名称" width="150" />
|
||
<el-table-column prop="model_name" label="模型" width="150" />
|
||
<el-table-column prop="provider" label="提供商" width="120">
|
||
<template #default="{ row }">
|
||
<el-tag size="small">{{ getProviderLabel(row.provider) }}</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="temperature" label="温度" width="100" />
|
||
<el-table-column prop="max_tokens" label="最大 Token" width="100" />
|
||
<el-table-column prop="is_default" label="默认" width="80">
|
||
<template #default="{ row }">
|
||
<el-tag size="small" :type="row.is_default ? 'success' : 'info'">
|
||
{{ row.is_default ? '是' : '否' }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="is_active" label="状态" width="80">
|
||
<template #default="{ row }">
|
||
<el-tag size="small" :type="row.is_active ? 'success' : 'info'">
|
||
{{ row.is_active ? '启用' : '禁用' }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" fixed="right" width="250">
|
||
<template #default="{ row }">
|
||
<el-button size="small" @click="handleTest(row)">测试</el-button>
|
||
<el-button size="small" @click="handleEdit(row)">编辑</el-button>
|
||
<el-button size="small" type="danger" @click="handleDelete(row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-card>
|
||
|
||
<!-- 添加/编辑对话框 -->
|
||
<el-dialog
|
||
v-model="showModelDialog"
|
||
:title="isEdit ? '编辑模型' : '添加模型'"
|
||
width="600px"
|
||
>
|
||
<el-form :model="modelForm" label-width="120px">
|
||
<el-form-item label="显示名称">
|
||
<el-input v-model="modelForm.display_name" placeholder="如:GPT-3.5" />
|
||
</el-form-item>
|
||
<el-form-item label="模型名称">
|
||
<el-input v-model="modelForm.model_name" placeholder="如:gpt-3.5-turbo" :disabled="isEdit" />
|
||
</el-form-item>
|
||
<el-form-item label="提供商">
|
||
<el-select v-model="modelForm.provider" placeholder="请选择" :disabled="isEdit">
|
||
<el-option label="OpenAI" value="openai" />
|
||
<el-option label="智谱 AI" value="zhipu" />
|
||
<el-option label="百度文心" value="baidu" />
|
||
<el-option label="阿里通义" value="aliyun" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="API 地址">
|
||
<el-input v-model="modelForm.api_url" placeholder="https://api.openai.com/v1" />
|
||
</el-form-item>
|
||
<el-form-item label="API Key">
|
||
<el-input v-model="modelForm.api_key" type="password" show-password placeholder="sk-..." />
|
||
</el-form-item>
|
||
<el-form-item label="温度">
|
||
<el-slider v-model="modelForm.temperature" :min="0" :max="1" :step="0.1" />
|
||
</el-form-item>
|
||
<el-form-item label="最大 Token 数">
|
||
<el-input-number v-model="modelForm.max_tokens" :min="1" :max="4096" />
|
||
</el-form-item>
|
||
<el-form-item label="设为默认">
|
||
<el-switch v-model="modelForm.is_default" />
|
||
</el-form-item>
|
||
<el-form-item label="启用">
|
||
<el-switch v-model="modelForm.is_active" />
|
||
</el-form-item>
|
||
</el-form>
|
||
|
||
<template #footer>
|
||
<el-button @click="showModelDialog = false">取消</el-button>
|
||
<el-button type="primary" @click="handleSubmit" :loading="saving">保存</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- 测试对话框 -->
|
||
<el-dialog
|
||
v-model="showTestDialog"
|
||
title="测试模型"
|
||
width="500px"
|
||
>
|
||
<el-form>
|
||
<el-form-item label="测试提示词">
|
||
<el-input
|
||
v-model="testPrompt"
|
||
type="textarea"
|
||
:rows="4"
|
||
placeholder="请输入测试内容,如:请写一条关于春天的评论"
|
||
/>
|
||
</el-form-item>
|
||
</el-form>
|
||
|
||
<template #footer>
|
||
<el-button @click="showTestDialog = false">取消</el-button>
|
||
<el-button type="primary" @click="handleRunTest" :loading="testing">测试</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted } from 'vue'
|
||
import { aiModelApi } from '@/api'
|
||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||
|
||
const loading = ref(false)
|
||
const saving = ref(false)
|
||
const testing = ref(false)
|
||
const modelList = ref([])
|
||
const showAddDialog = ref(false)
|
||
const showModelDialog = ref(false)
|
||
const showTestDialog = ref(false)
|
||
const isEdit = ref(false)
|
||
const currentModelId = ref(null)
|
||
const testPrompt = ref('')
|
||
|
||
const modelForm = ref({
|
||
display_name: '',
|
||
model_name: '',
|
||
provider: '',
|
||
api_url: '',
|
||
api_key: '',
|
||
temperature: 0.7,
|
||
max_tokens: 1000,
|
||
is_default: false,
|
||
is_active: true
|
||
})
|
||
|
||
const testData = ref({})
|
||
|
||
// 加载数据
|
||
const loadData = async () => {
|
||
loading.value = true
|
||
try {
|
||
const res = await aiModelApi.getList()
|
||
modelList.value = res || []
|
||
} catch (error) {
|
||
console.error('Load AI models error:', error)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 添加/编辑
|
||
const handleAdd = () => {
|
||
isEdit.value = false
|
||
modelForm.value = {
|
||
display_name: '',
|
||
model_name: '',
|
||
provider: '',
|
||
api_url: '',
|
||
api_key: '',
|
||
temperature: 0.7,
|
||
max_tokens: 1000,
|
||
is_default: false,
|
||
is_active: true
|
||
}
|
||
showModelDialog.value = true
|
||
}
|
||
|
||
const handleEdit = (row) => {
|
||
isEdit.value = true
|
||
currentModelId.value = row.id
|
||
modelForm.value = { ...row }
|
||
showModelDialog.value = true
|
||
}
|
||
|
||
// 提交
|
||
const handleSubmit = async () => {
|
||
saving.value = true
|
||
try {
|
||
if (isEdit.value) {
|
||
await aiModelApi.update(currentModelId.value, modelForm.value)
|
||
ElMessage.success('更新成功')
|
||
} else {
|
||
await aiModelApi.create(modelForm.value)
|
||
ElMessage.success('创建成功')
|
||
}
|
||
showModelDialog.value = false
|
||
loadData()
|
||
} catch (error) {
|
||
console.error('Save model error:', error)
|
||
} finally {
|
||
saving.value = false
|
||
}
|
||
}
|
||
|
||
// 删除
|
||
const handleDelete = (row) => {
|
||
ElMessageBox.confirm('确定要删除此模型配置吗?', '警告', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(async () => {
|
||
try {
|
||
await aiModelApi.delete(row.id)
|
||
ElMessage.success('删除成功')
|
||
loadData()
|
||
} catch (error) {
|
||
console.error('Delete model error:', error)
|
||
}
|
||
})
|
||
}
|
||
|
||
// 测试
|
||
const handleTest = (row) => {
|
||
currentModelId.value = row.id
|
||
testPrompt.value = '请写一条简短的评论'
|
||
showTestDialog.value = true
|
||
}
|
||
|
||
const handleRunTest = async () => {
|
||
testing.value = true
|
||
try {
|
||
const res = await aiModelApi.test({
|
||
model_id: currentModelId.value,
|
||
test_prompt: testPrompt.value
|
||
})
|
||
|
||
testData.value = res
|
||
|
||
if (res.success) {
|
||
ElMessage.success(`测试成功!消耗 ${res.tokens_used} tokens`)
|
||
console.log('Test result:', res.content)
|
||
} else {
|
||
ElMessage.error(`测试失败:${res.error_message}`)
|
||
}
|
||
} catch (error) {
|
||
console.error('Test model error:', error)
|
||
} finally {
|
||
testing.value = false
|
||
}
|
||
}
|
||
|
||
const getProviderLabel = (provider) => {
|
||
const map = { openai: 'OpenAI', zhipu: '智谱 AI', baidu: '百度文心', aliyun: '阿里通义' }
|
||
return map[provider] || provider
|
||
}
|
||
|
||
onMounted(() => {
|
||
loadData()
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.ai-models {
|
||
padding: 20px;
|
||
}
|
||
|
||
.card-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
</style>
|