From 78e1cda41cf6ad133e84efc78da50d77f2e43eca Mon Sep 17 00:00:00 2001
From: charles <981744753@qq.com>
Date: 星期五, 02 八月 2024 15:56:43 +0800
Subject: [PATCH] feat:完成新增会话的,会话记录的聊天模块
---
src/views/dmx/model/components/addModel.vue | 11 -
src/views/session/sessionManager/components/addSession.vue | 75 +++++++++--
src/api/session.ts | 4
src/api/interceptor.ts | 4
src/views/session/sessionManager/index.vue | 24 ++--
.idea/codeStyles/Project.xml | 4
src/views/sessionRecords/sessionRecordsManager/index.vue | 236 ++++++++++++++++++++++++++++----------
7 files changed, 249 insertions(+), 109 deletions(-)
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 3e22f4b..70dac63 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -3,7 +3,7 @@
<HTMLCodeStyleSettings>
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
</HTMLCodeStyleSettings>
- <JSCodeStyleSettings version="0">
+ <JSCodeStyleSettings>
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
@@ -11,7 +11,7 @@
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
</JSCodeStyleSettings>
- <TypeScriptCodeStyleSettings version="0">
+ <TypeScriptCodeStyleSettings>
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
diff --git a/src/api/interceptor.ts b/src/api/interceptor.ts
index f08ca35..0f73743 100644
--- a/src/api/interceptor.ts
+++ b/src/api/interceptor.ts
@@ -55,7 +55,7 @@
const res = response.data;
// if the custom code is not 20000, it is judged as an error.
- if (
+ /*if (
(res.retcode && res.retcode !== 0) ||
(res.code && res.code !== 20000)
) {
@@ -88,7 +88,7 @@
response.config.url === '/base/login'
) {
setAuthorization(response.headers.authorization);
- }
+ }*/
return res;
},
(error) => {
diff --git a/src/api/session.ts b/src/api/session.ts
index fe2b47f..bd56742 100644
--- a/src/api/session.ts
+++ b/src/api/session.ts
@@ -26,4 +26,8 @@
// 鑾峰彇浼氳瘽璇︽儏
export function getSessionDetailsApi(conversation_id:string) {
return axios.get<ISessionListResult>('/api/conversation/get?modeltype=localragflow',{params:{conversation_id}});
+}
+// 鑾峰彇鏅鸿兘鍔╂墜鍒楄〃
+export function getDialogListApi() {
+ return axios.get<ISessionListResult>('/api/dialog/list');
}
\ No newline at end of file
diff --git a/src/views/dmx/model/components/addModel.vue b/src/views/dmx/model/components/addModel.vue
index eeab066..456a8fa 100644
--- a/src/views/dmx/model/components/addModel.vue
+++ b/src/views/dmx/model/components/addModel.vue
@@ -1,4 +1,3 @@
-
<template>
<a-button type="primary" @click="handleClick" style="margin-left: 10px">
<template #icon>
@@ -138,7 +137,6 @@
done(false)
}else {
console.log('璇锋眰鏁版嵁');
-
}
})
};
@@ -176,12 +174,3 @@
})
</script>
-
-<script lang="ts">
-export default {
- name: 'add',
- methods: {
-
- }
-};
-</script>
\ No newline at end of file
diff --git a/src/views/session/sessionManager/components/addSession.vue b/src/views/session/sessionManager/components/addSession.vue
index 0a1c997..37ebde1 100644
--- a/src/views/session/sessionManager/components/addSession.vue
+++ b/src/views/session/sessionManager/components/addSession.vue
@@ -1,34 +1,75 @@
<script setup lang="ts">
- import { defineProps ,ref,defineEmits} from 'vue';
+ import { defineProps,ref,defineEmits, onMounted } from 'vue';
import { Message } from '@arco-design/web-vue';
- import { addSessionApi }from '@/api/session';
+ import { addSessionApi ,getDialogListApi }from '@/api/session';
const props=defineProps({
modalObj:Object
});
- const conversation_name=ref('');
+ const conversation=ref({ dialog_id:'', conversation_desc:'' });
+ const dialogList=ref([]);
const emit = defineEmits(['addSession']);
- const handleOk=async ()=>{
- if(conversation_name.value){
- const {code}=await addSessionApi({conversation_name:conversation_name.value});
- if(code===200){
- Message.success('娣诲姞鎴愬姛');
- emit('addSession')
- }
- }else{
- Message.warning('浼氳瘽鍚嶇О涓嶈兘涓虹┖');
- }
+ const queryDialogList=async ()=>{
+ const { code, data } = await getDialogListApi();
+ if(code===200){
+ dialogList.value = data;
+ }
+ };
+
+ const rules = {
+ dialog_id: [
+ {
+ required: true,
+ message: '鏅鸿兘鍔╂墜涓嶈兘涓虹┖',
+ },
+ ],
+ conversation_desc: [
+ {
+ required: true,
+ message: '鎻忚堪涓嶈兘涓虹┖',
+ }
+ ]
+ }
+ onMounted(()=>{
+ queryDialogList();
+ });
+ const formRef = ref();
+ const handleOk=()=>{
+ formRef.value.validate().then(async(res)=>{
+ if(!res){
+ const { code }=await addSessionApi({ ...conversation.value });
+ if(code===200){
+ Message.success('娣诲姞鎴愬姛');
+ emit('addSession');
+ setTimeout(()=>{
+ props.modalObj.add=false;
+ },500);
+ }else{
+ Message.warning('娣诲姞澶辫触');
+ }
+ }
+ });
+
+ return false;
+ }
+ const destroyData = ()=>{
+ formRef.value.resetFields();
}
</script>
<template>
<div>
- <a-modal v-model:visible="modalObj.add" @ok="handleOk" @cancel="modalObj.add=false">
+ <a-modal v-model:visible="modalObj.add" @before-ok="handleOk" @cancel="modalObj.add=false" @before-close="destroyData">
<template #title>
鏂板浼氳瘽
</template>
- <a-form>
- <a-form-item label="浼氳瘽鍚嶇О:">
- <a-input placeholder="璇疯緭鍏ヤ細璇濆悕绉�" v-model="conversation_name" style="width: 80%"></a-input>
+ <a-form ref="formRef" :model="conversation" :rules="rules">
+ <a-form-item label="鍔╂墜鍏宠仈:" field="dialog_id" @submit="handleSubmit">
+ <a-select style="width: 80%" v-model="conversation.dialog_id" placeholder="璇烽�夋嫨鍏宠仈鍔╂墜">
+ <a-option v-for="dialog in dialogList" :key="dialog.id" :value="dialog.id">{{dialog.name}}</a-option>
+ </a-select>
+ </a-form-item>
+ <a-form-item label="鎻忚堪:" field="conversation_desc">
+ <a-textarea placeholder="璇疯緭鍏ユ弿杩�" :max-length="100" show-word-limit :auto-size="{minRows:4,maxRows:5}" v-model="conversation.conversation_desc" style="width: 80%"></a-textarea>
</a-form-item>
</a-form>
</a-modal>
diff --git a/src/views/session/sessionManager/index.vue b/src/views/session/sessionManager/index.vue
index 6cdb28a..1348516 100644
--- a/src/views/session/sessionManager/index.vue
+++ b/src/views/session/sessionManager/index.vue
@@ -25,20 +25,20 @@
const streamStr=ref('');
const modalObj=reactive({ add:false });
//鏌ヨ浼氳瘽鍒楄〃
- const querySessionList = async () => {
+ const querySessionList = async () => {
const { code, data } =await sessionListApi();
- if (code === 200) {
- sessionList.value = data;
- if(Array.isArray(data)&&data.length>0){
- activeSessionId.value=data[0].id;
- const res= await getSessionDetailsApi(data[0].id);
- if(res.code===200){
- sessionDetailList.value=res.data.message;
- refreshScroll();
+ if (code === 200) {
+ sessionList.value = data;
+ if(Array.isArray(data)&&data.length>0){
+ activeSessionId.value=data[0].id;
+ const res= await getSessionDetailsApi(data[0].id);
+ if(res.code===200){
+ sessionDetailList.value=res.data.message;
+ refreshScroll();
+ }
}
- }
}else{
- Message.warning('鏌ヨ澶辫触');
+ Message.warning('鏌ヨ澶辫触');
}
};
//鏍规嵁浼氳瘽id鍒犻櫎浼氳瘽
@@ -142,7 +142,7 @@
</a-button>
</template>
<a-scrollbar class="left-list" style="height: 60vh;overflow-y: auto;">
- <div class="item" :class="{isLeftActive:activeSessionId===session.id}" v-for="session in sessionList" :key="session.id" @click="querySessionDetail(session)">
+ <div class="item" :class="{ isLeftActive:activeSessionId===session.id }" v-for="session in sessionList" :key="session.id" @click="querySessionDetail(session)">
<div class="item-left">
<IconQuestionCircleFill/>銆�
{{session.name}}
diff --git a/src/views/sessionRecords/sessionRecordsManager/index.vue b/src/views/sessionRecords/sessionRecordsManager/index.vue
index 528c003..3b3a1e9 100644
--- a/src/views/sessionRecords/sessionRecordsManager/index.vue
+++ b/src/views/sessionRecords/sessionRecordsManager/index.vue
@@ -1,14 +1,65 @@
<script setup lang="ts">
import { IconSearch,IconTiktokColor ,IconSend,IconClose} from '@arco-design/web-vue/es/icon';
import { useAppStore} from '@/store';
- import {computed,ref,onMounted,reactive} from 'vue';
- import {sessionListApi}from '@/api/session';
+ import { computed, ref, onMounted, reactive, nextTick } from 'vue';
import { Message } from '@arco-design/web-vue';
import moment from 'moment';
import AddSession from '@/views/session/sessionManager/components/addSession.vue';
+ import { sessionListApi, deleteSessionApi,getSessionDetailsApi,chatApi }from '@/api/session';
+ const sessionDetailList=ref([]);//鏍规嵁浼氳瘽id鍑烘潵鐨勪細璇濊鎯�
const sessionList=ref([]);//浼氳瘽鍒楄〃
- const modalObj=reactive({add:false});
- //鏌ヨ浼氳瘽鍒楄〃
+ const modalObj=reactive({ add:false });
+
+ const currIndex = ref(0)
+ const displayedText = ref('');// 姝e湪鏄剧ず鐨勬枃瀛�
+ let timer: number|null = null;
+ const streamStr=ref('');
+ const inputMsg=ref('');
+ const activeSessionId=ref('');
+
+ const sendMessage= async (event)=>{
+ event.preventDefault();
+ if(!activeSessionId.value){
+ Message.warning('璇烽�夋嫨浼氳瘽');
+ return;
+ }
+ if(inputMsg.value){
+ const {code,data} =await chatApi({conversation_id:activeSessionId.value,messages:inputMsg.value});
+ const res= await getSessionDetailsApi(activeSessionId.value);
+ if(res.code===200){
+ sessionDetailList.value=res.data.message.map((item,index)=>{
+ if(index===res.data.message.length-1){
+ item.role='last';
+ displayedText.value='';
+ currIndex.value=0;
+ streamStr.value=item.content;
+ startDisplayStr();
+ }
+ return item;
+ });
+ refreshScroll();
+ }
+ inputMsg.value='';
+ }else{
+ Message.warning('娑堟伅涓嶈兘涓虹┖');
+ }
+ };
+ const querySessionDetail=async (session)=>{
+ activeSessionId.value=session.id;
+ const {code,data}= await getSessionDetailsApi(session.id);
+ if(code===200){
+ sessionDetailList.value=data.message;
+ refreshScroll();//鍒锋柊婊氬姩鏉′綅缃�
+ }
+ };
+ const scrollbar = ref(null);
+ const refreshScroll=()=>{
+ nextTick(()=>{
+ const container = document.getElementById('home');
+ scrollbar.value.scrollTop(container.scrollHeight);
+ });
+ };
+ // 鏌ヨ浼氳瘽鍒楄〃
const querySessionList=async ()=>{
const {code,data} =await sessionListApi();
if(code===200){
@@ -28,6 +79,22 @@
const theme = computed(() => {
return appStore.theme;
});
+ //鏂囧瓧鍔ㄦ�佽緭鍑�
+ const startDisplayStr = () => {
+ if (timer) {
+ clearTimeout(timer!);
+ }
+ const res = streamStr.value;
+ // 灏嗘暟缁勪腑鐨勫瓧绗︿覆鎷兼帴璧锋潵
+ if (currIndex.value < res.length) {
+ displayedText.value += res[currIndex.value];
+ currIndex.value++;
+ setTimeout(startDisplayStr, 100);
+ } else {
+ clearTimeout(timer!);
+ timer = null
+ }
+ }
</script>
<template>
@@ -50,7 +117,7 @@
</a-card>
<a-card class="left">
<a-scrollbar class="left-list" style="height: calc(100vh - 160px);overflow-y: auto;overflow-x: hidden;">
- <div class="item" v-for="session in sessionList">
+ <div class="item" v-for="session in sessionList" @click="querySessionDetail(session)" :class="{ isLeftActive:activeSessionId===session.id }">
<div class="text" :class="{light:theme==='dark'}">{{session.name}}</div>
<div class="time">{{moment(new Date(session.create_time)).format('YYYY-MM-DD HH:mm:ss')}}</div>
</div>
@@ -59,68 +126,102 @@
</a-col>
<a-col :span="15">
<a-card class="center">
- <div class="center-title">鏅鸿兘闂瓟</div>
- <div class="center-content">
- 鎴戝彲浠ョ悊瑙e拰瀛︿範浜虹被鐨勮瑷�锛屽叿澶囧杞璇濈殑鑳藉姏锛岀幇鍦ㄥ拰鎴戝紑濮嬩氦娴佸惂~
- </div>
- <div class="center-question">
- <div class="center-question-left">璇曚竴璇曡繖鏍烽棶鎴�</div>
- <div class="center-question-right">
- <a-button type="primary">鎹竴鎹�</a-button>
+ <div v-if="sessionDetailList.length===0">
+ <div class="center-title">鏅鸿兘闂瓟</div>
+ <div class="center-content">
+ 鎴戝彲浠ョ悊瑙e拰瀛︿範浜虹被鐨勮瑷�锛屽叿澶囧杞璇濈殑鑳藉姏锛岀幇鍦ㄥ拰鎴戝紑濮嬩氦娴佸惂~
</div>
+ <div class="center-question">
+ <div class="center-question-left">璇曚竴璇曡繖鏍烽棶鎴�</div>
+ <div class="center-question-right">
+ <a-button type="primary">鎹竴鎹�</a-button>
+ </div>
+ </div>
+ <a-row justify="space-around" class="center-list">
+ <a-col :span="7" class="item">
+ <div class="item-title">
+ <IconTiktokColor></IconTiktokColor>鎶栭煶甯﹁揣鑴氭湰
+ </div>
+ <div class="item-content" :class="{dark:theme==='dark'}">
+ 缂栧啓寮曚汉娉ㄧ洰涓斿叿鏈夎鏈嶅姏鐨勩�侀�傜敤浜庝骇鍝佺殑...
+ </div>
+ </a-col>
+ <a-col :span="7" class="item">
+ <div class="item-title">
+ <IconTiktokColor></IconTiktokColor>鎶栭煶甯﹁揣鑴氭湰
+ </div>
+ <div class="item-content" :class="{dark:theme==='dark'}">
+ 缂栧啓寮曚汉娉ㄧ洰涓斿叿鏈夎鏈嶅姏鐨勩�侀�傜敤浜庝骇鍝佺殑...
+ </div>
+ </a-col>
+ <a-col :span="7" class="item">
+ <div class="item-title">
+ <IconTiktokColor></IconTiktokColor>鎶栭煶甯﹁揣鑴氭湰
+ </div>
+ <div class="item-content" :class="{dark:theme==='dark'}">
+ 缂栧啓寮曚汉娉ㄧ洰涓斿叿鏈夎鏈嶅姏鐨勩�侀�傜敤浜庝骇鍝佺殑...
+ </div>
+ </a-col>
+ <a-col :span="7" class="item">
+ <div class="item-title">
+ <IconTiktokColor></IconTiktokColor>鎶栭煶甯﹁揣鑴氭湰
+ </div>
+ <div class="item-content" :class="{dark:theme==='dark'}">
+ 缂栧啓寮曚汉娉ㄧ洰涓斿叿鏈夎鏈嶅姏鐨勩�侀�傜敤浜庝骇鍝佺殑...
+ </div>
+ </a-col>
+ <a-col :span="7" class="item">
+ <div class="item-title">
+ <IconTiktokColor></IconTiktokColor>鎶栭煶甯﹁揣鑴氭湰
+ </div>
+ <div class="item-content" :class="{dark:theme==='dark'}">
+ 缂栧啓寮曚汉娉ㄧ洰涓斿叿鏈夎鏈嶅姏鐨勩�侀�傜敤浜庝骇鍝佺殑...
+ </div>
+ </a-col>
+ <a-col :span="7" class="item">
+ <div class="item-title">
+ <IconTiktokColor></IconTiktokColor>鎶栭煶甯﹁揣鑴氭湰
+ </div>
+ <div class="item-content" :class="{dark:theme==='dark'}">
+ 缂栧啓寮曚汉娉ㄧ洰涓斿叿鏈夎鏈嶅姏鐨勩�侀�傜敤浜庝骇鍝佺殑...
+ </div>
+ </a-col>
+ </a-row>
</div>
- <a-row justify="space-around" class="center-list">
- <a-col :span="7" class="item">
- <div class="item-title">
- <IconTiktokColor></IconTiktokColor>鎶栭煶甯﹁揣鑴氭湰
- </div>
- <div class="item-content" :class="{dark:theme==='dark'}">
- 缂栧啓寮曚汉娉ㄧ洰涓斿叿鏈夎鏈嶅姏鐨勩�侀�傜敤浜庝骇鍝佺殑...
- </div>
- </a-col>
- <a-col :span="7" class="item">
- <div class="item-title">
- <IconTiktokColor></IconTiktokColor>鎶栭煶甯﹁揣鑴氭湰
- </div>
- <div class="item-content" :class="{dark:theme==='dark'}">
- 缂栧啓寮曚汉娉ㄧ洰涓斿叿鏈夎鏈嶅姏鐨勩�侀�傜敤浜庝骇鍝佺殑...
- </div>
- </a-col>
- <a-col :span="7" class="item">
- <div class="item-title">
- <IconTiktokColor></IconTiktokColor>鎶栭煶甯﹁揣鑴氭湰
- </div>
- <div class="item-content" :class="{dark:theme==='dark'}">
- 缂栧啓寮曚汉娉ㄧ洰涓斿叿鏈夎鏈嶅姏鐨勩�侀�傜敤浜庝骇鍝佺殑...
- </div>
- </a-col>
- <a-col :span="7" class="item">
- <div class="item-title">
- <IconTiktokColor></IconTiktokColor>鎶栭煶甯﹁揣鑴氭湰
- </div>
- <div class="item-content" :class="{dark:theme==='dark'}">
- 缂栧啓寮曚汉娉ㄧ洰涓斿叿鏈夎鏈嶅姏鐨勩�侀�傜敤浜庝骇鍝佺殑...
- </div>
- </a-col>
- <a-col :span="7" class="item">
- <div class="item-title">
- <IconTiktokColor></IconTiktokColor>鎶栭煶甯﹁揣鑴氭湰
- </div>
- <div class="item-content" :class="{dark:theme==='dark'}">
- 缂栧啓寮曚汉娉ㄧ洰涓斿叿鏈夎鏈嶅姏鐨勩�侀�傜敤浜庝骇鍝佺殑...
- </div>
- </a-col>
- <a-col :span="7" class="item">
- <div class="item-title">
- <IconTiktokColor></IconTiktokColor>鎶栭煶甯﹁揣鑴氭湰
- </div>
- <div class="item-content" :class="{dark:theme==='dark'}">
- 缂栧啓寮曚汉娉ㄧ洰涓斿叿鏈夎鏈嶅姏鐨勩�侀�傜敤浜庝骇鍝佺殑...
- </div>
- </a-col>
- </a-row>
+ <a-scrollbar ref="scrollbar" id="home" v-else class="chat-list" style="width:90%;overflow:auto;height: 60vh;margin: 0px auto">
+ <div class="chat-item" v-for="sessionDetail in sessionDetailList">
+ <a-comment
+ v-if="sessionDetail.role==='user'"
+ avatar="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp"
+ >
+ <template #content>
+ <div :class="{light:theme==='light'}">{{sessionDetail.content}}</div>
+ </template>
+ </a-comment>
+ <a-comment
+ v-else-if="sessionDetail.role==='assistant'"
+ avatar="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/9eeb1800d9b78349b24682c3518ac4a3.png~tplv-uwbnlip3yd-webp.webp"
+ >
+ <template #content>
+ <a-card class="chat-item-answer" style="background-color: rgba(63, 64, 79, 1);">
+ <div :class="{light:theme==='light'}">{{sessionDetail.content}}</div>
+ </a-card>
+ </template>
+ </a-comment>
+ <a-comment
+ v-else-if="sessionDetail.role==='last'"
+ avatar="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/9eeb1800d9b78349b24682c3518ac4a3.png~tplv-uwbnlip3yd-webp.webp"
+ >
+ <template #content>
+ <a-textarea readonly auto-size v-model="displayedText" class="chat-item-answer" style="background-color: rgba(63, 64, 79, 1);">
+ </a-textarea>
+ </template>
+ </a-comment>
+ </div>
+ </a-scrollbar>
+
<div class="center-bottom">
- <a-textarea style="height: 180px" placeholder="杈撳叆鎮ㄦ兂浜嗚В鐨勫唴瀹癸紝Shift+Enter鎹㈣" :max-length="500" allow-clear show-word-limit>
+ <a-textarea v-model="inputMsg" @keydown.shift.enter="sendMessage" style="height: 180px" placeholder="杈撳叆鎮ㄦ兂浜嗚В鐨勫唴瀹癸紝Shift+Enter鍙戦��" :max-length="500" allow-clear show-word-limit>
</a-textarea>
</div>
</a-card>
@@ -181,6 +282,9 @@
</template>
<style scoped lang="scss">
+ .isLeftActive{
+ background-color:lightgrey;
+ }
.light{
color: white !important;
}
@@ -210,10 +314,12 @@
}
.text{
color: black;
+ padding-left: 10px;
}
.time{
color: gray;
font-size: 12px;
+ padding-left: 10px;
}
}
}
@@ -269,7 +375,7 @@
.center-bottom{
position: absolute;
width: 90%;
- bottom: 70px;
+ bottom: 20px;
left:5%;
}
}
--
Gitblit v1.8.0