当前位置: 首页 > 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.dtcms.com/a/329133.html

相关文章:

  • C++QT HTTP与HTTPS的使用方式
  • Vue3从入门到精通:4.1 Vue Router 4深度解析与实战应用
  • 当GitHub宕机时,我们如何保持高效协作?分布式策略与应急方案详解
  • 将C#/.net项目附加到进程中
  • mac下载maven并配置,以及idea配置
  • 为什么要使用消息队列呢?
  • tlias智能学习辅助系统--Maven高级-聚合
  • 解决麒麟桌面系统时间不同步问题
  • Linux ARM64 内核解读之内核引导和初始化
  • 算法详细讲解 - 离散化/区间合并
  • AI编程:python测试MQ消息服务联接和消息接收
  • SimD小目标样本分配方法
  • 什么是HTTP的无状态(举例详解)
  • JavaScript 中 let、var、const 的区别详解
  • 如何用外部电脑访问本地网页?
  • Leetcode题解:215,数组中的第k个最大元素,如何使用快速算法解决!
  • 6 ABP 框架中的事件总线与分布式事件
  • 豆包 + 蘑兔 AI:圆你创作歌曲梦​
  • JavaWeb-Servlet基础
  • 4.0 vue3简介
  • 【深入浅出STM32(1)】 GPIO 深度解析:引脚特性、工作模式、速度选型及上下拉电阻详解
  • 【Docker项目实战】使用Docker部署todo任务管理器
  • [AI React Web]`意图识别`引擎 | `上下文选择算法` | `url内容抓取` | 截图捕获
  • Android 双屏异显技术全解析:从原理到实战的多屏交互方案
  • 开发手记:一个支持自动翻译的H5客服系统
  • TeamViewer 以数字化之力,赋能零售企业效率与客户体验双提升
  • 在线 A2C实践
  • 玩转Docker | 使用Docker部署MediaWiki文档管理平台
  • 大文件上传解决方案
  • React useMemo 深度指南:原理、误区、实战与 2025 最佳实践