diff --git a/harmony-os/SherpaOnnxHar/sherpa_onnx/BuildProfile.ets b/harmony-os/SherpaOnnxHar/sherpa_onnx/BuildProfile.ets
index 274f603791..ea97166bc9 100644
--- a/harmony-os/SherpaOnnxHar/sherpa_onnx/BuildProfile.ets
+++ b/harmony-os/SherpaOnnxHar/sherpa_onnx/BuildProfile.ets
@@ -1,7 +1,7 @@
 /**
  * Use these variables when you tailor your ArkTS code. They must be of the const type.
  */
-export const HAR_VERSION = '1.10.40';
+export const HAR_VERSION = '1.10.41';
 export const BUILD_MODE_NAME = 'debug';
 export const DEBUG = true;
 export const TARGET_NAME = 'default';
diff --git a/harmony-os/SherpaOnnxHar/sherpa_onnx/Index.ets b/harmony-os/SherpaOnnxHar/sherpa_onnx/Index.ets
index 7c1e95df4f..84286294a6 100644
--- a/harmony-os/SherpaOnnxHar/sherpa_onnx/Index.ets
+++ b/harmony-os/SherpaOnnxHar/sherpa_onnx/Index.ets
@@ -53,3 +53,8 @@ export { OfflineSpeakerSegmentationPyannoteModelConfig,
   OfflineSpeakerDiarization,
   FastClusteringConfig,
 } from './src/main/ets/components/NonStreamingSpeakerDiarization';
+
+export { KeywordSpotterConfig,
+  KeywordSpotterResult,
+  KeywordSpotter,
+} from './src/main/ets/components/KeywordSpotting';
diff --git a/harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/types/libsherpa_onnx/Index.d.ts b/harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/types/libsherpa_onnx/Index.d.ts
index 7db410a4cf..a51b9ed23b 100644
--- a/harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/types/libsherpa_onnx/Index.d.ts
+++ b/harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/cpp/types/libsherpa_onnx/Index.d.ts
@@ -68,3 +68,10 @@ export const getOfflineSpeakerDiarizationSampleRate: (handle: object) => number;
 export const offlineSpeakerDiarizationProcess: (handle: object, input: object) => object;
 export const offlineSpeakerDiarizationProcessAsync: (handle: object, input: object, callback: object) => object;
 export const offlineSpeakerDiarizationSetConfig: (handle: object, config: object) => void;
+
+export const createKeywordSpotter: (config: object, mgr?: object) => object;
+export const createKeywordStream: (handle: object, keywords?: string) => object;
+export const isKeywordStreamReady: (handle: object, stream: object) => boolean;
+export const decodeKeywordStream: (handle: object, stream: object) => void;
+export const resetKeywordStream: (handle: object, stream: object) => void;
+export const getKeywordResultAsJson: (handle: object, stream: object) => string;
diff --git a/harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/ets/components/KeywordSpotting.ets b/harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/ets/components/KeywordSpotting.ets
new file mode 100644
index 0000000000..f9c84d9ce5
--- /dev/null
+++ b/harmony-os/SherpaOnnxHar/sherpa_onnx/src/main/ets/components/KeywordSpotting.ets
@@ -0,0 +1,78 @@
+import {
+  createKeywordSpotter,
+  createKeywordStream,
+  isKeywordStreamReady,
+  decodeKeywordStream,
+  resetKeywordStream,
+  getKeywordResultAsJson,
+} from 'libsherpa_onnx.so';
+
+import { FeatureConfig } from './NonStreamingAsr';
+import { OnlineModelConfig, OnlineStream } from './StreamingAsr';
+
+export class KeywordSpotterConfig {
+  public featConfig: FeatureConfig = new FeatureConfig();
+  public modelConfig: OnlineModelConfig = new OnlineModelConfig();
+  public maxActivePaths: number = 4;
+  public numTrailingBlanks: number = 1;
+  public keywordsScore: number = 1;
+  public keywordsThreshold: number = 0.25;
+  public keywordsFile: string = '';
+}
+
+interface KeywordSpotterResultJson {
+  keyword: string;
+  timestamps: number[];
+  tokens: string[];
+}
+
+export class KeywordSpotterResult {
+  public keyword: string = '';
+  public tokens: string[] = [];
+  public timestamps: number[] = [];
+  public json: string = '';
+}
+
+export class KeywordSpotter {
+  public handle: object;
+  public config: KeywordSpotterConfig;
+
+  constructor(config: KeywordSpotterConfig, mgr?: object) {
+    this.handle = createKeywordSpotter(config, mgr);
+    this.config = config
+  }
+
+  createStream(keywords?: string): OnlineStream {
+    if (typeof keywords !== "undefined") {
+      return new OnlineStream(createKeywordStream(this.handle, keywords));
+    } else {
+      return new OnlineStream(createKeywordStream(this.handle));
+    }
+  }
+
+  isReady(stream: OnlineStream): boolean {
+    return isKeywordStreamReady(this.handle, stream.handle);
+  }
+
+  decode(stream: OnlineStream) {
+    decodeKeywordStream(this.handle, stream.handle);
+  }
+
+  reset(stream: OnlineStream) {
+    resetKeywordStream(this.handle, stream.handle);
+  }
+
+  getResult(stream: OnlineStream): KeywordSpotterResult {
+    const jsonStr: string = getKeywordResultAsJson(this.handle, stream.handle);
+
+    let o = JSON.parse(jsonStr) as KeywordSpotterResultJson;
+
+    const r = new KeywordSpotterResult()
+    r.keyword = o.keyword
+    r.timestamps = o.timestamps;
+    r.tokens = o.tokens;
+    r.json = jsonStr;
+
+    return r;
+  }
+}