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

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许可证。