pet/pages/assistant/assistant.vue

330 lines
8.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="assistant-container">
<u-navbar title="AI助手" :border="false" bg-color="#4ecdc4">
<template #right>
<u-icon name="book" color="white" size="20" @click="openKnowledge"></u-icon>
</template>
</u-navbar>
<!-- 快捷问题 -->
<view class="quick-questions" v-if="messageList.length <= 1">
<u-text text="常见问题" type="primary" size="16" bold margin="20rpx 0"></u-text>
<view class="question-grid">
<u-button
v-for="question in quickQuestions"
:key="question.id"
:text="question.text"
type="info"
size="mini"
plain
@click="askQuestion(question.text)"
></u-button>
</view>
</view>
<!-- 聊天区域 -->
<scroll-view class="chat-area" scroll-y="true" :scroll-top="scrollTop" scroll-with-animation="true">
<view class="message-list">
<view class="message-item" v-for="(message, index) in messageList" :key="index"
:class="message.type === 'user' ? 'user-message' : 'ai-message'">
<u-avatar
v-if="message.type === 'user'"
:src="userAvatar"
size="35"
shape="circle"
></u-avatar>
<u-avatar
v-else
src="/static/ai-avatar.png"
size="35"
shape="circle"
></u-avatar>
<view class="message-content">
<u-text :text="message.content" size="14" :type="message.type === 'user' ? 'primary' : 'info'"></u-text>
<u-text :text="message.time" type="tips" size="10" margin="8rpx 0 0 0"></u-text>
</view>
</view>
<!-- AI思考中状态 -->
<view class="message-item ai-message" v-if="isThinking">
<u-avatar src="/static/ai-avatar.png" size="35" shape="circle"></u-avatar>
<view class="message-content thinking">
<u-loading-icon mode="flower" color="#4ecdc4"></u-loading-icon>
<u-text text="AI正在思考中..." type="tips" size="12" margin="0 0 0 20rpx"></u-text>
</view>
</view>
</view>
</scroll-view>
<!-- 输入区域 -->
<view class="input-area">
<view class="input-container">
<u-input
v-model="inputMessage"
placeholder="请输入您的问题..."
:border="false"
bg-color="#f5f5f5"
shape="circle"
@confirm="sendMessage"
confirm-type="send"
></u-input>
<u-button
:text="inputMessage.trim() ? '发送' : '🎤'"
type="primary"
size="mini"
shape="circle"
:disabled="isThinking"
@click="inputMessage.trim() ? sendMessage() : startVoiceInput()"
></u-button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
inputMessage: '',
scrollTop: 0,
isThinking: false,
userAvatar: '/static/user-avatar.png',
messageList: [
{
type: 'ai',
content: '您好我是您的宠物AI助手🐾\n\n我可以为您解答关于宠物饲养、健康、训练、营养等方面的问题。有什么可以帮助您的吗',
time: this.getCurrentTime()
}
],
quickQuestions: [
{ id: 1, text: '猫咪不吃饭怎么办?' },
{ id: 2, text: '狗狗需要多久洗一次澡?' },
{ id: 3, text: '宠物疫苗接种时间' },
{ id: 4, text: '如何训练宠物定点上厕所?' },
{ id: 5, text: '宠物发烧的症状' },
{ id: 6, text: '幼猫喂养注意事项' }
],
// 知识库数据
knowledgeBase: {
'喂食': {
keywords: ['喂食', '吃饭', '食物', '饮食', '营养'],
responses: [
'定时定量喂食很重要成年猫每天2-3次幼猫3-4次。',
'选择优质的宠物食品,避免给宠物吃人类食物。',
'确保宠物随时有清洁的饮用水。'
]
},
'健康': {
keywords: ['健康', '生病', '症状', '发烧', '呕吐', '腹泻'],
responses: [
'定期体检很重要,建议每年至少一次。',
'注意观察宠物的食欲、精神状态和排便情况。',
'如果出现异常症状,请及时就医。'
]
},
'疫苗': {
keywords: ['疫苗', '接种', '免疫', '预防'],
responses: [
'幼猫幼犬8-12周开始接种疫苗。',
'成年宠物每年需要加强免疫。',
'常见疫苗包括三联疫苗和狂犬疫苗。'
]
},
'训练': {
keywords: ['训练', '教育', '行为', '定点', '上厕所'],
responses: [
'训练需要耐心和一致性。',
'使用正向强化,奖励好行为。',
'避免体罚,这会让宠物产生恐惧。'
]
},
'洗澡': {
keywords: ['洗澡', '清洁', '卫生'],
responses: [
'狗狗一般1-2周洗一次澡猫咪通常不需要经常洗澡。',
'使用宠物专用洗浴用品。',
'洗澡后要及时吹干,避免感冒。'
]
}
}
}
},
methods: {
getCurrentTime() {
const now = new Date()
return `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`
},
askQuestion(question) {
this.inputMessage = question
this.sendMessage()
},
sendMessage() {
if (!this.inputMessage.trim() || this.isThinking) return
// 添加用户消息
const userMessage = {
type: 'user',
content: this.inputMessage,
time: this.getCurrentTime()
}
this.messageList.push(userMessage)
// 开始AI思考
this.isThinking = true
this.scrollToBottom()
// 模拟AI回复
setTimeout(() => {
const aiMessage = {
type: 'ai',
content: this.getAIResponse(this.inputMessage),
time: this.getCurrentTime()
}
this.messageList.push(aiMessage)
this.isThinking = false
this.scrollToBottom()
}, 1500 + Math.random() * 1000) // 1.5-2.5秒随机延迟
this.inputMessage = ''
},
getAIResponse(question) {
// 智能匹配知识库
for (let category in this.knowledgeBase) {
const { keywords, responses } = this.knowledgeBase[category]
if (keywords.some(keyword => question.includes(keyword))) {
const randomResponse = responses[Math.floor(Math.random() * responses.length)]
return `${randomResponse}\n\n💡 如果您需要更详细的建议,建议咨询专业的宠物医生。`
}
}
// 默认回复
const defaultResponses = [
'这是一个很好的问题!建议您咨询专业的宠物医生获得更准确的建议。',
'每只宠物的情况都不同,建议根据具体情况来处理。您可以查看我们的知识库了解更多信息。',
'感谢您的提问!这个问题比较复杂,建议您带宠物去专业的宠物医院检查。',
'我理解您的担心。建议您记录宠物的具体症状,然后咨询专业医生。'
]
return defaultResponses[Math.floor(Math.random() * defaultResponses.length)]
},
scrollToBottom() {
this.$nextTick(() => {
this.scrollTop = 999999
})
},
startVoiceInput() {
uni.showToast({
title: '语音功能开发中',
icon: 'none'
})
},
openKnowledge() {
uni.navigateTo({
url: '/pages/assistant/knowledge'
})
}
}
}
</script>
<style lang="scss" scoped>
.assistant-container {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #f8f9fa;
}
.quick-questions {
background-color: white;
padding: 20rpx;
margin: 20rpx;
border-radius: 20rpx;
.question-grid {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
/deep/ .u-button {
margin: 0;
}
}
}
.chat-area {
flex: 1;
padding: 20rpx;
}
.message-list {
.message-item {
display: flex;
margin-bottom: 30rpx;
align-items: flex-start;
&.user-message {
flex-direction: row-reverse;
.message-content {
background-color: #4ecdc4;
margin-right: 20rpx;
border-radius: 20rpx 20rpx 8rpx 20rpx;
/deep/ .u-text {
color: white !important;
}
}
}
&.ai-message {
.message-content {
background-color: white;
margin-left: 20rpx;
border-radius: 20rpx 20rpx 20rpx 8rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
&.thinking {
display: flex;
align-items: center;
padding: 20rpx;
}
}
}
}
}
.message-content {
max-width: 70%;
padding: 20rpx;
/deep/ .u-text {
line-height: 1.5;
word-break: break-word;
white-space: pre-wrap;
}
}
.input-area {
background-color: white;
padding: 20rpx 30rpx;
border-top: 1rpx solid #eee;
.input-container {
display: flex;
align-items: center;
gap: 20rpx;
/deep/ .u-input {
flex: 1;
}
}
}
</style>