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
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: 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
|
|
}
|
|
}
|