Browse Source

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

newdev_shunjiawei
lxm 1 year ago
parent
commit
7e5971631d
  1. 1
      assets/lottie/intro_foriday.json
  2. 36
      lib/core/widgets/intro_overlay_builder.dart
  3. 28
      lib/data/services/novice_guide_service.dart
  4. 27
      lib/modules/home/views/home_view.dart
  5. 4
      lib/modules/meeting/controllers/meeting_record_controller.dart
  6. 4
      lib/modules/meeting/views/meeting_record_view.dart
  7. 10
      lib/modules/settings/controllers/settings_controller.dart
  8. 54
      local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift

1
assets/lottie/intro_foriday.json

File diff suppressed because one or more lines are too long

36
lib/core/widgets/intro_overlay_builder.dart

@ -1,8 +1,44 @@
import 'package:flutter/material.dart';
import 'package:flutter_intro/flutter_intro.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:lottie/lottie.dart';
class IntroOverlayBuilder {
static Widget homeBuilder(
StepWidgetParams params,
bool isWakeup, {
Function? onNext,
}) {
return Column(
children: [
SizedBox(
width: 200.w,
height: 200.w,
child: Lottie.asset('assets/lottie/intro_foriday.json'),
),
Padding(
padding: EdgeInsets.only(bottom: 20.w),
child: Text(
isWakeup ? '我在呢~' : '对着麦克风说:“小言小言”',
style: TextStyle(
fontSize: 15.sp,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
if (onNext != null)
_button(
'下一步',
() {
params.onNext!();
onNext();
},
),
],
);
}
static Widget aiBuilder(
StepWidgetParams params,
String text, {

28
lib/data/services/novice_guide_service.dart

@ -1,3 +1,6 @@
import 'dart:async';
import 'package:ble_service/ble_service.dart';
import 'package:flutter_intro/flutter_intro.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
@ -5,9 +8,14 @@ import 'package:get_storage/get_storage.dart';
class NoviceGuideService extends GetxService {
final GetStorage _storage = GetStorage();
bool isHomeGuide = true;
final BleService _bleService = BleService();
StreamSubscription<dynamic>? _statusSubscription;
bool isHomeGuide = false;
bool isAIGuide = true;
RxBool isWakeup = false.obs;
int aiStep = 0;
List aiStepsList = [
@ -56,6 +64,12 @@ class NoviceGuideService extends GetxService {
// isAIGuide = _storage.read('ai_guide') ?? false;
}
@override
void onClose() {
closeWakeupListen();
super.onClose();
}
void startHomeGuide() async {
if (!isHomeGuide) {
await Future.delayed(const Duration(milliseconds: 200));
@ -73,4 +87,16 @@ class NoviceGuideService extends GetxService {
Intro.of(Get.context!).start(group: 'ai');
}
}
void startWakeupListen() {
_statusSubscription = _bleService.onStatusUpdated.listen((event) {
if (event is Map && event['type'] == 'wakeup') {
isWakeup.value = true;
}
});
}
void closeWakeupListen() {
_statusSubscription?.cancel();
}
}

27
lib/modules/home/views/home_view.dart

@ -100,7 +100,9 @@ class HomeView extends GetView<HomeController> {
return IntroOverlayBuilder.aiBuilder(
params,
'欢迎使用Voitrans!首先,让我们唤醒你的专属 AI—— 小言',
onNext: () {},
onNext: () {
controller.noviceGuideService.startWakeupListen();
},
);
},
builder: (BuildContext context, GlobalKey key) => SizedBox(
@ -114,11 +116,26 @@ class HomeView extends GetView<HomeController> {
IntroStepBuilder(
group: 'home',
order: 2,
getOverlayPosition: ({
required Offset offset,
required Size screenSize,
required Size size,
}) {
return OverlayPosition(
top: 200.h,
width: screenSize.width,
crossAxisAlignment: CrossAxisAlignment.end,
);
},
overlayBuilder: (params) {
return IntroOverlayBuilder.aiBuilder(
params,
'对着麦克风说“小言小言”',
onNext: () {},
return Obx(
() => IntroOverlayBuilder.homeBuilder(
params,
controller.noviceGuideService.isWakeup.value,
onNext: () {
controller.noviceGuideService.closeWakeupListen();
},
),
);
},
builder: (BuildContext context, GlobalKey key) => SizedBox(

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

@ -138,7 +138,7 @@ class MeetingRecordController extends GetxController
switch (audioType.value) {
case 0:
fileName.value = "现场录音";
_audioSourceType = true;
_audioSourceType = false;
break;
case 1:
fileName.value = "音、视频录音";
@ -271,7 +271,7 @@ class MeetingRecordController extends GetxController
void _startHardwareServices() {
switch (audioType.value) {
case 0:
_bleManager.openEncoder();
// _bleManager.openEncoder();
break;
case 1:
_bleManager.openDecoder();

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

@ -95,7 +95,7 @@ class MeetingRecordView extends GetView<MeetingRecordController> {
unselectedLabelColor: Colors.grey,
tabs: const [
Tab(text: '音频'),
Tab(text: '文本'),
// Tab(text: '文本'),
],
),
Expanded(
@ -103,7 +103,7 @@ class MeetingRecordView extends GetView<MeetingRecordController> {
controller: controller.tabController,
children: [
_buildAudioTab(context, isDarkMode),
_buildTextTab(context, isDarkMode),
// _buildTextTab(context, isDarkMode),
],
),
),

10
lib/modules/settings/controllers/settings_controller.dart

@ -1,9 +1,11 @@
import 'package:agent_service/agent_service.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:get_storage/get_storage.dart';
import '../../../core/themes/theme_service.dart';
import '../../../data/services/speech_factory.dart';
import '../../../routes/app_routes.dart';
import '../models/language_model.dart';
import 'package:logger/logger.dart';
import '../../../data/services/ble_manager.dart';
@ -381,15 +383,21 @@ class SettingsController extends GetxController {
}
}
void setLanguage(LanguageModel data) {
Future<void> setLanguage(LanguageModel data) async {
if (data.value != 'system') {
List languageList = data.value.split('_');
Get.updateLocale(Locale(languageList[0], languageList[1]));
} else {
Get.updateLocale(Get.deviceLocale!);
}
print("languageList: ${data.value}");
language.value = data;
_storage.write('language', data.value);
// 延迟一下确保语言更新完成,然后重新进入应用
await Future.delayed(const Duration(milliseconds: 500));
// 重新进入应用 - 回到启动页面重新初始化
Get.offAllNamed(Routes.splash);
Get.back();
}

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

@ -997,7 +997,7 @@ class ChatApiStreamCallback: StreamCallback {
if speakResponse && reply && broadcast{
try agentService.azureTtsHelper?.speakStream(token)
// 在开始流式TTS时立即停止气泡音
try agentService.audioPlayer?.stopAwaitSound()
// try agentService.audioPlayer?.stopAwaitSound()
}
if (reply && token != "") {
try agentService.sendEvent(name: "assistant_token", data: ["token": token])
@ -1220,8 +1220,12 @@ class AudioPlayer {
private var player: AVAudioPlayer?
private var callingPlayer: AVAudioPlayer?
private var awaitPlayer: AVAudioPlayer? // 新增:等待音效播放器
private var awaitTimer: DispatchSourceTimer? // 新增:等待音效超时定时器
private let logger = OSLog(subsystem: "com.yunqiinnovation.agent_service", category: "AudioPlayer")
private let audioQueue = DispatchQueue(label: "agent.audio.player", qos: .userInitiated)
// 等待音效超时时间(秒)- 改为 var 以支持动态修改
private var awaitTimeoutSeconds: TimeInterval = 10.0
private var resourcesBundle: Bundle {
#if SWIFT_PACKAGE
@ -1247,7 +1251,14 @@ class AudioPlayer {
}
func playAwaitSound() {
// 先停止之前的等待音效和定时器
stopAwaitSound()
// 播放等待音效
playLoopSound(named: "await", fileType: "mp3", player: &awaitPlayer)
// 启动超时定时器
startAwaitTimeout()
}
func playStopSound() {
@ -1264,8 +1275,14 @@ class AudioPlayer {
}
func stopAwaitSound() {
// 停止音频播放
awaitPlayer?.stop()
awaitPlayer = nil
// 停止超时定时器
stopAwaitTimeout()
os_log("停止等待音效播放", log: logger, type: .debug)
}
private func playSound(named: String, fileType: String = "mp3") {
@ -1338,6 +1355,41 @@ class AudioPlayer {
os_log("播放循环音频失败: %{public}@", log: logger, type: .error, error.localizedDescription)
}
}
private func startAwaitTimeout() {
// 停止之前的定时器
stopAwaitTimeout()
// 创建新的定时器
let timer = DispatchSource.makeTimerSource(queue: DispatchQueue.global(qos: .utility))
awaitTimer = timer
timer.schedule(deadline: .now() + awaitTimeoutSeconds)
timer.setEventHandler { [weak self] in
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
os_log("等待音效超时,自动停止播放 - 超时时间: %.0f秒",
log: self.logger, type: .info, self.awaitTimeoutSeconds)
self.stopAwaitSound()
}
}
timer.resume()
os_log("启动等待音效超时定时器,超时时间: %.0f秒",
log: logger, type: .debug, awaitTimeoutSeconds)
}
private func stopAwaitTimeout() {
awaitTimer?.cancel()
awaitTimer = nil
}
func setAwaitTimeout(_ seconds: TimeInterval) {
awaitTimeoutSeconds = max(2.0, seconds) // 最小5秒
os_log("设置等待音效超时时间: %.0f秒", log: logger, type: .info, awaitTimeoutSeconds)
}
}
extension AgentServiceImpl: AzureAsrHelper.ContinuousRecognizeCallback {

Loading…
Cancel
Save