Browse Source

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

newdev_shunjiawei
tanlongsheng 10 months ago
parent
commit
62cde73101
  1. 3
      lib/core/translations/language/ar_sa.dart
  2. 3
      lib/core/translations/language/de_de.dart
  3. 6
      lib/core/translations/language/en_us.dart
  4. 3
      lib/core/translations/language/hi_in.dart
  5. 3
      lib/core/translations/language/it_it.dart
  6. 3
      lib/core/translations/language/ko_kr.dart
  7. 3
      lib/core/translations/language/pt_pt.dart
  8. 3
      lib/core/translations/language/ru_ru.dart
  9. 8
      lib/core/translations/language/zh_cn.dart
  10. 9
      lib/core/translations/language/zh_hk.dart
  11. 31
      lib/data/services/ble_manager.dart
  12. 39
      lib/modules/goods/views/goodsai_view.dart
  13. 51
      lib/modules/goods/views/goodsmeet_view.dart
  14. 51
      lib/modules/goods/views/goodstrans_view.dart
  15. 41
      lib/modules/goods/views/goodsvip_view.dart
  16. 48
      lib/modules/goods/views/widgets/goods_footer_section.dart
  17. 8
      lib/modules/meeting/views/meeting_home_view.dart
  18. 7
      lib/modules/translation/controllers/translation_controller.dart
  19. 8
      lib/modules/translation/middleware/views/translation_middleware_view.dart
  20. 6
      local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift
  21. 25
      local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleCommandSender.kt
  22. 27
      local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt

3
lib/core/translations/language/ar_sa.dart

@ -1188,8 +1188,7 @@ const Map<String, String> arSA = {
"guideSmsEnd": "Message sent—voice control is convenient",
// Goods pages common footer (placeholders)
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About',
'copyrightVoiTrans': '© 2025 VoiTrans',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1':

3
lib/core/translations/language/de_de.dart

@ -909,8 +909,7 @@ const Map<String, String> deDE = {
"guideSmsEnd": "Message sent—voice control is convenient",
// Goods pages common footer (placeholders)
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About',
'copyrightVoiTrans': '© 2025 VoiTrans',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1':

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

@ -189,7 +189,7 @@ const Map<String, String> enUS = {
// 商品页面(AI/翻译/会议)
'availablePackages': 'Available Packages',
'remainingQuota': 'Remaining Quota',
'totalCount': 'Total Count',
'totalQuota': 'Total Quota',
'remaining': 'Remaining',
'featureDescription': 'Feature Description',
// AI 功能卡片
@ -232,8 +232,8 @@ const Map<String, String> enUS = {
// 商品页通用页脚
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About',
'copyrightVoiTrans': '© 2025 VoiTrans',
'iapCustomerServiceQQLabel': 'IAP customer service QQ: @qq',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// 会议商品页描述
'meetingHeaderDesc1':

3
lib/core/translations/language/hi_in.dart

@ -877,8 +877,7 @@ const Map<String, String> hiIN = {
"guideSmsEnd": "Message sent—voice control is convenient",
// Goods pages common footer (placeholders)
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About',
'copyrightVoiTrans': '© 2025 VoiTrans',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1':

3
lib/core/translations/language/it_it.dart

@ -896,8 +896,7 @@ const Map<String, String> itIT = {
"guideSmsEnd": "Message sent—voice control is convenient",
// Goods pages common footer (placeholders)
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About',
'copyrightVoiTrans': '© 2025 VoiTrans',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1':

3
lib/core/translations/language/ko_kr.dart

@ -813,8 +813,7 @@ const Map<String, String> koKR = {
"guideSmsEnd": "Message sent—voice control is convenient",
// Goods pages common footer (placeholders)
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About',
'copyrightVoiTrans': '© 2025 VoiTrans',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1':

3
lib/core/translations/language/pt_pt.dart

@ -898,8 +898,7 @@ const Map<String, String> ptPT = {
"guideSmsEnd": "Message sent—voice control is convenient",
// Goods pages common footer (placeholders)
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About',
'copyrightVoiTrans': '© 2025 VoiTrans',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1':

3
lib/core/translations/language/ru_ru.dart

@ -891,8 +891,7 @@ const Map<String, String> ruRU = {
"guideSmsEnd": "Message sent—voice control is convenient",
// Goods pages common footer (placeholders)
'appNameProvider': 'App: VoiTrans · Provided by: VoiTrans',
'moreInfoViewInSettingsAbout': 'For more info, go to Settings > About',
'copyrightVoiTrans': '© 2025 VoiTrans',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1':

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

@ -183,7 +183,7 @@ const Map<String, String> zhCN = {
// 商品页面(AI/翻译/会议)
'availablePackages': '可购买套餐',
'remainingQuota': '剩余额度',
'totalCount': '总次数',
'totalQuota': '总额度',
'remaining': '剩余',
'featureDescription': '功能说明',
// AI 功能卡片
@ -225,9 +225,9 @@ const Map<String, String> zhCN = {
'trans_003_desc': '含 1000 次翻译(语音/文本)',
// 商品页通用页脚
'appNameProvider': '应用名称:VoiTrans · 服务提供:VoiTrans',
'moreInfoViewInSettingsAbout': '更多信息请前往 设置 > 关于 查看',
'copyrightVoiTrans': '© 2025 VoiTrans',
'appNameProvider': '应用名称:Voitrans · 服务提供:Voitrans',
'iapCustomerServiceQQLabel': '内购商品专属客服QQ:@qq',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// 会议商品页描述
'meetingHeaderDesc1': '录音转写、关键词检索与自动总结,提升会议效率。',

9
lib/core/translations/language/zh_hk.dart

@ -835,10 +835,11 @@ const Map<String, String> zhHK = {
"guideSmsInput": "Text Dad: I’ll be home for dinner",
"guideSmsSend": "Lily will send the message",
"guideSmsEnd": "Message sent—voice control is convenient",
// Goods pages common footer (placeholders)
'appNameProvider': '應用名稱:VoiTrans · 服務提供:VoiTrans',
'moreInfoViewInSettingsAbout': '更多信息請前往 設置 > 關於 查看',
'copyrightVoiTrans': '© 2025 VoiTrans',
// 商品页通用页脚
'appNameProvider': '應用名稱:Voitrans · 服務提供:Voitrans',
'iapCustomerServiceQQLabel': '內购商品专属客服QQ:@qq',
'copyrightVoitrans': '© 2025 Voitrans Technologies',
// Meeting goods page (placeholders)
'meetingHeaderDesc1': '錄音轉寫、關鍵詞檢索與自動總結,提升會議效率。',

31
lib/data/services/ble_manager.dart

@ -202,6 +202,8 @@ class BleManager extends GetxService {
final _isCodecActive = false.obs;
bool get isCodecActive => _isCodecActive.value;
RxBool get isCodecActiveRx => _isCodecActive;
bool _awaitingCodecOpen = false; //是否正在等待编码器打开的成功应答
bool _awaitingCodecClose = false; //是否正在等待编码器关闭的成功应答
// 订阅
StreamSubscription<dynamic>? _statusSubscription;
@ -267,7 +269,9 @@ class BleManager extends GetxService {
state == BleConnectionState.error) {
Logger.info('lxm--BLE设备已断开或发生错误');
_isConnected.value = false;
// 更新设备信息Add commentMore actions
_awaitingCodecOpen = false;
_awaitingCodecClose = false;
_isCodecActive.value = false;
Logger.info('lxm--断开连接时重置设备信息为0');
_updateDeviceInfoIfNeeded(
batteryLevel: 0,
@ -376,7 +380,16 @@ class BleManager extends GetxService {
print(" CONTROL_CODEC: $commandId,$data");
final bool codecSuccess = _isCodecControlSuccess(data);
_isCodecActive.value = codecSuccess; // 更新编解码器状态
if (_awaitingCodecOpen) {
//如果正在等待打开编解码器
_isCodecActive.value = codecSuccess; // 只在等待打开时更新状态
_awaitingCodecOpen = false;
} else if (_awaitingCodecClose) {
if (codecSuccess) {
_isCodecActive.value = false;
}
_awaitingCodecClose = false;
}
if (codecSuccess) {
print("lxm--编解码控制成功 (rawData 第二字节非 0)");
@ -991,19 +1004,27 @@ class BleManager extends GetxService {
/// 打开解码器
Future<bool> openDecoder() async {
try {
_awaitingCodecOpen = true;
_awaitingCodecClose = false;
_isCodecActive.value = false;
return await _bleService.openDecoder();
} catch (e) {
Logger.error('打开解码器失败: ${e.toString()}');
_awaitingCodecOpen = false;
return false;
}
}
/// 打开解码器
/// 打开A2DP解码器
Future<bool> openA2DPDecoder() async {
try {
_awaitingCodecOpen = true;
_awaitingCodecClose = false;
_isCodecActive.value = false;
return await _bleService.openA2DPDecoder();
} catch (e) {
Logger.error('打开解码器失败: ${e.toString()}');
_awaitingCodecOpen = false;
return false;
}
}
@ -1021,9 +1042,13 @@ class BleManager extends GetxService {
/// 关闭编解码器
Future<bool> closeCodec() async {
try {
_awaitingCodecOpen = false;
_awaitingCodecClose = true;
_isCodecActive.value = false;
return await _bleService.closeCodec();
} catch (e) {
Logger.error('关闭编解码器失败: ${e.toString()}');
_awaitingCodecClose = false;
return false;
}
}

39
lib/modules/goods/views/goodsai_view.dart

@ -6,6 +6,7 @@ import '../../../data/models/goods.dart';
import '../../../data/models/user_Info.dart';
import '../controllers/goodsai_controller.dart';
import '../utils/goods_i18n.dart';
import 'widgets/goods_footer_section.dart';
class GoodsaiView extends GetView<GoodsaiController> {
const GoodsaiView({super.key});
@ -61,7 +62,7 @@ class GoodsaiView extends GetView<GoodsaiController> {
SizedBox(height: 16.h),
_buildFeaturesSection(isDarkMode),
SizedBox(height: 16.h),
_buildFooterSection(isDarkMode),
GoodsFooterSection(isDarkMode: isDarkMode),
],
);
}
@ -212,7 +213,7 @@ class GoodsaiView extends GetView<GoodsaiController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${'totalCount'.tr}:$totalAi',
'${'totalQuota'.tr}:$totalAi',
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[700],
@ -334,40 +335,6 @@ class GoodsaiView extends GetView<GoodsaiController> {
);
}
Widget _buildFooterSection(bool isDarkMode) {
final subColor = isDarkMode ? Colors.white60 : Colors.grey[600];
return Padding(
padding: EdgeInsets.symmetric(vertical: 12.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: double.infinity,
child: Divider(color: isDarkMode ? Colors.white24 : Colors.black12),
),
SizedBox(height: 8.h),
Text(
'appNameProvider'.tr,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11.sp, color: subColor),
),
SizedBox(height: 4.h),
Text(
'moreInfoViewInSettingsAbout'.tr,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11.sp, color: subColor),
),
SizedBox(height: 4.h),
Text(
'copyrightVoiTrans'.tr,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11.sp, color: subColor),
),
],
),
);
}
Widget _buildFeatureCard(
bool isDarkMode, {
required IconData icon,

51
lib/modules/goods/views/goodsmeet_view.dart

@ -5,6 +5,7 @@ import '../../../data/models/goods.dart';
import '../../../data/models/user_Info.dart';
import '../controllers/goodsmeet_controller.dart';
import '../utils/goods_i18n.dart';
import 'widgets/goods_footer_section.dart';
class GoodsmeetView extends GetView<GoodsmeetController> {
const GoodsmeetView({super.key});
@ -64,7 +65,7 @@ class GoodsmeetView extends GetView<GoodsmeetController> {
if (index == controller.items.length + 2) {
return _buildFeaturesSection(isDarkMode);
}
return _buildFooterSection(isDarkMode);
return GoodsFooterSection(isDarkMode: isDarkMode);
},
);
}),
@ -195,7 +196,7 @@ class GoodsmeetView extends GetView<GoodsmeetController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${'totalCount'.tr}:$totalAi',
'${'totalQuota'.tr}:$totalAi',
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[700],
@ -256,12 +257,12 @@ class GoodsmeetView extends GetView<GoodsmeetController> {
fontWeight: FontWeight.w600,
color: isDarkMode ? Colors.white : Colors.black,
)),
SizedBox(height: 4.h),
Text(localizedGoodsDesc(item),
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[600],
)),
// SizedBox(height: 4.h),
// Text(localizedGoodsDesc(item),
// style: TextStyle(
// fontSize: 12.sp,
// color: isDarkMode ? Colors.white70 : Colors.grey[600],
// )),
],
),
),
@ -429,38 +430,4 @@ class GoodsmeetView extends GetView<GoodsmeetController> {
),
);
}
Widget _buildFooterSection(bool isDarkMode) {
final subColor = isDarkMode ? Colors.white60 : Colors.grey[600];
return Padding(
padding: EdgeInsets.symmetric(vertical: 12.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: double.infinity,
child: Divider(color: isDarkMode ? Colors.white24 : Colors.black12),
),
SizedBox(height: 8.h),
Text(
'appNameProvider'.tr,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11.sp, color: subColor),
),
SizedBox(height: 4.h),
Text(
'moreInfoViewInSettingsAbout'.tr,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11.sp, color: subColor),
),
SizedBox(height: 4.h),
Text(
'copyrightVoiTrans'.tr,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11.sp, color: subColor),
),
],
),
);
}
}

51
lib/modules/goods/views/goodstrans_view.dart

@ -5,6 +5,7 @@ import '../../../data/models/goods.dart';
import '../../../data/models/user_Info.dart';
import '../controllers/goodstrans_controller.dart';
import '../utils/goods_i18n.dart';
import 'widgets/goods_footer_section.dart';
class GoodstransView extends GetView<GoodstransController> {
const GoodstransView({super.key});
@ -63,7 +64,7 @@ class GoodstransView extends GetView<GoodstransController> {
if (index == controller.items.length + 2) {
return _buildFeaturesSection(isDarkMode);
}
return _buildFooterSection(isDarkMode);
return GoodsFooterSection(isDarkMode: isDarkMode);
},
);
}),
@ -194,7 +195,7 @@ class GoodstransView extends GetView<GoodstransController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${'totalCount'.tr}:$totalAi',
'${'totalQuota'.tr}:$totalAi',
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[700],
@ -255,12 +256,12 @@ class GoodstransView extends GetView<GoodstransController> {
fontWeight: FontWeight.w600,
color: isDarkMode ? Colors.white : Colors.black,
)),
SizedBox(height: 4.h),
Text(localizedGoodsDesc(item),
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[600],
)),
// SizedBox(height: 4.h),
// Text(localizedGoodsDesc(item),
// style: TextStyle(
// fontSize: 12.sp,
// color: isDarkMode ? Colors.white70 : Colors.grey[600],
// )),
],
),
),
@ -431,38 +432,4 @@ class GoodstransView extends GetView<GoodstransController> {
),
);
}
Widget _buildFooterSection(bool isDarkMode) {
final subColor = isDarkMode ? Colors.white60 : Colors.grey[600];
return Padding(
padding: EdgeInsets.symmetric(vertical: 12.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: double.infinity,
child: Divider(color: isDarkMode ? Colors.white24 : Colors.black12),
),
SizedBox(height: 8.h),
Text(
'appNameProvider'.tr,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11.sp, color: subColor),
),
SizedBox(height: 4.h),
Text(
'moreInfoViewInSettingsAbout'.tr,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11.sp, color: subColor),
),
SizedBox(height: 4.h),
Text(
'copyrightVoiTrans'.tr,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11.sp, color: subColor),
),
],
),
);
}
}

41
lib/modules/goods/views/goodsvip_view.dart

@ -5,6 +5,7 @@ import '../../../data/models/goods.dart';
import '../../../data/models/user_Info.dart';
import '../controllers/goodsvip_controller.dart';
import '../utils/goods_i18n.dart';
import 'widgets/goods_footer_section.dart';
class GoodsvipView extends GetView<GoodsvipController> {
const GoodsvipView({super.key});
@ -68,7 +69,7 @@ class GoodsvipView extends GetView<GoodsvipController> {
}
}
children.add(_buildFooterSection(isDarkMode));
children.add(GoodsFooterSection(isDarkMode: isDarkMode));
content = ListView(
key: ValueKey(userTick),
padding: EdgeInsets.all(16.w),
@ -223,40 +224,6 @@ class GoodsvipView extends GetView<GoodsvipController> {
);
}
Widget _buildFooterSection(bool isDarkMode) {
final subColor = isDarkMode ? Colors.white60 : Colors.grey[600];
return Padding(
padding: EdgeInsets.symmetric(vertical: 12.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: double.infinity,
child: Divider(color: isDarkMode ? Colors.white24 : Colors.black12),
),
SizedBox(height: 8.h),
Text(
'appNameProvider'.tr,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11.sp, color: subColor),
),
SizedBox(height: 4.h),
Text(
'moreInfoViewInSettingsAbout'.tr,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11.sp, color: subColor),
),
SizedBox(height: 4.h),
Text(
'copyrightVoiTrans'.tr,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11.sp, color: subColor),
),
],
),
);
}
Widget _buildTypeHeader(UsageType type, bool isDarkMode) {
final titles = {
UsageType.AI: 'aiFunction'.tr,
@ -442,7 +409,7 @@ class GoodsvipView extends GetView<GoodsvipController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${'totalCount'.tr}:$total',
'${'totalQuota'.tr}:$total',
style: TextStyle(fontSize: 12.sp, color: subColor),
),
Text(
@ -701,7 +668,7 @@ class GoodsvipView extends GetView<GoodsvipController> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${'totalCount'.tr}:$total',
'${'totalQuota'.tr}:$total',
style: TextStyle(fontSize: 12.sp, color: subColor),
),
Text(

48
lib/modules/goods/views/widgets/goods_footer_section.dart

@ -0,0 +1,48 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../../../data/models/appconfig.dart';
class GoodsFooterSection extends StatelessWidget {
final bool isDarkMode;
const GoodsFooterSection({super.key, required this.isDarkMode});
@override
Widget build(BuildContext context) {
final subColor = isDarkMode ? Colors.white60 : Colors.grey[600];
final qq = AppConfig.env('iapCustomerServiceQQ') ?? '';
return Padding(
padding: EdgeInsets.symmetric(vertical: 12.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: double.infinity,
child: Divider(color: isDarkMode ? Colors.white24 : Colors.black12),
),
SizedBox(height: 8.h),
Text(
'appNameProvider'.tr,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11.sp, color: subColor),
),
SizedBox(height: 4.h),
if (qq.isNotEmpty) ...[
Text(
'iapCustomerServiceQQLabel'.trParams({'qq': qq}),
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11.sp, color: subColor),
),
SizedBox(height: 4.h),
],
// SizedBox(height: 4.h),
Text(
'copyrightVoitrans'.tr,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11.sp, color: subColor),
),
],
),
);
}
}

8
lib/modules/meeting/views/meeting_home_view.dart

@ -513,9 +513,11 @@ class _MeetingHomeViewState extends State<MeetingHomeView>
}
String _formatHms(int seconds) {
int h = seconds ~/ 3600;
int m = (seconds % 3600) ~/ 60;
int s = seconds % 60;
final sec = seconds < 0 ? 0 : seconds; // 确保秒数非负
final d = Duration(seconds: sec);
final h = d.inHours;
final m = d.inMinutes.remainder(60);
final s = d.inSeconds.remainder(60);
String twoDigits(int n) => n.toString().padLeft(2, '0');
return '${twoDigits(h)}:${twoDigits(m)}:${twoDigits(s)}';
}

7
lib/modules/translation/controllers/translation_controller.dart

@ -1008,7 +1008,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver {
if (event.text.isEmpty) break;
//通话模式下:己方语言即为源语言,无需判断
detectedLanguageCode = sourceLanguageCode.value;
Logger.info("处理己方识别完成:${event.text}");
Logger.info("lxm---处理己方识别完成:${event.text}");
handleFinalResult(event.text);
break;
@ -1126,10 +1126,11 @@ class TranslationController extends GetxController with WidgetsBindingObserver {
/// 处理最终识别结果
/// [text] 识别的文本
Future<void> handleFinalResult(String text) async {
if (text.isEmpty || translationHistory.isEmpty) return;
if (text.isEmpty) return;
// 更新当前项
if (translationHistory.last.isIntermediate) {
if (translationHistory.isNotEmpty &&
translationHistory.last.isIntermediate) {
translationHistory.last.sourceText = text;
translationHistory.last.isIntermediate = false;
translationHistory.refresh();

8
lib/modules/translation/middleware/views/translation_middleware_view.dart

@ -212,9 +212,11 @@ class TranslationMiddlewareView
}
String _formatHms(int seconds) {
int h = seconds ~/ 3600;
int m = (seconds % 3600) ~/ 60;
int s = seconds % 60;
final sec = seconds < 0 ? 0 : seconds; // 确保秒数非负
final d = Duration(seconds: sec);
final h = d.inHours;
final m = d.inMinutes.remainder(60);
final s = d.inSeconds.remainder(60);
String twoDigits(int n) => n.toString().padLeft(2, '0');
return '${twoDigits(h)}:${twoDigits(m)}:${twoDigits(s)}';
}

6
local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift

@ -1707,14 +1707,16 @@ class ChatApiStreamCallback: StreamCallback {
return
}
responseBuilder += token
if (responseBuilder.isEmpty) { //关闭声音
try agentService.audioPlayer?.stopAwaitSound()
}
responseBuilder += token
if speakResponse && reply && broadcast{
try agentService.azureTtsHelper?.speakStream(sessionid:sessionid,token)
// 在开始流式TTS时立即停止气泡音
}
if (reply && token != "") {
try agentService.audioPlayer?.stopAwaitSound()
try agentService.sendEvent(name: "assistant_token", data: ["sessionid":sessionid,"token": token])
}
}catch {

25
local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleCommandSender.kt

@ -85,17 +85,6 @@ class BleCommandSender {
*/
fun notifyWakeupSignalReceived()
/**
* 获取录音文件对象
* @return 录音文件对象
*/
fun getRecordFile(): RecordingFile?
/**
* 获取重新压缩录音文件对象
* @return 重新压缩录音文件对象
*/
fun getRecordFile1(): RecordingFile?
}
private var callback: CommandSenderCallback? = null
@ -382,20 +371,6 @@ class BleCommandSender {
else -> "未知状态($codecStatus)"
}
// 处理录音文件
if (codecStatus == BleConst.CODEC_CONTROL_DECODE_ON ||
codecStatus == BleConst.CODEC_CONTROL_A2DP_PLAY ||
codecStatus == BleConst.CODEC_CONTROL_CALL_RECORD_PLAY ||
codecStatus == BleConst.CODEC_CONTROL_ENCODE_ON
) {
callback?.getRecordFile1()?.closeFile()
callback?.getRecordFile1()?.creatingFiles()
callback?.getRecordFile()?.closeFile()
callback?.getRecordFile()?.creatingFiles()
} else if (codecStatus == BleConst.CODEC_CONTROL_CLOSE) {
callback?.getRecordFile()?.closeFile()
callback?.getRecordFile1()?.closeFile()
}
Log.d(TAG, "收到设备响应,channelMode: $channelMode")

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

@ -212,10 +212,10 @@ object BleService {
scanHandler = Handler(Looper.getMainLooper())
recordfile = RecordingFile(this.context)
recordfile!!.fileName = "不拆分"
recordfile!!.fileName = "耳机端"
recordfile1 = RecordingFile(this.context)
recordfile1!!.fileName = "重新压缩"
recordfile1!!.fileName = "手机端"
// 初始化Opus音频管理器
if (!opusAudioManager.initialize()) {
@ -325,19 +325,7 @@ object BleService {
this@BleService.notifyWakeupSignalReceived()
}
/**
* 获取录音文件实例
*/
override fun getRecordFile(): RecordingFile? {
return recordfile
}
/**
* 获取录音文件实例1
*/
override fun getRecordFile1(): RecordingFile? {
return recordfile1
}
})
}
@ -875,14 +863,14 @@ object BleService {
// 统计接收到的字节数
bytesReceivedInCurrentSecond += data.size
processAudioData(data)
Log.i(TAG, "lxm--收到音频特征数据, 字节数=${data.size}")
// Log.i(TAG, "lxm--收到音频特征数据, 字节数=${data.size}")
}
BleConst.CALL_RECEIVE_AUDIO_CHAR_UUID -> {
// 统计接收到的字节数
bytesReceivedInCurrentSecond += data.size
processAudioData(data)
Log.i(TAG, "lxm--收到通话音频特征数据, 字节数=${data.size}")
//Log.i(TAG, "lxm--收到通话音频特征数据, 字节数=${data.size}")
}
// 通知特征数据(命令和控制)
BleConst.NOTIFY_CHAR_UUID -> {
@ -1119,6 +1107,8 @@ object BleService {
sampleRate: Int = 16000,
packetSize: Int = 40
): Boolean {
recordfile?.creatingFiles();
return opusAudioManager.startDecodeStream(hasHeader, channel, sampleRate, packetSize)
}
@ -1204,6 +1194,7 @@ object BleService {
if (audioChunk != null) {
// 发送音频数据块并等待回调
recordfile1?.saveAudioDataToWav(audioChunk)
sendAudioChunkWithCallback(audioChunk)
Thread.sleep(AUDIO_SEND_INTERVAL)
}
@ -1259,7 +1250,7 @@ object BleService {
isWaitingForWriteCallback = true
callWriteChar?.value = chunk
recordfile1?.saveAudioDataToWav(chunk)
//recordfile1?.saveAudioDataAsUtf8Hex(chunk, true)
val isSuccess = bluetoothGatt?.writeCharacteristic(callWriteChar)
@ -1439,7 +1430,7 @@ object BleService {
fun openA2DPDecoder(channelMode: Int = BleConst.AUDIO_CHANNEL_STEREO): Boolean {
Log.i(TAG, "打开A2DP解码器...")
startOpusEncodeStream()
recordfile1?.creatingFiles();
startOpusStreamDecoding(false, 2, 16000, 80)
val cmdData = byteArrayOf(
BleConst.CODEC_CONTROL_A2DP_PLAY.toByte(),

Loading…
Cancel
Save