You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

358 lines
8.8 KiB

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<String, dynamic>? meta;
ChatApiEvent({
required this.type,
this.content,
this.meta,
});
factory ChatApiEvent.fromMap(Map<String, dynamic> map) {
final typeStr = map['type'] as String;
final content = map['content'];
final meta = map['meta'] as Map<String, dynamic>?;
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<String, dynamic>? functionCall;
ChatMessage({
required this.role,
required this.content,
this.name,
this.functionCall,
});
Map<String, dynamic> 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<String, dynamic> map) {
return ChatMessage(
role: _roleFromString(map['role'] as String),
content: map['content'],
name: map['name'] as String?,
functionCall: map['function_call'] as Map<String, dynamic>?,
);
}
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<ChatApiEvent>? _eventStreamController;
/// 事件流
Stream<ChatApiEvent>? _eventStream;
/// 获取事件流
Stream<ChatApiEvent> get eventStream {
if (_eventStream == null) {
_eventStreamController = StreamController<ChatApiEvent>.broadcast();
_eventStream = _eventStreamController!.stream;
// 监听原生事件
_eventChannel.receiveBroadcastStream().listen(
(dynamic event) {
if (event is Map<dynamic, dynamic>) {
final eventMap = Map<String, dynamic>.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<bool> initialize({
required String apiKey,
String? organization,
String model = 'gpt-3.5-turbo',
String? baseUrl,
}) async {
try {
final result = await _channel.invokeMethod<bool>(
'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<String> sendMessage({
required List<ChatMessage> messages,
double temperature = 0.7,
int? maxTokens,
double topP = 1.0,
int n = 1,
List<String>? stop,
double presencePenalty = 0.0,
double frequencyPenalty = 0.0,
List<Map<String, dynamic>>? functions,
}) async {
try {
final messagesMap = messages.map((m) => m.toMap()).toList();
final result = await _channel.invokeMethod<String>(
'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<bool> sendMessageStream({
required List<ChatMessage> messages,
double temperature = 0.7,
int? maxTokens,
double topP = 1.0,
int n = 1,
List<String>? stop,
double presencePenalty = 0.0,
double frequencyPenalty = 0.0,
List<Map<String, dynamic>>? functions,
}) async {
try {
final messagesMap = messages.map((m) => m.toMap()).toList();
final result = await _channel.invokeMethod<bool>(
'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<bool> cancelStream() async {
try {
final result = await _channel.invokeMethod<bool>('cancelStream');
return result ?? false;
} catch (e) {
throw ChatApiException('取消流式请求失败: $e');
}
}
/// 获取可用的模型列表
Future<List<String>> getAvailableModels() async {
try {
final result = await _channel.invokeMethod<List<dynamic>>('getAvailableModels');
return result?.cast<String>() ?? [];
} catch (e) {
throw ChatApiException('获取模型列表失败: $e');
}
}
/// 设置默认模型
Future<bool> setModel(String model) async {
try {
final result = await _channel.invokeMethod<bool>(
'setModel',
{'model': model},
);
return result ?? false;
} catch (e) {
throw ChatApiException('设置模型失败: $e');
}
}
/// 估算token数量
Future<int> countTokens(String text) async {
try {
final result = await _channel.invokeMethod<int>(
'countTokens',
{'text': text},
);
return result ?? 0;
} catch (e) {
throw ChatApiException('计算token失败: $e');
}
}
/// 释放资源
Future<void> dispose() async {
await _eventStreamController?.close();
_eventStreamController = null;
_eventStream = null;
}
}