瀏覽代碼

【新增】AI:新建对话时,不使用默认角色

YunaiV 1 年之前
父節點
當前提交
8764c6c471
共有 3 個文件被更改,包括 63 次插入26 次删除
  1. 1 1
      src/api/ai/chat/conversation/index.ts
  2. 41 20
      src/views/ai/chat/Message.vue
  3. 21 5
      src/views/ai/chat/index.vue

+ 1 - 1
src/api/ai/chat/conversation/index.ts

@@ -12,8 +12,8 @@ export interface ChatConversationVO {
   temperature: number // 温度参数
   maxTokens: number // 单条回复的最大 Token 数量
   maxContexts: number // 上下文的最大 Message 数量
-  updateTime: number // 更新时间
   // 额外字段
+  systemMessage?: string // 角色设定
   modelName?: string // 模型名字
   roleAvatar?: string // 角色头像
   modelMaxTokens?: string // 模型的单条回复的最大 Token 数量

+ 41 - 20
src/views/ai/chat/Message.vue

@@ -1,8 +1,7 @@
 <template>
-  <div ref="messageContainer" style="height: 100%;overflow-y: auto;position: relative;">
-    <div class="chat-list" v-for="(item, index) in list" :key="index" >
+  <div ref="messageContainer" style="height: 100%; overflow-y: auto; position: relative">
+    <div class="chat-list" v-for="(item, index) in messageList" :key="index">
       <!--  靠左 message  -->
-      <!-- TODO 芋艿:类型判断 -->
       <div class="left-message message-item" v-if="item.type !== 'user'">
         <div class="avatar">
           <el-avatar :src="item.roleAvatar" />
@@ -16,10 +15,10 @@
           </div>
           <div class="left-btns">
             <el-button class="btn-cus" link @click="noCopy(item.content)">
-              <img class="btn-image" src="@/assets/ai/copy.svg"/>
+              <img class="btn-image" src="@/assets/ai/copy.svg" />
             </el-button>
             <el-button class="btn-cus" link @click="onDelete(item.id)">
-              <img class="btn-image" src="@/assets/ai/delete.svg" style="height: 17px; "/>
+              <img class="btn-image" src="@/assets/ai/delete.svg" style="height: 17px" />
             </el-button>
           </div>
         </div>
@@ -38,10 +37,14 @@
           </div>
           <div class="right-btns">
             <el-button class="btn-cus" link @click="noCopy(item.content)">
-              <img class="btn-image" src="@/assets/ai/copy.svg"/>
+              <img class="btn-image" src="@/assets/ai/copy.svg" />
             </el-button>
             <el-button class="btn-cus" link @click="onDelete(item.id)">
-              <img class="btn-image" src="@/assets/ai/delete.svg" style="height: 17px;margin-right: 12px;"/>
+              <img
+                class="btn-image"
+                src="@/assets/ai/delete.svg"
+                style="height: 17px; margin-right: 12px"
+              />
             </el-button>
             <el-button class="btn-cus" link @click="onRefresh(item)">
               <el-icon size="17"><RefreshRight /></el-icon>
@@ -60,30 +63,49 @@
   </div>
 </template>
 <script setup lang="ts">
-import {formatDate} from "@/utils/formatTime";
-import MarkdownView from "@/components/MarkdownView/index.vue";
-import {ChatMessageApi, ChatMessageVO} from "@/api/ai/chat/message";
-import {useClipboard} from "@vueuse/core";
-import {PropType} from "vue";
-import {ArrowDownBold, Edit, RefreshRight} from "@element-plus/icons-vue";
-
-const {copy} = useClipboard() // 初始化 copy 到粘贴板
+import { formatDate } from '@/utils/formatTime'
+import MarkdownView from '@/components/MarkdownView/index.vue'
+import { ChatMessageApi, ChatMessageVO } from '@/api/ai/chat/message'
+import { useClipboard } from '@vueuse/core'
+import { PropType } from 'vue'
+import { ArrowDownBold, Edit, RefreshRight } from '@element-plus/icons-vue'
+import { ChatConversationVO } from '@/api/ai/chat/conversation'
+
+const { copy } = useClipboard() // 初始化 copy 到粘贴板
 // 判断 消息列表 滚动的位置(用于判断是否需要滚动到消息最下方)
 const messageContainer: any = ref(null)
 const isScrolling = ref(false) //用于判断用户是否在滚动
 
 // 定义 props
 const props = defineProps({
+  conversation: {
+    type: Object as PropType<ChatConversationVO>,
+    required: true
+  },
   list: {
     type: Array as PropType<ChatMessageVO[]>,
     required: true
   }
 })
 
+const messageList = computed(() => {
+  if (props.list && props.list.length > 0) {
+    return props.list
+  }
+  if (props.conversation && props.conversation.systemMessage) {
+    return [{
+      id: 0,
+      type: 'system',
+      content: props.conversation.systemMessage
+    }]
+  }
+  return []
+})
+
 // ============ 处理对话滚动 ==============
 
-const scrollToBottom = async (isIgnore?: boolean) =>{
-   await nextTick(() => {
+const scrollToBottom = async (isIgnore?: boolean) => {
+  await nextTick(() => {
     //注意要使用nexttick以免获取不到dom
     if (isIgnore || !isScrolling.value) {
       messageContainer.value.scrollTop =
@@ -97,7 +119,7 @@ function handleScroll() {
   const scrollTop = scrollContainer.scrollTop
   const scrollHeight = scrollContainer.scrollHeight
   const offsetHeight = scrollContainer.offsetHeight
-  if ((scrollTop + offsetHeight) < (scrollHeight - 100)) {
+  if (scrollTop + offsetHeight < scrollHeight - 100) {
     // 用户开始滚动并在最底部之上,取消保持在最底部的效果
     isScrolling.value = true
   } else {
@@ -168,7 +190,7 @@ watch(list, async (newValue, oldValue) => {
 })
 
 // 提供方法给 parent 调用
-defineExpose({scrollToBottom, handlerGoTop})
+defineExpose({ scrollToBottom, handlerGoTop })
 
 // 定义 emits
 const emits = defineEmits(['onDeleteSuccess', 'onRefresh', 'onEdit'])
@@ -191,7 +213,6 @@ onMounted(async () => {
   overflow-y: scroll;
   //padding: 0 15px;
   //z-index: -1;
-
 }
 
 // 中间

+ 21 - 5
src/views/ai/chat/index.vue

@@ -36,10 +36,11 @@
           <div class="message-container" >
             <MessageLoading v-if="listLoading" />
             <MessageNewChat v-if="!activeConversation" @on-new-chat="handlerNewChat" />
-            <ChatEmpty v-if="!listLoading && list.length === 0 && activeConversation" @on-prompt="doSend"/>
-            <Message v-if="!listLoading && list.length > 0"
+            <ChatEmpty v-if="!listLoading && messageList.length === 0 && activeConversation" @on-prompt="doSend"/>
+            <Message v-if="!listLoading && messageList.length > 0"
                      ref="messageRef"
-                     :list="list"
+                     :conversation="activeConversation"
+                     :list="messageList"
                      @on-delete-success="handlerMessageDelete"
                      @on-edit="handlerMessageEdit"
                      @on-refresh="handlerMessageRefresh"/>
@@ -103,13 +104,11 @@ import MessageNewChat from './MessageNewChat.vue'
 import {ChatMessageApi, ChatMessageVO} from '@/api/ai/chat/message'
 import {ChatConversationApi, ChatConversationVO} from '@/api/ai/chat/conversation'
 import { getUserProfile, ProfileVO } from '@/api/system/user/profile'
-import {useClipboard} from '@vueuse/core'
 import ChatConversationUpdateForm from "@/views/ai/chat/components/ChatConversationUpdateForm.vue";
 import {Download, Top} from "@element-plus/icons-vue";
 
 const route = useRoute() // 路由
 const message = useMessage() // 消息弹窗
-const {copy} = useClipboard() // 初始化 copy 到粘贴板
 
 // ref 属性定义
 const activeConversationId = ref<string | null>(null) // 选中的对话编号
@@ -391,6 +390,23 @@ const stopStream = async () => {
 
 // ============== message 数据 =================
 
+/** 消息列表 */
+const messageList = computed(() => {
+  if (list.value.length > 0) {
+    return list.value
+  }
+  // 没有消息时,如果有 systemMessage 则展示它
+  // TODO add by 芋艿:这个消息下面,不能有复制、删除按钮
+  if (activeConversation.value?.systemMessage) {
+    return [{
+      id: 0,
+      type: 'system',
+      content: activeConversation.value.systemMessage
+    }]
+  }
+  return []
+})
+
 /**
  * 获取 - message 列表
  */