From 4f1bf45684ace2b5ed5ac64491f4936ae98ea9b4 Mon Sep 17 00:00:00 2001 From: tanlongsheng <252620078@qq.com> Date: Wed, 26 Mar 2025 09:45:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9ai=E5=9B=9E=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ios/Podfile | 2 +- ios/Podfile.lock | 236 ++++++++++++++++-- lib/data/services/ai_service.dart | 8 + lib/data/services/kouzi_ai_service.dart | 4 +- lib/data/services/volcano_ai_service.dart | 34 +-- .../chat/controllers/chat_controller.dart | 6 +- pubspec.yaml | 2 +- 7 files changed, 258 insertions(+), 34 deletions(-) create mode 100644 lib/data/services/ai_service.dart diff --git a/ios/Podfile b/ios/Podfile index 1a255e840..c10c27d8b 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '12.0' +platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/ios/Podfile.lock b/ios/Podfile.lock index aa4aa611a..33793d61b 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,47 +1,183 @@ PODS: + - app_settings (5.1.1): + - Flutter + - AppAuth (1.7.6): + - AppAuth/Core (= 1.7.6) + - AppAuth/ExternalUserAgent (= 1.7.6) + - AppAuth/Core (1.7.6) + - AppAuth/ExternalUserAgent (1.7.6): + - AppAuth/Core - audio_session (0.0.1): - Flutter - audio_waveforms (0.0.1): - Flutter - device_info_plus (0.0.1): - Flutter + - FBAEMKit (17.1.0): + - FBSDKCoreKit_Basics (= 17.1.0) + - FBSDKCoreKit (17.1.0): + - FBAEMKit (= 17.1.0) + - FBSDKCoreKit_Basics (= 17.1.0) + - FBSDKCoreKit_Basics (17.1.0) + - FBSDKLoginKit (17.1.0): + - FBSDKCoreKit (= 17.1.0) + - Firebase/Auth (11.8.0): + - Firebase/CoreOnly + - FirebaseAuth (~> 11.8.0) + - Firebase/CoreOnly (11.8.0): + - FirebaseCore (~> 11.8.0) + - firebase_auth (5.5.1): + - Firebase/Auth (= 11.8.0) + - firebase_core + - Flutter + - firebase_core (3.12.1): + - Firebase/CoreOnly (= 11.8.0) + - Flutter + - FirebaseAppCheckInterop (11.10.0) + - FirebaseAuth (11.8.1): + - FirebaseAppCheckInterop (~> 11.0) + - FirebaseAuthInterop (~> 11.0) + - FirebaseCore (~> 11.8.0) + - FirebaseCoreExtension (~> 11.8.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.0) + - GoogleUtilities/Environment (~> 8.0) + - GTMSessionFetcher/Core (< 5.0, >= 3.4) + - RecaptchaInterop (~> 100.0) + - FirebaseAuthInterop (11.10.0) + - FirebaseCore (11.8.1): + - FirebaseCoreInternal (~> 11.8.0) + - GoogleUtilities/Environment (~> 8.0) + - GoogleUtilities/Logger (~> 8.0) + - FirebaseCoreExtension (11.8.0): + - FirebaseCore (~> 11.8.0) + - FirebaseCoreInternal (11.8.0): + - "GoogleUtilities/NSData+zlib (~> 8.0)" - Flutter (1.0.0) - flutter_blue_plus_darwin (0.0.2): - Flutter - FlutterMacOS + - flutter_facebook_auth (7.1.1): + - FBSDKLoginKit (~> 17.1.0) + - Flutter + - flutter_image_compress_common (1.0.0): + - Flutter + - Mantle + - SDWebImage + - SDWebImageWebPCoder - flutter_local_notifications (0.0.1): - Flutter + - flutter_secure_storage (6.0.0): + - Flutter - flutter_tts (0.0.1): - Flutter + - fluwx (0.0.1): + - Flutter + - fluwx/pay (= 0.0.1) + - fluwx/pay (0.0.1): + - Flutter + - WechatOpenSDK-XCFramework (~> 2.0.4) + - google_sign_in_ios (0.0.1): + - AppAuth (>= 1.7.4) + - Flutter + - FlutterMacOS + - GoogleSignIn (~> 7.1) + - GTMSessionFetcher (>= 3.4.0) + - GoogleSignIn (7.1.0): + - AppAuth (< 2.0, >= 1.7.3) + - GTMAppAuth (< 5.0, >= 4.1.1) + - GTMSessionFetcher/Core (~> 3.3) + - GoogleUtilities/AppDelegateSwizzler (8.0.2): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Privacy + - GoogleUtilities/Environment (8.0.2): + - GoogleUtilities/Privacy + - GoogleUtilities/Logger (8.0.2): + - GoogleUtilities/Environment + - GoogleUtilities/Privacy + - GoogleUtilities/Network (8.0.2): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Privacy + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (8.0.2)": + - GoogleUtilities/Privacy + - GoogleUtilities/Privacy (8.0.2) + - GoogleUtilities/Reachability (8.0.2): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy + - GTMAppAuth (4.1.1): + - AppAuth/Core (~> 1.7) + - GTMSessionFetcher/Core (< 4.0, >= 3.3) + - GTMSessionFetcher (3.5.0): + - GTMSessionFetcher/Full (= 3.5.0) + - GTMSessionFetcher/Core (3.5.0) + - GTMSessionFetcher/Full (3.5.0): + - GTMSessionFetcher/Core - image_picker_ios (0.0.1): - Flutter - just_audio (0.0.1): - Flutter - FlutterMacOS + - libwebp (1.5.0): + - libwebp/demux (= 1.5.0) + - libwebp/mux (= 1.5.0) + - libwebp/sharpyuv (= 1.5.0) + - libwebp/webp (= 1.5.0) + - libwebp/demux (1.5.0): + - libwebp/webp + - libwebp/mux (1.5.0): + - libwebp/demux + - libwebp/sharpyuv (1.5.0) + - libwebp/webp (1.5.0): + - libwebp/sharpyuv + - Mantle (2.2.0): + - Mantle/extobjc (= 2.2.0) + - Mantle/extobjc (2.2.0) - MicrosoftCognitiveServicesSpeech-iOS (1.34.0) - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS - permission_handler_apple (9.3.0): - Flutter + - RecaptchaInterop (100.0.0) - record_darwin (1.0.0): - Flutter + - SDWebImage (5.21.0): + - SDWebImage/Core (= 5.21.0) + - SDWebImage/Core (5.21.0) + - SDWebImageWebPCoder (0.14.6): + - libwebp (~> 1.0) + - SDWebImage/Core (~> 5.17) - share_plus (0.0.1): - Flutter - speech_to_text (0.0.1): - Flutter - FlutterMacOS - Try + - sqflite_darwin (0.0.4): + - Flutter + - FlutterMacOS - Try (2.1.1) + - WechatOpenSDK-XCFramework (2.0.4) DEPENDENCIES: + - app_settings (from `.symlinks/plugins/app_settings/ios`) - audio_session (from `.symlinks/plugins/audio_session/ios`) - audio_waveforms (from `.symlinks/plugins/audio_waveforms/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) + - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) + - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - Flutter (from `Flutter`) - flutter_blue_plus_darwin (from `.symlinks/plugins/flutter_blue_plus_darwin/darwin`) + - flutter_facebook_auth (from `.symlinks/plugins/flutter_facebook_auth/ios`) + - flutter_image_compress_common (from `.symlinks/plugins/flutter_image_compress_common/ios`) - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) + - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - flutter_tts (from `.symlinks/plugins/flutter_tts/ios`) + - fluwx (from `.symlinks/plugins/fluwx/ios`) + - google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/darwin`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - just_audio (from `.symlinks/plugins/just_audio/darwin`) - MicrosoftCognitiveServicesSpeech-iOS (~> 1.34.0) @@ -50,27 +186,66 @@ DEPENDENCIES: - record_darwin (from `.symlinks/plugins/record_darwin/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - speech_to_text (from `.symlinks/plugins/speech_to_text/darwin`) + - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) SPEC REPOS: trunk: + - AppAuth + - FBAEMKit + - FBSDKCoreKit + - FBSDKCoreKit_Basics + - FBSDKLoginKit + - Firebase + - FirebaseAppCheckInterop + - FirebaseAuth + - FirebaseAuthInterop + - FirebaseCore + - FirebaseCoreExtension + - FirebaseCoreInternal + - GoogleSignIn + - GoogleUtilities + - GTMAppAuth + - GTMSessionFetcher + - libwebp + - Mantle - MicrosoftCognitiveServicesSpeech-iOS + - RecaptchaInterop + - SDWebImage + - SDWebImageWebPCoder - Try + - WechatOpenSDK-XCFramework EXTERNAL SOURCES: + app_settings: + :path: ".symlinks/plugins/app_settings/ios" audio_session: :path: ".symlinks/plugins/audio_session/ios" audio_waveforms: :path: ".symlinks/plugins/audio_waveforms/ios" device_info_plus: :path: ".symlinks/plugins/device_info_plus/ios" + firebase_auth: + :path: ".symlinks/plugins/firebase_auth/ios" + firebase_core: + :path: ".symlinks/plugins/firebase_core/ios" Flutter: :path: Flutter flutter_blue_plus_darwin: :path: ".symlinks/plugins/flutter_blue_plus_darwin/darwin" + flutter_facebook_auth: + :path: ".symlinks/plugins/flutter_facebook_auth/ios" + flutter_image_compress_common: + :path: ".symlinks/plugins/flutter_image_compress_common/ios" flutter_local_notifications: :path: ".symlinks/plugins/flutter_local_notifications/ios" + flutter_secure_storage: + :path: ".symlinks/plugins/flutter_secure_storage/ios" flutter_tts: :path: ".symlinks/plugins/flutter_tts/ios" + fluwx: + :path: ".symlinks/plugins/fluwx/ios" + google_sign_in_ios: + :path: ".symlinks/plugins/google_sign_in_ios/darwin" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" just_audio: @@ -85,25 +260,58 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/share_plus/ios" speech_to_text: :path: ".symlinks/plugins/speech_to_text/darwin" + sqflite_darwin: + :path: ".symlinks/plugins/sqflite_darwin/darwin" SPEC CHECKSUMS: - audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0 - audio_waveforms: a6dde7fe7c0ea05f06ffbdb0f7c1b2b2ba6cedcf - device_info_plus: 71ffc6ab7634ade6267c7a93088ed7e4f74e5896 + app_settings: 58017cd26b604ae98c3e65acbdd8ba173703cc82 + AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73 + audio_session: 19e9480dbdd4e5f6c4543826b2e8b0e4ab6145fe + audio_waveforms: cd736909ebc6b6a164eb74701d8c705ce3241e1c + device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d + FBAEMKit: cb719c53575a3be86ea873279f30d6a2c4e15881 + FBSDKCoreKit: ecdb980a24633ccb012700299ceb16d0235e14d2 + FBSDKCoreKit_Basics: 045101c4a9ef10c845347424d73a29aae02c3e43 + FBSDKLoginKit: 69eb59b2f839aba635616df6e422acd0ca88030a + Firebase: d80354ed7f6df5f9aca55e9eb47cc4b634735eaf + firebase_auth: 3d848b9b866b201e5c8e0c06d8b2cec272fd8825 + firebase_core: ac395f994af4e28f6a38b59e05a88ca57abeb874 + FirebaseAppCheckInterop: 9664c858489710f682766ef54e2b6741d3b62070 + FirebaseAuth: ad59a1a7b161e75f74c39f70179d2482d40e2737 + FirebaseAuthInterop: 01a804fb074424fd58b92dd50dd0272277199356 + FirebaseCore: 99fe0c4b44a39f37d99e6404e02009d2db5d718d + FirebaseCoreExtension: 3d3f2017a00d06e09ab4ebe065391b0bb642565e + FirebaseCoreInternal: df24ce5af28864660ecbd13596fc8dd3a8c34629 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_blue_plus_darwin: 09444a26fb6bdef523e55b68fc1c59af5a877ea6 - flutter_local_notifications: 395056b3175ba4f08480a7c5de30cd36d69827e4 - flutter_tts: b88dbc8655d3dc961bc4a796e4e16a4cc1795833 - image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a - just_audio: 4e391f57b79cad2b0674030a00453ca5ce817eed + flutter_blue_plus_darwin: 3ea4ec9133b377febcc8a70b28cd2d2dc9242bd9 + flutter_facebook_auth: 48be46091bd1a5cc5a66055f1228a9d99a28bfaa + flutter_image_compress_common: ec1d45c362c9d30a3f6a0426c297f47c52007e3e + flutter_local_notifications: df98d66e515e1ca797af436137b4459b160ad8c9 + flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12 + flutter_tts: 0f492aab6accf87059b72354fcb4ba934304771d + fluwx: daa284756ce53442b3d0417ceeda66e981906811 + google_sign_in_ios: 4111e87aa5e24a4404f00ea13479f35e571969cc + GoogleSignIn: d4281ab6cf21542b1cfaff85c191f230b399d2db + GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d + GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de + GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6 + image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 + just_audio: a42c63806f16995daf5b219ae1d679deb76e6a79 + libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8 + Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d MicrosoftCognitiveServicesSpeech-iOS: 723eccb3e459bbb530df3d9bfe84a291074b09eb - path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 - permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d - record_darwin: fb1f375f1d9603714f55b8708a903bbb91ffdb0a - share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a - speech_to_text: 9dc43a5df3cbc2813f8c7cc9bd0fbf94268ed7ac + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 + RecaptchaInterop: 7d1a4a01a6b2cb1610a47ef3f85f0c411434cb21 + record_darwin: 3b1a8e7d5c0cbf45ad6165b4d83a6ca643d929c3 + SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868 + SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 + share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f + speech_to_text: 627d3fd2194770b51abb324ba45c2d39398f24a8 + sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d Try: 5ef669ae832617b3cee58cb2c6f99fb767a4ff96 + WechatOpenSDK-XCFramework: 36fb2bea0754266c17184adf4963d7e6ff98b69f -PODFILE CHECKSUM: f35c1d63b4b8ce9c2eb88107f162ac59923c4839 +PODFILE CHECKSUM: 4f26889ae572e1722a139b651939749d40c71469 COCOAPODS: 1.16.2 diff --git a/lib/data/services/ai_service.dart b/lib/data/services/ai_service.dart new file mode 100644 index 000000000..91ab6fe7d --- /dev/null +++ b/lib/data/services/ai_service.dart @@ -0,0 +1,8 @@ +/// AI回复服务接口 +abstract class AiService { + /// 流式输出方法 + Stream sendMessageStream({ + required List> messages, + required String systemPrompt, + }); +} diff --git a/lib/data/services/kouzi_ai_service.dart b/lib/data/services/kouzi_ai_service.dart index 5162b5d32..b2496c42d 100644 --- a/lib/data/services/kouzi_ai_service.dart +++ b/lib/data/services/kouzi_ai_service.dart @@ -3,12 +3,14 @@ import 'dart:convert'; import 'package:http/http.dart' as http; import '../../core/utils/logger.dart'; +import 'ai_service.dart'; -class KouziAIService { +class KouziAIService implements AiService { final String apiKey = 'pat_QGDh6UGm3PaeL9GRS95JxrJ9aoU92ehMLQQ2NCre1TeBC5YeTcjpDmlz3efsJ8lh'; final String modelId = '7481292724306657316'; + @override Stream sendMessageStream({ required List> messages, required String systemPrompt, diff --git a/lib/data/services/volcano_ai_service.dart b/lib/data/services/volcano_ai_service.dart index f7e95ee03..576721642 100644 --- a/lib/data/services/volcano_ai_service.dart +++ b/lib/data/services/volcano_ai_service.dart @@ -2,7 +2,9 @@ import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:flutter_dotenv/flutter_dotenv.dart'; -class VolcanoAIService { +import 'ai_service.dart'; + +class VolcanoAIService implements AiService { final String apiKey; static const String _baseUrl = 'https://ark.cn-beijing.volces.com/api/v3'; static const String _chatEndpoint = '/chat/completions'; @@ -35,7 +37,7 @@ class VolcanoAIService { required String systemPrompt, }) async { final url = Uri.parse('$_baseUrl$_chatEndpoint'); - + final fullMessages = [ {'role': 'system', 'content': systemPrompt}, ...messages, @@ -59,8 +61,8 @@ class VolcanoAIService { if (response.statusCode == 200) { final data = json.decode(response.body); - if (data['choices'] != null && - data['choices'].isNotEmpty && + if (data['choices'] != null && + data['choices'].isNotEmpty && data['choices'][0]['message'] != null) { return data['choices'][0]['message']['content']; } @@ -78,12 +80,13 @@ class VolcanoAIService { } // 流式输出方法 + @override Stream sendMessageStream({ required List> messages, required String systemPrompt, }) async* { final url = Uri.parse('$_baseUrl$_chatEndpoint'); - + final fullMessages = [ {'role': 'system', 'content': systemPrompt}, ...messages, @@ -96,7 +99,7 @@ class VolcanoAIService { 'Authorization': 'Bearer $apiKey', 'Accept': 'text/event-stream', }); - + request.body = json.encode({ 'model': 'doubao-1-5-lite-32k-250115', 'messages': fullMessages, @@ -109,21 +112,22 @@ class VolcanoAIService { if (response.statusCode != 200) { final error = await response.stream.bytesToString(); - throw VolcanoAIException( - json.decode(error)['error']?['message'] ?? 'Unknown error occurred' - ); + throw VolcanoAIException(json.decode(error)['error']?['message'] ?? + 'Unknown error occurred'); } - await for (final chunk in response.stream.transform(utf8.decoder).transform(const LineSplitter())) { + await for (final chunk in response.stream + .transform(utf8.decoder) + .transform(const LineSplitter())) { if (chunk.isEmpty) continue; if (chunk.startsWith('data: ')) { final data = chunk.substring(6); if (data == '[DONE]') break; - + try { final jsonData = json.decode(data); - if (jsonData['choices'] != null && - jsonData['choices'].isNotEmpty && + if (jsonData['choices'] != null && + jsonData['choices'].isNotEmpty && jsonData['choices'][0]['delta'] != null && jsonData['choices'][0]['delta']['content'] != null) { yield jsonData['choices'][0]['delta']['content'] as String; @@ -144,7 +148,7 @@ class VolcanoAIService { class VolcanoAIException implements Exception { final String message; VolcanoAIException(this.message); - + @override String toString() => message; -} \ No newline at end of file +} diff --git a/lib/modules/chat/controllers/chat_controller.dart b/lib/modules/chat/controllers/chat_controller.dart index daa8f3eb9..cf9b07641 100644 --- a/lib/modules/chat/controllers/chat_controller.dart +++ b/lib/modules/chat/controllers/chat_controller.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:get/get.dart'; import 'package:flutter/widgets.dart'; import 'package:get_storage/get_storage.dart'; +import '../../../data/services/ai_service.dart'; import '../../../data/services/kouzi_ai_service.dart'; import '../../../data/services/speech_impl/voice_clone_tts_service.dart'; import '../models/message_model.dart'; @@ -17,7 +18,7 @@ import '../../../data/services/voice_interaction_service.dart'; class ChatController extends GetxController { // 服务 - late final _aiService; + late AiService _aiService; late TtsService _ttsService; final AsrService _asrService = Get.find(); final ChatHistoryService _historyService = Get.find(); @@ -90,6 +91,7 @@ class ChatController extends GetxController { agent = foundAgent; + // 亲子陪伴 if (agent.id != 'cyber_girlfriend') { _aiService = Get.find(); } else { @@ -97,9 +99,9 @@ class ChatController extends GetxController { _aiService = Get.find(); } + // 使用克隆音色语音合成 final GetStorage storage = GetStorage(); String timbre = storage.read('timbre') ?? '1'; - if (timbre == '1') { _ttsService = Get.find(); } else { diff --git a/pubspec.yaml b/pubspec.yaml index c9ce59886..775552854 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -50,7 +50,7 @@ dependencies: speech_to_text: ^7.0.0 fluwx: ^5.4.1 firebase_core: ^3.12.1 - firebase_auth: ^5.5.0 + firebase_auth: ^5.5.1 google_sign_in: ^6.2.2 flutter_facebook_auth: ^7.1.1 common_utils: ^2.1.0