|
@@ -1,5 +1,5 @@
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
-import { ref, nextTick, onMounted, computed, onUnmounted, reactive, watch } from 'vue'
|
|
|
|
|
|
+import { ref, nextTick, onMounted, computed, onUnmounted, reactive, watch, isReactive } from 'vue'
|
|
import { Local } from '/@/utils/storage'
|
|
import { Local } from '/@/utils/storage'
|
|
import { User, ChatDotRound, Delete, Edit, Check, Close } from '@element-plus/icons-vue'
|
|
import { User, ChatDotRound, Delete, Edit, Check, Close } from '@element-plus/icons-vue'
|
|
import { MarkdownPlugin } from '/@/components/markdown/type/markdown'
|
|
import { MarkdownPlugin } from '/@/components/markdown/type/markdown'
|
|
@@ -126,30 +126,84 @@ const sendMessage = () => {
|
|
tool_calls: [],
|
|
tool_calls: [],
|
|
})
|
|
})
|
|
|
|
|
|
- const fn = watch(
|
|
|
|
- () => rtn.render_content,
|
|
|
|
- (newVal) => console.log(newVal)
|
|
|
|
- )
|
|
|
|
-
|
|
|
|
inputMessage.value = ''
|
|
inputMessage.value = ''
|
|
-
|
|
|
|
scrollToBottom()
|
|
scrollToBottom()
|
|
- //
|
|
|
|
- // let toolcall: { name: string; param?: string; value?: string } | undefined = undefined
|
|
|
|
|
|
+ chatInternal(rtn)
|
|
|
|
+ messages.value.push(rtn)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const replaceMessage = (index: number) => {
|
|
|
|
+ // 获取当前用户消息
|
|
|
|
+ const userMessage = messages.value[index]
|
|
|
|
+ if (!userMessage || userMessage.role !== 'user') {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 查找对应的AI回复消息(通常是下一条消息)
|
|
|
|
+ let aiMessageIndex = -1
|
|
|
|
+ for (let i = index + 1; i < messages.value.length; i++) {
|
|
|
|
+ if (messages.value[i].role === 'assistant') {
|
|
|
|
+ aiMessageIndex = i
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let rtn: Message
|
|
|
|
+
|
|
|
|
+ if (aiMessageIndex !== -1) {
|
|
|
|
+ // 找到了AI回复消息
|
|
|
|
+ const aiMessage = messages.value[aiMessageIndex]
|
|
|
|
+
|
|
|
|
+ if (isReactive(aiMessage)) {
|
|
|
|
+ // 如果是reactive对象,清空内容
|
|
|
|
+ aiMessage.render_content = ''
|
|
|
|
+ aiMessage.content = ''
|
|
|
|
+ aiMessage.tool_calls = []
|
|
|
|
+ rtn = aiMessage
|
|
|
|
+ } else {
|
|
|
|
+ // 如果不是reactive对象,创建新的reactive对象替换
|
|
|
|
+ rtn = reactive<Message>({
|
|
|
|
+ id: aiMessage.id,
|
|
|
|
+ role: 'assistant',
|
|
|
|
+ render_content: '',
|
|
|
|
+ content: '',
|
|
|
|
+ timestamp: aiMessage.timestamp,
|
|
|
|
+ tool_calls: [],
|
|
|
|
+ })
|
|
|
|
+ messages.value[aiMessageIndex] = rtn
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ // 没有找到AI回复消息,创建新的
|
|
|
|
+ rtn = reactive<Message>({
|
|
|
|
+ id: `${Date.now()}`,
|
|
|
|
+ role: 'assistant',
|
|
|
|
+ render_content: '',
|
|
|
|
+ content: '',
|
|
|
|
+ timestamp: Date.now(),
|
|
|
|
+ tool_calls: [],
|
|
|
|
+ })
|
|
|
|
+ messages.value.push(rtn)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 重新发起对话
|
|
|
|
+ chatInternal(rtn,messages.value.slice(0,aiMessageIndex))
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const chatInternal = (rtn:Message,context: Message[] = messages.value) => {
|
|
chatInstance.value = assist.chat({
|
|
chatInstance.value = assist.chat({
|
|
chatRequest: {
|
|
chatRequest: {
|
|
message: prompt.value
|
|
message: prompt.value
|
|
? [
|
|
? [
|
|
- {
|
|
|
|
- id: `${Date.now()}`,
|
|
|
|
- role: 'system',
|
|
|
|
- render_content: prompt.value,
|
|
|
|
- content: prompt.value,
|
|
|
|
- timestamp: Date.now(),
|
|
|
|
- },
|
|
|
|
- ...messages.value,
|
|
|
|
- ]
|
|
|
|
- : messages.value,
|
|
|
|
|
|
+ {
|
|
|
|
+ id: `${Date.now()}`,
|
|
|
|
+ role: 'system',
|
|
|
|
+ render_content: prompt.value,
|
|
|
|
+ content: prompt.value,
|
|
|
|
+ timestamp: Date.now(),
|
|
|
|
+ },
|
|
|
|
+ ...context,
|
|
|
|
+ ]
|
|
|
|
+ : context,
|
|
modelClassId: selectedModel.value,
|
|
modelClassId: selectedModel.value,
|
|
},
|
|
},
|
|
onReceive: (resp: ChatResponse) => {
|
|
onReceive: (resp: ChatResponse) => {
|
|
@@ -211,7 +265,6 @@ ${resp.request.data.replace('\n', '')}
|
|
}
|
|
}
|
|
},
|
|
},
|
|
onComplete: (e) => {
|
|
onComplete: (e) => {
|
|
- fn()
|
|
|
|
if (e !== undefined) {
|
|
if (e !== undefined) {
|
|
rtn.content += `
|
|
rtn.content += `
|
|
|
|
|
|
@@ -221,7 +274,7 @@ ${resp.request.data.replace('\n', '')}
|
|
chatInstance.value = undefined
|
|
chatInstance.value = undefined
|
|
},
|
|
},
|
|
})
|
|
})
|
|
- messages.value.push(rtn)
|
|
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
// 终止对话
|
|
// 终止对话
|
|
@@ -401,8 +454,21 @@ const redirectToModelManager = () => router.push('manage/model')
|
|
|
|
|
|
<!-- 用户消息 -->
|
|
<!-- 用户消息 -->
|
|
<div v-if="message.role === 'user'" class="user-message-container">
|
|
<div v-if="message.role === 'user'" class="user-message-container">
|
|
- <div class="message-bubble user-bubble">
|
|
|
|
- {{ message.render_content }}
|
|
|
|
|
|
+ <div class="user-message-content">
|
|
|
|
+ <div class="message-bubble user-bubble">
|
|
|
|
+ {{ message.render_content }}
|
|
|
|
+ </div>
|
|
|
|
+ <div class="user-message-actions">
|
|
|
|
+ <el-button
|
|
|
|
+ type="primary"
|
|
|
|
+ size="small"
|
|
|
|
+ @click="replaceMessage(messages.indexOf(message))"
|
|
|
|
+ class="retry-btn"
|
|
|
|
+ plain
|
|
|
|
+ >
|
|
|
|
+ 重试
|
|
|
|
+ </el-button>
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
<el-avatar class="message-avatar" :src="getUserInfos.avatar" :icon="User" />
|
|
<el-avatar class="message-avatar" :src="getUserInfos.avatar" :icon="User" />
|
|
</div>
|
|
</div>
|
|
@@ -739,6 +805,31 @@ const redirectToModelManager = () => router.push('manage/model')
|
|
justify-content: flex-end;
|
|
justify-content: flex-end;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+.user-message-content {
|
|
|
|
+ display: flex;
|
|
|
|
+ flex-direction: column;
|
|
|
|
+ align-items: flex-end;
|
|
|
|
+ gap: 8px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.user-message-actions {
|
|
|
|
+ display: flex;
|
|
|
|
+ justify-content: flex-end;
|
|
|
|
+ opacity: 0;
|
|
|
|
+ transition: opacity 0.2s ease;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.user-message-container:hover .user-message-actions {
|
|
|
|
+ opacity: 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.retry-btn {
|
|
|
|
+ font-size: 12px;
|
|
|
|
+ padding: 4px 12px;
|
|
|
|
+ height: 24px;
|
|
|
|
+ border-radius: 12px;
|
|
|
|
+}
|
|
|
|
+
|
|
.user-bubble {
|
|
.user-bubble {
|
|
background: var(--el-color-primary);
|
|
background: var(--el-color-primary);
|
|
color: white;
|
|
color: white;
|