import 'dart:convert'; import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:get/get.dart'; import 'package:http/http.dart' as http; import 'package:just_audio/just_audio.dart'; import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart'; import '../../../core/utils/logger.dart'; import '../../../core/utils/upload_oss.dart'; import '../../../data/services/db/sqflite_api.dart'; class MeetingController extends GetxController { final ScrollController listController = ScrollController(); final AudioPlayer _audioPlayer = AudioPlayer(); // 是否还有更多数据 bool isGetMore = true; bool isLoading = false; int page = 1; int addQuantity = 0; TextEditingController titleController = TextEditingController(); // 录音标题 RxList dataList = [].obs; List dataListTask = []; bool isDisposed = false; final String _appid = '2316081933'; final String _token = 'mcJTh6OelBqU_L78lgGd77Nyrc_-5-En'; final String _cluster = 'volc_auc_meeting_flash'; final String _serviceUrl = 'https://openspeech.bytedance.com/api/v1/auc'; Map _headers = {}; @override void onInit() { super.onInit(); listController.addListener(_onScroll); Permission.storage.request(); _headers = { 'Authorization': 'Bearer; $_token', 'Content-Type': 'application/json', }; _getDataList(); } @override void onClose() { listController.dispose(); titleController.dispose(); _audioPlayer.dispose(); isDisposed = true; super.onClose(); } void _onScroll() { if (isGetMore && !isLoading && listController.position.pixels >= listController.position.maxScrollExtent - 100) { isLoading = true; page++; _getDataList(); } } // 请求本地数据 void _getDataList() async { List list = await SqfliteApi.getMeetingList((page - 1) * 10 + addQuantity); dataList.addAll(list); queryDataListTask(list); addQuantity = 0; if (list.length < 10) { isGetMore = false; } else { isGetMore = true; } isLoading = false; } void addAudio() async { EasyLoading.show(); FilePickerResult? result = await FilePicker.platform.pickFiles( withData: true, ); if (result != null) { PlatformFile file = result.files.first; String filePath = await _saveFile(file); String fileName = file.name; await _audioPlayer.setAudioSource(AudioSource.file(filePath)); var audiourl = await UploadOss.upload(filepath: filePath, rootDir: 'audio'); int seconds = _audioPlayer.duration?.inSeconds ?? 0; int creationTime = DateTime.now().millisecondsSinceEpoch; Map data = { 'title': fileName, 'type': 'IMPORT', 'seconds': seconds, 'filepath': filePath, 'audiourl': audiourl, 'tasktype': 0, 'creationtime': creationTime, }; final meetingId = await SqfliteApi.insertMeeting(data); if (meetingId != null) { dataList.insert(0, { 'id': meetingId, 'taskid': '', ...data, }); addQuantity++; } } EasyLoading.dismiss(); } Future _saveFile(PlatformFile file) async { final directory = await getApplicationDocumentsDirectory(); final String filePath = '${directory.path}/${file.name}'; final File localFile = File(filePath); await localFile.writeAsBytes(file.bytes!); return filePath; } // 修改标题 void editMeetingTitle(int id, String title) async { if (title.isNotEmpty) { SqfliteApi.editMeetingTitle(id, {'title': title}); int index = dataList.indexWhere((item) => item['id'] == id); if (index != -1) { final dataMap = Map.from(dataList[index]); dataMap['title'] = title; dataList[index] = dataMap; } } Get.back(); } // 删除数据 void deleteMeeting(int id, String filepath) async { dataList.removeWhere((item) => item['id'] == id); // 删除数据库中的记录 SqfliteApi.deleteMeeting(id); _deleteFile(filepath); addQuantity--; } // 删除文件 Future _deleteFile(String filepath) async { File file = File(filepath); bool fileExists = await file.exists(); if (fileExists) { await file.delete(); } } // 查询转写状态 void queryDataListTask(List list, {bool isAdd = true}) { for (var element in List.from(list)) { if (element['tasktype'] == 1) { if (isAdd) { dataListTask.add(element); } final taskId = element['taskid']; _fileRecognize(element['id'], taskId); } } } Future _fileRecognize(int id, String taskId) async { try { final startTime = DateTime.now().millisecondsSinceEpoch; if (isDisposed) return; var respDic = await _queryTask(taskId); var code = respDic['resp']['code'] as int; if (code == 1000) { await SqfliteApi.editMeetingTitle(id, {'tasktype': 2}); int index = dataList.indexWhere((item) => item['id'] == id); if (index != -1) { final dataMap = Map.from(dataList[index]); dataMap['tasktype'] = 2; dataList[index] = dataMap; int taskIndex = dataListTask.indexWhere((item) => item['id'] == id); if (taskIndex != -1) { dataListTask.removeAt(taskIndex); } } return; } else if (code < 2000) { Logger.debug("FileRecognize failed"); return; } while (!isDisposed) { await Future.delayed(const Duration(seconds: 2)); if (isDisposed) return; respDic = await _queryTask(taskId); code = respDic['resp']['code'] as int; if (code == 1000) { await SqfliteApi.editMeetingTitle(id, {'tasktype': 2}); int index = dataList.indexWhere((item) => item['id'] == id); if (index != -1) { final dataMap = Map.from(dataList[index]); dataMap['tasktype'] = 2; dataList[index] = dataMap; int taskIndex = dataListTask.indexWhere((item) => item['id'] == id); if (taskIndex != -1) { dataListTask.removeAt(taskIndex); } } return; } else if (code < 2000) { Logger.debug("FileRecognize failed"); return; } final currentTime = DateTime.now().millisecondsSinceEpoch; if (currentTime - startTime > 300 * 1000) { Logger.debug('wait time exceeds 300s'); return; } } } catch (e) { Logger.error('Error occurred: ${e.toString()}'); } } Future> _queryTask(String taskId) async { final queryBody = jsonEncode({ "appid": _appid, "token": _token, "id": taskId, "cluster": _cluster, }); try { final response = await http.post( Uri.parse('$_serviceUrl/query'), headers: _headers, body: queryBody, ); if (response.statusCode != 200) { throw Exception('Query failed with status: ${response.statusCode}'); } final respDic = jsonDecode(response.body); return respDic; } catch (e) { Logger.error('Query error: ${e.toString()}'); rethrow; } } }