Browse Source

上传获取服务器的配置信息

newdev_shunjiawei
liwei1dao 1 year ago
parent
commit
acf7c56bbe
  1. 30
      lib/data/models/appconfig_model.dart
  2. 37
      lib/data/models/appconfig_model.g.dart
  3. 9
      lib/data/services/network/api.dart
  4. 45
      lib/data/services/open_ai_service_adapter.dart
  5. 44
      lib/data/services/speech_impl/azure_asr_service.dart
  6. 56
      lib/data/services/speech_impl/azure_tts_service.dart
  7. 80
      lib/data/services/voice_interaction_service.dart
  8. 24
      lib/modules/login/controllers/login_controller.dart
  9. 23
      lib/modules/splash/controllers/splash_controller.dart
  10. 2
      local_plugins/open_ai_service/android/build.gradle.kts
  11. 24
      local_plugins/open_ai_service/android/src/main/kotlin/com/yunqiinnovation/open_ai_service/MCPClient.kt
  12. 3
      pubspec.yaml

30
lib/data/models/appconfig_model.dart

@ -0,0 +1,30 @@
import 'package:json_annotation/json_annotation.dart';
part 'appconfig_model.g.dart'; // 生成的文件名
@JsonSerializable()
class UserGetAppConfigResp {
final Map<String, String> env;
final Map<String, DBMCPServer> mcps;
UserGetAppConfigResp({required this.env, required this.mcps});
factory UserGetAppConfigResp.fromJson(Map<String, dynamic> json) =>
_$UserGetAppConfigRespFromJson(json);
Map<String, dynamic> toJson() => _$UserGetAppConfigRespToJson(this);
}
@JsonSerializable()
class DBMCPServer {
final String servername;
final String url;
final List<String>? tools;
DBMCPServer({
required this.servername,
required this.url,
required this.tools,
});
factory DBMCPServer.fromJson(Map<String, dynamic> json) =>
_$DBMCPServerFromJson(json);
Map<String, dynamic> toJson() => _$DBMCPServerToJson(this);
}

37
lib/data/models/appconfig_model.g.dart

@ -0,0 +1,37 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'appconfig_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
UserGetAppConfigResp _$UserGetAppConfigRespFromJson(
Map<String, dynamic> json) =>
UserGetAppConfigResp(
env: Map<String, String>.from(json['env'] as Map),
mcps: (json['mcps'] as Map<String, dynamic>).map(
(k, e) => MapEntry(k, DBMCPServer.fromJson(e as Map<String, dynamic>)),
),
);
Map<String, dynamic> _$UserGetAppConfigRespToJson(
UserGetAppConfigResp instance) =>
<String, dynamic>{
'env': instance.env,
'mcps': instance.mcps,
};
DBMCPServer _$DBMCPServerFromJson(Map<String, dynamic> json) => DBMCPServer(
servername: json['servername'] as String,
url: json['url'] as String,
tools:
(json['tools'] as List<dynamic>?)?.map((e) => e as String).toList(),
);
Map<String, dynamic> _$DBMCPServerToJson(DBMCPServer instance) =>
<String, dynamic>{
'servername': instance.servername,
'url': instance.url,
'tools': instance.tools,
};

9
lib/data/services/network/api.dart

@ -64,4 +64,13 @@ class Api {
params: params,
);
}
//app配置
static getappconfig([params]) {
return DioManager().request(
NWMethod.post,
'/api/home/user_getappconfig',
params: params,
);
}
}

45
lib/data/services/open_ai_service_adapter.dart

@ -1,7 +1,9 @@
import 'dart:async';
import 'dart:io';
import 'dart:convert';
import 'package:deep_voice/data/models/appconfig_model.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:get_storage/get_storage.dart';
import 'package:open_ai_service/open_ai_service.dart';
import 'package:get/get.dart';
import 'ai_service.dart';
@ -26,6 +28,7 @@ class OpenAIServiceAdapter implements AiService {
StreamSubscription<OpenAIEvent>? _eventSubscription;
final StreamController<StreamEvent> _tokenStreamController =
StreamController<StreamEvent>.broadcast();
final GetStorage _storage = GetStorage();
/// 构造函数
OpenAIServiceAdapter() {
@ -97,9 +100,13 @@ class OpenAIServiceAdapter implements AiService {
Future<bool> initialize() async {
try {
// 从.env文件中读取配置
final apiKey = dotenv.env['OPENAI_API_KEY'] ?? '';
final baseUrl = dotenv.env['OPENAI_BASE_URL'] ?? '';
final model = dotenv.env['OPENAI_MODEL'] ?? '';
// final apiKey = dotenv.env['OPENAI_API_KEY'] ?? '';
// final baseUrl = dotenv.env['OPENAI_BASE_URL'] ?? '';
// final model = dotenv.env['OPENAI_MODEL'] ?? '';
final _env = _storage.read("ENV") as Map<String, String>;
final apiKey = _env['OPENAI_API_KEY'] ?? '';
final baseUrl = _env['OPENAI_BASE_URL'] ?? '';
final model = _env['OPENAI_MODEL'] ?? '';
printInfo(info: '从.env读取OpenAI配置');
printInfo(info: '基础URL: $baseUrl');
@ -109,24 +116,24 @@ class OpenAIServiceAdapter implements AiService {
printError(info: '错误: OpenAI API密钥未配置,请在.env文件中设置OPENAI_API_KEY');
return false;
}
final _mcps = _storage.read("MCPS") as Map<String, DBMCPServer>;
// 读取.mcp.json文件
String mcpConfig = '';
try {
// 从Flutter资源包中加载.mcp.json
mcpConfig = await rootBundle.loadString('.mcp.json');
printInfo(info: '成功从资源包加载.mcp.json配置文件');
String mcpConfig = jsonEncode(_mcps);
// try {
// // 从Flutter资源包中加载.mcp.json
// mcpConfig = await rootBundle.loadString('.mcp.json');
// printInfo(info: '成功从资源包加载.mcp.json配置文件');
// 验证JSON格式
final jsonData = jsonDecode(mcpConfig);
if (jsonData is Map && jsonData.containsKey('mcpServers')) {
printInfo(info: '解析到有效的mcpServers配置');
} else {
printInfo(info: '.mcp.json内容格式不正确,期望包含mcpServers字段');
}
} catch (e) {
printError(info: '加载.mcp.json资源文件时出错: $e');
}
// // 验证JSON格式
// final jsonData = jsonDecode(mcpConfig);
// if (jsonData is Map && jsonData.containsKey('mcpServers')) {
// printInfo(info: '解析到有效的mcpServers配置');
// } else {
// printInfo(info: '.mcp.json内容格式不正确,期望包含mcpServers字段');
// }
// } catch (e) {
// printError(info: '加载.mcp.json资源文件时出错: $e');
// }
// 初始化OpenAI服务
final result = await _openAIService.initialize(

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

@ -1,6 +1,7 @@
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:get_storage/get_storage.dart';
import '../../../core/utils/logger.dart';
import 'package:get/get.dart';
import '../asr_service.dart';
@ -11,8 +12,9 @@ import '../asr_service.dart';
class AzureAsrService extends GetxService implements AsrService {
static final AzureAsrService to = Get.put(AzureAsrService());
static const MethodChannel _channel = MethodChannel('azure_speech/asr');
static const EventChannel _eventChannel = EventChannel('azure_speech/asr_events');
static const EventChannel _eventChannel =
EventChannel('azure_speech/asr_events');
final GetStorage _storage = GetStorage();
bool _isInitialized = false;
late final String _subscriptionKey;
late final String _serviceRegion;
@ -40,23 +42,23 @@ class AzureAsrService extends GetxService implements AsrService {
/// 从环境变量加载配置
void _loadConfig() {
_subscriptionKey = dotenv.env['AZURE_SPEECH_KEY'] ?? '';
_serviceRegion = dotenv.env['AZURE_SPEECH_REGION'] ?? '';
final _env = _storage.read("ENV") as Map<String, String>;
_subscriptionKey = _env['AZURE_SPEECH_KEY'] ?? '';
_serviceRegion = _env['AZURE_SPEECH_REGION'] ?? '';
if (_subscriptionKey.isEmpty || _serviceRegion.isEmpty) {
throw Exception('未找到 Azure 语音服务配置。请在 .env 文件中设置 AZURE_SPEECH_KEY 和 AZURE_SPEECH_REGION');
throw Exception(
'未找到 Azure 语音服务配置。请在 .env 文件中设置 AZURE_SPEECH_KEY 和 AZURE_SPEECH_REGION');
}
}
/// 设置事件通道
void _setupEventChannel() {
_eventSubscription = _eventChannel
.receiveBroadcastStream()
.listen((event) {
if (event is Map) {
_handleRecognitionEvent(event);
}
}, onError: _handleRecognitionError);
_eventSubscription = _eventChannel.receiveBroadcastStream().listen((event) {
if (event is Map) {
_handleRecognitionEvent(event);
}
}, onError: _handleRecognitionError);
}
@override
@ -64,7 +66,8 @@ class AzureAsrService extends GetxService implements AsrService {
List<String>? supportedLanguages,
}) async {
try {
final List<String> languages = supportedLanguages ?? _defaultSupportedLanguages;
final List<String> languages =
supportedLanguages ?? _defaultSupportedLanguages;
// 检查是否需要重新初始化
if (_isInitialized) {
@ -99,7 +102,8 @@ class AzureAsrService extends GetxService implements AsrService {
if (result is Map) {
final String text = result['text'] as String? ?? '';
final String detectedLanguage = result['detectedLanguage'] as String? ?? '';
final String detectedLanguage =
result['detectedLanguage'] as String? ?? '';
_latestRecognizedText = text;
_latestDetectedLanguage = detectedLanguage;
@ -134,7 +138,8 @@ class AzureAsrService extends GetxService implements AsrService {
_eventStreamController = StreamController<RecognitionEvent>.broadcast();
// 开始连续识别
final bool result = await _channel.invokeMethod('startContinuousRecognition');
final bool result =
await _channel.invokeMethod('startContinuousRecognition');
if (!result) {
_cleanupEventStream();
@ -157,7 +162,8 @@ class AzureAsrService extends GetxService implements AsrService {
}
try {
final bool result = await _channel.invokeMethod('stopContinuousRecognition');
final bool result =
await _channel.invokeMethod('stopContinuousRecognition');
_cleanupEventStream();
return result;
} catch (e) {
@ -185,7 +191,8 @@ class AzureAsrService extends GetxService implements AsrService {
switch (eventType) {
case 'result':
final String text = eventMap['text'] as String? ?? '';
final String detectedLanguage = eventMap['detectedLanguage'] as String? ?? '';
final String detectedLanguage =
eventMap['detectedLanguage'] as String? ?? '';
_latestRecognizedText = text;
_latestDetectedLanguage = detectedLanguage;
_eventStreamController?.add(RecognitionEvent(
@ -197,7 +204,8 @@ class AzureAsrService extends GetxService implements AsrService {
case 'recognizing':
final String text = eventMap['text'] as String? ?? '';
final String detectedLanguage = eventMap['detectedLanguage'] as String? ?? '';
final String detectedLanguage =
eventMap['detectedLanguage'] as String? ?? '';
_eventStreamController?.add(RecognitionEvent(
type: RecognitionEventType.intermediateResult,
text: text,

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

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:get_storage/get_storage.dart';
import '../../../core/utils/logger.dart';
import '../tts_service.dart';
@ -13,7 +14,7 @@ import '../tts_service.dart';
class AzureTtsService extends GetxService implements TtsService {
static final AzureTtsService to = Get.put(AzureTtsService());
static const MethodChannel _channel = MethodChannel('azure_speech/tts');
final GetStorage _storage = GetStorage();
bool _isInitialized = false;
late final String _subscriptionKey;
late final String _serviceRegion;
@ -71,25 +72,25 @@ class AzureTtsService extends GetxService implements TtsService {
@override
List<String> get supportedVoices => _supportedVoices;
AzureTtsService() {
_loadConfig();
}
/// 从环境变量加载配置
void _loadConfig() {
_subscriptionKey = dotenv.env['AZURE_SPEECH_KEY'] ?? '';
_serviceRegion = dotenv.env['AZURE_SPEECH_REGION'] ?? '';
final _env = _storage.read("ENV") as Map<String, String>;
_subscriptionKey = _env['AZURE_SPEECH_KEY'] ?? '';
_serviceRegion = _env['AZURE_SPEECH_REGION'] ?? '';
}
@override
Future<bool> initialize({
List<String>? supportedLanguages,
}) async {
// 检查是否需要重新初始化
if (_isInitialized) {
await dispose();
}
// 检查是否需要重新初始化
if (_isInitialized) {
await dispose();
}
try {
if (_subscriptionKey.isEmpty || _serviceRegion.isEmpty) {
@ -97,22 +98,17 @@ class AzureTtsService extends GetxService implements TtsService {
return false;
}
// 更新支持的语音列表(如果提供)
final String language = supportedLanguages?.first ?? 'zh-CN';
final result = await _channel.invokeMethod('initialize', {
'subscriptionKey': _subscriptionKey,
'region': _serviceRegion,
'language': language,
});
final result = await _channel.invokeMethod('initialize', {
'subscriptionKey': _subscriptionKey,
'region': _serviceRegion,
'language': language,
});
_isInitialized = true;
return result;
_isInitialized = true;
return result;
} catch (e) {
Logger.error('初始化失败: $e');
return false;
@ -138,7 +134,8 @@ class AzureTtsService extends GetxService implements TtsService {
}
/// 设置语音参数
Future<bool> setSpeechParams({int rate = 0, int pitch = 0, int volume = 100}) async {
Future<bool> setSpeechParams(
{int rate = 0, int pitch = 0, int volume = 100}) async {
if (!_isInitialized) await initialize();
try {
@ -208,7 +205,8 @@ class AzureTtsService extends GetxService implements TtsService {
}
/// 等待语音播放完成
Future<void> waitForSpeechCompletion({Duration timeout = const Duration(seconds: 30)}) async {
Future<void> waitForSpeechCompletion(
{Duration timeout = const Duration(seconds: 30)}) async {
// 首先检查当前状态
_checkSpeakingStatus();
if (!_speakingCache) return;
@ -242,8 +240,7 @@ class AzureTtsService extends GetxService implements TtsService {
// 使用正则表达式匹配句子,包括结束符号
// 匹配任意字符,直到遇到句子结束符号
final sentenceRegex = RegExp(
r'([^。.!!??;;:\n\r]+[。.!!??;;::\n\r]|[^。.!!??;;:\n\r]+(?:\.{3,}|…)|[^。.!!??;;:\n\r]+["」』])'
);
r'([^。.!!??;;:\n\r]+[。.!!??;;::\n\r]|[^。.!!??;;:\n\r]+(?:\.{3,}|…)|[^。.!!??;;:\n\r]+["」』])');
bool hasProcessed = false;
@ -347,7 +344,9 @@ class AzureTtsService extends GetxService implements TtsService {
final item = _textQueue.removeAt(0);
if (item.rate != _currentRate || item.pitch != _currentPitch || item.volume != _currentVolume) {
if (item.rate != _currentRate ||
item.pitch != _currentPitch ||
item.volume != _currentVolume) {
await setSpeechParams(
rate: item.rate,
pitch: item.pitch,
@ -400,7 +399,11 @@ class AzureTtsService extends GetxService implements TtsService {
final pitchValue = (pitch ?? _currentPitch).clamp(-100, 100);
final volumeValue = (volume ?? _currentVolume).clamp(0, 100);
final rateStr = rateValue == 0 ? '0%' : rateValue < 0 ? '${(rateValue * 0.9).round()}%' : '$rateValue%';
final rateStr = rateValue == 0
? '0%'
: rateValue < 0
? '${(rateValue * 0.9).round()}%'
: '$rateValue%';
final pitchStr = pitchValue == 0 ? '0%' : '${(pitchValue * 0.5).round()}%';
final volumeStr = "$volumeValue%";
@ -448,7 +451,6 @@ class AzureTtsService extends GetxService implements TtsService {
return _speakingCache;
}
}
}
/// 语音合成项目

80
lib/data/services/voice_interaction_service.dart

@ -1,8 +1,10 @@
import 'dart:async';
import 'dart:convert';
import 'package:deep_voice/data/models/appconfig_model.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:get_storage/get_storage.dart';
import '../models/events/voice_interaction_event.dart';
import '../../core/utils/logger.dart';
import '../../modules/chat/models/message_model.dart';
@ -14,22 +16,26 @@ import 'chat_history_service.dart';
/// 管理与平台原生语音交互服务的通信,提供统一的接口供应用使用
class VoiceInteractionService extends GetxService {
static VoiceInteractionService get to => Get.find<VoiceInteractionService>();
final GetStorage _storage = GetStorage();
// 方法通道
static const MethodChannel _channel = MethodChannel('com.deep_voice.voice_interaction');
static const MethodChannel _channel =
MethodChannel('com.deep_voice.voice_interaction');
// 事件通道
static const EventChannel _eventChannel = EventChannel('com.deep_voice.voice_interaction_events');
static const EventChannel _eventChannel =
EventChannel('com.deep_voice.voice_interaction_events');
// 服务状态
final _isServiceRunning = false.obs;
bool get isServiceRunning => _isServiceRunning.value;
// 流控制器
final _eventStreamController = StreamController<VoiceInteractionEvent>.broadcast();
final _eventStreamController =
StreamController<VoiceInteractionEvent>.broadcast();
// 事件流
Stream<VoiceInteractionEvent> get eventStream => _eventStreamController.stream;
Stream<VoiceInteractionEvent> get eventStream =>
_eventStreamController.stream;
// 事件通道订阅
StreamSubscription? _eventSubscription;
@ -51,28 +57,36 @@ class VoiceInteractionService extends GetxService {
// 聊天历史服务
late final ChatHistoryService _chatHistoryService;
/// 设置事件通道
void _setupEventChannel() {
_eventSubscription = _eventChannel
.receiveBroadcastStream()
.listen(_handleVoiceInteractionEvent, onError: (error) {
Logger.error('语音交互事件通道错误: $error');
});
Logger.error('语音交互事件通道错误: $error');
});
}
/// 从环境变量加载配置
void _loadConfig() {
_azureSpeechKey = dotenv.env['AZURE_SPEECH_KEY'] ?? '';
_azureSpeechRegion = dotenv.env['AZURE_SPEECH_REGION'] ?? '';
_openaiApiKey = dotenv.env['OPENAI_API_KEY'] ?? '';
_openaiBaseUrl = dotenv.env['OPENAI_BASE_URL'] ?? '';
_openaiModel = dotenv.env['OPENAI_MODEL'] ?? '';
_volcanoSpeechAppId = dotenv.env['VOLCANO_SPEECH_APP_ID'] ?? '';
_volcanoSpeechAppToken = dotenv.env['VOLCANO_SPEECH_APP_TOKEN'] ?? '';
// _azureSpeechKey = dotenv.env['AZURE_SPEECH_KEY'] ?? '';
// _azureSpeechRegion = dotenv.env['AZURE_SPEECH_REGION'] ?? '';
// _openaiApiKey = dotenv.env['OPENAI_API_KEY'] ?? '';
// _openaiBaseUrl = dotenv.env['OPENAI_BASE_URL'] ?? '';
// _openaiModel = dotenv.env['OPENAI_MODEL'] ?? '';
// _volcanoSpeechAppId = dotenv.env['VOLCANO_SPEECH_APP_ID'] ?? '';
// _volcanoSpeechAppToken = dotenv.env['VOLCANO_SPEECH_APP_TOKEN'] ?? '';
final _env = _storage.read("ENV") as Map<String, String>;
_azureSpeechKey = _env['AZURE_SPEECH_KEY'] ?? '';
_azureSpeechRegion = _env['AZURE_SPEECH_REGION'] ?? '';
_openaiApiKey = _env['OPENAI_API_KEY'] ?? '';
_openaiBaseUrl = _env['OPENAI_BASE_URL'] ?? '';
_openaiModel = _env['OPENAI_MODEL'] ?? '';
_volcanoSpeechAppId = _env['VOLCANO_SPEECH_APP_ID'] ?? '';
_volcanoSpeechAppToken = _env['VOLCANO_SPEECH_APP_TOKEN'] ?? '';
if (_azureSpeechKey.isEmpty || _azureSpeechRegion.isEmpty) {
Logger.warning('未找到 Azure 语音服务配置。请在 .env 文件中设置 AZURE_SPEECH_KEY 和 AZURE_SPEECH_REGION');
Logger.warning(
'未找到 Azure 语音服务配置。请在 .env 文件中设置 AZURE_SPEECH_KEY 和 AZURE_SPEECH_REGION');
}
// 加载MCP配置
@ -82,10 +96,14 @@ class VoiceInteractionService extends GetxService {
/// 加载MCP配置
void _loadMcpConfig() {
try {
rootBundle.loadString('.mcp.json').then((config) {
_mcpConfig = config;
Logger.info('成功加载MCP配置, 配置内容: $_mcpConfig');
});
final mcps = _storage.read("MCPS") as Map<String, DBMCPServer>;
String config = jsonEncode(mcps);
_mcpConfig = config;
Logger.info('成功加载MCP配置, 配置内容: $_mcpConfig');
// rootBundle.loadString('.mcp.json').then((config) {
// _mcpConfig = config;
// Logger.info('成功加载MCP配置, 配置内容: $_mcpConfig');
// });
} catch (e) {
Logger.warning('加载MCP配置失败: $e');
_mcpConfig = null;
@ -115,7 +133,8 @@ class VoiceInteractionService extends GetxService {
// 聊天历史更新事件
final String agentId = eventMap['agentId'] as String? ?? '';
final String userMessage = eventMap['userMessage'] as String? ?? '';
final String assistantMessage = eventMap['assistantMessage'] as String? ?? '';
final String assistantMessage =
eventMap['assistantMessage'] as String? ?? '';
final chatHistoryEvent = ChatHistoryEvent(
agentId: agentId,
@ -134,7 +153,6 @@ class VoiceInteractionService extends GetxService {
Logger.info('收到进入翻译模式事件,正在导航到翻译界面');
_navigateToTranslation();
break;
}
}
@ -143,7 +161,8 @@ class VoiceInteractionService extends GetxService {
void _navigateToTranslation() {
try {
// 使用GetX导航到翻译页面
Get.offNamedUntil(Routes.translation, (route) => route.settings.name == Routes.home);
Get.offNamedUntil(
Routes.translation, (route) => route.settings.name == Routes.home);
Logger.info('已导航到翻译界面');
} catch (e) {
Logger.error('导航到翻译界面失败: $e');
@ -151,7 +170,8 @@ class VoiceInteractionService extends GetxService {
}
/// 保存聊天历史
Future<void> _saveChatHistory(String agentId, String userMessage, String assistantMessage) async {
Future<void> _saveChatHistory(
String agentId, String userMessage, String assistantMessage) async {
try {
final timestamp = DateTime.now().millisecondsSinceEpoch;
@ -165,7 +185,8 @@ class VoiceInteractionService extends GetxService {
final assistantMsg = Message(
role: 'assistant',
content: assistantMessage,
timestamp: DateTime.fromMillisecondsSinceEpoch(timestamp + 1), // 确保助手消息时间戳晚于用户消息
timestamp: DateTime.fromMillisecondsSinceEpoch(
timestamp + 1), // 确保助手消息时间戳晚于用户消息
);
// 加载现有历史记录
@ -247,7 +268,8 @@ class VoiceInteractionService extends GetxService {
params['mcp_config'] = _mcpConfig;
}
final result = await _channel.invokeMethod<bool>('startService', params) ?? false;
final result =
await _channel.invokeMethod<bool>('startService', params) ?? false;
if (result) {
_isServiceRunning.value = true;
@ -287,7 +309,8 @@ class VoiceInteractionService extends GetxService {
/// 检查服务是否运行
Future<bool> checkServiceStatus() async {
try {
final bool result = await _channel.invokeMethod<bool>('isServiceRunning') ?? false;
final bool result =
await _channel.invokeMethod<bool>('isServiceRunning') ?? false;
_isServiceRunning.value = result;
return result;
} catch (e) {
@ -301,7 +324,8 @@ class VoiceInteractionService extends GetxService {
try {
Logger.info('暂停后台语音交互...');
final result = await _channel.invokeMethod<bool>('pauseVoiceInteraction') ?? false;
final result =
await _channel.invokeMethod<bool>('pauseVoiceInteraction') ?? false;
if (result) {
Logger.info('语音交互已暂停');

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

@ -1,3 +1,4 @@
import 'package:deep_voice/data/models/appconfig_model.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:logger/web.dart';
@ -692,7 +693,8 @@ class LoginController extends GetxController {
//final prefs = await GetStorage();
await _storage.write(
'user', jsonEncode(user.toJson())); // 使用 user.toJson()
//获取app的配置信息
await getAppConfig();
Get.offAllNamed(Routes.pairing);
// } else {
// throw FormatException('API 响应缺少 user 字段');
@ -722,4 +724,24 @@ class LoginController extends GetxController {
colorText: Colors.blue,
);
}
Future<bool> getAppConfig() async {
try {
print('getAppConfig:进来了');
//if (User.getname() != "") {
final response = await Api.getappconfig();
print('getAppConfig: $response');
if (response == null) return false;
print('getAppConfig:进来了');
// 根据API设计调整
final resp = UserGetAppConfigResp.fromJson(response);
// 存储用户信息(示例)
_storage.write('ENV', resp.env);
_storage.write('MCPS', resp.mcps);
return true;
} catch (e) {
print('getAppConfig 取失败: $e');
return false;
}
}
}

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

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:amap_flutter/amap_flutter.dart';
import 'package:deep_voice/data/models/appconfig_model.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
@ -88,6 +89,7 @@ class SplashController extends GetxController {
isLoggedIn = await getLoginToken();
}
if (isLoggedIn) {
await getAppConfig();
Get.offAllNamed(Routes.pairing);
} else {
Get.offAllNamed(Routes.login); // 跳转到登录页
@ -118,4 +120,25 @@ class SplashController extends GetxController {
return false;
}
}
Future<bool> getAppConfig() async {
try {
print('getAppConfig:进来了');
//if (User.getname() != "") {
final response = await Api.getappconfig();
print('getAppConfig: $response');
if (response == null) return false;
// 根据API设计调整
final resp = UserGetAppConfigResp.fromJson(response);
print('getAppConfig:进来了');
// 存储用户信息(示例)
_storage.write('ENV', resp.env);
_storage.write('MCPS', resp.mcps);
return true;
} catch (e) {
print('getAppConfig 取失败: $e');
return false;
}
}
}

2
local_plugins/open_ai_service/android/build.gradle.kts

@ -4,6 +4,7 @@ plugins {
// Kotlin Android 插件
id("org.jetbrains.kotlin.android")
id("com.github.johnrengelman.shadow") version "8.1.1"
kotlin("plugin.serialization") version "1.9.24"
}
android {
@ -58,4 +59,5 @@ dependencies {
implementation("io.ktor:ktor-client-okhttp:3.1.2")
implementation("io.ktor:ktor-client-logging:3.1.2")
implementation("com.google.code.gson:gson:2.10.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
}

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

@ -34,7 +34,17 @@ import io.ktor.client.request.*
import io.ktor.http.*
import com.yunqiinnovation.open_ai_service.mcp.CustomSseClientTransport
import io.ktor.util.valuesOf
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
@Serializable
data class ServerConfig(
val servername: String,
val url: String,
val tools: List<String>? = null
)
/**
* 工具类型枚举
*/
@ -484,15 +494,17 @@ class MCPClient(private val context: Context? = null) : AutoCloseable {
if (mcpConfigJson.isNotEmpty()) {
val mapper = ObjectMapper()
try {
val config = mapper.readValue(mcpConfigJson, Map::class.java)
Log.d(TAG, "传入JSON:${mcpConfigJson}")
val configMap: Map<String, ServerConfig> = Json.decodeFromString(mcpConfigJson)
// val config = mapper.readValue(mcpConfigJson, Map::class.java)
// 处理mcpServers格式
@Suppress("UNCHECKED_CAST")
val mcpServers = config["mcpServers"] as? Map<String, Map<String, String>>
if (mcpServers != null && mcpServers.isNotEmpty()) {
// val mcpServers = config["mcpServers"] as? Map<String, Map<String, String>>
if (configMap.isNotEmpty()) {
// 从服务器配置中提取URL
mcpServers.forEach { (serverId, serverConfig) ->
val url = serverConfig["url"]
configMap.forEach { (serverId, serverConfig) ->
val url = serverConfig.url
if (!url.isNullOrEmpty()) {
serverMap[serverId] = url
Log.d(TAG, "从配置中添加服务器 [$serverId]: $url")

3
pubspec.yaml

@ -13,6 +13,7 @@ dependencies:
sdk: flutter
cupertino_icons: ^1.0.6
get: ^4.6.6
json_annotation: ^4.9.0
get_storage: ^2.1.1
http: ^1.3.0
flutter_screenutil: ^5.9.0
@ -80,6 +81,8 @@ dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
build_runner: ^2.3.3 # 用于生成代码 flutter pub run build_runner build
json_serializable: ^6.6.0 # 用于自动生成代码
flutter:
uses-material-design: true

Loading…
Cancel
Save