| | |
| | | body { background: #f5f7fa; } |
| | | .container { max-width: 1100px; margin: 24px auto; } |
| | | .actions { display: flex; gap: 12px; align-items: center; } |
| | | .output { height: 65vh; } |
| | | .output { height: 60vh; } |
| | | .markdown-body { font-size: 14px; line-height: 1.4; white-space: pre-wrap; word-break: break-word; } |
| | | .markdown-body p { margin: 4px 0; } |
| | | .markdown-body ul, .markdown-body ol { margin: 4px 0 4px 16px; padding: 0; } |
| | |
| | | <span>WCS AI 助手</span> |
| | | </div> |
| | | |
| | | <div class="actions"> |
| | | <div class="actions" style="flex-wrap: wrap;"> |
| | | <el-button type="primary" :loading="loading" :disabled="streaming" @click="start">一键诊断系统</el-button> |
| | | <el-button type="warning" :disabled="!streaming" @click="stop">停止</el-button> |
| | | <el-button @click="clear">清空</el-button> |
| | | <span class="status">{{ statusText }}</span> |
| | | <el-button @click="clear">清空当前聊天</el-button> |
| | | <span class="status" style="margin-right: 12px;">{{ statusText }}</span> |
| | | <el-select v-model="currentChatId" placeholder="选择会话" style="min-width:240px;" @change="switchChat" :disabled="streaming"> |
| | | <el-option v-for="c in chats" :key="c.chatId" :label="(c.title||('会话 '+c.chatId)) + '('+(c.size||0)+')'" :value="c.chatId" /> |
| | | </el-select> |
| | | <el-button type="success" plain icon="el-icon-plus" @click="newChat" :disabled="streaming">新会话</el-button> |
| | | <el-button type="danger" plain icon="el-icon-delete" @click="deleteChat" :disabled="!currentChatId || streaming">删除会话</el-button> |
| | | </div> |
| | | |
| | | <el-divider></el-divider> |
| | |
| | | renderIntervalMs: 120, |
| | | stepChars: 6, |
| | | userInput: '', |
| | | autoScrollThreshold: 80 |
| | | autoScrollThreshold: 80, |
| | | chats: [], |
| | | currentChatId: '', |
| | | resetting: false |
| | | }; |
| | | }, |
| | | computed: { |
| | |
| | | } |
| | | }, |
| | | methods: { |
| | | loadChats: function() { |
| | | var self = this; |
| | | fetch(baseUrl + '/ai/diagnose/chats', { headers: { 'token': localStorage.getItem('token') } }) |
| | | .then(function(r){ return r.json(); }) |
| | | .then(function(arr){ if (Array.isArray(arr)) { self.chats = arr; } }); |
| | | }, |
| | | switchChat: function() { |
| | | var self = this; |
| | | if (!self.currentChatId) { self.clear(); return; } |
| | | fetch(baseUrl + '/ai/diagnose/chats/' + encodeURIComponent(self.currentChatId) + '/history', { headers: { 'token': localStorage.getItem('token') } }) |
| | | .then(function(r){ return r.json(); }) |
| | | .then(function(arr){ |
| | | if (!Array.isArray(arr)) return; |
| | | var msgs = []; |
| | | for (var i=0;i<arr.length;i++) { |
| | | var m = arr[i]; |
| | | if (m.role === 'assistant') msgs.push({ role: 'assistant', md: m.content || '', html: DOMPurify.sanitize(marked.parse((m.content||'').replace(/\\n/g,'\n'))), ts: self.nowStr() }); |
| | | else msgs.push({ role: 'user', text: m.content || '', ts: self.nowStr() }); |
| | | } |
| | | self.messages = msgs; |
| | | self.$nextTick(function(){ self.scrollToBottom(true); }); |
| | | }); |
| | | }, |
| | | newChat: function() { |
| | | var id = Date.now() + '_' + Math.random().toString(36).substr(2,8); |
| | | this.currentChatId = id; |
| | | this.resetting = true; |
| | | this.clear(); |
| | | }, |
| | | deleteChat: function() { |
| | | var self = this; |
| | | if (!self.currentChatId) return; |
| | | fetch(baseUrl + '/ai/diagnose/chats/' + encodeURIComponent(self.currentChatId), { method: 'DELETE', headers: { 'token': localStorage.getItem('token') } }) |
| | | .then(function(r){ return r.json(); }) |
| | | .then(function(ok){ if (ok === true) { self.currentChatId = ''; self.clear(); self.loadChats(); self.newChat(); } }); |
| | | }, |
| | | shouldAutoScroll: function() { |
| | | var el = this.$refs.chat; |
| | | if (!el) return false; |
| | |
| | | this.messages.push({ role: 'assistant', md: '', html: '', ts: this.nowStr() }); |
| | | this.scrollToBottom(true); |
| | | var url = baseUrl + '/ai/diagnose/askStream?prompt=' + encodeURIComponent(msg); |
| | | if (this.currentChatId) url += '&chatId=' + encodeURIComponent(this.currentChatId); |
| | | if (this.resetting) url += '&reset=true'; |
| | | this.source = new EventSource(url); |
| | | var self = this; |
| | | this.source.onopen = function() { |
| | |
| | | self.stop(); |
| | | }; |
| | | this.userInput = ''; |
| | | this.resetting = false; |
| | | }, |
| | | start: function() { |
| | | if (this.streaming) return; |
| | |
| | | last.html = DOMPurify.sanitize(marked.parse(renderSource)); |
| | | } |
| | | this.$nextTick(function() { this.scrollToBottom(true); }.bind(this)); |
| | | this.loadChats(); |
| | | }, |
| | | clear: function() { |
| | | this.messages = []; |
| | | this.pendingText = ''; |
| | | } |
| | | } |
| | | ,mounted: function() { |
| | | this.loadChats(); |
| | | this.newChat(); |
| | | } |
| | | }); |
| | | </script> |
| | | </body> |