From 6230c34eaee6498ad6bf1be9bd0db3a667aea234 Mon Sep 17 00:00:00 2001 From: Kwangsoo Yeo Date: Wed, 10 May 2023 17:45:42 -0700 Subject: [PATCH 01/15] add multilingual demo and initial lint fix --- .gitignore | 6 +- .../ios/Runner/AppDelegate.swift | 14 +- demo/flutter/ios/Runner/AppDelegate.swift | 14 +- .../ios-swiftui/BaristaDemo/ContentView.swift | 39 ++- demo/ios-swiftui/BaristaDemo/ViewModel.swift | 53 ++- .../ContentView.swift | 25 +- .../NotificationManager.swift | 18 +- .../project.pbxproj | 24 +- ...PicovoiceForegroundAppDemoUITests.xcscheme | 52 --- .../xcshareddata/xcschemes/arDemo.xcscheme | 53 +++ .../xcshareddata/xcschemes/deDemo.xcscheme | 53 +++ ...groundAppDemo.xcscheme => enDemo.xcscheme} | 39 ++- .../xcshareddata/xcschemes/esDemo.xcscheme | 53 +++ .../xcshareddata/xcschemes/frDemo.xcscheme | 53 +++ .../xcshareddata/xcschemes/hiDemo.xcscheme | 53 +++ .../xcshareddata/xcschemes/itDemo.xcscheme | 53 +++ .../xcshareddata/xcschemes/jaDemo.xcscheme | 53 +++ .../xcshareddata/xcschemes/koDemo.xcscheme | 53 +++ .../xcshareddata/xcschemes/nlDemo.xcscheme | 53 +++ .../xcshareddata/xcschemes/plDemo.xcscheme | 53 +++ .../xcshareddata/xcschemes/ptDemo.xcscheme | 53 +++ .../xcshareddata/xcschemes/ruDemo.xcscheme | 53 +++ .../xcshareddata/xcschemes/svDemo.xcscheme | 53 +++ .../xcshareddata/xcschemes/vnDemo.xcscheme | 53 +++ .../xcshareddata/xcschemes/zhDemo.xcscheme | 53 +++ .../ContentView.swift | 221 +++++++------ demo/ios/ForegroundApp/Podfile.lock | 2 +- demo/ios/ForegroundApp/pre-build.sh | 22 ++ demo/ios/README.md | 14 +- resources/.lint/spell-check/dict.txt | 5 + resources/.lint/swift/.swiftlint.yml | 5 +- resources/scripts/update_languages.py | 64 ++++ sdk/ios/Picovoice.swift | 74 +++-- .../PicovoiceAppTest/AppDelegate.swift | 7 +- .../PicovoiceAppTestUITests/BaseTest.swift | 6 +- .../PicovoiceAppTestUITests.swift | 312 +++++++++++------- .../PicovoiceLanguageTests.swift | 58 ++-- sdk/ios/PicovoiceErrors.swift | 30 +- sdk/ios/PicovoiceManager.swift | 83 ++--- 39 files changed, 1507 insertions(+), 475 deletions(-) delete mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/PicovoiceForegroundAppDemoUITests.xcscheme create mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/arDemo.xcscheme create mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/deDemo.xcscheme rename demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/{PicovoiceForegroundAppDemo.xcscheme => enDemo.xcscheme} (70%) create mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/esDemo.xcscheme create mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/frDemo.xcscheme create mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/hiDemo.xcscheme create mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/itDemo.xcscheme create mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/jaDemo.xcscheme create mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/koDemo.xcscheme create mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/nlDemo.xcscheme create mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/plDemo.xcscheme create mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ptDemo.xcscheme create mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ruDemo.xcscheme create mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/svDemo.xcscheme create mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/vnDemo.xcscheme create mode 100644 demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/zhDemo.xcscheme create mode 100755 demo/ios/ForegroundApp/pre-build.sh create mode 100644 resources/scripts/update_languages.py diff --git a/.gitignore b/.gitignore index 780107fba..4f48b3337 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,8 @@ node_modules demo/respeaker-rpi0/picovoice_demo_mic __pycache__ build -demo/c/cmake-build-debug \ No newline at end of file +demo/c/cmake-build-debug + +*.ppn +*.rhn +*.pv diff --git a/demo/flutter-clock/ios/Runner/AppDelegate.swift b/demo/flutter-clock/ios/Runner/AppDelegate.swift index 70693e4a8..d2a14bfb3 100644 --- a/demo/flutter-clock/ios/Runner/AppDelegate.swift +++ b/demo/flutter-clock/ios/Runner/AppDelegate.swift @@ -3,11 +3,11 @@ import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } } diff --git a/demo/flutter/ios/Runner/AppDelegate.swift b/demo/flutter/ios/Runner/AppDelegate.swift index 70693e4a8..d2a14bfb3 100644 --- a/demo/flutter/ios/Runner/AppDelegate.swift +++ b/demo/flutter/ios/Runner/AppDelegate.swift @@ -3,11 +3,11 @@ import Flutter @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } } diff --git a/demo/ios-swiftui/BaristaDemo/ContentView.swift b/demo/ios-swiftui/BaristaDemo/ContentView.swift index 128544c6e..3afd64cde 100644 --- a/demo/ios-swiftui/BaristaDemo/ContentView.swift +++ b/demo/ios-swiftui/BaristaDemo/ContentView.swift @@ -1,33 +1,32 @@ import SwiftUI struct ContentView: View { - + let activeBlue = Color(red: 55/255, green: 125/255, blue: 1, opacity: 1) let inactiveGrey = Color(red: 0.6, green: 0.6, blue: 0.6) - - + @ObservedObject var viewModel = ViewModel() - + var body: some View { - + return - VStack(alignment: .center, spacing:20) { + VStack(alignment: .center, spacing: 20) { Text("Say 'Hey Barista!'").font(.largeTitle).foregroundColor(activeBlue) - Image("cuppa").resizable().scaledToFit().padding(.horizontal,50.0) + Image("cuppa").resizable().scaledToFit().padding(.horizontal, 50.0) VStack(alignment: .center, spacing: 5) { - + Text("Beverage Size").font(.body).fontWeight(.semibold).foregroundColor(inactiveGrey) - + // Size row HStack(alignment: .center, spacing: 10) { ForEach(viewModel.sizeSel) { item in - Button(action: {}){ + Button(action: {}) { Text(item.title) .font(.system(size: 20)) .foregroundColor(item.isSelected ? Color.white : inactiveGrey) .padding(10) - + } .disabled(true) .background( @@ -40,17 +39,17 @@ struct ContentView: View { ) } } - + // # Shot row Text("Espresso Shots").font(.body).fontWeight(.semibold).foregroundColor(inactiveGrey).padding(.top, 8.0) HStack(alignment: .center, spacing: 7) { ForEach(viewModel.shotSel) { item in - Button(action: {}){ + Button(action: {}) { Text(item.title) .font(.system(size: 16)) .foregroundColor(item.isSelected ? Color.white : inactiveGrey) .padding(8.0) - + } .disabled(true) .background( @@ -63,18 +62,18 @@ struct ContentView: View { ) } } - + // Beverage row Text("Beverage Type").font(.body).fontWeight(.semibold).foregroundColor(inactiveGrey).padding(.top, 8.0) VStack(alignment: .center, spacing: 6) { HStack(alignment: .center) { ForEach(0.. Void) { + public func userNotificationCenter( + _ center: UNUserNotificationCenter, + didReceive response: UNNotificationResponse, + withCompletionHandler completionHandler: @escaping () -> Void + ) { completionHandler() } - public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { + public func userNotificationCenter( + _ center: UNUserNotificationCenter, + willPresent notification: UNNotification, + withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions + ) -> Void) { completionHandler([.badge, .banner, .sound]) } public func requestNotificationAuthorization() { - UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .sound], completionHandler: { (success, error) in + UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .sound], completionHandler: { (_, error) in if let error = error { print("Error: ", error) } diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/project.pbxproj b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/project.pbxproj index 4383e0f9b..aae0b668b 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/project.pbxproj +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/project.pbxproj @@ -11,8 +11,10 @@ 1760DF2F253A175000395344 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1760DF2E253A175000395344 /* ContentView.swift */; }; 1760DF31253A175500395344 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1760DF30253A175500395344 /* Assets.xcassets */; }; 1760DF34253A175500395344 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1760DF33253A175500395344 /* Preview Assets.xcassets */; }; - 1760DF58253A442A00395344 /* smart_lighting_ios.rhn in Resources */ = {isa = PBXBuildFile; fileRef = 1760DF57253A442A00395344 /* smart_lighting_ios.rhn */; }; - 1E846C94274D93DC00A63382 /* picovoice_ios.ppn in Resources */ = {isa = PBXBuildFile; fileRef = 1E846C93274D93DC00A63382 /* picovoice_ios.ppn */; }; + 1E6041B92A0C6BC800A10522 /* pre-build.sh in Resources */ = {isa = PBXBuildFile; fileRef = 1E6041B82A0C6BC800A10522 /* pre-build.sh */; }; + 1E6041BD2A0C6BD300A10522 /* keywords in Resources */ = {isa = PBXBuildFile; fileRef = 1E6041BA2A0C6BD300A10522 /* keywords */; }; + 1E6041BE2A0C6BD300A10522 /* contexts in Resources */ = {isa = PBXBuildFile; fileRef = 1E6041BB2A0C6BD300A10522 /* contexts */; }; + 1E6041BF2A0C6BD300A10522 /* models in Resources */ = {isa = PBXBuildFile; fileRef = 1E6041BC2A0C6BD300A10522 /* models */; }; 912216181D5264F91B289465 /* libPods-PicovoiceForegroundAppDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F8A4013300AFAB1C6A4B552 /* libPods-PicovoiceForegroundAppDemo.a */; }; /* End PBXBuildFile section */ @@ -36,8 +38,10 @@ 1760DF30253A175500395344 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 1760DF33253A175500395344 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 1760DF35253A175500395344 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 1760DF57253A442A00395344 /* smart_lighting_ios.rhn */ = {isa = PBXFileReference; lastKnownFileType = file; name = smart_lighting_ios.rhn; path = ../../../../resources/rhino/resources/contexts/ios/smart_lighting_ios.rhn; sourceTree = ""; }; - 1E846C93274D93DC00A63382 /* picovoice_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = file; name = picovoice_ios.ppn; path = ../../../../resources/porcupine/resources/keyword_files/ios/picovoice_ios.ppn; sourceTree = ""; }; + 1E6041B82A0C6BC800A10522 /* pre-build.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "pre-build.sh"; sourceTree = ""; }; + 1E6041BA2A0C6BD300A10522 /* keywords */ = {isa = PBXFileReference; lastKnownFileType = folder; path = keywords; sourceTree = ""; }; + 1E6041BB2A0C6BD300A10522 /* contexts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = contexts; sourceTree = ""; }; + 1E6041BC2A0C6BD300A10522 /* models */ = {isa = PBXFileReference; lastKnownFileType = folder; path = models; sourceTree = ""; }; 225F59ED6B6CC51898C796E9 /* Pods-PicovoiceDemoUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PicovoiceDemoUITests.debug.xcconfig"; path = "Target Support Files/Pods-PicovoiceDemoUITests/Pods-PicovoiceDemoUITests.debug.xcconfig"; sourceTree = ""; }; 2F8A4013300AFAB1C6A4B552 /* libPods-PicovoiceForegroundAppDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-PicovoiceForegroundAppDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 4AFC1C0D20FF305743767BCE /* Pods-PicovoiceForegroundAppDemoUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PicovoiceForegroundAppDemoUITests.release.xcconfig"; path = "Target Support Files/Pods-PicovoiceForegroundAppDemoUITests/Pods-PicovoiceForegroundAppDemoUITests.release.xcconfig"; sourceTree = ""; }; @@ -65,6 +69,7 @@ 1760DF20253A175000395344 = { isa = PBXGroup; children = ( + 1E6041B82A0C6BC800A10522 /* pre-build.sh */, 1760DF2B253A175000395344 /* PicovoiceForegroundAppDemo */, 1760DF2A253A175000395344 /* Products */, 1760DF3D253A185500395344 /* Frameworks */, @@ -83,8 +88,9 @@ 1760DF2B253A175000395344 /* PicovoiceForegroundAppDemo */ = { isa = PBXGroup; children = ( - 1E846C93274D93DC00A63382 /* picovoice_ios.ppn */, - 1760DF57253A442A00395344 /* smart_lighting_ios.rhn */, + 1E6041BB2A0C6BD300A10522 /* contexts */, + 1E6041BA2A0C6BD300A10522 /* keywords */, + 1E6041BC2A0C6BD300A10522 /* models */, 1760DF2C253A175000395344 /* PicovoiceForegroundAppDemo.swift */, 1760DF2E253A175000395344 /* ContentView.swift */, 1760DF30253A175500395344 /* Assets.xcassets */, @@ -188,9 +194,11 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1E846C94274D93DC00A63382 /* picovoice_ios.ppn in Resources */, + 1E6041BD2A0C6BD300A10522 /* keywords in Resources */, + 1E6041B92A0C6BC800A10522 /* pre-build.sh in Resources */, + 1E6041BF2A0C6BD300A10522 /* models in Resources */, 1760DF34253A175500395344 /* Preview Assets.xcassets in Resources */, - 1760DF58253A442A00395344 /* smart_lighting_ios.rhn in Resources */, + 1E6041BE2A0C6BD300A10522 /* contexts in Resources */, 1760DF31253A175500395344 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/PicovoiceForegroundAppDemoUITests.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/PicovoiceForegroundAppDemoUITests.xcscheme deleted file mode 100644 index cf7da93b4..000000000 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/PicovoiceForegroundAppDemoUITests.xcscheme +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/arDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/arDemo.xcscheme new file mode 100644 index 000000000..303843ac4 --- /dev/null +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/arDemo.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/deDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/deDemo.xcscheme new file mode 100644 index 000000000..2240ca659 --- /dev/null +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/deDemo.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/PicovoiceForegroundAppDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/enDemo.xcscheme similarity index 70% rename from demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/PicovoiceForegroundAppDemo.xcscheme rename to demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/enDemo.xcscheme index c57abdca7..c005b6db2 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/PicovoiceForegroundAppDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/enDemo.xcscheme @@ -1,10 +1,28 @@ + LastUpgradeVersion = "1310" + version = "1.7"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/frDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/frDemo.xcscheme new file mode 100644 index 000000000..11f48b2aa --- /dev/null +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/frDemo.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/hiDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/hiDemo.xcscheme new file mode 100644 index 000000000..dbe85088f --- /dev/null +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/hiDemo.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/itDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/itDemo.xcscheme new file mode 100644 index 000000000..3de1e18b4 --- /dev/null +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/itDemo.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/jaDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/jaDemo.xcscheme new file mode 100644 index 000000000..d14b8bb6a --- /dev/null +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/jaDemo.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/koDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/koDemo.xcscheme new file mode 100644 index 000000000..721809eca --- /dev/null +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/koDemo.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/nlDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/nlDemo.xcscheme new file mode 100644 index 000000000..9c82bf76a --- /dev/null +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/nlDemo.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/plDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/plDemo.xcscheme new file mode 100644 index 000000000..696d921a6 --- /dev/null +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/plDemo.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ptDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ptDemo.xcscheme new file mode 100644 index 000000000..14924db58 --- /dev/null +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ptDemo.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ruDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ruDemo.xcscheme new file mode 100644 index 000000000..a7ed39f75 --- /dev/null +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ruDemo.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/svDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/svDemo.xcscheme new file mode 100644 index 000000000..897f26438 --- /dev/null +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/svDemo.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/vnDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/vnDemo.xcscheme new file mode 100644 index 000000000..f7439d927 --- /dev/null +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/vnDemo.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/zhDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/zhDemo.xcscheme new file mode 100644 index 000000000..487641e81 --- /dev/null +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/zhDemo.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift index 140fac867..63dde3763 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift @@ -1,5 +1,5 @@ // -// Copyright 2018-2021 Picovoice Inc. +// Copyright 2018-2023 Picovoice Inc. // You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE" // file accompanying this source. // Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on @@ -11,115 +11,138 @@ import SwiftUI import Picovoice struct ContentView: View { - - let ACCESS_KEY = "${YOUR_ACCESS_KEY_HERE}" - - let keywordPath = Bundle.main.path(forResource: "picovoice_ios", ofType: "ppn") - let contextPath = Bundle.main.path(forResource: "smart_lighting_ios", ofType: "rhn") - + + let ACCESS_KEY = "Tw4jothrMMLyRYQ793yD/XF3DeithcbeNVsYlNN0Dc1vY26suWNOkg==" + + let language: String = ProcessInfo.processInfo.environment["LANGUAGE"]! + let wakeword: String = ProcessInfo.processInfo.environment["WAKEWORD"]! + let context: String = ProcessInfo.processInfo.environment["CONTEXT"]! + @State var textTimer: Timer? - + @State var picovoiceManager: PicovoiceManager! @State var buttonLabel = "START" @State var result: String = "" @State var errorMessage: String = "" - + var body: some View { - - VStack{ - Spacer() - Spacer() - Text("\(result)") - .foregroundColor(Color.black) - .padding() - - Text(errorMessage) - .padding() - .background(Color.red) - .foregroundColor(Color.white) - .frame(minWidth: 0, maxWidth: UIScreen.main.bounds.width - 50) - .font(.body) - .opacity(errorMessage.isEmpty ? 0 : 1) - .cornerRadius(.infinity) - Spacer() - - Text("Press the Start button and say \"Picovoice, turn off the lights\".") - .padding() - .foregroundColor(Color.black) - .multilineTextAlignment(.center) - - Button(action: { - if self.buttonLabel == "START" { - self.textTimer?.invalidate() - self.result = "" - - do { - self.picovoiceManager = PicovoiceManager( - accessKey: self.ACCESS_KEY, - keywordPath: self.keywordPath!, - onWakeWordDetection: { - result = "Wake Word Detected!\nListening for command..." - }, - contextPath: self.contextPath!, - onInference: { x in - DispatchQueue.main.async { - result = "{\n" - self.result += " \"isUnderstood\" : \"" + x.isUnderstood.description + "\",\n" - if x.isUnderstood { - self.result += " \"intent : \"" + x.intent + "\",\n" - if !x.slots.isEmpty { - result += " \"slots\" : {\n" - for (k, v) in x.slots { - self.result += " \"" + k + "\" : \"" + v + "\",\n" - } - result += " }\n" + + VStack { + Spacer() + Spacer() + Text("\(result)") + .foregroundColor(Color.black) + .padding() + + Text(errorMessage) + .padding() + .background(Color.red) + .foregroundColor(Color.white) + .frame(minWidth: 0, maxWidth: UIScreen.main.bounds.width - 50) + .font(.body) + .opacity(errorMessage.isEmpty ? 0 : 1) + .cornerRadius(.infinity) + Spacer() + + Text("Wake word: \(wakeword)\nContext: \(context)") + .padding() + .foregroundColor(Color.black) + .multilineTextAlignment(.center) + + Button(action: { + if self.buttonLabel == "START" { + self.textTimer?.invalidate() + self.result = "" + + let token = (language == "en") ? "" : "_\(language)" + + let keywordPath = Bundle.main.url( + forResource: "\(wakeword)_ios", + withExtension: "ppn", + subdirectory: "keywords")! + let ppnModelPath = Bundle.main.url( + forResource: "porcupine_params\(token)", + withExtension: "pv", + subdirectory: "models")! + + let contextPath = Bundle.main.url( + forResource: "\(context)_ios", + withExtension: "rhn", + subdirectory: "contexts")! + let rhnModelPath = Bundle.main.url( + forResource: "rhino_params\(token)", + withExtension: "pv", + subdirectory: "models")! + + do { + self.picovoiceManager = PicovoiceManager( + accessKey: self.ACCESS_KEY, + keywordPath: keywordPath.path, + onWakeWordDetection: { + result = "Wake Word Detected!\nListening for command..." + }, + contextPath: contextPath.path, + onInference: { x in + DispatchQueue.main.async { + result = "{\n" + self.result += " \"isUnderstood\" : \"" + x.isUnderstood.description + "\",\n" + if x.isUnderstood { + self.result += " \"intent : \"" + x.intent + "\",\n" + if !x.slots.isEmpty { + result += " \"slots\" : {\n" + for (k, v) in x.slots { + self.result += " \"" + k + "\" : \"" + v + "\",\n" } + result += " }\n" } - result += "}\n" } - - self.textTimer = Timer.scheduledTimer(withTimeInterval: 1.75, repeats: false) { timer in - if buttonLabel == "STOP" { - result = "Listening for Wake Word.." - } + result += "}\n" + } + + self.textTimer = Timer.scheduledTimer(withTimeInterval: 1.75, repeats: false) { _ in + if buttonLabel == "STOP" { + result = "Listening for Wake Word.." } - }) - - try self.picovoiceManager.start() - - self.buttonLabel = "STOP" - self.result = "Listening for Wake Word..." - } catch let error as PicovoiceInvalidArgumentError { - errorMessage = "\(error.localizedDescription)\nEnsure your AccessKey '\(ACCESS_KEY)' is valid" - } catch is PicovoiceActivationError { - errorMessage = "ACCESS_KEY activation error" - } catch is PicovoiceActivationRefusedError { - errorMessage = "ACCESS_KEY activation refused" - } catch is PicovoiceActivationLimitError { - errorMessage = "ACCESS_KEY reached its limit" - } catch is PicovoiceActivationThrottledError { - errorMessage = "ACCESS_KEY is throttled" - } catch { - errorMessage = "\(error)" - } - - } else { - self.picovoiceManager.stop() - self.buttonLabel = "START" - self.result = "" - self.textTimer?.invalidate() + } + }, + porcupineModelPath: ppnModelPath.path, + rhinoModelPath: rhnModelPath.path) + + try self.picovoiceManager.start() + + self.buttonLabel = "STOP" + self.result = "Listening for Wake Word..." + } catch let error as PicovoiceInvalidArgumentError { + errorMessage = "\(error.localizedDescription)\nEnsure your AccessKey '\(ACCESS_KEY)' is valid" + } catch is PicovoiceActivationError { + errorMessage = "ACCESS_KEY activation error" + } catch is PicovoiceActivationRefusedError { + errorMessage = "ACCESS_KEY activation refused" + } catch is PicovoiceActivationLimitError { + errorMessage = "ACCESS_KEY reached its limit" + } catch is PicovoiceActivationThrottledError { + errorMessage = "ACCESS_KEY is throttled" + } catch { + errorMessage = "\(error)" } - }) { - Text("\(buttonLabel)") - .padding() - .background(errorMessage.isEmpty ? Color.blue : Color.gray) - .foregroundColor(Color.white) - .font(.largeTitle) - }.disabled(!errorMessage.isEmpty) - } - .padding() - .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity) - .background(Color.white) + + } else { + self.picovoiceManager.stop() + self.buttonLabel = "START" + self.result = "" + self.textTimer?.invalidate() + } + }) { + Text("\(buttonLabel)") + .padding() + .background(errorMessage.isEmpty ? Color.blue : Color.gray) + .foregroundColor(Color.white) + .font(.largeTitle) + }.disabled(!errorMessage.isEmpty) + } + .padding() + .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity) + .background(Color.white) } } diff --git a/demo/ios/ForegroundApp/Podfile.lock b/demo/ios/ForegroundApp/Podfile.lock index f23c99479..016579a8a 100644 --- a/demo/ios/ForegroundApp/Podfile.lock +++ b/demo/ios/ForegroundApp/Podfile.lock @@ -27,4 +27,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: e859480d65f8db91f16bcae8fcb2b5cd2cd07dd9 -COCOAPODS: 1.12.0 +COCOAPODS: 1.11.2 diff --git a/demo/ios/ForegroundApp/pre-build.sh b/demo/ios/ForegroundApp/pre-build.sh new file mode 100755 index 000000000..8fbad39d6 --- /dev/null +++ b/demo/ios/ForegroundApp/pre-build.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +mkdir -p "${SRCROOT}/PicovoiceForegroundAppDemo/keywords/" +mkdir -p "${SRCROOT}/PicovoiceForegroundAppDemo/contexts/" +mkdir -p "${SRCROOT}/PicovoiceForegroundAppDemo/models/" + +rm "${SRCROOT}/PicovoiceForegroundAppDemo/keywords/"* +rm "${SRCROOT}/PicovoiceForegroundAppDemo/contexts/"* +rm "${SRCROOT}/PicovoiceForegroundAppDemo/models/"* + +if [ $1 == 'en' ]; +then + cp "${SRCROOT}/../../../resources/porcupine/resources/keyword_files/ios/"* "${SRCROOT}/PicovoiceForegroundAppDemo/keywords/" + cp "${SRCROOT}/../../../resources/porcupine/lib/common/porcupine_params.pv" "${SRCROOT}/PicovoiceForegroundAppDemo/models/" + cp "${SRCROOT}/../../../resources/rhino/resources/contexts/ios/"* "${SRCROOT}/PicovoiceForegroundAppDemo/contexts/" + cp "${SRCROOT}/../../../resources/rhino/lib/common/rhino_params.pv" "${SRCROOT}/PicovoiceForegroundAppDemo/models/" +else + cp "${SRCROOT}/../../../resources/porcupine/resources/keyword_files_$1/ios/"* "${SRCROOT}/PicovoiceForegroundAppDemo/keywords/" + cp "${SRCROOT}/../../../resources/porcupine/lib/common/porcupine_params_$1.pv" "${SRCROOT}/PicovoiceForegroundAppDemo/models/" + cp "${SRCROOT}/../../../resources/rhino/resources/contexts_$1/ios/"* "${SRCROOT}/PicovoiceForegroundAppDemo/contexts/" + cp "${SRCROOT}/../../../resources/rhino/lib/common/rhino_params_$1.pv" "${SRCROOT}/PicovoiceForegroundAppDemo/models/" +fi diff --git a/demo/ios/README.md b/demo/ios/README.md index b3d95fe95..bf53d3b2b 100644 --- a/demo/ios/README.md +++ b/demo/ios/README.md @@ -24,15 +24,17 @@ Open `PicovoiceBackgroundServiceDemo.xcworkspace` and paste your `AccessKey` int This demo runs wake word detection and context inference while the application is in focus. -To run the foreground application demo, go to [ForegroundApp](./ForegroundApp) directory. Then run: +To run the foreground application demo: -```console -pod install -``` +1) Go to [ForegroundApp](./ForegroundApp) directory. Then run: + +2) Open the `PicovoiceForegroundAppDemo.xcworkspace` in XCode + +3) Replace `let accessKey = "${YOUR_ACCESS_KEY_HERE}"` in the file [ContentView.swift](./ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift) with your `AccessKey`. -Open the `PicovoiceForegroundAppDemo.xcworkspace` and paste your `AccessKey` into the `ACCESS_KEY` variable in `ContentView.swift`. Then, build and run the demo through XCode. +4) Go to `Product > Scheme` and select the scheme for the language you would like to demo (e.g. `arScheme` -> Arabic Demo, `deScheme` -> German Demo) -## Wake Word Detection and Context Inference +5) Run the demo with a simulator or connected iOS device The default wake word is `Picovoice`. The default Rhino Speech-to-Intent context is `Smart Lighting`. Simply press start and the engine can recognize commands such as: diff --git a/resources/.lint/spell-check/dict.txt b/resources/.lint/spell-check/dict.txt index 939696e6d..47ad059ec 100644 --- a/resources/.lint/spell-check/dict.txt +++ b/resources/.lint/spell-check/dict.txt @@ -264,6 +264,7 @@ siri snowboy soundfile spegnere +SRCROOT Speisekammer spidev stachelschwein @@ -301,6 +302,10 @@ weiß Wohnzimmer xcframework xcworkspace +xcodeproj +xcshareddata +xcscheme +xcschemes xpresso ändere éclairage diff --git a/resources/.lint/swift/.swiftlint.yml b/resources/.lint/swift/.swiftlint.yml index a953c05b6..eac9add61 100644 --- a/resources/.lint/swift/.swiftlint.yml +++ b/resources/.lint/swift/.swiftlint.yml @@ -5,6 +5,9 @@ disabled_rules: - implicit_getter - cyclomatic_complexity - function_parameter_count + - type_body_length excluded: - ${PWD}/**/Pods - - ${PWD}/**/node_modules \ No newline at end of file + - ${PWD}/**/node_modules + - ${PWD}/**/resources/porcupine/ + - ${PWD}/**/resources/rhino diff --git a/resources/scripts/update_languages.py b/resources/scripts/update_languages.py new file mode 100644 index 000000000..268dd91eb --- /dev/null +++ b/resources/scripts/update_languages.py @@ -0,0 +1,64 @@ +# Copyright 2023 Picovoice Inc. +# +# You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE" +# file accompanying this source. +# +# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +import json +import os + +from xml.dom import minidom + + +def update_ios_demo(parameters): + + scheme_dir = os.path.join( + os.path.dirname(__file__), + "../../demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes") + base_scheme = os.path.join( + os.path.dirname(__file__), + scheme_dir, + "enDemo.xcscheme") + + for language, parameter in parameters.items(): + if language == 'en': + continue + + language_scheme = os.path.join(scheme_dir, f"{language}Demo.xcscheme") + if not os.path.exists(language_scheme): + print(f"Creating iOS demo scheme for `{language}`") + base_scheme_content = minidom.parse(base_scheme) + pre_build_action = base_scheme_content.getElementsByTagName('ActionContent')[0] + pre_build_action.setAttribute( + 'scriptText', + pre_build_action.attributes['scriptText'].value.replace(" en", f" {language}")) + + env_vars = base_scheme_content.getElementsByTagName('EnvironmentVariable') + for env_var in env_vars: + if env_var.getAttribute('key') == 'LANGUAGE': + env_var.setAttribute('value', language) + if env_var.getAttribute('key') == 'WAKEWORD': + env_var.setAttribute('value', parameter['wakeword']) + if env_var.getAttribute('key') == 'CONTEXT': + env_var.setAttribute('value', parameter['context']) + + with open(os.path.join(scheme_dir, f"{language}Demo.xcscheme"), 'w') as f: + f.write(base_scheme_content.toxml()) + else: + print(f"iOS scheme for `{language}` already exists") + + +def main(): + with open(os.path.join(os.path.dirname(__file__), "../.test/test_data.json"), encoding='utf-8') as f: + json_content = json.loads(f.read()) + + parameters = {x['language']: {'wakeword': x['wakeword'], 'context': x['context_name']} for x in json_content['tests']['parameters']} + update_ios_demo(parameters=parameters) + + +if __name__ == '__main__': + main() diff --git a/sdk/ios/Picovoice.swift b/sdk/ios/Picovoice.swift index 881d3dc22..6c478f3d6 100644 --- a/sdk/ios/Picovoice.swift +++ b/sdk/ios/Picovoice.swift @@ -1,5 +1,5 @@ // -// Copyright 2021-2022 Picovoice Inc. +// Copyright 2021-2023 Picovoice Inc. // You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE" // file accompanying this source. // Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on @@ -12,7 +12,8 @@ import Porcupine import Rhino /// Low-level iOS binding for Picovoice end-to-end platform. -/// Client passes in audio data and is notified upon detection of the wake word or completion of in voice command inference. +/// Client passes in audio data and is notified upon detection of the +/// wake word or completion of in voice command inference. public class Picovoice { private var porcupine: Porcupine? private var rhino: Rhino? @@ -35,53 +36,55 @@ public class Picovoice { /// - accessKey: The AccessKey obtained from Picovoice Console (https://console.picovoice.ai). /// - keywordPath: Absolute paths to keyword model file. /// - onWakeWordDetection: A callback that is invoked upon detection of the keyword. - /// - contextPath: Absolute path to file containing context parameters. A context represents the set of expressions (spoken commands), intents, and - /// intent arguments (slots) within a domain of interest. + /// - contextPath: Absolute path to file containing context parameters. A context represents + /// the set of expressions (spoken commands), intents, and intent arguments (slots) within a domain of interest. /// - onInference: A callback that is invoked upon completion of intent inference. /// - porcupineModelPath: Absolute path to file containing model parameters. - /// - porcupineSensitivity: Sensitivity for detecting keywords. Each value should be a number within [0, 1]. A higher sensitivity results in fewer misses at - /// the cost of increasing the false alarm rate. + /// - porcupineSensitivity: Sensitivity for detecting keywords. Each value should be a number within [0, 1]. + /// A higher sensitivity results in fewer misses at the cost of increasing the false alarm rate. /// - rhinoModelPath: Absolute path to file containing model parameters. - /// - rhinoSensitivity: Inference sensitivity. It should be a number within [0, 1]. A higher sensitivity value results in fewer misses at the cost of (potentially) - /// increasing the erroneous inference rate. + /// - rhinoSensitivity: Inference sensitivity. It should be a number within [0, 1]. A higher sensitivity value + /// results in fewer misses at the cost of (potentially) increasing the erroneous inference rate. /// - endpointDurationSec: Endpoint duration in seconds. An endpoint is a chunk of silence at the end of an - /// utterance that marks the end of spoken command. It should be a positive number within [0.5, 5]. A lower endpoint - /// duration reduces delay and improves responsiveness. A higher endpoint duration assures Rhino doesn't return inference - /// pre-emptively in case the user pauses before finishing the request. + /// utterance that marks the end of spoken command. It should be a positive number within [0.5, 5]. + /// A lower endpoint duration reduces delay and improves responsiveness. + /// A higher endpoint duration assures Rhino doesn't return inference pre-emptively + /// in case the user pauses before finishing the request. /// - requireEndpoint: If set to `true`, Rhino requires an endpoint (a chunk of silence) after the spoken command. - /// If set to `false`, Rhino tries to detect silence, but if it cannot, it still will provide inference regardless. Set - /// to `false` only if operating in an environment with overlapping speech (e.g. people talking in the background). + /// If set to `false`, Rhino tries to detect silence, but if it cannot, it still will provide + /// inference regardless. Set to `false` only if operating in an environment with overlapping speech + /// (e.g. people talking in the background). /// - Throws: PicovoiceError public init( - accessKey: String, - keywordPath: String, - onWakeWordDetection: @escaping (() -> Void), - contextPath: String, - onInference: @escaping ((Inference) -> Void), - porcupineModelPath: String? = nil, - porcupineSensitivity: Float32 = 0.5, - rhinoModelPath: String? = nil, - rhinoSensitivity: Float32 = 0.5, - endpointDurationSec: Float32 = 1.0, - requireEndpoint: Bool = true) throws { + accessKey: String, + keywordPath: String, + onWakeWordDetection: @escaping (() -> Void), + contextPath: String, + onInference: @escaping ((Inference) -> Void), + porcupineModelPath: String? = nil, + porcupineSensitivity: Float32 = 0.5, + rhinoModelPath: String? = nil, + rhinoSensitivity: Float32 = 0.5, + endpointDurationSec: Float32 = 1.0, + requireEndpoint: Bool = true) throws { self.onWakeWordDetection = onWakeWordDetection self.onInference = onInference do { try porcupine = Porcupine( - accessKey: accessKey, - keywordPath: keywordPath, - modelPath: porcupineModelPath, - sensitivity: porcupineSensitivity) + accessKey: accessKey, + keywordPath: keywordPath, + modelPath: porcupineModelPath, + sensitivity: porcupineSensitivity) try rhino = Rhino( - accessKey: accessKey, - contextPath: contextPath, - modelPath: rhinoModelPath, - sensitivity: rhinoSensitivity, - endpointDurationSec: endpointDurationSec, - requireEndpoint: requireEndpoint) + accessKey: accessKey, + contextPath: contextPath, + modelPath: rhinoModelPath, + sensitivity: rhinoSensitivity, + endpointDurationSec: endpointDurationSec, + requireEndpoint: requireEndpoint) contextInfo = rhino?.contextInfo } catch { @@ -113,7 +116,8 @@ public class Picovoice { /// - Throws: PicovoiceError public func process(pcm: [Int16]) throws { if pcm.count != Picovoice.frameLength { - throw PicovoiceInvalidArgumentError("Invalid frame length - expected \(Picovoice.frameLength), received \(pcm.count)") + throw PicovoiceInvalidArgumentError( + "Invalid frame length - expected \(Picovoice.frameLength), received \(pcm.count)") } if porcupine == nil || rhino == nil { diff --git a/sdk/ios/PicovoiceAppTest/PicovoiceAppTest/AppDelegate.swift b/sdk/ios/PicovoiceAppTest/PicovoiceAppTest/AppDelegate.swift index 496fb090d..4531b6322 100644 --- a/sdk/ios/PicovoiceAppTest/PicovoiceAppTest/AppDelegate.swift +++ b/sdk/ios/PicovoiceAppTest/PicovoiceAppTest/AppDelegate.swift @@ -1,5 +1,5 @@ // -// Copyright 2022 Picovoice Inc. +// Copyright 2022-2023 Picovoice Inc. // You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE" // file accompanying this source. // Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on @@ -13,7 +13,10 @@ import UIKit class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { return true } } diff --git a/sdk/ios/PicovoiceAppTest/PicovoiceAppTestUITests/BaseTest.swift b/sdk/ios/PicovoiceAppTest/PicovoiceAppTestUITests/BaseTest.swift index 462ddb880..fb9104c32 100644 --- a/sdk/ios/PicovoiceAppTest/PicovoiceAppTestUITests/BaseTest.swift +++ b/sdk/ios/PicovoiceAppTest/PicovoiceAppTestUITests/BaseTest.swift @@ -17,7 +17,7 @@ class BaseTest: XCTestCase { let accessKey: String = "{TESTING_ACCESS_KEY_HERE}" var isWakeWordDetected = false - var inferenceResult: Inference? = nil + var inferenceResult: Inference? override func setUp() { super.setUp() @@ -41,9 +41,9 @@ class BaseTest: XCTestCase { func processFile(picovoice: Picovoice, testAudioURL: URL) throws { let data = try Data(contentsOf: testAudioURL) let frameLengthBytes = Int(Rhino.frameLength) * 2 - var pcmBuffer = Array(repeating: 0, count: Int(Rhino.frameLength)) + var pcmBuffer = [Int16](repeating: 0, count: Int(Rhino.frameLength)) var index = 44 - while (index + frameLengthBytes < data.count) { + while index + frameLengthBytes < data.count { _ = pcmBuffer.withUnsafeMutableBytes { data.copyBytes(to: $0, from: index..<(index + frameLengthBytes)) } diff --git a/sdk/ios/PicovoiceAppTest/PicovoiceAppTestUITests/PicovoiceAppTestUITests.swift b/sdk/ios/PicovoiceAppTest/PicovoiceAppTestUITests/PicovoiceAppTestUITests.swift index 15b1175c5..a73c6624b 100644 --- a/sdk/ios/PicovoiceAppTest/PicovoiceAppTestUITests/PicovoiceAppTestUITests.swift +++ b/sdk/ios/PicovoiceAppTest/PicovoiceAppTestUITests/PicovoiceAppTestUITests.swift @@ -1,5 +1,5 @@ // -// Copyright 2022 Picovoice Inc. +// Copyright 2022-2023 Picovoice Inc. // You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE" // file accompanying this source. // Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on @@ -17,14 +17,20 @@ class PicovoiceAppTestUITests: BaseTest { func testInitSuccessSimple() throws { let bundle = Bundle(for: type(of: self)) - let keywordPath = bundle.path(forResource: "picovoice_ios", ofType: "ppn", inDirectory: "test_resources/keyword_files/en")! - let contextPath = bundle.path(forResource: "coffee_maker_ios", ofType: "rhn", inDirectory: "test_resources/context_files/en")! + let keywordPath = bundle.path( + forResource: "picovoice_ios", + ofType: "ppn", + inDirectory: "test_resources/keyword_files/en")! + let contextPath = bundle.path( + forResource: "coffee_maker_ios", + ofType: "rhn", + inDirectory: "test_resources/context_files/en")! let p = try Picovoice( - accessKey: accessKey, - keywordPath: keywordPath, - onWakeWordDetection: wakeWordCallback, - contextPath: contextPath, - onInference: inferenceCallback) + accessKey: accessKey, + keywordPath: keywordPath, + onWakeWordDetection: wakeWordCallback, + contextPath: contextPath, + onInference: inferenceCallback) XCTAssert(Picovoice.picovoiceVersion != "") XCTAssert(Picovoice.frameLength > 0) @@ -35,18 +41,30 @@ class PicovoiceAppTestUITests: BaseTest { func testInitSuccessCustomModelPaths() throws { let bundle = Bundle(for: type(of: self)) - let keywordPath = bundle.path(forResource: "picovoice_ios", ofType: "ppn", inDirectory: "test_resources/keyword_files/en")! - let contextPath = bundle.path(forResource: "coffee_maker_ios", ofType: "rhn", inDirectory: "test_resources/context_files/en")! - let porcupineModelPath = bundle.path(forResource: "porcupine_params", ofType: "pv", inDirectory: "test_resources/model_files/")! - let rhinoModelPath = bundle.path(forResource: "rhino_params", ofType: "pv", inDirectory: "test_resources/model_files/")! + let keywordPath = bundle.path( + forResource: "picovoice_ios", + ofType: "ppn", + inDirectory: "test_resources/keyword_files/en")! + let contextPath = bundle.path( + forResource: "coffee_maker_ios", + ofType: "rhn", + inDirectory: "test_resources/context_files/en")! + let porcupineModelPath = bundle.path( + forResource: "porcupine_params", + ofType: "pv", + inDirectory: "test_resources/model_files/")! + let rhinoModelPath = bundle.path( + forResource: "rhino_params", + ofType: "pv", + inDirectory: "test_resources/model_files/")! let p = try Picovoice( - accessKey: accessKey, - keywordPath: keywordPath, - onWakeWordDetection: wakeWordCallback, - contextPath: contextPath, - onInference: inferenceCallback, - porcupineModelPath: porcupineModelPath, - rhinoModelPath: rhinoModelPath) + accessKey: accessKey, + keywordPath: keywordPath, + onWakeWordDetection: wakeWordCallback, + contextPath: contextPath, + onInference: inferenceCallback, + porcupineModelPath: porcupineModelPath, + rhinoModelPath: rhinoModelPath) XCTAssert(p.contextInfo != "") p.delete() @@ -54,16 +72,22 @@ class PicovoiceAppTestUITests: BaseTest { func testInitSuccessCustomSensitivities() throws { let bundle = Bundle(for: type(of: self)) - let keywordPath = bundle.path(forResource: "picovoice_ios", ofType: "ppn", inDirectory: "test_resources/keyword_files/en")! - let contextPath = bundle.path(forResource: "coffee_maker_ios", ofType: "rhn", inDirectory: "test_resources/context_files/en")! + let keywordPath = bundle.path( + forResource: "picovoice_ios", + ofType: "ppn", + inDirectory: "test_resources/keyword_files/en")! + let contextPath = bundle.path( + forResource: "coffee_maker_ios", + ofType: "rhn", + inDirectory: "test_resources/context_files/en")! let p = try Picovoice( - accessKey: accessKey, - keywordPath: keywordPath, - onWakeWordDetection: wakeWordCallback, - contextPath: contextPath, - onInference: inferenceCallback, - porcupineSensitivity: 0.7, - rhinoSensitivity: 0.35) + accessKey: accessKey, + keywordPath: keywordPath, + onWakeWordDetection: wakeWordCallback, + contextPath: contextPath, + onInference: inferenceCallback, + porcupineSensitivity: 0.7, + rhinoSensitivity: 0.35) XCTAssert(p.contextInfo != "") p.delete() @@ -71,17 +95,23 @@ class PicovoiceAppTestUITests: BaseTest { func testInitFailWithMismatchedPorcupineLanguage() throws { let bundle = Bundle(for: type(of: self)) - let keywordPath = bundle.path(forResource: "heuschrecke_ios", ofType: "ppn", inDirectory: "test_resources/keyword_files/de")! - let contextPath = bundle.path(forResource: "coffee_maker_ios", ofType: "rhn", inDirectory: "test_resources/context_files/en")! + let keywordPath = bundle.path( + forResource: "heuschrecke_ios", + ofType: "ppn", + inDirectory: "test_resources/keyword_files/de")! + let contextPath = bundle.path( + forResource: "coffee_maker_ios", + ofType: "rhn", + inDirectory: "test_resources/context_files/en")! var didFail = false do { _ = try Picovoice( - accessKey: accessKey, - keywordPath: keywordPath, - onWakeWordDetection: wakeWordCallback, - contextPath: contextPath, - onInference: inferenceCallback) + accessKey: accessKey, + keywordPath: keywordPath, + onWakeWordDetection: wakeWordCallback, + contextPath: contextPath, + onInference: inferenceCallback) } catch { didFail = true } @@ -91,17 +121,23 @@ class PicovoiceAppTestUITests: BaseTest { func testInitFailWithMismatchedRhinoLanguage() throws { let bundle = Bundle(for: type(of: self)) - let keywordPath = bundle.path(forResource: "picovoice_ios", ofType: "ppn", inDirectory: "test_resources/keyword_files/en")! - let contextPath = bundle.path(forResource: "beleuchtung_ios", ofType: "rhn", inDirectory: "test_resources/context_files/de")! + let keywordPath = bundle.path( + forResource: "picovoice_ios", + ofType: "ppn", + inDirectory: "test_resources/keyword_files/en")! + let contextPath = bundle.path( + forResource: "beleuchtung_ios", + ofType: "rhn", + inDirectory: "test_resources/context_files/de")! var didFail = false do { _ = try Picovoice( - accessKey: accessKey, - keywordPath: keywordPath, - onWakeWordDetection: wakeWordCallback, - contextPath: contextPath, - onInference: inferenceCallback) + accessKey: accessKey, + keywordPath: keywordPath, + onWakeWordDetection: wakeWordCallback, + contextPath: contextPath, + onInference: inferenceCallback) } catch { didFail = true } @@ -112,16 +148,19 @@ class PicovoiceAppTestUITests: BaseTest { func testInitFailWithInvalidKeywordPath() throws { let bundle = Bundle(for: type(of: self)) let keywordPath = "bad_path/bad_path.ppn" - let contextPath = bundle.path(forResource: "coffee_maker_ios", ofType: "rhn", inDirectory: "test_resources/context_files/en")! + let contextPath = bundle.path( + forResource: "coffee_maker_ios", + ofType: "rhn", + inDirectory: "test_resources/context_files/en")! var didFail = false do { _ = try Picovoice( - accessKey: accessKey, - keywordPath: keywordPath, - onWakeWordDetection: wakeWordCallback, - contextPath: contextPath, - onInference: inferenceCallback) + accessKey: accessKey, + keywordPath: keywordPath, + onWakeWordDetection: wakeWordCallback, + contextPath: contextPath, + onInference: inferenceCallback) } catch { didFail = true } @@ -131,17 +170,20 @@ class PicovoiceAppTestUITests: BaseTest { func testInitFailWithInvalidContextPath() throws { let bundle = Bundle(for: type(of: self)) - let keywordPath = bundle.path(forResource: "picovoice_ios", ofType: "ppn", inDirectory: "test_resources/keyword_files/en")! + let keywordPath = bundle.path( + forResource: "picovoice_ios", + ofType: "ppn", + inDirectory: "test_resources/keyword_files/en")! let contextPath = "bad_path/bad_path.rhn" var didFail = false do { _ = try Picovoice( - accessKey: accessKey, - keywordPath: keywordPath, - onWakeWordDetection: wakeWordCallback, - contextPath: contextPath, - onInference: inferenceCallback) + accessKey: accessKey, + keywordPath: keywordPath, + onWakeWordDetection: wakeWordCallback, + contextPath: contextPath, + onInference: inferenceCallback) } catch { didFail = true } @@ -151,19 +193,25 @@ class PicovoiceAppTestUITests: BaseTest { func testInitFailWithInvalidPorcupineModelPath() throws { let bundle = Bundle(for: type(of: self)) - let keywordPath = bundle.path(forResource: "picovoice_ios", ofType: "ppn", inDirectory: "test_resources/keyword_files/en")! - let contextPath = bundle.path(forResource: "coffee_maker_ios", ofType: "rhn", inDirectory: "test_resources/context_files/en")! + let keywordPath = bundle.path( + forResource: "picovoice_ios", + ofType: "ppn", + inDirectory: "test_resources/keyword_files/en")! + let contextPath = bundle.path( + forResource: "coffee_maker_ios", + ofType: "rhn", + inDirectory: "test_resources/context_files/en")! let porcupineModelPath = "bad_path/bad_path.pv" var didFail = false do { _ = try Picovoice( - accessKey: accessKey, - keywordPath: keywordPath, - onWakeWordDetection: wakeWordCallback, - contextPath: contextPath, - onInference: inferenceCallback, - porcupineModelPath: porcupineModelPath) + accessKey: accessKey, + keywordPath: keywordPath, + onWakeWordDetection: wakeWordCallback, + contextPath: contextPath, + onInference: inferenceCallback, + porcupineModelPath: porcupineModelPath) } catch { didFail = true } @@ -173,19 +221,25 @@ class PicovoiceAppTestUITests: BaseTest { func testInitFailWithInvalidRhinoModelPath() throws { let bundle = Bundle(for: type(of: self)) - let keywordPath = bundle.path(forResource: "picovoice_ios", ofType: "ppn", inDirectory: "test_resources/keyword_files/en")! - let contextPath = bundle.path(forResource: "coffee_maker_ios", ofType: "rhn", inDirectory: "test_resources/context_files/en")! + let keywordPath = bundle.path( + forResource: "picovoice_ios", + ofType: "ppn", + inDirectory: "test_resources/keyword_files/en")! + let contextPath = bundle.path( + forResource: "coffee_maker_ios", + ofType: "rhn", + inDirectory: "test_resources/context_files/en")! let rhinoModelPath = "bad_path/bad_path.pv" var didFail = false do { _ = try Picovoice( - accessKey: accessKey, - keywordPath: keywordPath, - onWakeWordDetection: wakeWordCallback, - contextPath: contextPath, - onInference: inferenceCallback, - rhinoModelPath: rhinoModelPath) + accessKey: accessKey, + keywordPath: keywordPath, + onWakeWordDetection: wakeWordCallback, + contextPath: contextPath, + onInference: inferenceCallback, + rhinoModelPath: rhinoModelPath) } catch { didFail = true } @@ -195,18 +249,24 @@ class PicovoiceAppTestUITests: BaseTest { func testInitFailWithInvalidPorcupineSensitivity() throws { let bundle = Bundle(for: type(of: self)) - let keywordPath = bundle.path(forResource: "picovoice_ios", ofType: "ppn", inDirectory: "test_resources/keyword_files/en")! - let contextPath = bundle.path(forResource: "coffee_maker_ios", ofType: "rhn", inDirectory: "test_resources/context_files/en")! + let keywordPath = bundle.path( + forResource: "picovoice_ios", + ofType: "ppn", + inDirectory: "test_resources/keyword_files/en")! + let contextPath = bundle.path( + forResource: "coffee_maker_ios", + ofType: "rhn", + inDirectory: "test_resources/context_files/en")! var didFail = false do { _ = try Picovoice( - accessKey: accessKey, - keywordPath: keywordPath, - onWakeWordDetection: wakeWordCallback, - contextPath: contextPath, - onInference: inferenceCallback, - porcupineSensitivity: 10) + accessKey: accessKey, + keywordPath: keywordPath, + onWakeWordDetection: wakeWordCallback, + contextPath: contextPath, + onInference: inferenceCallback, + porcupineSensitivity: 10) } catch { didFail = true } @@ -216,18 +276,24 @@ class PicovoiceAppTestUITests: BaseTest { func testInitFailWithInvalidRhinoSensitivity() throws { let bundle = Bundle(for: type(of: self)) - let keywordPath = bundle.path(forResource: "picovoice_ios", ofType: "ppn", inDirectory: "test_resources/keyword_files/en")! - let contextPath = bundle.path(forResource: "coffee_maker_ios", ofType: "rhn", inDirectory: "test_resources/context_files/en")! + let keywordPath = bundle.path( + forResource: "picovoice_ios", + ofType: "ppn", + inDirectory: "test_resources/keyword_files/en")! + let contextPath = bundle.path( + forResource: "coffee_maker_ios", + ofType: "rhn", + inDirectory: "test_resources/context_files/en")! var didFail = false do { _ = try Picovoice( - accessKey: accessKey, - keywordPath: keywordPath, - onWakeWordDetection: wakeWordCallback, - contextPath: contextPath, - onInference: inferenceCallback, - rhinoSensitivity: -1) + accessKey: accessKey, + keywordPath: keywordPath, + onWakeWordDetection: wakeWordCallback, + contextPath: contextPath, + onInference: inferenceCallback, + rhinoSensitivity: -1) } catch { didFail = true } @@ -237,17 +303,23 @@ class PicovoiceAppTestUITests: BaseTest { func testInitFailWithWrongPorcupinePlatform() throws { let bundle = Bundle(for: type(of: self)) - let keywordPath = bundle.path(forResource: "alexa_linux", ofType: "ppn", inDirectory: "test_resources/keyword_files/en")! - let contextPath = bundle.path(forResource: "coffee_maker_ios", ofType: "rhn", inDirectory: "test_resources/context_files/en")! + let keywordPath = bundle.path( + forResource: "alexa_linux", + ofType: "ppn", + inDirectory: "test_resources/keyword_files/en")! + let contextPath = bundle.path( + forResource: "coffee_maker_ios", + ofType: "rhn", + inDirectory: "test_resources/context_files/en")! var didFail = false do { _ = try Picovoice( - accessKey: accessKey, - keywordPath: keywordPath, - onWakeWordDetection: wakeWordCallback, - contextPath: contextPath, - onInference: inferenceCallback) + accessKey: accessKey, + keywordPath: keywordPath, + onWakeWordDetection: wakeWordCallback, + contextPath: contextPath, + onInference: inferenceCallback) } catch { didFail = true } @@ -257,17 +329,23 @@ class PicovoiceAppTestUITests: BaseTest { func testInitFailWithWrongRhinoPlatform() throws { let bundle = Bundle(for: type(of: self)) - let keywordPath = bundle.path(forResource: "picovoice_ios", ofType: "ppn", inDirectory: "test_resources/keyword_files/en")! - let contextPath = bundle.path(forResource: "coffee_maker_linux", ofType: "rhn", inDirectory: "test_resources/context_files/en")! + let keywordPath = bundle.path( + forResource: "picovoice_ios", + ofType: "ppn", + inDirectory: "test_resources/keyword_files/en")! + let contextPath = bundle.path( + forResource: "coffee_maker_linux", + ofType: "rhn", + inDirectory: "test_resources/context_files/en")! var didFail = false do { _ = try Picovoice( - accessKey: accessKey, - keywordPath: keywordPath, - onWakeWordDetection: wakeWordCallback, - contextPath: contextPath, - onInference: inferenceCallback) + accessKey: accessKey, + keywordPath: keywordPath, + onWakeWordDetection: wakeWordCallback, + contextPath: contextPath, + onInference: inferenceCallback) } catch { didFail = true } @@ -277,19 +355,31 @@ class PicovoiceAppTestUITests: BaseTest { func testInitWithNonAsciiModelName() throws { let bundle = Bundle(for: type(of: self)) - let keywordPath = bundle.path(forResource: "manzana_ios", ofType: "ppn", inDirectory: "test_resources/keyword_files/es")! - let contextPath = bundle.path(forResource: "iluminación_inteligente_ios", ofType: "rhn", inDirectory: "test_resources/context_files/es")! - let porcupineModelPath = bundle.path(forResource: "porcupine_params_es", ofType: "pv", inDirectory: "test_resources/model_files")! - let rhinoModelPath = bundle.path(forResource: "rhino_params_es", ofType: "pv", inDirectory: "test_resources/model_files")! + let keywordPath = bundle.path( + forResource: "manzana_ios", + ofType: "ppn", + inDirectory: "test_resources/keyword_files/es")! + let contextPath = bundle.path( + forResource: "iluminación_inteligente_ios", + ofType: "rhn", + inDirectory: "test_resources/context_files/es")! + let porcupineModelPath = bundle.path( + forResource: "porcupine_params_es", + ofType: "pv", + inDirectory: "test_resources/model_files")! + let rhinoModelPath = bundle.path( + forResource: "rhino_params_es", + ofType: "pv", + inDirectory: "test_resources/model_files")! let p = try Picovoice( - accessKey: accessKey, - keywordPath: keywordPath, - onWakeWordDetection: wakeWordCallback, - contextPath: contextPath, - onInference: inferenceCallback, - porcupineModelPath: porcupineModelPath, - rhinoModelPath: rhinoModelPath) + accessKey: accessKey, + keywordPath: keywordPath, + onWakeWordDetection: wakeWordCallback, + contextPath: contextPath, + onInference: inferenceCallback, + porcupineModelPath: porcupineModelPath, + rhinoModelPath: rhinoModelPath) XCTAssert(p.contextInfo != "") p.delete() diff --git a/sdk/ios/PicovoiceAppTest/PicovoiceAppTestUITests/PicovoiceLanguageTests.swift b/sdk/ios/PicovoiceAppTest/PicovoiceAppTestUITests/PicovoiceLanguageTests.swift index 297e770e7..509325850 100644 --- a/sdk/ios/PicovoiceAppTest/PicovoiceAppTestUITests/PicovoiceLanguageTests.swift +++ b/sdk/ios/PicovoiceAppTest/PicovoiceAppTestUITests/PicovoiceLanguageTests.swift @@ -1,5 +1,5 @@ // -// Copyright 2022 Picovoice Inc. +// Copyright 2022-2023 Picovoice Inc. // You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE" // file accompanying this source. // Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on @@ -12,15 +12,15 @@ import XCTest import Picovoice -struct TestData : Decodable { +struct TestData: Decodable { var tests: TestDataTests } -struct TestDataTests : Decodable { +struct TestDataTests: Decodable { var parameters: [TestDataParametersTest] } -struct TestDataParametersTest : Decodable { +struct TestDataParametersTest: Decodable { var language: String var wakeword: String var context_name: String @@ -28,16 +28,19 @@ struct TestDataParametersTest : Decodable { var inference: TestDataInference } -struct TestDataInference : Decodable { +struct TestDataInference: Decodable { var intent: String - var slots: [String : String] + var slots: [String: String] } class PicovoiceLanguageTests: BaseTest { func testWrapper() throws { let bundle = Bundle(for: type(of: self)) - let testDataJsonUrl = bundle.url(forResource: "test_data", withExtension: "json", subdirectory: "test_resources")! + let testDataJsonUrl = bundle.url( + forResource: "test_data", + withExtension: "json", + subdirectory: "test_resources")! let testDataJsonData = try Data(contentsOf: testDataJsonUrl) let testData = try JSONDecoder().decode(TestData.self, from: testDataJsonData) @@ -45,23 +48,38 @@ class PicovoiceLanguageTests: BaseTest { let suffix = testCase.language == "en" ? "" : "_\(testCase.language)" let language: String = testCase.language - let porcupineModelPath: String = bundle.path(forResource: "porcupine_params\(suffix)", ofType: "pv", inDirectory: "test_resources/model_files")! - let rhinoModelPath: String = bundle.path(forResource: "rhino_params\(suffix)", ofType: "pv", inDirectory: "test_resources/model_files")! - let keywordPath: String = bundle.path(forResource: "\(testCase.wakeword)_ios", ofType: "ppn", inDirectory: "test_resources/keyword_files/\(testCase.language)")! - let contextPath: String = bundle.path(forResource: "\(testCase.context_name)_ios", ofType: "rhn", inDirectory: "test_resources/context_files/\(testCase.language)")! - let testAudioPath: URL? = bundle.url(forResource: "\(testCase.audio_file)", withExtension: "", subdirectory: "test_resources/audio_samples")! + let porcupineModelPath: String = bundle.path( + forResource: "porcupine_params\(suffix)", + ofType: "pv", + inDirectory: "test_resources/model_files")! + let rhinoModelPath: String = bundle.path( + forResource: "rhino_params\(suffix)", + ofType: "pv", + inDirectory: "test_resources/model_files")! + let keywordPath: String = bundle.path( + forResource: "\(testCase.wakeword)_ios", + ofType: "ppn", + inDirectory: "test_resources/keyword_files/\(testCase.language)")! + let contextPath: String = bundle.path( + forResource: "\(testCase.context_name)_ios", + ofType: "rhn", + inDirectory: "test_resources/context_files/\(testCase.language)")! + let testAudioPath: URL? = bundle.url( + forResource: "\(testCase.audio_file)", + withExtension: "", + subdirectory: "test_resources/audio_samples")! let expectedIntent: String = testCase.inference.intent let expectedSlots: [String: String] = testCase.inference.slots try XCTContext.runActivity(named: "(\(language))") { _ in - let p = try! Picovoice( - accessKey: accessKey, - keywordPath: keywordPath, - onWakeWordDetection: wakeWordCallback, - contextPath: contextPath, - onInference: inferenceCallback, - porcupineModelPath: porcupineModelPath, - rhinoModelPath: rhinoModelPath) + let p = try Picovoice( + accessKey: accessKey, + keywordPath: keywordPath, + onWakeWordDetection: wakeWordCallback, + contextPath: contextPath, + onInference: inferenceCallback, + porcupineModelPath: porcupineModelPath, + rhinoModelPath: rhinoModelPath) XCTAssert(Picovoice.picovoiceVersion != "") XCTAssert(Picovoice.frameLength > 0) diff --git a/sdk/ios/PicovoiceErrors.swift b/sdk/ios/PicovoiceErrors.swift index fdbe269dc..6a0ed2702 100644 --- a/sdk/ios/PicovoiceErrors.swift +++ b/sdk/ios/PicovoiceErrors.swift @@ -7,13 +7,13 @@ // specific language governing permissions and limitations under the License. // -public class PicovoiceError : LocalizedError { - private let message: String; - +public class PicovoiceError: LocalizedError { + private let message: String + public init (_ message: String) { self.message = message } - + public var errorDescription: String? { return message } @@ -25,24 +25,24 @@ public class PicovoiceError : LocalizedError { } } -public class PicovoiceMemoryError : PicovoiceError {} +public class PicovoiceMemoryError: PicovoiceError {} -public class PicovoiceIOError : PicovoiceError {} +public class PicovoiceIOError: PicovoiceError {} -public class PicovoiceInvalidArgumentError : PicovoiceError {} +public class PicovoiceInvalidArgumentError: PicovoiceError {} -public class PicovoiceStopIterationError : PicovoiceError {} +public class PicovoiceStopIterationError: PicovoiceError {} -public class PicovoiceKeyError : PicovoiceError {} +public class PicovoiceKeyError: PicovoiceError {} -public class PicovoiceInvalidStateError : PicovoiceError {} +public class PicovoiceInvalidStateError: PicovoiceError {} -public class PicovoiceRuntimeError : PicovoiceError {} +public class PicovoiceRuntimeError: PicovoiceError {} -public class PicovoiceActivationError : PicovoiceError {} +public class PicovoiceActivationError: PicovoiceError {} -public class PicovoiceActivationLimitError : PicovoiceError {} +public class PicovoiceActivationLimitError: PicovoiceError {} -public class PicovoiceActivationThrottledError : PicovoiceError {} +public class PicovoiceActivationThrottledError: PicovoiceError {} -public class PicovoiceActivationRefusedError : PicovoiceError {} +public class PicovoiceActivationRefusedError: PicovoiceError {} diff --git a/sdk/ios/PicovoiceManager.swift b/sdk/ios/PicovoiceManager.swift index 52272c8a4..02de15bfa 100644 --- a/sdk/ios/PicovoiceManager.swift +++ b/sdk/ios/PicovoiceManager.swift @@ -1,5 +1,5 @@ // -// Copyright 2018-2022 Picovoice Inc. +// Copyright 2018-2023 Picovoice Inc. // You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE" // file accompanying this source. // Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on @@ -11,8 +11,8 @@ import ios_voice_processor import Rhino import Porcupine - -/// High-level iOS binding for Picovoice end-to-end platform. It handles recording audio from microphone, processes it in real-time using Picovoice, and notifies the +/// High-level iOS binding for Picovoice end-to-end platform. It handles recording audio +/// from microphone, processes it in real-time using Picovoice, and notifies the /// client upon detection of the wake word or completion of in voice command inference. public class PicovoiceManager { private var picovoice: Picovoice? @@ -38,37 +38,38 @@ public class PicovoiceManager { /// - accessKey: The AccessKey obtained from Picovoice Console (https://console.picovoice.ai). /// - keywordPath: Absolute paths to keyword model file. /// - onWakeWordDetection: A callback that is invoked upon detection of the keyword. - /// - contextPath: Absolute path to file containing context parameters. A context represents the set of expressions (spoken commands), intents, and - /// intent arguments (slots) within a domain of interest. + /// - contextPath: Absolute path to file containing context parameters. A context represents + /// the set of expressions (spoken commands), intents, and intent arguments (slots) within a domain of interest. /// - onInference: A callback that is invoked upon completion of intent inference. /// - porcupineModelPath: Absolute path to file containing model parameters. - /// - porcupineSensitivity: Sensitivity for detecting keywords. Each value should be a number within [0, 1]. A higher sensitivity results in fewer misses at - /// the cost of increasing the false alarm rate. + /// - porcupineSensitivity: Sensitivity for detecting keywords. Each value should be a number within [0, 1]. + /// A higher sensitivity results in fewer misses at the cost of increasing the false alarm rate. /// - rhinoModelPath: Absolute path to file containing model parameters. - /// - rhinoSensitivity: Inference sensitivity. It should be a number within [0, 1]. A higher sensitivity value results in fewer misses at the cost of (potentially) - /// increasing the erroneous inference rate. + /// - rhinoSensitivity: Inference sensitivity. It should be a number within [0, 1]. A higher sensitivity value + /// results in fewer misses at the cost of (potentially) increasing the erroneous inference rate. /// - endpointDurationSec: Endpoint duration in seconds. An endpoint is a chunk of silence at the end of an - /// utterance that marks the end of spoken command. It should be a positive number within [0.5, 5]. A lower endpoint - /// duration reduces delay and improves responsiveness. A higher endpoint duration assures Rhino doesn't return inference - /// pre-emptively in case the user pauses before finishing the request. + /// utterance that marks the end of spoken command. It should be a positive number within [0.5, 5]. + /// A lower endpoint duration reduces delay and improves responsiveness. + /// A higher endpoint duration assures Rhino doesn't return inference pre-emptively + /// in case the user pauses before finishing the request. /// - requireEndpoint: If set to `true`, Rhino requires an endpoint (a chunk of silence) after the spoken command. - /// If set to `false`, Rhino tries to detect silence, but if it cannot, it still will provide inference regardless. Set - /// to `false` only if operating in an environment with overlapping speech (e.g. people talking in the background). - /// - processErrorCallback: Invoked if an error occurs while processing frames. If missing, error will be printed to console. + /// If set to `false`, Rhino tries to detect silence, but if it cannot, it still will provide + /// inference regardless. Set to `false` only if operating in an environment with overlapping speech + /// (e.g. people talking in the background). /// - Throws: PicovoiceError public init( - accessKey: String, - keywordPath: String, - onWakeWordDetection: @escaping (() -> Void), - contextPath: String, - onInference: @escaping ((Inference) -> Void), - porcupineModelPath: String? = nil, - porcupineSensitivity: Float32 = 0.5, - rhinoModelPath: String? = nil, - rhinoSensitivity: Float32 = 0.5, - endpointDurationSec: Float32 = 1.0, - requireEndpoint: Bool = true, - processErrorCallback: ((Error) -> Void)? = nil) { + accessKey: String, + keywordPath: String, + onWakeWordDetection: @escaping (() -> Void), + contextPath: String, + onInference: @escaping ((Inference) -> Void), + porcupineModelPath: String? = nil, + porcupineSensitivity: Float32 = 0.5, + rhinoModelPath: String? = nil, + rhinoSensitivity: Float32 = 0.5, + endpointDurationSec: Float32 = 1.0, + requireEndpoint: Bool = true, + processErrorCallback: ((Error) -> Void)? = nil) { self.accessKey = accessKey self.keywordPath = keywordPath @@ -106,22 +107,22 @@ public class PicovoiceManager { } picovoice = try Picovoice( - accessKey: self.accessKey, - keywordPath: self.keywordPath, - onWakeWordDetection: self.onWakeWordDetection, - contextPath: self.contextPath, - onInference: self.onInference, - porcupineModelPath: self.porcupineModelPath, - porcupineSensitivity: self.porcupineSensitivity, - rhinoModelPath: self.rhinoModelPath, - rhinoSensitivity: self.rhinoSensitivity, - endpointDurationSec: self.endpointDurationSec, - requireEndpoint: self.requireEndpoint) + accessKey: self.accessKey, + keywordPath: self.keywordPath, + onWakeWordDetection: self.onWakeWordDetection, + contextPath: self.contextPath, + onInference: self.onInference, + porcupineModelPath: self.porcupineModelPath, + porcupineSensitivity: self.porcupineSensitivity, + rhinoModelPath: self.rhinoModelPath, + rhinoSensitivity: self.rhinoSensitivity, + endpointDurationSec: self.endpointDurationSec, + requireEndpoint: self.requireEndpoint) try VoiceProcessor.shared.start( - frameLength: Picovoice.frameLength, - sampleRate: Picovoice.sampleRate, - audioCallback: self.audioCallback + frameLength: Picovoice.frameLength, + sampleRate: Picovoice.sampleRate, + audioCallback: self.audioCallback ) } From c2112a228d0e53e4059f5cb73c7d6b811bd100aa Mon Sep 17 00:00:00 2001 From: Kwangsoo Yeo Date: Thu, 11 May 2023 16:20:51 -0700 Subject: [PATCH 02/15] fix --- .../ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift index 63dde3763..5f18aa083 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift @@ -12,7 +12,7 @@ import Picovoice struct ContentView: View { - let ACCESS_KEY = "Tw4jothrMMLyRYQ793yD/XF3DeithcbeNVsYlNN0Dc1vY26suWNOkg==" + let ACCESS_KEY = "${YOUR_ACCESS_KEY_HERE}" let language: String = ProcessInfo.processInfo.environment["LANGUAGE"]! let wakeword: String = ProcessInfo.processInfo.environment["WAKEWORD"]! From dfba86d9c7f8f4c6163399df04171b37cd70c18e Mon Sep 17 00:00:00 2001 From: Kwangsoo Yeo Date: Thu, 11 May 2023 17:02:56 -0700 Subject: [PATCH 03/15] update demo and lint --- .../ios-swiftui/BaristaDemo/ContentView.swift | 28 ++- demo/ios-swiftui/BaristaDemo/ViewModel.swift | 22 +- .../ContentView.swift | 108 ++++---- .../NotificationManager.swift | 6 +- .../xcshareddata/xcschemes/arDemo.xcscheme | 3 +- .../xcshareddata/xcschemes/deDemo.xcscheme | 3 +- .../xcshareddata/xcschemes/enDemo.xcscheme | 4 +- .../xcshareddata/xcschemes/esDemo.xcscheme | 3 +- .../xcshareddata/xcschemes/frDemo.xcscheme | 3 +- .../xcshareddata/xcschemes/hiDemo.xcscheme | 3 +- .../xcshareddata/xcschemes/itDemo.xcscheme | 3 +- .../xcshareddata/xcschemes/jaDemo.xcscheme | 3 +- .../xcshareddata/xcschemes/koDemo.xcscheme | 3 +- .../xcshareddata/xcschemes/nlDemo.xcscheme | 3 +- .../xcshareddata/xcschemes/plDemo.xcscheme | 3 +- .../xcshareddata/xcschemes/ptDemo.xcscheme | 3 +- .../xcshareddata/xcschemes/ruDemo.xcscheme | 3 +- .../xcshareddata/xcschemes/svDemo.xcscheme | 3 +- .../xcshareddata/xcschemes/vnDemo.xcscheme | 3 +- .../xcshareddata/xcschemes/zhDemo.xcscheme | 3 +- .../ContentView.swift | 232 ++++++++++-------- demo/ios/ForegroundApp/pre-build.sh | 8 +- resources/scripts/update_languages.py | 5 +- sdk/ios/Picovoice-iOS.podspec | 4 +- sdk/ios/PicovoiceManager.swift | 6 + 25 files changed, 252 insertions(+), 216 deletions(-) diff --git a/demo/ios-swiftui/BaristaDemo/ContentView.swift b/demo/ios-swiftui/BaristaDemo/ContentView.swift index 3afd64cde..63eb9d39e 100644 --- a/demo/ios-swiftui/BaristaDemo/ContentView.swift +++ b/demo/ios-swiftui/BaristaDemo/ContentView.swift @@ -21,7 +21,7 @@ struct ContentView: View { // Size row HStack(alignment: .center, spacing: 10) { ForEach(viewModel.sizeSel) { item in - Button(action: {}) { + Button { Text(item.title) .font(.system(size: 20)) .foregroundColor(item.isSelected ? Color.white : inactiveGrey) @@ -41,10 +41,15 @@ struct ContentView: View { } // # Shot row - Text("Espresso Shots").font(.body).fontWeight(.semibold).foregroundColor(inactiveGrey).padding(.top, 8.0) + Text("Espresso Shots") + .font(.body) + .fontWeight(.semibold) + .foregroundColor(inactiveGrey) + .padding(.top, 8.0) + HStack(alignment: .center, spacing: 7) { ForEach(viewModel.shotSel) { item in - Button(action: {}) { + Button { Text(item.title) .font(.system(size: 16)) .foregroundColor(item.isSelected ? Color.white : inactiveGrey) @@ -64,11 +69,16 @@ struct ContentView: View { } // Beverage row - Text("Beverage Type").font(.body).fontWeight(.semibold).foregroundColor(inactiveGrey).padding(.top, 8.0) + Text("Beverage Type") + .font(.body) + .fontWeight(.semibold) + .foregroundColor(inactiveGrey) + .padding(.top, 8.0) + VStack(alignment: .center, spacing: 6) { HStack(alignment: .center) { ForEach(0.. Void) { + ) -> Void) { completionHandler([.badge, .banner, .sound]) } public func requestNotificationAuthorization() { - UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .sound], completionHandler: { (_, error) in + UNUserNotificationCenter.current().requestAuthorization( + options: [.badge, .alert, .sound], + completionHandler: { (_, error) in if let error = error { print("Error: ", error) } diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/arDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/arDemo.xcscheme index 303843ac4..6d2562f61 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/arDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/arDemo.xcscheme @@ -2,8 +2,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/deDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/deDemo.xcscheme index 2240ca659..34ba9fe46 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/deDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/deDemo.xcscheme @@ -2,8 +2,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/enDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/enDemo.xcscheme index c005b6db2..a2d2bba5f 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/enDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/enDemo.xcscheme @@ -10,11 +10,11 @@ ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction"> + scriptText = "${SRCROOT}/pre-build.sh en picovoice coffee_maker"> diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/esDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/esDemo.xcscheme index 65b76fc4d..ca01d8d99 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/esDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/esDemo.xcscheme @@ -2,8 +2,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/frDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/frDemo.xcscheme index 11f48b2aa..976bb1d34 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/frDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/frDemo.xcscheme @@ -2,8 +2,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/hiDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/hiDemo.xcscheme index dbe85088f..19e70ca26 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/hiDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/hiDemo.xcscheme @@ -2,8 +2,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/itDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/itDemo.xcscheme index 3de1e18b4..48dc0a9d0 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/itDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/itDemo.xcscheme @@ -2,8 +2,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/jaDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/jaDemo.xcscheme index d14b8bb6a..19d001af4 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/jaDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/jaDemo.xcscheme @@ -2,8 +2,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/koDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/koDemo.xcscheme index 721809eca..1f952138f 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/koDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/koDemo.xcscheme @@ -2,8 +2,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/nlDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/nlDemo.xcscheme index 9c82bf76a..45614c924 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/nlDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/nlDemo.xcscheme @@ -2,8 +2,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/plDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/plDemo.xcscheme index 696d921a6..c9176a8f9 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/plDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/plDemo.xcscheme @@ -2,8 +2,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ptDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ptDemo.xcscheme index 14924db58..c50acb8b3 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ptDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ptDemo.xcscheme @@ -2,8 +2,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ruDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ruDemo.xcscheme index a7ed39f75..7f3d3dbda 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ruDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ruDemo.xcscheme @@ -2,8 +2,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/svDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/svDemo.xcscheme index 897f26438..8b7359df3 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/svDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/svDemo.xcscheme @@ -2,8 +2,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/vnDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/vnDemo.xcscheme index f7439d927..1b40616f0 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/vnDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/vnDemo.xcscheme @@ -2,8 +2,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/zhDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/zhDemo.xcscheme index 487641e81..9281692c2 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/zhDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/zhDemo.xcscheme @@ -2,8 +2,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift index 5f18aa083..f1793c125 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift @@ -10,6 +10,14 @@ import SwiftUI import Picovoice +struct SheetView: View { + @Binding var contextInfo: String + + var body: some View { + Text(self.contextInfo) + } +} + struct ContentView: View { let ACCESS_KEY = "${YOUR_ACCESS_KEY_HERE}" @@ -24,125 +32,131 @@ struct ContentView: View { @State var buttonLabel = "START" @State var result: String = "" @State var errorMessage: String = "" + @State var contextInfo: String = "" + @State var showInfo: Bool = false var body: some View { + NavigationView { + VStack { + Spacer() + Spacer() + Text("\(result)") + .foregroundColor(Color.black) + .padding() - VStack { - Spacer() - Spacer() - Text("\(result)") - .foregroundColor(Color.black) - .padding() - - Text(errorMessage) - .padding() - .background(Color.red) - .foregroundColor(Color.white) - .frame(minWidth: 0, maxWidth: UIScreen.main.bounds.width - 50) - .font(.body) - .opacity(errorMessage.isEmpty ? 0 : 1) - .cornerRadius(.infinity) - Spacer() - - Text("Wake word: \(wakeword)\nContext: \(context)") - .padding() - .foregroundColor(Color.black) - .multilineTextAlignment(.center) - - Button(action: { - if self.buttonLabel == "START" { - self.textTimer?.invalidate() - self.result = "" - - let token = (language == "en") ? "" : "_\(language)" - - let keywordPath = Bundle.main.url( - forResource: "\(wakeword)_ios", - withExtension: "ppn", - subdirectory: "keywords")! - let ppnModelPath = Bundle.main.url( - forResource: "porcupine_params\(token)", - withExtension: "pv", - subdirectory: "models")! - - let contextPath = Bundle.main.url( - forResource: "\(context)_ios", - withExtension: "rhn", - subdirectory: "contexts")! - let rhnModelPath = Bundle.main.url( - forResource: "rhino_params\(token)", - withExtension: "pv", - subdirectory: "models")! - - do { - self.picovoiceManager = PicovoiceManager( - accessKey: self.ACCESS_KEY, - keywordPath: keywordPath.path, - onWakeWordDetection: { - result = "Wake Word Detected!\nListening for command..." - }, - contextPath: contextPath.path, - onInference: { x in - DispatchQueue.main.async { - result = "{\n" - self.result += " \"isUnderstood\" : \"" + x.isUnderstood.description + "\",\n" - if x.isUnderstood { - self.result += " \"intent : \"" + x.intent + "\",\n" - if !x.slots.isEmpty { - result += " \"slots\" : {\n" - for (k, v) in x.slots { - self.result += " \"" + k + "\" : \"" + v + "\",\n" + Text(errorMessage) + .padding() + .background(Color.red) + .foregroundColor(Color.white) + .frame(minWidth: 0, maxWidth: UIScreen.main.bounds.width - 50) + .font(.body) + .opacity(errorMessage.isEmpty ? 0 : 1) + .cornerRadius(.infinity) + Spacer() + + Button { + if self.buttonLabel == "START" { + self.textTimer?.invalidate() + self.result = "" + + let token = (language == "en") ? "" : "_\(language)" + + let keywordPath = Bundle.main.url( + forResource: "\(wakeword)_ios", + withExtension: "ppn", + subdirectory: "keywords")! + let ppnModelPath = Bundle.main.url( + forResource: "porcupine_params\(token)", + withExtension: "pv", + subdirectory: "models")! + + let contextPath = Bundle.main.url( + forResource: "\(context)_ios", + withExtension: "rhn", + subdirectory: "contexts")! + let rhnModelPath = Bundle.main.url( + forResource: "rhino_params\(token)", + withExtension: "pv", + subdirectory: "models")! + + do { + self.picovoiceManager = PicovoiceManager( + accessKey: self.ACCESS_KEY, + keywordPath: keywordPath.path, + onWakeWordDetection: { + result = "Wake Word Detected!\nListening for command..." + }, + contextPath: contextPath.path, + onInference: { x in + DispatchQueue.main.async { + result = "{\n" + self.result += " \"isUnderstood\" : \"" + + x.isUnderstood.description + "\",\n" + if x.isUnderstood { + self.result += " \"intent : \"" + x.intent + "\",\n" + if !x.slots.isEmpty { + result += " \"slots\" : {\n" + for (k, v) in x.slots { + self.result += " \"" + k + "\" : \"" + v + "\",\n" + } + result += " }\n" } - result += " }\n" } + result += "}\n" } - result += "}\n" - } - self.textTimer = Timer.scheduledTimer(withTimeInterval: 1.75, repeats: false) { _ in - if buttonLabel == "STOP" { - result = "Listening for Wake Word.." + self.textTimer = Timer.scheduledTimer(withTimeInterval: 1.75, repeats: false) { _ in + if buttonLabel == "STOP" { + result = "Listening for Wake Word.." + } } - } - }, - porcupineModelPath: ppnModelPath.path, - rhinoModelPath: rhnModelPath.path) - - try self.picovoiceManager.start() - - self.buttonLabel = "STOP" - self.result = "Listening for Wake Word..." - } catch let error as PicovoiceInvalidArgumentError { - errorMessage = "\(error.localizedDescription)\nEnsure your AccessKey '\(ACCESS_KEY)' is valid" - } catch is PicovoiceActivationError { - errorMessage = "ACCESS_KEY activation error" - } catch is PicovoiceActivationRefusedError { - errorMessage = "ACCESS_KEY activation refused" - } catch is PicovoiceActivationLimitError { - errorMessage = "ACCESS_KEY reached its limit" - } catch is PicovoiceActivationThrottledError { - errorMessage = "ACCESS_KEY is throttled" - } catch { - errorMessage = "\(error)" + }, + porcupineModelPath: ppnModelPath.path, + rhinoModelPath: rhnModelPath.path) + + try self.picovoiceManager.start() + + self.buttonLabel = "STOP" + self.result = "Listening for '\(wakeword.uppercased())'..." + } catch let error as PicovoiceInvalidArgumentError { + errorMessage = + "\(error.localizedDescription)\nEnsure your AccessKey '\(ACCESS_KEY)' is valid" + } catch is PicovoiceActivationError { + errorMessage = "ACCESS_KEY activation error" + } catch is PicovoiceActivationRefusedError { + errorMessage = "ACCESS_KEY activation refused" + } catch is PicovoiceActivationLimitError { + errorMessage = "ACCESS_KEY reached its limit" + } catch is PicovoiceActivationThrottledError { + errorMessage = "ACCESS_KEY is throttled" + } catch { + errorMessage = "\(error)" + } + + } else { + self.picovoiceManager.stop() + self.buttonLabel = "START" + self.result = "" + self.textTimer?.invalidate() } - - } else { - self.picovoiceManager.stop() - self.buttonLabel = "START" - self.result = "" - self.textTimer?.invalidate() - } - }) { - Text("\(buttonLabel)") - .padding() - .background(errorMessage.isEmpty ? Color.blue : Color.gray) - .foregroundColor(Color.white) - .font(.largeTitle) - }.disabled(!errorMessage.isEmpty) + } label: { + Text("\(buttonLabel)") + .padding() + .background(errorMessage.isEmpty ? Color.blue : Color.gray) + .foregroundColor(Color.white) + .font(.largeTitle) + }.disabled(!errorMessage.isEmpty) + } + .padding() + .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity) + .background(Color.white) + .navigationBarItems(trailing: Button("Context Info") { + self.showInfo = true + }) + } + .sheet(isPresented: self.$showInfo) { + SheetView(contextInfo: self.$contextInfo) } - .padding() - .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity) - .background(Color.white) } } diff --git a/demo/ios/ForegroundApp/pre-build.sh b/demo/ios/ForegroundApp/pre-build.sh index 8fbad39d6..275297e2a 100755 --- a/demo/ios/ForegroundApp/pre-build.sh +++ b/demo/ios/ForegroundApp/pre-build.sh @@ -10,13 +10,13 @@ rm "${SRCROOT}/PicovoiceForegroundAppDemo/models/"* if [ $1 == 'en' ]; then - cp "${SRCROOT}/../../../resources/porcupine/resources/keyword_files/ios/"* "${SRCROOT}/PicovoiceForegroundAppDemo/keywords/" + cp "${SRCROOT}/../../../resources/porcupine/resources/keyword_files/ios/$2_ios.ppn" "${SRCROOT}/PicovoiceForegroundAppDemo/keywords/" cp "${SRCROOT}/../../../resources/porcupine/lib/common/porcupine_params.pv" "${SRCROOT}/PicovoiceForegroundAppDemo/models/" - cp "${SRCROOT}/../../../resources/rhino/resources/contexts/ios/"* "${SRCROOT}/PicovoiceForegroundAppDemo/contexts/" + cp "${SRCROOT}/../../../resources/rhino/resources/contexts/ios/$3_ios.rhn" "${SRCROOT}/PicovoiceForegroundAppDemo/contexts/" cp "${SRCROOT}/../../../resources/rhino/lib/common/rhino_params.pv" "${SRCROOT}/PicovoiceForegroundAppDemo/models/" else - cp "${SRCROOT}/../../../resources/porcupine/resources/keyword_files_$1/ios/"* "${SRCROOT}/PicovoiceForegroundAppDemo/keywords/" + cp "${SRCROOT}/../../../resources/porcupine/resources/keyword_files_$1/ios/$2_ios.ppn" "${SRCROOT}/PicovoiceForegroundAppDemo/keywords/" cp "${SRCROOT}/../../../resources/porcupine/lib/common/porcupine_params_$1.pv" "${SRCROOT}/PicovoiceForegroundAppDemo/models/" - cp "${SRCROOT}/../../../resources/rhino/resources/contexts_$1/ios/"* "${SRCROOT}/PicovoiceForegroundAppDemo/contexts/" + cp "${SRCROOT}/../../../resources/rhino/resources/contexts_$1/ios/$3_ios.rhn" "${SRCROOT}/PicovoiceForegroundAppDemo/contexts/" cp "${SRCROOT}/../../../resources/rhino/lib/common/rhino_params_$1.pv" "${SRCROOT}/PicovoiceForegroundAppDemo/models/" fi diff --git a/resources/scripts/update_languages.py b/resources/scripts/update_languages.py index 268dd91eb..c825aafa3 100644 --- a/resources/scripts/update_languages.py +++ b/resources/scripts/update_languages.py @@ -35,7 +35,10 @@ def update_ios_demo(parameters): pre_build_action = base_scheme_content.getElementsByTagName('ActionContent')[0] pre_build_action.setAttribute( 'scriptText', - pre_build_action.attributes['scriptText'].value.replace(" en", f" {language}")) + pre_build_action.attributes['scriptText'].value + .replace(" en", f" {language}") + .replace(" picovoice", f" {parameter['wakeword']}") + .replace(" coffee_maker", f" {parameter['context']}")) env_vars = base_scheme_content.getElementsByTagName('EnvironmentVariable') for env_var in env_vars: diff --git a/sdk/ios/Picovoice-iOS.podspec b/sdk/ios/Picovoice-iOS.podspec index d3beb20a1..8393110ec 100644 --- a/sdk/ios/Picovoice-iOS.podspec +++ b/sdk/ios/Picovoice-iOS.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = 'Picovoice-iOS' s.module_name = 'Picovoice' - s.version = '2.2.0' + s.version = '2.2.1' s.license = {:type => 'Apache 2.0'} s.summary = 'iOS SDK for the Picovoice Offline Voice Recognition Platform' s.description = @@ -18,7 +18,7 @@ Pod::Spec.new do |s| DESC s.homepage = 'https://github.com/Picovoice/picovoice/tree/master/sdk/ios' s.author = { 'Picovoice' => 'hello@picovoice.ai' } - s.source = { :git => "https://github.com/Picovoice/picovoice.git", :tag => "Picovoice-iOS-v2.2.0" } + s.source = { :git => "https://github.com/Picovoice/picovoice.git", :tag => "Picovoice-iOS-v2.2.1" } s.ios.deployment_target = '11.0' s.swift_version = '5.0' s.source_files = 'sdk/ios/*.{swift}' diff --git a/sdk/ios/PicovoiceManager.swift b/sdk/ios/PicovoiceManager.swift index 02de15bfa..ddb2aee25 100644 --- a/sdk/ios/PicovoiceManager.swift +++ b/sdk/ios/PicovoiceManager.swift @@ -32,6 +32,12 @@ public class PicovoiceManager { private var processErrorCallback: ((PicovoiceError) -> Void)? + public var contextInfo: String { + get { + return (self.picovoice != nil) ? self.picovoice.contextInfo : "" + } + } + /// Constructor. /// /// - Parameters: From 924acb9c48d77f1dfe8ee82d7d7ba1f3ecf03aee Mon Sep 17 00:00:00 2001 From: Kwangsoo Yeo Date: Thu, 11 May 2023 17:44:14 -0700 Subject: [PATCH 04/15] address issues based on rhino --- .../ContentView.swift | 32 +++++----- demo/ios/ForegroundApp/pre-build.sh | 2 - demo/ios/README.md | 61 +------------------ sdk/ios/PicovoiceManager.swift | 2 +- 4 files changed, 19 insertions(+), 78 deletions(-) diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift index f1793c125..a78595df8 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift @@ -59,34 +59,34 @@ struct ContentView: View { self.textTimer?.invalidate() self.result = "" - let token = (language == "en") ? "" : "_\(language)" - let keywordPath = Bundle.main.url( forResource: "\(wakeword)_ios", withExtension: "ppn", - subdirectory: "keywords")! - let ppnModelPath = Bundle.main.url( - forResource: "porcupine_params\(token)", - withExtension: "pv", - subdirectory: "models")! + subdirectory: "keywords")!.path + let ppnModelPath = (language == "en") ? nil : + Bundle.main.url( + forResource: "porcupine_params_\(language)", + withExtension: "pv", + subdirectory: "models")!.path let contextPath = Bundle.main.url( forResource: "\(context)_ios", withExtension: "rhn", - subdirectory: "contexts")! - let rhnModelPath = Bundle.main.url( - forResource: "rhino_params\(token)", - withExtension: "pv", - subdirectory: "models")! + subdirectory: "contexts")!.path + let rhnModelPath = (language == "en") ? nil : + Bundle.main.url( + forResource: "rhino_params_\(language)", + withExtension: "pv", + subdirectory: "models")!.path do { self.picovoiceManager = PicovoiceManager( accessKey: self.ACCESS_KEY, - keywordPath: keywordPath.path, + keywordPath: keywordPath, onWakeWordDetection: { result = "Wake Word Detected!\nListening for command..." }, - contextPath: contextPath.path, + contextPath: contextPath, onInference: { x in DispatchQueue.main.async { result = "{\n" @@ -111,8 +111,8 @@ struct ContentView: View { } } }, - porcupineModelPath: ppnModelPath.path, - rhinoModelPath: rhnModelPath.path) + porcupineModelPath: ppnModelPath, + rhinoModelPath: rhnModelPath) try self.picovoiceManager.start() diff --git a/demo/ios/ForegroundApp/pre-build.sh b/demo/ios/ForegroundApp/pre-build.sh index 275297e2a..0feeed8f1 100755 --- a/demo/ios/ForegroundApp/pre-build.sh +++ b/demo/ios/ForegroundApp/pre-build.sh @@ -11,9 +11,7 @@ rm "${SRCROOT}/PicovoiceForegroundAppDemo/models/"* if [ $1 == 'en' ]; then cp "${SRCROOT}/../../../resources/porcupine/resources/keyword_files/ios/$2_ios.ppn" "${SRCROOT}/PicovoiceForegroundAppDemo/keywords/" - cp "${SRCROOT}/../../../resources/porcupine/lib/common/porcupine_params.pv" "${SRCROOT}/PicovoiceForegroundAppDemo/models/" cp "${SRCROOT}/../../../resources/rhino/resources/contexts/ios/$3_ios.rhn" "${SRCROOT}/PicovoiceForegroundAppDemo/contexts/" - cp "${SRCROOT}/../../../resources/rhino/lib/common/rhino_params.pv" "${SRCROOT}/PicovoiceForegroundAppDemo/models/" else cp "${SRCROOT}/../../../resources/porcupine/resources/keyword_files_$1/ios/$2_ios.ppn" "${SRCROOT}/PicovoiceForegroundAppDemo/keywords/" cp "${SRCROOT}/../../../resources/porcupine/lib/common/porcupine_params_$1.pv" "${SRCROOT}/PicovoiceForegroundAppDemo/models/" diff --git a/demo/ios/README.md b/demo/ios/README.md index bf53d3b2b..6a328fe6f 100644 --- a/demo/ios/README.md +++ b/demo/ios/README.md @@ -36,62 +36,5 @@ To run the foreground application demo: 5) Run the demo with a simulator or connected iOS device -The default wake word is `Picovoice`. The default Rhino Speech-to-Intent context is `Smart Lighting`. Simply press start and the engine can recognize commands such as: - -> Picovoice, turn off the lights. - -or - -> Picovoice, set the lights in the bedroom to blue. - -See below for the full context: - -```yaml -context: - expressions: - changeColor: - - "[turn, make] (all, the) lights $color:color" - - "[change, set, switch] (all, the) lights to $color:color" - - "[turn, make] (the) $location:location (color, light, lights) $color:color" - - "[change, set, switch] (the) $location:location (color, light, lights) to $color:color" - - "[turn, make] (the) [color, light, lights] [at, in] (the) $location:location $color:color" - - "[change, set, switch] (the) [color, light, lights] [at, in] (the) $location:location to $color:color" - - "[turn, make] (the) [color, light, lights] $color:color [at, in] (the) $location:location" - - "[change, set, switch] (the) [color, light, lights] to $color:color [at, in] (the) $location:location" - changeLightState: - - "[switch, turn] $state:state (all, the) lights" - - "[switch, turn] (all, the) lights $state:state" - - "[switch, turn] $state:state (the) $location:location (light, lights)" - - "[switch, turn] (the) $location:location [light, lights] $state:state" - - "[switch, turn] $state:state (the) [light, lights] [at, in] (the) $location:location" - - "[switch, turn] (the) [light, lights] [in, at] the $location:location $state:state" - changeLightStateOff: - - "shut off (all, the) lights" - - "shut (all, the) lights off" - - "shut off (the) $location:location (light, lights)" - - "shut (the) $location:location (light, lights) off" - - "shut off (the) [light, lights] [at, in] (the) $location:location" - - "shut (the) [light, lights] off [at, in] (the) $location:location" - - "shut (the) [light, lights] [at, in] (the) $location:location off" - slots: - color: - - "blue" - - "green" - - "orange" - - "pink" - - "purple" - - "red" - - "white" - - "yellow" - state: - - "off" - - "on" - location: - - "bathroom" - - "bedroom" - - "closet" - - "hallway" - - "kitchen" - - "living room" - - "pantry" -``` +6) Once the demo app has started, press the `start` button to start detecing keywords and infering context. To see more details about +the current context information, press the `Context Info` button on the top right corner in the app. diff --git a/sdk/ios/PicovoiceManager.swift b/sdk/ios/PicovoiceManager.swift index ddb2aee25..c5a5f3a76 100644 --- a/sdk/ios/PicovoiceManager.swift +++ b/sdk/ios/PicovoiceManager.swift @@ -34,7 +34,7 @@ public class PicovoiceManager { public var contextInfo: String { get { - return (self.picovoice != nil) ? self.picovoice.contextInfo : "" + return (self.picovoice != nil) ? self.picovoice!.contextInfo : "" } } From a73134697ca5e345baf08ba8b542ce613a409ff9 Mon Sep 17 00:00:00 2001 From: Kwangsoo Yeo Date: Fri, 12 May 2023 11:20:40 -0700 Subject: [PATCH 05/15] update demo and fix dict --- .../NotificationManager.swift | 8 +- .../ContentView.swift | 124 ++++++++++-------- demo/ios/README.md | 2 +- 3 files changed, 73 insertions(+), 61 deletions(-) diff --git a/demo/ios/BackgroundService/PicovoiceBackgroundServiceDemo/NotificationManager.swift b/demo/ios/BackgroundService/PicovoiceBackgroundServiceDemo/NotificationManager.swift index 3108b1bb6..43db50a43 100644 --- a/demo/ios/BackgroundService/PicovoiceBackgroundServiceDemo/NotificationManager.swift +++ b/demo/ios/BackgroundService/PicovoiceBackgroundServiceDemo/NotificationManager.swift @@ -38,10 +38,10 @@ class NotificationManager: NSObject, UNUserNotificationCenterDelegate { UNUserNotificationCenter.current().requestAuthorization( options: [.badge, .alert, .sound], completionHandler: { (_, error) in - if let error = error { - print("Error: ", error) - } - }) + if let error = error { + print("Error: ", error) + } + }) } public func sendNotification(message: String) { diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift index a78595df8..1c2f28f5b 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift @@ -14,7 +14,11 @@ struct SheetView: View { @Binding var contextInfo: String var body: some View { - Text(self.contextInfo) + ScrollView { + Text(self.contextInfo) + .padding() + .font(.system(size: 14)) + } } } @@ -35,6 +39,62 @@ struct ContentView: View { @State var contextInfo: String = "" @State var showInfo: Bool = false + func initPicovoice() { + let keywordPath = Bundle.main.url( + forResource: "\(wakeword)_ios", + withExtension: "ppn", + subdirectory: "keywords")!.path + let ppnModelPath = (language == "en") ? nil : + Bundle.main.url( + forResource: "porcupine_params_\(language)", + withExtension: "pv", + subdirectory: "models")!.path + + let contextPath = Bundle.main.url( + forResource: "\(context)_ios", + withExtension: "rhn", + subdirectory: "contexts")!.path + let rhnModelPath = (language == "en") ? nil : + Bundle.main.url( + forResource: "rhino_params_\(language)", + withExtension: "pv", + subdirectory: "models")!.path + + self.picovoiceManager = PicovoiceManager( + accessKey: self.ACCESS_KEY, + keywordPath: keywordPath, + onWakeWordDetection: { + result = "Wake Word Detected!\nListening for command..." + }, + contextPath: contextPath, + onInference: { x in + DispatchQueue.main.async { + result = "{\n" + self.result += " \"isUnderstood\" : \"" + + x.isUnderstood.description + "\",\n" + if x.isUnderstood { + self.result += " \"intent : \"" + x.intent + "\",\n" + if !x.slots.isEmpty { + result += " \"slots\" : {\n" + for (k, v) in x.slots { + self.result += " \"" + k + "\" : \"" + v + "\",\n" + } + result += " }\n" + } + } + result += "}\n" + } + + self.textTimer = Timer.scheduledTimer(withTimeInterval: 1.75, repeats: false) { _ in + if buttonLabel == "STOP" { + result = "Listening for Wake Word.." + } + } + }, + porcupineModelPath: ppnModelPath, + rhinoModelPath: rhnModelPath) + } + var body: some View { NavigationView { VStack { @@ -58,64 +118,13 @@ struct ContentView: View { if self.buttonLabel == "START" { self.textTimer?.invalidate() self.result = "" - - let keywordPath = Bundle.main.url( - forResource: "\(wakeword)_ios", - withExtension: "ppn", - subdirectory: "keywords")!.path - let ppnModelPath = (language == "en") ? nil : - Bundle.main.url( - forResource: "porcupine_params_\(language)", - withExtension: "pv", - subdirectory: "models")!.path - - let contextPath = Bundle.main.url( - forResource: "\(context)_ios", - withExtension: "rhn", - subdirectory: "contexts")!.path - let rhnModelPath = (language == "en") ? nil : - Bundle.main.url( - forResource: "rhino_params_\(language)", - withExtension: "pv", - subdirectory: "models")!.path + if self.picovoiceManager == nil { + self.initPicovoice() + } do { - self.picovoiceManager = PicovoiceManager( - accessKey: self.ACCESS_KEY, - keywordPath: keywordPath, - onWakeWordDetection: { - result = "Wake Word Detected!\nListening for command..." - }, - contextPath: contextPath, - onInference: { x in - DispatchQueue.main.async { - result = "{\n" - self.result += " \"isUnderstood\" : \"" + - x.isUnderstood.description + "\",\n" - if x.isUnderstood { - self.result += " \"intent : \"" + x.intent + "\",\n" - if !x.slots.isEmpty { - result += " \"slots\" : {\n" - for (k, v) in x.slots { - self.result += " \"" + k + "\" : \"" + v + "\",\n" - } - result += " }\n" - } - } - result += "}\n" - } - - self.textTimer = Timer.scheduledTimer(withTimeInterval: 1.75, repeats: false) { _ in - if buttonLabel == "STOP" { - result = "Listening for Wake Word.." - } - } - }, - porcupineModelPath: ppnModelPath, - rhinoModelPath: rhnModelPath) - try self.picovoiceManager.start() - + self.contextInfo = "" self.buttonLabel = "STOP" self.result = "Listening for '\(wakeword.uppercased())'..." } catch let error as PicovoiceInvalidArgumentError { @@ -151,6 +160,9 @@ struct ContentView: View { .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity) .background(Color.white) .navigationBarItems(trailing: Button("Context Info") { + if self.picovoiceManager == nil { + initPicovoice() + } self.showInfo = true }) } diff --git a/demo/ios/README.md b/demo/ios/README.md index 6a328fe6f..d8ebdfaca 100644 --- a/demo/ios/README.md +++ b/demo/ios/README.md @@ -36,5 +36,5 @@ To run the foreground application demo: 5) Run the demo with a simulator or connected iOS device -6) Once the demo app has started, press the `start` button to start detecing keywords and infering context. To see more details about +6) Once the demo app has started, press the `start` button to start detecting keywords and inferring context. To see more details about the current context information, press the `Context Info` button on the top right corner in the app. From 661005adec41fcb4d488f2334e884a0e3dcb2aa7 Mon Sep 17 00:00:00 2001 From: Kwangsoo Yeo Date: Fri, 12 May 2023 17:07:31 -0700 Subject: [PATCH 06/15] add check --- .../PicovoiceForegroundAppDemo/ContentView.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift index 1c2f28f5b..244c2555a 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift @@ -163,7 +163,9 @@ struct ContentView: View { if self.picovoiceManager == nil { initPicovoice() } - self.showInfo = true + if self.picovoiceManager != nil { + self.showInfo = true + } }) } .sheet(isPresented: self.$showInfo) { From d1d1952525e2641e0a115a4632ff40e583c97e7b Mon Sep 17 00:00:00 2001 From: Kwangsoo Yeo Date: Mon, 15 May 2023 12:47:19 -0700 Subject: [PATCH 07/15] update rhino pac --- sdk/ios/Picovoice-iOS.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/ios/Picovoice-iOS.podspec b/sdk/ios/Picovoice-iOS.podspec index 8393110ec..c9c341f9e 100644 --- a/sdk/ios/Picovoice-iOS.podspec +++ b/sdk/ios/Picovoice-iOS.podspec @@ -25,6 +25,6 @@ Pod::Spec.new do |s| s.exclude_files = 'sdk/ios/PicovoiceAppTest/**' s.dependency 'Porcupine-iOS', '~> 2.2.0' - s.dependency 'Rhino-iOS', '~> 2.2.0' + s.dependency 'Rhino-iOS', '~> 2.2.1' s.dependency 'ios-voice-processor', '~> 1.0.2' end From a93be4fe04e2c0b4ed4b0a50bc418c33de3effb1 Mon Sep 17 00:00:00 2001 From: Kwangsoo Yeo Date: Mon, 15 May 2023 13:03:06 -0700 Subject: [PATCH 08/15] update values --- sdk/ios/Picovoice.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/ios/Picovoice.swift b/sdk/ios/Picovoice.swift index 6c478f3d6..07b7dd4d0 100644 --- a/sdk/ios/Picovoice.swift +++ b/sdk/ios/Picovoice.swift @@ -25,7 +25,7 @@ public class Picovoice { public static let sampleRate = Porcupine.sampleRate public static let porcupineVersion = Porcupine.version public static let rhinoVersion = Rhino.version - public static let picovoiceVersion = "2.1.0" + public static let picovoiceVersion = "2.2.0" public var contextInfo: String? = "" private var isWakeWordDetected: Bool = false @@ -86,7 +86,7 @@ public class Picovoice { endpointDurationSec: endpointDurationSec, requireEndpoint: requireEndpoint) - contextInfo = rhino?.contextInfo + contextInfo = (rhino != nil) ? rhino!.contextInfo : "" } catch { throw mapToPicovoiceError(error) } From 3926e14b613f1db79a9a9f2c76f79951239118f9 Mon Sep 17 00:00:00 2001 From: Kwangsoo Yeo Date: Mon, 15 May 2023 13:23:29 -0700 Subject: [PATCH 09/15] fix sig --- sdk/ios/Picovoice.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/ios/Picovoice.swift b/sdk/ios/Picovoice.swift index 07b7dd4d0..d2805dfea 100644 --- a/sdk/ios/Picovoice.swift +++ b/sdk/ios/Picovoice.swift @@ -26,7 +26,7 @@ public class Picovoice { public static let porcupineVersion = Porcupine.version public static let rhinoVersion = Rhino.version public static let picovoiceVersion = "2.2.0" - public var contextInfo: String? = "" + public var contextInfo: String = "" private var isWakeWordDetected: Bool = false From c7aebf79e3d540a4e47efdd4069ccf9e340cd8c8 Mon Sep 17 00:00:00 2001 From: Kwangsoo Yeo Date: Mon, 15 May 2023 13:56:12 -0700 Subject: [PATCH 10/15] udpate demo --- .../PicovoiceForegroundAppDemo/ContentView.swift | 7 ++++++- demo/ios/ForegroundApp/Podfile | 2 +- demo/ios/ForegroundApp/Podfile.lock | 14 +++++++------- sdk/ios/PicovoiceAppTest/Podfile | 4 ++-- sdk/ios/PicovoiceAppTest/Podfile.lock | 16 ++++++++-------- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift index 244c2555a..45104ad98 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift @@ -93,6 +93,12 @@ struct ContentView: View { }, porcupineModelPath: ppnModelPath, rhinoModelPath: rhnModelPath) + + do { + try self.picovoiceManager.start() + self.contextInfo = self.picovoiceManager.contextInfo + self.picovoiceManager.stop() + } catch { } } var body: some View { @@ -124,7 +130,6 @@ struct ContentView: View { do { try self.picovoiceManager.start() - self.contextInfo = "" self.buttonLabel = "STOP" self.result = "Listening for '\(wakeword.uppercased())'..." } catch let error as PicovoiceInvalidArgumentError { diff --git a/demo/ios/ForegroundApp/Podfile b/demo/ios/ForegroundApp/Podfile index 61191234b..cfcce5997 100644 --- a/demo/ios/ForegroundApp/Podfile +++ b/demo/ios/ForegroundApp/Podfile @@ -3,5 +3,5 @@ source 'https://cdn.cocoapods.org/' platform :ios, '11.0' target 'PicovoiceForegroundAppDemo' do - pod 'Picovoice-iOS', '2.2.0' + pod 'Picovoice-iOS', '2.2.1' end diff --git a/demo/ios/ForegroundApp/Podfile.lock b/demo/ios/ForegroundApp/Podfile.lock index 016579a8a..5dbdeca7f 100644 --- a/demo/ios/ForegroundApp/Podfile.lock +++ b/demo/ios/ForegroundApp/Podfile.lock @@ -1,16 +1,16 @@ PODS: - ios-voice-processor (1.0.3) - - Picovoice-iOS (2.2.0): + - Picovoice-iOS (2.2.1): - ios-voice-processor (~> 1.0.2) - Porcupine-iOS (~> 2.2.0) - - Rhino-iOS (~> 2.2.0) + - Rhino-iOS (~> 2.2.1) - Porcupine-iOS (2.2.0): - ios-voice-processor (~> 1.0.2) - - Rhino-iOS (2.2.0): + - Rhino-iOS (2.2.1): - ios-voice-processor (~> 1.0.2) DEPENDENCIES: - - Picovoice-iOS (= 2.2.0) + - Picovoice-iOS (= 2.2.1) SPEC REPOS: trunk: @@ -21,10 +21,10 @@ SPEC REPOS: SPEC CHECKSUMS: ios-voice-processor: 65b25a8db69ea25ffba0eeef37bae71a982f34cc - Picovoice-iOS: d6e4692fad8349857c9edbaf0dfa12d6644f4b0f + Picovoice-iOS: 1e08e45a588d209c7b93b818b08e050e5c6946af Porcupine-iOS: 34f7b77fbd5f999eb9c4daa94acbb6c90c08ad1e - Rhino-iOS: 5f6c2edc809a913f7559da93fc92c0e66c7bf711 + Rhino-iOS: c6671667cfda310b8367e7c3611f247cb256f10e -PODFILE CHECKSUM: e859480d65f8db91f16bcae8fcb2b5cd2cd07dd9 +PODFILE CHECKSUM: 724181c3de99c45958994ce269bc9083f48cf64d COCOAPODS: 1.11.2 diff --git a/sdk/ios/PicovoiceAppTest/Podfile b/sdk/ios/PicovoiceAppTest/Podfile index 32a3876a7..edd2ac0d6 100644 --- a/sdk/ios/PicovoiceAppTest/Podfile +++ b/sdk/ios/PicovoiceAppTest/Podfile @@ -3,10 +3,10 @@ source 'https://cdn.cocoapods.org/' platform :ios, '11.0' target 'PicovoiceAppTest' do - pod 'Picovoice-iOS', '~> 2.2.0' + pod 'Picovoice-iOS', '~> 2.2.1' end target 'PicovoiceAppTestUITests' do - pod 'Picovoice-iOS', '~> 2.2.0' + pod 'Picovoice-iOS', '~> 2.2.1' end diff --git a/sdk/ios/PicovoiceAppTest/Podfile.lock b/sdk/ios/PicovoiceAppTest/Podfile.lock index afad72676..0638602ac 100644 --- a/sdk/ios/PicovoiceAppTest/Podfile.lock +++ b/sdk/ios/PicovoiceAppTest/Podfile.lock @@ -1,16 +1,16 @@ PODS: - ios-voice-processor (1.0.3) - - Picovoice-iOS (2.2.0): + - Picovoice-iOS (2.2.1): - ios-voice-processor (~> 1.0.2) - Porcupine-iOS (~> 2.2.0) - - Rhino-iOS (~> 2.2.0) + - Rhino-iOS (~> 2.2.1) - Porcupine-iOS (2.2.0): - ios-voice-processor (~> 1.0.2) - - Rhino-iOS (2.2.0): + - Rhino-iOS (2.2.1): - ios-voice-processor (~> 1.0.2) DEPENDENCIES: - - Picovoice-iOS (~> 2.2.0) + - Picovoice-iOS (~> 2.2.1) SPEC REPOS: trunk: @@ -21,10 +21,10 @@ SPEC REPOS: SPEC CHECKSUMS: ios-voice-processor: 65b25a8db69ea25ffba0eeef37bae71a982f34cc - Picovoice-iOS: d6e4692fad8349857c9edbaf0dfa12d6644f4b0f + Picovoice-iOS: 1e08e45a588d209c7b93b818b08e050e5c6946af Porcupine-iOS: 34f7b77fbd5f999eb9c4daa94acbb6c90c08ad1e - Rhino-iOS: 5f6c2edc809a913f7559da93fc92c0e66c7bf711 + Rhino-iOS: c6671667cfda310b8367e7c3611f247cb256f10e -PODFILE CHECKSUM: 28b71d5858306bf1259b24a6650cea93188af63d +PODFILE CHECKSUM: 243b33e4e7452d1c2f7de32eabbf48e1b4aa235b -COCOAPODS: 1.12.0 +COCOAPODS: 1.11.2 From 2b3e87f9fa55c227e3d6db0fa9481fc50bc36eac Mon Sep 17 00:00:00 2001 From: Kwangsoo Yeo Date: Mon, 15 May 2023 14:24:13 -0700 Subject: [PATCH 11/15] improve flow --- .../PicovoiceForegroundAppDemo/ContentView.swift | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift index 45104ad98..e7d6453e3 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift @@ -95,9 +95,13 @@ struct ContentView: View { rhinoModelPath: rhnModelPath) do { - try self.picovoiceManager.start() - self.contextInfo = self.picovoiceManager.contextInfo - self.picovoiceManager.stop() + if self.picovoiceManager.contextInfo == "" && buttonLabel == "START" { + try self.picovoiceManager.start() + self.contextInfo = self.picovoiceManager.contextInfo + self.picovoiceManager.stop() + } else { + self.contextInfo = self.picovoiceManager.contextInfo + } } catch { } } From 737d07cfd426f77389cef537aa6c14c20edc022c Mon Sep 17 00:00:00 2001 From: Kwangsoo Yeo Date: Mon, 15 May 2023 17:39:01 -0700 Subject: [PATCH 12/15] rebase --- .../xcshareddata/xcschemes/arDemo.xcscheme | 6 +++--- .../xcshareddata/xcschemes/deDemo.xcscheme | 2 +- .../xcshareddata/xcschemes/esDemo.xcscheme | 2 +- .../xcshareddata/xcschemes/frDemo.xcscheme | 2 +- .../xcshareddata/xcschemes/hiDemo.xcscheme | 6 +++--- .../xcshareddata/xcschemes/itDemo.xcscheme | 2 +- .../xcshareddata/xcschemes/jaDemo.xcscheme | 6 +++--- .../xcshareddata/xcschemes/koDemo.xcscheme | 6 +++--- .../xcshareddata/xcschemes/nlDemo.xcscheme | 2 +- .../xcshareddata/xcschemes/plDemo.xcscheme | 6 +++--- .../xcshareddata/xcschemes/ptDemo.xcscheme | 2 +- .../xcshareddata/xcschemes/ruDemo.xcscheme | 6 +++--- .../xcshareddata/xcschemes/svDemo.xcscheme | 6 +++--- .../xcshareddata/xcschemes/vnDemo.xcscheme | 6 +++--- .../xcshareddata/xcschemes/zhDemo.xcscheme | 6 +++--- 15 files changed, 33 insertions(+), 33 deletions(-) diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/arDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/arDemo.xcscheme index 6d2562f61..a3656322a 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/arDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/arDemo.xcscheme @@ -2,9 +2,9 @@ - + - + @@ -33,7 +33,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/deDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/deDemo.xcscheme index 34ba9fe46..2c4249755 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/deDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/deDemo.xcscheme @@ -4,7 +4,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/esDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/esDemo.xcscheme index ca01d8d99..410737bae 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/esDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/esDemo.xcscheme @@ -4,7 +4,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/frDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/frDemo.xcscheme index 976bb1d34..e27b799d0 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/frDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/frDemo.xcscheme @@ -4,7 +4,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/hiDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/hiDemo.xcscheme index 19e70ca26..0e9a29713 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/hiDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/hiDemo.xcscheme @@ -2,9 +2,9 @@ - + - + @@ -33,7 +33,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/itDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/itDemo.xcscheme index 48dc0a9d0..c42e846b5 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/itDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/itDemo.xcscheme @@ -4,7 +4,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/jaDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/jaDemo.xcscheme index 19d001af4..6bc9d1587 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/jaDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/jaDemo.xcscheme @@ -2,9 +2,9 @@ - + - + @@ -33,7 +33,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/koDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/koDemo.xcscheme index 1f952138f..c530ece1f 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/koDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/koDemo.xcscheme @@ -2,9 +2,9 @@ - + - + @@ -33,7 +33,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/nlDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/nlDemo.xcscheme index 45614c924..4ae3dd922 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/nlDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/nlDemo.xcscheme @@ -4,7 +4,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/plDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/plDemo.xcscheme index c9176a8f9..84ca52323 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/plDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/plDemo.xcscheme @@ -2,9 +2,9 @@ - + - + @@ -33,7 +33,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ptDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ptDemo.xcscheme index c50acb8b3..77683f641 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ptDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ptDemo.xcscheme @@ -4,7 +4,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ruDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ruDemo.xcscheme index 7f3d3dbda..201fb20f0 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ruDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/ruDemo.xcscheme @@ -2,9 +2,9 @@ - + - + @@ -33,7 +33,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/svDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/svDemo.xcscheme index 8b7359df3..3c2dfdd9b 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/svDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/svDemo.xcscheme @@ -2,9 +2,9 @@ - + - + @@ -33,7 +33,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/vnDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/vnDemo.xcscheme index 1b40616f0..0ae06fb5f 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/vnDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/vnDemo.xcscheme @@ -2,9 +2,9 @@ - + - + @@ -33,7 +33,7 @@ - + diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/zhDemo.xcscheme b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/zhDemo.xcscheme index 9281692c2..40d1977bb 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/zhDemo.xcscheme +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo.xcodeproj/xcshareddata/xcschemes/zhDemo.xcscheme @@ -2,9 +2,9 @@ - + - + @@ -33,7 +33,7 @@ - + From 614a1224e0e10d880a0d5fa103200fa52f3b8d47 Mon Sep 17 00:00:00 2001 From: Kwangsoo Yeo Date: Tue, 16 May 2023 10:30:37 -0700 Subject: [PATCH 13/15] rev v1 --- .../ContentView.swift | 60 ++++++++++--------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift index e7d6453e3..8ead5d2e9 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift @@ -93,16 +93,28 @@ struct ContentView: View { }, porcupineModelPath: ppnModelPath, rhinoModelPath: rhnModelPath) - + } + + func startPicovoice() -> Bool { do { - if self.picovoiceManager.contextInfo == "" && buttonLabel == "START" { - try self.picovoiceManager.start() - self.contextInfo = self.picovoiceManager.contextInfo - self.picovoiceManager.stop() - } else { - self.contextInfo = self.picovoiceManager.contextInfo - } - } catch { } + try self.picovoiceManager.start() + return true + } catch let error as PicovoiceInvalidArgumentError { + errorMessage = + "\(error.localizedDescription)\nEnsure your AccessKey '\(ACCESS_KEY)' is valid" + } catch is PicovoiceActivationError { + errorMessage = "ACCESS_KEY activation error" + } catch is PicovoiceActivationRefusedError { + errorMessage = "ACCESS_KEY activation refused" + } catch is PicovoiceActivationLimitError { + errorMessage = "ACCESS_KEY reached its limit" + } catch is PicovoiceActivationThrottledError { + errorMessage = "ACCESS_KEY is throttled" + } catch { + errorMessage = "\(error)" + } + + return false } var body: some View { @@ -131,26 +143,12 @@ struct ContentView: View { if self.picovoiceManager == nil { self.initPicovoice() } - - do { - try self.picovoiceManager.start() + + if startPicovoice() { self.buttonLabel = "STOP" self.result = "Listening for '\(wakeword.uppercased())'..." - } catch let error as PicovoiceInvalidArgumentError { - errorMessage = - "\(error.localizedDescription)\nEnsure your AccessKey '\(ACCESS_KEY)' is valid" - } catch is PicovoiceActivationError { - errorMessage = "ACCESS_KEY activation error" - } catch is PicovoiceActivationRefusedError { - errorMessage = "ACCESS_KEY activation refused" - } catch is PicovoiceActivationLimitError { - errorMessage = "ACCESS_KEY reached its limit" - } catch is PicovoiceActivationThrottledError { - errorMessage = "ACCESS_KEY is throttled" - } catch { - errorMessage = "\(error)" + self.contextInfo = self.picovoiceManager.contextInfo } - } else { self.picovoiceManager.stop() self.buttonLabel = "START" @@ -173,7 +171,15 @@ struct ContentView: View { initPicovoice() } if self.picovoiceManager != nil { - self.showInfo = true + if self.buttonLabel == "START" { + if self.startPicovoice() { + self.contextInfo = self.picovoiceManager.contextInfo + self.showInfo = true + self.picovoiceManager.stop() + } + } else { + self.showInfo = true + } } }) } From 0bbda00f0767ff3b96faefee184476c215204334 Mon Sep 17 00:00:00 2001 From: Kwangsoo Yeo Date: Tue, 16 May 2023 10:36:05 -0700 Subject: [PATCH 14/15] fix lint --- .../PicovoiceForegroundAppDemo/ContentView.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift index 8ead5d2e9..249174369 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift @@ -94,7 +94,7 @@ struct ContentView: View { porcupineModelPath: ppnModelPath, rhinoModelPath: rhnModelPath) } - + func startPicovoice() -> Bool { do { try self.picovoiceManager.start() @@ -113,7 +113,7 @@ struct ContentView: View { } catch { errorMessage = "\(error)" } - + return false } @@ -143,7 +143,7 @@ struct ContentView: View { if self.picovoiceManager == nil { self.initPicovoice() } - + if startPicovoice() { self.buttonLabel = "STOP" self.result = "Listening for '\(wakeword.uppercased())'..." From 2e3ea621dd7036da620fe73c5dd1c824b866b4a9 Mon Sep 17 00:00:00 2001 From: Kwangsoo Yeo Date: Tue, 16 May 2023 11:12:50 -0700 Subject: [PATCH 15/15] rev v2 --- .../ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift | 2 +- demo/ios/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift index 249174369..331c72c62 100644 --- a/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift +++ b/demo/ios/ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift @@ -87,7 +87,7 @@ struct ContentView: View { self.textTimer = Timer.scheduledTimer(withTimeInterval: 1.75, repeats: false) { _ in if buttonLabel == "STOP" { - result = "Listening for Wake Word.." + result = "Listening for '\(wakeword.uppercased())'..." } } }, diff --git a/demo/ios/README.md b/demo/ios/README.md index d8ebdfaca..a0a37cbd9 100644 --- a/demo/ios/README.md +++ b/demo/ios/README.md @@ -32,7 +32,7 @@ To run the foreground application demo: 3) Replace `let accessKey = "${YOUR_ACCESS_KEY_HERE}"` in the file [ContentView.swift](./ForegroundApp/PicovoiceForegroundAppDemo/ContentView.swift) with your `AccessKey`. -4) Go to `Product > Scheme` and select the scheme for the language you would like to demo (e.g. `arScheme` -> Arabic Demo, `deScheme` -> German Demo) +4) Go to `Product > Scheme` and select the scheme for the language you would like to demo (e.g. `arDemo` -> Arabic Demo, `deDemo` -> German Demo) 5) Run the demo with a simulator or connected iOS device