Fetch "transcript" values from Google speech api - ios

I am trying to fetch the "transcript" value from the following result:
{
transcript: "1 2 3 4"
confidence: 0.902119
words {
start_time {
nanos: 200000000
}
end_time {
nanos: 700000000
}
word: "1"
}
words {
start_time {
nanos: 700000000
}
end_time {
nanos: 900000000
}
word: "2"
}
words {
start_time {
nanos: 900000000
}
end_time {
seconds: 1
}
word: "3"
}
words {
start_time {
seconds: 1
}
end_time {
seconds: 1
nanos: 300000000
}
word: "4"
}
}
The code I am writing to get it is :
for result in response.resultsArray! {
if let result = result as? StreamingRecognitionResult {
for alternative in result.alternativesArray {
if let alternative = alternative as? StreamingRecognitionResult {
textView.text = "\(alternative["transcript"])"
}
}
}
}
So when I am trying to put the value in textview.text I am getting an error stating :
"Type 'StreamingRecognitionResult' has no subscript members ".
Please help.

The key lines are:
let tmpBestResult = (response.resultsArray.firstObject as! StreamingRecognitionResult)
let tmpBestAlternativeOfResult = tmpBestResult.alternativesArray.firstObject as! SpeechRecognitionAlternative
let bestTranscript = tmpBestAlternativeOfResult.transcript
The placement of these lines inside the streamAudioData() is given below:
SpeechRecognitionService.sharedInstance.streamAudioData(audioData,languageCode: self.selectedLangType.rawValue,
completion:
{ [weak self] (response, error) in
guard let strongSelf = self else {
return
}
if let error = error {
debugPrint(">>)) Process_delegate error >> \(error.localizedDescription)")
strongSelf.stopRecordingSpeech()
self?.delegate.conversionDidFail(errorMsg: error.localizedDescription)
} else if let response = response {
var finished = false
debugPrint(response)
for result in response.resultsArray! {
if let result = result as? StreamingRecognitionResult {
if result.isFinal {
finished = true
}
}
}
let tmpBestResult = (response.resultsArray.firstObject as! StreamingRecognitionResult)
let tmpBestAlternativeOfResult = tmpBestResult.alternativesArray.firstObject as! SpeechRecognitionAlternative
let bestTranscript = tmpBestAlternativeOfResult.transcript
strongSelf.delegate.conversionOnProcess(intermediateTranscript: bestTranscript!, isFinal: finished)
if finished {
//UI
strongSelf.stopRecordingSpeech()
strongSelf.delegate.conversionDidFinish(finalTranscript: bestTranscript!)
}
}
})
Happy Coding ;)

So the code will be changed to this:
for alternative in result.alternativesArray {
if let alternative1 = alternative as? SpeechRecognitionAlternative {
textView.text = "\(alternative1.transcript)"
}
}

Related

Wrong Print Order With Web Request

I am trying to read data from Google Sheet API and get the last 5 rows. Here is my function:
func fetchData() {
let range = "TestSheet"
var convertedLogList : [Log] = []
var fetchResult: [[String]] = []
let query = GTLRSheetsQuery_SpreadsheetsValuesGet.query(withSpreadsheetId: Globals.shared.YOUR_SHEET_ID, range: range)
Globals.shared.sheetService.executeQuery(query) { (ticket, result, error) in
if let error = error {
print(error)
return
}
guard let values = (result as? GTLRSheets_ValueRange)?.values else {
print("No data found.")
return
}
fetchResult = values.map { $0.map { $0 as? String ?? "" } }
for row in fetchResult {
// convert [String] to a Log object
var log = Log()
log.timestamp = row[0]
log.nthTime = row[1]
log.openNew = row[2]
if row.count == 4 {
log.note = row[3]
}
convertedLogList.append(log)
}
print("===== convertedLogList: ", convertedLogList)
}
var latestLogs : [Log] = []
var counter = 0
// take the latest 5 logs
for log in convertedLogList.reversed() {
if counter < convertedLogList.count && counter < 5 {
counter += 1
latestLogs.append(log)
} else {
break
}
}
print("+++++ latestLogs: ", latestLogs)
}
I have 2 print statements in my code but the print order is wrong. Here is the print output:
+++++ latestLogs: []
===== convertedLogList: [Log(id: xxxxxxxxx, timestamp: "10/24/2022", nthTime: "1", openNew: "Yes", note: "), Log(id:xxxxxxx,....) .... ]
I wonder why the print order is wrong. How can I utilize the await with Google Sheet API in Swift to solve this issue?

How to fix memory issues given by Instrument tools in Swift?

I have memory issues, especially for the error
XPC connection interrupted
The screen is freezing for a few seconds..
So, I've been learning how to use the Instruments tools and try to fix this error. However, I've been trying to find the error in my code and it's apparently not the fault of my code but maybe the libraries?
As a result of this test, I've got some warnings (the purple ones):
Memory Issues (3 leaked types):
- 1 instance of _DateStorage leaked (0x10b1eb060)
- 1 instance of OS_dispatch_data leaked (0x10b0b1ac0)
- 1 32-byte malloc block leaked (x10b1eb040)
Could you tell me how to fix these warnings, knowing there is no backtrace available? Or how could I find somewhere that could tell me to fix those?
EDIT:
Thanks to Instrument tools, I found the function that caused the problem! So, I don't know if it is really about memory or Idk but here's the function!
The accurate and useful error I get is : "Closure #1 in closure #1 in MessagesTableViewController.getLastMessages"
I found here What is a closure #1 error in swift?, the error is probably caused by forced optional types. So, I am going to try to remove those.
func getLastMessages(cell: ContactMessageTableViewCell, index: IndexPath) {
// first, we get the total number of messages in chatRoom
var numberOfMessagesInChatRoom = 0
let previousCellArray = self.tableView.visibleCells as! [ContactMessageTableViewCell]
var index1 = 0
var messages = [JSQMessage]()
var sortedMessages = [JSQMessage]()
var messagesSortedByChatRooms = [String: [JSQMessage]]()
var doesHaveMessagesCount = false
var doesHaveSortedMessagesCount = false
let firstQuery = Constants.refs.databaseChats.queryOrderedByKey()
_ = firstQuery.observe(.childAdded, with: { [weak self] snapshot in
if let data = snapshot.value as? [String: String],
let id = data["sender_id"],
let name = data["name"],
let text = data["text"],
let chatRoom = data["chatRoom"],
!text.isEmpty
{
if let message = JSQMessage(senderId: id, displayName: name, text: text)
{
messages.append(message)
var arrayVariable = [JSQMessage]()
// we wanna get all messages and put it in the array corresponding to the chat room key
if messagesSortedByChatRooms[chatRoom] != nil { // if there is already the chatRoom key in dictionary
if let message1 = messagesSortedByChatRooms[chatRoom] {
arrayVariable = message1
}
arrayVariable.append(message)
messagesSortedByChatRooms[chatRoom] = arrayVariable
} else { // if there isn't the chatRoom key
arrayVariable.append(message)
messagesSortedByChatRooms[chatRoom] = arrayVariable
}
}
}
DispatchQueue.main.async {
// we have to sort messages by date
for (chatRoom, messagesArray) in messagesSortedByChatRooms {
var loopIndex = 0
var lastMessage: JSQMessage?
var array = [JSQMessage]()
for message in messagesArray { // we run through the messages array
array.removeAll()
loopIndex += 1
if loopIndex != 1 {
if message.date > lastMessage!.date {
array.append(message)
messagesSortedByChatRooms[chatRoom] = array
} else {
array.append(lastMessage!)
messagesSortedByChatRooms[chatRoom] = array
}
} else {
lastMessage = message
if messagesArray.count == 1 {
array.append(message)
messagesSortedByChatRooms[chatRoom] = array
}
}
}
}
if !doesHaveMessagesCount {
//doesHaveMessagesCount = true
// we have the number of chats in database
let secondQuery = Constants.refs.databaseChats.queryOrderedByPriority()
_ = secondQuery.observe(.childAdded, with: { [ weak self] snapshot in
if let data = snapshot.value as? [String: String],
let id = data["sender_id"],
let name = data["name"],
let text = data["text"],
let chatRoom = data["chatRoom"],
!text.isEmpty
{
if let message = JSQMessage(senderId: id, displayName: name, text: text)
{
index1 += 1
if chatRoom != nil {
if let unwrappedSelf = self {
if unwrappedSelf.sortedChatRoomsArray.contains(chatRoom) {
sortedMessages.append(message)
for (chatRoomKey, messageArray) in messagesSortedByChatRooms {
unwrappedSelf.lastMessages[chatRoomKey] = messageArray[0]
}
}
}
}
if let unwrappedSelf = self {
if index1 == messages.count && chatRoom != unwrappedSelf.roomName {
sortedMessages.append(JSQMessage(senderId: id, displayName: name, text: "no message"))
}
}
}
}
DispatchQueue.main.async {
if let unwrappedSelf = self {
if !doesHaveSortedMessagesCount {
//doesHaveSortedMessagesCount = true
if unwrappedSelf.sortedChatRoomsArray.indices.contains(index.row) {
if unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]] != nil {
if unwrappedSelf.lastMessagesArray.count != 0 {
let currentChatRoom = unwrappedSelf.sortedChatRoomsArray[index.row]
if unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.text != "no message" {
if UUID(uuidString: unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]!.text) == nil {
cell.contactLastMessageLabel.text = unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.text
} else {
cell.contactLastMessageLabel.text = "New image"
}
} else {
cell.contactLastMessageLabel.text = ""
cell.contactLastMessageLabel.font = UIFont(name:"HelveticaNeue-Light", size: 16.0)
}
if unwrappedSelf.lastMessagesArray.indices.contains(index.row) {
if unwrappedSelf.lastMessagesArray[index.row] != unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.text {
if unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.senderId != PFUser.current()?.objectId {
if unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.text != "no message" {
cell.contactLastMessageLabel.font = UIFont(name:"HelveticaNeue-Bold", size: 16.0)
}
var numberOfDuplicates = 0
for cell in previousCellArray {
if cell.contactLastMessageLabel.text == unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]?.text {
numberOfDuplicates += 1
}
}
if numberOfDuplicates == 0 {
if unwrappedSelf.selectedUserObjectId != "" {
unwrappedSelf.changeCellOrder(index: index.row, selectedUserObjectId: unwrappedSelf.selectedUserObjectId, lastMessage: unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]!.text)
} else {
unwrappedSelf.changeCellOrder(index: index.row, selectedUserObjectId: "none", lastMessage: unwrappedSelf.lastMessages[unwrappedSelf.sortedChatRoomsArray[index.row]]!.text)
}
} else {
unwrappedSelf.tableView.reloadData()
}
cell.activityIndicatorView.stopAnimating()
}
} else {
cell.contactLastMessageLabel.font = UIFont(name:"HelveticaNeue-Light", size: 16.0)
}
}
}
} else {
}
}
}
}
}
})
}
}
})
}
FINL EDIT: I put a closure inside of another closure so it created an infine loop ;)

iOS Swift convenience initializer self used before self.init called

so I have been trying to create a "Period" class, with the following attributes:
class PTPeriod {
// MARK: Stored Properties
var start: Date
var end: Date
var place: PTPlace?
//MARK: DESIGNATED NITIALIZER
init(start: Date, end: Date, place: PTPlace? = nil) {
self.start = start
self.end = end
self.place = place
}
And I want to initialize it with a convenience init that accepts a dictionary like the following:
{
"close" : {
"day" : 1,
"time" : "0000"
},
"open" : {
"day" : 0,
"time" : "0900"
}
}
This is my initializer, originally I put the heavy lifting into a helper method. However, i was getting the same error I have now so I removed the helper method and the error is still occurring. Unsure where it thinks I am calling self.
UPDATE: moved the date formatting into a date formatter extension, but the error still persists! unsure WHY. new init shown:
My new Convenience init:
// MARK: Convenience init for initializing periods pulled from Google Place API
convenience init?(placeData: [String:Any], place: PTPlace? = nil) throws {
var start: Date? = nil
var end: Date? = nil
var formatter = DateFormatter()
do {
for (key, value) in placeData {
let period = value as! [String: Any]
if (key == "open") {
start = try formatter.upcoming_date(with: period)
} else if (key == "close") {
end = try formatter.upcoming_date(with: period)
} else {
break
}
}
if (start != nil && end != nil) { self.init(start: start!, end: end!, place: place) }
else { print("we f'd up") }
}
catch { print(error.localizedDescription) }
}
Here is my DateFormatter.upcoming_date method:
func upcoming_date(with googlePlacePeriod: [String: Any]) throws -> Date? {
if let day = googlePlacePeriod["day"] as? Int {
if (day < 0) || (day > 6) { throw SerializationError.invalid("day", day) } // throw an error if day is not between 0-6
if let time = googlePlacePeriod["time"] as? String {
if time.characters.count != 4 { throw SerializationError.invalid("time", time) } // throw an error if time is not 4 char long
var upcoming_date: Date
let gregorian = Calendar(identifier: .gregorian)
let current_day_of_week = Date().getDayOfWeekInt()
let dayOfPeriod = day + 1
///TRUST THAT THIS WORKS... NO JODAS
var distance = dayOfPeriod - current_day_of_week // inverse = false
if (dayOfPeriod < current_day_of_week) {
switch distance {
case -1: distance = 6
case -2: distance = 5
case -3: distance = 4
case -4: distance = 3
case -5: distance = 2
case -6: distance = 1
default: break
}
}
/** time example: "1535" translates into 3:35PM
first two characters in string are "hour" (15)
last two characters in string are "minute(35)
**/
let hour = Int(time.substring(to: time.index(time.startIndex, offsetBy: 2)))!
let minute = Int(time.substring(from: time.index(time.endIndex, offsetBy: -2)))
upcoming_date = Date().fastForward(amount: distance, unit: "days", inverse: false)!
var components = gregorian.dateComponents([.year, .month, .day, .hour, .minute, .second], from: upcoming_date)
components.hour = hour
components.minute = minute
upcoming_date = gregorian.date(from: components)!
return upcoming_date
}
else { throw SerializationError.missing("time") }
}
else { throw SerializationError.missing("day") }
}
You have a failable initializer, so if it fails, you must return nil to let it know it failed:
if (start != nil && end != nil) {
self.init(start: start!, end: end!, place: place) }
} else {
print("we f'd up")
return nil
}
Also, in your do-catch, you need to either
re-throw the error in the catch block
catch {
print(error.localizedDescription)
throw error
}
eliminate the do-catch blocks altogether; or
just return nil:
catch {
print(error.localizedDescription)
return nil
}
If you do this, you'd presumably not define this failable initializer as one that throws because you're no longer throwing.
Given that you're unlikely to do anything meaningful with the thrown error, I'd just make it a failable initializer that doesn't throw:
convenience init?(placeData: [String: Any], place: PTPlace? = nil) {
var start: Date?
var end: Date?
let formatter = DateFormatter()
for (key, value) in placeData {
let period = value as! [String: Any]
if key == "open" {
start = try? formatter.upcoming_date(with: period)
} else if key == "close" {
end = try? formatter.upcoming_date(with: period)
} else {
break // I'm not sure why you're doing this; it seems extremely imprudent (esp since dictionaries are not ordered)
}
}
if let start = start, let end = end {
self.init(start: start, end: end, place: place)
} else {
print("either start or end were not found")
return nil
}
}

How to reduce the fetch time of CNContacts?

Hi am using CNContacts to fetch my contacts but takes around two minutes to display all the contacts in swift.Is there any way to speed up my Fetching time?
do
{
try store.enumerateContactsWithFetchRequest(request)
{ contact, stop in
contacts.append(contact)
}
}
catch
{
print(error)
}
for contact in contacts
{
let formatter = CNContactFormatter()
formatter.style = .FullName
if(((formatter.stringFromContact(contact))) != nil)
{
for phoneNumber:CNLabeledValue in contact.phoneNumbers
{
let number = (contact.phoneNumbers[0].value as! CNPhoneNumber).valueForKey("digits") as! String
let lable :String = CNLabeledValue.localizedStringForLabel(phoneNumber.label)
if (lable.containsString("mobile"))
{
if((contact.emailAddresses.isEmpty))
{
self.Allemail.addObject((""))
}
else
{
self.Allemail.addObject((contact.emailAddresses[0].value))
}
self.Contactname=NSString(format:"'%#'",(formatter.stringFromContact(contact))!)
let contactnumber=NSString(format:"'%#'",number)
self.ContactsDictionary.addObject(self.Contactname)
self.allNumbers.addObject(contactnumber as String)
}
}
for i in 0..<self.ContactsDictionary.count
{
if(i == 0)
{
self.jsonstring = "[{'Name':\(self.ContactsDictionary.objectAtIndex(i)),'Number':\(self.allNumbers.objectAtIndex(i))}"
}else
{
self.jsonstring = "\(self.jsonstring),{'Name':\(self.ContactsDictionary.objectAtIndex(i)),'Number':\(self.allNumbers.objectAtIndex(i))}"
}
}
self.jsonstring = "\(self.jsonstring)]"
}
}
self.contactupload()

NSExpression Calculator in Swift

I am trying to duplicate Need to write calculator in Objective-C in Swift but my code is not working.
import Foundation
var equation:NSString = "5*(2.56-1.79)-4.1"
var result = NSExpression(format: equation, argumentArray: nil)
println(result)
As already said in a comment, you have to call expressionValueWithObject()
on the expression:
let expr = NSExpression(format: equation)
if let result = expr.expressionValueWithObject(nil, context: nil) as? NSNumber {
let x = result.doubleValue
println(x)
} else {
println("failed")
}
Update for Swift 3:
let expr = NSExpression(format: equation)
if let result = expr.expressionValue(with: nil, context: nil) as? Double {
print(result) // -0.25
} else {
print("failed")
}
Details
Xcode 9.4.1, Swift 4.1
Xcode 10.2.1 (10E1001), Swift 5
Solution
import Foundation
extension String {
private func allNumsToDouble() -> String {
let symbolsCharSet = ".,"
let fullCharSet = "0123456789" + symbolsCharSet
var i = 0
var result = ""
var chars = Array(self)
while i < chars.count {
if fullCharSet.contains(chars[i]) {
var numString = String(chars[i])
i += 1
loop: while i < chars.count {
if fullCharSet.contains(chars[i]) {
numString += String(chars[i])
i += 1
} else {
break loop
}
}
if let num = Double(numString) {
result += "\(num)"
} else {
result += numString
}
} else {
result += String(chars[i])
i += 1
}
}
return result
}
func calculate() -> Double? {
let transformedString = allNumsToDouble()
let expr = NSExpression(format: transformedString)
return expr.expressionValue(with: nil, context: nil) as? Double
}
}
Usage
"3*(3-1)-5".calculate()
Full sample
func test(_ expressrion: String) {
if let num = expressrion.calculate() {
print("\(expressrion) = \(num)")
} else {
print("\(expressrion) = nil")
}
}
test("3*(3-1)-5")
test("5.2*(2-1.79)-5.1")
test("11/5")
Results

Resources