mirror of
https://github.com/home-assistant/iOS.git
synced 2026-06-18 11:15:36 -05:00
<!-- Thank you for submitting a Pull Request and helping to improve Home Assistant. Please complete the following sections to help the processing and review of your changes. Please do not delete anything from this template. --> ## Summary <!-- Provide a brief summary of the changes you have made and most importantly what they aim to achieve --> This PR deprecate intents from siri intents definition and migrates them to App Intent. ## Screenshots <!-- If this is a user-facing change not in the frontend, please include screenshots in light and dark mode. --> ## Link to pull request in Documentation repository <!-- Pull requests that add, change or remove functionality must have a corresponding pull request in the Companion App Documentation repository (https://github.com/home-assistant/companion.home-assistant). Please add the number of this pull request after the "#" --> Documentation: home-assistant/companion.home-assistant# ## Any other notes <!-- If there is any other information of note, like if this Pull Request is part of a bigger change, please include it here. -->
106 lines
3.3 KiB
Swift
106 lines
3.3 KiB
Swift
import AppIntents
|
|
import Foundation
|
|
import Shared
|
|
|
|
@available(iOS 16.4, *)
|
|
struct AssistPromptAppIntent: AppIntent {
|
|
static var title: LocalizedStringResource = .init(
|
|
"app_intents.assist_prompt.title",
|
|
defaultValue: "Assist prompt"
|
|
)
|
|
|
|
static var description = IntentDescription(.init(
|
|
"app_intents.assist_prompt.description",
|
|
defaultValue: "Send a text prompt to Assist"
|
|
))
|
|
|
|
@Parameter(title: .init("app_intents.assist_prompt.prompt.title", defaultValue: "Prompt"))
|
|
var prompt: String
|
|
|
|
@Parameter(title: .init("app_intents.assist.pipeline.title", defaultValue: "Pipeline"))
|
|
var pipeline: AssistPipelineEntity
|
|
|
|
func perform() async throws -> some IntentResult & ReturnsValue<String> {
|
|
await Current.connectivity.syncNetworkInformation()
|
|
guard let server = Current.servers.server(for: .init(rawValue: pipeline.serverId)) else {
|
|
throw ShortcutAppIntentError(L10n.AppIntents.Error.noServer)
|
|
}
|
|
|
|
guard server.info.version >= .conversationWebhook else {
|
|
throw ShortcutAppIntentError(HomeAssistantAPI.APIError.mustUpgradeHomeAssistant(
|
|
current: server.info.version,
|
|
minimum: .conversationWebhook
|
|
).localizedDescription)
|
|
}
|
|
|
|
let result = try await AssistPromptRunner(server: server).assist(
|
|
prompt: prompt,
|
|
pipelineId: pipeline.id.isEmpty ? nil : pipeline.id
|
|
)
|
|
return .result(value: result)
|
|
}
|
|
}
|
|
|
|
@available(iOS 16.4, *)
|
|
private final class AssistPromptRunner: NSObject, AssistServiceDelegate {
|
|
private let server: Server
|
|
private var assistService: AssistService?
|
|
private var continuation: CheckedContinuation<String, Error>?
|
|
|
|
init(server: Server) {
|
|
self.server = server
|
|
super.init()
|
|
}
|
|
|
|
func assist(prompt: String, pipelineId: String?) async throws -> String {
|
|
try await withCheckedThrowingContinuation { continuation in
|
|
self.continuation = continuation
|
|
let assistService = AssistService(server: server)
|
|
assistService.delegate = self
|
|
self.assistService = assistService
|
|
assistService.assist(source: .text(input: prompt, pipelineId: pipelineId, expectTTS: false))
|
|
}
|
|
}
|
|
|
|
func didReceiveStreamResponseChunk(_ content: String) {
|
|
/* no-op */
|
|
}
|
|
|
|
func didReceiveEvent(_ event: AssistEvent) {
|
|
/* no-op */
|
|
}
|
|
|
|
func didReceiveSttContent(_ content: String) {
|
|
/* no-op */
|
|
}
|
|
|
|
func didReceiveIntentEndContent(_ content: String) {
|
|
resume(with: .success(content))
|
|
}
|
|
|
|
func didReceiveGreenLightForAudioInput() {
|
|
/* no-op */
|
|
}
|
|
|
|
func didReceiveTtsMediaUrl(_ mediaUrl: URL) {
|
|
/* no-op */
|
|
}
|
|
|
|
func didReceiveError(code: String, message: String) {
|
|
resume(with: .failure(ShortcutAppIntentError("\(code) - \(message)")))
|
|
}
|
|
|
|
private func resume(with result: Swift.Result<String, Error>) {
|
|
guard let continuation else { return }
|
|
self.continuation = nil
|
|
assistService = nil
|
|
|
|
switch result {
|
|
case let .success(value):
|
|
continuation.resume(returning: value)
|
|
case let .failure(error):
|
|
continuation.resume(throwing: error)
|
|
}
|
|
}
|
|
}
|