From 685426aeef3d479cb8b33e37e153e9da3f97af37 Mon Sep 17 00:00:00 2001 From: Eric Mikulin Date: Wed, 4 Dec 2024 17:09:20 -0800 Subject: [PATCH 1/5] v2.1 iOS --- .github/workflows/ios-browserstack.yml | 3 + .github/workflows/ios-perf.yml | 3 + .github/workflows/swift-codestyle.yml | 4 +- binding/ios/CheetahAppTest/.gitignore | 3 + .../CheetahAppTest.xcodeproj/project.pbxproj | 66 ++++--- .../CheetahAppTestUITests.swift | 180 ++++++++++++++---- .../test_resources/.gitkeep | 0 .../ios/CheetahAppTest/copy_test_resources.sh | 17 ++ binding/ios/README.md | 14 ++ lib/ios/PvCheetah.xcframework/Info.plist | 10 +- .../PvCheetah.framework/Headers/picovoice.h | 2 + .../ios-arm64/PvCheetah.framework/Info.plist | Bin 796 -> 795 bytes .../PvCheetah.framework/Headers/picovoice.h | 2 + .../PvCheetah.framework/Info.plist | Bin 776 -> 775 bytes 14 files changed, 242 insertions(+), 62 deletions(-) create mode 100644 binding/ios/CheetahAppTest/CheetahAppTestUITests/test_resources/.gitkeep create mode 100755 binding/ios/CheetahAppTest/copy_test_resources.sh diff --git a/.github/workflows/ios-browserstack.yml b/.github/workflows/ios-browserstack.yml index 4e3d8071..01e5e220 100644 --- a/.github/workflows/ios-browserstack.yml +++ b/.github/workflows/ios-browserstack.yml @@ -36,6 +36,9 @@ jobs: - name: Make build dir run: mkdir ddp + - name: Copy test_resources + run: ./copy_test_resources.sh + - name: Inject AccessKey run: sed -i '.bak' 's:{TESTING_ACCESS_KEY_HERE}:${{secrets.PV_VALID_ACCESS_KEY}}:' CheetahAppTestUITests/CheetahAppTestUITests.swift diff --git a/.github/workflows/ios-perf.yml b/.github/workflows/ios-perf.yml index 59f73325..5a24d143 100644 --- a/.github/workflows/ios-perf.yml +++ b/.github/workflows/ios-perf.yml @@ -46,6 +46,9 @@ jobs: - name: Make build dir run: mkdir ddp + - name: Copy test_resources + run: ./copy_test_resources.sh + - name: Inject AccessKey run: sed -i '.bak' 's:{TESTING_ACCESS_KEY_HERE}:${{secrets.PV_VALID_ACCESS_KEY}}:' PerformanceTest/PerformanceTest.swift diff --git a/.github/workflows/swift-codestyle.yml b/.github/workflows/swift-codestyle.yml index 8c51f677..efa06aa1 100644 --- a/.github/workflows/swift-codestyle.yml +++ b/.github/workflows/swift-codestyle.yml @@ -12,7 +12,7 @@ on: - '**/*.swift' jobs: - check-switch-codestyle: + check-swift-codestyle: runs-on: ubuntu-latest steps: @@ -21,4 +21,4 @@ jobs: - name: Check swift codestyle uses: norio-nomura/action-swiftlint@3.2.1 with: - args: lint --config resources/.lint/swift/.swiftlint.yml --strict \ No newline at end of file + args: lint --config resources/.lint/swift/.swiftlint.yml --strict diff --git a/binding/ios/CheetahAppTest/.gitignore b/binding/ios/CheetahAppTest/.gitignore index 5b281327..38ef34e4 100644 --- a/binding/ios/CheetahAppTest/.gitignore +++ b/binding/ios/CheetahAppTest/.gitignore @@ -18,3 +18,6 @@ build/* xcuserdata Pods ddp + +CheetahAppTestUITests/test_resources/* +!CheetahAppTestUITests/test_resources/.gitkeep diff --git a/binding/ios/CheetahAppTest/CheetahAppTest.xcodeproj/project.pbxproj b/binding/ios/CheetahAppTest/CheetahAppTest.xcodeproj/project.pbxproj index 7dcebef6..e13a81a8 100644 --- a/binding/ios/CheetahAppTest/CheetahAppTest.xcodeproj/project.pbxproj +++ b/binding/ios/CheetahAppTest/CheetahAppTest.xcodeproj/project.pbxproj @@ -3,18 +3,17 @@ archiveVersion = 1; classes = { }; - objectVersion = 55; + objectVersion = 70; objects = { /* Begin PBXBuildFile section */ + 072F6D492D02533000E29DF3 /* test_resources in Resources */ = {isa = PBXBuildFile; fileRef = 072F6D482D02533000E29DF3 /* test_resources */; }; 1E00655827CFF7EB006FF6E9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E00655727CFF7EB006FF6E9 /* AppDelegate.swift */; }; 1E00655C27CFF7EB006FF6E9 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E00655B27CFF7EB006FF6E9 /* ViewController.swift */; }; 1E00655F27CFF7EB006FF6E9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1E00655D27CFF7EB006FF6E9 /* Main.storyboard */; }; 1E00656127CFF7EC006FF6E9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1E00656027CFF7EC006FF6E9 /* Assets.xcassets */; }; 1E00656427CFF7EC006FF6E9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1E00656227CFF7EC006FF6E9 /* LaunchScreen.storyboard */; }; 1E00657927CFF7EC006FF6E9 /* CheetahAppTestUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E00657827CFF7EC006FF6E9 /* CheetahAppTestUITests.swift */; }; - 1E00658A27CFFAB3006FF6E9 /* test.wav in Resources */ = {isa = PBXBuildFile; fileRef = 1E00658927CFFAB3006FF6E9 /* test.wav */; }; - 1E00658C27CFFABD006FF6E9 /* cheetah_params.pv in Resources */ = {isa = PBXBuildFile; fileRef = 1E00658B27CFFABD006FF6E9 /* cheetah_params.pv */; }; 1E5B7B332800F75900F8BDDB /* PerformanceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E5B7B322800F75900F8BDDB /* PerformanceTest.swift */; }; 1E5B7B362800F77300F8BDDB /* test.wav in Resources */ = {isa = PBXBuildFile; fileRef = 1E5B7B352800F77300F8BDDB /* test.wav */; }; 1E5B7B382800F7AA00F8BDDB /* cheetah_params.pv in Resources */ = {isa = PBXBuildFile; fileRef = 1E5B7B372800F7AA00F8BDDB /* cheetah_params.pv */; }; @@ -42,6 +41,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 072F6D482D02533000E29DF3 /* test_resources */ = {isa = PBXFileReference; lastKnownFileType = folder; name = test_resources; path = CheetahAppTestUITests/test_resources; sourceTree = ""; }; 1E00655427CFF7EB006FF6E9 /* CheetahAppTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CheetahAppTest.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1E00655727CFF7EB006FF6E9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 1E00655B27CFF7EB006FF6E9 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; @@ -52,8 +52,6 @@ 1E00657427CFF7EC006FF6E9 /* CheetahAppTestUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CheetahAppTestUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 1E00657827CFF7EC006FF6E9 /* CheetahAppTestUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheetahAppTestUITests.swift; sourceTree = ""; }; 1E00658827CFFA3C006FF6E9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 1E00658927CFFAB3006FF6E9 /* test.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = test.wav; path = ../../../../resources/audio_samples/test.wav; sourceTree = ""; }; - 1E00658B27CFFABD006FF6E9 /* cheetah_params.pv */ = {isa = PBXFileReference; lastKnownFileType = file; name = cheetah_params.pv; path = ../../../../lib/common/cheetah_params.pv; sourceTree = ""; }; 1E5B7B302800F6FE00F8BDDB /* PerformanceTest.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PerformanceTest.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 1E5B7B322800F75900F8BDDB /* PerformanceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PerformanceTest.swift; sourceTree = ""; }; 1E5B7B342800F76700F8BDDB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -61,6 +59,33 @@ 1E5B7B372800F7AA00F8BDDB /* cheetah_params.pv */ = {isa = PBXFileReference; lastKnownFileType = file; name = cheetah_params.pv; path = ../../../../lib/common/cheetah_params.pv; sourceTree = ""; }; /* End PBXFileReference section */ +/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ + 072F6D4A2D02533A00E29DF3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + .gitkeep, + audio_samples/test_de.wav, + audio_samples/test_es.wav, + audio_samples/test_fr.wav, + audio_samples/test_it.wav, + audio_samples/test_pt.wav, + audio_samples/test.wav, + model_files/cheetah_params_de.pv, + model_files/cheetah_params_es.pv, + model_files/cheetah_params_fr.pv, + model_files/cheetah_params_it.pv, + model_files/cheetah_params_pt.pv, + model_files/cheetah_params.pv, + test_data.json, + ); + target = 1E00657327CFF7EC006FF6E9 /* CheetahAppTestUITests */; + }; +/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + 072F6CE02D023C7C00E29DF3 /* test_resources */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (072F6D4A2D02533A00E29DF3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = test_resources; sourceTree = ""; }; +/* End PBXFileSystemSynchronizedRootGroup section */ + /* Begin PBXFrameworksBuildPhase section */ 1E00655127CFF7EB006FF6E9 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; @@ -93,6 +118,7 @@ 1E00654B27CFF7EB006FF6E9 = { isa = PBXGroup; children = ( + 072F6D482D02533000E29DF3 /* test_resources */, 1E5B7B312800F71E00F8BDDB /* PerformanceTest */, 1E00655627CFF7EB006FF6E9 /* CheetahAppTest */, 1E00657727CFF7EC006FF6E9 /* CheetahAppTestUITests */, @@ -127,8 +153,7 @@ 1E00657727CFF7EC006FF6E9 /* CheetahAppTestUITests */ = { isa = PBXGroup; children = ( - 1E00658927CFFAB3006FF6E9 /* test.wav */, - 1E00658B27CFFABD006FF6E9 /* cheetah_params.pv */, + 072F6CE02D023C7C00E29DF3 /* test_resources */, 1E00657827CFF7EC006FF6E9 /* CheetahAppTestUITests.swift */, 1E00658827CFFA3C006FF6E9 /* Info.plist */, ); @@ -186,6 +211,9 @@ dependencies = ( 1E00657627CFF7EC006FF6E9 /* PBXTargetDependency */, ); + fileSystemSynchronizedGroups = ( + 072F6CE02D023C7C00E29DF3 /* test_resources */, + ); name = CheetahAppTestUITests; productName = CheetahAppTestUITests; productReference = 1E00657427CFF7EC006FF6E9 /* CheetahAppTestUITests.xctest */; @@ -242,7 +270,7 @@ ); mainGroup = 1E00654B27CFF7EB006FF6E9; packageReferences = ( - E15A377C2CF7B6D600A96F85 /* XCRemoteSwiftPackageReference "cheetah" */, + 07BA482F2D01233800A57078 /* XCLocalSwiftPackageReference "../../../../cheetah" */, ); productRefGroup = 1E00655527CFF7EB006FF6E9 /* Products */; projectDirPath = ""; @@ -270,8 +298,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1E00658C27CFFABD006FF6E9 /* cheetah_params.pv in Resources */, - 1E00658A27CFFAB3006FF6E9 /* test.wav in Resources */, + 072F6D492D02533000E29DF3 /* test_resources in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -524,7 +551,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 65723695GD; + DEVELOPMENT_TEAM = 8TK4L7UF2X; GENERATE_INFOPLIST_FILE = YES; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -546,7 +573,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 65723695GD; + DEVELOPMENT_TEAM = 8TK4L7UF2X; GENERATE_INFOPLIST_FILE = YES; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -652,23 +679,16 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ + 07BA482F2D01233800A57078 /* XCLocalSwiftPackageReference "../../../../cheetah" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = ../../../../cheetah; + }; E1E0C7FE2CF11FD9001D6D84 /* XCLocalSwiftPackageReference "../../../../cheetah" */ = { isa = XCLocalSwiftPackageReference; relativePath = ../../../../cheetah; }; /* End XCLocalSwiftPackageReference section */ -/* Begin XCRemoteSwiftPackageReference section */ - E15A377C2CF7B6D600A96F85 /* XCRemoteSwiftPackageReference "cheetah" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/Picovoice/cheetah"; - requirement = { - kind = exactVersion; - version = 2.0.1; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - /* Begin XCSwiftPackageProductDependency section */ E1E0C8002CF120B0001D6D84 /* Cheetah */ = { isa = XCSwiftPackageProductDependency; diff --git a/binding/ios/CheetahAppTest/CheetahAppTestUITests/CheetahAppTestUITests.swift b/binding/ios/CheetahAppTest/CheetahAppTestUITests/CheetahAppTestUITests.swift index 867fa896..c3855cc1 100644 --- a/binding/ios/CheetahAppTest/CheetahAppTestUITests/CheetahAppTestUITests.swift +++ b/binding/ios/CheetahAppTest/CheetahAppTestUITests/CheetahAppTestUITests.swift @@ -11,18 +11,80 @@ import AVFoundation import XCTest import Cheetah +extension String { + subscript(index: Int) -> Character { + return self[self.index(self.startIndex, offsetBy: index)] + } +} + +extension String { + public func levenshtein(_ other: String) -> Int { + let sCount = self.count + let oCount = other.count + + guard sCount != 0 else { + return oCount + } + + guard oCount != 0 else { + return sCount + } + + let line: [Int] = Array(repeating: 0, count: oCount + 1) + var mat: [[Int]] = Array(repeating: line, count: sCount + 1) + + for i in 0...sCount { + mat[i][0] = i + } + + for j in 0...oCount { + mat[0][j] = j + } + + for j in 1...oCount { + for i in 1...sCount { + if self[i - 1] == other[j - 1] { + mat[i][j] = mat[i - 1][j - 1] // no operation + } else { + let del = mat[i - 1][j] + 1 // deletion + let ins = mat[i][j - 1] + 1 // insertion + let sub = mat[i - 1][j - 1] + 1 // substitution + mat[i][j] = min(min(del, ins), sub) + } + } + } + + return mat[sCount][oCount] + } +} + +struct TestData: Decodable { + var tests: Tests +} + +struct Tests: Decodable { + var language_tests: [LanguageTest] +} + +struct LanguageTest: Decodable { + var language: String + var audio_file: String + var transcript: String + var punctuations: [String] + var error_rate: Float +} + class CheetahDemoUITests: XCTestCase { let accessKey: String = "{TESTING_ACCESS_KEY_HERE}" - let transcript: String = "Mr quilter is the apostle of the middle classes and we are glad to welcome his gospel" - let transcriptWithPunctuation: String = - "Mr. Quilter is the apostle of the middle classes and we are glad to welcome his gospel." - - let modelURL = Bundle(for: CheetahDemoUITests.self).url(forResource: "cheetah_params", withExtension: "pv")! override func setUpWithError() throws { continueAfterFailure = true } + func characterErrorRate(transcript: String, expectedTranscript: String) -> Float { + return Float(transcript.levenshtein(expectedTranscript)) / Float(expectedTranscript.count) + } + func processFile(cheetah: Cheetah, fileURL: URL) throws -> String { let data = try Data(contentsOf: fileURL) let frameLengthBytes = Int(Cheetah.frameLength) * 2 @@ -44,43 +106,85 @@ class CheetahDemoUITests: XCTestCase { return res } - func testTranscribe() throws { - let cheetah = try Cheetah(accessKey: accessKey, modelURL: modelURL) - + func runTestTranscribe( + modelPath: String, + testAudio: String, + expectedTranscript: String, + errorRate: Float, + enableAutomaticPunctuation: Bool = false + ) throws { let bundle = Bundle(for: type(of: self)) - let fileURL: URL = bundle.url(forResource: "test", withExtension: "wav")! - let res: String = try processFile(cheetah: cheetah, fileURL: fileURL) + let audioFileURL: URL = bundle.url( + forResource: testAudio, + withExtension: "", + subdirectory: "test_resources/audio_samples")! + + let cheetah = try Cheetah(accessKey: accessKey, modelPath: modelPath, enableAutomaticPunctuation: enableAutomaticPunctuation) + + let res: String = try processFile(cheetah: cheetah, fileURL: audioFileURL) cheetah.delete() - XCTAssertEqual(transcript, res) + XCTAssert(characterErrorRate( + transcript: res, + expectedTranscript: expectedTranscript) < errorRate) } - func testTranscribeCustomEndpointDuration() throws { - let cheetah = try Cheetah( - accessKey: accessKey, - modelURL: modelURL, - endpointDuration: 1.5) - + func testTranscribe() throws { let bundle = Bundle(for: type(of: self)) - let fileURL: URL = bundle.url(forResource: "test", withExtension: "wav")! - let res: String = try processFile(cheetah: cheetah, fileURL: fileURL) - cheetah.delete() - - XCTAssertEqual(transcript, res) + 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) + + for testCase in testData.tests.language_tests { + let suffix = testCase.language == "en" ? "" : "_\(testCase.language)" + let modelPath: String = bundle.path( + forResource: "cheetah_params\(suffix)", + ofType: "pv", + inDirectory: "test_resources/model_files")! + + var expectedTranscript = testCase.transcript + for p in testCase.punctuations { + expectedTranscript = expectedTranscript.replacingOccurrences(of: p, with: "") + } + + try XCTContext.runActivity(named: "(\(testCase.language))") { _ in + try runTestTranscribe( + modelPath: modelPath, + testAudio: testCase.audio_file, + expectedTranscript: expectedTranscript, + errorRate: testCase.error_rate) + } + } } func testTranscribeWithPunctuation() throws { - let cheetah = try Cheetah( - accessKey: accessKey, - modelURL: modelURL, - enableAutomaticPunctuation: true) - let bundle = Bundle(for: type(of: self)) - let fileURL: URL = bundle.url(forResource: "test", withExtension: "wav")! - let res: String = try processFile(cheetah: cheetah, fileURL: fileURL) - cheetah.delete() - - XCTAssertEqual(transcriptWithPunctuation, res) + 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) + + for testCase in testData.tests.language_tests { + let suffix = testCase.language == "en" ? "" : "_\(testCase.language)" + let modelPath: String = bundle.path( + forResource: "cheetah_params\(suffix)", + ofType: "pv", + inDirectory: "test_resources/model_files")! + + try XCTContext.runActivity(named: "(\(testCase.language))") { _ in + try runTestTranscribe( + modelPath: modelPath, + testAudio: testCase.audio_file, + expectedTranscript: testCase.transcript, + errorRate: testCase.error_rate, + enableAutomaticPunctuation: false) + } + } } func testFrameLength() throws { @@ -96,6 +200,12 @@ class CheetahDemoUITests: XCTestCase { } func testMessageStack() throws { + let bundle = Bundle(for: type(of: self)) + let modelURL: URL = bundle.url( + forResource: "cheetah_params", + withExtension: "pv", + subdirectory: "test_resources/model_files")! + var first_error: String = "" do { let cheetah = try Cheetah.init(accessKey: "invalid", modelURL: modelURL) @@ -114,6 +224,12 @@ class CheetahDemoUITests: XCTestCase { } func testProcessMessageStack() throws { + let bundle = Bundle(for: type(of: self)) + let modelURL: URL = bundle.url( + forResource: "cheetah_params", + withExtension: "pv", + subdirectory: "test_resources/model_files")! + let cheetah = try Cheetah(accessKey: accessKey, modelURL: modelURL) cheetah.delete() diff --git a/binding/ios/CheetahAppTest/CheetahAppTestUITests/test_resources/.gitkeep b/binding/ios/CheetahAppTest/CheetahAppTestUITests/test_resources/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/binding/ios/CheetahAppTest/copy_test_resources.sh b/binding/ios/CheetahAppTest/copy_test_resources.sh new file mode 100755 index 00000000..73ac4fdf --- /dev/null +++ b/binding/ios/CheetahAppTest/copy_test_resources.sh @@ -0,0 +1,17 @@ +LIB_DIR="../../../lib" +RESOURCE_DIR="../../../resources" +ASSETS_DIR="./CheetahAppTestUITests/test_resources" + +echo "Creating test resources asset directory" +mkdir -p ${ASSETS_DIR} + +echo "Copying test audio samples..." +mkdir -p ${ASSETS_DIR}/audio_samples +cp ${RESOURCE_DIR}/audio_samples/*.wav ${ASSETS_DIR}/audio_samples + +echo "Copying test model files..." +mkdir -p ${ASSETS_DIR}/model_files +cp ${LIB_DIR}/common/*.pv ${ASSETS_DIR}/model_files + +echo "Copying test data file..." +cp ${RESOURCE_DIR}/.test/test_data.json ${ASSETS_DIR} diff --git a/binding/ios/README.md b/binding/ios/README.md index 894d9b1a..ad813af6 100644 --- a/binding/ios/README.md +++ b/binding/ios/README.md @@ -86,6 +86,20 @@ while true { Replace `${ACCESS_KEY}` with yours obtained from [Picovoice Console](https://console.picovoice.ai/) and `${MODEL_FILE}` with the name of the Cheetah model file name. Finally, when done be sure to explicitly release the resources using `cheetah.delete()`. +### Language Model + +Default models for supported languages can be found in [lib/common](../../lib/common). + +Create custom language models using the [Picovoice Console](https://console.picovoice.ai/). Here you can train +language models with custom vocabulary and boost words in the existing vocabulary. + +Pass in the `.pv` file via the `modelURL` or `modelPath` constructor argument: +```swift +let cheetah = Cheetah(accessKey: accessKey, modelPath: "${MODEL_FILE_PATH") +// or +let cheetah = Cheetah(accessKey: accessKey, modelURL: "${MODEL_FILE_URL}") +``` + ## Running Unit Tests Copy your `AccessKey` into the `accessKey` variable in [`CheetahAppTestUITests.swift`](CheetahAppTest/CheetahAppTestUITests/CheetahAppTestUITests.swift). Open [`CheetahAppTest.xcodeproj`](CheetahAppTest/CheetahAppTest.xcodeproj) with XCode and run the tests with `Product > Test`. diff --git a/lib/ios/PvCheetah.xcframework/Info.plist b/lib/ios/PvCheetah.xcframework/Info.plist index dc88639f..ed37406d 100644 --- a/lib/ios/PvCheetah.xcframework/Info.plist +++ b/lib/ios/PvCheetah.xcframework/Info.plist @@ -8,32 +8,32 @@ BinaryPath PvCheetah.framework/PvCheetah LibraryIdentifier - ios-arm64_x86_64-simulator + ios-arm64 LibraryPath PvCheetah.framework SupportedArchitectures arm64 - x86_64 SupportedPlatform ios - SupportedPlatformVariant - simulator BinaryPath PvCheetah.framework/PvCheetah LibraryIdentifier - ios-arm64 + ios-arm64_x86_64-simulator LibraryPath PvCheetah.framework SupportedArchitectures arm64 + x86_64 SupportedPlatform ios + SupportedPlatformVariant + simulator CFBundlePackageType diff --git a/lib/ios/PvCheetah.xcframework/ios-arm64/PvCheetah.framework/Headers/picovoice.h b/lib/ios/PvCheetah.xcframework/ios-arm64/PvCheetah.framework/Headers/picovoice.h index 886558d1..3f13d705 100644 --- a/lib/ios/PvCheetah.xcframework/ios-arm64/PvCheetah.framework/Headers/picovoice.h +++ b/lib/ios/PvCheetah.xcframework/ios-arm64/PvCheetah.framework/Headers/picovoice.h @@ -77,6 +77,8 @@ PV_API pv_status_t pv_get_error_stack( */ PV_API void pv_free_error_stack(char **message_stack); +PV_API void pv_set_sdk(const char *sdk); + #ifdef __cplusplus } diff --git a/lib/ios/PvCheetah.xcframework/ios-arm64/PvCheetah.framework/Info.plist b/lib/ios/PvCheetah.xcframework/ios-arm64/PvCheetah.framework/Info.plist index 1f5e613ac4272533757814ca174c34c1cd1a13bd..2f612a3954016e93381ad7ffdb9cba583d594a09 100644 GIT binary patch delta 86 zcmbQkHk)n32Sz3fgUO#5%^3|RYcW~r8abJpL}V6ZL9M`RXczT&Dcpy%Qp{a>M jn4zhgv0+Mxq2c6-Oo^QROjDSqG0k9_HTgG_JmUfYv27bB diff --git a/lib/ios/PvCheetah.xcframework/ios-arm64_x86_64-simulator/PvCheetah.framework/Headers/picovoice.h b/lib/ios/PvCheetah.xcframework/ios-arm64_x86_64-simulator/PvCheetah.framework/Headers/picovoice.h index 886558d1..3f13d705 100644 --- a/lib/ios/PvCheetah.xcframework/ios-arm64_x86_64-simulator/PvCheetah.framework/Headers/picovoice.h +++ b/lib/ios/PvCheetah.xcframework/ios-arm64_x86_64-simulator/PvCheetah.framework/Headers/picovoice.h @@ -77,6 +77,8 @@ PV_API pv_status_t pv_get_error_stack( */ PV_API void pv_free_error_stack(char **message_stack); +PV_API void pv_set_sdk(const char *sdk); + #ifdef __cplusplus } diff --git a/lib/ios/PvCheetah.xcframework/ios-arm64_x86_64-simulator/PvCheetah.framework/Info.plist b/lib/ios/PvCheetah.xcframework/ios-arm64_x86_64-simulator/PvCheetah.framework/Info.plist index 5fec36a7c62aa817acc1f9f9e0eb1bad0cc239d0..ca11747141192b2872850be202cddd57029942dd 100644 GIT binary patch delta 85 zcmeBRYiHYVo{`DIVDd#qb4J6-oJ`IvMo#7?lLMGU)GhQ3;{}8>3o`QaQj0TlOLG!S n@{0_Cq9KN6h6bUAW=tNe(o{`DYc=AO?b4G*7oJ`IvhHmEOlLMGUG|cr(;{}8>3o`QaQj0TlOLG!S p@{0_Cq9KN+CI(@Krf$ZDDItc2le?M1Sv#5fm?lhq&Lqz`2>>VE82 Date: Thu, 5 Dec 2024 14:13:02 -0800 Subject: [PATCH 2/5] v2.1 iOS - Linting --- .../CheetahAppTestUITests/CheetahAppTestUITests.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/binding/ios/CheetahAppTest/CheetahAppTestUITests/CheetahAppTestUITests.swift b/binding/ios/CheetahAppTest/CheetahAppTestUITests/CheetahAppTestUITests.swift index c3855cc1..4a1a4d35 100644 --- a/binding/ios/CheetahAppTest/CheetahAppTestUITests/CheetahAppTestUITests.swift +++ b/binding/ios/CheetahAppTest/CheetahAppTestUITests/CheetahAppTestUITests.swift @@ -119,7 +119,10 @@ class CheetahDemoUITests: XCTestCase { withExtension: "", subdirectory: "test_resources/audio_samples")! - let cheetah = try Cheetah(accessKey: accessKey, modelPath: modelPath, enableAutomaticPunctuation: enableAutomaticPunctuation) + let cheetah = try Cheetah( + accessKey: accessKey, + modelPath: modelPath, + enableAutomaticPunctuation: enableAutomaticPunctuation) let res: String = try processFile(cheetah: cheetah, fileURL: audioFileURL) cheetah.delete() From 6be9d0ec0d49a690dcc2bb1592c39a5865d69258 Mon Sep 17 00:00:00 2001 From: Eric Mikulin Date: Thu, 5 Dec 2024 14:19:49 -0800 Subject: [PATCH 3/5] v2.1 iOS - XCode fixes --- .../CheetahAppTest/CheetahAppTest.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/binding/ios/CheetahAppTest/CheetahAppTest.xcodeproj/project.pbxproj b/binding/ios/CheetahAppTest/CheetahAppTest.xcodeproj/project.pbxproj index e13a81a8..380f1d73 100644 --- a/binding/ios/CheetahAppTest/CheetahAppTest.xcodeproj/project.pbxproj +++ b/binding/ios/CheetahAppTest/CheetahAppTest.xcodeproj/project.pbxproj @@ -503,7 +503,7 @@ INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -532,7 +532,7 @@ INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", From baff74c6c9a14f7bea271470b68ab760e0b4b24b Mon Sep 17 00:00:00 2001 From: Eric Mikulin Date: Thu, 5 Dec 2024 14:42:02 -0800 Subject: [PATCH 4/5] v2.1 iOS - XCode fixes --- .../CheetahAppTest.xcodeproj/project.pbxproj | 89 ++++++++++++------- 1 file changed, 55 insertions(+), 34 deletions(-) diff --git a/binding/ios/CheetahAppTest/CheetahAppTest.xcodeproj/project.pbxproj b/binding/ios/CheetahAppTest/CheetahAppTest.xcodeproj/project.pbxproj index 380f1d73..f5451e80 100644 --- a/binding/ios/CheetahAppTest/CheetahAppTest.xcodeproj/project.pbxproj +++ b/binding/ios/CheetahAppTest/CheetahAppTest.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 70; + objectVersion = 60; objects = { /* Begin PBXBuildFile section */ @@ -42,6 +42,20 @@ /* Begin PBXFileReference section */ 072F6D482D02533000E29DF3 /* test_resources */ = {isa = PBXFileReference; lastKnownFileType = folder; name = test_resources; path = CheetahAppTestUITests/test_resources; sourceTree = ""; }; + 07E777C32D02632A005A41E7 /* test.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = test.wav; sourceTree = ""; }; + 07E777C42D02632A005A41E7 /* test_de.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = test_de.wav; sourceTree = ""; }; + 07E777C52D02632A005A41E7 /* test_es.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = test_es.wav; sourceTree = ""; }; + 07E777C62D02632A005A41E7 /* test_fr.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = test_fr.wav; sourceTree = ""; }; + 07E777C72D02632A005A41E7 /* test_it.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = test_it.wav; sourceTree = ""; }; + 07E777C82D02632A005A41E7 /* test_pt.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = test_pt.wav; sourceTree = ""; }; + 07E777CA2D02632A005A41E7 /* cheetah_params.pv */ = {isa = PBXFileReference; lastKnownFileType = file; path = cheetah_params.pv; sourceTree = ""; }; + 07E777CB2D02632A005A41E7 /* cheetah_params_de.pv */ = {isa = PBXFileReference; lastKnownFileType = file; path = cheetah_params_de.pv; sourceTree = ""; }; + 07E777CC2D02632A005A41E7 /* cheetah_params_es.pv */ = {isa = PBXFileReference; lastKnownFileType = file; path = cheetah_params_es.pv; sourceTree = ""; }; + 07E777CD2D02632A005A41E7 /* cheetah_params_fr.pv */ = {isa = PBXFileReference; lastKnownFileType = file; path = cheetah_params_fr.pv; sourceTree = ""; }; + 07E777CE2D02632A005A41E7 /* cheetah_params_it.pv */ = {isa = PBXFileReference; lastKnownFileType = file; path = cheetah_params_it.pv; sourceTree = ""; }; + 07E777CF2D02632A005A41E7 /* cheetah_params_pt.pv */ = {isa = PBXFileReference; lastKnownFileType = file; path = cheetah_params_pt.pv; sourceTree = ""; }; + 07E777D12D02632A005A41E7 /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; + 07E777D22D02632A005A41E7 /* test_data.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = test_data.json; sourceTree = ""; }; 1E00655427CFF7EB006FF6E9 /* CheetahAppTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CheetahAppTest.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1E00655727CFF7EB006FF6E9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 1E00655B27CFF7EB006FF6E9 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; @@ -59,33 +73,6 @@ 1E5B7B372800F7AA00F8BDDB /* cheetah_params.pv */ = {isa = PBXFileReference; lastKnownFileType = file; name = cheetah_params.pv; path = ../../../../lib/common/cheetah_params.pv; sourceTree = ""; }; /* End PBXFileReference section */ -/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ - 072F6D4A2D02533A00E29DF3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - .gitkeep, - audio_samples/test_de.wav, - audio_samples/test_es.wav, - audio_samples/test_fr.wav, - audio_samples/test_it.wav, - audio_samples/test_pt.wav, - audio_samples/test.wav, - model_files/cheetah_params_de.pv, - model_files/cheetah_params_es.pv, - model_files/cheetah_params_fr.pv, - model_files/cheetah_params_it.pv, - model_files/cheetah_params_pt.pv, - model_files/cheetah_params.pv, - test_data.json, - ); - target = 1E00657327CFF7EC006FF6E9 /* CheetahAppTestUITests */; - }; -/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ - -/* Begin PBXFileSystemSynchronizedRootGroup section */ - 072F6CE02D023C7C00E29DF3 /* test_resources */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (072F6D4A2D02533A00E29DF3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = test_resources; sourceTree = ""; }; -/* End PBXFileSystemSynchronizedRootGroup section */ - /* Begin PBXFrameworksBuildPhase section */ 1E00655127CFF7EB006FF6E9 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; @@ -115,6 +102,43 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 07E777C92D02632A005A41E7 /* audio_samples */ = { + isa = PBXGroup; + children = ( + 07E777C32D02632A005A41E7 /* test.wav */, + 07E777C42D02632A005A41E7 /* test_de.wav */, + 07E777C52D02632A005A41E7 /* test_es.wav */, + 07E777C62D02632A005A41E7 /* test_fr.wav */, + 07E777C72D02632A005A41E7 /* test_it.wav */, + 07E777C82D02632A005A41E7 /* test_pt.wav */, + ); + path = audio_samples; + sourceTree = ""; + }; + 07E777D02D02632A005A41E7 /* model_files */ = { + isa = PBXGroup; + children = ( + 07E777CA2D02632A005A41E7 /* cheetah_params.pv */, + 07E777CB2D02632A005A41E7 /* cheetah_params_de.pv */, + 07E777CC2D02632A005A41E7 /* cheetah_params_es.pv */, + 07E777CD2D02632A005A41E7 /* cheetah_params_fr.pv */, + 07E777CE2D02632A005A41E7 /* cheetah_params_it.pv */, + 07E777CF2D02632A005A41E7 /* cheetah_params_pt.pv */, + ); + path = model_files; + sourceTree = ""; + }; + 07E777D32D02632A005A41E7 /* test_resources */ = { + isa = PBXGroup; + children = ( + 07E777C92D02632A005A41E7 /* audio_samples */, + 07E777D02D02632A005A41E7 /* model_files */, + 07E777D12D02632A005A41E7 /* .gitkeep */, + 07E777D22D02632A005A41E7 /* test_data.json */, + ); + path = test_resources; + sourceTree = ""; + }; 1E00654B27CFF7EB006FF6E9 = { isa = PBXGroup; children = ( @@ -153,7 +177,7 @@ 1E00657727CFF7EC006FF6E9 /* CheetahAppTestUITests */ = { isa = PBXGroup; children = ( - 072F6CE02D023C7C00E29DF3 /* test_resources */, + 07E777D32D02632A005A41E7 /* test_resources */, 1E00657827CFF7EC006FF6E9 /* CheetahAppTestUITests.swift */, 1E00658827CFFA3C006FF6E9 /* Info.plist */, ); @@ -211,9 +235,6 @@ dependencies = ( 1E00657627CFF7EC006FF6E9 /* PBXTargetDependency */, ); - fileSystemSynchronizedGroups = ( - 072F6CE02D023C7C00E29DF3 /* test_resources */, - ); name = CheetahAppTestUITests; productName = CheetahAppTestUITests; productReference = 1E00657427CFF7EC006FF6E9 /* CheetahAppTestUITests.xctest */; @@ -503,7 +524,7 @@ INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -532,7 +553,7 @@ INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", From d0a11d307bad8e7c96c2d9d6cc41cb88c33ffc21 Mon Sep 17 00:00:00 2001 From: Eric Mikulin Date: Thu, 5 Dec 2024 15:43:16 -0800 Subject: [PATCH 5/5] v2.1 iOS - Update Podspec version --- binding/ios/Cheetah-iOS.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binding/ios/Cheetah-iOS.podspec b/binding/ios/Cheetah-iOS.podspec index dc4b1bb6..19843135 100644 --- a/binding/ios/Cheetah-iOS.podspec +++ b/binding/ios/Cheetah-iOS.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = 'Cheetah-iOS' s.module_name = 'Cheetah' - s.version = '2.0.1' + s.version = '2.1.0' s.license = {:type => 'Apache 2.0'} s.summary = 'iOS SDK for Picovoice\'s Cheetah speech-to-text engine.' s.description =