微信小程序实现和AI语音对话功能

1.效果

微信小程序与AI语音对话

2.效果主要实现技术
①AI语音合成(阿里云平台)
②微信小程序同声传译功能
③本功能是用原生微信小程序实现的(可自行转成uniapp代码)

3.同声传译
进入微信服务市场,搜索同声传译就能找到这个插件,然后添加到自己的微信小程序中。
可在微信公众平台,设置==》第三方设置==》插件管理中看到添加的插件
在这里插入图片描述
4.添加同声传译插件后可在自己项目中配置,打开app.json

{"plugins": {"WechatSI": {"version": "0.3.5","provider": "wx069ba97219f66d99"}}
}

5.代码
index.wxml

<view class="container">
<!-- <privacypopup></privacypopup> --><view class="header"><view><image class="tit jello-horizontal" src="../../../assets/image/1/4.png" mode="aspectFit"></image><!-- 默认初始化 --><image wx:if="{{msgText==1}}" class="textSty" src="../../../assets/image/5.png" mode="aspectFit"></image><!-- 对话正在进行中 --><image wx:elif="{{msgText==2}}" class="textSty" src="../../../assets/image/said.png" mode="aspectFit"></image><!-- 3对话暂停 --><!-- <image  wx:elif="{{msgText==3}}" class="textSty" src="../../../assets/image/pause.png" mode="aspectFit"></image> --><!-- 4对话出现问题 --><!-- <image  wx:elif="{{msgText==4}}" class="textSty" src="../../../assets/image/anew.png" mode="aspectFit"></image> --></view></view><view bindtap="openAi" class="content"><view class="logos"><!-- <image class="tit1 pulsate-bck" src="../../../assets/image/cheng.png" mode="aspectFit"></image> --><view class="logos_item roll-in-blurred-left"><image class="ce1 {{ annimationFlag? 'rotate-center' : '' }}" src="../../../assets/image/ce1.png" mode="aspectFit"></image><image class="ce2 {{ annimationFlag? 'pulsate-bck' : '' }}" src="../../../assets/image/ce2.png" mode="aspectFit"></image></view><!-- 动画音律 --><view class="dajianshiBox" wx:if="{{touchstart}}"><view class="dajianshi "><span></span><span></span><span></span><span></span><span></span></view></view></view><view class="iconSty"><view class="iconSty_left"><image class="close1" bindtap="backIndex" src="../../../assets/image/close.png" mode="aspectFit"></image></view><view class="iconSty_center"><view data-flag='1' bindlongpress="touchStart" bindtouchend="touchEnd"><image class="{{touchstart == false?'microphone1':'microphone2'}}" src="../../../assets/image/{{touchstart == false?'microphone':'prohibit'}}.png" mode="aspectFit"></image><!-- <image class="microphone2" src="../../../assets/image/prohibit.png" mode="aspectFit"></image> --></view></view><view class="iconSty_right"><!-- <image bindtap="openContent" class="fish1" src="../../../assets/image/fish.png" mode="aspectFit"></image> --><image bindtap="openContent" class="fish1" src="../../../assets/image/sa.png" mode="aspectFit"></image></view></view><!-- <image class="tit2" src="../../../assets/image/1/3.png" mode="aspectFit"></image> --></view><view class="footer"><image class="end" src="../../../assets/image/end.png" mode="aspectFit"></image></view><!-- 弹窗 历史记录(不需要可删除)--><view class="modal-mask" wx:if="{{showModal}}"><view class="modal-container"><image class="modal-bg" src="../../../assets/image/contentbg.png" mode="scaleToFill"></image><!-- 这里放置需要滚动的内容 --><view class="modal-content"><!-- 多文本展示区域 padding-bottom: 30rpx;--><view class="text-content"><scroll-view id="scroll-view" scroll-into-view="{{toView}}" scroll-y="true" style="height: 655rpx;box-sizing: border-box;"><view style="box-sizing: border-box;"><view wx:for="{{msglist}}" wx:key="*this" id="item{{index}}"><!-- 右侧布局 wx:if="{{item.type === 'right'}}"--><view class="right-layout" ><view class='right-msg' bindlongpress="copyText" data-key="{{item.question}}">{{item.question}}</view><view class="right-arrow-layout"><view class="right-arrow-img"></view></view><view class="right_item"><image class="right-arrow-photo" src='../../../assets/image/missing-face.png' mode='aspectFill'></image></view></view><!-- 左侧布局 wx:elif="{{item.type === 'left'}}"--><view class="left-layout" ><view class="left_item"><image class="left-arrow-photo" src='../../../assets/image/cheng.png' mode='aspectFill'></image></view><view class="left-arrow-layout"><!-- 小尖角 --><view class="left-arrow-img"></view></view><!-- index.wxml --><view class='left-msg' bindlongpress="copyText" data-key="{{item.answer}}">{{item.answer}}</view></view></view></view></scroll-view></view></view><view class="modal-btns"><!-- <image bindtap="copyText" class="modal_img1" src="../../../assets/image/copyBtn.png" mode="scaleToFill"></image> --><image class="" src="../../../assets/image/restart.png" mode="scaleToFill" bindtap="closeModal"></image></view></view></view><!-- 登录 --><loginwin login_show="{{loginShow}}" bind:customEvent="onChildEvent"></loginwin>
</view>

index.wxss

@charset "UTF-8";.container {display: flex;flex-direction: column;height: 100%;/* 之前的样式保持不变 */background-color: #000;min-height: 100vh;position: relative;
}.container .header {padding: 20rpx;text-align: center;
}.container .header {flex: 1;display: flex;justify-content: center;align-items: center;/* 头部固定高度或其他样式 */
}.container .header image {display: block;
}.container .content {flex-grow: 1;overflow-y: auto;padding: 20rpx;text-align: center;display: flex;flex-direction: column;align-items: center;
}.container .footer {/* 底部固定高度或其他样式 */padding: 20rpx 0 40rpx 0;text-align: center;
}.tit {width: 235rpx;height: 70rpx;
}.textSty {width: 217rpx;height: 73rpx;box-sizing: border-box;margin-top: 35rpx;
}.tit1 {width: 369rpx;height: 368rpx;
}.ce1 {width: 368rpx;height: 368rpx;
}.ce2 {width: 330rpx;height: 330rpx;position: absolute;left: 19.5rpx;top: 20.8rpx;
}.iconSty {display: flex;justify-content: space-around;align-items: flex-end;height: 172rpx;padding-bottom: 48rpx;width: 79%;/* height: 327rpx; */
}.logos {text-align: center;flex: 1;position: relative;
}.logos_item {position: relative;
}.iconSty_left .close1 {width: 65rpx;height: 65rpx;
}.iconSty_center .microphone1 {width: 59rpx;height: 83rpx;
}.microphone2 {width: 75rpx;height: 107rpx;
}.iconSty_right .fish1 {width: 65rpx;height: 65rpx;
}.tit2 {width: 190rpx;height: 22rpx;margin-top: 69rpx;
}.end {width: 214rpx;height: 74rpx;
}/* 弹窗 */
.modal-mask {touch-action: none; /* 禁止触摸滚动 */position: fixed;top: 0;left: 0;right: 0;bottom: 0;z-index: 9999999999999999;background-color: rgba(0, 0, 0, 0.5);display: flex;justify-content: center;align-items: center;
}.modal-container {width: 603rpx;height: 878rpx;background-color: transparent;border-radius: 10rpx;/* overflow: hidden; */position: relative;
}.modal-bg {width: 603rpx;height: 878rpx;position: absolute;top: 0;left: 0;
}.modal-content {position: relative;box-sizing: border-box;padding: 90rpx 32rpx 20rpx 32rpx;color: #000;height: 88%;/* overflow: hidden; *//* 根据实际情况调整文本样式 */
}.text-content {/* 适当调整多文本展示区域的样式 */width: 100%;height: 100%;/* overflow-y: auto; *//* border: 1px solid red; */
}.modal-btns {display: flex;justify-content: center;padding: 47rpx 0rpx;position: absolute;bottom: 0;width: 100%;
}.modal-btns image {width: 148rpx;height: 56rpx;
}.modal_img1 {margin-right: 34rpx;
}.btn {width: 48%;height: 80rpx;line-height: 80rpx;border-radius: 10rpx;text-align: center;color: #fff;background-color: #007aff;
}/* 滚动条 */
.text-content::-webkit-scrollbar {/*滚动条整体样式*//*高宽分别对应横竖滚动条的尺寸*//* width: 3px;height: 1px; */
}.text-content::-webkit-scrollbar-thumb {/*滚动条里面小方块*//* border-radius: 10px;height: 10px;-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);background: #4D4D4D; */
}
.text-content::-webkit-scrollbar-track {/*滚动条里面轨道*//* -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);border-radius: 5px;background: #ffffff; */
}
/* 聊天页面 */
/* 左侧布局 */
.left-layout {position: relative;display: flex;justify-content: flex-start;padding: 20rpx 60rpx 2vw 2vw;
}.left-arrow-photo {width: 60rpx;height: 60rpx;min-width: 60rpx;min-height: 60rpx;border-radius: 50%;margin-top: 5rpx;
}.left-msg {flex: 1;font-size: 25rpx;color: #444;line-height: 45rpx;display: flex;justify-content: flex-start;align-items: center;padding: 10rpx;background-color: #ccc;margin-left: -12rpx;border-radius: 10rpx;z-index: 10;
}.left-arrow-layout {position: relative;width: 35rpx;height: 65rpx;display: flex;align-items: center;z-index: 9;
}.left-arrow-img {width: 0;height: 0;border-top: 9px solid transparent;border-right: 9px solid #ccc;border-bottom: 9px solid transparent;position: absolute;top: 5rpx;left: 5px;
}/* 右侧布局 */
.right-layout {box-sizing: border-box;display: flex;justify-content: flex-end;padding: 20rpx 2vw 2vw 15vw;/* border: 1px solid green; */
}.right-arrow-photo {width: 60rpx;height: 60rpx;min-width: 60rpx;min-height: 60rpx;border-radius: 50%;margin-top: 5rpx;
}.right-msg {flex: 1;box-sizing: border-box;font-size: 25rpx;color: #444;line-height: 45rpx;display: flex;justify-content: flex-start;align-items: center;padding: 10rpx;background-color: #96EB6A;margin-right: -1rpx;border-radius: 10rpx;z-index: 10;
}.right-arrow-layout {position: relative;width: 35rpx;height: 65rpx;margin-right: 5rpx;display: flex;align-items: center;z-index: 9;
}.right-arrow-img {width: 0;height: 0;border-top: 18rpx solid transparent;border-right: 18rpx solid transparent;border-left: 18rpx solid #96EB6A;border-bottom: 18rpx solid transparent;position: absolute;top: 13rpx;left: -2rpx;
}.right_item {width: 70rpx;height: 70rpx;text-align: center;
}.left_item {width: 70rpx;height: 70rpx;text-align: center;
}/* 动画 */
.pulsate-bck {-webkit-animation: pulsate-bck 2s ease-in-out infinite both;animation: pulsate-bck 2s ease-in-out infinite both;
}@-webkit-keyframes pulsate-bck {0% {-webkit-transform: scale(1);transform: scale(1);}50% {-webkit-transform: scale(0.9);transform: scale(0.9);}100% {-webkit-transform: scale(1);transform: scale(1);}
}@keyframes pulsate-bck {0% {-webkit-transform: scale(1);transform: scale(1);}50% {-webkit-transform: scale(0.9);transform: scale(0.9);}100% {-webkit-transform: scale(1);transform: scale(1);}
}/* 旋转 */
.rotate-center {-webkit-animation: rotate-center 1.9s linear infinite;animation: rotate-center 1.9s linear infinite;
}@-webkit-keyframes rotate-center {0% {-webkit-transform: rotate(0);transform: rotate(0);}100% {-webkit-transform: rotate(360deg);transform: rotate(360deg);}
}@keyframes rotate-center {0% {-webkit-transform: rotate(0);transform: rotate(0);}100% {-webkit-transform: rotate(360deg);transform: rotate(360deg);}
}/* 音律动画 */
.dajianshi {/* margin:100px auto 0; */width: 100rpx;height: 55rpx;display: flex;margin: 0 auto;
}.dajianshi span {width: 12rpx;border-radius: 18px;margin-right: 9rpx;
}.dajianshi span:nth-child(1) {animation: bar1 2s 0.2s infinite linear;
}.dajianshi span:nth-child(2) {animation: bar2 2s 0.4s infinite linear;
}.dajianshi span:nth-child(3) {animation: bar3 2s 0.6s infinite linear;
}.dajianshi span:nth-child(4) {animation: bar4 2s 0.8s infinite linear;
}.dajianshi span:nth-child(5) {animation: bar5 2s 1.0s infinite linear;
}.dajianshi span:nth-child(6) {animation: bar6 2s 1.2s infinite linear;
}.dajianshi span:nth-child(7) {animation: bar7 2s 1.4s infinite linear;
}.dajianshi span:nth-child(8) {animation: bar8 2s 1.6s infinite linear;
}.dajianshi span:nth-child(9) {animation: bar9 2s 1.8s infinite linear;
}@keyframes bar1 {0% {background: #FF6600;margin-top: 20%;height: 10%;}50% {background: #FF6600;height: 100%;margin-top: 0%;}100% {background: #FF6600;height: 10%;margin-top: 20%;}
}@keyframes bar2 {0% {background: #FF6600;margin-top: 20%;height: 10%;}50% {background: #FF6600;height: 100%;margin-top: 0%;}100% {background: #FF6600;height: 10%;margin-top: 20%;}
}@keyframes bar3 {0% {background: #FF6600;margin-top: 20%;height: 10%;}50% {background: #FF6600;height: 100%;margin-top: 0%;}100% {background: #FF6600;height: 10%;margin-top: 20%;}
}@keyframes bar4 {0% {background: #FF6600;margin-top: 20%;height: 10%;}50% {background: #FF6600;height: 100%;margin-top: 0%;}100% {background: #FF6600;height: 10%;margin-top: 20%;}
}@keyframes bar5 {0% {background: #FF6600;margin-top: 20%;height: 10%;}50% {background: #FF6600;height: 100%;margin-top: 0%;}100% {background: #FF6600;height: 10%;margin-top: 20%;}
}.dajianshiBox {width: 100%;position: absolute;bottom: 0;
}
/* 滚动条样式设置 */
/* 设置 scroll-view 的滚动条样式 */
.scroll-view::-webkit-scrollbar {width: 8px;  /* 滚动条宽度 */height: 8px; /* 滚动条高度,如果是横向滚动,这里设置高度 */
}/* 滚动条轨道 */
.scroll-view::-webkit-scrollbar-track {background-color: #4D4D4D; /* 滚动条轨道背景色 */
}/* 滚动条滑块 */
.scroll-view::-webkit-scrollbar-thumb {background-color: #999999; /* 滚动条滑块颜色 */border-radius: 10rpx; /* 滑块边框圆角 */
}/* 滚动条滑块悬停状态 */
.scroll-view::-webkit-scrollbar-thumb:hover {background-color: #555; /* 滚动条滑块悬停时的颜色 */
}
/* 滑入式动画 */
.slide-in-elliptic-top-fwd {-webkit-animation: slide-in-elliptic-top-fwd 0.7s cubic-bezier(0.250, 0.460, 0.450, 0.940) 1s both;/* Standard animation property */animation: slide-in-elliptic-top-fwd 0.7s cubic-bezier(0.250, 0.460, 0.450, 0.940) 1s both;
}
@-webkit-keyframes slide-in-elliptic-top-fwd {0% {-webkit-transform: translateY(-600px) rotateX(-30deg) scale(0);transform: translateY(-600px) rotateX(-30deg) scale(0);-webkit-transform-origin: 50% 100%;transform-origin: 50% 100%;opacity: 0;}100% {-webkit-transform: translateY(0) rotateX(0) scale(1);transform: translateY(0) rotateX(0) scale(1);-webkit-transform-origin: 50% 1400px;transform-origin: 50% 1400px;opacity: 1;}
}
@keyframes slide-in-elliptic-top-fwd {0% {-webkit-transform: translateY(-600px) rotateX(-30deg) scale(0);transform: translateY(-600px) rotateX(-30deg) scale(0);-webkit-transform-origin: 50% 100%;transform-origin: 50% 100%;opacity: 0;}100% {-webkit-transform: translateY(0) rotateX(0) scale(1);transform: translateY(0) rotateX(0) scale(1);-webkit-transform-origin: 50% 1400px;transform-origin: 50% 1400px;opacity: 1;}
}
/* 果冻 */
.jello-horizontal {-webkit-animation: jello-horizontal 0.9s 0.5s both;animation: jello-horizontal 0.9s 0.5s both;
}
@-webkit-keyframes jello-horizontal {0% {-webkit-transform: scale3d(1, 1, 1);transform: scale3d(1, 1, 1);}30% {-webkit-transform: scale3d(1.25, 0.75, 1);transform: scale3d(1.25, 0.75, 1);}40% {-webkit-transform: scale3d(0.75, 1.25, 1);transform: scale3d(0.75, 1.25, 1);}50% {-webkit-transform: scale3d(1.15, 0.85, 1);transform: scale3d(1.15, 0.85, 1);}65% {-webkit-transform: scale3d(0.95, 1.05, 1);transform: scale3d(0.95, 1.05, 1);}75% {-webkit-transform: scale3d(1.05, 0.95, 1);transform: scale3d(1.05, 0.95, 1);}100% {-webkit-transform: scale3d(1, 1, 1);transform: scale3d(1, 1, 1);}
}
@keyframes jello-horizontal {0% {-webkit-transform: scale3d(1, 1, 1);transform: scale3d(1, 1, 1);}30% {-webkit-transform: scale3d(1.25, 0.75, 1);transform: scale3d(1.25, 0.75, 1);}40% {-webkit-transform: scale3d(0.75, 1.25, 1);transform: scale3d(0.75, 1.25, 1);}50% {-webkit-transform: scale3d(1.15, 0.85, 1);transform: scale3d(1.15, 0.85, 1);}65% {-webkit-transform: scale3d(0.95, 1.05, 1);transform: scale3d(0.95, 1.05, 1);}75% {-webkit-transform: scale3d(1.05, 0.95, 1);transform: scale3d(1.05, 0.95, 1);}100% {-webkit-transform: scale3d(1, 1, 1);transform: scale3d(1, 1, 1);}
}
/* 滚入 */
.roll-in-blurred-left {-webkit-animation: roll-in-blurred-left 0.65s cubic-bezier(0.230, 1.000, 0.320, 1.000) both;animation: roll-in-blurred-left 0.65s cubic-bezier(0.230, 1.000, 0.320, 1.000) both;
}@-webkit-keyframes roll-in-blurred-left {0% {-webkit-transform: translateX(-1000px) rotate(-720deg);transform: translateX(-1000px) rotate(-720deg);-webkit-filter: blur(50px);filter: blur(50px);opacity: 0;}100% {-webkit-transform: translateX(0) rotate(0deg);transform: translateX(0) rotate(0deg);-webkit-filter: blur(0);filter: blur(0);opacity: 1;}
}
@keyframes roll-in-blurred-left {0% {-webkit-transform: translateX(-1000px) rotate(-720deg);transform: translateX(-1000px) rotate(-720deg);-webkit-filter: blur(50px);filter: blur(50px);opacity: 0;}100% {-webkit-transform: translateX(0) rotate(0deg);transform: translateX(0) rotate(0deg);-webkit-filter: blur(0);filter: blur(0);opacity: 1;}
}

index.js

// pages/ai/aiVoice/index.ts
//const { TextEncoder, TextDecoder } = require('../../../miniprogram_npm/text-encoding-shim/index.js')
//let Wxml2canvas  = require('wxml2canvas/index.js');
const app = getApp();
//引入插件:微信同声传译
const plugin = requirePlugin('WechatSI');
//获取全局唯一的语音识别管理器recordRecoManager
const manager = plugin.getRecordRecognitionManager();
Page({/*** 页面的初始数据*/data: {isplay: true,onstops: true, //默认执行onStopisFlag: false, //是否点击录音到获取结果之间状态longPressTimer: null, // 用于存储长按定时器的变量touchStartTime: 0, //长按开始touchEndTime: 0, //松开结束 authsetting: false, //是否获取授权url: "地址",openid: null,islongPress: false, //是否长按ParentValue: 'Parent',loginShow: false, //登录弹窗默认关闭annimationFlag: false, //logo动画默认关闭touchstart: false, //默认没有按下toView: null,scrollTop: 0,src: '', //语音地址resultobj: {result: "",tempFilePath: ""},msgText: 1, //1默认初始化  2对话进行中   3结束对话  4对话出现问题flag: 1,haveflag: false, //防止重复点击recordState: false, //麦克风默认关闭状态msglist: [], //聊天记录showModal: false, //历时消息记录},/*** 生命周期函数--监听页面加载*/onLoad() {const str = new TextDecoder('utf-8').decode(new Uint8Array("jsfjsdfslkdf看见撒巅峰时刻京东方·1"))console.log("str",str)// 关闭主页按钮wx.hideHomeButton();wx.setNavigationBarTitle({title: "AI对话"})//  判断用户是否登录this.isLogin();// 获取语音授权this.getSeeting(1);//识别语音this.initRecord();const authset = wx.getStorageSync('AUTHSETTING');if (!authset) { //没有获取录音权限// 重新获取录音权限this.getSeeting(1);}},/*** 生命周期函数--监听页面初次渲染完成*/onReady() {//创建内部 audio 上下文 InnerAudioContext 对象。this.innerAudioContext = wx.createInnerAudioContext();this.innerAudioContext.src = '';// this.innerAudioContext.onError(function (res) {//   console.log(res);//   wx.showToast({//     title: '语音播放失败',//     icon: 'none',//   })// })},/*** 生命周期函数--监听页面显示*/onShow() {},// 获取聊天记录getChartQuery() {wx.showLoading({title: '读取中...',icon: 'none',mask: true})console.log('openid', wx.getStorageSync('OPENID'));let openId = wx.getStorageSync('OPENID');// 获取语音接口wx.request({url: this.data.url + '/cyjgVoice/record',method: 'POST',data: {openId: openId},success: res1 => {wx.hideLoading();this.setData({showModal: true});let data1 = res1.data.data;if (res1.data.code == 200) {//设置语音this.setData({msglist: data1})// 模拟异步数据加载setTimeout(() => {//  页面进入时滚动到底部,给在data中定义的变量赋值this.setData({toView: `item${this.data.msglist.length - 1}`,});}); // 假设数据加载需要一定时间,这里设置一个延时} else {wx.showToast({title: res1.data.msg,icon: 'none',duration: 2000})}}})},// 判断用户是否登录isLogin() {// 获取本地存储中的 OPENIDconst openid = wx.getStorageSync('OPENID');if (openid) {// 如果本地存储中存在 OPENID,则说明用户已经登录过,可以直接使用 OPENID 进行后续操作this.setData({loginShow: false})// 这里可以进行其他操作,比如直接跳转到主页面} else {// 如果本地存储中没有 OPENID,则需要调用登录接口获取 OPENIDthis.setData({loginShow: true,openid: openid})}},onChildEvent: function (event) {this.setData({loginShow: event.detail.login_show})},// 复制粘贴copyText(e) {let key = e.currentTarget.dataset.key;wx.setClipboardData({ //设置系统剪贴板的内容data: key,success(res) {wx.getClipboardData({ // 获取系统剪贴板的内容success(res) {wx.showToast({title: '复制成功',icon: "none"})}})}})},//暂停语音backIndex() {this.setData({msgText: 1, //初始化touchstart: false, //按钮恢复初始状态annimationFlag: false,haveflag: false,'resultobj.tempFilePath': "",isplay: false,resultText: "",src: ""})this.innerAudioContext.src = " "wx.stopBackgroundAudio();this.innerAudioContext.stop(); //暂停音频// 如何判断当前是语音录制识别状态if (this.data.isFlag) {this.setData({onstops: false, //是否执行onStop})wx.showLoading({title: '关闭中...',icon: 'none',// mask: true})// 停止识别manager.stop();}},// 播放语音yuyinPlay: function (e) {console.log("播放1", e);if (this.data.src == '' && this.data.isplay) {console.log("播放2",this.data.src,'222',this.data.isplay);return;}this.setData({msgText: 2, //正在对话annimationFlag: true,haveflag: true})this.innerAudioContext.src = this.data.src; // 设置音频地址this.innerAudioContext.onError(function (res) {this.setData({msgText: 1, //初始化annimationFlag: false,haveflag: false})wx.showToast({title: '语音播放失败',icon: 'none',})})this.innerAudioContext.onTimeUpdate(() => {// console.log('音频播放进度更新', this.data.src);});this.innerAudioContext.onEnded(() => { // 添加播放结束的回调this.setData({msgText: 1, //初始化annimationFlag: false,haveflag: false})// 在这里执行播放完毕后的操作,比如关闭语音this.innerAudioContext.stop(); // 使用 stop 方法停止音频并重置播放状态});this.innerAudioContext.play(); // 播放音频},// 结束语音end: function (e) {that.setData({msgText: 1, //初始化annimationFlag: false})this.innerAudioContext.stop(); //暂停音频},//识别语音 -- 初始化initRecord() {const that = this;// 有新的识别内容返回,则会调用此事件manager.onRecognize = function (res) {console.log("有新的识别内容返回,则会调用此事件")}// 正常开始录音识别时会调用此事件manager.onStart = function (res) {console.log("成功开始录音识别", res)that.setData({// annimationFlag:true})}//识别结束事件manager.onStop = function (res) {if (!that.data.isplay) {wx.showToast({title: "请说话",icon: 'success',image: '/assets/image/no_voice.png',duration: 1000,success: function (res) {this.setData({haveflag: false,})},fail: function (res) {console.log(res);}});return false}if (res.result == '') {wx.hideLoading();// wx.showToast({//   title: '听不清楚,请重新说一遍!',//   icon: 'none',//   duration: 2000// })// that.setData({//   msgText: 1, //初始化//   haveflag: false,//   isFlag: false,// })that.showRecordEmptyTip()return;} else {// wx.showLoading({//   title: '正在思考...',//   icon: 'none',// })that.setData({resultobj: {result: res.result,tempFilePath: res.tempFilePath,msgText: 2, //正在对话annimationFlag: true}})//  调用接口// that.resultAPi();that.resultTextApi();// that.resultAPi3();}}// 识别错误事件manager.onError = function (res) {console.log("error msg", res);wx.hideLoading();wx.showToast({icon: "none",title: '请重新开始~'})that.setData({haveflag: false,msgText: 1,annimationFlag: false,isFlag: false, //当前录制语音识别状态})}},// 根据wx.getSetting判断用户是否打开了录音权限,如果没有打开,则通过wx.authorize,向用户打开授权请求,如果用户拒绝了,就给用户打开授权设置页面。getSeeting(type) {// wx.showLoading({//   title: '获取录音权限',//   icon: 'none',//   mask: true// })const _this = thiswx.getSetting({ //获取用户当前设置success: res => {// wx.hideLoading();// console.log('获取权限', res);if (res.authSetting['scope.record']) { //查看是否授权了录音设置// console.log('获取权限1111');const authset = wx.setStorageSync('AUTHSETTING', true);_this.setData({authsetting: true})if (type == 2) {wx.showToast({title: '获取录音权限成功,点击重新开始!',icon: 'none',duration: 2000})}} else {// 用户还没有授权,向 用户发起授权请求wx.authorize({ //提前向用户发起授权请求,调用后会立刻弹窗询问用户是否同意授权小程序使用某项功能或获取用户的某些数据,但不会实际调用对应接口scope: 'scope.record',success() { //用户同意授权摄像头// console.log("同意授权");// wx.showToast({//   title: '获取录音权限成功',//   icon: 'none',//   duration: 2000// })},fail() { //用户不同意授权摄像头_this.openSetting()}})}},fail() {// console.log('获取用户授权信息失败');wx.showToast({title: '获取权限失败',icon: 'none',duration: 2000})}})},openSetting() {wx.openSetting({success(res) {console.log(res);if (res.authSetting['scope.record']) {console.log('用户已经同意录音权限');// 在这里可以再次执行录音操作或者其他逻辑} else {console.log('用户依然拒绝录音权限');// 可以提示用户继续操作的限制或者做其他处理}},fail() {console.log('打开设置页面失败');},});},//请求语音结果resultAPi() {//调用接口wx.request({url: this.data.url + '/cyjgVoice/question',method: 'POST',data: {question: this.data.resultobj.result,openId: wx.getStorageSync('OPENID')},success: res => {let data = res.data.data;if (res.data.code == 200 && this.data.isplay) {// 获取语音接口wx.request({url: this.data.url + '/cyjgVoice/voice',method: 'POST',data: {id: data.id,code: data.code,openId: data.openId},success: res1 => {wx.hideLoading();let data1 = res1.data.data;if (res1.data.code == 200 && this.data.isplay) {console.log("语音结果成功");// //设置语音this.setData({src: data1.voiceUrl,isFlag: false,resultText: data1.answer})if (this.data.src) {// 文字转语音// this.wordYun();this.yuyinPlay();} else {console.log("没拿到");}} else if (res1.data.code != 200) {wx.showToast({title: res1.data.msg,icon: 'none',duration: 2000})}}})} else if (res.data.code != 200) {wx.hideLoading();wx.showToast({title: res.data.msg,icon: 'none',duration: 2000})this.setData({msgText: 1})}}})},//获取文字接口resultTextApi() {//调用接口const formdata = {question: this.data.resultobj.result,openId: wx.getStorageSync('OPENID'),};const requestTask = wx.request({url: this.data.url + '/cyjgVoice/ans',method: 'POST',header: {'content-type': 'application/x-www-form-urlencoded' // 或者 'application/json' 如果你的后端能接受JSON格式},data: formdata, // 直接使用formdata对象success: res => {console.log("语音1111", res);wx.hideLoading();if (res.data.code == 200 && this.data.isplay) {let data = res.data.data;console.log("语音结果成功");//设置语音this.setData({isFlag: false,resultText:data.answer,src:data.voiceUrl})if (data.voiceUrl) {// 文字转语音this.yuyinPlay();} else {console.log("没拿到");}} else if (res.data.code != 200) {wx.hideLoading();wx.showToast({title: res.data.msg,icon: 'none',duration: 2000})this.setData({msgText: 1})}}})});},//语音  --按住说话touchStart(e) {// 判断是否获取录音权限if (this.data.haveflag) { //true 请先结束语音wx.showToast({title: '请先关闭语音!',icon: 'none',duration: 2000})return false}// 当前正在识别语音,还没结束上一次识别,请先关闭再进行录音if (this.data.isFlag) { //true 请先结束语音wx.showToast({title: '请先关闭语音!',icon: 'none',duration: 2000})return false}this.setData({islongPress: true,isplay: true})var flag = Number(e.currentTarget.dataset.flag)this.setData({recordState: true, //录音状态flag: flag,touchstart: true, //按下msgText: 2, //初始化状态})// 语音开始识别manager.start({lang: 'zh_CN', // 识别的语言})},// resultAPi3() {//调用接口  获取后端请求返回的base64答案,前端转成文字,利用同声传译生成语音功能wx.request({url: this.data.url + '/cyjgVoice/question',method: 'POST',data: {question: this.data.resultobj.result,openId: wx.getStorageSync('OPENID')},success: res => {console.log("语音1111", res.data);let data = res.data.data;if (res.data.code == 200 && this.data.isplay) {// 获取语音接口wx.hideLoading();// //设置语音this.setData({// src: data.voiceUrl,isFlag: false,resultText: data.answer})this.base64ChangeVideo(data.voiceUrl);} else if (res.data.code != 200) {wx.hideLoading();wx.showToast({title: res.data.msg,icon: 'none',duration: 2000})this.setData({msgText: 1})}}})},// base64转mp3音频base64ChangeVideo(base64Data) {// const backgroundAudioManager = wx.getBackgroundAudioManager()const audioPath = wx.env.USER_DATA_PATH + '/ordernew.mp3'const fs = wx.getFileSystemManager();let that = this;fs.writeFile({filePath: audioPath,data: base64Data,encoding: 'base64',success(res) {that.setData({src: audioPath})that.yuyinPlay();},})},//语音  --松开结束touchEnd(e) {if (!(this.data.islongPress)) { //如果是长按执行下面内容return false}wx.showLoading({title: '正在思考...',icon: 'none',})if (this.data.haveflag) { //true 请先结束语音wx.hideLoading();// wx.showToast({//   title: '请先关闭语音111!',//   icon: 'none',//   duration: 2000// })return false}this.setData({touchstart: false,recordState: false,islongPress: false, //长按初始状态isFlag: true, //判断从松手到识别录音期间状态haveflag: true})// 语音结束识别manager.stop();},// 打开弹窗openContent() {if ((this.data.msgText == 1 && !(this.data.annimationFlag)) || (this.data.msgText == 2 && this.data.annimationFlag)) { //true 请先结束语音// wx.showToast({//   title: '请先关闭对话!',//   icon: 'none',//   duration: 2000// })this.getChartQuery();} else {return false}},// 关闭弹窗closeModal() {this.setData({showModal: false})},showRecordEmptyTip: function () {this.setData({msgText: 1, //初始化haveflag: false,isFlag: false,})wx.showToast({title: "请说话",icon: 'success',image: '/assets/image/no_voice.png',duration: 1000,success: function (res) {},fail: function (res) {console.log(res);}});},// 文字转语音wordYun: function (e) {var that = this;var content = this.data.resultText;plugin.textToSpeech({lang: "zh_CN",tts: true,content: content,success: function (res) {console.log("succ tts", res.filename);that.setData({src: res.filename})that.yuyinPlay();},fail: function (res) {console.log("fail tts", res)}})},/*** 生命周期函数--监听页面隐藏*/onHide() {this.innerAudioContext.stop();},/*** 生命周期函数--监听页面卸载*/onUnload() {this.innerAudioContext.stop();},/*** 页面相关事件处理函数--监听用户下拉动作*/onPullDownRefresh() {},/*** 页面上拉触底事件的处理函数*/onReachBottom() {},/*** 用户点击右上角分享*/onShareAppMessage() {}
})

index.json

{"usingComponents": {"loginwin": "../../../components/loginwin/index"}
}

6.注意:
2.微信同声传译点录音start后,不说话然后调用stop,需要10S以上才能返回结果,目前没有找到解决方案(有解决的小伙伴,给我说一下,谢谢~)
3.如果同声传译真机调试使用不了,报错“start:fail api scope is not declared in the privacy agreement”,需要去微信公众平台更新一下隐私协议,吧麦克风添加进去
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
7.微信登录组件
效果
在这里插入图片描述
7.1 创建loginwin组件
在这里插入图片描述
7.2 index.wxml代码

<view><view  class="modal-mask1"  wx:if="{{login_show}}"><view class="modal-container1"><!-- 微信授权流程 --><view class="popupBox1"><view class="ruleContent"><view class="loginIcon1"><image src="../../assets/image/weixin.png" class="wx-icon" mode="aspectFit"></image></view><view class="ruleTitle">微信授权登录</view></view><view class="popupClose"><image src="../../assets/image/loginBtn.png" class="login-btn" bindtap="login1" mode="widthFix"></image></view><view><view class="flex_start flex_items endSty"><checkbox-group bindchange="checkboxChange" class="checkbox-group" style="transform: scale(0.8);"><checkbox value="all" checked="{{allchecked}}" color="#00C800" class="checkbox"></checkbox>
</checkbox-group><view class="txt">阅读用户协议<text bindtap="read" class="policy-text">《用户协议及隐私政策》</text></view></view></view></view></view></view><!-- 获取微信头像部分 不需要可删除-->
<!-- 引入必要样式 -->
<view class="modal-mask" wx:if="{{getHeadShow}}" >
<view class="modal-container" wx:if="{{getHeadShow}}" style="padding:0;"><view class="popupBox"><view class="ruleContent"><view class="loginIcon"><button class="avatar-wrapper" open-type="chooseAvatar"  bindchooseavatar="onChooseAvatar"><image wx:if="userInfo.headImg" class="avatar" src="{{userInfo.headImg}}"></image><image v-else class="avatar" src="../../assets/image/cheng.png"></image><view class="up_img">上传头像</view></button></view><view class="ruleTitle"><!-- <input type="text" class="weui-input" placeholder="请输入昵称" bindinput="getNickname" /> --><input value="{{userInfo.nickName||''}}" bindchange="onInput" type="nickname" class="weui-input" placeholder="请输入昵称" /></view></view><view class="popupClose"><!-- <button class="avatar-wrapper1" open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"><image src="../../static/loginBtn.png" mode="widthFix"></image>
</button> -->
<button >
保存
</button></view></view>
</view>
</view>
</view>

7.3 index.js代码

// pages/ai/loginpage/index.ts
Component({// "component": true,properties: {login_show: {type: Boolean,value: false, // 设置默认值observer: function (oldVal, newVal) { //每次父组件向子组件传值的时候都会调用这个函数console.log("间停止", oldVal, newVal) // 旧数据和新数据// this.Fn()}},},/*** 页面的初始数据*/data: {allchecked: false,//是否选中login_show: false,//默认不显示getHeadShow: false,//是否获取昵称及用户头像url: "地址",userInfo: {nickName: '',openId: '',headImg: '',}},onLoad() {},// 可以在这里监听属性变化observerLoginShow: function (newVal, oldVal) {console.log('监听', newVal);},/*** 生命周期函数--监听页面初次渲染完成*/onReady() {},/*** 生命周期函数--监听页面显示*/onShow() {},methods: {//隐私协议read(){wx.navigateTo({url: '/pages/ai/userAgreement/index',})},// 登录login1() {if (!this.data.allchecked) {wx.showToast({title: '请阅读并勾选用户协议',icon: 'none'})return}this.getUserInfo();},//复选框checkboxChange(n) {console.log('复选框', n)if (n.detail.value[0]) {this.setData({allchecked: true})} else {this.setData({allchecked: false})}},getUserInfo() {var that = this;wx.showLoading({ // 展示加载框title: '加载中',});let code = '';wx.login({success: (loginRes) => {console.log("登录code",loginRes)code = loginRes.code;},fail: () => {wx.showToast({title: "微信登录授权失败",icon: "none"});}});wx.getUserProfile({desc: '登录',success: (info) => {console.log('登录的openid', info)let obj = {code: code,rawData: info.rawData,signature: info.signature,encryptedData: info.encryptedData,iv: info.iv};// 登录成功wx.showLoading({mask: true,title: '登录中...'});//  登录接口wx.request({url:this.data.url+'/cyjgVoice/login',method: 'POST',data:obj,success: res => {wx.hideLoading();console.log("登录",res.data);let info = res.data;if (info.code == 200) {wx.setStorageSync('OPENID', info.data.openId);wx.setStorageSync('TOKEN', info.data.token);// 给父组件传值  关闭组件that.triggerEvent('customEvent', {login_show: false});} else {//登录出错wx.showToast({title: res.data.msg,icon: "none"});}}})},fail: (error) => {// 处理getUserProfile失败的情况}});},// 图片上传 onChooseAvatar: function (e) {console.log('图片', e)let that = this;// 获取七牛云tokengetQiniuyunToken().then(res => {if (res.code === 20000) {// 构建key值const imgurl = e.detail.avatarUrl.replace('http://tmp/', '');const key = 'ar/files/' + new Date().getTime() + '_' + imgurl;wx.showLoading({mask: true,title: '上传中...',});// 准备上传文件wx.uploadFile({url: 'https://upload-z2.qiniup.com', // 华东地区上传filePath: e.detail.avatarUrl,name: 'file',method: 'POST',formData: {key: key, // key值token: res.token, // 七牛云token值},success: (uploadFileRes) => {// 解析返回的JSON字符串const strToObj = JSON.parse(uploadFileRes.data);// 拼接域名和key值得到完整URLconst backUrl = VUE_APP_IMG_URL + strToObj.key;// 更新用户信息的头像地址that.userInfo.headImg = backUrl;wx.hideLoading();},fail: (fail) => {wx.showToast({title: '网络错误',icon: 'none',});// 注意:原代码中的data.fail(fail)调用在小程序中可能无对应逻辑,需根据实际情况调整wx.hideLoading();},complete: () => {// 完成回调,可根据需要处理}});} else {// 如果获取token失败,根据业务需求处理}}).catch(error => {wx.showToast({title: error.message || '请求失败',icon: 'none',});});},},/*** 生命周期函数--监听页面隐藏*/onHide() {},/*** 生命周期函数--监听页面卸载*/onUnload() {},/*** 页面相关事件处理函数--监听用户下拉动作*/onPullDownRefresh() {},/*** 页面上拉触底事件的处理函数*/onReachBottom() {},/*** 用户点击右上角分享*/onShareAppMessage() {}
})

7.4 index.wxss代码

/* 添加或调整样式以匹配原生小程序组件 */
.modal-mask1 {position: fixed;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(0, 0, 0, 0.5);display: flex;justify-content: center;align-items: center;z-index: 999;
}.modal-container1 {width: 500rpx;border-radius: 8rpx;background-color: #fff;padding: 40rpx;
}.wx-icon {width: 120rpx;height: 120rpx;
}.login-btn {width: 260rpx;height: 58rpx;
}/* 其他样式保持与uni-app中的样式一致,但需根据微信原生组件调整类名和属性 */
.flex_start {display: flex;align-items: center;justify-content: flex-end;
}.txt {color: #161828;font-size: 24rpx;margin-left: 7rpx;
}.txt text {color: #000;font-weight: 600;text-decoration: underline;
}.endSty {width: 100%;justify-content: center;
}.avatar-wrapper {padding: 0;width: 180px !important;border-radius: 8px;margin: auto;/* margin-top: 40px; */margin-bottom: 50rpx;position: relative;padding-bottom: 20rpx;background-color: transparent;/* text-align: center; */}
.avatar-wrapper1{padding: 0;width: 180px !important;border-radius: 8px;margin: auto;position: relative;padding-bottom: 20rpx;background-color: transparent;
}
.avatar-wrapper1::after {border: none;
}
.weui-input {font-size: 28rpx;border-bottom: 1px solid #000;width: 207rpx;margin: auto;
}.up_img {width: 120rpx;height: 34rpx;color: #fff;background-color: #000;line-height: 34rpx;text-align: center;font-size: 22rpx;border-radius: 17rpx;position: absolute;left: 50%;transform: translateX(-50%);z-index: 999;bottom: 0;
}.avatar-wrapper::after {border: none;
}.avatar {display: block;width: 150rpx;height: 150rpx;border-radius: 50%;margin: auto;
}
.popupBox1 {width: 100%;border-radius: 8rpx 8rpx;
}
.loginIcon1 {position: relative;display: flex;justify-content: center;padding: 30rpx 0 30rpx 0;
}.popupClose {box-sizing: border-box;padding: 70rpx 0 30rpx 0;text-align: center;}
.popupClose image {/* width: 250rpx;height: 58rpx; */vertical-align: middle;
}
.btnSty{
width: 260rpx !important;
height: 58rpx;
}
.ruleTitle {text-align: center;font-weight: bold;
}

7.5 index.json代码

{"usingComponents": {}
}```

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/46776.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python关于excel常用函数(pandas篇)

iterrows函数&#xff1a; Pandas的基础数据结构可以分为两种&#xff1a;DataFrame和Series。不同于Series的是&#xff0c;Dataframe不仅有行索引还有列索引 。df.iterrows( )函数&#xff1a;可以返回所有的行索引&#xff0c;以及该行的所有内容。 pd.read_excel&#xf…

小型数控车床对现代制造业的影响

小型数控车床作为现代制造业的重要生产工具&#xff0c;集成了计算机控制、精密机械、电子技术和自动化技术&#xff0c;为各种复杂零件的加工&#xff0c;在生产效率和精度上带来了显著提升&#xff0c;它是制造业中不可或缺的基础装备&#xff0c;在金属切削加工领域发挥着关…

车间数据采集网关的工作原理和应用场景-天拓四方

在智能制造日益盛行的今天&#xff0c;车间数据采集作为整个生产流程中的关键环节&#xff0c;其重要性愈发凸显。数据采集网关作为这一环节的核心设备&#xff0c;扮演着承上启下的重要角色。本文旨在深入探讨车间数据采集网关的工作原理和应用场景。 一、数据采集网关的工作…

Java基础知识——继承

目录 一、什么是继承 二、类的继承格式 三、继承的特点 四、继承的类型 五、继承的关键字 六、为什么使用继承 一、什么是继承 继承是面向对象编程&#xff08;OOP&#xff09;的四大基本原则之一&#xff0c;它允许我们创建一个新类&#xff0c;继承并扩展现有类的属性和…

【HarmonyOS学习】Calendar Kit日历管理

简介 Calendar Kit提供日历与日程管理能力&#xff0c;包括日历的获取和日程的创建能力。 Calendar Kit为用户提供了一系列接口来获取日历账户&#xff0c;并使用特定的接口向日历账户中写入日程。 如果写入的日程带有提醒时间则系统会在时间到达时向用户发送提醒。 约束点…

eclipse 新建类class文件增加copyright版权信息

1、Window -> Preferences 2、输入code,找到code templates Java > Code Style > Code Templates 比如进行如何的设置&#xff1a; 3、新增类文件&#xff0c;会自动增加版权&#xff1a;

2024.7.12单片机PWM

遇到了一个光标变成下划线的问题&#xff1a; Keil5光标变下划线&#xff0c;变回来的方法_keil5光标是下划线-CSDN博客 这里是用了输入捕获&#xff08;IC&#xff1a;input capture&#xff09;&#xff0c;输出比较&#xff08;OC:Output Compare&#xff09;区别 学到这…

解析DDD开发框架Axon

在微服务架构盛行的当下&#xff0c;领域驱动设计&#xff08;DDD&#xff09;也得到了崭新的发展。在DDD中包含了聚合、领域事件等核心概念&#xff0c;也需要引入CQRS、事件溯源等架构模式。对于开发人员而言&#xff0c;如何简单而高效的实现这些核心概念和架构模式是一大痛…

集群节点状态异常的解决方式

文章目录 集群节点状态异常的解决方式问题概述解决方式1.关闭所有服务2.对所有集群删除Hadoop相关文件2.1 删除Hadoop系统运行时创建的临时数据和文件2.2 删除Hadoop的数据文件 3.重新对Hadoop节点进行初始化和启用4.重启服务&#xff0c;检查节点状态 集群节点状态异常的解决方…

软件测试工作流程

1、目的 有效的保证软件质量;有效的制定不同测试类型(软件系统测试、音频主观性测试、专项测试、自动化测试、性能测试、用户体验测试)的软件测试计划;按照计划进行测试,发现软件中存在的问题;对软件中已经解决的问题进行有效的验证;判定测试过程和问题验证的有效性。2、…

PostgreSQL(二十一)clog的作用与管理

一、CLOG的概念及作用 1、基础概念 &#xff08;1&#xff09;CLOG&#xff1a;记录事务号的状态&#xff0c;可以用其判断行的可见性。每个事务状态占用两个bit位。 tip&#xff1a;事务的状态有4种&#xff1a;IN_PROGRESS&#xff0c;COMMITTED&#xff0c;ABORTED和SUB_…

如何应对AI发展下的伦理挑战

目录 1.概述 2.构建可靠的AI隐私保护机制 2.1. 最小化数据收集 2.2. 数据去标识化 2.3. 加密技术 2.4. 分布式学习和边缘计算 2.5. 强化用户控制权 2.6. 独立审计和合规性检查 2.7. 持续教育和培训 2.8.小结 3.确保AI算法的公正性和透明度 3.1.增强AI决策透明度的方…

第一百五十九节 Java IO教程 - Java输入流、文件输入流、缓冲输入流、推回输入流

Java IO教程 - Java输入流 抽象基本组件是InputStream类。 InputStream|--FileInputStream |--ByteArrayInputStream |--PipedInputStream|--FilterInputStream|--BufferedInputStream |--PushbackInputStream |--DataInputStream |--ObjectInputStream我们有FileInputStream&…

【C++】——类和对象(中)

文章目录 类的默认成员函数构造函数析构函数拷贝构造函数赋值运算符重载运算符重载 const成员函数 类的默认成员函数 在C中&#xff0c;类&#xff08;class&#xff09;可以拥有多种成员函数&#xff0c;其中一些成员函数在类定义中没有显式声明时&#xff0c;编译器会隐式地…

Windows上LabVIEW编译生成可执行程序

LabVIEW项目浏览器(Project Explorer)中的"Build Specifications"就是用来配置项目发布方法的。在"Build Specifications"右键菜单中选取"New"&#xff0c;可以看到程序有几种不同的发布方法&#xff1a;Application(EXE)、Installer、.Net Inte…

C++第七弹 -- C/C++内存管理

目录 前言一. C/C内存分布二. C语言中动态内存管理方式三. C中动态内存管理四. operator new与operator delete函数五. new和delete的实现原理1.内置类型2. 自定义类型 六. 定位new表达式(placement-new)七. 常见面试题总结 前言 在C/C编程中&#xff0c;内存管理是至关重要的…

超详细Midjourney国际版注册使用全流程

众所周知&#xff0c;目前Midjourney AI绘画的国内版本有很多种&#xff0c;甚至微信、浏览器插件等都有&#xff0c;眼花缭乱&#xff0c;使用门槛低&#xff0c;无需特殊网络手段即可访问使用。 不过&#xff0c;根据一些用户的反馈&#xff0c;尽管国内的那些版本在注册和充…

软件测试——测试用例

工作职责&#xff1a; 1.负责产品系统测试&#xff0c;包括功能测试、性能测试、稳定性测试、用户场景测试、可靠性测试等。 2.负责测试相关文档的编写&#xff0c;包括测试计划、测试用例、测试报告等。 3.负责自动化测试框架、用例的维护。 岗位要求&#xff1a; 1.熟练…

人工智能与伦理挑战:多维度应对策略

人工智能技术近年来取得了迅猛发展&#xff0c;广泛应用于医疗诊断、金融分析、教育辅助、自动驾驶等各个领域&#xff0c;极大地提升了生产效率和服务质量&#xff0c;推动了科技进步和商业创新。然而&#xff0c;伴随其普及和应用的泛滥&#xff0c;AI也带来了数据隐私侵犯、…

C#知识|账号管理系统:添加账号的功能笔记

哈喽,你好啊,我是雷工! 本节记录账号管理系统中添加账号的逻辑过程,以下为学习笔记。 01 实现内容 ①:实现当点击【保存到数据库】按钮时,将账号名称、原创篇数、账号简介、账号类型显示的内容存储到LGAccountManagerDB数据库的Account表中; ②:实现点击【保存到数据库…