uniapp开发小程序实现AI聊天打字机功能

慈云数据 2024-04-10 技术支持 46 0

uni-app官网

 一、创建uni-app

我用的是vue-cli命令行创建uniapp项目。

踩坑1:执行命令报错了

npm ERR! Darwin 20.6.0

npm ERR! argv "/Users/zhuzhu/.nvm/versions/node/v6.2.0/bin/node" "/Users/zhuzhu/.nvm/versions/node/v6.2.0/bin/npm" "install"

npm ERR! node v6.2.0

npm ERR! npm  v3.8.9

npm ERR! This request requires auth credentials. Run `npm login` and repeat the request.

npm ERR! 

npm ERR! If you need help, you may report this error at:

npm ERR!    

npm ERR! Please include the following file with any support request:

npm ERR!     /Users/zhuzhu/Downloads/uni-preset-vue-vite/npm-debug.log

解决:直接访问官网的gitee,下载模板,然后npm install,之后在npm run XX运行你想要的程序就好啦。

二、开发聊天功能

实现思路

之前开发的是网页版的,现在要改成小程序,接口是算法已经写好的,直接拿来了。前端这块实现最重要的是success回调里的代码,接口返回的是流式(如图一),然后前端通过截取最后一次对话内容,通过startTyping方法实现打字机效果

图一

上代码(样式和方法可直接copy用)

    
        
            悬浮
        
        
          
                 
                  
                      
                          
                            {{ item.content }}
                          
                      
                      
                      
                          
                          
                      
                  
                  
                      
                          
                      
                      
                      
                          {{item.ai_content}}
                      
                  
              
            
        
        
            
            发送
        
    
.main-dislogue {
  height: calc(100vh - 70px);
  background: #f5f5f5;
  display: flex;
  flex-direction: column;
}
/* 头部悬浮 */
.header-suspension {
  width: 100rpx;
  height: 300rpx;
  /* pointer-events: none; */
  z-index: 100;
  position: fixed;
  right: 10rpx;
  bottom: 300rpx;
}
.head-image {
  width: 74rpx;
  height: 74rpx;
  z-index: 99;
  background: #d4d4d4;
  border-radius: 50%;
  padding: 6rpx;
  box-shadow: 0px 2rpx 20rpx rgba(0, 0, 0, 0.5);
}
.record-btn {
  width: 74rpx;
  height: 74rpx;
  background: #FFFFFF;
  border-radius: 50%;
  font-size: 26rpx;
  text-align: center;
  padding: 6rpx;
  box-shadow: 0px 2rpx 20rpx rgba(0, 0, 0, 0.5);
  color: #4A90E2;
  margin-top: 29rpx;
}
/* 内容 */
.content {
    padding: 12rpx;
    padding-bottom: 100px;
    background: #f5f5f5;
}
/* #scrollpage {
} */
/* 问 */
.ask {
    display: flex;
    justify-content: flex-end;
    width: 100%;
    margin-top: 6rpx;
}
.ask-avatar {
    width: 120rpx;
    margin-top: 20rpx;
}
.ask-sex {
    width: 100rpx;
    height: 100rpx;
}
.ask-bulge {
    position: relative;
    top: 41rpx;
    right: 23rpx;
    display: block;
    width: 0;
    height: 0;
    border: 15rpx solid #38a579;
    transform: rotate(45deg);
}
.ask-text {
    z-index: 1;
}
.ask-desc {
    background: #38a579;
    border-radius: 13rpx;
    padding: 15rpx;
    line-height: 58rpx;
    margin-top: 27rpx;
    white-space: pre-line;
    word-break: break-all;
    color: #fff;
    margin-left: 124rpx;
}
/* 答 */
.answer {
    display: flex;
    justify-content: flex-start;
    margin-top: 6rpx;
}
.answer-avatar {
    width: 120rpx;
    margin-top: 20rpx;
}
.answer-ai {
  width: 100rpx;
  height: 100rpx;
}
.answer-bulge {
    position: relative;
    top: 41rpx;
    left: 23rpx;
    display: block;
    width: 0;
    height: 0;
    border: 15rpx solid #ffffff;
    transform: rotate(45deg);
}
.answer-text {
    z-index: 1;
}
.answer-desc {
    margin-right: 88rpx;
    border-radius: 13rpx;
    line-height: 58rpx;
    background: #fff;
    margin-top: 27rpx;
    tab-size: 12rpx;
    padding: 15rpx;
    white-space: pre-wrap;
    box-shadow: 0rpx 5rpx 47rpx 0rpx #97979773;
}
/* 尾部 */
.bottom {
    border-top: 2rpx solid #CCCCCC;
    background: #f5f5f5;
    display: flex;
    padding: 10rpx;
    padding-bottom: 50rpx;
    position: fixed;
    bottom: 0;
    z-index: 99;
    width: 100%;
}
.bottom-input {
    flex: 1;
    font-size: 35rpx;
    border-radius: 10rpx;
    background: #FFFFFF;
    padding: 17rpx;
}
.bottom-button {
  width: 190rpx;
  height: 80rpx;
  font-size: 14px;
  line-height: 80rpx;
  margin-left: 20rpx;
  background: #4A90E2 !important;
}
import Api from "@/utils/api.js";
import base from '@/utils/base.js';
const BASE_URL = base.baseUrl;
const recorderManager = uni.getRecorderManager()
export default {
    data() {
        return {
            sex: "",
            birthDate: "",
            generateRecordsFlag: false,
            dest: [],
            dialogue_code: "",
            value: "",
            isSend: false,
            scrollTop: 0,
            currentText: "",
            isSpeaking: false
        }
    },
    onLoad(option) {
        this.sex = option.sex;
        this.birthDate = option.birthDate;
        this.dialogue_code = option.dialogue_code;
    },
    onReady() {
        let _this = this;
        uni.getStorage({
            key: 'gpt_h5_dialogue',
            success: function (res) {
                let list = res.data || "";
                if (list.length) {
                    this.dest = JSON.parse(list);
                    if (this.dest.length >= 2) {
                        this.generateRecordsFlag = true;
                    }
                } else {
                    setTimeout(() => {
                        _this.handleSend();
                    }, 500)
                }
            }
        });
    },
    methods: {
        // 年龄转换
        ageCalculation(date) {
            var today = new Date();
            // 获取出生日期
            var birthDate = new Date(date); // 假设出生日期为1990年1月1日
            // 计算年龄
            var age = today.getFullYear() - birthDate.getFullYear();
            var m = today.getMonth(), d = today.getDate();
            if (m  {
                    let str = JSON.stringify(res.data);
                    // 将字符串按"data: ["分割,然后取最后一个部分  
                    const lastDataSection = str.split("data: [").pop();
                    // 截取最后一个JSON对象的部分  
                    const lastJsonString = lastDataSection.split("]")[0].replace(/\\/g, '');
                    // 解析JSON字符串  
                    const lastJsonObject = JSON.parse(lastJsonString);
                    // 获取ai_content的值  
                    const lastAiContent = lastJsonObject.ai_content;
                    console.log(lastAiContent, 'lastAiContent');
                    ai_content = lastAiContent;
                    if (lastAiContent == "") {
                        // 返回空,则默认提示
                        ai_content = "目前公司GPU服务器有限,会因为调试需要临时中断出现服务不可用,请稍后重试。";
                    }
                    _this.dest[_this.dest.length - 1].ai_content = "";
                    if (!startFlag) {
                        startFlag = true
                        startTyping();
                    }
                }
            });
            function startTyping() {
                let currentIndex = 0;
                const typingSpeed = 100; // 打字速度,单位:毫秒
                const timer = setInterval(() => {
                    _this.dest[_this.dest.length - 1].ai_content += ai_content[currentIndex];
                    currentIndex++;
                    _this.scrollToBottom();
                    if (currentIndex >= ai_content.length) {
                        clearInterval(timer);
                        _this.isSend = false;
                    }
                }, typingSpeed);
                uni.setStorage({
                    key: 'gpt_h5_dialogue',
                    data: JSON.stringify(_this.dest),
                    success: function () { }
                });
            }
        },
        // 滚动至聊天底部
        scrollToBottom() {
            this.$nextTick(() => {
                const query = uni.createSelectorQuery();
                query.select('#scrollpage').boundingClientRect();
                query.exec(res => {
                    this.scrollTop = res[0].height;
                    uni.pageScrollTo({
                        scrollTop: res[0].height + 170, // 将滚动位置设置为顶部
                        duration: 300 // 滚动到顶部的动画时长,单位为毫秒
                    });
                })
            })
        }
    },
}

效果图

打字机效果可以自行试试哈,整体页面大概是这个样子

 

 

 

微信扫一扫加客服

微信扫一扫加客服

点击启动AI问答
Draggable Icon