Skip to content

Commit 1072b78

Browse files
committed
add llm error alert & abort
1 parent 3b343ab commit 1072b78

File tree

7 files changed

+88
-50
lines changed

7 files changed

+88
-50
lines changed

gui/src/App.vue

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<WatchShared v-model:open="open" v-model:paths="paths" />
66
</template>
77
<script setup>
8-
import { onMounted, ref, computed } from "vue";
8+
import { onMounted, ref, computed, watch } from "vue";
99
import { setAuthorization, AUTH_TYPE } from "@/service/common/request";
1010
import { useToast } from "primevue/usetoast";
1111
import { useConfirm } from "primevue/useconfirm";
@@ -27,14 +27,18 @@ store.commit('account/setUser', {id:''});
2727
store.commit('notice/setToast', toast);
2828
store.commit('notice/setConfirm', confirm);
2929
30-
const selectedMesh = computed(() => {
31-
return store.getters["account/selectedMesh"]
32-
});
33-
30+
watch(() => store.getters["account/selectedMesh"], ()=>{
31+
store.commit('notice/setErrorLength', 0);
32+
},{
33+
deep:true
34+
})
35+
const errorLength = computed(() => store.getters["notice/errorLength"] );
3436
const open = ref(false);
3537
const paths = ref()
3638
const timmer = () => {
37-
store.dispatch('notice/rooms');
39+
if(errorLength < 10){
40+
store.dispatch('notice/rooms');
41+
}
3842
if(!paths.value && isMobile()){
3943
getShared(false, (res)=>{
4044
if(res && res.length>0){

gui/src/service/BotService.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import MCPService from '@/service/MCPService';
1111
export default class BotService {
1212

1313
mcpService = null
14+
stream = null
1415

1516
constructor(){
1617
this.mcpService = new MCPService();
@@ -307,6 +308,7 @@ export default class BotService {
307308
}
308309
]
309310
*/
311+
310312
chatLLM(roomId, sysmessages, messages, tools, llm, callback) {
311313
const mesh = this.getMesh();
312314
let body = { messages: (sysmessages||[]).concat(messages) };
@@ -317,12 +319,21 @@ export default class BotService {
317319
writeLogFile('ztm-llm.log', `[${new Date().toISOString()}] request llm ${url} by ${JSON.stringify(body)}\n`);
318320

319321
setItem(STORE_BOT_CONTENT(mesh?.name, roomId), messages, ()=> {
320-
const stream = fetchAsStream();
321-
stream.post(
322+
this.stream = fetchAsStream();
323+
this.stream.post(
322324
url,
323325
body,
324326
callback
325327
)
326328
},llm?.memoryLength||10)
327329
}
330+
getStreaming() {
331+
return !!this.stream;
332+
}
333+
chatCancel() {
334+
if(!!this.stream){
335+
this.stream.cancel();
336+
this.stream = null;
337+
}
338+
}
328339
}

gui/src/service/common/request.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,7 @@ function fetchAsStream() {
6767
body: JSON.stringify(data),
6868
signal: controller.signal
6969
});
70-
if (!response.ok) {
71-
const _msg = `HTTP error! status: ${response.status}`
72-
processMessage(response?.statusText || _msg, true);
73-
throw new Error(_msg);
74-
return
75-
}
70+
7671

7772
if (!response.body) {
7873
throw new Error('ReadableStream not supported in this browser');
@@ -88,10 +83,16 @@ function fetchAsStream() {
8883
const { done,value } = await reader.read();
8984
if (done) {
9085
// 处理缓冲区中剩余的数据
91-
if (buffer.trim()) {
92-
processBuffer(true)
93-
}
9486
console.log('Stream complete');
87+
if (!response.ok) {
88+
const _msg = `HTTP error! status: ${response.status}`
89+
throw new Error(buffer || _msg || response);
90+
buffer = '';
91+
} else {
92+
if (buffer.trim()) {
93+
processBuffer(true)
94+
}
95+
}
9596
break;
9697
}
9798

@@ -128,9 +129,11 @@ function fetchAsStream() {
128129
}
129130
}
130131
} catch (error) {
131-
if (error.name === 'AbortError') {
132+
if (error?.name === 'AbortError') {
133+
processMessage("请求已被取消", true);
132134
console.log('请求已被取消');
133135
} else {
136+
processMessage(error?.stack || error, true);
134137
console.error('Fetch error:', error);
135138
}
136139
}

gui/src/store/modules/mcp.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,9 @@ export default {
110110
callback(res, ending){
111111
const choices = res?.choices;
112112
const choice = !!choices && choices[0];
113-
if(choice?.message){
113+
if(typeof(res) == 'string'){
114+
commit('pushMessage', {message:res, ending:true});
115+
} else if(choice?.message){
114116
const message = choice?.message?.reasoning_content||choice?.message?.content||'';
115117
commit('pushMessage', {message, ending:true});
116118
} else {

gui/src/store/modules/notice.js

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,47 @@ export default {
99
toast:null,
1010
app:null,
1111
unread:0,
12+
errorLength:0,
1213
rooms:[],
1314
pushed:{},
1415
},
1516
actions: {
1617
async rooms({ commit, getters }) {
17-
const res = await chatService.getRooms();
18-
commit('setRooms',(res || []).sort((a, b) => b.time - a.time));
19-
const news = (res || []).filter((room)=>!!room.updated) || [];
20-
let _unread = 0;
21-
news.forEach((room)=>{
22-
if(room.updated>0){
23-
_unread += room.updated;
24-
let _msg = ""
25-
const _pushed = getters['pushed'];
26-
if(!!room?.peer){
27-
const _key = `${room?.peer}-${room?.latest?.sender}-${room?.time}`;
28-
if(!_pushed[_key]){
29-
commit('setPushedByKey',_key);
30-
send(room?.peer, room?.latest?.message?.text?`${room?.latest?.message?.text}`:`[${room?.latest?.message?.files?.length>1?'Files':'File'}]`)
31-
}
32-
}else {
33-
const _key = `${room?.group}-${room?.latest?.sender}-${room?.time}`;
34-
if(!_pushed[_key]){
35-
commit('setPushedByKey',_key);
36-
send(room?.name, room?.latest?.message?.text?`${room?.latest?.sender}:${room?.latest?.message?.text}`:`${room?.latest?.sender}:[${room?.latest?.message?.files?.length>1?'Files':'File'}]`)
18+
try{
19+
const res = await chatService.getRooms();
20+
commit('setRooms',(res || []).sort((a, b) => b.time - a.time));
21+
const news = (res || []).filter((room)=>!!room.updated) || [];
22+
let _unread = 0;
23+
news.forEach((room)=>{
24+
if(room.updated>0){
25+
_unread += room.updated;
26+
let _msg = ""
27+
const _pushed = getters['pushed'];
28+
if(!!room?.peer){
29+
const _key = `${room?.peer}-${room?.latest?.sender}-${room?.time}`;
30+
if(!_pushed[_key]){
31+
commit('setPushedByKey',_key);
32+
send(room?.peer, room?.latest?.message?.text?`${room?.latest?.message?.text}`:`[${room?.latest?.message?.files?.length>1?'Files':'File'}]`)
33+
}
34+
}else {
35+
const _key = `${room?.group}-${room?.latest?.sender}-${room?.time}`;
36+
if(!_pushed[_key]){
37+
commit('setPushedByKey',_key);
38+
send(room?.name, room?.latest?.message?.text?`${room?.latest?.sender}:${room?.latest?.message?.text}`:`${room?.latest?.sender}:[${room?.latest?.message?.files?.length>1?'Files':'File'}]`)
39+
}
3740
}
3841
}
39-
}
40-
});
41-
commit('setUnread',_unread);
42+
});
43+
commit('setUnread',_unread);
44+
}catch(e){
45+
commit('setErrorLength',getters['errorLength'] + 1);
46+
}
4247
},
4348
},
4449
getters: {
50+
errorLength: (state) => {
51+
return state.errorLength;
52+
},
4553
pushed: (state) => {
4654
return state.pushed;
4755
},
@@ -62,6 +70,9 @@ export default {
6270
},
6371
},
6472
mutations: {
73+
setErrorLength(state, errorLength) {
74+
state.errorLength = errorLength;
75+
},
6576
setPushedByKey(state, pushed) {
6677
state.pushed[pushed] = true;
6778
},

gui/src/views/chat/BotChat.vue

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const loading = ref(true);
2323
const store = useStore();
2424
const botService = new BotService();
2525
const mcpService = new MCPService();
26+
const callbackProxy = ref();
2627
const props = defineProps(['room']);
2728
const emits = defineEmits(['back','peer','manager','history','notify','update:room']);
2829
const selectedMesh = computed(() => {
@@ -82,7 +83,7 @@ const makeToolcall = () => {
8283
const cancelToolcall = () => {
8384
openToolcallEditor.value = false;
8485
toolcallTarget.value.status = "cancel"
85-
callbackProxy(
86+
callbackProxy.value(
8687
msgHtml(lastmsg.value, toolcallTarget.value),
8788
false,
8889
true
@@ -109,7 +110,7 @@ const openToolcall = () => {
109110
openToolcallEditor.value = true;
110111
loaddata();
111112
setTimeout(()=>{
112-
callbackProxy(
113+
callbackProxy.value(
113114
msgHtml(lastmsg.value, toolcallTarget.value),
114115
false,
115116
false
@@ -251,17 +252,16 @@ const inputStyle = computed(() => {
251252
})
252253
const hasMediaDevices = computed(() => true);
253254
const delta = ref('');
254-
let callbackProxy = null;
255255
const workerOnMessage = (msg) => {
256256
const toolcall = store.getters["mcp/toolcall"]
257257
if(msg?.message){
258-
callbackProxy(
258+
callbackProxy.value(
259259
msgHtml(msg?.message, toolcall),
260260
true
261261
);
262262
} else {
263263
setTimeout(()=>{
264-
callbackProxy(
264+
callbackProxy.value(
265265
msgHtml(msg?.delta, toolcall),
266266
msg?.ending,
267267
!msg?.first
@@ -396,7 +396,7 @@ const request = ref({
396396
// writeMobileFile('postMessageHTML.txt',html);
397397
chat.value.addMessage({role: 'user',html:html},false);
398398
}
399-
callbackProxy = (html2,ending)=>{
399+
callbackProxy.value = (html2,ending)=>{
400400
//body
401401
// let html2 = "";
402402
// body?.files.forEach((file)=>{
@@ -430,7 +430,7 @@ const request = ref({
430430
}else if(body?.messages){
431431
432432
if(body?.messages[0]){
433-
callbackProxy = (html,ending,overwrite) => {
433+
callbackProxy.value = (html,ending,overwrite) => {
434434
// loading.value = false;
435435
signals.onResponse({files:[],overwrite: true});
436436
chat.value.addMessage({html,role: 'ai',overwrite: overwrite},overwrite);
@@ -485,6 +485,12 @@ const openPeer = () => {
485485
emits('peer',llm.value?.name);
486486
}
487487
488+
const streaming = computed(() => !!callbackProxy.value )
489+
const chatCancel = () => {
490+
botService.chatCancel();
491+
callbackProxy.value = null;
492+
loading.value = false;
493+
}
488494
const loadllm = (callback) => {
489495
botService.checkLLM(props?.room?.id,(res) => {
490496
llm.value = res;
@@ -569,6 +575,7 @@ defineExpose({
569575
<template #end>
570576
<Button icon="pi pi-history" @click="gohistory" severity="secondary" text />
571577
<Button icon="pi pi-cog" @click="showManage" severity="secondary" text />
578+
<Button v-if="streaming" icon="pi pi-stop-circle" @click="chatCancel()" severity="danger" text />
572579
</template>
573580
</AppHeader>
574581
<div class="w-full flex" style="height: calc(100vh - 37px);flex: 1;margin: 0;flex-direction: column;">

gui/src/views/chat/Main.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ onMounted(()=>{
405405
v-if="selectRoom?.bot"
406406
v-model:room="selectRoom"
407407
@back="backList"
408-
@manager="() => manager = 'bot'"
408+
@manager="() => { botHistory = false;manager = 'bot'; }"
409409
@history="() => botHistory = true"
410410
@notify="loadBotHistory"
411411
/>

0 commit comments

Comments
 (0)