diff --git a/examples/router/axios.js b/examples/router/axios.js index af795cae..772913c0 100644 --- a/examples/router/axios.js +++ b/examples/router/axios.js @@ -9,6 +9,8 @@ instance.defaults.baseURL = baseURLs[process.env.NODE_ENV] instance.interceptors.request.use(config => { if (config.url.startsWith("/node")) { config.baseURL = "/ns" + } else if (config.url.startsWith("/sse")) { + config.baseURL = "/" } else if (/\/project\/activeAnalysis/.test(location.pathname)) { config.baseURL = "/analysis" } else if (/\/project\/beta/.test(location.pathname)) { diff --git a/ui/packages/ai/AiCopilot.vue b/ui/packages/ai/AiCopilot.vue index 60231120..ad856600 100644 --- a/ui/packages/ai/AiCopilot.vue +++ b/ui/packages/ai/AiCopilot.vue @@ -14,7 +14,7 @@ export default { }, data() { return { - show: false, + show: true, expand: false, loading: false, prompt: "", @@ -82,10 +82,6 @@ export default { handleSend() { if (!this.prompt.trim()) return this.$message.error("无法发送空白信息") else if (this.isNeedPosition && !this.latlng) return this.$message.error("请先选择您所在的位置") - const concatenateStr = (content, i = 0, target = this.history.at(-1)) => { - target.content += content.slice(i, i + 1) - if (++i < content.length) setTimeout(() => concatenateStr(content, i, target), 50) - } this.$debounce(() => { const {currentConversation: conversationId, app, prompt: content, latlng, files} = this.$data const {id: fileId, url: sdkFileUrl, name: fileName} = files[0] || {} @@ -93,13 +89,7 @@ export default { this.history.push(message) this.loading = true this.clearCache() - this.http.post("/app/appaicopilotinfo/add", message).then(res => { - if (res?.data?.length >= 2) { - const last = res.data.at(-1) - this.history.push({...last, content: ""}) - concatenateStr(last.content) - } - }).finally(() => { + this.sendMessage(message).finally(() => { this.loading = false this.getConversations() }) @@ -145,6 +135,52 @@ export default { handleUpload() { if (this.$refs.uploader.checkUpload()) this.$refs.uploadTrigger.click() else this.$message.error("最多上传一个文件") + }, + sendMessage(message, isSSE = false) { + if (isSSE) { + const {content, sdkFileUrl} = message + const body = { + inputs: {}, + query: content, + response_mode: "streaming", + user: "kubbo", + } + if (sdkFileUrl) body.files = [{type: 'image', url: sdkFileUrl, transfer_method: "remote_url"}] + return new Promise(resolve => this.http.post("/sse/chat-messages", body, { + withoutToken: 1, headers: { + Accept: 'text/event-stream', + Authorization: "Bearer app-DRXYELe63911kx7F9RvKUonf" + }, + onDownloadProgress: evt => { + evt.target.responseText.split("data:").forEach(data => { + if (data.trim()) { + const res = JSON.parse(data.trim()) + const chunk = res.answer?.trim() + if (!!chunk) { + if (this.history.at(-1).userType != 1) { + this.history.push({userType: 1, content: chunk}) + } else if (!this.history.at(-1).content?.includes(chunk)) { + this.history.at(-1).content += chunk + } + } + if (res.event == "message_end") resolve() + } + }) + } + })) + } else { + const concatenateStr = (content, i = 0, target = this.history.at(-1)) => { + target.content += content.slice(i, i + 1) + if (++i < content.length) setTimeout(() => concatenateStr(content, i, target), 50) + } + return this.http.post("/app/appaicopilotinfo/add", message).then(res => { + if (res?.data?.length >= 2) { + const last = res.data.at(-1) + this.history.push({...last, content: ""}) + return concatenateStr(last.content) + } + }) + } } }, watch: { @@ -165,7 +201,6 @@ export default { this.handleChangeConversation(this.conversations.at(0) || {appId, aiConfigId, ability}) }) } - } diff --git a/vue.config.js b/vue.config.js index 5eae659c..c6fc5c30 100644 --- a/vue.config.js +++ b/vue.config.js @@ -38,6 +38,14 @@ module.exports = { '^/lan': '/' } }, + '/sse': { + target: "http://192.168.1.87:10409/v1", + changeOrigin: true, + pathRewrite: { + //地址重写 + '^/sse': '/' + } + }, }, disableHostCheck: true, }