Janus-Pro-7B结合Vue前端框架:构建现代化AI管理平台

news2026/4/12 8:18:03
Janus-Pro-7B结合Vue前端框架构建现代化AI管理平台最近在折腾一个AI模型管理平台后台用的是性能不错的Janus-Pro-7B前端选来选去还是决定用Vue。原因很简单Vue的生态成熟上手快组件库丰富特别适合做这种需要快速迭代、界面交互复杂的后台管理系统。今天这篇文章我就结合自己的实践经验聊聊怎么用Vue给Janus-Pro-7B模型搭一个既好看又好用的管理前台。这个平台不仅能让你方便地测试模型、查看生成结果还能监控模型运行状态算是一个比较完整的实战案例。我会从前端工程化搭建讲起到状态管理、数据可视化最后再聊聊怎么和模型的后端API顺畅对接。如果你也在考虑为你的大模型项目做一个管理界面或者想学习如何将现代前端框架与AI服务结合那这篇文章应该能给你一些实用的参考。1. 项目规划与技术选型在动手写代码之前先得把项目想清楚。我们这个平台的核心目标是让使用者可能是算法工程师、产品经理或者运营同学能在一个统一的界面上完成对Janus-Pro-7B模型的各项操作。核心功能模块模型测试与对话提供一个类似ChatGPT的交互界面可以输入文本实时获取模型的生成结果。历史记录与管理保存每次的对话或生成任务支持按时间、内容搜索和回看。性能监控面板用图表展示模型的响应时间、Token消耗、请求成功率等关键指标。系统配置与管理管理模型API的端点、密钥以及一些前端显示相关的设置。基于这些功能我们选择了以下技术栈前端框架Vue 3 Composition API。Vue 3的响应式系统更高效Composition API让逻辑组织更清晰特别适合我们这种状态复杂的管理后台。构建工具Vite。启动和热更新速度飞快开发体验极佳。UI组件库Element Plus。它基于Vue 3组件丰富、设计成熟能极大减少我们写基础组件的时间。状态管理Pinia。这是Vue官方推荐的状态管理库比Vuex更简单直观TypeScript支持也好。HTTP客户端Axios。处理API请求的老牌选择拦截器、错误处理都很方便。图表可视化ECharts。功能强大图表类型丰富社区活跃能满足我们各种监控图表的需求。路由Vue Router。管理我们平台内的页面跳转。这个组合算是目前Vue生态里比较主流和稳健的选择社区资源多遇到问题也容易找到解决方案。2. 前端工程化与项目初始化万事开头难但用现在的工具链初始化一个Vue项目已经变得非常简单了。我们一步步来。首先打开终端用Vite官方模板创建一个新项目npm create vuelatest janus-pro-manager创建过程中命令行会交互式地让你选择一些特性。对于我们的项目我建议这样选TypeScript选择Yes。类型检查能在开发阶段就避免很多低级错误让代码更健壮。JSX选择No。我们主要用单文件组件.vue暂时用不到JSX。Vue Router选择Yes。我们需要多页面路由。Pinia选择Yes。用于状态管理。ESLint选择Yes。保持代码风格统一。Prettier选择Yes。自动格式化代码。项目创建好后进入目录安装我们选定的UI库和图表库cd janus-pro-manager npm install element-plus element-plus/icons-vue npm install echarts vue-echarts npm install axios npm install接下来我们需要做一些基础配置。在main.ts或main.js中全局引入Element Plus和它的图标库// main.ts import { createApp } from vue import { createPinia } from pinia import ElementPlus from element-plus import * as ElementPlusIconsVue from element-plus/icons-vue import element-plus/dist/index.css import App from ./App.vue import router from ./router const app createApp(App) // 注册所有Element Plus图标 for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component) } app.use(createPinia()) app.use(router) app.use(ElementPlus) app.mount(#app)然后我们规划一下项目的目录结构。一个清晰的结构能让后续开发维护省心很多src/ ├── api/ # 所有与后端API交互的接口函数 ├── assets/ # 静态资源图片、样式 ├── components/ # 公共组件 ├── composables/ # 可组合函数Vue 3的hooks ├── router/ # 路由配置 ├── stores/ # Pinia状态仓库 ├── types/ # TypeScript类型定义 ├── utils/ # 工具函数 ├── views/ # 页面级组件 │ ├── Dashboard.vue # 监控仪表盘 │ ├── Chat.vue # 模型测试对话页 │ ├── History.vue # 历史记录页 │ └── Settings.vue # 设置页 └── App.vue这样一个具备现代化前端工程化特征的项目骨架就搭好了。接下来我们开始填充血肉。3. 核心功能模块实现平台的功能主要围绕几个页面展开。我们先从最核心的模型对话界面开始。3.1 模型测试与对话界面这个界面是用户使用最频繁的地方核心是一个聊天窗口。我们创建一个Chat.vue组件。首先在stores/目录下创建一个Pinia store来管理对话状态// stores/chat.ts import { defineStore } from pinia import { ref } from vue import type { ChatMessage } from /types/chat export const useChatStore defineStore(chat, () { // 当前对话的消息列表 const messages refChatMessage[]([ { id: 1, role: assistant, content: 你好我是Janus-Pro-7B模型有什么可以帮您, timestamp: new Date() } ]) // 用户输入的文本 const inputText ref() // 是否正在加载等待模型响应 const isLoading ref(false) // 发送消息给模型 async function sendMessage() { if (!inputText.value.trim() || isLoading.value) return const userMessage: ChatMessage { id: Date.now(), role: user, content: inputText.value, timestamp: new Date() } messages.value.push(userMessage) const currentInput inputText.value inputText.value isLoading.value true try { // 这里调用我们后面会定义的API函数 const response await chatWithModel(currentInput) const assistantMessage: ChatMessage { id: Date.now() 1, role: assistant, content: response.content, timestamp: new Date() } messages.value.push(assistantMessage) } catch (error) { console.error(对话失败:, error) // 可以在这里添加错误提示比如用Element Plus的ElMessage组件 } finally { isLoading.value false } } // 清空对话历史 function clearHistory() { messages.value [ { id: 1, role: assistant, content: 对话历史已清空。有什么可以帮您, timestamp: new Date() } ] } return { messages, inputText, isLoading, sendMessage, clearHistory } })然后在api/目录下创建与后端Janus-Pro-7B模型API交互的模块// api/model.ts import axios from axios // 创建axios实例配置基础URL和超时时间 const modelApi axios.create({ baseURL: import.meta.env.VITE_MODEL_API_BASEURL || http://localhost:8000, timeout: 60000 // 模型生成可能需要较长时间 }) // 请求拦截器可以在这里添加认证token等 modelApi.interceptors.request.use(config { const token localStorage.getItem(api_token) if (token) { config.headers.Authorization Bearer ${token} } return config }) // 响应拦截器统一处理错误 modelApi.interceptors.response.use( response response.data, error { console.error(API请求错误:, error) return Promise.reject(error) } ) // 与模型对话的接口 export async function chatWithModel(prompt: string, options?: any) { return modelApi.post(/v1/chat/completions, { model: janus-pro-7b, messages: [{ role: user, content: prompt }], stream: false, // 我们先实现非流式流式后续可以升级 ...options }) } // 获取模型信息 export async function getModelInfo() { return modelApi.get(/v1/models) }有了状态管理和API层我们的Chat.vue组件就可以专注于视图和交互了!-- views/Chat.vue -- template div classchat-container el-card classchat-card template #header div classcard-header spanJanus-Pro-7B 模型测试/span el-button typedanger :iconDelete clickclearChat sizesmall清空对话/el-button /div /template !-- 消息展示区域 -- div classmessages-area refmessagesRef div v-formsg in chatStore.messages :keymsg.id classmessage-item :classmsg.role div classavatar el-avatar :iconmsg.role user ? User : Robot / /div div classmessage-content div classmessage-role{{ msg.role user ? 我 : Janus-Pro-7B }}/div div classmessage-text{{ msg.content }}/div div classmessage-time{{ formatTime(msg.timestamp) }}/div /div /div div v-ifchatStore.isLoading classloading-indicator el-icon classis-loadingLoading //el-icon span模型正在思考中.../span /div /div !-- 输入区域 -- div classinput-area el-input v-modelchatStore.inputText typetextarea :rows3 placeholder输入您的问题或指令... keydown.enter.exact.preventhandleSend :disabledchatStore.isLoading / div classinput-actions el-button typeprimary :iconPromotion clickhandleSend :loadingchatStore.isLoading :disabled!chatStore.inputText.trim() 发送 /el-button el-tooltip content按Enter发送ShiftEnter换行 el-iconInfoFilled //el-icon /el-tooltip /div /div /el-card /div /template script setup langts import { onMounted, ref, nextTick } from vue import { useChatStore } from /stores/chat import { Delete, User, Robot, Promotion, Loading, InfoFilled } from element-plus/icons-vue import { formatTime } from /utils/date const chatStore useChatStore() const messagesRef refHTMLElement() // 发送消息 const handleSend () { chatStore.sendMessage() // 发送后滚动到底部 nextTick(() { scrollToBottom() }) } // 清空对话 const clearChat () { chatStore.clearHistory() } // 滚动到消息区域底部 const scrollToBottom () { if (messagesRef.value) { messagesRef.value.scrollTop messagesRef.value.scrollHeight } } // 组件挂载时自动滚动到底部 onMounted(() { scrollToBottom() }) /script style scoped .chat-container { height: calc(100vh - 100px); padding: 20px; } .chat-card { height: 100%; display: flex; flex-direction: column; } .card-header { display: flex; justify-content: space-between; align-items: center; } .messages-area { flex: 1; overflow-y: auto; padding: 20px; border-bottom: 1px solid #eee; margin-bottom: 20px; } .message-item { display: flex; margin-bottom: 20px; } .message-item.user { flex-direction: row-reverse; } .message-item.user .message-content { align-items: flex-end; margin-right: 12px; } .message-item.assistant .message-content { margin-left: 12px; } .avatar { flex-shrink: 0; } .message-content { max-width: 70%; display: flex; flex-direction: column; } .message-role { font-size: 12px; color: #666; margin-bottom: 4px; } .message-text { background: #f5f7fa; padding: 12px 16px; border-radius: 8px; line-height: 1.5; white-space: pre-wrap; } .user .message-text { background: #409eff; color: white; } .message-time { font-size: 12px; color: #999; margin-top: 4px; } .loading-indicator { display: flex; align-items: center; gap: 8px; color: #666; padding: 12px; } .input-area { display: flex; flex-direction: column; gap: 12px; } .input-actions { display: flex; justify-content: flex-end; align-items: center; gap: 12px; } /style这样一个基础的对话界面就完成了。它包含了消息展示、输入发送、加载状态、清空历史等核心功能界面也还算美观。3.2 监控仪表盘实现管理平台另一个重要功能是监控。我们需要一个仪表盘来展示模型的使用情况、性能指标等。这里我们用ECharts来绘制图表。首先创建一个用于监控的Pinia store// stores/monitor.ts import { defineStore } from vue import { ref } from vue import type { MetricData } from /types/monitor export const useMonitorStore defineStore(monitor, () { // 响应时间数据示例数据 const responseTimeData refMetricData[]([ { time: 09:00, value: 1.2 }, { time: 10:00, value: 1.5 }, { time: 11:00, value: 1.1 }, { time: 12:00, value: 2.0 }, { time: 13:00, value: 1.8 }, { time: 14:00, value: 1.3 }, { time: 15:00, value: 1.4 }, ]) // 请求量数据 const requestCountData refMetricData[]([ { time: 09:00, value: 120 }, { time: 10:00, value: 180 }, { time: 11:00, value: 220 }, { time: 12:00, value: 150 }, { time: 13:00, value: 190 }, { time: 14:00, value: 210 }, { time: 15:00, value: 240 }, ]) // 今日统计 const todayStats ref({ totalRequests: 1310, avgResponseTime: 1.5s, successRate: 99.2%, tokenUsage: 45.8K }) // 模拟从API获取最新监控数据 async function fetchMonitorData() { // 这里实际应该调用后端监控API // 暂时用模拟数据 console.log(获取监控数据...) } return { responseTimeData, requestCountData, todayStats, fetchMonitorData } })然后创建一个Dashboard.vue组件使用ECharts渲染图表!-- views/Dashboard.vue -- template div classdashboard h2模型监控仪表盘/h2 !-- 今日概览卡片 -- el-row :gutter20 classstats-row el-col :xs24 :sm12 :md6 v-forstat in statItems :keystat.title el-card shadowhover classstat-card div classstat-content div classstat-icon :style{ backgroundColor: stat.color } el-icon :size24component :isstat.icon //el-icon /div div classstat-info div classstat-value{{ stat.value }}/div div classstat-title{{ stat.title }}/div /div /div /el-card /el-col /el-row !-- 图表区域 -- el-row :gutter20 classcharts-row el-col :xs24 :lg12 el-card classchart-card template #header span模型响应时间趋势秒/span /template div refresponseTimeChartRef styleheight: 300px;/div /el-card /el-col el-col :xs24 :lg12 el-card classchart-card template #header span请求量趋势/span /template div refrequestChartRef styleheight: 300px;/div /el-card /el-col /el-row !-- 最近请求记录 -- el-card classrecent-card template #header span最近请求记录/span /template el-table :datarecentRequests stylewidth: 100% el-table-column proptime label时间 width180 / el-table-column propendpoint label接口 / el-table-column propstatus label状态 width100 template #defaultscope el-tag :typescope.row.status 成功 ? success : danger sizesmall {{ scope.row.status }} /el-tag /template /el-table-column el-table-column propduration label耗时 width100 / el-table-column proptokens labelTokens width100 / /el-table /el-card /div /template script setup langts import { onMounted, ref, computed } from vue import { useMonitorStore } from /stores/monitor import * as echarts from echarts import type { ECharts } from echarts import { Clock, TrendCharts, Check, DataLine } from element-plus/icons-vue const monitorStore useMonitorStore() const responseTimeChartRef refHTMLElement() const requestChartRef refHTMLElement() let responseTimeChart: ECharts | null null let requestChart: ECharts | null null // 今日统计卡片数据 const statItems computed(() [ { title: 总请求数, value: monitorStore.todayStats.totalRequests.toLocaleString(), icon: DataLine, color: #409eff }, { title: 平均响应时间, value: monitorStore.todayStats.avgResponseTime, icon: Clock, color: #67c23a }, { title: 成功率, value: monitorStore.todayStats.successRate, icon: Check, color: #e6a23c }, { title: Token使用量, value: monitorStore.todayStats.tokenUsage, icon: TrendCharts, color: #f56c6c } ]) // 最近请求记录模拟数据 const recentRequests [ { time: 2024-01-15 14:30:22, endpoint: /v1/chat/completions, status: 成功, duration: 1.2s, tokens: 256 }, { time: 2024-01-15 14:28:15, endpoint: /v1/chat/completions, status: 成功, duration: 1.5s, tokens: 189 }, { time: 2024-01-15 14:25:43, endpoint: /v1/models, status: 成功, duration: 0.1s, tokens: - }, { time: 2024-01-15 14:22:10, endpoint: /v1/chat/completions, status: 失败, duration: 3.0s, tokens: 0 }, { time: 2024-01-15 14:20:05, endpoint: /v1/chat/completions, status: 成功, duration: 1.8s, tokens: 312 }, ] // 初始化响应时间图表 const initResponseTimeChart () { if (!responseTimeChartRef.value) return responseTimeChart echarts.init(responseTimeChartRef.value) const option { tooltip: { trigger: axis }, xAxis: { type: category, data: monitorStore.responseTimeData.map(item item.time) }, yAxis: { type: value, name: 秒 }, series: [{ data: monitorStore.responseTimeData.map(item item.value), type: line, smooth: true, lineStyle: { color: #409eff }, areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: rgba(64, 158, 255, 0.3) }, { offset: 1, color: rgba(64, 158, 255, 0.1) } ]) } }], grid: { left: 3%, right: 4%, bottom: 3%, containLabel: true } } responseTimeChart.setOption(option) } // 初始化请求量图表 const initRequestChart () { if (!requestChartRef.value) return requestChart echarts.init(requestChartRef.value) const option { tooltip: { trigger: axis }, xAxis: { type: category, data: monitorStore.requestCountData.map(item item.time) }, yAxis: { type: value, name: 次数 }, series: [{ data: monitorStore.requestCountData.map(item item.value), type: bar, itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: #83bff6 }, { offset: 0.5, color: #188df0 }, { offset: 1, color: #188df0 } ]) } }], grid: { left: 3%, right: 4%, bottom: 3%, containLabel: true } } requestChart.setOption(option) } // 监听窗口大小变化重绘图表 const handleResize () { responseTimeChart?.resize() requestChart?.resize() } onMounted(() { initResponseTimeChart() initRequestChart() window.addEventListener(resize, handleResize) // 模拟定时更新数据 setInterval(() { // 在实际项目中这里应该调用API获取最新数据 // monitorStore.fetchMonitorData() // 然后更新图表 // responseTimeChart?.setOption({...}) }, 30000) }) // 组件卸载时清理 onUnmounted(() { window.removeEventListener(resize, handleResize) responseTimeChart?.dispose() requestChart?.dispose() }) /script style scoped .dashboard { padding: 20px; } .stats-row { margin-bottom: 20px; } .stat-card { margin-bottom: 20px; } .stat-content { display: flex; align-items: center; gap: 16px; } .stat-icon { width: 48px; height: 48px; border-radius: 8px; display: flex; align-items: center; justify-content: center; color: white; } .stat-info { flex: 1; } .stat-value { font-size: 24px; font-weight: bold; margin-bottom: 4px; } .stat-title { font-size: 14px; color: #666; } .charts-row { margin-bottom: 20px; } .chart-card { margin-bottom: 20px; } .recent-card { margin-top: 20px; } /style这样我们就有了一个功能完整的监控仪表盘包含统计卡片、趋势图表和最近请求记录表格。3.3 路由与布局配置有了各个页面组件我们需要用Vue Router把它们组织起来并创建一个统一的布局。首先配置路由// router/index.ts import { createRouter, createWebHistory } from vue-router import Layout from /layouts/Layout.vue const router createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: /, component: Layout, redirect: /dashboard, children: [ { path: dashboard, name: Dashboard, component: () import(/views/Dashboard.vue), meta: { title: 仪表盘, icon: DataBoard } }, { path: chat, name: Chat, component: () import(/views/Chat.vue), meta: { title: 模型测试, icon: ChatRound } }, { path: history, name: History, component: () import(/views/History.vue), meta: { title: 历史记录, icon: Document } }, { path: settings, name: Settings, component: () import(/views/Settings.vue), meta: { title: 系统设置, icon: Setting } } ] } ] }) export default router然后创建一个布局组件包含侧边栏导航和顶部栏!-- layouts/Layout.vue -- template div classlayout-container !-- 侧边栏 -- el-aside :widthisCollapse ? 64px : 200px classsidebar div classlogo span v-if!isCollapseJanus-Pro Manager/span el-icon v-elseMonitor //el-icon /div el-menu :default-activeactiveMenu :collapseisCollapse router background-color#304156 text-color#bfcbd9 active-text-color#409eff el-menu-item v-forroute in menuRoutes :keyroute.path :indexroute.path el-iconcomponent :isroute.meta?.icon //el-icon template #title{{ route.meta?.title }}/template /el-menu-item /el-menu /el-aside !-- 主内容区 -- div classmain-container !-- 顶部栏 -- el-header classheader div classheader-left el-button :iconisCollapse ? Expand : Fold clicktoggleCollapse text sizesmall / el-breadcrumb separator/ el-breadcrumb-item v-foritem in breadcrumbs :keyitem.path {{ item.meta?.title }} /el-breadcrumb-item /el-breadcrumb /div div classheader-right el-dropdown span classuser-info el-avatar :size32 :iconUserFilled / span classusername管理员/span /span template #dropdown el-dropdown-menu el-dropdown-item个人中心/el-dropdown-item el-dropdown-item divided退出登录/el-dropdown-item /el-dropdown-menu /template /el-dropdown /div /el-header !-- 页面内容 -- div classcontent router-view / /div /div /div /template script setup langts import { computed, ref } from vue import { useRoute } from vue-router import { Fold, Expand, Monitor, UserFilled } from element-plus/icons-vue import router from /router const route useRoute() const isCollapse ref(false) // 获取菜单路由 const menuRoutes computed(() { return router.options.routes[0].children || [] }) // 当前激活的菜单 const activeMenu computed(() { return route.path }) // 面包屑导航 const breadcrumbs computed(() { const matched route.matched.filter(item item.meta?.title) return matched }) // 切换侧边栏折叠 const toggleCollapse () { isCollapse.value !isCollapse.value } /script style scoped .layout-container { display: flex; height: 100vh; } .sidebar { background-color: #304156; transition: width 0.3s; } .logo { height: 60px; display: flex; align-items: center; justify-content: center; color: white; font-size: 18px; font-weight: bold; border-bottom: 1px solid #2b3848; } .el-menu { border-right: none; } .main-container { flex: 1; display: flex; flex-direction: column; overflow: hidden; } .header { height: 60px; display: flex; align-items: center; justify-content: space-between; padding: 0 20px; border-bottom: 1px solid #e6e6e6; background-color: white; } .header-left { display: flex; align-items: center; gap: 16px; } .header-right { display: flex; align-items: center; } .user-info { display: flex; align-items: center; gap: 8px; cursor: pointer; } .username { font-size: 14px; } .content { flex: 1; padding: 20px; overflow-y: auto; background-color: #f5f7fa; } /style4. 与后端API的联调实践前端界面都准备好了最后也是最关键的一步就是和真正的Janus-Pro-7B模型后端API对接。这里有些实践经验可以分享。4.1 环境配置与代理设置在开发阶段前端运行在localhost:5173Vite默认端口而后端API可能运行在另一个端口比如localhost:8000。这就涉及到跨域问题。我们可以在vite.config.ts中配置代理// vite.config.ts import { defineConfig } from vite import vue from vitejs/plugin-vue export default defineConfig({ plugins: [vue()], server: { proxy: { /api: { target: http://localhost:8000, // 你的后端地址 changeOrigin: true, rewrite: (path) path.replace(/^\/api/, ) } } } })然后在.env.development环境变量文件中配置API基础地址# .env.development VITE_MODEL_API_BASEURL/api这样前端开发时请求/api/v1/chat/completions就会被代理到http://localhost:8000/v1/chat/completions。4.2 API请求封装与错误处理我们之前已经封装了基础的API请求但在实际项目中还需要更完善的错误处理和状态管理。我们可以创建一个更健壮的API封装// utils/request.ts import axios, { type AxiosRequestConfig, type AxiosResponse } from axios import { ElMessage } from element-plus // 创建axios实例 const service axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, timeout: 30000, headers: { Content-Type: application/json } }) // 请求拦截器 service.interceptors.request.use( (config) { // 可以在这里添加token等认证信息 const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config }, (error) { console.error(请求错误:, error) return Promise.reject(error) } ) // 响应拦截器 service.interceptors.response.use( (response: AxiosResponse) { // 根据后端返回的数据结构调整 const res response.data // 假设后端返回格式为 { code: 0, data: ..., message: success } if (res.code ! 0) { ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message || Error)) } return res.data }, (error) { console.error(响应错误:, error) let message 请求失败 if (error.response) { // 有响应但状态码不是2xx switch (error.response.status) { case 400: message 请求参数错误 break case 401: message 未授权请重新登录 // 可以在这里跳转到登录页 break case 403: message 拒绝访问 break case 404: message 请求资源不存在 break case 500: message 服务器内部错误 break default: message 请求失败: ${error.response.status} } } else if (error.request) { // 请求发出但没有收到响应 message 网络错误请检查网络连接 } else { // 请求配置出错 message error.message } ElMessage.error(message) return Promise.reject(error) } ) export default service然后更新我们的模型API模块// api/model.ts import request from /utils/request export interface ChatMessage { role: user | assistant | system content: string } export interface ChatCompletionRequest { model: string messages: ChatMessage[] temperature?: number max_tokens?: number stream?: boolean } export interface ChatCompletionResponse { id: string choices: Array{ message: ChatMessage finish_reason: string index: number } usage: { prompt_tokens: number completion_tokens: number total_tokens: number } } // 对话接口 export async function chatCompletion(params: ChatCompletionRequest): PromiseChatCompletionResponse { return request.post(/v1/chat/completions, params) } // 流式对话接口如果需要 export async function chatCompletionStream( params: ChatCompletionRequest, onMessage: (chunk: string) void, onError?: (error: Error) void, onComplete?: () void ) { const response await fetch(${import.meta.env.VITE_API_BASE_URL}/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${localStorage.getItem(token) || } }, body: JSON.stringify({ ...params, stream: true }) }) if (!response.ok) { throw new Error(HTTP error! status: ${response.status}) } const reader response.body?.getReader() const decoder new TextDecoder() if (!reader) return try { while (true) { const { done, value } await reader.read() if (done) { onComplete?.() break } const chunk decoder.decode(value) const lines chunk.split(\n).filter(line line.trim() ! ) for (const line of lines) { if (line.startsWith(data: )) { const data line.slice(6) if (data [DONE]) { onComplete?.() return } try { const parsed JSON.parse(data) const content parsed.choices[0]?.delta?.content || if (content) { onMessage(content) } } catch (e) { console.error(解析流式响应失败:, e) } } } } } catch (error) { onError?.(error as Error) } }4.3 实际联调中的注意事项在实际和Janus-Pro-7B后端联调时可能会遇到一些问题这里分享几个常见的情况和解决方法跨域问题除了前端配置代理后端也需要配置CORS。确保后端返回正确的CORS头。长响应超时大模型生成可能需要较长时间需要调整超时设置。我们在axios配置中设置了30秒超时如果还不够可以根据实际情况调整。流式响应处理如果后端支持流式输出前端可以用SSEServer-Sent Events或fetch API处理像上面代码展示的那样。这能显著提升用户体验让用户看到逐字输出的效果。错误处理模型API可能返回各种错误比如模型加载失败、显存不足、输入过长等。前端需要做好相应的错误提示。加载状态管理在等待模型响应时要有清晰的加载状态提示比如上面我们用的加载动画。如果是流式响应可以显示正在生成...的提示。Token计数大模型按Token收费或受限制前端可以显示本次对话消耗的Token数帮助用户控制成本。5. 总结到这里一个基于Vue的Janus-Pro-7B模型管理平台的前端部分就基本完成了。我们从前端工程化搭建开始一步步实现了模型测试对话、监控仪表盘、历史记录等核心功能最后还讨论了如何与后端API进行联调。实际用下来Vue 3的Composition API让逻辑组织变得很清晰Element Plus提供了丰富的组件大大加快了开发速度。ECharts的图表能力也完全能满足监控需求。整个开发过程比较顺畅遇到的问题也都有成熟的解决方案。当然这只是一个基础版本还有很多可以完善的地方。比如可以加入用户权限管理不同角色看到不同的功能可以增加模型对比测试功能同时测试多个模型版本还可以加入更详细的日志分析帮助优化提示词效果。如果你也在做类似的项目建议先从核心功能开始快速做出一个可用的版本然后再根据实际需求逐步迭代。前端技术选型上Vue这套组合拳确实挺适合这种中后台管理系统的生态完善学习曲线也相对平缓。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2509014.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…