termux-stt 1.5.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,16 +6,16 @@
6
6
  [![npm downloads](https://img.shields.io/npm/dm/termux-stt.svg?style=flat-square&color=b91c1c)](https://www.npmjs.com/package/termux-stt)
7
7
  [![License](https://img.shields.io/badge/License-Apache_2.0-004499.svg?style=flat-square)](https://github.com/uno-km/termux-stt)
8
8
 
9
- > **디바이스 리소스를 활용한 통합 온디바이스 음성인식(STT) 및 순수 Python 128d X-Vector 화자 분리 프레임워크**
10
- > *Unified On-Device Speech-to-Text Utilizing Device Resources & Pure Python 128d X-Vector Speaker Diarization*
9
+ > **디바이스 리소스를 활용한 통합 온디바이스 음성인식(STT) 및 차세대 신경망 화자 분리(PyAnnote 3.0 + CAM++ 192d + TS-VAD) 프레임워크**
10
+ > *Unified On-Device Speech-to-Text & Neural Multi-Speaker Diarization (PyAnnote 3.0 + CAM++ 192d + TS-VAD Overlap Resolver)*
11
11
 
12
12
  ---
13
13
 
14
14
  ## Architecture & Overview
15
15
 
16
- Whisper.cpp, Vosk, Sherpa-ONNX 3대 네이티브 엔진을 통합하고, 닫힌 형태 순수 Python 128차원 X-Vector 클러스터링을 결합하여 80MB 미만의 초경량 메모리로 100% 온디바이스 실시간 음성인식과 화자 분리를 구현합니다.
16
+ Whisper.cpp(네이티브 Vulkan GPU / NEON CPU) 및 Sherpa-ONNX 듀얼 모던 엔진을 통합하고, PyAnnote 3.0 신경망 세그멘테이션, 3D-Speaker CAM++ 192차원 성문 임베딩, TS-VAD 동시 발화(마이크 물림) 분리기를 결합하여 완전 온디바이스 실시간 다중 화자 음성인식을 구현합니다.
17
17
 
18
- Integrates Whisper.cpp, Vosk, and Sherpa-ONNX with a closed-form pure-Python 128-dimensional X-Vector clustering algorithm that operates in under 80MB RAM with zero cloud egress.
18
+ Integrates Whisper.cpp (Native Vulkan GPU / NEON CPU) and Sherpa-ONNX with PyAnnote 3.0 neural segmentation, 3D-Speaker CAM++ 192-dim embeddings, and TS-VAD overlapped speech resolution with zero cloud egress.
19
19
 
20
20
  ---
21
21
 
@@ -28,17 +28,17 @@ pip install termux-stt
28
28
  ```python
29
29
  from termux_stt import create_engine
30
30
 
31
- # 1. Initialize Engine with Hybrid GPU-Encoder / CPU-Decoder Acceleration
32
- engine = create_engine("whisper", model="small", lang="en", threads=4, split_mode=True)
31
+ # 1. Initialize Whisper Engine with Vulkan GPU / CPU Hybrid Acceleration
32
+ engine = create_engine("whisper", model="small", lang="ko", threads=4, split_mode=True)
33
33
 
34
34
  # 2. Transcribe Audio directly into Subtitles
35
35
  result = engine.transcribe("samples/jfk_1min.wav")
36
36
  print("Transcript:\n", result.text)
37
37
  print("SRT Subtitles:\n", result.to_srt())
38
38
 
39
- # 3. 2-Speaker Diarization without PyTorch
40
- hybrid = create_engine("hybrid", lang="en", num_speakers=2)
41
- diar_result = hybrid.diarize("samples/jfk_1min.wav")
39
+ # 3. Multi-Speaker Neural Diarization (PyAnnote 3.0 + CAM++ 192d + TS-VAD)
40
+ hybrid = create_engine("hybrid", lang="ko", num_speakers=2)
41
+ diar_result = hybrid.diarize("samples/kor_diarization.wav")
42
42
  for seg in diar_result.segments:
43
43
  print(f"[{seg.speaker}] ({seg.start:.1f}s -> {seg.end:.1f}s): {seg.text}")
44
44
 
@@ -53,12 +53,19 @@ const { createEngine } = require("termux-stt");
53
53
 
54
54
  async function main() {
55
55
  // 1. Initialize Whisper Engine
56
- const engine = createEngine("whisper", { model: "tiny", lang: "en", threads: 4 });
56
+ const engine = createEngine("whisper", { model: "tiny", lang: "ko", threads: 4 });
57
57
 
58
58
  // 2. Transcribe Audio
59
59
  const result = await engine.transcribe("samples/jfk_1min.wav");
60
60
  console.log("Transcript:", result.text);
61
61
  console.log("SRT Subtitles:\n", result.toSrt());
62
+
63
+ // 3. Neural Diarization via Hybrid Engine
64
+ const hybrid = createEngine("hybrid", { lang: "ko", numSpeakers: 2 });
65
+ const diarResult = await hybrid.diarize("samples/kor_diarization.wav");
66
+ for (const seg of diarResult.segments) {
67
+ console.log(`[${seg.speaker}] (${seg.start.toFixed(1)}s -> ${seg.end.toFixed(1)}s): ${seg.text}`);
68
+ }
62
69
  }
63
70
  main();
64
71
 
@@ -66,46 +73,6 @@ main();
66
73
 
67
74
  ---
68
75
 
69
- ## Distributed Clustering & Memory Pooling (AMEVA-Cluster)
70
-
71
- Termux-STT natively integrates with **AMEVA-Cluster** (`pip install ameva-cluster`) for distributed large-model speech recognition (e.g. `whisper-large-v3-turbo`) across interconnected mobile fleets.
72
-
73
- ### 1. Install Cluster Runtime
74
- ```bash
75
- pip install ameva-cluster
76
- # or Node.js:
77
- npm install @ameva/cluster
78
- ```
79
-
80
- ### 2. Launch Worker Node on Remote Phone
81
- ```bash
82
- # On remote worker device (e.g. Galaxy A53):
83
- ameva-cluster worker --port 50052
84
- ```
85
-
86
- ### 3. Distributed Transcription via Master Node
87
- ```bash
88
- # Master node sharding Whisper-Large layers across remote phone RAM:
89
- termux-stt transcribe meeting.wav \
90
- --model whisper-large-v3-turbo.bin \
91
- --rpc 192.0.2.10:50052,192.0.2.11:50052
92
- ```
93
-
94
- ```python
95
- from termux_stt import create_engine
96
-
97
- # Python SDK Distributed STT
98
- engine = create_engine(
99
- "whisper",
100
- model="large-v3-turbo",
101
- cluster_rpc_servers="192.0.2.10:50052,192.0.2.11:50052"
102
- )
103
- result = engine.transcribe("meeting.wav")
104
- print(result.text)
105
- ```
106
-
107
- ---
108
-
109
76
  ## Official Documentation & Benchmarks
110
77
  - [Official Architecture & API Reference](https://uno-km.vercel.app/lib/stt/)
111
78
  - [Ecosystem Metrics & Registry Stats](https://uno-km.vercel.app/foundation/metrics)
package/README.pypi.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![Python](https://img.shields.io/pypi/pyversions/termux-stt.svg?style=flat-square)](https://pypi.org/project/termux-stt/)
5
5
  [![License](https://img.shields.io/badge/License-Apache_2.0-004499.svg?style=flat-square)](https://github.com/uno-km/termux-stt)
6
6
 
7
- > Unified On-Device Speech-to-Text Utilizing Device Resources & Pure Python 128d X-Vector Speaker Diarization
7
+ > Unified On-Device Speech-to-Text & Neural Multi-Speaker Diarization (PyAnnote 3.0 + CAM++ 192d + TS-VAD Overlap Resolver)
8
8
 
9
9
  ## Installation
10
10
 
@@ -17,24 +17,24 @@ pip install termux-stt
17
17
  ```python
18
18
  from termux_stt import create_engine
19
19
 
20
- # 1. Initialize Engine with Hybrid GPU-Encoder / CPU-Decoder Acceleration
21
- engine = create_engine("whisper", model="small", lang="en", threads=4, split_mode=True)
20
+ # 1. Initialize Whisper Engine with Vulkan GPU / CPU Hybrid Acceleration
21
+ engine = create_engine("whisper", model="small", lang="ko", threads=4, split_mode=True)
22
22
 
23
23
  # 2. Transcribe Audio directly into Subtitles
24
24
  result = engine.transcribe("samples/jfk_1min.wav")
25
25
  print("Transcript:\n", result.text)
26
26
  print("SRT Subtitles:\n", result.to_srt())
27
27
 
28
- # 3. 2-Speaker Diarization without PyTorch
29
- hybrid = create_engine("hybrid", lang="en", num_speakers=2)
30
- diar_result = hybrid.diarize("samples/jfk_1min.wav")
28
+ # 3. Multi-Speaker Neural Diarization (PyAnnote 3.0 + CAM++ 192d + TS-VAD)
29
+ hybrid = create_engine("hybrid", lang="ko", num_speakers=2)
30
+ diar_result = hybrid.diarize("samples/kor_diarization.wav")
31
31
  for seg in diar_result.segments:
32
32
  print(f"[{seg.speaker}] ({seg.start:.1f}s -> {seg.end:.1f}s): {seg.text}")
33
33
 
34
34
  ```
35
35
 
36
36
  ## Description
37
- Integrates Whisper.cpp, Vosk, and Sherpa-ONNX with a closed-form pure-Python 128-dimensional X-Vector clustering algorithm that operates in under 80MB RAM with zero cloud egress.
37
+ Integrates Whisper.cpp (Native Vulkan GPU / NEON CPU) and Sherpa-ONNX with PyAnnote 3.0 neural segmentation, 3D-Speaker CAM++ 192-dim embeddings, and TS-VAD overlapped speech resolution with zero cloud egress.
38
38
 
39
39
  ## Documentation
40
40
  - [Official Documentation & API Reference](https://uno-km.vercel.app/lib/stt/)
package/index.d.ts CHANGED
@@ -45,7 +45,7 @@ export class WhisperEngine extends Engine {
45
45
  diarize(audioPath: string, numSpeakers?: number): Promise<TranscriptResult>;
46
46
  }
47
47
 
48
- export class VoskEngine extends Engine {
48
+ export class SherpaEngine extends Engine {
49
49
  transcribe(audioPath: string, options?: any): Promise<TranscriptResult>;
50
50
  diarize(audioPath: string, numSpeakers?: number): Promise<TranscriptResult>;
51
51
  }
@@ -56,8 +56,13 @@ export class HybridEngine extends Engine {
56
56
  }
57
57
 
58
58
  export function createEngine(
59
- engineName?: 'whisper' | 'vosk' | 'hybrid' | string,
59
+ engineName?: 'whisper' | 'sherpa' | 'hybrid' | string,
60
60
  options?: EngineOptions
61
61
  ): Engine;
62
62
 
63
- export function formatTime(seconds: number, separator?: string): string;
63
+ export class TermuxSTT {
64
+ engine: Engine;
65
+ constructor(options?: EngineOptions & { engine?: string });
66
+ transcribe(filePath: string, options?: any): Promise<TranscriptResult>;
67
+ diarize(filePath: string, options?: any): Promise<TranscriptResult>;
68
+ }
package/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
- * termux-stt Node.js entry point
2
+ * termux-stt Node.js entry point (v2.0.0)
3
3
  */
4
4
 
5
5
  const { Engine, TranscriptResult, Segment, formatTime } = require('./lib/engine');
6
6
  const { WhisperEngine } = require('./lib/whisper');
7
- const { VoskEngine } = require('./lib/vosk');
7
+ const { SherpaEngine } = require('./lib/sherpa');
8
8
  const { HybridEngine } = require('./lib/hybrid');
9
9
 
10
10
  function createEngine(engineName = 'whisper', options = {}) {
@@ -12,12 +12,14 @@ function createEngine(engineName = 'whisper', options = {}) {
12
12
  switch (name) {
13
13
  case 'whisper':
14
14
  return new WhisperEngine(options);
15
- case 'vosk':
16
- return new VoskEngine(options);
15
+ case 'sherpa':
16
+ return new SherpaEngine(options);
17
17
  case 'hybrid':
18
18
  return new HybridEngine(options);
19
+ case 'vosk':
20
+ throw new Error("Vosk has been deprecated and completely removed in v2.0.0. Please use 'sherpa' (SenseVoice) or 'whisper'.");
19
21
  default:
20
- throw new Error(`Unknown engine: ${engineName}. Available: whisper, vosk, hybrid`);
22
+ throw new Error(`Unknown engine: ${engineName}. Available: whisper, sherpa, hybrid`);
21
23
  }
22
24
  }
23
25
 
@@ -41,7 +43,7 @@ module.exports = {
41
43
  TranscriptResult,
42
44
  Segment,
43
45
  WhisperEngine,
44
- VoskEngine,
46
+ SherpaEngine,
45
47
  HybridEngine,
46
48
  formatTime
47
49
  };
package/lib/hybrid.js CHANGED
@@ -53,7 +53,7 @@ class HybridEngine extends Engine {
53
53
 
54
54
  getInfo() {
55
55
  return {
56
- name: 'Hybrid Vosk+Whisper (Node.js)',
56
+ name: 'Hybrid Neural Diarizer + Whisper (Node.js)',
57
57
  model: this.model,
58
58
  language: this.lang,
59
59
  numSpeakers: this.numSpeakers
package/lib/sherpa.js ADDED
@@ -0,0 +1,97 @@
1
+ /**
2
+ * SherpaEngine for Node.js - Non-Autoregressive SenseVoice STT & Neural Diarization
3
+ */
4
+
5
+ const { spawn } = require('child_process');
6
+ const { Engine, TranscriptResult, Segment } = require('./engine');
7
+
8
+ class SherpaEngine extends Engine {
9
+ constructor(config = {}) {
10
+ super(config);
11
+ this.model = config.model || 'sensevoice-small-int8';
12
+ this.lang = config.lang || 'ko';
13
+ this.threads = config.threads || 4;
14
+ }
15
+
16
+ async transcribe(audioPath, options = {}) {
17
+ return new Promise((resolve, reject) => {
18
+ const args = [
19
+ '-m', 'termux_stt.cli.main',
20
+ 'transcribe',
21
+ '--engine', 'sherpa',
22
+ '--model', this.model,
23
+ '--lang', this.lang,
24
+ '--format', 'json',
25
+ audioPath
26
+ ];
27
+
28
+ const proc = spawn('python', args, { env: process.env });
29
+ let stdout = '';
30
+ let stderr = '';
31
+
32
+ proc.stdout.on('data', (d) => { stdout += d.toString(); });
33
+ proc.stderr.on('data', (d) => { stderr += d.toString(); });
34
+
35
+ proc.on('close', (code) => {
36
+ if (code !== 0) {
37
+ return reject(new Error(`Sherpa transcription failed (code ${code}): ${stderr}`));
38
+ }
39
+ try {
40
+ const parsed = JSON.parse(stdout);
41
+ const segments = (parsed.segments || []).map(
42
+ s => new Segment(s.start, s.end, s.text, s.speaker, s.confidence)
43
+ );
44
+ resolve(new TranscriptResult(parsed.text, segments, parsed.language || this.lang, parsed.duration));
45
+ } catch (e) {
46
+ resolve(new TranscriptResult(stdout.trim(), [new Segment(0, 0, stdout.trim())], this.lang));
47
+ }
48
+ });
49
+ });
50
+ }
51
+
52
+ async diarize(audioPath, numSpeakers = 2) {
53
+ return new Promise((resolve, reject) => {
54
+ const args = [
55
+ '-m', 'termux_stt.cli.main',
56
+ 'diarize',
57
+ '--engine', 'sherpa',
58
+ '--speakers', String(numSpeakers),
59
+ '--format', 'json',
60
+ audioPath
61
+ ];
62
+
63
+ const proc = spawn('python', args, { env: process.env });
64
+ let stdout = '';
65
+ let stderr = '';
66
+
67
+ proc.stdout.on('data', (d) => { stdout += d.toString(); });
68
+ proc.stderr.on('data', (d) => { stderr += d.toString(); });
69
+
70
+ proc.on('close', (code) => {
71
+ if (code !== 0) {
72
+ return reject(new Error(`Sherpa diarization failed (code ${code}): ${stderr}`));
73
+ }
74
+ try {
75
+ const parsed = JSON.parse(stdout);
76
+ const segments = (parsed.segments || []).map(
77
+ s => new Segment(s.start, s.end, s.text, s.speaker, s.confidence)
78
+ );
79
+ resolve(new TranscriptResult(parsed.text, segments, parsed.language || this.lang, parsed.duration));
80
+ } catch (e) {
81
+ resolve(new TranscriptResult(stdout.trim(), [new Segment(0, 0, stdout.trim())], this.lang));
82
+ }
83
+ });
84
+ });
85
+ }
86
+
87
+ getInfo() {
88
+ return {
89
+ name: 'Sherpa-ONNX (Node.js)',
90
+ model: this.model,
91
+ language: this.lang,
92
+ threads: this.threads
93
+ };
94
+ }
95
+ }
96
+
97
+ module.exports = { SherpaEngine };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "termux-stt",
3
- "version": "1.5.0",
4
- "description": "On-device Speech-to-Text & speaker diarization framework utilizing device resources for Android Termux",
3
+ "version": "2.0.1",
4
+ "description": "On-device Speech-to-Text & neural speaker diarization framework for Android Termux (Whisper Vulkan GPU & Sherpa-ONNX)",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
7
  "bin": {
package/lib/vosk.js DELETED
@@ -1,60 +0,0 @@
1
- /**
2
- * VoskEngine for Node.js
3
- */
4
-
5
- const { spawn } = require('child_process');
6
- const { Engine, TranscriptResult, Segment } = require('./engine');
7
-
8
- class VoskEngine extends Engine {
9
- constructor(config = {}) {
10
- super(config);
11
- this.model = config.model || 'small-ko-0.22';
12
- this.lang = config.lang || 'ko';
13
- }
14
-
15
- async transcribe(audioPath, options = {}) {
16
- return new Promise((resolve, reject) => {
17
- const args = [
18
- '-m', 'termux_stt.cli.main',
19
- 'transcribe',
20
- '--engine', 'vosk',
21
- '--model', this.model,
22
- '--lang', this.lang,
23
- '--format', 'json',
24
- audioPath
25
- ];
26
-
27
- const proc = spawn('python', args, { env: process.env });
28
- let stdout = '';
29
- let stderr = '';
30
-
31
- proc.stdout.on('data', (d) => { stdout += d.toString(); });
32
- proc.stderr.on('data', (d) => { stderr += d.toString(); });
33
-
34
- proc.on('close', (code) => {
35
- if (code !== 0) {
36
- return reject(new Error(`Vosk transcription failed (code ${code}): ${stderr}`));
37
- }
38
- try {
39
- const parsed = JSON.parse(stdout);
40
- const segments = (parsed.segments || []).map(
41
- s => new Segment(s.start, s.end, s.text, s.speaker, s.confidence)
42
- );
43
- resolve(new TranscriptResult(parsed.text, segments, parsed.language || this.lang, parsed.duration));
44
- } catch (e) {
45
- resolve(new TranscriptResult(stdout.trim(), [new Segment(0, 0, stdout.trim())], this.lang));
46
- }
47
- });
48
- });
49
- }
50
-
51
- getInfo() {
52
- return {
53
- name: 'Vosk (Node.js)',
54
- model: this.model,
55
- language: this.lang
56
- };
57
- }
58
- }
59
-
60
- module.exports = { VoskEngine };