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.

514 lines
18 KiB

import Foundation
import UIKit
import CoreLocation
import Contacts
import EventKit
/// 系统功能处理器
class SystemFunctionHandler {
private let TAG = "SystemFunctionHandler"
private let context: Any
static let ACTION_EXIT_INTERACTION = "com.yunqiinnovation.deepsound.action.EXIT_INTERACTION"
/// 初始化系统功能处理器
/// - Parameter context: 应用上下文
init(context: Any) {
self.context = context
}
/// 注册所有系统功能
/// - Parameter client: MCP客户端
func registerAllFunctions(client: MCPClient) {
// 注册退出交互函数
registerExitInteractionFunction(client)
// 注册翻译模式函数
registerTranslationModeFunction(client)
// 注册发送短信函数
registerSendTextMessageFunction(client)
// 注册拨打电话函数
registerMakePhoneCallFunction(client)
// 注册打开应用函数
registerOpenAppFunction(client)
// 注册设置提醒函数
registerSetReminderFunction(client)
// 注册获取当前时间函数
registerGetCurrentTimeFunction(client)
// 注册获取当前位置函数
registerGetCurrentLocationFunction(client)
print("\(TAG) 所有系统功能注册完成")
}
/// 注册退出交互函数
private func registerExitInteractionFunction(_ client: MCPClient) {
// 定义函数参数
let parameters: [String: Any] = [
"type": "object",
"properties": [:],
"required": []
]
// 创建函数处理器
let handler = ExitInteractionHandler()
// 注册函数
client.registerLocalFunction(
name: "exit_interaction",
description: "结束当前交互",
parameters: parameters,
handler: handler
)
print("\(TAG) 已注册退出交互功能")
}
/// 注册翻译模式函数
private func registerTranslationModeFunction(_ client: MCPClient) {
// 定义函数参数
let parameters: [String: Any] = [
"type": "object",
"properties": [:],
"required": []
]
// 创建函数处理器
let handler = TranslationModeHandler()
// 注册函数
client.registerLocalFunction(
name: "enter_translation_mode",
description: "用户请求进入实时翻译模式时,启动实时翻译功能",
parameters: parameters,
handler: handler
)
print("\(TAG) 已注册翻译模式功能")
}
/// 注册发送短信函数
private func registerSendTextMessageFunction(_ client: MCPClient) {
// 定义函数参数
let parameters: [String: Any] = [
"type": "object",
"properties": [
"contact": [
"type": "string",
"description": "联系人姓名或电话号码"
],
"message": [
"type": "string",
"description": "短信内容"
]
],
"required": ["contact", "message"]
]
// 创建函数处理器
let handler = SendTextMessageHandler()
// 注册函数
client.registerLocalFunction(
name: "send_text_message",
description: "发送短信",
parameters: parameters,
handler: handler
)
print("\(TAG) 已注册发送短信功能")
}
/// 注册拨打电话函数
private func registerMakePhoneCallFunction(_ client: MCPClient) {
// 定义函数参数
let parameters: [String: Any] = [
"type": "object",
"properties": [
"contact": [
"type": "string",
"description": "联系人姓名或电话号码"
]
],
"required": ["contact"]
]
// 创建函数处理器
let handler = MakePhoneCallHandler()
// 注册函数
client.registerLocalFunction(
name: "make_phone_call",
description: "拨打电话",
parameters: parameters,
handler: handler
)
print("\(TAG) 已注册拨打电话功能")
}
/// 注册打开应用函数
private func registerOpenAppFunction(_ client: MCPClient) {
// 定义函数参数
let parameters: [String: Any] = [
"type": "object",
"properties": [
"app_name": [
"type": "string",
"description": "应用名称"
]
],
"required": ["app_name"]
]
// 创建函数处理器
let handler = OpenAppHandler()
// 注册函数
client.registerLocalFunction(
name: "open_app",
description: "当用户请求打开特定应用时,启动相应应用",
parameters: parameters,
handler: handler
)
print("\(TAG) 已注册打开应用功能")
}
/// 注册设置提醒函数
private func registerSetReminderFunction(_ client: MCPClient) {
// 定义函数参数
let parameters: [String: Any] = [
"type": "object",
"properties": [
"title": [
"type": "string",
"description": "提醒标题"
],
"content": [
"type": "string",
"description": "提醒内容"
],
"time": [
"type": "string",
"description": "提醒时间,格式为'yyyy-MM-dd HH:mm',如'2023-12-31 14:30'"
]
],
"required": ["title", "time"]
]
// 创建函数处理器
let handler = SetReminderHandler()
// 注册函数
client.registerLocalFunction(
name: "set_reminder",
description: "设置提醒事项",
parameters: parameters,
handler: handler
)
print("\(TAG) 已注册设置提醒功能")
}
/// 注册获取当前时间函数
private func registerGetCurrentTimeFunction(_ client: MCPClient) {
// 定义函数参数
let parameters: [String: Any] = [
"type": "object",
"properties": [
"format": [
"type": "string",
"description": "时间格式,可选,默认为标准格式"
]
],
"required": []
]
// 创建函数处理器
let handler = GetCurrentTimeHandler()
// 注册函数
client.registerLocalFunction(
name: "get_current_time",
description: "获取当前日期和时间",
parameters: parameters,
handler: handler
)
print("\(TAG) 已注册获取当前时间功能")
}
/// 注册获取当前位置函数
private func registerGetCurrentLocationFunction(_ client: MCPClient) {
// 定义函数参数
let parameters: [String: Any] = [
"type": "object",
"properties": [:],
"required": []
]
// 创建函数处理器
let handler = GetCurrentLocationHandler()
// 注册函数
client.registerLocalFunction(
name: "get_current_location",
description: "获取当前地理位置",
parameters: parameters,
handler: handler
)
print("\(TAG) 已注册获取当前位置功能")
}
}
/// 退出交互处理器
class ExitInteractionHandler: FunctionHandler {
func handle(arguments: [String: Any]) async throws -> String {
// 发送通知和广播
NotificationCenter.default.post(
name: Notification.Name(SystemFunctionHandler.ACTION_EXIT_INTERACTION),
object: nil,
userInfo: ["timestamp": Date().timeIntervalSince1970]
)
return "{\"result\": \"已结束当前交互\"}"
}
}
/// 翻译模式处理器
class TranslationModeHandler: FunctionHandler {
func handle(arguments: [String: Any]) async throws -> String {
// 发送通知
NotificationCenter.default.post(
name: Notification.Name("com.yunqiinnovation.deepsound.ACTION_ENTER_TRANSLATION_MODE"),
object: nil,
userInfo: ["timestamp": Date().timeIntervalSince1970]
)
return "{\"result\": \"已进入实时翻译模式\"}"
}
}
/// 发送短信处理器
class SendTextMessageHandler: FunctionHandler {
func handle(arguments: [String: Any]) async throws -> String {
guard let contact = arguments["contact"] as? String,
let message = arguments["message"] as? String else {
return "{\"result\": \"发送短信失败:缺少联系人或消息内容\"}"
}
// iOS不允许应用直接发送短信,但可以打开短信应用
if let url = URL(string: "sms:\(contact)&body=\(message.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")") {
DispatchQueue.main.async {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
return "{\"result\": \"已打开短信应用,收件人:\(contact)\"}"
}
return "{\"result\": \"发送短信失败:无法打开短信应用\"}"
}
}
/// 拨打电话处理器
class MakePhoneCallHandler: FunctionHandler {
func handle(arguments: [String: Any]) async throws -> String {
guard let contact = arguments["contact"] as? String else {
return "{\"result\": \"拨打电话失败:缺少联系人\"}"
}
let phoneNumber = contact.replacingOccurrences(of: "[^+0-9]", with: "", options: .regularExpression)
if let url = URL(string: "tel://\(phoneNumber)") {
DispatchQueue.main.async {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
return "{\"result\": \"正在拨打\(contact)的电话\"}"
}
return "{\"result\": \"拨打电话失败:无法拨打电话\"}"
}
}
/// 打开应用处理器
class OpenAppHandler: FunctionHandler {
func handle(arguments: [String: Any]) async throws -> String {
guard let appName = arguments["app_name"] as? String else {
return "{\"result\": \"打开应用失败:缺少应用名称\"}"
}
// iOS没有直接打开其他应用的API,只能通过URL Scheme
// 这里只是模拟返回成功,实际上无法在iOS上实现这个功能
return "{\"result\": \"打开应用功能在iOS上受限,无法直接打开\(appName)\"}"
}
}
/// 设置提醒处理器
class SetReminderHandler: FunctionHandler {
func handle(arguments: [String: Any]) async throws -> String {
guard let title = arguments["title"] as? String,
let timeStr = arguments["time"] as? String else {
return "{\"result\": \"设置提醒失败:缺少标题或时间\"}"
}
let content = arguments["content"] as? String ?? ""
// 解析时间
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm"
guard let date = dateFormatter.date(from: timeStr) else {
return "{\"result\": \"设置提醒失败:时间格式无效,请使用'yyyy-MM-dd HH:mm'格式\"}"
}
// 使用EventKit添加提醒
let eventStore = EKEventStore()
let event = EKEvent(eventStore: eventStore)
event.title = title
event.notes = content
event.startDate = date
event.endDate = date.addingTimeInterval(3600) // 1小时后
event.calendar = eventStore.defaultCalendarForNewEvents
do {
try eventStore.save(event, span: .thisEvent)
return "{\"result\": \"已创建提醒: \(title), 时间: \(timeStr)\"}"
} catch {
return "{\"result\": \"设置提醒失败:\(error.localizedDescription)\"}"
}
}
}
/// 获取当前时间处理器
class GetCurrentTimeHandler: FunctionHandler {
func handle(arguments: [String: Any]) async throws -> String {
let format = arguments["format"] as? String
let calendar = Calendar.current
let date = Date()
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "zh_CN")
let timeStr: String
switch format?.lowercased() {
case "short":
dateFormatter.dateFormat = "HH:mm"
timeStr = dateFormatter.string(from: date)
case "date":
dateFormatter.dateFormat = "yyyy年MM月dd日"
timeStr = dateFormatter.string(from: date)
case "time":
dateFormatter.dateFormat = "HH:mm:ss"
timeStr = dateFormatter.string(from: date)
case "full":
dateFormatter.dateFormat = "yyyy年MM月dd日 EEEE HH:mm:ss"
timeStr = dateFormatter.string(from: date)
case "iso":
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
timeStr = dateFormatter.string(from: date)
default:
dateFormatter.dateFormat = "yyyy年MM月dd日 HH:mm"
timeStr = dateFormatter.string(from: date)
}
// 获取星期几
let weekDay: String
if format == "full" {
weekDay = "" // 已经包含在dateFormatter里
} else {
let weekDayNum = calendar.component(.weekday, from: date)
switch weekDayNum {
case 1: weekDay = "星期日"
case 2: weekDay = "星期一"
case 3: weekDay = "星期二"
case 4: weekDay = "星期三"
case 5: weekDay = "星期四"
case 6: weekDay = "星期五"
case 7: weekDay = "星期六"
default: weekDay = ""
}
}
// 格式化结果
let resultTime: String
if format == "short" || format == "time" {
resultTime = timeStr
} else if format == "full" {
resultTime = timeStr // already contains weekday
} else {
resultTime = "\(timeStr) \(weekDay)"
}
return "{\"result\": \"\(resultTime)\", \"time\": \"\(resultTime)\"}"
}
}
/// 获取当前位置处理器
class GetCurrentLocationHandler: NSObject, FunctionHandler {
private let locationManager = CLLocationManager()
private var locationCompletionHandler: ((String, Bool) -> Void)?
func handle(arguments: [String: Any]) async throws -> String {
return await withCheckedContinuation { continuation in
self.getLocation { message, success in
continuation.resume(returning: "{\"result\": \"\(message)\", \"success\": \(success)}")
}
}
}
private func getLocation(completion: @escaping (String, Bool) -> Void) {
locationCompletionHandler = completion
// 检查权限
let authStatus = CLLocationManager.authorizationStatus()
if authStatus == .denied || authStatus == .restricted {
completion("需要位置权限才能获取当前位置", false)
return
}
// 检查位置服务是否开启
if !CLLocationManager.locationServicesEnabled() {
completion("位置服务未启用,请打开GPS或网络定位", false)
return
}
// 如果有最后的位置,使用它
if let lastLocation = locationManager.location {
let message = "当前位置: 经度 \(lastLocation.coordinate.longitude), 纬度 \(lastLocation.coordinate.latitude)"
completion(message, true)
return
}
// 否则请求更新
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
// 设置超时
DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in
if let handler = self?.locationCompletionHandler {
self?.locationManager.stopUpdatingLocation()
handler("获取位置超时,请稍后重试", false)
self?.locationCompletionHandler = nil
}
}
}
}
// 扩展以接收位置更新
extension GetCurrentLocationHandler: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last, let handler = locationCompletionHandler else { return }
manager.stopUpdatingLocation()
let message = "当前位置: 经度 \(location.coordinate.longitude), 纬度 \(location.coordinate.latitude)"
handler(message, true)
locationCompletionHandler = nil
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
manager.stopUpdatingLocation()
locationCompletionHandler?("获取位置失败: \(error.localizedDescription)", false)
locationCompletionHandler = nil
}
}