Twilio Studio Say/Gather Hints - twilio

We are using the Twilio Studio for managing our IVR flows, and have come across an issue when recognising particular numbers.
Example: A verification code that has 22 in it, is being recognised by Twilio as "tutu"
Aside from changing the settings like "recognition language", I'd like to get Twilio to recognise numbers more than other inputs. There is the option for "Speech Recognition Hints" which is a comma separate list of values - but what should you put in there? The documentation just talks about a comma separated list, nothing else!
Any help gratefully received.
Thanks in advance

You could see if entering $OOV_CLASS_DIGIT_SEQUENCE in the hints section has any impact on the captured SpeechResult.
Another option is to run the result through a normalization Twilio Function that converts tutu to 22.
I would recommend DTMF when capturing digits, to avoid this.
// converts number words to integers (e.g. "one two three" => 123)
function convertStringToInteger( str ) {
let resultValue = "";
let arrInput = [];
let valuesToConvert = {
"one": "1",
"two": "2",
"to": "2",
"three": "3",
"four": "4",
"five": "5",
"six": "6",
"seven": "7",
"eight": "8",
"nine": "9",
"zero": "0"
};
str = str.replace(/[.,-]/g," "); // sanitize string for punctuation
arrInput = str.split(" "); // split input into an array
// iterate through array and convert values
arrInput.forEach( thisValue => {
if( ! isNaN(parseInt(thisValue)) ) { // value is already an integer
resultValue += `${parseInt(thisValue)}`;
} else { // non-integer
if( valuesToConvert[thisValue] !== undefined) {
resultValue += valuesToConvert[thisValue];
} else {
// we don't know how to interpret this number..
return false;
}
}
});
console.log('value converted!', str, ' ====> ', resultValue);
return resultValue;
}

Related

insert a character inside an Int Swift

I have a number, I want to insert a column ":" between each two consecutive digits inside that number, and get a String as a result
For example:
let number: Int = 34567
let result: String = "3:4:5:6:7"
Thanks for any help,
Possible solution:
let result = String(number).map({ String($0) }).joined(separator: ":")
With explanation of intermediary results to help understand what's going on on theses 3 chained methods:
let interemdiary1 = String(number)
print("interemdiary1: \(interemdiary1)")
let interemdiary2 = interemdiary1.map({ String($0 )})
print("interemdiary2: \(interemdiary2)")
let interemdiary3 = interemdiary2.joined(separator: ":")
print("interemdiary3: \(interemdiary3)")
Output:
$>interemdiary1: 34567
$>interemdiary2: ["3", "4", "5", "6", "7"]
$>interemdiary3: 3:4:5:6:7
First, let's transform your number into a String.
Then, let's create an array of it where each character (as a String) of the previous result is an element of it. I used a map() of it.
Finally, we use joined(separator:) to assemble them.
Another kind of solution can be found there:
How add separator to string at every N characters in swift? It's just that you do it each 1 characters.
You need to join it by :
use this
let result = String(number).map({String($0)}).joined(separator: ":")

Sorting Big Int value in Swift

I have a problem to sort some numbers, which are string first. The numbers are too huge for UInt64, so i converted the string numbers to float and then sorted it. That works out great. But then i need to print these numbers with no decimals. So I tried to format the numbers. But the Bigger number are changing its value after formatting it.
Here is the Input array to sort -
["6","31415926535897932384626433832795","1","3","10","3","5"]
And I need to print output in exactly this format -
1
3
3
5
10
31415926535897932384626433832795
Here is my code in swift -
import Foundation
var a = Array<Float>()
var b = ["6","31415926535897932384626433832795","1","3","10","3","5"]
a = b.map{ Float($0)! }
for i in 0..<(a.count-1){
var min = i
for j in (i+1)..<a.count{
if a[j] < a[min] {
min = j
}
}
var temp = a[i]
a[i] = a[min]
a[min] = temp
}
for val in a{
print(String(format: "%.0f",val.rounded(.down)))
}
My Output is -
1
3
3
5
6
10
31415927314585224784361549725696
If you notice the last biggest number is changed from the original input. Any suggestions would be much appreciated! Thanks!
You can use numeric comparison:
let values = ["6","31415926535897932384626433832795","1","3","10","3","5"]
let sortedValues = values.sorted { (value1, value2) in
let order = value1.compare(value2, options: .numeric)
return order == .orderedAscending
}
print(sortedValues) // ["1", "3", "3", "5", "6", "10", "31415926535897932384626433832795"]
With using float, you may get unexpected result for orders between big ints:
var str = "Hello, playground"
let inArray = [
"6",
"31415926535897932384626433832797",
"31415926535897932384626433832796",
"31415926535897932384626433832795",
"1",
"3"
]
let outArray = inArray.sorted {Float($0)! < Float($1)!}
print(outArray)
//->["1", "3", "6", "31415926535897932384626433832797", "31415926535897932384626433832796", "31415926535897932384626433832795"]
As described in mag_zbc's answer, Float has about only 7 significant digits, so all less significant digits are lost.
Float("31415926535897932384626433832797") == Float("31415926535897932384626433832795")
//->true
If the digits of your numbers are 38 at most, you can use Decimal (as also suggested in mag_zbc's answer).
let outWithDecimal = inArray.sorted {Decimal(string: $0)! < Decimal(string: $1)!}
print(outWithDecimal)
//->["1", "3", "6", "31415926535897932384626433832795", "31415926535897932384626433832796", "31415926535897932384626433832797"]
Or else, if your data contains numbers with more than 38 digits, String comparison would work with a little pre-processing:
(Assuming all your numbers are non-negative integer.)
extension String {
func fillZeroLeft(_ length: Int) -> String {
if self.characters.count < length {
return String.init(repeating: "0", count: length-self.characters.count) + self
} else {
return self
}
}
}
let maxLen = inArray.lazy.map{$0.characters.count}.max()!
let outWithString = inArray.sorted {$0.fillZeroLeft(maxLen) < $1.fillZeroLeft(maxLen)}
print(outWithString)
//->["1", "3", "6", "31415926535897932384626433832795", "31415926535897932384626433832796", "31415926535897932384626433832797"]
(But numeric comparison in Sulthan's answer seems to be better for me!)
It's impossible to accurately represent such big numbers using primitive types in Swift.
Your value is ~3e+32
UInt64 has a max value of ~1,8e+18
Float uses 24 bits for a significant, which allows to accurately represent a number up to ~1.6e+8
Double uses 53 bits for significant, which allows to accurately represent a number up to ~9e+15
Floating point types (Float and Double) are able to hold much greater values, but they will lose accuracy above the numbers their significants can hold.
Apart from using some external library, I'd suggest using NSDecimalNumber class, which is supposed to be able to hold up to 38 decimal digits - which is enough for numbers in your example. However, if you need even bigger numbers, then you'll need to look for some external library.

Matching an exact key in SwiftyJson

I'm really having trouble with determining a specific value returned in SwiftyJson; hopefully, someone can help explain this to me.
I want to see if there is a match between a predetermined word, "apple" to any of the words received from the JSON responses.
If there is a match then a message is displayed, and the user either chooses to progress to the next level or the user returns to the home screen.
If there is no match then a message is displayed, and the user must either continue playing or cancel playing.
I would like to do this for multiple words across different levels of the game.
Level one: match "apple" to any of the received JSON responses.
Level two: match "computer" to any of the received JSON responses.
Level three: match "telephone" or "phone" or "iPhone" or "Android" or any or all of the above to any of the received JSON responses.
So, basically, I can get all of the JSON responses, but I'm having a hard time finding out how to set up to determine if there is a specific, predefined JSON response returned.
I have looked everywhere for weeks with another post but to no avail :(
JSON RESPONSES
{
"responses" : [
{
"labelAnnotations" : [
{
"mid" : "\/m\/01m2v",
"score" : 0.9245476,
"description" : "computer keyboard"
},
{
"mid" : "\/m\/01c648",
"score" : 0.7945268,
"description" : "laptop"
},
{
"mid" : "\/m\/01mfj",
"score" : 0.74227184,
"description" : "computer hardware"
},
{
"mid" : "\/m\/0541p",
"score" : 0.7062791,
"description" : "multimedia"
},
{
"mid" : "\/m\/07c1v",
"score" : 0.7039645,
"description" : "technology"
},
{
"mid" : "\/m\/03gq5hm",
"score" : 0.69323385,
"description" : "font"
},
{
"mid" : "\/m\/0bs7_0t",
"score" : 0.6724673,
"description" : "electronic device"
},
{
"mid" : "\/m\/01vdm0",
"score" : 0.66489816,
"description" : "electronic keyboard"
},
{
"mid" : "\/m\/0121tl",
"score" : 0.60392517,
"description" : "electronic instrument"
},
{
"mid" : "\/m\/0h8n5_7",
"score" : 0.5834592,
"description" : "laptop replacement keyboard"
}
]
}
]
}
CODE TO SHOW ALL JSON RESPONSES
// Use SwiftyJSON to parse results
let json = JSON(data: dataToParse)
let errorObj: JSON = json["error"]
// Parse the response
print(json)
let responses: JSON = json["responses"][0]
// Get label annotations
let labelAnnotations: JSON = responses["labelAnnotations"]
let numLabels: Int = labelAnnotations.count
var labels: Array<String> = []
if numLabels > 0 {
var labelResultsText:String = "Labels found: "
for index in 0..<numLabels {
let label = labelAnnotations[index]["description"].stringValue
labels.append(label)
}
for label in labels {
// if it's not the last item add a comma
if labels[labels.count - 1] != label {
labelResultsText += "\(label), "
} else {
labelResultsText += "\(label)"
}
}
self.labelResults.text = labelResultsText
} else {
self.labelResults.text = "No labels found"
}
EDIT
I'm apparently not able to answer my own question, I'll post an edit since I think it's a better solution but #pierce's was pretty decent for a single word, not many; it just wasn't applicable for a game setting application.
So, I created a new NSObject, created a
static var _words: [[String]] = [
["apple", "computer", "beer"]]
then
func checkAnnotations(annotations: [Annotation]) -> Bool {
var isMatched = false
let searchWords = self.words
for searchWord in searchWords {
for annotation in annotations {
if searchWord == annotation.descriptionString {
isMatched = true
break
}
}
if isMatched {
break
}
}
return isMatched
}
then created a function to handle the level state,
and finally compared that to the JSON response in the View Controller and advanced level if matched
// Get JSON key value
let labelAnnotations = responses["labelAnnotations"].arrayValue
let annotationObjects: [Annotation] = labelAnnotations.flatMap({ annotationDictionary in
if let mid = annotationDictionary["mid"].string,
let score = annotationDictionary["score"].double,
let description = annotationDictionary["description"].string {
let annotation = Annotation(mid: mid, score: score, descriptionString: description)
return annotation
}
return nil
})
//print(annotationObjects)
let searchString = LevelState.shared.words[0]
print("Level \(LevelState.shared.level), looking for: \(searchString)")
var isMatched = LevelState.shared.checkAnnotations(annotations: annotationObjects)
if isMatched {
LevelState.shared.advance()
}
let alertTitle = isMatched ? "Congrats! You got \(searchString)" : "Keep looking for \(searchString)"
//let translationResult = "Translated: \(levelDescription) to \(translatedText)"
let alertController = UIAlertController(title: alertTitle, message: nil, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alertController, animated: true, completion: nil)
}
self.prepareForNewLevel()
})
}
First thing - I really don't understand why you want to append a comma at the end of each description. I really thing that's unnecessary. Are you confused about separating elements in an array? Because the actual Strings don't require that, it's only if you're manually writing out the elements of an array (i.e. let array = ["a", "b", "c"]).
So then say you setup a property for this labels array, which is an array of Strings.
var labels: Array<String> = []
Once you've gone through and appended all the description values from your JSON, you can then manipulate it.
if numLabels > 0 {
for index in 0..<numLabels {
let label = labelAnnotations[index]["description"].stringValue
labels.append(label)
}
}
Now you could create a method that would return a filtered array of Strings based on some user entered word:
func findMatches(_ userEntry: String) -> [String] {
return labels.filter { $0.contains(userEntry) }
}
Now you could use the above method to handle some sort of user entry, like say you had the text from a UITextField named textField:
// Return the filtered matches based on the textField text (unless nil)
let matches = findMatches(textField.text ?? "")
// Print the number of matches, and also show the matches
print("Found \(matches.count) matches to user input\r\(matches)")
Now if you had labels which held ["a", "aa", "ba", "b", "c", "apple"], and ran the above code where the userEntry was just the letter "a", you'd see this print out in the console window:
Found 4 matches to user input
["a", "aa", "ba", "apple"]
EDIT - You can use the findMatches method above for what you're trying to do with pre-determined words to match. I'm not sure what you're trying to do exactly, but there are a couple different ways. First, say you had an array of pre-determined words you wanted to check as an array:
let words = ["word", "verb", "noun", "adverb"]
Then you could loop through that and check each one
for word in words {
let matches = findMatches(word)
if matches.count > 0 {
print("Found \(matches.count) matches to \(word)\r\(matches)")
} else {
// Do whatever you want when there are no matches
print("No matches found")
}
}
If you want to just check for a specific word, and have a specific response you could setup a method like so:
func checkWord(word: String, noMatchResponse: String) {
let matches = findMatches(word)
if matches.count > 0 {
print("Found \(matches.count) matches to \(word)\r\(matches)")
} else {
// Do whatever with the no match response
print(noMatchResponse)
}
}
There are so many ways you could implement this. You could also use a switch statement, and then use different case statements for each pre-determined word. It's really up to you and how you want to design your game.

Recursive Array Manipulation in Swift

I have a custom array used by a calculator, the array acts as an RPN stack. Many real life RPN calculators allow manipulation of the stack, and I am working on the same. To get an idea an example stack would be:
["1", "2", "+"] which would evaluate to 3. The core of it is the operations follow the operands.
["2", "1", "2", "+" "x"] evaluates to 6
["3.1415", "sin"] evaluates to 0
I would like to be able to "roll my stack" As in take the currently evaluated expression at the very end of the stack and roll it to the front. The problem is the operators, as the amount of binary and unary operators changes the way the stack is rotated.
["100", "1", "2", "+"]still would evaluate to 3, because 100 has not been accessed by an operator.
I need a way to recursively roll the stack, to take the last set of evaluated operands and roll it in front off all the operands yet to be evaluated.
Example:
["100", "1", "2", "+"] would roll to ["1", "2", "+", "100",] then ["100", "2", "1", "2", "+" "x"]would roll to ["2", "1", "2", "+" "x", "100"] and ["100", "3.1415", "sin"] would roll to ["3.1415", "sin","100"]
I am having problem with this, and the recursion of it. Currently I am doing this:
// safeRoll
func rollOpStack() {
var lastIndex = opStack.count - 1
var tmp: Op = opStack[lastIndex]
switch tmp {
case .UnaryOperation:
if opStack.count >= 2 {
var tmp2: Op = opStack[lastIndex - 1]
var appender: [Op] = [tmp2, tmp]
opStack.removeLast()
opStack.removeLast()
var appended: [Op] = appender + opStack
opStack = appended
}
case .BinaryOperation:
if opStack.count >= 3 {
var tmp2: Op = opStack[lastIndex - 1]
var tmp3: Op = opStack[lastIndex - 2]
var appender: [Op] = [tmp3, tmp2, tmp]
opStack.removeLast()
opStack.removeLast()
opStack.removeLast()
var appended: [Op] = appender + opStack
opStack = appended
}
default:
if opStack.count > 0 {
opStack.removeLast()
println(opStack)
opStack.insert(tmp, atIndex: 0)
}
}
}
This works... until more binary or unary operators are applied than just one, because the function is not recursive. How can I roll the stack recursively, and ensure that the entirety of the last evaluated list is rolled to the front of the stack? Thanks for the help.
This should do the trick:
func beginningIndexForOperationEndingAt(index: Int) -> Int? {
if index < 0 || index >= opStack.count {
return nil
}
switch opStack[index] {
case .UnaryOperation:
return beginningIndexForOperationEndingAt(index-1)
case .BinaryOperation:
if let firstOp = beginningIndexForOperationEndingAt(index-1) {
return beginningIndexForOperationEndingAt(firstOp-1)
}
return nil
default:
return index
}
}
If you call beginningIndexForOperationEndingAt(opStack.count-1) you will get the starting index for the last full operation, which you can then splice from the end of the array to the beginning
func rollOpStack() {
if let index = beginningIndexForOperationEndingAt(opStack.count-1) {
var newArray = opStack[index..<opStack.count]
newArray += opStack[0..<index]
var i = 0
for op in newArray {
opStack[i++] = op
}
} else {
//No complete operation...
}
}
Let me know if you run into any issues. Hope this helps! If it does, please don't forget to mark my answer as accepted! Thanks.

Error when trying to convert string to a double

I am trying to convert a String into a Double value in Swift. After doing a lot of research, I believe that this would be the best method to turn my string to an Double. But now I am getting an error that I have no idea of how to fix.
var purchaseAmount: Double = 200
var cashTendered: Double = 425.45
var changeRequired: Double = 0
var currencyValues = ["100", "50", "20", "10", "5", "2", "1", "0.50", "0.20", "0.10", "0.05"]
import Cocoa
if cashTendered < purchaseAmount {
println("Not enough cash tendered")
} else {
changeRequired = cashTendered - purchaseAmount
for currency in currencyValues {
var doubleCurrency = (currency as NSString).doubleValue
var amountOfCurrency = changeRequired / doubleCurrency
amountOfCurrency = floor(amountOfCurrency)
changeRequired = changeRequired - (amountOfCurrency * currency)
changeRequired = round(changeRequired * 100)/100
println("$\(currency) X \(Int(amountOfCurrency))")
}
}
Here is the error:
What do I have to do to solve this problem?
First of all initialise String array like below:
let currencyValues : [String] = ["100", "50", "20", "10", "5", "2", "1", "0.50", "0.20", "0.10", "0.05"]
However it is not required type declaration because of Swift has vital feature Type Interface. But most of the practice it is good to define type while working with array.
And about converting string to double you can use below code:
for currency : String in currencyValues {
let doubleCurrency = NSNumberFormatter().numberFromString(currency)!.doubleValue
print(doubleCurrency)
}
Posting code would be easier to look at than an image, but if all else fails there is NSNumberFormatter. Other advantage of NSNumberFormatter would allow you to convert both directions and get nice output for things like currency.

Resources