|
@@ -43,7 +43,9 @@ input {
|
|
|
|
|
|
<script>
|
|
<script>
|
|
import CCDChatCell from "@/components/CCDChatCell";
|
|
import CCDChatCell from "@/components/CCDChatCell";
|
|
|
|
+import { fetchEventSource } from '@microsoft/fetch-event-source';
|
|
let websocketAPIURL = "wss://chat.forgetive.net/free_chat"
|
|
let websocketAPIURL = "wss://chat.forgetive.net/free_chat"
|
|
|
|
+let sseAPIURL = "https://notebook.forgetive.net/freeai/llm"
|
|
|
|
|
|
export default {
|
|
export default {
|
|
name: 'CCDChatSystem',
|
|
name: 'CCDChatSystem',
|
|
@@ -57,12 +59,14 @@ export default {
|
|
},
|
|
},
|
|
{
|
|
{
|
|
"type" : "tip",
|
|
"type" : "tip",
|
|
- "content" : "您好,我是 C Code Develop & C Notebook 智能代码工具,可以为您生成代码"
|
|
|
|
|
|
+ "content" : "您好,我是 C Code Develop & C Notebook AI助手,可以帮您解决代码问题。从编程技巧到历史人文,我无所不知。快来跟我聊天吧~"
|
|
}
|
|
}
|
|
],
|
|
],
|
|
history: [],
|
|
history: [],
|
|
socketObject: null,
|
|
socketObject: null,
|
|
- wannaKill: false
|
|
|
|
|
|
+ wannaKill: false,
|
|
|
|
+ sseInstance: null,
|
|
|
|
+ abortController: null
|
|
}
|
|
}
|
|
},
|
|
},
|
|
mounted() {
|
|
mounted() {
|
|
@@ -83,6 +87,9 @@ export default {
|
|
this.scrollViewScrollToBottom()
|
|
this.scrollViewScrollToBottom()
|
|
},
|
|
},
|
|
doPostMessage() {
|
|
doPostMessage() {
|
|
|
|
+ if (this.sseInstance) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
let question = this.$refs.inputAsk.value
|
|
let question = this.$refs.inputAsk.value
|
|
if (question.length == 0) {
|
|
if (question.length == 0) {
|
|
this.insertMessageBlock({
|
|
this.insertMessageBlock({
|
|
@@ -91,8 +98,85 @@ export default {
|
|
})
|
|
})
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
+ this.insertMessageBlock({
|
|
|
|
+ "type" : "ask",
|
|
|
|
+ "content" : question
|
|
|
|
+ })
|
|
this.$refs.inputAsk.value = ""
|
|
this.$refs.inputAsk.value = ""
|
|
- this.doAsyncChat(question)
|
|
|
|
|
|
+ this.doAsyncSSE(question)
|
|
|
|
+ },
|
|
|
|
+ doAsyncSSE(message) {
|
|
|
|
+ let self = this
|
|
|
|
+ self.allowInput = false
|
|
|
|
+ let messageCard = {
|
|
|
|
+ "type" : "answer",
|
|
|
|
+ "content" : ""
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let messageModel = []
|
|
|
|
+ for (let index in self.model) {
|
|
|
|
+ let model = self.model[index]
|
|
|
|
+ if (model.type == "ask") {
|
|
|
|
+ messageModel.push({
|
|
|
|
+ "role" : "user",
|
|
|
|
+ "content" : model.content
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ else if (model.type == "answer") {
|
|
|
|
+ messageModel.push({
|
|
|
|
+ "role" : "assistant",
|
|
|
|
+ "content" : model.content
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ self.insertMessageBlock(messageCard)
|
|
|
|
+ self.insertMessageBlock({
|
|
|
|
+ "type" : "answerTyping",
|
|
|
|
+ "content" : ""
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ self.abortController = new AbortController()
|
|
|
|
+ let eventSource = fetchEventSource(sseAPIURL, {
|
|
|
|
+ method: 'POST',
|
|
|
|
+ signal: self.abortController.signal,
|
|
|
|
+ headers: {
|
|
|
|
+ "Content-Type": 'application/json',
|
|
|
|
+ "Access-Control-Allow-Origin": true
|
|
|
|
+ },
|
|
|
|
+ body: JSON.stringify({
|
|
|
|
+ "stream" : true,
|
|
|
|
+ "messages" : messageModel
|
|
|
|
+ }),
|
|
|
|
+ onmessage(event) {
|
|
|
|
+ let partModel = JSON.parse(event.data)
|
|
|
|
+ if (partModel["v"] != null) {
|
|
|
|
+ messageCard.content += partModel["v"]
|
|
|
|
+ self.scrollViewScrollToBottom()
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ onerror(err) {
|
|
|
|
+ if (messageCard.content.length < 5) {
|
|
|
|
+ messageCard.content = "回答出了一点问题"
|
|
|
|
+ }
|
|
|
|
+ self.sseInstance = null
|
|
|
|
+ self.allowInput = true
|
|
|
|
+ self.doShutdown()
|
|
|
|
+ throw err
|
|
|
|
+ },
|
|
|
|
+ onclose() {
|
|
|
|
+ self.sseInstance = null
|
|
|
|
+ self.allowInput = true
|
|
|
|
+ self.abortController = null
|
|
|
|
+ for (let id = 0; id < self.model.length; id++) {
|
|
|
|
+ if (self.model[id].type == "answerTyping") {
|
|
|
|
+ self.model.splice(id, 1)
|
|
|
|
+ id--;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ self.sseInstance = eventSource
|
|
},
|
|
},
|
|
doAsyncChat(message) {
|
|
doAsyncChat(message) {
|
|
this.allowInput = false
|
|
this.allowInput = false
|
|
@@ -157,8 +241,21 @@ export default {
|
|
}
|
|
}
|
|
},
|
|
},
|
|
doShutdown() {
|
|
doShutdown() {
|
|
- if (this.socketObject != null) {
|
|
|
|
- this.socketObject.close(1000)
|
|
|
|
|
|
+ let self = this
|
|
|
|
+ if (self.socketObject != null) {
|
|
|
|
+ self.socketObject.close(1000)
|
|
|
|
+ }
|
|
|
|
+ if (self.abortController != null) {
|
|
|
|
+ self.abortController.abort()
|
|
|
|
+ self.sseInstance = null
|
|
|
|
+ self.allowInput = true
|
|
|
|
+ self.abortController = null
|
|
|
|
+ for (let id = 0; id < self.model.length; id++) {
|
|
|
|
+ if (self.model[id].type == "answerTyping") {
|
|
|
|
+ self.model.splice(id, 1)
|
|
|
|
+ id--;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|