Siri在运行AppIntent时进入请求参数的循环。

huangapple go评论77阅读模式
英文:

Siri enters loop of requesting parameter when running AppIntent

问题

我想要使用AppIntents框架来添加快捷方式和Siri支持。使用快捷方式或从Spotlight中运行我的意图都没有问题,因为显示了基于触摸的UI来进行消歧义。然而,当我要求Siri执行此操作时,她陷入了一个循环,一直问我设置参数的问题。

我的AppIntent实现如下:

struct StartSessionIntent: AppIntent {
    static var title: LocalizedStringResource = "start_recording"

    @Parameter(title: "activity", requestValueDialog: IntentDialog("which_activity"))
    var activity: ActivityEntity

    @MainActor
    func perform() async throws -> some IntentResult & ProvidesDialog {
        let activityToSelect: ActivityEntity = self.activity
        guard let selectedActivity = Activity[activityToSelect.name] else {
            return .result(dialog: "activity_not_found")
        }
        ...
        return .result(dialog: "recording_started \(selectedActivity.name.localized())")
    }
}

ActivityEntity的实现如下:

struct ActivityEntity: AppEntity {
    static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "activity")
    typealias DefaultQuery = MobilityActivityQuery
    static var defaultQuery: MobilityActivityQuery = MobilityActivityQuery()

    var id: String
    var name: String
    var icon: String

    var displayRepresentation: DisplayRepresentation {
        DisplayRepresentation(title: "\(self.name.localized())", image: .init(systemName: self.icon))
    }
}

struct MobilityActivityQuery: EntityQuery {
    func entities(for identifiers: [String]) async throws -> [ActivityEntity] {
        Activity.all()?.compactMap({ activity in
            identifiers.contains(where: { $0 == activity.name }) ? ActivityEntity(id: activity.name, name: activity.name, icon: activity.icon) : nil
        }) ?? []
    }

    func suggestedEntities() async throws -> [ActivityEntity] {
        Activity.all()?.compactMap({ activity in
            ActivityEntity(id: activity.name, name: activity.name, icon: activity.icon)
        }) ?? []
    }
}

有人知道可能是什么原因导致了这种情况,以及如何解决这个问题吗?提前感谢。

英文:

I want to add shortcut and Siri support using the AppIntents framework. Running my intent using shortcuts or from spotlight works fine, as the touch based UI for the disambiguation is shown. However, when I ask Siri to perform this action, she gets into a loop of asking me the question to set the parameter.

My AppIntent is implemented as following:

struct StartSessionIntent: AppIntent {
    static var title: LocalizedStringResource = "start_recording"

    @Parameter(title: "activity", requestValueDialog: IntentDialog("which_activity"))
    var activity: ActivityEntity

    @MainActor
    func perform() async throws -> some IntentResult & ProvidesDialog {
        let activityToSelect: ActivityEntity = self.activity
        guard let selectedActivity = Activity[activityToSelect.name] else {
            return .result(dialog: "activity_not_found")
        }
        ...
        return .result(dialog: "recording_started (selectedActivity.name.localized())")
    }
}

The ActivityEntity is implemented like this:

struct ActivityEntity: AppEntity {
    static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "activity")
    typealias DefaultQuery = MobilityActivityQuery
    static var defaultQuery: MobilityActivityQuery = MobilityActivityQuery()

    var id: String
    var name: String
    var icon: String

    var displayRepresentation: DisplayRepresentation {
        DisplayRepresentation(title: "\(self.name.localized())", image: .init(systemName: self.icon))
    }
}

struct MobilityActivityQuery: EntityQuery {
    func entities(for identifiers: [String]) async throws -> [ActivityEntity] {
        Activity.all()?.compactMap({ activity in
            identifiers.contains(where: { $0 == activity.name }) ? ActivityEntity(id: activity.name, name: activity.name, icon: activity.icon) : nil
        }) ?? []
    }

    func suggestedEntities() async throws -> [ActivityEntity] {
        Activity.all()?.compactMap({ activity in
            ActivityEntity(id: activity.name, name: activity.name, icon: activity.icon)
        }) ?? []
    }
}

Has anyone an idea what might be causing this and how I can fix this behavior? Thanks in advance.

答案1

得分: 1

  1. 第一个可能性是你没有为你的 @Parameter 设置 default 属性。这个属性告诉 Siri 如果用户没有指定参数要使用什么值。如果你不设置这个属性,Siri 将始终要求用户设置参数。

要解决这个问题,你可以将 default 属性设置为参数的默认值。例如,如果你的参数是一个字符串,你可以将 default 属性设置为空字符串。

  1. 第二个可能性是你正在使用自定义的 IntentDialog 用于你的 @Parameter。如果你正在使用自定义的 IntentDialog,你需要确保对话框包含一种让用户取消请求的方法。如果用户取消请求,Siri 将无法设置参数,并会要求用户再次设置它。

要解决这个问题,你可以在你的 IntentDialog 中添加一个 cancel 按钮。这将允许用户在不设置参数的情况下取消请求。

以下是通过设置 default 属性来解决问题的示例:

struct StartSessionIntent: AppIntent {
    static var title: LocalizedStringResource = "start_recording"

    @Parameter(
        title: "activity",
        requestValueDialog: IntentDialog("which_activity"),
        default: ""
    )
    var activity: String

    @MainActor
    func perform() async throws -> some IntentResult & ProvidesDialog {
        let activityToSelect: ActivityEntity = Activity[activity] ?? ActivityEntity(id: "", name: "", icon: "")
        guard let selectedActivity = Activity[activityToSelect.name] else {
            return .result(dialog: "activity_not_found")
        }
        // ...
        return .result(dialog: "recording_started \(selectedActivity.name.localized())")
    }
}

以下是通过在 IntentDialog 中添加 cancel 按钮来解决问题的示例:

struct StartSessionIntent: AppIntent {
    static var title: LocalizedStringResource = "start_recording"

    @Parameter(
        title: "activity",
        requestValueDialog: IntentDialog("which_activity", buttons: [.cancel()])
    )
    var activity: String

    @MainActor
    func perform() async throws -> some IntentResult & ProvidesDialog {
        let activityToSelect: ActivityEntity = Activity[activity] ?? ActivityEntity(id: "", name: "", icon: "")
        guard let selectedActivity = Activity[activityToSelect.name] else {
            return .result(dialog: "activity_not_found")
        }
        // ...
        return .result(dialog: "recording_started \(selectedActivity.name.localized())")
    }
}

希望这可以帮助你!

英文:

I can see two possible reasons why Siri might be asking you to set the parameter for your AppIntent multiple times.

  1. The first possibility is that you have not set the default property for your @Parameter. This property tells Siri what value to use for the parameter if the user does not specify one. If you do not set this property, Siri will always ask the user to set the parameter.

To fix this, you can set the default property to the default value for your parameter. For example, if your parameter is a string, you could set the default property to an empty string.

  1. The second possibility is that you are using a custom IntentDialog for your @Parameter. If you are using a custom IntentDialog, you need to make sure that the dialog includes a way for the user to cancel the request. If the user cancels the request, Siri will not be able to set the parameter and will ask the user to set it again.

To fix this, you can add a cancel button to your IntentDialog. This will allow the user to cancel the request without setting the parameter.

Here is an example of how you could fix the problem by setting the default property:

struct StartSessionIntent: AppIntent {
    static var title: LocalizedStringResource = "start_recording"

    @Parameter(
        title: "activity",
        requestValueDialog: IntentDialog("which_activity"),
        default: ""
    )
    var activity: String

    @MainActor
    func perform() async throws -> some IntentResult & ProvidesDialog {
        let activityToSelect: ActivityEntity = Activity[activity] ?? ActivityEntity(id: "", name: "", icon: "")
        guard let selectedActivity = Activity[activityToSelect.name] else {
            return .result(dialog: "activity_not_found")
        }
        ...
        return .result(dialog: "recording_started \(selectedActivity.name.localized())")
    }
}


Here is an example of how you could fix the problem by adding a `cancel` button to your `IntentDialog`:


struct StartSessionIntent: AppIntent {
    static var title: LocalizedStringResource = "start_recording"

    @Parameter(
        title: "activity",
        requestValueDialog: IntentDialog("which_activity", buttons: [.cancel()])
    )
    var activity: String

    @MainActor
    func perform() async throws -> some IntentResult & ProvidesDialog {
        let activityToSelect: ActivityEntity = Activity[activity] ?? ActivityEntity(id: "", name: "", icon: "")
        guard let selectedActivity = Activity[activityToSelect.name] else {
            return .result(dialog: "activity_not_found")
        }
        ...
        return .result(dialog: "recording_started \(selectedActivity.name.localized())")
    }
}

I hope this helps!

huangapple
  • 本文由 发表于 2023年6月15日 19:13:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76481885.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定