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.

340 lines
13 KiB

import Flutter
import UIKit
import Foundation
/// OpenAI服务插件主类
public class OpenAIServicePlugin: NSObject, FlutterPlugin, FlutterStreamHandler {
// MARK: - 常量
private static let methodChannelName = "com.yunqiinnovation.open_ai_service/methods"
private static let eventChannelName = "com.yunqiinnovation.open_ai_service/events"
// MARK: - 属性
private var methodChannel: FlutterMethodChannel?
private var eventChannel: FlutterEventChannel?
private var eventSink: FlutterEventSink?
private var openAIService: OpenAIService?
// MARK: - 插件注册
public static func register(with registrar: FlutterPluginRegistrar) {
let instance = OpenAIServicePlugin()
// 初始化方法通道
let methodChannel = FlutterMethodChannel(
name: methodChannelName,
binaryMessenger: registrar.messenger()
)
instance.methodChannel = methodChannel
registrar.addMethodCallDelegate(instance, channel: methodChannel)
// 初始化事件通道
let eventChannel = FlutterEventChannel(
name: eventChannelName,
binaryMessenger: registrar.messenger()
)
instance.eventChannel = eventChannel
eventChannel.setStreamHandler(instance)
// 初始化OpenAI服务
instance.openAIService = OpenAIService()
}
// MARK: - FlutterPlugin
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
guard let service = openAIService else {
result(FlutterError(code: "SERVICE_NOT_INITIALIZED",
message: "OpenAI服务未初始化",
details: nil))
return
}
switch call.method {
case "initialize":
handleInitialize(call: call, result: result, service: service)
case "registerFunction":
handleRegisterFunction(call: call, result: result, service: service)
case "sendMessage":
handleSendMessage(call: call, result: result, service: service)
case "sendMessageStream":
handleSendMessageStream(call: call, result: result, service: service)
case "sendFunctionCallResult":
handleSendFunctionCallResult(call: call, result: result, service: service)
case "createUserMessage":
handleCreateUserMessage(call: call, result: result, service: service)
case "createAssistantMessage":
handleCreateAssistantMessage(call: call, result: result, service: service)
case "initializeMcpClient":
handleInitializeMcpClient(call: call, result: result, service: service)
case "isMcpInitialized":
handleIsMcpInitialized(call: call, result: result, service: service)
case "closeMcpClient":
handleCloseMcpClient(call: call, result: result, service: service)
case "handleMcpToolCall":
handleMcpToolCall(call: call, result: result, service: service)
default:
result(FlutterMethodNotImplemented)
}
}
// MARK: - FlutterStreamHandler
public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
self.eventSink = events
return nil
}
public func onCancel(withArguments arguments: Any?) -> FlutterError? {
self.eventSink = nil
return nil
}
// MARK: - 方法处理
private func handleInitialize(call: FlutterMethodCall, result: @escaping FlutterResult, service: OpenAIService) {
guard let args = call.arguments as? [String: Any],
let apiKey = args["apiKey"] as? String else {
result(FlutterError(code: "INVALID_ARGUMENTS",
message: "缺少必要参数",
details: nil))
return
}
let baseUrl = args["baseUrl"] as? String ?? ""
let model = args["model"] as? String ?? ""
let mcpServer = args["mcpServer"] as? String ?? ""
let success = service.initialize(
apiKey: apiKey,
baseUrl: baseUrl,
model: model,
mcpServer: mcpServer
)
result(success)
}
private func handleRegisterFunction(call: FlutterMethodCall, result: @escaping FlutterResult, service: OpenAIService) {
guard let args = call.arguments as? [String: Any],
let name = args["name"] as? String,
let description = args["description"] as? String,
let parameters = args["parameters"] as? [String: Any] else {
result(FlutterError(code: "INVALID_ARGUMENTS",
message: "缺少必要参数",
details: nil))
return
}
let success = service.registerFunction(name: name, description: description, parameters: parameters)
result(success)
}
private func handleSendMessage(call: FlutterMethodCall, result: @escaping FlutterResult, service: OpenAIService) {
guard let args = call.arguments as? [String: Any],
let messagesArray = args["messages"] as? [[String: Any]] else {
result(FlutterError(code: "INVALID_ARGUMENTS",
message: "缺少消息参数",
details: nil))
return
}
do {
let response = try service.sendMessage(messages: messagesArray)
result(response)
} catch {
result(FlutterError(code: "OPENAI_ERROR",
message: error.localizedDescription,
details: nil))
}
}
private func handleSendMessageStream(call: FlutterMethodCall, result: @escaping FlutterResult, service: OpenAIService) {
guard let args = call.arguments as? [String: Any],
let messagesArray = args["messages"] as? [[String: Any]] else {
result(FlutterError(code: "INVALID_ARGUMENTS",
message: "缺少消息参数",
details: nil))
return
}
guard let eventSink = self.eventSink else {
result(FlutterError(code: "NO_EVENT_SINK",
message: "没有可用的事件流接收器",
details: nil))
return
}
// 创建回调处理器
let callback = StreamCallbackImpl(eventSink: eventSink)
// 发送流式消息
service.sendMessageStream(messages: messagesArray, callback: callback)
result(true)
}
private func handleSendFunctionCallResult(call: FlutterMethodCall, result: @escaping FlutterResult, service: OpenAIService) {
guard let args = call.arguments as? [String: Any],
let messagesArray = args["messages"] as? [[String: Any]],
let functionCall = args["functionCall"] as? [String: Any],
let functionResult = args["functionResult"] as? String else {
result(FlutterError(code: "INVALID_ARGUMENTS",
message: "缺少必要参数",
details: nil))
return
}
guard let eventSink = self.eventSink else {
result(FlutterError(code: "NO_EVENT_SINK",
message: "没有可用的事件流接收器",
details: nil))
return
}
// 创建回调处理器
let callback = StreamCallbackImpl(eventSink: eventSink)
// 发送函数调用结果
service.sendFunctionCallResult(
messages: messagesArray,
functionCall: functionCall,
functionResult: functionResult,
callback: callback
)
result(true)
}
private func handleCreateUserMessage(call: FlutterMethodCall, result: @escaping FlutterResult, service: OpenAIService) {
guard let args = call.arguments as? [String: Any],
let content = args["content"] as? String else {
result(FlutterError(code: "INVALID_ARGUMENTS",
message: "缺少内容参数",
details: nil))
return
}
let message = service.createUserMessage(content: content)
result(message)
}
private func handleCreateAssistantMessage(call: FlutterMethodCall, result: @escaping FlutterResult, service: OpenAIService) {
guard let args = call.arguments as? [String: Any],
let content = args["content"] as? String else {
result(FlutterError(code: "INVALID_ARGUMENTS",
message: "缺少内容参数",
details: nil))
return
}
let message = service.createAssistantMessage(content: content)
result(message)
}
private func handleInitializeMcpClient(call: FlutterMethodCall, result: @escaping FlutterResult, service: OpenAIService) {
guard let args = call.arguments as? [String: Any],
let serverUrl = args["serverUrl"] as? String else {
result(FlutterError(code: "INVALID_ARGUMENTS",
message: "缺少服务器URL参数",
details: nil))
return
}
let success = service.initializeMcpClient(serverUrl: serverUrl)
result(success)
}
private func handleIsMcpInitialized(call: FlutterMethodCall, result: @escaping FlutterResult, service: OpenAIService) {
let isInitialized = service.isMcpInitialized()
result(isInitialized)
}
private func handleCloseMcpClient(call: FlutterMethodCall, result: @escaping FlutterResult, service: OpenAIService) {
service.closeMcpClient()
result(true)
}
private func handleMcpToolCall(call: FlutterMethodCall, result: @escaping FlutterResult, service: OpenAIService) {
guard let args = call.arguments as? [String: Any],
let functionCallJson = args["functionCall"] as? String else {
result(FlutterError(code: "INVALID_ARGUMENTS",
message: "缺少函数调用参数",
details: nil))
return
}
Task {
do {
let toolResult = try await service.handleMcpToolCall(functionCallJson: functionCallJson)
DispatchQueue.main.async {
result(toolResult)
}
} catch {
DispatchQueue.main.async {
result(FlutterError(code: "MCP_TOOL_ERROR",
message: "处理MCP工具调用失败: \(error.localizedDescription)",
details: nil))
}
}
}
}
}
// MARK: - 流式回调实现
private class StreamCallbackImpl: StreamCallback {
private let eventSink: FlutterEventSink
init(eventSink: @escaping FlutterEventSink) {
self.eventSink = eventSink
}
func onToken(_ token: String) {
DispatchQueue.main.async {
self.eventSink(["type": "token", "content": token])
}
}
func onComplete() {
DispatchQueue.main.async {
self.eventSink(["type": "complete"])
}
}
func onError(_ error: Error) {
DispatchQueue.main.async {
self.eventSink(["type": "error", "content": error.localizedDescription])
}
}
func onFunctionCall(_ functionCall: [String: Any]) {
DispatchQueue.main.async {
if let jsonData = try? JSONSerialization.data(withJSONObject: functionCall),
let jsonString = String(data: jsonData, encoding: .utf8) {
self.eventSink(["type": "function_call", "content": jsonString])
}
}
}
func onFunctionCallResult(_ functionCall: [String: Any], _ functionCallResult: [String: Any]) {
DispatchQueue.main.async {
if let callData = try? JSONSerialization.data(withJSONObject: functionCall),
let callString = String(data: callData, encoding: .utf8),
let resultData = try? JSONSerialization.data(withJSONObject: functionCallResult),
let resultString = String(data: resultData, encoding: .utf8) {
self.eventSink([
"type": "function_call_result",
"function_call": callString,
"result": resultString
])
}
}
}
}