当前位置: 首页 > news >正文

vue实现模拟 ai 对话功能

<template><div class="content" ><div class="left-part"><div class="left-part-title"><img src="../../assets/images/main/ai-icon.png" alt=""><span>AI问答模式</span></div><div class="left-part-btn" @click="startNewDialog"><img src="../../assets/images/main/ai-chat-icon.png" alt=""><span>开启新对话</span></div><div class="chart-history"><div v-for="(i,j) in state.chartHistory" :key="j" class="chart-item"><div class="chart-item-title">{{ i.date }}</div><div class="chart-item-list"><div v-for="(k,l) in i.children" :key="l" @click="getCurrentHistory(k)">{{ k.content }}</div></div></div></div></div><div class="right-part"><div class="right-part-dialog" ref="contentRef"><div class="right-part-dialog-item" v-for="(i,j) in state.chatContentData" :key="j" :class="[i.sender]"><div class="right-part-dialog-item-content" v-if="i.sender == 'people'">{{ i.content }}</div><div  v-if="i.sender == 'bot'"><div class="right-part-dialog-item-content">{{ i.content }}</div><div style="margin-top: 15px;" v-html="i.content1" ></div></div></div></div><div class="right-part-input"><div class="main-input"><a-textarea :bordered="false" :disabled="state.inputDisabled" :auto-size="{ minRows: 5, maxRows: 5 }" v-model:value.trim="state.inputValue"  @keydown.enter.prevent="handleEnterKey" placeholder="请输入内容" /><div class="main-input-btn" :class="{ 'main-input-btn-active': state.inputValue}" @click.enter="sendQuestion"><svg t="1752720657922" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="20272" width="200" height="200"><path d="M512 0C229.974122 0 0.946396 229.027726 0.946396 511.053604s229.027726 511.053604 511.053604 511.053605 511.053604-229.027726 511.053604-511.053605S794.025878 0 512 0z m-96.532348 779.829945v-123.031424l73.818854 20.820703-73.818854 102.210721z m232.813309-88.961183l-227.134935-70.033272L625.567468 382.343808 364.362292 603.80037 152.369686 539.445471l613.264325-297.168207-117.35305 448.591498z m0 0" fill="currentColor" p-id="20273"></path></svg></div></div></div></div></div>
</template><script lang="ts" setup>
import {getChatHistory} from '../../components/http/api/index'
import axios from 'axios'
import {onMounted, reactive,ref,nextTick} from 'vue'
const props=defineProps(['question'])
const state = reactive({inputValue: props.question,inputDisabled:false,chartHistory:[],chatContentData:[{content: '你好!我是AI助手,有什么可以帮您的?',content1:'',sender: 'bot'},]
})const contentRef = ref()
onMounted(() => {// if(props.question){//     sendQuestion()// }chatHistory() // 获取聊天记录})// 点击历史记录
const getCurrentHistory=(val)=>{if(state.inputDisabled) returnstate.inputValue = val.contentsendQuestion()
}
const chatHistory =  () => { getChatHistory().then(res=>{if(res.data&&res.data.length>0){state.chartHistory = res.data}else{state.chartHistory =[]}})
}
const handleEnterKey = (e: KeyboardEvent) => {// 检查是否同时按下了Shift键(允许换行)if (e.shiftKey) {// 允许默认行为(换行)return;}// 如果没有按Shift键且输入内容不为空,则发送消息if (!e.shiftKey && state.inputValue.trim()) {sendQuestion()}// 如果按下了Shift+Enter,会自动换行(默认行为)
}
const sendQuestion = ()=>{if (!state.inputValue.trim()) return// 添加用户消息state.chatContentData.push({content: state.inputValue,sender: 'people'})// 清空输入框const userMessage = state.inputValuestate.inputValue = ''state.inputDisabled = truescrollToBottom() // 滚动条滚动到最底部// 这里可以调用AI接口获取回复getAIResponse(userMessage)
}const startNewDialog = ()=>{ state.chatContentData=[{content: '你好!我是AI助手,有什么可以帮您的?',sender: 'bot'}]
}
const scrollToBottom = () => {if (contentRef.value) {nextTick(() => {contentRef.value.scrollTop = contentRef.value.scrollHeight})}
}const getAIResponse = async (message: string) => {try {const token = 'Bearer private-x|eyJhbGciOHJvamVjdF9pZNrdiJ9.VFgYNiqhoeTKjwnKDHa7Qgn97L2NE4';// 第一步:获取 conversation_idconst conversationResponse = await axios.post('http://125.22.614.25/api/ai_apaas/v1/app/conversation',{app_id: '78ed55c5-62-9e7c-e3710a0'},{headers: {'Authorization': token,'X-Authorization': token,'Content-Type': 'application/json'},timeout: 10000 // 设置超时时间为10秒});const conversationId = conversationResponse.data.conversation_id;// 第二步:获取回答const answerResponse = await axios.post('http://125.22.614.25/api/ai_apaas/v1/app/conversation/runs',{app_id: '78ed55c5-62-9e7c-e3710a0',query: message,stream: false,conversation_id: conversationId},{headers: {'Authorization': token,'X-Authorization': token,'Content-Type': 'application/json'}});// 添加AI回复到聊天记录state.chatContentData.push({content: answerResponse.data.answer,sender: 'bot'});} catch (error) {console.error('Error:', error);// 出错时显示错误信息state.chatContentData.push({content: '获取回答时出错,请稍后重试',sender: 'bot'});} finally {state.inputDisabled = false;scrollToBottom();chatHistory() // 获取最新的聊天记录}
};
</script><style lang="less" scoped>
.content {width: 100%;height: 100%;display: flex;.left-part {width: 21%;height: 100%;background: #f6fbfb;// padding:30px 5px 30px 25px;padding-top: 30px;border-radius: 8px 0 0 8px;display: flex;flex-direction: column;align-items: center;.left-part-title{display: flex;align-items: center;gap:12px ;font-weight: 600;font-size: 24px;line-height: 34px;letter-spacing: 0%;color: #333;img{width: 32px;height: 32px;}}.left-part-btn{width: 136px;height: 48px;background: #d7edeb;border-radius: 8px;display: flex;align-items: center;justify-content: center;gap:8px;font-family: PingFang SC;font-weight: 500;font-size: 16px;line-height: 100%;letter-spacing: 0%;color: #249d91;cursor: pointer;user-select: none;margin-top:24px ;margin-bottom: 64px;}.chart-history{flex:1;width: 100%;overflow-y: auto;padding-left: 20px;display: flex;flex-direction: column;gap:30px;.chart-item{display: flex;flex-direction: column;gap:24px;.chart-item-title{font-weight: 600;font-size: 16px;line-height: 22px;letter-spacing: 0%;color: #333333;}.chart-item-list{display: flex;flex-direction: column;gap:12px;font-family: PingFang SC;font-weight: 400;font-size: 16px;line-height: 22px;color:#333;cursor: pointer;}}}}.right-part {width: 79%;height: 100%;background: #fff;padding: 15px 0;padding-top: 25px;display: flex;flex-direction: column;.right-part-dialog{padding: 0 48px;padding-bottom: 20px;flex: 1;width: 100%;overflow-y: auto;display: flex;flex-direction: column;gap:20px ;.right-part-dialog-item.bot{font-weight: 400;font-size: 16px;line-height: 26px;color: #333;.right-part-dialog-item-content{padding: 13px 16px;background: #def0ef;font-family: PingFang SC;font-weight: 400;font-size: 16px;line-height:22px;letter-spacing: 0%;color: #333;border-radius: 8px;display: inline-flex;justify-content: flex-end;word-break: break-all;}}.right-part-dialog-item.people{display: flex;justify-content: flex-end;.right-part-dialog-item-content{padding: 13px 16px;background: #249d91;font-family: PingFang SC;font-weight: 400;font-size: 16px;line-height:22px;letter-spacing: 0%;color: #ffff;border-radius: 8px;display: inline-flex;justify-content: flex-end;word-break: break-all;}}}.right-part-input{padding: 0 48px;width: 100%;height: 129px;.main-input{width: 100%;position: relative;border:2px solid #249d91 ;border-radius: 16px;.ant-input{padding: 11px;}.main-input-btn{position: absolute;color: #d5e0df;width: 32px;height: 32px;right: 16px;bottom: 16px;cursor: not-allowed;svg{width: 100%;height: 100%;}}.main-input-btn-active{color: #249d91;cursor: pointer;}}}}
}
</style>

http://www.lryc.cn/news/620312.html

相关文章:

  • JS的学习5
  • vue修改element的css属性
  • 决策树回归:用“分而治之”的智慧,搞定非线性回归难题(附3D可视化)
  • 北京JAVA基础面试30天打卡09
  • uniapp授权登录
  • 硬件工程师八月实战项目分享
  • 8.13迎来联动:PUBG布加迪,新版本37.1内容资讯!低配置也能飙车吃鸡!
  • 谈一些iOS组件化相关的东西
  • 【Golang】 Context.WithCancel 全面解析与实战指南
  • CAN仲裁机制的原理
  • 【CV 目标检测】③——目标检测方法
  • 玳瑁的嵌入式日记D17-08013(linux文件编程)
  • 深度学习(5):激活函数
  • Linux 桌面到工作站的“性能炼金术”——开发者效率的 6 个隐形瓶颈与破解方案
  • Celery+RabbitMQ+Redis
  • AR展厅在文化展示与传承领域的应用​
  • 嵌入式学习(day26)frambuffer帧缓冲
  • 嵌入式|VNC实现开发板远程Debian桌面
  • PG靶机 - Pelican
  • 飞凌OK3568开发板QT应用程序编译流程
  • 21. 抽象类和接口的区别
  • 【单板硬件】器件采购:BOM表
  • 大数据可视化设计 | 智能家居 UI 设计:从落地方法到案例拆解
  • 【从网络基础到实战】理解TCP/IP协议体系的核心要点(包含ARP协议等其他协议介绍)
  • 词向量转化
  • nginx知识点
  • C语言相关简单数据结构:顺序表
  • 使用 Simple Floating Menu 插件轻松实现浮动联系表单
  • Linux学习-UI技术
  • phpstudy搭建pikachu