x
This commit is contained in:
+3
-3
@@ -5,7 +5,7 @@ ENV = 'development'
|
||||
|
||||
# VITE_APP_BASE_API_Url = 'https://aits.jlbank.com.cn:7001'
|
||||
|
||||
# VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
|
||||
VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
|
||||
|
||||
|
||||
# VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7002'
|
||||
@@ -16,14 +16,14 @@ ENV = 'development'
|
||||
# dev
|
||||
# VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001'
|
||||
# sit
|
||||
VITE_APP_BASE_API_Url = 'http://25.18.122.91:9786'
|
||||
#VITE_APP_BASE_API_Url = 'http://25.18.122.91:9786'
|
||||
# UAT
|
||||
# VITE_APP_BASE_API_Url = 'http://25.18.122.78:9786'
|
||||
|
||||
# DEV
|
||||
# app入口
|
||||
|
||||
VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001'
|
||||
# VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001'
|
||||
# VITE_APP_BASE_API_Url = 'http://25.16.122.91:9786'
|
||||
# VITE_APP_BASE_API_Url = 'http://25.18.122.66:9786'
|
||||
|
||||
|
||||
@@ -411,6 +411,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/test/testChat",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/course/index",
|
||||
"style": {
|
||||
|
||||
@@ -32,68 +32,15 @@
|
||||
import showDialog from '@/common/dialogMessage'
|
||||
|
||||
const bbbb = () => {
|
||||
// showDialog({
|
||||
// title: '提示信息',
|
||||
// content: '检测到您已离开,即将退出学习页面。',
|
||||
// confirmText: '确认',
|
||||
// showCancel: false,
|
||||
// cancelText: '再想想',
|
||||
// success: (res) => {
|
||||
// if (res.confirm) {
|
||||
// console.log('用户点击确定');
|
||||
// }
|
||||
// },
|
||||
// cancel: () => {
|
||||
// console.log('用户点击取消');
|
||||
// }
|
||||
// });
|
||||
|
||||
showDialog({
|
||||
title: '提示',
|
||||
content: '检测到您已存在学习记录,要继续学习吗?',
|
||||
confirmText: '重新学习',
|
||||
showCancel: true,
|
||||
cancelText: '继续学习',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
console.log('用户点击确定');
|
||||
}
|
||||
},
|
||||
cancel: () => {
|
||||
console.log('用户点击取消');
|
||||
}
|
||||
});
|
||||
}
|
||||
const aaaa = () => {
|
||||
common.show('提示','检测到您已存在学习记录,要继续学习吗?','继续学习', '重新学习').then(res => {
|
||||
|
||||
})
|
||||
|
||||
|
||||
// function show(title, msg, showCancel = true, cancelText = '取消', confirmText = '确定') {
|
||||
|
||||
|
||||
// showDialog({
|
||||
// title: '提示',
|
||||
// content: '检测到您已存在学习记录,要继续学习吗?',
|
||||
// confirmText: '重新学习',
|
||||
// showCancel: true,
|
||||
// cancelText: '继续学习',
|
||||
// success: (res) => {
|
||||
// if (res.confirm) {
|
||||
// console.log('用户点击确定');
|
||||
// }
|
||||
// },
|
||||
// cancel: () => {
|
||||
// console.log('用户点击取消');
|
||||
// }
|
||||
// });
|
||||
common.navigateTo('/pages/test/testChat')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$bg-margin-left: 50rpx;
|
||||
|
||||
.detail-body {
|
||||
margin: 30rpx $bg-margin-left 0 $bg-margin-left;
|
||||
background: #ffffff;
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
<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 ai">
|
||||
<view class="chat-avatar ai-avatar">
|
||||
<text class="iconfont icon-ai"></text>
|
||||
</view>
|
||||
<view class="chat-content">
|
||||
<view class="content-text">{{ asrResult }}</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" @touchend="stopRecord" @touchcancel="handleTouchEnd">
|
||||
<text class="btn-text">{{ isHolding ? '松开发送' : '按住 说话/发送' }}</text>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Recorder from 'recorder-core';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
scrollBottom: 0,
|
||||
inputAreaHeight: 80,
|
||||
isHolding: false,
|
||||
asrResult: '',
|
||||
recorderManager: null, // 原生录音管理器
|
||||
ws: null, // WebSocket连接
|
||||
isRecording: false,
|
||||
CHUNK_SIZE: 6400, // 200ms/块
|
||||
recordFilePath: '', // 录音文件路径
|
||||
fileReaderTimer: null, // 分片读取定时器
|
||||
recorder: null, // 录音实例
|
||||
audioStream: [], // 实时音频流缓存
|
||||
sampleRate: 16000, // 采样率(常用 16000/44100)
|
||||
bitRate: 16, // 位深
|
||||
channels: 1 // 声道(单声道)
|
||||
};
|
||||
},
|
||||
onLoad() {
|
||||
this.initRecorder()
|
||||
},
|
||||
onUnload() {
|
||||
// 页面卸载时销毁实例
|
||||
this.destroyRecorder();
|
||||
},
|
||||
methods: {
|
||||
// 初始化录音器
|
||||
initRecorder() {
|
||||
console.log('plus.audio', plus.audio);
|
||||
|
||||
// 确保 plus.audio 存在
|
||||
if (!plus.audio) {
|
||||
console.error('5+ API 音频模块未加载');
|
||||
uni.showToast({ title: '录音功能初始化失败', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
// 原初始化逻辑
|
||||
const options = {
|
||||
filename: '_doc/audio/temp_recorder.amr',
|
||||
format: 'amr',
|
||||
sampleRate: 16000,
|
||||
bitRate: 16,
|
||||
channels: 1,
|
||||
bufferSize: 4096,
|
||||
onRecorded: (buffer) => {
|
||||
this.handleRealTimeStream(buffer);
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
this.recorder = plus.audio.getRecorder(options);
|
||||
console.log('录音器初始化成功');
|
||||
} catch (e) {
|
||||
console.error('创建录音实例失败:', e);
|
||||
uni.showToast({ title: '录音功能初始化失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
// 开始录音
|
||||
startRecord() {
|
||||
console.log('下·', this.isRecording, !this.recorder);
|
||||
if (this.isRecording || !this.recorder) return;
|
||||
this.isRecording = true;
|
||||
this.audioStream = []; // 清空历史流
|
||||
|
||||
this.recorder.record(
|
||||
() => {
|
||||
console.log('录音开始成功');
|
||||
},
|
||||
(err) => {
|
||||
console.error('录音启动失败:', err);
|
||||
this.isRecording = false;
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
// 停止录音
|
||||
stopRecord() {
|
||||
if (!this.isRecording || !this.recorder) return;
|
||||
this.isRecording = false;
|
||||
|
||||
this.recorder.stop(
|
||||
(filePath) => {
|
||||
console.log('录音停止,文件路径:', filePath);
|
||||
// 最终完整文件(可选)
|
||||
this.handleFinalFile(filePath);
|
||||
},
|
||||
(err) => {
|
||||
console.error('录音停止失败:', err);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ai-chat-container {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background-color: #f5f7fa;
|
||||
box-sizing: border-box;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.chat-list {
|
||||
width: 100%;
|
||||
padding: 20rpx 16rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.chat-item {
|
||||
display: flex;
|
||||
margin-bottom: 30rpx;
|
||||
max-width: 85%;
|
||||
}
|
||||
|
||||
.ai-avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
margin-right: 20rpx;
|
||||
background-color: #9f7aea;
|
||||
}
|
||||
|
||||
.icon-ai {
|
||||
font-size: 40rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.chat-content .content-text {
|
||||
padding: 24rpx 28rpx;
|
||||
border-radius: 20rpx 20rpx 20rpx 8rpx;
|
||||
line-height: 1.6;
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
background-color: #fff;
|
||||
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;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.hold-send-btn:active {
|
||||
background-color: #3182ce;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: 'iconfont' !important;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
.icon-ai::before {
|
||||
content: '\e602';
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<view>
|
||||
<video :is-live="true" id="myVideo" :src="videoSrc" :autoplay="true"></video>
|
||||
<live-pusher id="livePusher" ref="livePusher" class="livePusher" url="rtmp://25.18.122.148:9605/voice_in/aa" mode="SD" :muted="true" :enable-camera="false" :auto-focus="true" :beauty="1" whiteness="2" aspect="9:16" @statechange="statechange" @netstatus="netstatus" @error="error"></live-pusher>
|
||||
|
||||
<view class="btn" @click="prepare"><text>预热</text></view>
|
||||
<view class="btn" @click="start"><text>开始推流</text></view>
|
||||
<view class="btn" @click="pause"><text>暂停推流</text></view>
|
||||
<view class="btn" @click="resume"><text>恢复推流</text></view>
|
||||
<view class="btn" @click="stop"><text>停止推流</text></view>
|
||||
<view class="btn" @click="snapshot"><text>快照</text></view>
|
||||
<view class="btn" @click="startPreview"><text>开启摄像头预览</text></view>
|
||||
<view class="btn" @click="stopPreview"><text>关闭摄像头预览</text></view>
|
||||
<view class="btn" @click="switchCamera"><text>切换摄像头</text></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { prepareApi } from '@/api/talk.js'
|
||||
var pusher
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
context: null,
|
||||
baseName: 'aaa'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
videoSrc() {
|
||||
return 'rtmp://rtmp.home.tymas.cn:1935/voice_in/' + this.baseName
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
const videoContext = uni.createVideoContext('myVideo')
|
||||
videoContext.setVolume(1.0)
|
||||
// 注意:需要在onReady中 或 onLoad 延时
|
||||
// pusher = uni.createLivePusherContext('livePusher', this)
|
||||
// console.log(pusher)
|
||||
},
|
||||
methods: {
|
||||
statechange(e) {
|
||||
console.log('statechange:', e, JSON.stringify(e))
|
||||
},
|
||||
netstatus(e) {
|
||||
console.log('netstatus:' + JSON.stringify(e))
|
||||
},
|
||||
error(e) {
|
||||
console.log('error:' + JSON.stringify(e))
|
||||
},
|
||||
start: function () {
|
||||
console.log('statechange:', pusher.start)
|
||||
pusher.start({
|
||||
success: a => {
|
||||
console.log('livePusher.start:' + JSON.stringify(a))
|
||||
}
|
||||
})
|
||||
},
|
||||
prepare: function () {
|
||||
this.initPusher()
|
||||
// prepareApi(this.baseName)
|
||||
// .then(res => {
|
||||
// console.log(res)
|
||||
// })
|
||||
// .catch(err => {
|
||||
// console.log(err)
|
||||
// if (err === 'prepare') {
|
||||
// this.initPusher()
|
||||
// }
|
||||
// })
|
||||
},
|
||||
close: function () {
|
||||
pusher.close({
|
||||
success: a => {
|
||||
console.log('livePusher.close:' + JSON.stringify(a))
|
||||
}
|
||||
})
|
||||
},
|
||||
snapshot: function () {
|
||||
pusher.snapshot({
|
||||
success: e => {
|
||||
console.log(JSON.stringify(e))
|
||||
}
|
||||
})
|
||||
},
|
||||
resume: function () {
|
||||
pusher.resume({
|
||||
success: a => {
|
||||
console.log('livePusher.resume:' + JSON.stringify(a))
|
||||
}
|
||||
})
|
||||
},
|
||||
pause: function () {
|
||||
pusher.pause({
|
||||
success: a => {
|
||||
console.log('livePusher.pause:' + JSON.stringify(a))
|
||||
}
|
||||
})
|
||||
},
|
||||
stop: function () {
|
||||
pusher.stop({
|
||||
success: a => {
|
||||
console.log(JSON.stringify(a))
|
||||
}
|
||||
})
|
||||
},
|
||||
switchCamera: function () {
|
||||
pusher.switchCamera({
|
||||
success: a => {
|
||||
console.log('livePusher.switchCamera:' + JSON.stringify(a))
|
||||
}
|
||||
})
|
||||
},
|
||||
startPreview: function () {
|
||||
pusher.startPreview({
|
||||
success: a => {
|
||||
console.log('livePusher.startPreview:' + JSON.stringify(a))
|
||||
}
|
||||
})
|
||||
},
|
||||
stopPreview: function () {
|
||||
pusher.stopPreview({
|
||||
success: a => {
|
||||
console.log('livePusher.stopPreview:' + JSON.stringify(a))
|
||||
}
|
||||
})
|
||||
},
|
||||
initPusher() {
|
||||
pusher = new plus.video.LivePusher('pusher-box', {
|
||||
url: 'rtmp://rtmp.home.tymas.cn:1935/voice_in/' + this.baseName,
|
||||
'enable-camera': true
|
||||
})
|
||||
pusher.addEventListener('statechange', this.statechange)
|
||||
pusher.addEventListener('netstatus', this.netstatus)
|
||||
pusher.addEventListener('error', this.error)
|
||||
console.log(pusher)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.btn {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
background-color: #ccc;
|
||||
margin-bottom: 5rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -346,6 +346,14 @@
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
},{
|
||||
"path": "pages/test/testChat",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"app-plus": {
|
||||
"titleNView": false
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -10,5 +10,10 @@ export default defineConfig({
|
||||
port: 5174,
|
||||
strictPort: true, // 可选:端口被占用时直接报错(避免自动切换端口)
|
||||
open: false // 可选:启动后自动打开浏览器(按需开启)
|
||||
},
|
||||
base: './', // 关键:设置基础路径为相对路径
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
assetsDir: 'assets' // 和打包后的目录一致
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user