问题描述
我能够设置 Alexa 自定义技能并从我的 IOS 应用程序中调用它。当我在 Alexa 控制台模拟器中测试技能时,我可以看到 JSON 输出,我想从我的 IOS 应用程序中获取它,但是,我在解析它时遇到了问题。我的 IOS 代码运行良好,因为我可以听到来自我的自定义技能的文本响应。
{
"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 客户端,但不会发送生成它的技能命令的直接输出副本。您根本无法从响应中解析它。