import 'dart:async'; import 'dart:convert'; import 'package:flutter/services.dart'; /// ChatAPI服务异常 class ChatApiException implements Exception { final String message; ChatApiException(this.message); @override String toString() => 'ChatApiException: $message'; } /// ChatAPI服务事件类型 enum ChatApiEventType { token, complete, error, functionCall, } /// ChatAPI服务事件 class ChatApiEvent { final ChatApiEventType type; final dynamic content; final Map? meta; ChatApiEvent({required this.type, this.content, this.meta}); factory ChatApiEvent.fromMap(Map map) { final typeStr = map['type'] as String; final content = map['content']; final rawMeta = map['meta'] as String?; final meta = rawMeta != null ? jsonDecode(rawMeta) : null; return ChatApiEvent( type: _typeFromString(typeStr), content: content, meta: meta, ); } static ChatApiEventType _typeFromString(String typeStr) { switch (typeStr) { case 'token': return ChatApiEventType.token; case 'complete': return ChatApiEventType.complete; case 'error': return ChatApiEventType.error; case 'functionCall': return ChatApiEventType.functionCall; default: throw ArgumentError('未知的事件类型: $typeStr'); } } } /// ChatAPI服务插件 class ChatApiService { static const MethodChannel _channel = MethodChannel('com.yunqiinnovation.chat_api/methods'); static const EventChannel _eventChannel = EventChannel('com.yunqiinnovation.chat_api/events'); /// 事件流控制器 StreamController? _eventStreamController; /// 事件流 Stream? _eventStream; /// 获取事件流 Stream get eventStream { if (_eventStream == null) { _eventStreamController = StreamController.broadcast(); _eventStream = _eventStreamController!.stream; // 监听原生事件 _eventChannel.receiveBroadcastStream().listen( (dynamic event) { if (event is Map) { final eventMap = Map.from(event); final chatApiEvent = ChatApiEvent.fromMap(eventMap); _eventStreamController!.add(chatApiEvent); } }, onError: (error) { _eventStreamController!.addError(ChatApiException('事件流错误: $error')); }, ); } return _eventStream!; } /// 初始化ChatAPI服务 /// /// [apiKey] OpenAI API密钥 /// [baseUrl] 可选,自定义API基础URL /// [model] 可选,自定义使用的模型 /// [mcpServer] 可选,MCP服务器地址配置 Future initialize({ required String apiKey, String baseUrl = '', String model = '', String mcpServer = '', }) async { try { final result = await _channel.invokeMethod( 'initialize', { 'apiKey': apiKey, 'baseUrl': baseUrl, 'model': model, 'mcpServer': mcpServer, }, ); return result ?? false; } catch (e) { throw ChatApiException('初始化失败: $e'); } } /// 注册函数 /// /// [name] 函数名称 /// [description] 函数描述 /// [parameters] 函数参数 Future registerFunction({ required String name, required String description, required Map parameters, }) async { try { final result = await _channel.invokeMethod( 'registerFunction', { 'name': name, 'description': description, 'parameters': parameters, }, ); return result ?? false; } catch (e) { throw ChatApiException('注册函数失败: $e'); } } /// 创建用户消息 /// /// [content] 消息内容 Future> createUserMessage(String content) async { try { final result = await _channel.invokeMethod>( 'createUserMessage', {'content': content}, ); if (result == null) { throw ChatApiException('创建用户消息失败: 结果为空'); } return Map.from(result); } catch (e) { throw ChatApiException('创建用户消息失败: $e'); } } /// 创建助手消息 /// /// [content] 消息内容 Future> createAssistantMessage(String content) async { try { final result = await _channel.invokeMethod>( 'createAssistantMessage', {'content': content}, ); if (result == null) { throw ChatApiException('创建助手消息失败: 结果为空'); } return Map.from(result); } catch (e) { throw ChatApiException('创建助手消息失败: $e'); } } /// 发送消息(非流式输出) /// /// [messages] 消息列表 Future sendMessage({ required List> messages, String? systemPrompt, //提示词 String? userProperties, //用户属性 }) async { try { // 构建新的消息列表 final List> updatedMessages = []; // 如果有提示词,先添加 system role if (systemPrompt != null && systemPrompt.isNotEmpty) { updatedMessages.add({ 'role': 'system', 'content': systemPrompt, }); } // 如果有用户属性,可以作为 user 的一个"隐式指令"传进去 if (userProperties != null && userProperties.isNotEmpty) { updatedMessages.add({ 'role': 'user', 'content': '【用户属性】$userProperties', }); } // 添加原始消息 updatedMessages.addAll(messages); final result = await _channel.invokeMethod( 'sendMessage', { 'messages': updatedMessages, }, ); if (result == null) { throw ChatApiException('发送消息失败: 结果为空'); } return result; } catch (e) { throw ChatApiException('发送消息失败: $e'); } } /// 发送消息(流式输出) /// /// [messages] 消息列表 /// /// 返回一个布尔值,表示请求是否已开始 Future sendMessageStream({ required List> messages, String? systemPrompt, //提示词 String? userProperties, //用户属性 }) async { try { // 构建新的消息列表 final List> updatedMessages = []; // 如果有提示词,先添加 system role if (systemPrompt != null && systemPrompt.isNotEmpty) { updatedMessages.add({ 'role': 'system', 'content': systemPrompt, }); } // 如果有用户属性,可以作为 user 的一个"隐式指令"传进去 if (userProperties != null && userProperties.isNotEmpty) { updatedMessages.add({ 'role': 'user', 'content': '【用户属性】$userProperties', }); } // 添加原始消息 updatedMessages.addAll(messages); final result = await _channel.invokeMethod( 'sendMessageStream', { 'messages': updatedMessages, }, ); return result ?? false; } catch (e) { throw ChatApiException('发送流式消息失败: $e'); } } /// 发送函数调用结果 /// /// [messages] 消息列表 /// [functionCall] 函数调用信息 /// [functionResult] 函数调用结果 /// /// 返回一个布尔值,表示请求是否已开始 Future sendFunctionCallResult({ required List> messages, required Map functionCall, required String functionResult, }) async { try { final result = await _channel.invokeMethod( 'sendFunctionCallResult', { 'messages': messages, 'functionCall': functionCall, 'functionResult': functionResult, }, ); return result ?? false; } catch (e) { throw ChatApiException('发送函数调用结果失败: $e'); } } /// 取消当前流式请求 Future cancelCurrentStream() async { try { final result = await _channel.invokeMethod('cancelCurrentStream'); return result ?? false; } catch (e) { throw ChatApiException('取消请求失败: $e'); } } /// 从JSON字符串解析函数调用 Map parseFunctionCall(String functionCallJson) { try { return json.decode(functionCallJson) as Map; } catch (e) { throw ChatApiException('解析函数调用失败: $e'); } } /// 初始化MCP客户端 /// /// [serverUrl] MCP服务器WebSocket地址 /// /// 返回一个布尔值,表示请求是否已开始初始化(实际初始化过程是异步的) Future initializeMcpClient(String serverUrl) async { try { final result = await _channel.invokeMethod( 'initializeMcpClient', {'serverUrl': serverUrl}, ); return result ?? false; } catch (e) { throw ChatApiException('初始化MCP客户端失败: $e'); } } /// 检查MCP客户端是否已初始化 Future isMcpInitialized() async { try { final result = await _channel.invokeMethod('isMcpInitialized'); return result ?? false; } catch (e) { throw ChatApiException('检查MCP客户端状态失败: $e'); } } /// 关闭MCP客户端 Future closeMcpClient() async { try { final result = await _channel.invokeMethod('closeMcpClient'); return result ?? false; } catch (e) { throw ChatApiException('关闭MCP客户端失败: $e'); } } /// 处理MCP工具调用 /// /// [functionCall] 函数调用信息,必须包含name和arguments字段 /// /// 返回工具调用结果 Future handleMcpToolCall(Map functionCall) async { try { final result = await _channel.invokeMethod( 'handleMcpToolCall', {'functionCall': jsonEncode(functionCall)}, ); return result ?? "处理MCP工具调用失败: 结果为空"; } catch (e) { throw ChatApiException('处理MCP工具调用失败: $e'); } } /// 处理函数调用(自动处理本地函数和MCP工具) /// /// 这是一个辅助方法,用于简化函数调用处理流程: /// 1. MCP工具会被自动处理,不会通过回调返回 /// 2. 只有本地函数才需要手动处理 /// 3. 提供统一的处理接口 /// /// 参数: /// [functionCall] 函数调用信息 /// [messages] 消息上下文 /// [localFunctionHandler] 本地函数处理器,接收函数名和参数,返回处理结果 /// /// 返回值: /// 布尔值表示是否成功处理(已将结果发送回OpenAI) Future handleFunctionCall({ required Map functionCall, required List> messages, required Future Function( String name, Map arguments) localFunctionHandler, }) async { final name = functionCall['name'] as String; final argumentsJson = functionCall['arguments'] as String; // 解析参数 Map arguments; try { arguments = json.decode(argumentsJson) as Map; } catch (e) { arguments = {}; } try { // 调用本地函数处理器 final result = await localFunctionHandler(name, arguments); // 发送结果回ChatAPI return sendFunctionCallResult( messages: messages, functionCall: functionCall, functionResult: result, ); } catch (e) { throw ChatApiException('处理函数调用失败: $e'); } } }