Browse Source

修改声音复刻

weicu
tanlongsheng 10 months ago
parent
commit
dd269fec96
  1. 128
      lib/modules/voice_replication/views/recorder_bottom_sheet.dart

128
lib/modules/voice_replication/views/recorder_bottom_sheet.dart

@ -1,8 +1,19 @@
import 'dart:io';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:record/record.dart';
import 'package:uuid/uuid.dart';
import '../../../core/utils/permission_util.dart';
import '../../../data/models/appconfig.dart';
import '../controllers/voice_replication_controller.dart';
class RecorderBottomSheet extends StatefulWidget {
@ -15,13 +26,24 @@ class RecorderBottomSheet extends StatefulWidget {
class _RecorderBottomSheetState extends State<RecorderBottomSheet> {
final _controller = Get.find<VoiceReplicationController>();
final GetStorage _storage = GetStorage();
final _record = AudioRecorder();
bool _isRecording = false;
String _resourceKey = '';
String _resourceRegion = '';
String _jessicaConsentId = '';
String _voiceTalentName = '';
String _jessicaPersonalVoiceId = '';
String _path = '';
@override
void initState() {
super.initState();
_getDefaultData();
}
@override
@ -30,6 +52,103 @@ class _RecorderBottomSheetState extends State<RecorderBottomSheet> {
super.dispose();
}
void _getDefaultData() async {
_resourceKey = AppConfig.env('AZURE_SPEECH_KEY') ?? '';
_resourceRegion = AppConfig.env('AZURE_SPEECH_REGION') ?? 'eastasia';
_jessicaConsentId = const Uuid().v4();
Map? userInfo = _storage.read('user_info');
if (userInfo != null) {
_voiceTalentName = userInfo['user']['name'] ?? '';
_jessicaPersonalVoiceId = userInfo['user']['uid'] ?? '';
}
}
void _startRecording() async {
setState(() {
_isRecording = true;
});
await PermissionUtil.instance.requestPermission(
permissionType: Permission.microphone,
permissionName: 'microphonePermission'.tr,
explanationText: 'microphonePermissionExplanation'.tr,
permanentDenialText: 'microphonePermissionPermanentDenial'.tr,
);
final directory = await getApplicationDocumentsDirectory();
final recordDir = Directory('${directory.path}/VoiceReplication');
if (!await recordDir.exists()) {
await recordDir.create(recursive: true);
}
_path =
'${directory.path}/VoiceReplication/recording_${DateTime.now().millisecondsSinceEpoch}.wav';
await _record.start(
const RecordConfig(
encoder: AudioEncoder.wav,
sampleRate: 24000,
numChannels: 1,
),
path: _path,
);
}
void _completeRecorder() async {
EasyLoading.show(status: '正在创建个人语音...');
try {
await _record.stop();
await _consents();
await _personalvoices();
} catch (e) {
Get.snackbar('error'.tr, e.toString(), snackPosition: SnackPosition.TOP);
}
EasyLoading.dismiss();
}
Future<void> _consents() async {
final url = Uri.parse(
'https://$_resourceRegion.api.cognitive.microsoft.com/customvoice/consents/$_jessicaConsentId?api-version=2024-02-01-preview');
final request = http.MultipartRequest('POST', url);
request.headers['Ocp-Apim-Subscription-Key'] = _resourceKey;
request.fields['description'] = 'Consent for $_voiceTalentName voice';
request.fields['projectId'] = 'Voitrans';
request.fields['voiceTalentName'] = _voiceTalentName;
request.fields['companyName'] = '深圳市云衍智能科技有限公司';
request.fields['locale'] = 'zh-CN';
request.files.add(await http.MultipartFile.fromPath('audiodata', _path));
final streamed = await request.send();
final response = await http.Response.fromStream(streamed);
if (streamed.statusCode < 200 || streamed.statusCode >= 300) {
throw Exception('Failed to create consent: ${response.statusCode}');
}
}
Future<void> _personalvoices() async {
final url = Uri.parse(
'https://$_resourceRegion.api.cognitive.microsoft.com/customvoice/personalvoices/$_jessicaPersonalVoiceId?api-version=2024-02-01-preview');
final request = http.MultipartRequest('POST', url);
request.headers['Ocp-Apim-Subscription-Key'] = _resourceKey;
request.fields['projectId'] = 'Voitrans';
request.fields['consentId'] = _jessicaConsentId;
request.files.add(await http.MultipartFile.fromPath('audiodata', _path));
final streamed = await request.send();
final response = await http.Response.fromStream(streamed);
if (streamed.statusCode >= 200 && streamed.statusCode < 300) {
final bodyText = utf8.decode(response.bodyBytes, allowMalformed: true);
if (bodyText.isNotEmpty) {
final decoded = jsonDecode(bodyText);
print('------2-------$decoded');
_controller.speakerProfileId.value = decoded['speakerProfileId'];
_storage.write('open_voice_replication', true);
_storage.write('speakerProfileId', decoded['speakerProfileId']);
}
} else {
throw Exception(
'Failed to create personal voice: ${response.statusCode}');
}
}
@override
Widget build(BuildContext context) {
return Padding(
@ -145,9 +264,12 @@ class _RecorderBottomSheetState extends State<RecorderBottomSheet> {
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
_isRecording = !_isRecording;
});
if (_isRecording) {
Get.back();
_completeRecorder();
} else {
_startRecording();
}
},
child: Container(
height: 48.w,

Loading…
Cancel
Save