Browse Source

Merge branch 'new_dev' of https://github.com/deepcloud2048/deep_voice into new_dev

newdev_shunjiawei
liwei1dao 1 year ago
parent
commit
f948d38b28
  1. 16
      lib/core/translations/language/en_us.dart
  2. 12
      lib/core/translations/language/zh_cn.dart
  3. 2
      lib/data/services/meeting/meeting_task_service.dart
  4. 35
      lib/modules/agent/controllers/agent_controller.dart
  5. 183
      lib/modules/agent/views/agent_view.dart
  6. 12
      lib/modules/meeting/controllers/meeting_record_controller.dart
  7. 67
      lib/modules/meeting/views/meeting_record_view.dart
  8. 117
      lib/modules/ota_upgrade/controllers/ota_core_contropller.dart
  9. 13
      lib/modules/ota_upgrade/controllers/ota_upgrade_controller.dart
  10. 7
      lib/modules/ota_upgrade/views/ota_upgrade_view.dart
  11. 32
      lib/modules/settings/views/settings_view.dart
  12. 108
      lib/modules/translation/views/translation_view.dart
  13. 1
      local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt
  14. 4
      local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/SimpleAudioReceiver.kt
  15. 4
      local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt

16
lib/core/translations/language/en_us.dart

@ -305,8 +305,20 @@ const Map<String, String> enUS = {
"loadFailedClickRetry": "Load failed, click to retry", "loadFailedClickRetry": "Load failed, click to retry",
"swipeUpForMore": "Swipe up for more", "swipeUpForMore": "Swipe up for more",
// Agent Controller // Preset prompts
'welcomeMessage': 'Hello! I\'m **XiaoYan**, I can help you:\n\n' "presetMusic": "Play some music", // Play some music
"presetNavigation": "Navigation to", // Navigation
"presetWeather": "Today's weather", // Weather
"presetNews": "Today's news", // News
"presetFood": "Nearby food", // Food
"playSomeMusic": "Play some popular music", // 播放一些流行音乐
"navigationTo": "Please help me navigate to", // 导航到
"todayWeather": "How's the weather today?", // 今日天气
"todayNews": "What's the news today?", // 今日新闻
"nearbyFood": "What delicious food is nearby?", // 美食
// Agent controller
'welcomeMessage': 'Hello! I\'m **Xiaoyan**, I can help you:\n\n'
'• Answer questions and provide information\n\n' '• Answer questions and provide information\n\n'
'• Real-time voice translation\n\n' '• Real-time voice translation\n\n'
'• Recommend music and podcasts\n\n' '• Recommend music and podcasts\n\n'

12
lib/core/translations/language/zh_cn.dart

@ -295,6 +295,18 @@ const Map<String, String> zhCN = {
"loadFailedClickRetry": "加载失败,点击重试", "loadFailedClickRetry": "加载失败,点击重试",
"swipeUpForMore": "向上滑动查看更多", "swipeUpForMore": "向上滑动查看更多",
// 预设提示词
"presetMusic": "来点音乐", // 来点音乐
"presetNavigation": "导航到", // 导航
"presetWeather": "今日天气", // 今日天气
"presetNews": "今日新闻", // 今日新闻
"presetFood": "附近美食", // 美食
"playSomeMusic": "播放一些流行音乐", // 播放一些流行音乐
"navigationTo": "请帮我导航到", // 导航到
"todayWeather": "今天天气如何?", // 今日天气
"todayNews": "今天有哪些新闻?", // 今日新闻
"nearbyFood": "附近有哪些美食?", // 美食
// Agent controller // Agent controller
'welcomeMessage': '你好!我是**小言**,我能帮你:\n\n' 'welcomeMessage': '你好!我是**小言**,我能帮你:\n\n'
'• 答问题和提供信息\n\n' '• 答问题和提供信息\n\n'

2
lib/data/services/meeting/meeting_task_service.dart

@ -26,7 +26,7 @@ class MeetingTaskService extends GetxService {
final String _appid = '2316081933'; final String _appid = '2316081933';
final String _token = 'mcJTh6OelBqU_L78lgGd77Nyrc_-5-En'; final String _token = 'mcJTh6OelBqU_L78lgGd77Nyrc_-5-En';
final String _cluster = 'volc_auc_common_flash'; final String _cluster = 'volc_auc_tele_flash';
final String _serviceUrl = 'https://openspeech.bytedance.com/api/v1/auc'; final String _serviceUrl = 'https://openspeech.bytedance.com/api/v1/auc';
Map<String, String> _headers = {}; Map<String, String> _headers = {};

35
lib/modules/agent/controllers/agent_controller.dart

@ -1287,6 +1287,41 @@ class AgentController extends GetxController {
useImagePrompt('请翻译这张图片中的文字'); useImagePrompt('请翻译这张图片中的文字');
} }
// 预设提示词处理(文本输入模式)
void preSetPromptAction(String presetType) {
// 确保在文本输入模式下
if (!isTextInputMode.value) {
// 如果不在文本模式,先切换到文本模式
isTextInputMode.value = true;
}
switch (presetType) {
case 'Music':
textController.text = 'playSomeMusic'.tr;
break;
case 'Navigation':
textController.text = 'navigationTo'.tr;
break;
case 'Weather':
textController.text = 'todayWeather'.tr;
break;
case 'News':
textController.text = 'todayNews'.tr;
break;
case 'Food':
textController.text = 'nearbyFood'.tr;
break;
default:
textController.text = presetType;
break;
}
// 自动发送消息
if (presetType != 'Navigation') {
sendMessage();
}
}
// 模式历史记录 // 模式历史记录
VoiceInputMode? _previousInputMode; VoiceInputMode? _previousInputMode;

183
lib/modules/agent/views/agent_view.dart

@ -341,80 +341,127 @@ class _AgentViewState extends State<AgentView> with WidgetsBindingObserver {
child: Column( child: Column(
children: [ children: [
// 图片预览区域 - 仅在图片输入模式下显示 // 图片预览区域 - 仅在图片输入模式下显示
Obx(() { Obx(
if (controller.isImageInputActive.value && () {
controller.selectedImagePath.value != null) { if (controller.isImageInputActive.value &&
return Column( controller.selectedImagePath.value != null) {
children: [ return Column(
// 图片预览和关闭按钮 children: [
Stack( // 图片预览和关闭按钮
children: [ Stack(
ClipRRect( children: [
borderRadius: BorderRadius.circular(12.w), ClipRRect(
child: Image.file( borderRadius: BorderRadius.circular(12.w),
File(controller.selectedImagePath.value!), child: Image.file(
height: 150.h, File(controller.selectedImagePath.value!),
width: double.infinity, height: 150.h,
fit: BoxFit.cover, width: double.infinity,
fit: BoxFit.cover,
),
), ),
), Positioned(
Positioned( top: 8.h,
top: 8.h, right: 8.w,
right: 8.w, child: GestureDetector(
child: GestureDetector( onTap: () => controller.clearImageInput(),
onTap: () => controller.clearImageInput(), child: Container(
child: Container( padding: EdgeInsets.all(4.w),
padding: EdgeInsets.all(4.w), decoration: BoxDecoration(
decoration: BoxDecoration( color: Colors.black.withOpacity(0.6),
color: Colors.black.withOpacity(0.6), shape: BoxShape.circle,
shape: BoxShape.circle, ),
), child: Icon(
child: Icon( Icons.close,
Icons.close, color: Colors.white,
color: Colors.white, size: 16.sp,
size: 16.sp, ),
), ),
), ),
), ),
),
],
),
// 预设提示选项
SizedBox(height: 12.h),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
_buildPromptChip(
context: context,
label: 'summarizeImageContent'.tr, //总结图片内容
onTap: () => controller.summarizeImage(),
),
SizedBox(width: 8.w),
_buildPromptChip(
context: context,
label: 'extractImageText'.tr, //抽取图像文字
onTap: () =>
controller.extractTextFromImage(),
),
SizedBox(width: 8.w),
_buildPromptChip(
context: context,
label: 'translateImageText'.tr, //翻译图像文字
onTap: () =>
controller.translateImageText(),
),
], ],
), ),
),
SizedBox(height: 12.h), // 预设提示选项
], SizedBox(height: 12.h),
); SingleChildScrollView(
} else { scrollDirection: Axis.horizontal,
return const SizedBox.shrink(); child: Row(
} children: [
}), _buildPromptChip(
context: context,
label:
'summarizeImageContent'.tr, //总结图片内容
onTap: () => controller.summarizeImage(),
),
SizedBox(width: 8.w),
_buildPromptChip(
context: context,
label: 'extractImageText'.tr, //抽取图像文字
onTap: () =>
controller.extractTextFromImage(),
),
SizedBox(width: 8.w),
_buildPromptChip(
context: context,
label: 'translateImageText'.tr, //翻译图像文字
onTap: () =>
controller.translateImageText(),
),
],
),
),
SizedBox(height: 12.h),
],
);
} else if (controller.isTextInputMode.value &&
!controller.hasTextInput.value) {
// 文本输入模式下,且输入框为空
return Column(
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
_buildPromptChip(
context: context,
label: 'presetMusic'.tr, // 来点音乐
onTap: () => controller
.preSetPromptAction('Music')),
SizedBox(width: 8.w),
_buildPromptChip(
context: context,
label: 'presetNavigation'.tr, // 导航
onTap: () =>
controller.preSetPromptAction(
'Navigation')),
SizedBox(width: 8.w),
_buildPromptChip(
context: context,
label: 'presetWeather'.tr, // 天气
onTap: () => controller
.preSetPromptAction('Weather')),
SizedBox(width: 8.w),
_buildPromptChip(
context: context,
label: 'presetNews'.tr, // 新闻
onTap: () => controller
.preSetPromptAction('News')),
SizedBox(width: 8.w),
_buildPromptChip(
context: context,
label: 'presetFood'.tr, // 美食
onTap: () => controller
.preSetPromptAction('Food')),
],
)),
SizedBox(height: 12.h),
],
);
} else {
return const SizedBox.shrink();
}
},
),
// 输入控件区域 - 包含输入行和展开的选项 // 输入控件区域 - 包含输入行和展开的选项
Column( Column(

12
lib/modules/meeting/controllers/meeting_record_controller.dart

@ -61,10 +61,10 @@ class MeetingRecordController extends GetxController
StreamSubscription<Uint8List>? _audioDataSubscription; StreamSubscription<Uint8List>? _audioDataSubscription;
// 添加波形放大倍数变量 // 添加波形放大倍数变量
final double waveAmplifyFactor = 100.0; // 增加波动幅度 final double waveAmplifyFactor = 250.0; // 增加波动幅度
final RxDouble ursorPosition = 0.0.obs; // 当前播放位置 final RxDouble ursorPosition = 0.0.obs; // 当前播放位置
final RxInt _currentPosition = 0.obs; // 原始位置索引 final RxInt _currentPosition = 0.obs; // 原始位置索引
int maxPoints = 500; // 最大显示点数(根据屏幕宽度优化) int maxPoints = 300; // 最大显示点数(根据屏幕宽度优化)
int sampleRate = 16000; // 假设音频采样率(根据实际情况调整) int sampleRate = 16000; // 假设音频采样率(根据实际情况调整)
// 波形流动动画控制器 // 波形流动动画控制器
@ -72,7 +72,7 @@ class MeetingRecordController extends GetxController
late Animation<double> waveformAnimation; late Animation<double> waveformAnimation;
// 设置最大点数(根据屏幕宽度) // 设置最大点数(根据屏幕宽度)
void setMaxPoints(double screenWidth) { void setMaxPoints(double screenWidth) {
maxPoints = screenWidth ~/ 2; // 每2像素一个数据点 maxPoints = screenWidth ~/ 3; // 增加数据点密度以填满整个区域
} }
@override @override
@ -377,7 +377,7 @@ class MeetingRecordController extends GetxController
return _currentPosition.value / waveData.length; return _currentPosition.value / waveData.length;
} }
/// 添加处理后的音频数据 - 优化流动效果 /// 添加处理后的音频数据 - 优化全屏流动效果
void _addAudioData(Float32List newAudio) { void _addAudioData(Float32List newAudio) {
if (!isRecording.value) return; if (!isRecording.value) return;
@ -389,8 +389,8 @@ class MeetingRecordController extends GetxController
for (final sample in downsampled) { for (final sample in downsampled) {
waveData.add(sample); waveData.add(sample);
//维护合理的数据长度 - 保持滑动窗口效果 // 维护合理的数据长度 - 保持足够的数据以填满整个屏幕
if (waveData.length > maxPoints) { if (waveData.length > maxPoints * 2) {
waveData.removeAt(0); // 移除最旧的数据 waveData.removeAt(0); // 移除最旧的数据
} }
} }

67
lib/modules/meeting/views/meeting_record_view.dart

@ -477,10 +477,10 @@ class RealTimeWaveformPainter extends CustomPainter {
} }
} }
/// 绘制中央时间参考线 /// 绘制中央时间参考线(只保留水平线)
void _drawCenterLine( void _drawCenterLine(
Canvas canvas, Size size, double centerX, double centerY) { Canvas canvas, Size size, double centerX, double centerY) {
// 绘制水平中线 // 只绘制水平中线
final horizontalLinePaint = Paint() final horizontalLinePaint = Paint()
..color = ..color =
(isDarkMode ? Colors.white : Colors.black).withValues(alpha: 0.15) (isDarkMode ? Colors.white : Colors.black).withValues(alpha: 0.15)
@ -492,51 +492,25 @@ class RealTimeWaveformPainter extends CustomPainter {
horizontalLinePaint, horizontalLinePaint,
); );
// 绘制垂直时间参考线(红色,更醒目) // 移除垂直时间参考线和三角形指示器
final centerLinePaint = Paint()
..color = Colors.red.withValues(alpha: 0.8)
..strokeWidth = 2.0
..style = PaintingStyle.stroke;
canvas.drawLine(
Offset(centerX, centerY - size.height * 0.4),
Offset(centerX, centerY + size.height * 0.4),
centerLinePaint,
);
// 在参考线顶部绘制小三角形指示器
final trianglePath = Path();
final triangleSize = 4.0;
trianglePath.moveTo(centerX, centerY - size.height * 0.4);
trianglePath.lineTo(
centerX - triangleSize, centerY - size.height * 0.4 - triangleSize);
trianglePath.lineTo(
centerX + triangleSize, centerY - size.height * 0.4 - triangleSize);
trianglePath.close();
final trianglePaint = Paint()
..color = Colors.red
..style = PaintingStyle.fill;
canvas.drawPath(trianglePath, trianglePaint);
} }
/// 绘制实时流动波形 /// 绘制实时流动波形(扩散到整个区域)
void _drawWaveform(Canvas canvas, Size size, double centerX, double centerY) { void _drawWaveform(Canvas canvas, Size size, double centerX, double centerY) {
final barWidth = 2.5; // 波形条宽度 final barWidth = 2.5; // 波形条宽度
final barSpacing = 0.5; // 波形条间距 final barSpacing = 0.5; // 波形条间距
final totalBarWidth = barWidth + barSpacing; final totalBarWidth = barWidth + barSpacing;
// 计算中央参考线左侧可以显示多少个波形条 // 计算整个宽度可以显示多少个波形条
final maxBarsOnLeft = (centerX / totalBarWidth).floor(); final maxBars = (size.width / totalBarWidth).floor();
// 绘制左侧流动波形(历史数据,从右向左流动) // 绘制扩散到整个区域的波形
_drawLeftWaveform( _drawFullWaveform(
canvas, centerX, centerY, barWidth, totalBarWidth, maxBarsOnLeft); canvas, size, centerY, barWidth, totalBarWidth, maxBars);
} }
/// 绘制左侧历史波形(从右向左流动) /// 绘制扩散到整个区域的波形
void _drawLeftWaveform(Canvas canvas, double centerX, double centerY, void _drawFullWaveform(Canvas canvas, Size size, double centerY,
double barWidth, double totalBarWidth, int maxBars) { double barWidth, double totalBarWidth, int maxBars) {
final dataLength = waveData.length; final dataLength = waveData.length;
if (dataLength == 0) return; if (dataLength == 0) return;
@ -544,24 +518,25 @@ class RealTimeWaveformPainter extends CustomPainter {
// 计算流动偏移量 // 计算流动偏移量
final flowOffset = animationValue * totalBarWidth; final flowOffset = animationValue * totalBarWidth;
// 绘制最近的波形条(最多显示maxBars个) // 绘制波形条,从左到右填满整个区域
final displayCount = min(dataLength, maxBars); final displayCount = min(dataLength, maxBars);
for (int i = 0; i < displayCount; i++) { for (int i = 0; i < displayCount; i++) {
// 计算波形条的x位置:从参考线开始,向左排列,加上流动偏移 // 计算波形条的x位置:从左边开始排列,加上流动偏移
final x = centerX - (i + 1) * totalBarWidth + flowOffset; final x = i * totalBarWidth + flowOffset;
// 如果波形条完全移出屏幕右侧,跳过绘制
if (x > size.width) continue;
// 如果波形条完全移出屏幕左侧,跳过绘制 // 如果波形条完全移出屏幕左侧,跳过绘制
if (x + barWidth < 0) continue; if (x + barWidth < 0) continue;
// 获取对应的音频数据(最新的数据在数组末尾) // 获取对应的音频数据(循环使用数据以填满整个区域)
final dataIndex = dataLength - 1 - i; final dataIndex = (dataLength - 1 - (i % dataLength)) % dataLength;
if (dataIndex < 0) continue;
final amplitude = waveData[dataIndex]; final amplitude = waveData[dataIndex];
// 计算透明度:越远的波形条越透明 // 计算透明度:中央区域更亮,边缘渐暗
final opacity = (1.0 - (i / displayCount) * 0.6).clamp(0.2, 1.0); final distanceFromCenter = (x - size.width / 2).abs() / (size.width / 2);
final opacity = (1.0 - distanceFromCenter * 0.4).clamp(0.3, 1.0);
_drawWaveBar(canvas, x, centerY, barWidth, amplitude, opacity); _drawWaveBar(canvas, x, centerY, barWidth, amplitude, opacity);
} }

117
lib/modules/ota_upgrade/controllers/ota_core_contropller.dart

@ -53,6 +53,123 @@ class OtaCoreService {
// ==================== 设备检查功能 ==================== // ==================== 设备检查功能 ====================
/// 检查BLE设备连接状态
/// 返回true表示设备已连接,可以进行升级
/// 返回false表示设备未连接,不能进行升级
bool checkBleConnectionStatus() {
try {
// 检查BLE管理器的连接状态
if (!_bleManager.isConnected) {
//_showBleDisconnectedDialog();
return false;
}
// 检查设备信息是否可用
final deviceInfo = _bleManager.deviceInfo.value;
if (deviceInfo == null) {
_showDeviceInfoUnavailableDialog();
return false;
}
return true;
} catch (e) {
_showBleCheckFailedSnackbar('检查BLE连接状态时发生错误:$e');
return false;
}
}
/// 显示BLE设备未连接对话框
void _showBleDisconnectedDialog() {
Get.dialog(
AlertDialog(
title: Text(
'BLE设备未连接',
style: TextStyle(
color: Colors.red[700],
fontWeight: FontWeight.w600,
),
),
content: Text(
'固件升级需要连接BLE设备\n请确保设备已正确连接后再试',
style: TextStyle(
color: Colors.red[600],
),
),
actions: [
TextButton(
onPressed: () => Get.back(),
style: TextButton.styleFrom(
foregroundColor: Colors.red[700],
),
child: const Text('确定'),
),
],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: BorderSide(
color: Colors.red.withValues(alpha: 0.3),
width: 1,
),
),
backgroundColor: Colors.red[50],
),
);
}
/// 显示设备信息不可用对话框
void _showDeviceInfoUnavailableDialog() {
Get.dialog(
AlertDialog(
title: Text(
'设备信息不可用',
style: TextStyle(
color: Colors.orange[700],
fontWeight: FontWeight.w600,
),
),
content: Text(
'无法获取设备信息\n请重新连接设备或稍后再试',
style: TextStyle(
color: Colors.orange[600],
),
),
actions: [
TextButton(
onPressed: () => Get.back(),
style: TextButton.styleFrom(
foregroundColor: Colors.orange[700],
),
child: const Text('确定'),
),
],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: BorderSide(
color: Colors.orange.withValues(alpha: 0.3),
width: 1,
),
),
backgroundColor: Colors.orange[50],
),
);
}
/// 显示BLE连接检查失败提示
/// [message] 错误信息
void _showBleCheckFailedSnackbar(String message) {
Get.snackbar(
'BLE连接检查失败',
message,
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.red[600],
colorText: Colors.white,
icon: const Icon(
Icons.bluetooth_disabled,
color: Colors.white,
),
);
}
/// 检查设备电量是否满足升级条件 /// 检查设备电量是否满足升级条件
/// 返回true表示电量充足,可以进行升级 /// 返回true表示电量充足,可以进行升级
/// 返回false表示电量不足,不能进行升级 /// 返回false表示电量不足,不能进行升级

13
lib/modules/ota_upgrade/controllers/ota_upgrade_controller.dart

@ -27,11 +27,12 @@ class OtaUpgradeController extends GetxController {
final RxDouble downloadProgress = 0.0.obs; final RxDouble downloadProgress = 0.0.obs;
final RxDouble progress = 0.0.obs; final RxDouble progress = 0.0.obs;
final RxInt type = OtaCoreService.NOT_STARTED.obs; final RxInt type = OtaCoreService.NOT_STARTED.obs;
final RxBool isUpdateAvailable = true.obs; final RxBool isUpdateAvailable = false.obs;
final RxBool isDownloading = false.obs; final RxBool isDownloading = false.obs;
final RxBool isUpgrade = false.obs; final RxBool isUpgrade = false.obs;
final RxBool isFetchingDeviceInfo = true.obs; final RxBool isFetchingDeviceInfo = false.obs;
final RxBool showDetailedStatus = false.obs; final RxBool showDetailedStatus = false.obs;
final RxBool isBleConnected = true.obs;
String _address = ''; String _address = '';
String _updatePackageAddress = ''; String _updatePackageAddress = '';
@ -53,6 +54,14 @@ class OtaUpgradeController extends GetxController {
/// 初始化控制器 /// 初始化控制器
/// 设置事件监听并加载版本信息 /// 设置事件监听并加载版本信息
Future<void> _initializeController() async { Future<void> _initializeController() async {
// 首先检查BLE设备连接状态
if (!_coreService.checkBleConnectionStatus()) {
//isFetchingDeviceInfo.value = false;
//errorMessage.value = 'unconnected'.tr;
isBleConnected.value = false;
return;
}
_listenToOtaEvents(); _listenToOtaEvents();
await _loadVersionInfo(); await _loadVersionInfo();
} }

7
lib/modules/ota_upgrade/views/ota_upgrade_view.dart

@ -397,7 +397,8 @@ class OtaUpgradeView extends GetView<OtaUpgradeController> {
), ),
// 版本状态指示器 // 版本状态指示器
SizedBox(height: 14.h), SizedBox(height: 14.h),
_buildVersionStatusIndicator(isDarkMode), if (controller.isBleConnected.value)
_buildVersionStatusIndicator(isDarkMode),
], ],
); );
} }
@ -836,7 +837,9 @@ class OtaUpgradeView extends GetView<OtaUpgradeController> {
label: Text( label: Text(
controller.isUpdateAvailable.value controller.isUpdateAvailable.value
? 'ota_updateNow'.tr ? 'ota_updateNow'.tr
: 'latestVersion'.tr, // 立即更新 : 已是最新版本 : controller.isBleConnected.value
? 'latestVersion'.tr // 立即更新 : 已是最新版本
: 'unconnected'.tr,
style: TextStyle( style: TextStyle(
fontSize: 16.sp, fontSize: 16.sp,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,

32
lib/modules/settings/views/settings_view.dart

@ -515,22 +515,22 @@ class SettingsView extends GetView<SettingsController> {
// ? Colors.white.withOpacity(0.1) // ? Colors.white.withOpacity(0.1)
// : Colors.grey[200]), // : Colors.grey[200]),
//BLE测试 //BLE测试
_buildSimpleNavigationSetting( // _buildSimpleNavigationSetting(
title: 'opus解码测试', // title: 'opus解码测试',
subtitle: '测试opus解码', // subtitle: '测试opus解码',
icon: Icons.bluetooth_searching, // icon: Icons.bluetooth_searching,
iconBgColor: isDarkMode // iconBgColor: isDarkMode
? Colors.green[900]!.withOpacity(0.3) // ? Colors.green[900]!.withOpacity(0.3)
: Colors.green[100]!, // : Colors.green[100]!,
iconColor: // iconColor:
isDarkMode ? Colors.green[300]! : Colors.green[600]!, // isDarkMode ? Colors.green[300]! : Colors.green[600]!,
titleColor: isDarkMode ? Colors.white : null, // titleColor: isDarkMode ? Colors.white : null,
subtitleColor: isDarkMode ? Colors.white70 : null, // subtitleColor: isDarkMode ? Colors.white70 : null,
onTap: () { // onTap: () {
Get.toNamed(Routes.opusTest); // Get.toNamed(Routes.opusTest);
}, // },
isDarkMode: isDarkMode, // isDarkMode: isDarkMode,
), // ),
// Divider( // Divider(
// height: 1, // height: 1,
// color: isDarkMode // color: isDarkMode

108
lib/modules/translation/views/translation_view.dart

@ -523,63 +523,63 @@ class TranslationView extends GetView<TranslationController> {
), ),
// 添加间距 // 添加间距
SizedBox(height: 16.h), //SizedBox(height: 16.h),
// 语音识别结果显示框 // 语音识别结果显示框
Container( // Container(
width: double.infinity, // width: double.infinity,
padding: EdgeInsets.all(12.w), // padding: EdgeInsets.all(12.w),
decoration: BoxDecoration( // decoration: BoxDecoration(
color: isDarkMode ? Colors.grey[800] : Colors.grey[100], // color: isDarkMode ? Colors.grey[800] : Colors.grey[100],
borderRadius: BorderRadius.circular(8.r), // borderRadius: BorderRadius.circular(8.r),
border: Border.all( // border: Border.all(
color: isDarkMode ? Colors.grey[600]! : Colors.grey[300]!, // color: isDarkMode ? Colors.grey[600]! : Colors.grey[300]!,
width: 1, // width: 1,
), // ),
), // ),
child: Obx(() { // child: Obx(() {
// 显示最新的语音识别结果 // // 显示最新的语音识别结果
final recognitionText = controller.latestRecognitionText.value; // final recognitionText = controller.latestRecognitionText.value;
final detectedLanguage = controller.detectedLanguageCode1.value; // final detectedLanguage = controller.detectedLanguageCode1.value;
return Column( // return Column(
crossAxisAlignment: CrossAxisAlignment.start, // crossAxisAlignment: CrossAxisAlignment.start,
children: [ // children: [
// 标题 // // 标题
Text( // Text(
'麦头语音识别结果', // '麦头语音识别结果',
style: TextStyle( // style: TextStyle(
fontSize: 12.sp, // fontSize: 12.sp,
color: isDarkMode ? Colors.grey[400] : Colors.grey[600], // color: isDarkMode ? Colors.grey[400] : Colors.grey[600],
fontWeight: FontWeight.w500, // fontWeight: FontWeight.w500,
), // ),
), // ),
SizedBox(height: 4.h), // SizedBox(height: 4.h),
// 识别文本 - 这里显示 finalResult1 的内容 // // 识别文本 - 这里显示 finalResult1 的内容
Text( // Text(
recognitionText.isEmpty ? '等待语音输入...' : recognitionText, // recognitionText.isEmpty ? '等待语音输入...' : recognitionText,
style: TextStyle( // style: TextStyle(
fontSize: 14.sp, // fontSize: 14.sp,
color: isDarkMode ? Colors.white : Colors.black87, // color: isDarkMode ? Colors.white : Colors.black87,
height: 1.3, // height: 1.3,
), // ),
), // ),
// 检测到的语言(如果有) // // 检测到的语言(如果有)
if (detectedLanguage.isNotEmpty) ...[ // if (detectedLanguage.isNotEmpty) ...[
SizedBox(height: 4.h), // SizedBox(height: 4.h),
Text( // Text(
'检测语言: $detectedLanguage', // '检测语言: $detectedLanguage',
style: TextStyle( // style: TextStyle(
fontSize: 10.sp, // fontSize: 10.sp,
color: // color:
isDarkMode ? Colors.grey[500] : Colors.grey[500], // isDarkMode ? Colors.grey[500] : Colors.grey[500],
), // ),
), // ),
], // ],
], // ],
); // );
}), // }),
), // ),
], ],
); );
}), }),

1
local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt

@ -321,6 +321,7 @@ class AzureAsrHelper(private val context: Context) {
isContinuousRecognitionActive = true isContinuousRecognitionActive = true
return true return true
} catch (e: Exception) { } catch (e: Exception) {
Log.e(tag, "开始连续识别失败: ${e.message}")
audioStream!!.stopMicrophoneCapture() audioStream!!.stopMicrophoneCapture()
isContinuousRecognitionActive = false isContinuousRecognitionActive = false
return false return false

4
local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/SimpleAudioReceiver.kt

@ -236,7 +236,7 @@ class SimpleAudioReceiver(private val context: Context) {
private fun runMicrophoneCapture() { private fun runMicrophoneCapture() {
try { try {
// 首先设置通话音频模式 // 首先设置通话音频模式
setupCommunicationAudioMode() //setupCommunicationAudioMode()
val supportedSampleRates = intArrayOf(16000, 8000, 11025, 22050, 44100) val supportedSampleRates = intArrayOf(16000, 8000, 11025, 22050, 44100)
val sampleRate = supportedSampleRates.firstOrNull { rate -> val sampleRate = supportedSampleRates.firstOrNull { rate ->
val bufferSize = AudioRecord.getMinBufferSize(rate, channelConfig, audioFormat) val bufferSize = AudioRecord.getMinBufferSize(rate, channelConfig, audioFormat)
@ -329,7 +329,7 @@ class SimpleAudioReceiver(private val context: Context) {
audioRecord?.stop() audioRecord?.stop()
// 恢复音频模式 这里会导致关闭麦克风卡住待优化 // 恢复音频模式 这里会导致关闭麦克风卡住待优化
restoreCommunicationAudioMode() //restoreCommunicationAudioMode()
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "停止麦克风捕获失败: ${e.message}") Log.e(TAG, "停止麦克风捕获失败: ${e.message}")

4
local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt

@ -1415,9 +1415,9 @@ startBytesStatistics()
// 将新数据添加到缓冲区 // 将新数据添加到缓冲区
audioBuffer.addAll(data.toList()) audioBuffer.addAll(data.toList())
// 当缓冲区达到80字节时,发送数据 // 当缓冲区达到120字节时,发送数据
while (audioBuffer.size >= AUDIO_CHUNK_SIZE) { while (audioBuffer.size >= AUDIO_CHUNK_SIZE) {
// 取出80字节数据 // 取出120字节数据
val chunk = ByteArray(AUDIO_CHUNK_SIZE) val chunk = ByteArray(AUDIO_CHUNK_SIZE)
for (i in 0 until AUDIO_CHUNK_SIZE) { for (i in 0 until AUDIO_CHUNK_SIZE) {
chunk[i] = audioBuffer.removeAt(0) chunk[i] = audioBuffer.removeAt(0)

Loading…
Cancel
Save