iOS/Sources/Shared/Intents/AssistIntentHandler.swift

90 lines
3.2 KiB
Swift

import Intents
import ObjectMapper
import PromiseKit
class AssistIntentHandler: NSObject, AssistIntentHandling {
typealias Intent = AssistIntent
func resolveServer(for intent: Intent, with completion: @escaping (IntentServerResolutionResult) -> Void) {
if let server = Current.servers.server(for: intent) {
completion(.success(with: .init(server: server)))
} else {
completion(.needsValue())
}
}
func provideServerOptions(for intent: Intent, with completion: @escaping ([IntentServer]?, Error?) -> Void) {
completion(IntentServer.all, nil)
}
func provideServerOptionsCollection(
for intent: Intent,
with completion: @escaping (INObjectCollection<IntentServer>?, Error?) -> Void
) {
completion(.init(items: IntentServer.all), nil)
}
func defaultLanguage(for intent: AssistIntent) -> IntentLanguage? {
Locale.current.asIntentLanguage
}
func provideLanguageOptions(
for intent: AssistIntent,
with completion: @escaping ([IntentLanguage]?, Error?) -> Void
) {
completion(Locale.current.intentLanguages, nil)
}
func provideLanguageOptionsCollection(
for intent: AssistIntent,
with completion: @escaping (INObjectCollection<IntentLanguage>?, Error?) -> Void
) {
completion(.init(items: Locale.current.intentLanguages), nil)
}
func handle(intent: AssistIntent, completion: @escaping (AssistIntentResponse) -> Void) {
guard let server = Current.servers.server(for: intent) else {
completion(.failure(error: "no server provided"))
return
}
guard server.info.version >= .conversationWebhook else {
completion(.failure(error: HomeAssistantAPI.APIError.mustUpgradeHomeAssistant(
current: server.info.version,
minimum: .conversationWebhook
).localizedDescription))
return
}
struct ConversationResponse: ImmutableMappable {
var speech: String
init(map: Map) throws {
self.speech = try map.value("response.speech.plain.speech")
}
}
Current.webhooks.sendEphemeral(
server: server,
request: .init(
type: "conversation_process",
data: [
"text": intent.text,
"language": intent.language?.identifier ?? Locale.current.identifier,
]
)
).map { (original: [String: Any]) -> (ConversationResponse, [String: Any]) in
let object: ConversationResponse = try Mapper().map(JSONObject: original)
return (object, original)
}.done { object, original in
Current.Log.info("finishing with \(object)")
let value = IntentAssistResult(identifier: nil, display: object.speech)
value.json = try String(decoding: JSONSerialization.data(withJSONObject: original), as: UTF8.self)
completion(.success(result: value))
}.catch { error in
Current.Log.error("erroring with \(error)")
completion(.failure(error: error.localizedDescription))
}
}
}