| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507 |
- <template>
- <div class="model-detail-root">
- <!-- 面包屑导航 -->
- <el-breadcrumb separator="/" class="model-breadcrumb">
- <el-breadcrumb-item>市场模型</el-breadcrumb-item>
- <el-breadcrumb-item>模型详情</el-breadcrumb-item>
- </el-breadcrumb>
- <div class="model-top-right-btns">
- <el-button type="plain" size="small" @click="returnModel" class="custom-button">
- <el-icon ><ArrowLeft /></el-icon>
- 返回列表
- </el-button>
- <el-button type="plain" size="small" class="custom-button">
- <el-icon><Refresh /></el-icon>
- 刷新
- </el-button>
- <el-button type="primary" size="small" class="custom-button">
- <el-icon><Edit /></el-icon>
- 编辑
- </el-button>
- <el-button type="danger" size="small" class="custom-button">
- <el-icon><SwitchButton /></el-icon>
- 禁用
- </el-button>
- </div>
- <!-- 顶部信息区(单卡片,左右分布) -->
- <el-card class="model-top-card" shadow="never">
- <div class="model-top-flex">
- <!-- 左侧基本信息 -->
- <div class="model-top-left">
- <div class="model-top-title">基本信息</div>
- <div class="model-top-row">
- <span class="model-top-label">模型名称:</span>
- <span class="model-top-value">GPT-4{{model?.modelName}}</span>
- </div>
- <div class="model-top-row">
- <span class="model-top-label">模型类型:</span>
- <span class="model-top-value">大语言模型(LLM){{model?.modelType}}</span>
- </div>
- <div class="model-top-row">
- <span class="model-top-label">模型版本:</span>
- <span class="model-top-value">gpt-4-1106-preview{{model?.modelVersion}}</span>
- </div>
- <div class="model-top-row">
- <span class="model-top-label">状态:</span>
- <el-tag type="success" size="small" v-if="model?.status===1">启用</el-tag>
- <el-tag type="warning" size="small" v-else-if="model?.status === 0">测试中</el-tag>
- </div>
- <div class="model-top-row">
- <span class="model-top-label">API地址:</span>
- <a class="model-top-link" href="https://api.openai.com/v1/chat/completions" target="_blank">https://api.openai.com/v1/chat/completions{{model?.baseUrl}}</a>
- </div>
- <div class="model-top-row">
- <span class="model-top-label">描述:</span>
- <span class="model-top-value">{{model?.description}}GPT-4是OpenAI最先进的大型语言模型,在各种专业和学术基准上表现最佳。相比GPT-3.5,GPT-4在创造性写作、编码和解决复杂问题方面表现出显著提升,能更好地遵循用户意图,理解和生成更长的内容。</span>
- </div>
- </div>
- <!-- 右侧服务信息和按钮 -->
- <div class="model-top-right">
- <div class="model-top-right-info">
- <div style="display: flex"><span class="model-top-label">服务商:</span>  OpenAI</div>
- <div style="display: flex"><span class="model-top-label">优先级:</span>  90{{model?.priority}}</div>
- <div style="display: flex"><span class="model-top-label">创建时间:</span>  2025-05-15 10:30:15{{model?.createTime}}</div>
- <div style="display: flex"><span class="model-top-label">更新时间:</span>  2025-06-20 14:45:30{{model?.updateTime}}</div>
- </div>
- </div>
- </div>
- </el-card>
- <!-- 参数配置 -->
- <el-card class="model-section-card">
- <div class="model-section-title">
- <span>参数配置</span>
- <el-button type="primary" size="small" class="model-btn-add">+ 添加参数</el-button>
- </div>
- <el-table :data="tableData" class="model-param-table" border header-cell-class-name="model-th" cell-class-name="model-td">
- <el-table-column prop="name" label="参数名称" align="center" min-width="120" />
- <el-table-column prop="type" label="参数类型" align="center" min-width="120" />
- <el-table-column prop="defaultValue" label="默认值" align="center" min-width="100" />
- <el-table-column prop="isRequired" label="是否必需" align="center" min-width="100" />
- <el-table-column prop="description" label="描述" min-width="200" />
- <el-table-column label="操作" align="center" min-width="100">
- <template #default="scope">
- <el-button @click="handleEdit(scope.$index, scope.row)" type="text" size="small">编辑</el-button>
- <el-button @click="handleDelete(scope.$index, scope.row)" type="text" size="small">删除</el-button>
- </template>
- </el-table-column>
- </el-table>
- </el-card>
- <!-- 抽屉 -->
- <el-drawer
- v-model="drawerVisible"
- direction="rtl"
- size="40%"
- class="drawer-style"
- >
- <template #header="{close,titleId,titleClass}">
- <h2 :id="titleId" style="color:#000000">编辑参数</h2>
- </template>
- <div >
- <h4>模型</h4>
- <el-card class="model-card" style=" background:#F5F5F5;">
- GPT-4 (OpenAI)<br/>
- <span style="color: #777777">版本: gpt-4-1106-preview</span>
- </el-card>
- <h4>快速添加参数模板</h4>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-card class="center-content" style="height: 150px;background: #FAFAFA" >
- <div>OpenAI Chat模板</div>
- <div style="color: #777777">6个参数</div>
- </el-card>
- </el-col>
- <el-col :span="12">
- <el-card class="center-content"style="background: #FAFAFA">
- <div>OpenAI Embedding模板</div>
- <div style="color: #777777">三个参数</div>
- </el-card>
- </el-col>
- </el-row>
- <h4>参数列表</h4>
- <div v-for="(item, index) in tableData" :key="index" class="parameter-card">
- <el-card shadow="never" style="background-color: #FAFAFA" >
- <div class="card-content">
- <div class="param-name">{{ item.name }} <span style="color: #777777">{{item.type}}</span></div>
- <div class="actions" style="display: flex">
- <el-button @click="handleEdit(index, item)" type="text" size="small" ></el-button>
- <el-button @click="handleDelete(index, item)" type="text" size="small"style="margin-left:auto" ><el-icon color="red"><DeleteFilled /></el-icon></el-button>
- </div>
- </div>
- </el-card>
- </div>
- <el-card style="display: flex;justify-content: center; align-items: center; flex-direction: column;" :body-style="{padding:'1px'}">
- <el-button @click="addParameter" type="plain" >添加参数</el-button>
- </el-card>
- <div style="text-align: right; margin-top: 20px;">
- <el-button @click="drawerVisible = false">取消</el-button>
- <el-button @click="saveEdit" type="primary">保存</el-button>
- </div>
- </div>
- </el-drawer>
- <!-- 调用统计 -->
- <el-row :gutter="20" class="model-stat-row">
- <el-col :span="6" v-for="(item, idx) in statList" :key="item.label">
- <el-card class="model-stat-card" shadow="never">
- <div class="model-stat-label">{{ item.label }}</div>
- <div class="model-stat-value">{{ item.value }}</div>
- <div :class="['model-stat-trend', item.trend > 0 ? 'up' : 'down']">
- <span v-if="item.trend > 0">↑ {{ item.trend }}% 较上月</span>
- <span v-else>↓ {{ Math.abs(item.trend) }}% 较上月</span>
- </div>
- </el-card>
- </el-col>
- <div class="model-stat-select">
- <el-select v-model="statRange" size="small" style="width: 80px">
- <el-option label="本月" value="month" />
- <el-option label="本年" value="year" />
- </el-select>
- </div>
- </el-row>
- <!-- 调用趋势 -->
- <el-card class="model-section-card model-chart-section">
- <div class="model-chart-title">调用趋势</div>
- <div id="callTrendChart" style="width: 100%; height: 320px;"></div>
- <div class="model-chart-footer">调用趋势曲线数据</div>
- </el-card>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, onMounted } from 'vue'
- import * as echarts from 'echarts'
- import { ArrowLeft, Refresh } from '@element-plus/icons-vue';
- import { useRoute,useRouter } from 'vue-router';
- import { ModelConfigVo} from '@/api/modelConfig/types'
- import {toggleStatus} from '@/api/modelConfig/index.js'
- const route = useRoute()
- const router = useRouter()
- const model = ref<ModelConfigVo>(route.query.model)
- // 表格数据
- const tableData = ref([
- { name: 'temperature', type: 'NUMBER', defaultValue: '0.7', isRequired: '否', description: '控制生成文本的随机性,值越小结果越随机' },
- { name: 'max_tokens', type: 'NUMBER', defaultValue: '1024', isRequired: '否', description: '生成文本的最大令牌数' },
- { name: 'top_p', type: 'NUMBER', defaultValue: '0.95', isRequired: '否', description: '核采样阈值,控制模型选择词的概率分布' },
- { name: 'frequency_penalty', type: 'NUMBER', defaultValue: '0', isRequired: '否', description: '减少重复词组的出现概率' },
- { name: 'presence_penalty', type: 'NUMBER', defaultValue: '0', isRequired: '否', description: '增加新话题出现的概率' },
- { name: 'stream', type: 'BOOLEAN', defaultValue: 'false', isRequired: '否', description: '是否启用流式输出' }
- ])
- // 统计卡片数据
- const statList = ref([
- { label: '调用次数', value: '156,783', trend: 12.5 },
- { label: '平均响应时间', value: '1.68s', trend: -0.2 },
- { label: '成功率', value: '99.87%', trend: 0.05 },
- { label: 'Token消耗', value: '5.6M', trend: 18.3 }
- ])
- // 其他响应式数据
- const statRange = ref('month')
- const drawerVisible = ref(false)
- const currentRow = ref({})
- const currentRowIndex = ref(-1)
- // 生命周期钩子
- onMounted(() => {
- initCallTrendChart()
- })
- // 方法
- const handleEdit = (index, row) => {
- currentRowIndex.value = index
- currentRow.value = { ...row }
- drawerVisible.value = true
- }
- const handleDelete = (index) => {
- tableData.value.splice(index, 1)
- }
- const saveEdit = () => {
- tableData.value[currentRowIndex.value] = { ...currentRow.value }
- drawerVisible.value = false
- }
- const returnModel = () => {
- router.push('/modelMarket')
- }
- const initCallTrendChart = () => {
- const callTrendChart = echarts.init(document.getElementById('callTrendChart'))
- const option = {
- tooltip: {},
- xAxis: {
- type: 'category',
- data: ['1月', '2月', '3月', '4月', '5月', '6月'],
- axisLine: { lineStyle: { color: '#e5e6eb' } },
- axisLabel: { color: '#888' },
- },
- yAxis: {
- type: 'value',
- axisLine: { lineStyle: { color: '#e5e6eb' } },
- splitLine: { lineStyle: { color: '#f0f0f0' } },
- axisLabel: { color: '#888' },
- },
- series: [
- {
- data: [120, 200, 150, 80, 70, 110],
- type: 'bar',
- name: '调用次数',
- itemStyle: { color: '#409EFF', borderRadius: [4, 4, 0, 0] },
- barWidth: 24,
- },
- ],
- grid: { left: 40, right: 20, top: 30, bottom: 30 },
- }
- callTrendChart.setOption(option)
- }
- </script>
- <style scoped>
- .actions{
- display: flex;
- }
- .drawer-style{
- header.el-drawer__header{
- margin-bottom: 0 !important;
- }
- }
- :deep(header.el-drawer__header){
- margin-bottom: 0 !important;
- }
- /* 确保图标靠右对齐 */
- .parameter-card {
- margin-bottom: 0;
- }
- .card-content {
- display: flex;
- justify-content: space-between;
- width: 100%;
- }
- .param-name {
- font-size: 14px;
- color: #606266;
- }
- .center-content {
- display: flex;
- justify-content: center; /* 水平居中 */
- align-items: center; /* 垂直居中 */
- height: 100%; /* 确保容器有足够的高度 */
- }
- .model-detail-root {
- background: #f7f8fa;
- min-height: 100vh;
- padding: 0 24px 24px 24px;
- }
- .model-breadcrumb {
- margin: 18px 0 8px 0;
- }
- .model-top-card {
- border-radius: 10px;
- border: 1px solid #e5e6eb;
- background: #fff;
- box-shadow: none;
- padding: 0 32px 0 32px;
- margin-bottom: 24px;
- }
- .model-top-flex {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- align-items: flex-start;
- min-height: 160px;
- padding: 24px 0 18px 0;
- }
- .model-top-left {
- flex: 1.5;
- display: flex;
- flex-direction: column;
- justify-content: flex-start;
- gap: 20px;
- }
- .model-top-title {
- font-size: 16px;
- font-weight: 600;
- margin-bottom: 12px;
- }
- .model-top-row {
- display: flex;
- align-items: center;
- font-size: 13px;
- margin-bottom: 4px;
- gap: 20px;
- }
- .model-top-label {
- color: #888;
- min-width: 80px;
- margin-right: 2px;
- }
- .model-top-value {
- color: #222;
- margin-right: 24px;
- word-break: break-all;
- }
- .model-top-link {
- color: #409eff;
- text-decoration: underline;
- }
- .model-top-right {
- flex: 1;
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- justify-content: space-between;
- min-width: 360px;
- margin-left: 32px;
- margin-right: 32px;
- gap: 30px;
- }
- .model-top-right-info {
- color: #222;
- font-size: 13px;
- margin-bottom: 0;
- text-align: left;
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- justify-content: center;
- flex: 1;
- min-width: 180px;
- gap: 20px;
- }
- .model-top-right-btns {
- display: flex;
- flex-direction: row;
- gap:0.1px;
- margin-top: 0;
- align-items: flex-start;
- justify-content: flex-end;
- }
- .model-section-card {
- border-radius: 10px;
- border: 1px solid #e5e6eb;
- background: #fff;
- box-shadow: none;
- margin-top: 24px;
- padding: 0 0 18px 0;
- }
- .model-section-title {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 0 24px;
- font-size: 15px;
- font-weight: 500;
- height: 48px;
- background: #fff;
- border-bottom: 1px solid #f0f0f0;
- }
- .model-btn-add {
- min-width: 90px;
- margin-top: 0;
- align-self: flex-start;
- }
- .model-param-table {
- margin: 0 24px 0 24px;
- font-size: 13px;
- --el-table-border-color: #e5e6eb;
- --el-table-header-bg-color: #f7f8fa;
- --el-table-header-text-color: #888;
- --el-table-row-hover-bg-color: #f5f7fa;
- }
- .model-th {
- background: #f7f8fa !important;
- color: #888 !important;
- font-weight: 500 !important;
- height: 38px !important;
- }
- .model-td {
- height: 38px !important;
- padding: 0 8px !important;
- }
- .model-stat-row {
- margin-top: 24px;
- margin-bottom: 0;
- position: relative;
- }
- .model-stat-card {
- border-radius: 10px;
- border: 1px solid #e5e6eb;
- background: #fff;
- box-shadow: none;
- min-height: 100px;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: flex-start;
- padding: 18px 0 12px 24px;
- }
- .model-stat-label {
- color: #888;
- font-size: 13px;
- margin-bottom: 2px;
- }
- .model-stat-value {
- font-size: 22px;
- font-weight: 600;
- color: #222;
- margin: 2px 0 2px 0;
- }
- .model-stat-trend {
- font-size: 12px;
- margin-top: 2px;
- }
- .model-stat-trend.up {
- color: #67c23a;
- }
- .model-stat-trend.down {
- color: #f56c6c;
- }
- .model-stat-select {
- position: absolute;
- right: 24px;
- top: 0;
- }
- .model-chart-section {
- margin-top: 24px;
- padding: 0 0 18px 0;
- }
- .model-chart-title {
- font-size: 15px;
- font-weight: 500;
- color: #222;
- margin-bottom: 8px;
- padding-left: 24px;
- padding-top: 18px;
- }
- .model-chart-footer {
- color: #bfbfbf;
- font-size: 12px;
- text-align: right;
- margin-top: 8px;
- padding-right: 24px;
- }
- </style>
|