1-实现实时语音需要准备哪些东西
1-1 注册腾讯云并开通实时语音服务并创建秘钥拿到appid和SecretId和SecretKey(新用户免费送4个小时)



1-2 前往微信公众号插件市场开通腾讯云智能语音
腾讯云智能语音 | 小程序

1-3 前往隐私协议设置获取语音权限(切记,隐私权限更新后不会立马生效,需要大概1个小时左右)
2-实现方法(Taro版-vue写法)
2-1 新建一个index文件
app.json
plugins: {
QCloudAIVoice: {
version: '2.3.4', 插件版本号
provider: '' 插件appid
}
},
let plugin = Taro.requirePlugin('QCloudAIVoice')
let speechRecognizerManager = plugin.speechRecognizerManager()
const speechRecognizerManagerFn = () => {
speechRecognizerManager.OnRecognitionStart = res => {
console.log('开始识别', res)
}
speechRecognizerManager.OnSentenceBegin = res => {
console.log('一句话开始', res)
}
speechRecognizerManager.OnRecognitionResultChange = res => {
noSuccess(res)
if (res.code === 0) {
speechGesturePrompt.value = res.result.voice_text_str
} else {
countdownSendMessage()
noSuccess(res)
}
}
speechRecognizerManager.OnSentenceEnd = res => {
speechGesturePrompt.value = res.result.voice_text_str
console.log('一句话结束', res)
}
speechRecognizerManager.OnRecognitionComplete = res => {
console.log('识别结束', res)
}
speechRecognizerManager.OnError = res => {
console.log('识别失败', res)
noSuccess(res)
}
speechRecognizerManager.OnRecorderStop = res => {
console.log('录音结束', res)
}
}
const speechParameter = {
secretkey: '', 腾讯云获取
secretid: '', 腾讯云获取
appid: '', 腾讯云获取
engine_model_type: '16k_zh-PY', 语言种类
word_info: 2, 是否显示词级别时间戳
vad_silence_time: 240, 语音断句检测阈值
voice_format: 1 voice_format
}
speechRecognizerManager.start(speechParameter)
speechRecognizerManager.stop()
3-实现效果

4-如何在程序实现sse
const requestTask = Taro.request({
url: `xxx`,
enableChunked: true,
method: "GET",
timeout: '120000',
success(res) {
console.log(res.data)
},
fail: function (error) {
console.error(error);
},
complete: function () {
console.log('请求完成', str);
}
})
requestTask.onChunkReceived(res => {
console.log( res, res.data);
})
原理:
在微信小程序中实现并利用`enableChunked`选项,可以通过`wx.request`方法来实现。`enableChunked`设置为`true`允许微信小程序通过流式传输接收服务器发送的数据,这对于需要实时更新数据的应用场景非常有用。
首先,需要在发起请求时设置`enableChunked`为`true`,这样微信小程序就会在响应头中开启`transfer-encoding: chunked`,从而支持流式传输。通过调用`onChunkReceived`方法,可以监听到每个数据块(chunk)的接收。这个方法会在接收到新的数据块时被触发,允许开发者对每个数据块进行处理。
此外,为了监听SSE连接的结束,可以在`wx.request`的配置中添加一个`complete`回调函数。这个回调函数会在请求完成(无论是成功还是失败)时被调用,可以用来检测连接是否结束。如果需要在连接结束时执行特定的操作,可以在这个回调函数中添加相应的逻辑。
需要注意的是,由于微信小程序的API并不直接支持SSE协议,因此需要通过`wx.request`接口模拟实现SSE的功能。这意味着接收到的数据可能是以`Uint8Array`的形式,需要将其转换为文本以便进一步处理。这可以通过使用`TextDecoder`来实现,将接收到的数据解码为UTF-8格式的字符串。
综上所述,微信小程序通过`wx.request`方法并设置`enableChunked`为`true`来实现SSE的流式传输,并通过监听`onChunkReceived`方法来处理每个接收到的数据块。同时,通过在`wx.request`配置中添加`complete`回调函数来检测连接是否结束,并在需要时执行相应的操作
5-拿到后端返回的流式数据如何进行处理并实现打字机效果
let self = this
function setIntervalAnimateResponseText () {
self.animationFrameId = setInterval(() => {
animateResponseText()
}, 20)
}
setIntervalAnimateResponseText()
async function animateResponseText () {
if (self.isStop) {
return
}
if (self.finished && responseQueue.length === 0) {
self.stopMessageRequestTask(assistantId)
if (!self.topicId) {
await self.brainyTopics()
}
if (!fileUrls?.length) {
await self.chatgptQuestions({
id: assistantId,
prompt: !message ? fileUrls : message,
answer: self?.messagesList?.find((x: any) => x.id === assistantId)?.content
})
}
return
}
if (responseQueue.length > 0) {
const fetchCount = 3
for (let i = 0; i < fetchCount; i++) {
const item = responseQueue[i]
if (item) {
content += item
}
}
responseQueue = responseQueue.slice(fetchCount)
}
self.uploadMessage({
id: assistantId,
content: content,
role: 'assistant'
})
self.setScrollTopsState(1)
}
requestTask.onChunkReceived(res => {
animationFrameIdIndex += 1
const text = utf8Array2Str(new Uint8Array(res.data))
self.chatLoading = true
if (animationFrameIdIndex > 5) {
self.clearIntervalAnimationFrameId()
animationFrameIdIndex = 0
setIntervalAnimateResponseText()
}
text.split('data:').map((res1: any) => {
if (res1.replaceAll(/\s+/g, '') !== '') {
try {
const reText = res1
const newRes = JSON.parse(reText)
const input = ![ 'DONE', '[DONE]' ].includes(newRes) ? JSON.parse(reText) : ''
if (input.length > 0) {
const text = JSON.parse(input).choices[0].message.content
for (const item of text.replace(/\\n/g, '\n\n')) {
responseQueue.push(item)
}
}
self.finished = [ 'DONE', '[DONE]' ].includes(newRes)
} catch (error) {
self.clearIntervalAnimationFrameId()
console.log(error)
content = ''
}
}
return null
})
})
5-1 注意
let decoder = new TextDecoder('utf-8');
let text = decoder.decode(res.data)
在真机是失效得 需要换成 npm install utf8Array2Str
const text = utf8Array2Str(new Uint8Array(res.data))
6-其他问题
6-1 scroll-view动画过渡效果频繁调用一直滑到底部会偶尔回弹
1-原因
因为 scroll-view得动画效果有300ms得过渡时间,当开始往底部滚动得时候,调用次数过于频繁,比如100ms一次得时候,此时scroll-view动画效果还没有结束,此时在执行新的动画效果旧得没有结束就会出现错乱,这个是官方得老bug了,
2-解决方法
写入一个定时器 每一次执行动画效果后再执行新一轮动画效果
nextTick(() => {
if (timer.value) return
timer.value = setTimeout(() => {
Taro.createSelectorQuery()
.select('#scrollView')
.boundingClientRect(res => {
let scrollTops = 0
scrollTops += res?.height + 6666
if (scrollTops > 0) {
if (messageStore.scrollTop === scrollTops) return
messageStore.scrollTop = scrollTops
}
})
.exec()
clearTimeout(timer.value)
timer.value = null
}, time)
})
6-2 输入框出现光标调用微信获取键盘高度api 键盘和输入框有一定距离
分情况
1-当有两个输入框都调用的时候 且配置不一样 则最终出现得高度按最高算 需要保持一致
2-可能用的是高度height,建议用定位进行处处理
6-3 如何实现微信小程序上传本机pdf
新建外部得h5文件并部署在单独服务器上,然后用<web-view>嵌入并进行通信就可以实现
6-4 调用微信上传api拿到得文件名是官方定义得文件名不是自己得文件名
在进行上传得时候 携带一个文件名给后端 然后上传成功后 后端返回带有正确文件名得地址回来
6-5 textarea对于数字英文无法进行换行
给一个class类并加入line-break: anywhere; 该问题是官方老bug
6-6 如何对markdown字符进行标识
如果你是taro用户 直接去uniapp插件市场下载源码 并写入到代码中