@@ -832,3 +832,111 @@ class SherpaOnnxSpokenLanguageIdentificationWrapper {
832
832
return SherpaOnnxSpokenLanguageIdentificationResultWrapper ( result: result)
833
833
}
834
834
}
835
+
836
+ // keyword spotting
837
+
838
+ class SherpaOnnxKeywordResultWrapper {
839
+ /// A pointer to the underlying counterpart in C
840
+ let result : UnsafePointer < SherpaOnnxKeywordResult > !
841
+
842
+ var keyword : String {
843
+ return String ( cString: result. pointee. keyword)
844
+ }
845
+
846
+ var count : Int32 {
847
+ return result. pointee. count
848
+ }
849
+
850
+ var tokens : [ String ] {
851
+ if let tokensPointer = result. pointee. tokens_arr {
852
+ var tokens : [ String ] = [ ]
853
+ for index in 0 ..< count {
854
+ if let tokenPointer = tokensPointer [ Int ( index) ] {
855
+ let token = String ( cString: tokenPointer)
856
+ tokens. append ( token)
857
+ }
858
+ }
859
+ return tokens
860
+ } else {
861
+ let tokens : [ String ] = [ ]
862
+ return tokens
863
+ }
864
+ }
865
+
866
+ init ( result: UnsafePointer < SherpaOnnxKeywordResult > ! ) {
867
+ self . result = result
868
+ }
869
+
870
+ deinit {
871
+ if let result {
872
+ DestroyKeywordResult ( result)
873
+ }
874
+ }
875
+ }
876
+
877
+ func sherpaOnnxKeywordSpotterConfig(
878
+ featConfig: SherpaOnnxFeatureConfig ,
879
+ modelConfig: SherpaOnnxOnlineModelConfig ,
880
+ keywordsFile: String ,
881
+ maxActivePaths: Int = 4 ,
882
+ numTrailingBlanks: Int = 1 ,
883
+ keywordsScore: Float = 1.0 ,
884
+ keywordsThreshold: Float = 0.25
885
+ ) -> SherpaOnnxKeywordSpotterConfig {
886
+ return SherpaOnnxKeywordSpotterConfig (
887
+ feat_config: featConfig,
888
+ model_config: modelConfig,
889
+ max_active_paths: Int32 ( maxActivePaths) ,
890
+ num_trailing_blanks: Int32 ( numTrailingBlanks) ,
891
+ keywords_score: keywordsScore,
892
+ keywords_threshold: keywordsThreshold,
893
+ keywords_file: toCPointer ( keywordsFile)
894
+ )
895
+ }
896
+
897
+ class SherpaOnnxKeywordSpotterWrapper {
898
+ /// A pointer to the underlying counterpart in C
899
+ let spotter : OpaquePointer !
900
+ var stream : OpaquePointer !
901
+
902
+ init (
903
+ config: UnsafePointer < SherpaOnnxKeywordSpotterConfig > !
904
+ ) {
905
+ spotter = CreateKeywordSpotter ( config)
906
+ stream = CreateKeywordStream ( spotter)
907
+ }
908
+
909
+ deinit {
910
+ if let stream {
911
+ DestroyOnlineStream ( stream)
912
+ }
913
+
914
+ if let spotter {
915
+ DestroyKeywordSpotter ( spotter)
916
+ }
917
+ }
918
+
919
+ func acceptWaveform( samples: [ Float ] , sampleRate: Int = 16000 ) {
920
+ AcceptWaveform ( stream, Int32 ( sampleRate) , samples, Int32 ( samples. count) )
921
+ }
922
+
923
+ func isReady( ) -> Bool {
924
+ return IsKeywordStreamReady ( spotter, stream) == 1 ? true : false
925
+ }
926
+
927
+ func decode( ) {
928
+ DecodeKeywordStream ( spotter, stream)
929
+ }
930
+
931
+ func getResult( ) -> SherpaOnnxKeywordResultWrapper {
932
+ let result : UnsafePointer < SherpaOnnxKeywordResult > ? = GetKeywordResult (
933
+ spotter, stream)
934
+ return SherpaOnnxKeywordResultWrapper ( result: result)
935
+ }
936
+
937
+ /// Signal that no more audio samples would be available.
938
+ /// After this call, you cannot call acceptWaveform() any more.
939
+ func inputFinished( ) {
940
+ InputFinished ( stream)
941
+ }
942
+ }
0 commit comments