Browse Source

aichat 暂停

master
xueyinfei 2 weeks ago
parent
commit
565385567f
  1. 4
      vue-fastapi-frontend/src/api/aichat/aichat.js
  2. 24
      vue-fastapi-frontend/src/layout/components/AppMain.vue
  3. 5
      vue-fastapi-frontend/src/utils/request.js
  4. 64
      vue-fastapi-frontend/src/views/aichat/aichat.vue
  5. 28
      vue-fastapi-frontend/src/views/aichat/index.vue

4
vue-fastapi-frontend/src/api/aichat/aichat.js

@ -22,8 +22,8 @@ export function getChatList(sessionId) {
}) })
} }
export function postChatMessage(data) { export function postChatMessage(data,signal) {
return postStream('/aichat-api/stream-chat',data) return postStream('/aichat-api/robot/robot_chat',data,signal)
} }
export function DeleteChatSession(sessionId) { export function DeleteChatSession(sessionId) {

24
vue-fastapi-frontend/src/layout/components/AppMain.vue

@ -11,8 +11,8 @@
<el-link :underline="false" class="ai_chat_link" :style="{display: showDiv?'none':'block'}" @click="showDivClick"> <el-link :underline="false" class="ai_chat_link" :style="{display: showDiv?'none':'block'}" @click="showDivClick">
<img src="@/assets/images/aichat.gif"/> <img src="@/assets/images/aichat.gif"/>
</el-link> </el-link>
<div class="ai_chat_div" :style="aiChatDivStyle"> <div class="ai_chat_div" v-if="showDiv" :style="aiChatDivStyle">
<aichat-index :is_large="largeDiv" :chatDataList="chatDataList"></aichat-index> <aichat-index :is_large="largeDiv"></aichat-index>
<div class="ai_chat_div_operate"> <div class="ai_chat_div_operate">
<el-link :underline="false" style="font-size: 20px;" :style="{display:largeDiv?'none':'block'}" @click="littleChatDiv"><i class="ri-collapse-diagonal-line"></i></el-link> <el-link :underline="false" style="font-size: 20px;" :style="{display:largeDiv?'none':'block'}" @click="littleChatDiv"><i class="ri-collapse-diagonal-line"></i></el-link>
<el-link :underline="false" style="font-size: 20px;" :style="{display:largeDiv?'block':'none'}" @click="largeChatDiv"><i class="ri-expand-diagonal-line"></i></el-link> <el-link :underline="false" style="font-size: 20px;" :style="{display:largeDiv?'block':'none'}" @click="largeChatDiv"><i class="ri-expand-diagonal-line"></i></el-link>
@ -35,7 +35,6 @@ const route = useRoute()
const tagsViewStore = useTagsViewStore() const tagsViewStore = useTagsViewStore()
const showDiv = ref(false) const showDiv = ref(false)
const largeDiv = ref(true) const largeDiv = ref(true)
const chatDataList = ref([])
const aiChatDivStyle = ref({display: 'none',width: '450px',height: '600px',bottom: '16px',right: '16px'}) const aiChatDivStyle = ref({display: 'none',width: '450px',height: '600px',bottom: '16px',right: '16px'})
@ -61,25 +60,6 @@ function largeChatDiv(){
function showDivClick(){ function showDivClick(){
showDiv.value = !showDiv.value showDiv.value = !showDiv.value
aiChatDivStyle.value.display = 'block' aiChatDivStyle.value.display = 'block'
if (Cookies.get("chatSessionId")){
//
getChatList(Cookies.get("chatSessionId")).then(res=>{
let array = res.data
if (array && array.length >0){
for (let i = 0; i < array.length; i++) {
if (array[i].type === 'answer'){
array[i].content = JSON.parse(array[i].content)
}
if (array[i].type === 'question'){
array[i].file = JSON.parse(array[i].file)
}
}
}
chatDataList.value = array
})
}else {
Cookies.set("chatSessionId",uuidv4())
}
} }
function littleChatDiv(){ function littleChatDiv(){

5
vue-fastapi-frontend/src/utils/request.js

@ -157,11 +157,12 @@ export default service
* @param data 请求body * @param data 请求body
* @returns * @returns
*/ */
export function postStream(url, data) { export function postStream(url, data,signal) {
const headers = { 'Content-Type': 'application/json' } const headers = { 'Content-Type': 'application/json' }
return fetch(url, { return fetch(url, {
method: 'POST', method: 'POST',
body: data ? JSON.stringify(data) : undefined, body: data ? JSON.stringify(data) : undefined,
headers: headers headers: headers,
signal: signal.signal
}) })
} }

64
vue-fastapi-frontend/src/views/aichat/aichat.vue

@ -44,7 +44,7 @@
v-if="item.isStop && !item.isEnd" v-if="item.isStop && !item.isEnd"
@click="startChat(index)" @click="startChat(index)"
link link
>继续 >重新生成
</el-button> </el-button>
<el-button type="primary" v-else-if="!item.isEnd" @click="stopChat(index)" link <el-button type="primary" v-else-if="!item.isEnd" @click="stopChat(index)" link
>停止回答 >停止回答
@ -150,7 +150,7 @@
</div> </div>
</div> </div>
<!-- 文件导入对话框 --> <!-- 文件导入对话框 -->
<el-dialog title="文件导入" v-model="upload.open" width="400px" append-to-body> <el-dialog z-index="9999" title="文件导入" v-model="upload.open" width="400px" append-to-body>
<el-upload v-if="upload.open" <el-upload v-if="upload.open"
ref="uploadRef" ref="uploadRef"
:headers="upload.headers" :headers="upload.headers"
@ -229,6 +229,7 @@ const inputValue = ref('')
const chartOpenId = ref('') const chartOpenId = ref('')
const chatList = ref([]) const chatList = ref([])
const answerList = ref([]) const answerList = ref([])
const controller = ref(null)
const popoverVisible = ref(false) const popoverVisible = ref(false)
const currentMachine = ref([]) const currentMachine = ref([])
@ -263,32 +264,22 @@ function setScrollBottom() {
*/ */
const scrollTop = ref(0) const scrollTop = ref(0)
const scorll = ref(true)
const getMaxHeight = () => { const getMaxHeight = () => {
return dialogScrollbar.value.scrollHeight return dialogScrollbar.value.scrollHeight
} }
const handleScrollTop = ($event) => { const handleScrollTop = ($event) => {
scrollTop.value = $event.scrollTop scrollTop.value = $event.scrollTop
if (
dialogScrollbar.value.scrollHeight - (scrollTop.value + scrollDiv.value.wrapRef.offsetHeight) <=
30
) {
scorll.value = true
} else {
scorll.value = false
}
emit('scroll', { ...$event, dialogScrollbar: dialogScrollbar.value, scrollDiv: scrollDiv.value }) emit('scroll', { ...$event, dialogScrollbar: dialogScrollbar.value, scrollDiv: scrollDiv.value })
} }
const handleScroll = () => { const handleScroll = () => {
if (!props.log && scrollDiv.value) { if (scrollDiv.value) {
// //
if (scrollDiv.value.wrapRef.offsetHeight < dialogScrollbar.value.scrollHeight) { if (scrollDiv.value.wrapRef.offsetHeight < dialogScrollbar.value.scrollHeight) {
// //
if (scorll.value) {
scrollDiv.value.setScrollTop(getMaxHeight()) scrollDiv.value.setScrollTop(getMaxHeight())
}
} }
} }
} }
@ -303,7 +294,8 @@ const handleFileSuccess = (response, file, fileList) => {
currentFiles.value.push({file:response.data.file,bucket:response.data.bucket}) currentFiles.value.push({file:response.data.file,bucket:response.data.bucket})
upload.open = false; upload.open = false;
upload.isUploading = false; upload.isUploading = false;
proxy.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true }); proxy.$modal.msgSuccess(response.msg);
// proxy.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "", { dangerouslyUseHTMLString: true });
}; };
/** 提交上传文件 */ /** 提交上传文件 */
@ -425,7 +417,9 @@ async function sendChatHandle(event) {
if (!event.ctrlKey) { if (!event.ctrlKey) {
// ctrl // ctrl
event.preventDefault() event.preventDefault()
if (inputValue.value.trim() && ((chatList.value.length > 1 && chatList.value[chatList.value.length - 1].isEnd) || chatList.value.length < 2)) { if (inputValue.value.trim() && (chatList.value.length === 0||
(chatList.value[chatList.value.length - 1].isStop ||
chatList.value[chatList.value.length - 1].isEnd))) {
chatList.value.push({ chatList.value.push({
"type": "question", "type": "question",
"content": inputValue.value.trim(), "content": inputValue.value.trim(),
@ -434,13 +428,13 @@ async function sendChatHandle(event) {
"sessionName": chatList.value.length > 0 ? chatList.value[0].content.substring(0, 20) : inputValue.value.trim().substring(0, 20), "sessionName": chatList.value.length > 0 ? chatList.value[0].content.substring(0, 20) : inputValue.value.trim().substring(0, 20),
"file": currentFiles.value "file": currentFiles.value
}) })
let question = JSON.parse(JSON.stringify(chatList.value[chatList.value.length - 1]))
question.file = JSON.stringify(question.file)
await addChat(question)
nextTick(() => { nextTick(() => {
// //
scrollDiv.value.setScrollTop(getMaxHeight()) scrollDiv.value.setScrollTop(getMaxHeight())
}) })
let question = JSON.parse(JSON.stringify(chatList.value[chatList.value.length - 1]))
question.file = JSON.stringify(question.file)
await addChat(question)
inputValue.value = '' inputValue.value = ''
let data = { let data = {
"query": inputValue.value.trim(), "query": inputValue.value.trim(),
@ -459,7 +453,11 @@ async function sendChatHandle(event) {
} }
function sendChatMessage(data){ function sendChatMessage(data){
postChatMessage(data).then(res=>{ controller.value = new AbortController()
postChatMessage(data,{signal:controller.value.signal}).then(res=>{
if (res.status !== 200){
chatList.value.push({"type":"answer","content":[{"type":"text","content":"服务异常,错误码:"+res.status}],"isEnd":true,"isStop":false,"sessionId":chatList.value[0].sessionId,"sessionName":chatList.value[0].sessionName,"operate":'',"thumbDownReason":''})
}else {
currentFiles.value = [] currentFiles.value = []
chatList.value.push({"type":"answer","content":[],"isEnd":false,"isStop":false,"sessionId":chatList.value[0].sessionId,"sessionName":chatList.value[0].sessionName, "operate":'',"thumbDownReason":''}) chatList.value.push({"type":"answer","content":[],"isEnd":false,"isStop":false,"sessionId":chatList.value[0].sessionId,"sessionName":chatList.value[0].sessionName, "operate":'',"thumbDownReason":''})
answerList.value.push({"index":chatList.value.length-1, "content":[], "isEnd":false}) answerList.value.push({"index":chatList.value.length-1, "content":[], "isEnd":false})
@ -470,16 +468,21 @@ function sendChatMessage(data){
answer.content = JSON.stringify(answer.content) answer.content = JSON.stringify(answer.content)
addChat(answer) addChat(answer)
}) })
}
}).catch((e) => { }).catch((e) => {
chatList.value.push({"type":"answer","content":[{"type":"text","content":"服务异常"}],"isEnd":true,"isStop":false}) chatList.value.push({"type":"answer","content":[{"type":"text","content":"服务异常"}],"isEnd":true,"isStop":false,"sessionId":chatList.value[0].sessionId,"sessionName":chatList.value[0].sessionName,"operate":"","thumbDownReason":""})
}) })
} }
watch( watch(
chatList, chatList,
() => { () => {
handleScroll() nextTick(() => {
}, //
{ deep: true, immediate: true } scrollDiv.value.setScrollTop(getMaxHeight())
})
},{
deep:true, immediate:true
}
) )
const getWrite = (reader) => { const getWrite = (reader) => {
let tempResult = ''; let tempResult = '';
@ -533,7 +536,8 @@ const getWrite = (reader) => {
answerList.value[answerList.value.length - 1].content.push({"content":chunk.choices[0].delta.content,"type":"text"}) answerList.value[answerList.value.length - 1].content.push({"content":chunk.choices[0].delta.content,"type":"text"})
} }
} }
if (!chatList.value[answerList.value[answerList.value.length - 1].index].isStop){ let isStop = chatList.value[chatList.value.length-1].isStop
if (!isStop){
chatList.value[chatList.value.length - 1].content = answerList.value[answerList.value.length - 1].content chatList.value[chatList.value.length - 1].content = answerList.value[answerList.value.length - 1].content
} }
nextTick(() => { nextTick(() => {
@ -543,7 +547,7 @@ const getWrite = (reader) => {
if (chunk.isEnd){ if (chunk.isEnd){
answerList.value[answerList.value.length - 1].isEnd = true answerList.value[answerList.value.length - 1].isEnd = true
answerList.value[answerList.value.length - 1].time = formatDate(new Date()) answerList.value[answerList.value.length - 1].time = formatDate(new Date())
if (!chatList.value[answerList.value[answerList.value.length - 1].index].isStop){ if (!isStop){
chatList.value[chatList.value.length - 1].isEnd = true chatList.value[chatList.value.length - 1].isEnd = true
chatList.value[chatList.value.length - 1].time = formatDate(new Date()) chatList.value[chatList.value.length - 1].time = formatDate(new Date())
} }
@ -565,9 +569,15 @@ const getWrite = (reader) => {
const stopChat = (index) => { const stopChat = (index) => {
chatList.value[index].isStop = true chatList.value[index].isStop = true
if (controller.value !== null){
controller.value.abort()
}
let answer = JSON.parse(JSON.stringify(chatList.value[index]))
answer.content = JSON.stringify(answer.content)
addChat(answer)
} }
const startChat = (index) => { const startChat = (index) => {
chatList.value[index].isStop = false regenerationChart(index)
} }
defineExpose({ defineExpose({

28
vue-fastapi-frontend/src/views/aichat/index.vue

@ -109,7 +109,7 @@ function deleteLog(row) {
listChatHistory(sessionId).then(response =>{ listChatHistory(sessionId).then(response =>{
chatLogeData.value = response.data chatLogeData.value = response.data
}) })
proxy.$modal.msgSuccess("复制成功"); proxy.$modal.msgSuccess("删除成功");
}) })
} }
@ -159,7 +159,31 @@ function clickListHandle(item){
}) })
} }
watch(() => props.chatDataList, value => currentRecordList.value = JSON.parse(JSON.stringify(value))) watch(() => props.chatDataList, value => currentRecordList.value = JSON.parse(JSON.stringify(value)))
onMounted(
()=>{
if (Cookies.get("chatSessionId")){
//
getChatList(Cookies.get("chatSessionId")).then(res=>{
let array = res.data
if (array && array.length >0){
for (let i = 0; i < array.length; i++) {
if (array[i].type === 'answer'){
array[i].content = JSON.parse(array[i].content)
}
if (array[i].type === 'question'){
array[i].file = JSON.parse(array[i].file)
}
}
}
currentRecordList.value = array
}).then(()=>{
AiChatRef.value.setScrollBottom()
})
}else {
Cookies.set("chatSessionId",uuidv4())
}
}
)
</script> </script>
<style lang="scss"> <style lang="scss">

Loading…
Cancel
Save