IOS 15 SFSpeechURLRecognitionRequest recognises only first phrase from a file - ios

IOS 15 Swift 5.
I want to fully transcribe recorded audio from a file
func transcribeAudio(url: URL) {
let recognizer = SFSpeechRecognizer()
let request = SFSpeechURLRecognitionRequest(url: url)
request.requiresOnDeviceRecognition = true;
request.taskHint = .dictation;
recognizer?.recognitionTask(with: request) { [unowned self] (result, error) in
guard let result = result else {
print("There was an error: \(error!)")
return
}
if result.isFinal {
print(result.bestTranscription.formattedString)
}
}
}
Console output first phrase instead of full text
How can I rewrite a code to transcribe the whole audio file?
Thanks!

The solution was to
Put request and recognizer to class props
Exclude partial results
Print all results, not final one
func transcribeAudio(url: URL) {
request = SFSpeechURLRecognitionRequest(url: url)
request?.requiresOnDeviceRecognition = true;
request?.shouldReportPartialResults = false;
recognizer?.supportsOnDeviceRecognition = true;
recognizer?.recognitionTask(with: request!) { [unowned self] (result, error) in
guard let result = result else {
print("There was an error: \(error!)")
return
}
RNEventEmitter.emitter.sendEvent(withName: "OnRecognition", body: result.bestTranscription.formattedString)
print(result.bestTranscription.formattedString)
}
}

Related

Json data not showing on tableView swift 5

I fetched the data and it is showing when printing but when i try to display it on tableview.Nothing is coming
Am i placing tableview.reloadData in wrong place ?
override func viewDidLoad() {
super.viewDidLoad()
fetchData()
tableView.reloadData()
}
func fetchData()
{
if let url = URL(string: urlConstant) {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, res, err) in
if err == nil
{
let decoder = JSONDecoder()
if let safeData = data
{
do{
let results = try decoder.decode(Results.self, from: safeData)
guard let array = results.Result as? [Products] else {return }
for product in array
{
self.productArray.append(product)
}
} catch {
print(error)
}
}
}
}
task.resume()
}
self.tableView.reloadData()
}
If you are getting correct response(check it once) from the server then next thing you need to reload tableView after getting the response from the server and populating the array.
func fetchData() {
if let url = URL(string: urlConstant) {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, res, err) in
if err == nil
{
let decoder = JSONDecoder()
if let safeData = data
{
do{
let results = try decoder.decode(Results.self, from: safeData)
guard let array = results.Result as? [Products] else {return }
for product in array {
self.productArray.append(product)
}
// Reload table view here
DispatchQueue.main.async {
self.tableView.reloadData()
}
} catch {
print(error)
}
}
}
}
task.resume()
}
}
Alternative, you can add completion handled in fetchData method.

Is it possible to run multiple instances of SFSpeechRecognizer?

I've implemented Apple's SpeechRecognizer to convert speech to text. I have multiple audio recordings so I'm creating mulitple SFSpeechRecognizer instance so that all of those are converted parallely and I've also used DispatchGroup so that I can get completion at last one's end. But I'm keep getting error kAFAssistantErrorDomain error 209.
private var dispatchGroup = DispatchGroup()
allURLs.forEach { (singleURL) in
DispatchQueue.main.async {
thisSelf.dispatchGroup.enter()
let request = SFSpeechURLRecognitionRequest(url: url)
guard let recognizer = SFSpeechRecognizer() else {
thisSelf.dispatchGroup.leave()
completion(.failure(thisSelf.speechReconInitError))
return
}
request.shouldReportPartialResults = false
if !recognizer.isAvailable {
thisSelf.dispatchGroup.leave()
return
}
recognizer.recognitionTask(with: request) { [weak thisSelf] (result, error) in
guard let reconSelf = thisSelf else { return }
if let error = error {
completion(.failure(error))
if let nsError = error as NSError? {
print("Error while transcripting audio: \(url.path), Code, Domain, Description: \(nsError.code), \(nsError.domain), \(nsError.localizedDescription)")
} else {
print("Error while transcripting audio: \(url.path), Error: \(error.localizedDescription)")
}
reconSelf.dispatchGroup.leave()
} else if let transcriptionResult = result, transcriptionResult.isFinal {
transcribedText += transcriptionResult.bestTranscription.formattedString
reconSelf.dispatchGroup.leave()
}
}
thisSelf.dispatchGroup.notify(queue: .main) {
if !transcribedText.isEmpty {
completion(transcribedText)
}
}
}
}
And If I transcribe only one audio to text at one time then I don't get any error.
TIA

I have problems with JSON - Data is repeated

I have a app and problem is repeating the data inside tableView.
How do I fix data replication inside Array ?
func jsonGet(page: Int) {
let pathFull = "https://test.com"
guard let url = URL(string: pathFull) else {return} //
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else {return}
do {
let posts = try JSONDecoder().decode(JobsData.self, from: data)
for post in posts.jobs.data {
self.newsPost.append(post)
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
} catch let jsonErr {
self.alertViewBaisc(title: "erorr", text: "error", button: "ok")
print("Error serializing json", jsonErr)
}
}.resume()
}
Issue is you are keep inserting in newsPost data see self.newsPost.append(post) Line
Replace your code with
func jsonGet(page: Int) {
let pathFull = "https://test.com"
guard let url = URL(string: pathFull) else {return} //
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else {return}
do {
let posts = try JSONDecoder().decode(JobsData.self, from: data)
var tempPost = [DataType]()
for post in posts.jobs.data {
tempPost.append(post)
}
self. newsPost = tempPost
DispatchQueue.main.async {
self.tableView.reloadData()
}
} catch let jsonErr {
self.alertViewBaisc(title: "erorr", text: "error", button: "ok")
print("Error serializing json", jsonErr)
}
}.resume()
}
Also another way is you can check that if post is already in your array or not
(self. newsPost.filter{$0.uniqueKey == post.uniqueKey}.count == 0)
You can clear the arr with every call
self.newsPost.removeAll()
or declare it like
var newsPost = Set<Post>() // this will guarantee uniqueness in a single fetch
also you don't need a for - loop you can directly do
newsPost = posts.jobs.data
apart from the issue
You can use contains to sort out this issue:
let posts = try JSONDecoder().decode(JobsData.self, from: data)
for post in posts.jobs.data {
if self.newPost contains(post){
//Skip
}
else{
self.newsPost.append(post)
}
}
Just replace
for post in posts.jobs.data {
self.newsPost.append(post)
}
with
self.newsPosts = posts.jobs.data
This avoids the redundant repeat loop as well as the duplicate entries since the new data replaces the old.

How to download multiple audio files from url and play offline in App

I want to download multiple audio files from url and play offline in App . This is what i do in my coding but some time array loop stop downloading . And Also I have one more array to download. and this code is only for download. playing audio is working proper.
override func viewDidLoad() {
super.viewDidLoad()
print("Begin of code")
self.linksToUrls()
self.startDownloadingUrls()
print("End of code")
}
// create a function to start the audio data download
func getAudioDataFromUrl(audioUrl:NSURL, completion: #escaping ((_ data: NSData?) -> Void)) {
URLSession.shared.dataTask(with: audioUrl as URL) { (data, response, error) in
completion(data as NSData?)
print("dfdgfdg",data!)
}.resume()
}
// create another function to save the audio data
func saveAudioData(audio:NSData, destination:NSURL) -> Bool {
if audio.write(to: destination as URL, atomically: true) {
print("The file \"\(destination.lastPathComponent!)\" was successfully saved.")
return true
}
return false
}
// just convert your links to Urls
func linksToUrls(){
print("IntroductoryMusicFile1 = count = ",IntroductoryMusicFile1.count)
audioUrls = NewsAudio1
.map() { NSURL(string: $0) }
.filter() { $0 != nil }
print("introcount",IntroductoryMusicFile1.count)
musicUrls = IntroductoryMusicFile1
.map() { NSURL(string: $0) }
.filter() { $0 != nil }
}
// create a loop to start downloading your urls
func startDownloadingUrls(){
arrayplay.removeAll()
//if (musicUrls = "The URL?"){ }
// let syn = SyncBlock()
for url in 0 ... musicUrls.count-1 {
let aaa = musicUrls[url]
let audioType = audioUrls[url]
print(aaa!)
print("audioType",audioType!)
if aaa == NSURL(string: ""){
arrayplay.append("")
}else{
print("Started downloading \"\(String(describing: aaa?.lastPathComponent!))\".")
let url1 = aaa
let request = URLRequest(url: url1! as URL)
let task = URLSession.shared.dataTask(with: request) {data, response, error in
if let httpResponse = response as? HTTPURLResponse {
print("statusCode: \(httpResponse.statusCode)")
if httpResponse.statusCode == 404{
print("Refresh token...")
// self.audioPlay()
self.arrayplay.append("")
}else{
self.getAudioDataFromUrl(audioUrl: aaa!) { data in
DispatchQueue.main.async() {
print("Finished downloading \"\(String(describing: aaa?.lastPathComponent!))\".")
print("Started saving \"\(String(describing: aaa?.lastPathComponent!))\".")
if self.saveAudioData(audio: data!, destination: self.documentsUrl.appendingPathComponent(aaa!.lastPathComponent!)! as NSURL ) {
// do what ever if writeToURL was successful
// print("",data)
self.arrayplay.append(aaa!.lastPathComponent!)
self.data1 = self.arrayplay as! [String]
print("data1",self.data1)
print("",self.data1.count)
if self.data1.count == self.musicUrls.count {
print("complete")
self.downloadDataAnnotation()
}
//self.synk.complete()
// print("abc")
} else {
// print("The File \"\(url.lastPathComponent!.stringByDeletingPathExtension)\" was not saved.")
}
}
}
}
}
}
task.resume()
}
}
}
Can any one suggest me the better code or any other way to download multiple audio file ...

Why nsurlsession.datataskwithrequst was canceled

I am using nsurlsession on RxSwift.
I am facing two problems about nsurlsession on RxSwift.
I created Custom Observable.
This Observable has used nsurlsession.
nsurlsession.datataskwithrequst was canceled everytime on RxSwift.
My code is here
func getWorkInfo(request:NSURLRequest,type1:C.Type,type2:W.Type? = nil) -> Observable<(C?,[W]?, NSHTTPURLResponse)>{
return Observable.create { observer in
var d: NSDate?
if Logging.URLRequests(request) {
d = NSDate()
}
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) { (data, response, error) in
guard let response = response, data = data else {
ColorLogger.defaultInstance?.error(error)
observer.on(.Error(error ?? RxCocoaURLError.Unknown))
return
}
guard let httpResponse = response as? NSHTTPURLResponse else {
observer.on(.Error(RxCocoaURLError.NonHTTPResponse(response: response)))
return
}
guard let jsonString: String = NSString(data:data, encoding:NSUTF8StringEncoding) as? String else{
observer.on(.Error(ApiError.FormatError))
return
}
//カウント系
let countObj = Mapper<C>().map(jsonString)
//一覧系
//二つ目を指定してない場合はnilを返す
if type2 != nil{
let aryObj = Mapper<W>().mapArray(jsonString)
observer.on(.Next(countObj,aryObj, httpResponse))
}else{
observer.on(.Next(countObj,nil, httpResponse))
}
observer.on(.Completed)
}
let t = task
t.resume()
return AnonymousDisposable{task.cancel()}
}
}
Above method was called by here.
func getWorkCount(dicParam: NSDictionary) -> Observable<WorkCount?> {
// URL作成
let strParam = dicParam.urlEncodedString()
let strUrl = Const.ShiftApiBase.SFT_API_DOMAIN+Const.ApiUrl.WORK_COUNT+"?"+strParam
// 求人リストデータを取得
let url = NSURL(string: strUrl)!
let request = NSURLRequest(URL: url)
let client = WorkClient<WorkCount,Work>()
ColorLogger.defaultInstance?.debug(strUrl)
return client.getWorkInfo(request, type1: WorkCount.self)
.observeOn(Dependencies.sharedDependencies.backgroundWorkScheduler)
.catchError{(error) -> Observable<(WorkCount?,[Work]?, NSHTTPURLResponse)> in
print("error")
ColorLogger.defaultInstance?.error("UnknownError")
return Observable.empty()
}
.map { countObj,workObj,httpResponse in
if httpResponse.statusCode != 200 {
throw ApiError.Bad
}
return countObj
}
.observeOn(Dependencies.sharedDependencies.mainScheduler)
}
And My subscribe is here.
/**
検索件数を取得
- parameter param: <#param description#>
*/
func getSearchCount(param: [String:String]){
let dicParam = NSDictionary(dictionary: param)
api.getWorkCount(dicParam)
.catchError{
error -> Observable<WorkCount?> in
switch error{
case ApiError.Bad:
ColorLogger.defaultInstance?.error("status error")
break
case ApiError.FormatError:
ColorLogger.defaultInstance?.error("FormatError")
break
case ApiError.NoResponse:
ColorLogger.defaultInstance?.error("NoResponse")
break
default:
ColorLogger.defaultInstance?.error("UnKnownError")
break
}
return Observable.just(nil)
}
.subscribeNext { [weak self] countObj in
self?.count.value = countObj?.returned_count
}
.addDisposableTo(disposeBag)
}
I have two problems.
1:nsurlsession was canceled every time.I don know reason.
2:Even if I got error on NSURLSession,I could not catch error on "CatchError".
By the way,when i try to use the following code,But nsurlsession might be canceled.
It might be a base nsurlsession on RxSwift.
func getWorkCount4(dicParam: NSDictionary) -> Observable<WorkCount?> {
// URL作成
let strParam = dicParam.urlEncodedString()
let strUrl = Const.ShiftApiBase.SFT_API_DOMAIN+Const.ApiUrl.WORK_COUNT+"?"+strParam
// 求人リストデータを取得
let url = NSURL(string: strUrl)!
let request = NSURLRequest(URL: url)
let session = ApiBase.sharedObj.createNSURLSession()
return NSURLSession.sharedSession().rx_response(request)
.observeOn(Dependencies.sharedDependencies.backgroundWorkScheduler)
.map { data,httpResponse in
if httpResponse.statusCode != Const.HTTP_RESPONSE.HTTP_STATUS_CODE_OK {
throw ApiError.Bad
}
guard let jsonString: String = NSString(data:data, encoding:NSUTF8StringEncoding) as? String else{
throw ApiError.FormatError
}
let countObj = Mapper<WorkCount>().map(jsonString)
return countObj
}
.observeOn(Dependencies.sharedDependencies.mainScheduler)
}
What is this problem?
I could resolve by myself.
Above method does not have any problem.
Below code has problem.
// MARK: - 検索カウント
extension SearchCount{
/// 検索用のViewModel
var searchViewModel:SearchViewModel {
return SearchViewModel()
}
/**
検索の件数を取得
*/
func getSearchCount(){
setApiParameter()
searchViewModel.getSearchCount(apiParam)
}
}
I defined searchViewModel on Class,the i could resolve.

Resources