CzRger 2 månader sedan
förälder
incheckning
74e1828105
3 ändrade filer med 134 tillägg och 29 borttagningar
  1. 90 0
      src/views/chat/chat.ts
  2. 43 28
      src/views/chat/index.vue
  3. 1 1
      src/views/manage/app/make/index.vue

+ 90 - 0
src/views/chat/chat.ts

@@ -0,0 +1,90 @@
+import { ElButton, ElNotification } from 'element-plus'
+import { h } from 'vue'
+
+export const chatMessage = (params, funcs) => {
+  fetch(
+    `${(import.meta as any).env.VITE_WORKFLOW_API_PROXY}/app/chat-messages`,
+    {
+      method: 'POST',
+      body: JSON.stringify(params),
+      headers: {
+        Authorization: localStorage.getItem(
+          (import.meta as any).env.VITE_TOKEN,
+        ),
+        'Content-Type': 'application/json',
+      } as any,
+    },
+  ).then((res) => {
+    handleStream({ response: res, ...funcs })
+  })
+}
+
+const handleStream = ({
+  response,
+  onData,
+  onMessageEnd,
+  onStart,
+  onEnd,
+  onError,
+}) => {
+  if (!response.ok) throw new Error('Network response was not ok')
+
+  const reader = response.body?.getReader()
+  const decoder = new TextDecoder('utf-8')
+  let buffer = ''
+  let bufferObj: any = {}
+  const dataFlag = 'data:'
+  const read = () => {
+    let hasError = false
+    reader?.read().then((result: any) => {
+      if (result.done) {
+        onEnd?.()
+        return
+      }
+      buffer += decoder.decode(result.value, { stream: true })
+      const lines = buffer.split('\n')
+      try {
+        lines.forEach((message) => {
+          if (message.startsWith(dataFlag)) {
+            try {
+              bufferObj = JSON.parse(message.substring(dataFlag.length))
+            } catch (e) {
+              return
+            }
+            const { event } = bufferObj
+            if (event === 'chat_start') {
+              onStart?.(bufferObj)
+            } else if (event === 'message') {
+              onData(unicodeToChar(bufferObj.answer), bufferObj)
+            } else if (event === 'message_end') {
+              onMessageEnd(bufferObj)
+            } else if (event === 'error') {
+              ElNotification({
+                title: bufferObj.error_type,
+                message: bufferObj.error_message,
+                type: 'error',
+                duration: 0,
+              })
+              onError?.(bufferObj)
+            }
+          }
+        })
+        buffer = lines[lines.length - 1]
+      } catch (e) {
+        console.log('zxcxllasldsll')
+        hasError = true
+        return
+      }
+      if (!hasError) read()
+    })
+  }
+  read()
+}
+
+const unicodeToChar = (text: string) => {
+  if (!text) return ''
+
+  return text.replace(/\\u[0-9a-f]{4}/g, (_match, p1) => {
+    return String.fromCharCode(parseInt(p1, 16))
+  })
+}

+ 43 - 28
src/views/chat/index.vue

@@ -32,46 +32,46 @@
       <div class="mt-2 flex w-full items-center">
         <div class="mx-auto" />
         <audioCom class="mr-2" @onAudio="onAudio" />
-        <template v-if="state.text">
-          <template v-if="state.isWaiting">
-            <el-tooltip content="等待回复中" placement="top">
-              <div
-                class="flex h-8 w-8 cursor-no-drop items-center justify-center rounded-sm bg-[var(--czr-main-color)] opacity-50"
-              >
-                <SvgIcon name="wait" color="#ffffff" size="20" />
-              </div>
-            </el-tooltip>
-          </template>
-          <template v-else-if="state.isStop">
-            <el-tooltip content="停止生成" placement="top">
+        <template v-if="state.isWaiting">
+          <el-tooltip content="等待回复中" placement="top">
+            <div
+              class="flex h-8 w-8 cursor-no-drop items-center justify-center rounded-sm bg-[var(--czr-main-color)] opacity-50"
+            >
+              <SvgIcon name="wait" color="#ffffff" size="20" />
+            </div>
+          </el-tooltip>
+        </template>
+        <template v-else-if="state.isStop">
+          <el-tooltip content="停止生成" placement="top">
+            <div
+              class="__hover flex h-8 w-8 items-center justify-center rounded-sm bg-[var(--czr-main-color)]"
+              @click="onStop()"
+            >
+              <div class="h-3 w-3 bg-[#ffffff]" />
+            </div>
+          </el-tooltip>
+        </template>
+        <template v-else>
+          <template v-if="state.text">
+            <el-tooltip content="发送" placement="top">
               <div
                 class="__hover flex h-8 w-8 items-center justify-center rounded-sm bg-[var(--czr-main-color)]"
-                @click="onStop()"
+                @click="onSend()"
               >
-                <div class="h-3 w-3 bg-[#ffffff]" />
+                <img src="@/assets/images/chat/send.png" />
               </div>
             </el-tooltip>
           </template>
           <template v-else>
-            <el-tooltip content="发送" placement="top">
+            <el-tooltip content="请输入问题" placement="top">
               <div
-                class="__hover flex h-8 w-8 items-center justify-center rounded-sm bg-[var(--czr-main-color)]"
-                @click="onSend()"
+                class="flex h-8 w-8 cursor-no-drop items-center justify-center rounded-sm bg-[var(--czr-main-color)] opacity-50"
               >
                 <img src="@/assets/images/chat/send.png" />
               </div>
             </el-tooltip>
           </template>
         </template>
-        <template v-else>
-          <el-tooltip content="请输入问题" placement="top">
-            <div
-              class="flex h-8 w-8 cursor-no-drop items-center justify-center rounded-sm bg-[var(--czr-main-color)] opacity-50"
-            >
-              <img src="@/assets/images/chat/send.png" />
-            </div>
-          </el-tooltip>
-        </template>
       </div>
     </div>
   </div>
@@ -85,6 +85,7 @@ import audioCom from './audio/index.vue'
 import { AnswerStruct } from '@/types/chat'
 import { isValue } from '@/utils/czr-util'
 import { ElMessage } from 'element-plus'
+import { chatMessage } from '@/views/chat/chat'
 
 const state: any = reactive({
   text: '',
@@ -94,7 +95,7 @@ const state: any = reactive({
     query: '',
   },
   isWaiting: false,
-  isStop: true,
+  isStop: false,
 })
 const ref_text = ref()
 const ref_chatMsg = ref()
@@ -199,7 +200,7 @@ const scrollToEnd = () => {
 }
 const onSend = (text = '') => {
   if ((isValue(state.text.trim()) || text) && !state.loading) {
-    if (state.isWaiting) {
+    if (state.isWaiting || state.isStop) {
       ElMessage({
         message: '问题回复中,请稍后提问!',
         grouping: true,
@@ -227,6 +228,20 @@ const onSend = (text = '') => {
     scrollToEnd()
     state.isWaiting = true
     state.isStop = true
+    chatMessage(state.params, {
+      onData: (text, data) => {
+        console.log(text, data)
+        state.isWaiting = false
+        // answer.messageId = messageId
+        // answer.taskId = taskId
+        answer.loading = false
+        answer.text += text
+        scrollToEnd()
+      },
+      onMessageEnd: (data) => {
+        state.isStop = false
+      },
+    })
   }
 }
 const onStop = () => {}

+ 1 - 1
src/views/manage/app/make/index.vue

@@ -748,7 +748,7 @@ const state: any = reactive({
     value: '',
   },
   dragRefresh: true,
-  isDebug: false,
+  isDebug: true,
   history: [
     { type: 'submit', date: '2024-03-06 22:24:54' },
     { type: 'publish', date: '2024-03-06 22:24:54' },