|
@@ -1,10 +1,11 @@
|
|
|
<script setup lang="ts">
|
|
|
import { ref, nextTick, onMounted, computed, onUnmounted, reactive, watch, isReactive } from 'vue'
|
|
|
import { Local } from '/@/utils/storage'
|
|
|
-import { User, ChatDotRound, Delete, Edit, Check, Close } from '@element-plus/icons-vue'
|
|
|
+import { User, ChatDotRound, Delete, Edit, Check, Close, ArrowDown } from '@element-plus/icons-vue'
|
|
|
import { MarkdownPlugin } from '/@/components/markdown/type/markdown'
|
|
|
import EChartsPlugin from '/@/components/markdown/plugins/echarts'
|
|
|
import ToolsLoadingPlugin from '/@/components/markdown/plugins/tools-loading'
|
|
|
+import TablePlugin from '/@/components/markdown/plugins/table'
|
|
|
import Markdown from '/@/components/markdown/Markdown.vue'
|
|
|
import assist from '/@/api/assist'
|
|
|
import { ChatResponse, LmConfigInfo, LmSession, Message } from '/@/api/assist/type'
|
|
@@ -13,7 +14,7 @@ import { Setting as EleSetting } from '@element-plus/icons-vue'
|
|
|
import { useRouter } from 'vue-router'
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
|
|
|
-const plugins: Array<MarkdownPlugin<any>> = [EChartsPlugin(), ToolsLoadingPlugin()]
|
|
|
+const plugins: Array<MarkdownPlugin<any>> = [EChartsPlugin(), ToolsLoadingPlugin(), TablePlugin()]
|
|
|
|
|
|
//聊天管理接口
|
|
|
// 消息列表
|
|
@@ -230,7 +231,9 @@ const chatInternal = (rtn: Message, context: Message[] = messages.value) => {
|
|
|
rtn.content += resp.message
|
|
|
break
|
|
|
case 'toolres': {
|
|
|
- rtn.render_content += `
|
|
|
+
|
|
|
+ if (showToolCalls.value) {
|
|
|
+ rtn.render_content += `
|
|
|
\`\`\`tools-loading
|
|
|
resp
|
|
|
${resp.response.name}
|
|
@@ -238,6 +241,8 @@ ${resp.response.data.replace('\n', '')}
|
|
|
\`\`\`
|
|
|
|
|
|
`
|
|
|
+ }
|
|
|
+
|
|
|
messages.value.push({
|
|
|
id: messages.value.length,
|
|
|
tool_call_id: resp.response.id,
|
|
@@ -252,7 +257,8 @@ ${resp.response.data.replace('\n', '')}
|
|
|
}
|
|
|
|
|
|
case 'toolcall': {
|
|
|
- rtn.render_content += `
|
|
|
+ if (showToolCalls.value) {
|
|
|
+ rtn.render_content += `
|
|
|
\`\`\`tools-loading
|
|
|
request
|
|
|
${resp.request.name}
|
|
@@ -260,6 +266,8 @@ ${resp.request.data.replace('\n', '')}
|
|
|
\`\`\`
|
|
|
|
|
|
`
|
|
|
+ }
|
|
|
+
|
|
|
rtn.tool_calls?.push({
|
|
|
id: resp.request.id,
|
|
|
type: 'function',
|
|
@@ -465,6 +473,10 @@ const canSendMessage = computed(() => {
|
|
|
|
|
|
const router = useRouter()
|
|
|
const redirectToModelManager = () => router.push('manage/model')
|
|
|
+
|
|
|
+// 设置面板相关状态
|
|
|
+const showSettingsPanel = ref(false)
|
|
|
+const showToolCalls = ref(false)
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
@@ -473,7 +485,26 @@ const redirectToModelManager = () => router.push('manage/model')
|
|
|
<el-aside width="300px" class="chat-sidebar">
|
|
|
<div class="sidebar-header">
|
|
|
<h3>对话历史</h3>
|
|
|
- <el-button round :icon="EleSetting" size="small" @click="redirectToModelManager"></el-button>
|
|
|
+ <el-dropdown v-model="showSettingsPanel" trigger="click" placement="bottom-end">
|
|
|
+ <el-button round :icon="EleSetting" size="small">
|
|
|
+ <el-icon class="el-icon--right">
|
|
|
+ <ArrowDown />
|
|
|
+ </el-icon>
|
|
|
+ </el-button>
|
|
|
+ <template #dropdown>
|
|
|
+ <el-dropdown-menu>
|
|
|
+ <el-dropdown-item class="settings-item">
|
|
|
+ <div class="settings-row">
|
|
|
+ <span class="settings-label">显示工具调用</span>
|
|
|
+ <el-switch v-model="showToolCalls" size="small" />
|
|
|
+ </div>
|
|
|
+ </el-dropdown-item>
|
|
|
+ <el-dropdown-item @click="redirectToModelManager">
|
|
|
+ <span class="settings-label">模型管理</span>
|
|
|
+ </el-dropdown-item>
|
|
|
+ </el-dropdown-menu>
|
|
|
+ </template>
|
|
|
+ </el-dropdown>
|
|
|
</div>
|
|
|
<el-scrollbar class="conversation-list" v-loading="loadConversations">
|
|
|
<div
|
|
@@ -596,7 +627,16 @@ const redirectToModelManager = () => router.push('manage/model')
|
|
|
{{ 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>
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ @click="replaceMessage(messages.indexOf(message))"
|
|
|
+ class="retry-btn"
|
|
|
+ plain
|
|
|
+ :disabled="isConversationActive"
|
|
|
+ >
|
|
|
+ 重试
|
|
|
+ </el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
<el-avatar class="message-avatar" :src="getUserInfos.avatar" :icon="User" />
|
|
@@ -617,25 +657,7 @@ const redirectToModelManager = () => router.push('manage/model')
|
|
|
<!-- 标题和描述 -->
|
|
|
<div class="empty-text">
|
|
|
<h2 class="empty-title">开始新的对话</h2>
|
|
|
- <p class="empty-description">选择工具和模型,然后在下方输入您的问题开始对话</p>
|
|
|
</div>
|
|
|
-
|
|
|
- <!-- 快速开始提示 -->
|
|
|
- <div class="quick-start">
|
|
|
- <div class="quick-start-item">
|
|
|
- <span class="step-number">1</span>
|
|
|
- <span class="step-text">选择需要的工具</span>
|
|
|
- </div>
|
|
|
- <div class="quick-start-item">
|
|
|
- <span class="step-number">2</span>
|
|
|
- <span class="step-text">选择AI模型</span>
|
|
|
- </div>
|
|
|
- <div class="quick-start-item">
|
|
|
- <span class="step-number">3</span>
|
|
|
- <span class="step-text">输入问题并发送</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
<!-- 示例问题 -->
|
|
|
<div class="example-questions">
|
|
|
<h4>试试这些问题:</h4>
|
|
@@ -703,7 +725,7 @@ const redirectToModelManager = () => router.push('manage/model')
|
|
|
|
|
|
<!-- 按钮组 -->
|
|
|
<div class="button-group">
|
|
|
- <el-button type="warning" size="small" @click="clearMessage" style="margin-left: 12px" :loading="loadingClearMessage"> 清空 </el-button>
|
|
|
+ <el-button v-show="messages.length !== 0" type="warning" size="small" @click="clearMessage" style="margin-left: 12px" :loading="loadingClearMessage"> 清空 </el-button>
|
|
|
<el-button
|
|
|
v-if="!isConversationActive"
|
|
|
type="primary"
|
|
@@ -769,6 +791,7 @@ const redirectToModelManager = () => router.push('manage/model')
|
|
|
border-bottom: 1px solid var(--el-border-color-light);
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
|
|
|
h3 {
|
|
|
margin: 0;
|
|
@@ -778,6 +801,35 @@ const redirectToModelManager = () => router.push('manage/model')
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/* 设置面板样式 */
|
|
|
+:deep(.el-dropdown-menu) {
|
|
|
+ .settings-item {
|
|
|
+ padding: 0;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .settings-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 8px 16px;
|
|
|
+ min-width: 160px;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: var(--el-fill-color-light);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .settings-label {
|
|
|
+ font-size: 14px;
|
|
|
+ color: var(--el-text-color-primary);
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
.conversation-list {
|
|
|
flex: 1;
|
|
|
padding: 10px;
|