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.
8.4 KiB
8.4 KiB
OpenAI服务插件
提供与OpenAI API的原生交互功能,支持流式输出和函数调用,同时支持Android和iOS平台。
功能特点
- 原生实现,性能更好
- 支持流式输出,实时显示AI回复
- 支持函数调用(工具调用)
- 支持自定义API基础URL
- 支持Android和iOS平台
- 提供简洁易用的Dart接口
安装
将该插件添加到您的pubspec.yaml文件中:
dependencies:
open_ai_service:
path: local_plugins/open_ai_service
使用方法
初始化
首先需要初始化OpenAI服务,提供API密钥和可选的基础URL和模型:
import 'package:open_ai_service/open_ai_service.dart';
final openAIService = OpenAIService();
// 使用OpenAI官方API和默认模型
await openAIService.initialize(apiKey: 'your_openai_api_key');
// 或使用自定义API端点和模型
await openAIService.initialize(
apiKey: 'your_api_key',
baseUrl: 'https://your-custom-endpoint.com/v1/chat/completions',
model: 'gpt-4-0125-preview', // 自定义模型
);
普通聊天
发送消息并获取非流式回复:
// 创建用户消息
final userMessage = await openAIService.createUserMessage('你好,请介绍一下自己');
// 发送消息
final response = await openAIService.sendMessage(
messages: [userMessage],
systemPrompt: '你是一个有帮助的AI助手,请简洁地回答问题。',
);
print('AI回复: $response');
流式输出
使用流式输出获取实时回复:
// 注册事件监听
final subscription = openAIService.processEvents(
onToken: (token) {
// 收到部分回复
print('收到部分回复: $token');
// 更新UI...
},
onComplete: () {
// 回复完成
print('回复完成');
},
onError: (error) {
// 处理错误
print('错误: $error');
},
onFunctionCall: (functionCall) {
// 处理函数调用
print('函数调用: $functionCall');
handleFunctionCall(functionCall);
},
);
// 发送流式消息
await openAIService.sendMessageStream(
messages: [userMessage],
systemPrompt: '你是一个有帮助的AI助手,请简洁地回答问题。',
);
// 完成后,记得取消订阅
// subscription.cancel();
函数调用
注册函数并处理函数调用:
// 注册一个天气查询函数
await openAIService.registerFunction(
name: 'get_weather',
description: '获取指定城市的天气信息',
parameters: {
'type': 'object',
'properties': {
'city': {
'type': 'string',
'description': '城市名称,如北京、上海等',
},
'date': {
'type': 'string',
'description': '查询日期,默认为今天',
},
},
'required': ['city'],
},
);
// 处理函数调用
void handleFunctionCall(Map<String, dynamic> functionCall) {
final name = functionCall['name'];
final arguments = jsonDecode(functionCall['arguments']);
final id = functionCall['id'];
if (name == 'get_weather') {
final city = arguments['city'];
final date = arguments['date'] ?? '今天';
// 获取天气信息(实际应用中应调用天气API)
final weatherResult = '{"temperature": 25, "condition": "晴天", "humidity": 40}';
// 发送函数调用结果
openAIService.sendFunctionCallResult(
messages: messages, // 当前的消息历史
systemPrompt: systemPrompt,
functionCall: functionCall,
functionResult: weatherResult,
);
}
}
示例应用
一个简单的聊天机器人示例:
import 'package:flutter/material.dart';
import 'package:open_ai_service/open_ai_service.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'OpenAI 聊天',
theme: ThemeData(primarySwatch: Colors.blue),
home: ChatScreen(),
);
}
}
class ChatScreen extends StatefulWidget {
@override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
final OpenAIService _openAIService = OpenAIService();
final TextEditingController _textController = TextEditingController();
final List<Map<String, dynamic>> _messages = [];
StreamSubscription? _subscription;
String _currentResponse = '';
bool _isLoading = false;
@override
void initState() {
super.initState();
_initializeOpenAI();
}
Future<void> _initializeOpenAI() async {
try {
await _openAIService.initialize(
apiKey: 'your_api_key_here',
);
// 注册事件监听
_subscription = _openAIService.processEvents(
onToken: (token) {
setState(() {
_currentResponse += token;
});
},
onComplete: () {
_addAIMessage(_currentResponse);
setState(() {
_currentResponse = '';
_isLoading = false;
});
},
onError: (error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('错误: $error')),
);
setState(() {
_isLoading = false;
});
},
onFunctionCall: (functionCall) {
// 处理函数调用...
},
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('初始化失败: $e')),
);
}
}
void _sendMessage() async {
if (_textController.text.isEmpty) return;
final userMessage = _textController.text;
_addUserMessage(userMessage);
_textController.clear();
try {
setState(() {
_isLoading = true;
});
final message = await _openAIService.createUserMessage(userMessage);
await _openAIService.sendMessageStream(
messages: _messages,
systemPrompt: '你是一个有帮助的AI助手,请简洁地回答问题。',
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('发送消息失败: $e')),
);
setState(() {
_isLoading = false;
});
}
}
void _addUserMessage(String content) {
setState(() {
_messages.add({
'role': 'user',
'content': content,
});
});
}
void _addAIMessage(String content) {
setState(() {
_messages.add({
'role': 'assistant',
'content': content,
});
});
}
@override
void dispose() {
_subscription?.cancel();
_textController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('OpenAI 聊天')),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: _messages.length + (_currentResponse.isNotEmpty ? 1 : 0),
itemBuilder: (context, index) {
if (index < _messages.length) {
final message = _messages[index];
final isUser = message['role'] == 'user';
return ListTile(
leading: Icon(isUser ? Icons.person : Icons.computer),
title: Text(message['content']),
);
} else {
// 显示当前正在生成的回复
return ListTile(
leading: Icon(Icons.computer),
title: Text(_currentResponse),
);
}
},
),
),
if (_isLoading)
LinearProgressIndicator(),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Expanded(
child: TextField(
controller: _textController,
decoration: InputDecoration(
hintText: '输入消息...',
border: OutlineInputBorder(),
),
),
),
IconButton(
icon: Icon(Icons.send),
onPressed: _sendMessage,
),
],
),
),
],
),
);
}
}
注意事项
- 请确保您的API密钥安全存储,不要直接硬编码在应用程序中
- 流式输出需要在调用
sendMessageStream之前注册事件监听 - 使用完毕后记得取消事件订阅
许可证
此插件遵循MIT许可证。