Browse Source

上传配置相关逻辑

weicu
liwei1dao 1 year ago
parent
commit
0258fbafa8
  1. 28
      lib/data/models/appconfig.dart
  2. 30
      lib/data/services/ble_manager.dart
  3. 9
      lib/data/services/open_ai_service_adapter.dart
  4. 36
      lib/data/services/speech_impl/azure_asr_service.dart
  5. 20
      lib/data/services/speech_impl/azure_tts_service.dart
  6. 9
      lib/data/services/spotify_service.dart
  7. 14
      lib/data/services/volcano_translation_service.dart
  8. 8
      lib/modules/login/controllers/login_controller.dart
  9. 9
      lib/modules/splash/controllers/splash_controller.dart
  10. 2
      local_plugins/open_ai_service/android/src/main/kotlin/com/yunqiinnovation/open_ai_service/MCPClient.kt
  11. 4
      local_plugins/open_ai_service/android/src/main/kotlin/com/yunqiinnovation/open_ai_service/OpenAIService.kt

28
lib/data/models/appconfig.dart

@ -0,0 +1,28 @@
import 'dart:convert';
import 'package:deep_voice/data/models/appconfig_model.dart';
class AppConfig {
static late UserGetAppConfigResp config;
// 可选:提供初始化方法
static void initialize(UserGetAppConfigResp resp) {
config = resp;
}
//环境变量
static String? env(String key) {
return config.env[key];
}
//mcp配置
static dynamic mcpConfig() {
return {"mcpServers": config.mcps};
}
//智能体配置
static String agent(String agentId) {
final foundAgent = config.agents.firstWhere((agent) => agent.id == agentId);
return jsonEncode((foundAgent));
}
}

30
lib/data/services/ble_manager.dart

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:deep_voice/data/models/appconfig.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:ble_service/ble_service.dart'; import 'package:ble_service/ble_service.dart';
import 'package:deep_voice/core/utils/logger.dart'; import 'package:deep_voice/core/utils/logger.dart';
@ -383,17 +384,28 @@ class BleManager extends GetxService {
Future<bool> startBleService() async { Future<bool> startBleService() async {
try { try {
// 从.env文件直接读取环境变量 // 从.env文件直接读取环境变量
final azureSpeechKey = dotenv.env['AZURE_SPEECH_KEY'] ?? ''; // final azureSpeechKey = dotenv.env['AZURE_SPEECH_KEY'] ?? '';
final azureSpeechRegion = dotenv.env['AZURE_SPEECH_REGION'] ?? 'eastasia'; // final azureSpeechRegion = dotenv.env['AZURE_SPEECH_REGION'] ?? 'eastasia';
final openaiApiKey = dotenv.env['OPENAI_API_KEY'] ?? ''; // final openaiApiKey = dotenv.env['OPENAI_API_KEY'] ?? '';
// final openaiBaseUrl =
// dotenv.env['OPENAI_BASE_URL'] ?? 'https://api.openai.com/v1';
// final openaiModel = dotenv.env['OPENAI_MODEL'] ?? 'gpt-3.5-turbo';
// 从Flutter资源包中加载.mcp.json
// final mcpConfig = await rootBundle.loadString('.mcp.json');
// 验证JSON格式
// final jsonData = jsonDecode(mcpConfig);
final azureSpeechKey = AppConfig.env('AZURE_SPEECH_KEY') ?? '';
final azureSpeechRegion =
AppConfig.env('AZURE_SPEECH_REGION') ?? 'eastasia';
final openaiApiKey = AppConfig.env('OPENAI_API_KEY') ?? '';
final openaiBaseUrl = final openaiBaseUrl =
dotenv.env['OPENAI_BASE_URL'] ?? 'https://api.openai.com/v1'; AppConfig.env('OPENAI_BASE_URL') ?? 'https://api.openai.com/v1';
final openaiModel = dotenv.env['OPENAI_MODEL'] ?? 'gpt-3.5-turbo'; final openaiModel = AppConfig.env('OPENAI_MODEL') ?? 'gpt-3.5-turbo';
// 从Flutter资源包中加载.mcp.json // 从Flutter资源包中加载.mcp.json
final mcpConfig = await rootBundle.loadString('.mcp.json'); final jsonData = AppConfig.mcpConfig();
// 验证JSON格式
final jsonData = jsonDecode(mcpConfig);
final config = <String, dynamic>{ final config = <String, dynamic>{
// 语音代理配置参数 // 语音代理配置参数
'azureSpeechKey': azureSpeechKey, 'azureSpeechKey': azureSpeechKey,

9
lib/data/services/open_ai_service_adapter.dart

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:convert'; import 'dart:convert';
import 'package:deep_voice/data/models/appconfig.dart';
import 'package:deep_voice/data/models/appconfig_model.dart'; import 'package:deep_voice/data/models/appconfig_model.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:get_storage/get_storage.dart'; import 'package:get_storage/get_storage.dart';
@ -103,10 +104,10 @@ class OpenAIServiceAdapter implements AiService {
// final apiKey = dotenv.env['OPENAI_API_KEY'] ?? ''; // final apiKey = dotenv.env['OPENAI_API_KEY'] ?? '';
// final baseUrl = dotenv.env['OPENAI_BASE_URL'] ?? ''; // final baseUrl = dotenv.env['OPENAI_BASE_URL'] ?? '';
// final model = dotenv.env['OPENAI_MODEL'] ?? ''; // final model = dotenv.env['OPENAI_MODEL'] ?? '';
final _env = _storage.read("ENV") as Map<String, String>; // final _env = _storage.read("ENV") as Map<String, String>;
final apiKey = _env['OPENAI_API_KEY'] ?? ''; final apiKey = AppConfig.env('OPENAI_API_KEY') ?? '';
final baseUrl = _env['OPENAI_BASE_URL'] ?? ''; final baseUrl = AppConfig.env('OPENAI_BASE_URL') ?? '';
final model = _env['OPENAI_MODEL'] ?? ''; final model = AppConfig.env('OPENAI_MODEL') ?? '';
printInfo(info: '从.env读取OpenAI配置'); printInfo(info: '从.env读取OpenAI配置');
printInfo(info: '基础URL: $baseUrl'); printInfo(info: '基础URL: $baseUrl');

36
lib/data/services/speech_impl/azure_asr_service.dart

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:deep_voice/data/models/appconfig.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:get_storage/get_storage.dart'; import 'package:get_storage/get_storage.dart';
import '../../../core/utils/logger.dart'; import '../../../core/utils/logger.dart';
@ -20,7 +21,7 @@ class AzureAsrService extends GetxService implements AsrService {
static const MethodChannel _channel = MethodChannel('azure_speech/asr'); static const MethodChannel _channel = MethodChannel('azure_speech/asr');
static const EventChannel _eventChannel = static const EventChannel _eventChannel =
EventChannel('azure_speech/asr_events'); EventChannel('azure_speech/asr_events');
final GetStorage _storage = GetStorage(); // final GetStorage _storage = GetStorage();
bool _isInitialized = false; bool _isInitialized = false;
late final String _subscriptionKey; late final String _subscriptionKey;
late final String _serviceRegion; late final String _serviceRegion;
@ -51,9 +52,9 @@ class AzureAsrService extends GetxService implements AsrService {
/// 从环境变量加载配置 /// 从环境变量加载配置
void _loadConfig() { void _loadConfig() {
final _env = _storage.read("ENV") as Map<String, String>; // final _env = _storage.read("ENV") as Map<String, String>;
_subscriptionKey = _env['AZURE_SPEECH_KEY'] ?? ''; _subscriptionKey = AppConfig.env('AZURE_SPEECH_KEY') ?? '';
_serviceRegion = _env['AZURE_SPEECH_REGION'] ?? ''; _serviceRegion = AppConfig.env('AZURE_SPEECH_REGION') ?? '';
if (_subscriptionKey.isEmpty || _serviceRegion.isEmpty) { if (_subscriptionKey.isEmpty || _serviceRegion.isEmpty) {
throw Exception( throw Exception(
@ -312,4 +313,31 @@ class AzureAsrService extends GetxService implements AsrService {
_isInitialized = false; _isInitialized = false;
} }
} }
@override
Future<bool> pushAudioData(Uint8List data) async {
if (!_isInitialized) {
await initialize(useExternalAudio: true);
}
if (_audioSourceType != AudioSourceType.external) {
Logger.error('当前非外部音频模式,不能推送音频数据');
return false;
}
try {
final bool result = await _channel.invokeMethod('pushAudioData', {
'audioData': data // Flutter 会自动将 Uint8List 转换为 ByteBuffer
});
if (!result) {
throw Exception('推送音频数据失败');
}
return true;
} catch (e) {
Logger.error('推送音频数据失败: $e');
return false;
}
}
} }

20
lib/data/services/speech_impl/azure_tts_service.dart

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:deep_voice/data/models/appconfig.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart'; import 'package:get_storage/get_storage.dart';
@ -13,9 +14,10 @@ import '../tts_service.dart';
class AzureTtsService extends GetxService implements TtsService { class AzureTtsService extends GetxService implements TtsService {
static final AzureTtsService to = Get.put(AzureTtsService()); static final AzureTtsService to = Get.put(AzureTtsService());
static const MethodChannel _channel = MethodChannel('azure_speech/tts'); static const MethodChannel _channel = MethodChannel('azure_speech/tts');
static const EventChannel _eventChannel = EventChannel('azure_speech/tts_events'); static const EventChannel _eventChannel =
EventChannel('azure_speech/tts_events');
final GetStorage _storage = GetStorage(); // final GetStorage _storage = GetStorage();
bool _isInitialized = false; bool _isInitialized = false;
late final String _subscriptionKey; late final String _subscriptionKey;
late final String _serviceRegion; late final String _serviceRegion;
@ -28,7 +30,8 @@ class AzureTtsService extends GetxService implements TtsService {
bool _isProcessingQueue = false; bool _isProcessingQueue = false;
// 事件流 // 事件流
final StreamController<TtsEvent> _eventStreamController = StreamController<TtsEvent>.broadcast(); final StreamController<TtsEvent> _eventStreamController =
StreamController<TtsEvent>.broadcast();
StreamSubscription? _eventSubscription; StreamSubscription? _eventSubscription;
// 可观察状态 // 可观察状态
@ -53,9 +56,9 @@ class AzureTtsService extends GetxService implements TtsService {
/// 从环境变量加载配置 /// 从环境变量加载配置
void _loadConfig() { void _loadConfig() {
final _env = _storage.read("ENV") as Map<String, String>; // final _env = _storage.read("ENV") as Map<String, String>;
_subscriptionKey = _env['AZURE_SPEECH_KEY'] ?? ''; _subscriptionKey = AppConfig.env('AZURE_SPEECH_KEY') ?? '';
_serviceRegion = _env['AZURE_SPEECH_REGION'] ?? ''; _serviceRegion = AppConfig.env('AZURE_SPEECH_REGION') ?? '';
} }
/// 设置事件通道 /// 设置事件通道
@ -281,7 +284,10 @@ class AzureTtsService extends GetxService implements TtsService {
// 监听事件流检查队列是否完成 // 监听事件流检查队列是否完成
final subscription = onEvent.listen((event) { final subscription = onEvent.listen((event) {
// 当队列为空且不在处理中,且当前非说话状态,完成操作 // 当队列为空且不在处理中,且当前非说话状态,完成操作
if (_textQueue.isEmpty && !_isProcessingQueue && !_isSpeaking.value && !completer.isCompleted) { if (_textQueue.isEmpty &&
!_isProcessingQueue &&
!_isSpeaking.value &&
!completer.isCompleted) {
completer.complete(true); completer.complete(true);
} }
}); });

9
lib/data/services/spotify_service.dart

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:convert'; import 'dart:convert';
import 'package:deep_voice/data/models/appconfig.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:get_storage/get_storage.dart'; import 'package:get_storage/get_storage.dart';
import 'package:spotify_sdk/spotify_sdk.dart'; import 'package:spotify_sdk/spotify_sdk.dart';
@ -12,7 +13,7 @@ import 'package:path_provider/path_provider.dart';
/// OpenAI服务适配器 - 连接AiService接口与OpenAIService插件 /// OpenAI服务适配器 - 连接AiService接口与OpenAIService插件
class SpotifService { class SpotifService {
bool isInitialized = false; bool isInitialized = false;
final GetStorage _storage = GetStorage(); // final GetStorage _storage = GetStorage();
late String SPOTIFY_CLIENT_ID; late String SPOTIFY_CLIENT_ID;
late String SPOTIFY_REDIRECT_URL; late String SPOTIFY_REDIRECT_URL;
@ -20,9 +21,9 @@ class SpotifService {
/// 初始化OpenAI服务 /// 初始化OpenAI服务
Future<bool> initialize() async { Future<bool> initialize() async {
if (!isInitialized) { if (!isInitialized) {
final _env = _storage.read("ENV") as Map<String, String>; // final _env = _storage.read("ENV") as Map<String, String>;
SPOTIFY_CLIENT_ID = _env['SPOTIFY_CLIENT_ID'] ?? ''; SPOTIFY_CLIENT_ID = AppConfig.env('SPOTIFY_CLIENT_ID') ?? '';
SPOTIFY_REDIRECT_URL = _env['SPOTIFY_REDIRECT_URL'] ?? ''; SPOTIFY_REDIRECT_URL = AppConfig.env('SPOTIFY_REDIRECT_URL') ?? '';
printInfo( printInfo(
info: info:
"SpotifService----------- initialize SPOTIFY_CLIENT_ID:${SPOTIFY_CLIENT_ID} SPOTIFY_REDIRECT_URL:${SPOTIFY_REDIRECT_URL}"); "SpotifService----------- initialize SPOTIFY_CLIENT_ID:${SPOTIFY_CLIENT_ID} SPOTIFY_REDIRECT_URL:${SPOTIFY_REDIRECT_URL}");

14
lib/data/services/volcano_translation_service.dart

@ -1,5 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:math'; import 'dart:math';
import 'package:deep_voice/data/models/appconfig.dart';
import 'package:get_storage/get_storage.dart'; import 'package:get_storage/get_storage.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
@ -22,7 +23,7 @@ class VolcanoTranslationService extends GetxService {
// 语言管理器 // 语言管理器
final LanguageManager _languageManager = Get.find<LanguageManager>(); final LanguageManager _languageManager = Get.find<LanguageManager>();
final GetStorage _storage = GetStorage(); // final GetStorage _storage = GetStorage();
// 构造函数 // 构造函数
VolcanoTranslationService(); VolcanoTranslationService();
@ -33,10 +34,13 @@ class VolcanoTranslationService extends GetxService {
String? region, String? region,
}) async { }) async {
try { try {
final _env = _storage.read("ENV") as Map<String, String>; // final _env = _storage.read("ENV") as Map<String, String>;
_accessKey = accessKey ?? _env['VOLCANO_TRANSLATION_ACCESS_KEY'] ?? ''; _accessKey =
_secretKey = secretKey ?? _env['VOLCANO_TRANSLATION_SECRET_KEY'] ?? ''; accessKey ?? AppConfig.env('VOLCANO_TRANSLATION_ACCESS_KEY') ?? '';
_region = region ?? _env['VOLCANO_TRANSLATION_REGION'] ?? 'cn-north-1'; _secretKey =
secretKey ?? AppConfig.env('VOLCANO_TRANSLATION_SECRET_KEY') ?? '';
_region =
region ?? AppConfig.env('VOLCANO_TRANSLATION_REGION') ?? 'cn-north-1';
_service = 'translate'; _service = 'translate';
_baseUrl = 'https://translate.volcengineapi.com'; _baseUrl = 'https://translate.volcengineapi.com';

8
lib/modules/login/controllers/login_controller.dart

@ -1,3 +1,4 @@
import 'package:deep_voice/data/models/appconfig.dart';
import 'package:deep_voice/data/models/appconfig_model.dart'; import 'package:deep_voice/data/models/appconfig_model.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -739,9 +740,10 @@ class LoginController extends GetxController {
// 根据API设计调整 // 根据API设计调整
final resp = UserGetAppConfigResp.fromJson(response); final resp = UserGetAppConfigResp.fromJson(response);
// 存储用户信息(示例) // 存储用户信息(示例)
_storage.write('ENV', resp.env); // _storage.write('ENV', resp.env);
_storage.write('AGENTS', resp.agents); // _storage.write('AGENTS', resp.agents);
_storage.write('MCPS', resp.mcps); // _storage.write('MCPS', resp.mcps);
AppConfig.initialize(resp);
return true; return true;
} catch (e) { } catch (e) {
print('getAppConfig 取失败: $e'); print('getAppConfig 取失败: $e');

9
lib/modules/splash/controllers/splash_controller.dart

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:amap_flutter/amap_flutter.dart'; import 'package:amap_flutter/amap_flutter.dart';
import 'package:deep_voice/data/models/appconfig.dart';
import 'package:deep_voice/data/models/appconfig_model.dart'; import 'package:deep_voice/data/models/appconfig_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@ -132,10 +133,10 @@ class SplashController extends GetxController {
final resp = UserGetAppConfigResp.fromJson(response); final resp = UserGetAppConfigResp.fromJson(response);
print('getAppConfig:进来了'); print('getAppConfig:进来了');
// 存储用户信息(示例) // 存储用户信息(示例)
_storage.write('ENV', resp.env); // _storage.write('ENV', resp.env);
_storage.write('AGENTS', resp.agents); // _storage.write('AGENTS', resp.agents);
_storage.write('MCPS', resp.mcps); // _storage.write('MCPS', resp.mcps);
AppConfig.initialize(resp);
return true; return true;
} catch (e) { } catch (e) {
print('getAppConfig 取失败: $e'); print('getAppConfig 取失败: $e');

2
local_plugins/open_ai_service/android/src/main/kotlin/com/yunqiinnovation/open_ai_service/MCPClient.kt

@ -313,7 +313,7 @@ class MCPSubClient(
"function" to functionMap "function" to functionMap
)) ))
Log.d(TAG, "成功转换工具 ${tool.name()} 到OpenAI函数格式") Log.d(TAG, "成功转换工具 ${tool.name()} 到OpenAI函数格式 $functionMap")
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "转换工具 ${tool.name()} 失败: ${e.message}") Log.e(TAG, "转换工具 ${tool.name()} 失败: ${e.message}")
} }

4
local_plugins/open_ai_service/android/src/main/kotlin/com/yunqiinnovation/open_ai_service/OpenAIService.kt

@ -337,6 +337,8 @@ class OpenAIService(private val context: Context? = null) {
// 获取参数 // 获取参数
val argumentsJson = functionCall.getString("arguments") val argumentsJson = functionCall.getString("arguments")
Log.e(TAG, "自动处理MCP工具调用: name:${name} argumentsJson:${argumentsJson}")
val arguments = mcpClient?.parseJsonArguments(argumentsJson) ?: mapOf() val arguments = mcpClient?.parseJsonArguments(argumentsJson) ?: mapOf()
// 调用工具(统一通过MCPClient处理) // 调用工具(统一通过MCPClient处理)
@ -607,7 +609,7 @@ class OpenAIService(private val context: Context? = null) {
for (i in 0 until toolCalls.length()) { for (i in 0 until toolCalls.length()) {
val toolCall = toolCalls.getJSONObject(i) val toolCall = toolCalls.getJSONObject(i)
val index = toolCall.getInt("index") val index = toolCall.getInt("index")
Log.e(TAG, "解析道AI需要调用工具: $toolCall")
// 创建或获取现有的工具调用信息 // 创建或获取现有的工具调用信息
val toolCallInfo = finalToolCalls.getOrPut(index) { ToolCallInfo() } val toolCallInfo = finalToolCalls.getOrPut(index) { ToolCallInfo() }

Loading…
Cancel
Save