import 'dart:async'; import 'dart:convert'; import 'package:flutter/services.dart'; /// 聊天API异常 class ChatApiException implements Exception { final String message; ChatApiException(this.message); @override String toString() => 'ChatApiException: $message'; } /// 聊天API事件类型 enum ChatApiEventType { /// 收到新的token token, /// 对话完成 complete, /// 发生错误 error, /// 函数调用 functionCall, } /// 聊天API事件 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 meta = map['meta'] as Map?; 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'); } } } /// 消息角色 enum MessageRole { system, user, assistant, function, } extension MessageRoleExtension on MessageRole { String get value { switch (this) { case MessageRole.system: return 'system'; case MessageRole.user: return 'user'; case MessageRole.assistant: return 'assistant'; case MessageRole.function: return 'function'; } } } /// 聊天消息 class ChatMessage { final MessageRole role; final dynamic content; final String? name; final Map? functionCall; ChatMessage({ required this.role, required this.content, this.name, this.functionCall, }); Map toMap() { final map = { 'role': role.value, 'content': content, }; if (name != null) { map['name'] = name!; } if (functionCall != null) { map['function_call'] = functionCall!; } return map; } factory ChatMessage.fromMap(Map map) { return ChatMessage( role: _roleFromString(map['role'] as String), content: map['content'], name: map['name'] as String?, functionCall: map['function_call'] as Map?, ); } static MessageRole _roleFromString(String roleStr) { switch (roleStr) { case 'system': return MessageRole.system; case 'user': return MessageRole.user; case 'assistant': return MessageRole.assistant; case 'function': return MessageRole.function; default: throw ArgumentError('未知的角色类型: $roleStr'); } } } /// 聊天API插件 class ChatApi { 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!; } /// 初始化聊天API服务 /// /// [apiKey] OpenAI API密钥 /// [organization] 可选,组织ID /// [model] 可选,使用的模型,默认为gpt-3.5-turbo /// [baseUrl] 可选,自定义API基础URL Future initialize({ required String apiKey, String? organization, String model = 'gpt-3.5-turbo', String? baseUrl, }) async { try { final result = await _channel.invokeMethod( 'initialize', { 'apiKey': apiKey, 'organization': organization, 'model': model, 'baseUrl': baseUrl, }, ); return result ?? false; } catch (e) { throw ChatApiException('初始化失败: $e'); } } /// 发送聊天消息 /// /// [messages] 消息列表 /// [temperature] 温度参数,控制输出的随机性 /// [maxTokens] 最大token数 /// [topP] 核心采样参数 /// [n] 生成的回复数量 /// [stop] 停止序列 /// [presencePenalty] 存在惩罚 /// [frequencyPenalty] 频率惩罚 /// [functions] 可用的函数列表 Future sendMessage({ required List messages, double temperature = 0.7, int? maxTokens, double topP = 1.0, int n = 1, List? stop, double presencePenalty = 0.0, double frequencyPenalty = 0.0, List>? functions, }) async { try { final messagesMap = messages.map((m) => m.toMap()).toList(); final result = await _channel.invokeMethod( 'sendMessage', { 'messages': messagesMap, 'temperature': temperature, 'maxTokens': maxTokens, 'topP': topP, 'n': n, 'stop': stop, 'presencePenalty': presencePenalty, 'frequencyPenalty': frequencyPenalty, 'functions': functions, }, ); if (result == null) { throw ChatApiException('发送消息失败: 结果为空'); } return result; } catch (e) { throw ChatApiException('发送消息失败: $e'); } } /// 发送聊天消息(流式输出) /// /// [messages] 消息列表 /// [temperature] 温度参数,控制输出的随机性 /// [maxTokens] 最大token数 /// [topP] 核心采样参数 /// [n] 生成的回复数量 /// [stop] 停止序列 /// [presencePenalty] 存在惩罚 /// [frequencyPenalty] 频率惩罚 /// [functions] 可用的函数列表 Future sendMessageStream({ required List messages, double temperature = 0.7, int? maxTokens, double topP = 1.0, int n = 1, List? stop, double presencePenalty = 0.0, double frequencyPenalty = 0.0, List>? functions, }) async { try { final messagesMap = messages.map((m) => m.toMap()).toList(); final result = await _channel.invokeMethod( 'sendMessageStream', { 'messages': messagesMap, 'temperature': temperature, 'maxTokens': maxTokens, 'topP': topP, 'n': n, 'stop': stop, 'presencePenalty': presencePenalty, 'frequencyPenalty': frequencyPenalty, 'functions': functions, }, ); return result ?? false; } catch (e) { throw ChatApiException('发送流式消息失败: $e'); } } /// 取消当前的流式请求 Future cancelStream() async { try { final result = await _channel.invokeMethod('cancelStream'); return result ?? false; } catch (e) { throw ChatApiException('取消流式请求失败: $e'); } } /// 获取可用的模型列表 Future> getAvailableModels() async { try { final result = await _channel.invokeMethod>('getAvailableModels'); return result?.cast() ?? []; } catch (e) { throw ChatApiException('获取模型列表失败: $e'); } } /// 设置默认模型 Future setModel(String model) async { try { final result = await _channel.invokeMethod( 'setModel', {'model': model}, ); return result ?? false; } catch (e) { throw ChatApiException('设置模型失败: $e'); } } /// 估算token数量 Future countTokens(String text) async { try { final result = await _channel.invokeMethod( 'countTokens', {'text': text}, ); return result ?? 0; } catch (e) { throw ChatApiException('计算token失败: $e'); } } /// 释放资源 Future dispose() async { await _eventStreamController?.close(); _eventStreamController = null; _eventStream = null; } }