@medc-com-br/ngx-jaimes-scribe 0.1.2
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/.turbo/turbo-build.log +28 -0
- package/README.md +760 -0
- package/ng-package.json +10 -0
- package/package.json +41 -0
- package/src/assets/pcm-processor.js +72 -0
- package/src/lib/components/recorder/recorder.component.ts +743 -0
- package/src/lib/services/audio-capture.service.ts +190 -0
- package/src/lib/services/scribe-socket.service.ts +264 -0
- package/src/lib/services/vad.service.ts +65 -0
- package/src/lib/worklets/audio-worklet.d.ts +14 -0
- package/src/lib/worklets/pcm-processor.worklet.ts +81 -0
- package/src/public-api.ts +5 -0
- package/tsconfig.lib.json +24 -0
package/ng-package.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@medc-com-br/ngx-jaimes-scribe",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Angular library for real-time medical transcription",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/medc-com-br/medc-jaimes.git",
|
|
8
|
+
"directory": "libs/ngx-jaimes-scribe"
|
|
9
|
+
},
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"registry": "https://registry.npmjs.org",
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"license": "UNLICENSED",
|
|
15
|
+
"author": "MEDC Sistemas de Saúde",
|
|
16
|
+
"keywords": ["angular", "transcription", "medical", "speech-to-text", "healthcare"],
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@angular/common": "^19.0.0",
|
|
19
|
+
"@angular/core": "^19.0.0",
|
|
20
|
+
"@medc-com-br/jaimes-shared": "^0.1.0",
|
|
21
|
+
"rxjs": "^7.8.0"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"tslib": "^2.8.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@angular/compiler": "^19.0.0",
|
|
28
|
+
"@angular/compiler-cli": "^19.0.0",
|
|
29
|
+
"@angular/common": "^19.0.0",
|
|
30
|
+
"@angular/core": "^19.0.0",
|
|
31
|
+
"ng-packagr": "^19.0.0",
|
|
32
|
+
"rxjs": "^7.8.0",
|
|
33
|
+
"typescript": "~5.6.0",
|
|
34
|
+
"zone.js": "~0.15.0"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "ng-packagr -p ng-package.json",
|
|
38
|
+
"clean": "rm -rf dist"
|
|
39
|
+
},
|
|
40
|
+
"sideEffects": false
|
|
41
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const TARGET_SAMPLE_RATE = 16000;
|
|
2
|
+
const BUFFER_SIZE = 4096;
|
|
3
|
+
|
|
4
|
+
class PcmProcessor extends AudioWorkletProcessor {
|
|
5
|
+
constructor(options) {
|
|
6
|
+
super();
|
|
7
|
+
|
|
8
|
+
this.inputSampleRate = options.processorOptions?.inputSampleRate || 48000;
|
|
9
|
+
this.resampleRatio = this.inputSampleRate / TARGET_SAMPLE_RATE;
|
|
10
|
+
|
|
11
|
+
this.inputBuffer = new Float32Array(BUFFER_SIZE * 2);
|
|
12
|
+
this.inputBufferIndex = 0;
|
|
13
|
+
|
|
14
|
+
const outputBufferSize = Math.ceil(BUFFER_SIZE / this.resampleRatio);
|
|
15
|
+
this.resampleBuffer = new Float32Array(outputBufferSize);
|
|
16
|
+
this.resampleBufferIndex = 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
process(inputs, _outputs, _parameters) {
|
|
20
|
+
const input = inputs[0];
|
|
21
|
+
if (!input || !input[0]) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const inputChannel = input[0];
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < inputChannel.length; i++) {
|
|
28
|
+
this.inputBuffer[this.inputBufferIndex++] = inputChannel[i];
|
|
29
|
+
|
|
30
|
+
if (this.inputBufferIndex >= BUFFER_SIZE) {
|
|
31
|
+
this.processBuffer();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
processBuffer() {
|
|
39
|
+
const outputLength = Math.floor(this.inputBufferIndex / this.resampleRatio);
|
|
40
|
+
|
|
41
|
+
for (let i = 0; i < outputLength; i++) {
|
|
42
|
+
const srcIndex = i * this.resampleRatio;
|
|
43
|
+
const srcIndexFloor = Math.floor(srcIndex);
|
|
44
|
+
const srcIndexCeil = Math.min(srcIndexFloor + 1, this.inputBufferIndex - 1);
|
|
45
|
+
const t = srcIndex - srcIndexFloor;
|
|
46
|
+
|
|
47
|
+
const sample = this.inputBuffer[srcIndexFloor] * (1 - t) + this.inputBuffer[srcIndexCeil] * t;
|
|
48
|
+
this.resampleBuffer[this.resampleBufferIndex++] = sample;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const pcmData = this.float32ToPcm16(this.resampleBuffer.subarray(0, this.resampleBufferIndex));
|
|
52
|
+
this.port.postMessage(pcmData, [pcmData]);
|
|
53
|
+
|
|
54
|
+
this.inputBufferIndex = 0;
|
|
55
|
+
this.resampleBufferIndex = 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
float32ToPcm16(float32Array) {
|
|
59
|
+
const buffer = new ArrayBuffer(float32Array.length * 2);
|
|
60
|
+
const view = new DataView(buffer);
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < float32Array.length; i++) {
|
|
63
|
+
const sample = Math.max(-1, Math.min(1, float32Array[i]));
|
|
64
|
+
const int16 = sample < 0 ? sample * 0x8000 : sample * 0x7fff;
|
|
65
|
+
view.setInt16(i * 2, int16, true);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return buffer;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
registerProcessor('pcm-processor', PcmProcessor);
|