Files
aistream-test/测试流式传输uniapp/pages/index/原生.vue
T
2025-12-01 03:42:34 +08:00

353 lines
7.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="ai-chat-container">
<!-- 聊天消息列表 -->
<scroll-view class="chat-list" scroll-y scroll-bottom="{{scrollBottom}}"
:style="{height: `calc(100vh - ${inputAreaHeight}px)`}">
<!-- 系统消息 -->
<view class="chat-item system">
<view class="chat-avatar system-avatar">
<text class="iconfont icon-robot"></text>
</view>
<view class="chat-content">
<view class="content-text">你好我是智能助手有什么可以帮你的</view>
</view>
</view>
<!-- 用户消息 -->
<view class="chat-item user">
<view class="chat-content">
<view class="content-text">请问uniapp怎么实现语音流式传输</view>
</view>
<view class="chat-avatar user-avatar">
<text class="iconfont icon-user"></text>
</view>
</view>
<!-- AI回复消息 -->
<view class="chat-item ai">
<view class="chat-avatar ai-avatar">
<text class="iconfont icon-ai"></text>
</view>
<view class="chat-content">
<view class="content-text">
UniApp实现语音流式传输可通过5+ API采集音频帧结合WebSocket分块发送核心步骤包括
1. 初始化录音实例16k采样率单声道PCM);
2. 建立WebSocket连接
3. 分块发送音频数据
4. 接收实时ASR结果
</view>
</view>
</view>
</scroll-view>
<!-- 输入区域 + 按住发送按钮 -->
<view class="input-area" :style="{height: inputAreaHeight + 'px'}">
<!-- 按住发送按钮底部固定 -->
<view class="send-btn-area">
<button class="hold-send-btn" @touchstart="startRecord">
<text class="btn-text">{{status ? '松开发送' : '按住 说话/发送'}}</text>
</button>
</view>
</view>
<yao-RecordFrame ref="recordFrame" @onFrameRecorded="frameRecorded" @currentDecibels="onCurrentDecibels"
@onStop="stopIt"></yao-RecordFrame>
</view>
</template>
<script>
import {
myApi
} from "@/uni_modules/ty-uts-test";
export default {
data() {
return {
inputAreaHeight: 80,
status: "未录音",
recorder: null, // 录音实例
recordTimer: null, // 定时读取定时器
};
},
onUnload() {
// 页面卸载清理资源
this.stopRecord();
},
methods: {
// 开始录音
async startRecord() {
// 获取电量信息
// uni.getBatteryInfo({
// success(res) {
// console.log(res);
// uni.showToast({
// title: "当前电量:" + res.level + '%',
// icon: 'none'
// });
// }
// })
// * 1、引入方法声明 import { myApi } from "@/uni_modules/uts-api"
// * 2、方法调用
// myApi({
// paramA: true,
// complete: (res) => {
// console.log(res)
// }
// });
this.$refs.recordFrame.start({
sampleRate: 16000,
frameSize: 1024,
gain: 1.0 //增益值,数字越高音频声音越大 1.0~20.0
})
},
// 停止录音
stopRecord() {
},
frameRecorded({
isLastFrame,
frameBuffer
}) {
// console.log(isLastFrame,frameBuffer);
if (!isLastFrame) {
this.frameBuffer = frameBuffer;
}
this.isLastFrame = isLastFrame ? 'true' : 'false';
},
onCurrentDecibels(decibels) {
//当前分贝值 最小可测分贝(-80) 最大可测分贝(-30)
console.log("当前分贝:" + decibels)
}
}
};
</script>
<style scoped lang="scss">
// 全局容器
.ai-chat-container {
width: 100%;
height: 100vh;
background-color: #f5f7fa;
box-sizing: border-box;
padding-bottom: env(safe-area-inset-bottom); // 适配iOS底部安全区
}
// 聊天列表
.chat-list {
width: 100%;
padding: 20rpx 16rpx;
box-sizing: border-box;
// 消息项通用样式
.chat-item {
display: flex;
margin-bottom: 30rpx;
max-width: 85%;
// 头像通用样式
.chat-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-right: 20rpx;
background-color: #fff;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
.iconfont {
font-size: 40rpx;
}
}
// 消息内容
.chat-content {
.content-text {
padding: 24rpx 28rpx;
border-radius: 20rpx;
line-height: 1.6;
font-size: 32rpx;
color: #333;
word-wrap: break-word;
word-break: break-all;
}
}
}
// 系统消息
.system {
margin: 0 auto 30rpx;
.chat-avatar {
background-color: #e8f4f8;
.iconfont {
color: #4299e1;
}
}
.chat-content {
.content-text {
background-color: #e8f4f8;
color: #2d3748;
border-radius: 16rpx;
}
}
}
// 用户消息(右对齐)
.user {
margin-left: auto;
flex-direction: row-reverse;
.chat-avatar {
margin-right: 0;
margin-left: 20rpx;
background-color: #4299e1;
.iconfont {
color: #fff;
}
}
.chat-content {
.content-text {
background-color: #4299e1;
color: #fff;
border-radius: 20rpx 20rpx 8rpx 20rpx;
}
}
}
// AI消息(左对齐)
.ai {
.chat-avatar {
background-color: #9f7aea;
.iconfont {
color: #fff;
}
}
.chat-content {
.content-text {
background-color: #fff;
border-radius: 20rpx 20rpx 20rpx 8rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
}
}
}
}
// 输入区域
.input-area {
width: 100%;
background-color: #fff;
padding: 16rpx 20rpx;
box-sizing: border-box;
border-top: 1rpx solid #eee;
// 输入框容器
.input-box {
position: relative;
width: 100%;
margin-bottom: 20rpx;
.input-text {
width: 100%;
min-height: 80rpx;
max-height: 200rpx;
padding: 20rpx 24rpx;
padding-right: 80rpx;
box-sizing: border-box;
border: 1rpx solid #e5e7eb;
border-radius: 40rpx;
font-size: 32rpx;
line-height: 1.5;
background-color: #f9fafb;
resize: none;
outline: none;
}
.clear-btn {
position: absolute;
right: 20rpx;
top: 50%;
transform: translateY(-50%);
width: 60rpx;
height: 60rpx;
border-radius: 50%;
background-color: #e5e7eb;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
margin: 0;
.iconfont {
font-size: 32rpx;
color: #6b7280;
}
}
}
// 按住发送按钮区域
.send-btn-area {
width: 100%;
display: flex;
justify-content: center;
.hold-send-btn {
width: 80%;
height: 90rpx;
line-height: 90rpx;
border-radius: 45rpx;
background-color: #4299e1;
color: #fff;
font-size: 34rpx;
font-weight: 500;
box-shadow: 0 4rpx 12rpx rgba(66, 153, 225, 0.3);
transition: all 0.2s ease;
padding: 0;
margin: 0;
&:active {
background-color: #3182ce;
transform: scale(0.98);
}
.btn-text {
font-size: 34rpx;
}
}
}
}
// 图标占位样式(可替换为自定义图标/图片)
.iconfont {
font-family: "iconfont" !important;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-robot::before {
content: "\e600";
}
.icon-user::before {
content: "\e601";
}
.icon-ai::before {
content: "\e602";
}
.icon-clear::before {
content: "\e603";
}
</style>