如何将alexa自定义技能的body结果解析为JSON

问题描述

我能够设置 Alexa 自定义技能并从我的 IOS 应用程序中调用它。当我在 Alexa 控制台模拟器中测试技能时,我可以看到 JSON 输出,我想从我的 IOS 应用程序中获取它,但是,我在解析它时遇到了问题。我的 IOS 代码运行良好,因为我可以听到来自我的自定义技能的文本响应。

这是我想要获取/解析的示例 JSON 输出

    {
        "body": {
            "version": "1.0","response": {
                "outputSpeech": {
                    "type": "SSML","ssml": "<speak>Hello this is a custom skill</speak>"
                },"type": "_DEFAULT_RESPONSE"
            },"sessionAttributes": {},"userAgent": "ask-node/2.9.0 Node/v10.23.1 sample/hello-world/v1.2"
        }
    }
    

这是发布录音的代码

func postRecording(authToken:String,jsonData:String,audioData: Data) {
        var request = URLRequest(url: URL(string: EVENTS_ENDPOINT)!)
        //request.cachePolicy = NSURLRequest.CachePolicy.ReloadIgnoringCacheData
        request.httpShouldHandleCookies = false
        request.timeoutInterval = 60
        request.httpMethod = "POST"
        request.setValue("Bearer \(authToken)",forHTTPHeaderField: "Authorization")
        
        let boundry = NSUUID().uuidString
        let contentType = "multipart/form-data; boundary=\(boundry)"
        
        request.setValue(contentType,forHTTPHeaderField: "Content-Type")
        
        var bodyData = Data()
        
        bodyData.append("--\(boundry)\r\n".data(using: String.Encoding.utf8)!)
        bodyData.append("Content-disposition: form-data; name=\"Metadata\"\r\n".data(using: String.Encoding.utf8)!)
        bodyData.append("Content-Type: application/json; charset=UTF-8\r\n\r\n".data(using: String.Encoding.utf8)!)
        bodyData.append(jsonData.data(using: String.Encoding.utf8)!)
        bodyData.append("\r\n".data(using: String.Encoding.utf8)!)
        
        bodyData.append("--\(boundry)\r\n".data(using: String.Encoding.utf8)!)
        bodyData.append("Content-disposition: form-data; name=\"audio\"\r\n".data(using: String.Encoding.utf8)!)
        bodyData.append("Content-Type: audio/L16; rate=16000; channels=1\r\n\r\n".data(using: String.Encoding.utf8)!)
        bodyData.append(audioData)
        bodyData.append("\r\n".data(using: String.Encoding.utf8)!)
        
        bodyData.append("--\(boundry)--\r\n".data(using: String.Encoding.utf8)!)
        
        session.uploadTask(with: request,from: bodyData,completionHandler: { (data:Data?,response:URLResponse?,error:Error?) -> Void in
            if (error != nil) {
                print("Send audio error: \(String(describing: error?.localizedDescription))")
            } else {
                let res = response as! HTTPURLResponse
                if (res.statusCode >= 200 && res.statusCode <= 299) {
                    if let contentTypeHeader = res.allHeaderFields["Content-Type"] {
                        let boundary = self.extractBoundary(contentTypeHeader: contentTypeHeader as! String)
                        let directives = self.extractDirectives(data: data!,boundary: boundary)
                        self.directiveHandler?(directives)
                    } else {
                        print("Content type in response is empty")
                    }
                }
            }
        }).resume()
    }

func extractDirectives(data: Data,boundary: String) -> [DirectiveData] {
        var directives = [DirectiveData]()
        
        let innerBoundry = "--\(boundary)".data(using: String.Encoding.utf8)!
        let endBoundry = "--\(boundary)--".data(using: String.Encoding.utf8)!
        let contentTypeApplicationjson = "Content-Type: application/json; charset=UTF-8".data(using: String.Encoding.utf8)!
        let contentTypeAudio = "Content-Type: application/octet-stream".data(using: String.Encoding.utf8)!
        let headerEnd = "\r\n\r\n".data(using: String.Encoding.utf8)!
        
        var startIndex = 0
        while (true) {
            let firstAppearance = data.range(of: innerBoundry,in: startIndex..<(data.count))
            if (firstAppearance == nil) {
                break
            }
            var secondAppearance = data.range(of: innerBoundry,in: (firstAppearance?.upperBound)!..<(data.count))
            if (secondAppearance == nil) {
                secondAppearance = data.range(of: endBoundry,in: (firstAppearance?.upperBound)!..<(data.count))
                if (secondAppearance == nil) {
                    break
                }
            } else {
                startIndex = (secondAppearance?.lowerBound)!
            }
            let subdata = data.subdata(in: (firstAppearance?.upperBound)!..<(secondAppearance?.lowerBound)!)
            var contentType = subdata.range(of: contentTypeApplicationjson)
            if (contentType != nil) {
                let headerRange = subdata.range(of: headerEnd)
                var directiveData = String(data: subdata.subdata(in: (headerRange?.upperBound)!..<subdata.count),encoding: String.Encoding.utf8) ?? "Directive data is not String"
                directiveData = directiveData.replacingOccurrences(of: "\r\n",with: "")
                directives.append(DirectiveData(contentType: "application/json",data: directiveData.data(using: String.Encoding.utf8)!))
                print("Directive: \(directiveData)")
            }
            contentType = subdata.range(of: contentTypeAudio)
            if (contentType != nil) {
                let headerRange = subdata.range(of: headerEnd)
                let audioData = subdata.subdata(in: (headerRange?.upperBound)!..<subdata.count)
                directives.append(DirectiveData(contentType: "application/octet-stream",data: audioData))
                print("Audio data")
            }
        }
        return directives
    }

我当前的代码仅返回此示例响应

{
    "header": {
        "namespace": "SpeechSynthesizer","name": "Speak","messageId": "35601dca-413f-4788-93ed-305e04328d0e","dialogRequestId": "db933fd9-3766-407d-99f6-2b33d9c814e6","keys": {
            "isBlocking": true,"channel": "audio"
        }
    },"payload": {
        "format": "AUdio_MPEG","token": "amzn1.as-ct.v1.ThirdPartySdkSpeechlet#ACRI#ValidatedSpeakDirective_amzn1.ask.skill.5718d3ec-b56a-4a5a-bd61-fdd4ab501fc2_ca3ae40b-52cd-4be9-b831-98e975a57e5a_VoiceInitiated#ACRI#[[ENCRYPTED_WITH_AlexaServiceKeyMasterUtil]]AAAAAAAAAAAHT6zrrzQh3EDQVwUGrjOpUAAAAAAAAACFZJ/VU0i9/OCY89UvtcV9X0291NLF7L7nE4irlDAGaph7NlUpgq0ps31s8OflwHh/9wr3vp5Py+Gz+2Lgd8N6fPXWxPHP8+E6R8sLiRh9Cg==",}
}

解决方法

如果我没看错,你不会得到那个回复。

您似乎有一台 AVS 设备向 Alexa 语音服务发布音频。

您发送的音频由服务接收,转换为意图和数据,然后发送给您的技能。

您正在寻找的带有“speak”标签的响应由 ASK SDK 从您的技能发送到 Alexa。

Alexa 将其转换为音频并将音频发送到您的 AVS 客户端,但不会发送生成它的技能命令的直接输出副本。您根本无法从响应中解析它。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...