在家开发了录音按钮功能

This commit is contained in:
终究是寂寞
2026-03-05 00:25:04 +08:00
parent 696a48f3d6
commit 015af519fb
7 changed files with 50 additions and 29 deletions
+2 -3
View File
@@ -2,11 +2,10 @@
ENV = 'development'
# 'development'
#VITE_APP_BASE_API_Url = 'https://aits.jlbank.com.cn:7001'
VITE_APP_BASE_API_Url = 'https://aits.jlbank.com.cn:7001'
VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7002'
#VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7002'
# DEV
#VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001'
+19 -8
View File
@@ -243,6 +243,16 @@
.gif-box {
display: none;
}
.textarea {
visibility: visible;
pointer-events: none;
user-select: none;
}
}
&.is-translate.success .textarea {
visibility: visible;
pointer-events: auto;
user-select: auto;
}
&::after {
content: '';
@@ -262,7 +272,11 @@
&.success::after {
left: 78% !important;
}
// 输入框默认并不可见
.textarea {
visibility: hidden;
}
&.failed,&.networkError {
width: 506rpx;
height: 114rpx;
@@ -275,17 +289,14 @@
.error-tip-div {
display: flex !important;
visibility: visible; // 激活后可见
// animation: fadeIn 0.4s ease-out 0.1s forwards;
}
.textarea {
visibility: hidden; // 初始不可见且不占交互位置
}
}
&.init{
.textarea {
visibility: hidden; // 初始不可见且不占交互位置
visibility: hidden;
}
}
}
.talk-dialog {
width: 100%;
+2 -2
View File
@@ -8,8 +8,8 @@ const IsAndEnv = getPhoneEnvBool('AND')
// const url = '/traapp/asrAiModelSocket/open';
const url = '/traapp/asrAiModelSocket/open';
const _baseUrl = get_base_url(url).split('http').join('ws');
export const wsUrl = _baseUrl + url + '?summary=' + getToken();
// export const wsUrl = 'wss://ty_chat_test.home.tymas.cn:8000/ws/audio';
// export const wsUrl = _baseUrl + url + '?summary=' + getToken();
export const wsUrl = 'ws://10.10.10.8:8000/ws/asr';
const windowInfo = uni.getWindowInfo();
// 安全区域信息
const safeArea = windowInfo.safeArea;
@@ -9,6 +9,7 @@
*/
export type StatusType = 'default' | 'voice_recording' | 'text_input' | 'voice_to_text' | 'voice_send_ing' | 'send_over';
/**
* 语音转文字的子状态(仅当主状态为 voice_to_text 时生效)
*/
@@ -20,6 +21,7 @@ export type VoiceToTextSubStatus =
| 'failed' // 转换失败(网络/识别错误等)
| 'networkError'; // 转换失败(网络错误等)
export type WorkModeType = 'both' | 'text-only' | 'voice-only' ;
/** 错误码枚举 - 直接映射提示文本 */
export enum ErrorCode {
+19 -10
View File
@@ -19,7 +19,7 @@
ref="inputRef"
v-model="inputText"
:maxlength="props.maxlength"
:adjustPosition="false"
:adjustPosition="props.adjustPosition"
placeholderStyle="color:#999999;font-size:26rpx"
placeholder="请输入文字"
:disabled="props.isDisabled"
@@ -110,7 +110,7 @@
<script setup lang="ts">
import * as TouchBtnImages from './touch-btn.images'; // 导出图片
import { StatusType, VoiceToTextSubStatus, ErrorCode } from './touch-btn.types';
import { StatusType, VoiceToTextSubStatus, ErrorCode,WorkModeType } from './touch-btn.types';
import type { TouchBtnEmits } from './touch-btn.types';
import { wsUrl, bottomAreaTopBoundary, horizontalSplitX, initWebSocket, showErrorTip, vibrateLight } from './touch-btn';
import { ref, computed, onMounted, nextTick, watch, reactive } from 'vue';
@@ -161,6 +161,10 @@
type: Number,
default: 1000
},
adjustPosition:{
default: true,
type: Boolean
},
answerMethod:{
type: String,
default: '01',
@@ -170,7 +174,7 @@
}
}
});
const workMode = computed(() => {
const workMode = computed<WorkModeType>(() => {
const modeMap = {
'01': 'both',
'02': 'text-only',
@@ -254,6 +258,7 @@
voice_to_text_status.value = '';
tempText.value = '';
allText.value = '';
console.log('都清空了');
initWebSocket(wsUrl)
.then((socketTask) => {
ws.value = socketTask;
@@ -267,7 +272,7 @@
tempText.value = '';
allText.value = allText.value + body;
} else if (msgType === MessageType.TIP_MESSAGE) {
tempText.value = body as string;
tempText.value += body as string;
} else if (msgType === MessageType.CONTROL_CMD) {
// 返回结束消息
const controlBody = body as ControlBody;
@@ -305,7 +310,7 @@
});
})
.catch(() => {
// stopRecord('networkError');
stopRecord('networkError');
console.log('网络出现问题');
});
pressTimer.value = setTimeout(() => {
@@ -321,6 +326,7 @@
startAudioRecord({
onFrame: (pcmData: any) => {
if (wsStatus.value && ws.value) {
console.log('pcmData', pcmData.length);
ws.value.send({ data: ProtocolCodec.pack(MessageType.AUDIO_DATA, pcmData) });
}
},
@@ -439,9 +445,14 @@
};
// 切换键盘语音
const changeBtn = () => {
const changeBtn = (_isInputVisible = true) => {
if (props.isDisabled) return;
isInputVisible.value = !isInputVisible.value;
// 只要不是仅录音,就可以切换到录音按钮
if(workMode.value === 'text-only') {
isInputVisible.value = false
}
// 否则为true
isInputVisible.value = _isInputVisible;
inputText.value = '';
};
// 按钮右侧图标(三个功能)
@@ -454,8 +465,6 @@
} else {
isInputVisible.value = !isInputVisible.value;
}
inputText.value = '';
};
// 禁用时点击给的提示
const disabled_click = () => {
@@ -471,7 +480,7 @@
closePopup();
}
};
setupKeyboardHeightListener((height: number) => {
const _height = Math.max(height - 100, 0);
pageBoxMarginBottom.value = `${_height}px`;
+5 -5
View File
@@ -135,7 +135,7 @@
</view>
</scroll-view>
</view>
<TouchBtn
<!-- <TouchBtn
class="talk-btns"
@uploadVoice="uploadRecordNow"
@submitAnswer="submitAnswerNow"
@@ -144,10 +144,10 @@
:isLoading="!answerIsOver"
:adjustPosition="true"
:isDisabled="isHistory"
/>
<!-- <touch-btn @uploadVoice="uploadRecordNow" @submitAnswer="submitAnswerNow"
/> -->
<touch-btn @uploadVoice="uploadRecordNow" @submitAnswer="submitAnswerNow"
@startRecord="startRecordCallback" :loadingText="sendLoadingText" :isLoading="!answerIsOver"
:adjustPosition="true" :isDisabled="isHistory" /> -->
:adjustPosition="true" :isDisabled="isHistory" />
<History ref="historyRef" @showDetail="showHistoryDetail"></History>
<PreviewVue ref="previewRef" />
@@ -167,7 +167,7 @@
import { ref, unref, onMounted, watch, nextTick, computed, onActivated } from 'vue';
import common from '@/common/common';
import { setupKeyboardHeightListener } from '@/common/common';
import TouchBtn from '@/pages/course/components/touchBtn.vue';
// import TouchBtn from '@/pages/course/components/touchBtn.vue';
import TalkingItem from './components/talking-item.vue';
import PreviewVue from './components/preview.vue';
import { useSocketStore } from '@/store/socket.js';
@@ -14,7 +14,7 @@ import AtomicBoolean from "java.util.concurrent.atomic.AtomicBoolean";
const isRecording = new AtomicBoolean(false); // 原子布尔值,保证线程安全
// 1. 音频采集参数(极简配置,适配大部分设备)
const sampleRate : Int = 48000; // 采样率
const sampleRate : Int = 16000; // 采样率
const channelConfig = AudioFormat.CHANNEL_IN_MONO; // 单声道
const audioFormat = AudioFormat.ENCODING_PCM_16BIT; // 16位PCM
const minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);