@hoanghong/speaking-angular 0.5.0 → 0.6.0
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/CHANGELOG.md +6 -0
- package/README.md +166 -130
- package/package.json +9 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## 0.6.0
|
|
2
|
+
|
|
3
|
+
- Versioned overall local pronunciation score (harmonic mean of accuracy and completeness).
|
|
4
|
+
- Explicit score scale, availability, components, exclusions and calibration status.
|
|
5
|
+
- New clients accept older servers without inventing an overall score.
|
|
6
|
+
|
|
1
7
|
## 0.5.0
|
|
2
8
|
|
|
3
9
|
- Optional multi-criteria local pronunciation diagnostics with methods, limitations and unavailable scores.
|
package/README.md
CHANGED
|
@@ -1,192 +1,228 @@
|
|
|
1
1
|
# @hoanghong/speaking-angular
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Angular 18 / RxJS 7.8 SDK for realtime transcription, audio upload and US English pronunciation diagnostics. Service connections, sessions and worklet loading are automatic; no service URL or service token is required. Models run on the service. MIT license.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Install from npm
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install
|
|
8
|
+
npm install @hoanghong/speaking-core@0.6.0 @hoanghong/speaking-angular@0.6.0
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## 1. Install from the version 0.6.0 release ZIP
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
Chưa publish 0.5.0 lên registry. Các tính năng nhận dạng cũ vẫn dùng được.
|
|
13
|
+
Copy both npm tarballs into your application's vendor directory:
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
```bash
|
|
16
|
+
npm install ./vendor/hoanghong-speaking-core-0.6.0.tgz ./vendor/hoanghong-speaking-angular-0.6.0.tgz
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
For a new application, first run npx @angular/cli@18 new speaking-demo --standalone --routing=false --style=css, then cd speaking-demo. These instructions use local archives and do not assume registry publication.
|
|
20
|
+
|
|
21
|
+
## 2. Configure an application key, if supplied
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
`@hoanghong/speaking-angular`, rồi gọi trong class component:
|
|
23
|
+
Use the following src/app/app.config.ts when FSEL has provided a key. Without a key, use an empty providers array for the basic anonymous quota.
|
|
20
24
|
|
|
21
25
|
```ts
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
filename: file.name,
|
|
29
|
-
});
|
|
30
|
-
console.log(result.phoneme_similarity, result.comparisons, result.warnings);
|
|
31
|
-
}
|
|
26
|
+
import { ApplicationConfig } from '@angular/core';
|
|
27
|
+
import { provideSpeakingApp } from '@hoanghong/speaking-angular';
|
|
28
|
+
|
|
29
|
+
export const appConfig: ApplicationConfig = {
|
|
30
|
+
providers: [provideSpeakingApp({ appKey: 'YOUR_APP_KEY' })],
|
|
31
|
+
};
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
Có thể dùng câu/đoạn đọc: thay referenceText bằng đúng nội dung cần đọc và bỏ
|
|
36
|
-
expectedPhonemes nếu server đã cài eSpeak; không dùng chuỗi âm của `cat` cho đoạn khác.
|
|
37
|
-
Hỗ trợ audio tối đa 120 giây/25 MiB, reference 4096 ký tự, client chờ tối đa 11 phút.
|
|
38
|
-
Thêm `signal: controller.signal` để hủy request. Hàm reject khi lỗi; UI cần catch và hiển thị.
|
|
39
|
-
`calibrated=false`: similarity chỉ là đối chiếu âm vị, chưa phải điểm phát âm chính thức.
|
|
40
|
-
Kết quả có timestamp, âm thiếu/thừa/thay thế, formant/pitch/intensity/PSD và warnings.
|
|
34
|
+
Use src/main.ts:
|
|
41
35
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
```ts
|
|
37
|
+
import { bootstrapApplication } from '@angular/platform-browser';
|
|
38
|
+
import { AppComponent } from './app/app.component';
|
|
39
|
+
import { appConfig } from './app/app.config';
|
|
46
40
|
|
|
47
|
-
|
|
41
|
+
bootstrapApplication(AppComponent, appConfig).catch(console.error);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Application keys are visible application identifiers, not administrative credentials. Key quotas/status are managed server-side. An invalid/disabled key returns INVALID_APP_KEY rather than falling back to anonymous access. Never embed service credentials.
|
|
48
45
|
|
|
49
|
-
|
|
46
|
+
## 3. Complete pronunciation example
|
|
47
|
+
|
|
48
|
+
Replace src/app/app.component.ts below. The learner reads the displayed passage, selects a recording and clicks Assess pronunciation. Alternatively, record with the existing speaking component; its completed callback supplies the same audio File. Assessment is a separate explicit action.
|
|
50
49
|
|
|
51
50
|
```ts
|
|
52
51
|
import { Component, OnDestroy } from '@angular/core';
|
|
53
|
-
import {
|
|
52
|
+
import {
|
|
53
|
+
FselSpeakingComponent, PronunciationAssessment, SpeakingError,
|
|
54
|
+
SpeakingResult, SpeakingService,
|
|
55
|
+
} from '@hoanghong/speaking-angular';
|
|
54
56
|
|
|
55
57
|
@Component({
|
|
56
|
-
selector: 'app-root',
|
|
58
|
+
selector: 'app-root',
|
|
59
|
+
standalone: true,
|
|
57
60
|
imports: [FselSpeakingComponent],
|
|
61
|
+
providers: [SpeakingService],
|
|
58
62
|
template: `
|
|
59
|
-
<main
|
|
60
|
-
<h1>
|
|
61
|
-
<
|
|
62
|
-
|
|
63
|
-
<
|
|
63
|
+
<main>
|
|
64
|
+
<h1>US English pronunciation practice</h1>
|
|
65
|
+
<p>Read this passage: {{ referenceText }}</p>
|
|
66
|
+
<label for="recording">Choose an audio recording (maximum 120 seconds)</label>
|
|
67
|
+
<input id="recording" type="file" accept="audio/*"
|
|
68
|
+
[disabled]="busy" (change)="selectFile($event)" />
|
|
69
|
+
<p>Or record the passage, then stop before 120 seconds:</p>
|
|
70
|
+
@if (!busy) {
|
|
71
|
+
<fsel-speaking serviceType="realtime" initialLanguage="en"
|
|
72
|
+
(completed)="onCompleted($event)" (failed)="onFailed($event)" />
|
|
73
|
+
}
|
|
64
74
|
@if (audioUrl) {
|
|
65
75
|
<audio controls [src]="audioUrl"></audio>
|
|
66
|
-
|
|
76
|
+
}
|
|
77
|
+
<button type="button" [disabled]="!audio || busy" (click)="assess()">
|
|
78
|
+
Assess pronunciation
|
|
79
|
+
</button>
|
|
80
|
+
<button type="button" [disabled]="!busy" (click)="cancel()">Cancel</button>
|
|
81
|
+
@if (busy) { <p role="status">Assessing pronunciation...</p> }
|
|
82
|
+
@if (assessment) {
|
|
83
|
+
<p>Phoneme similarity: {{ assessment.phoneme_similarity }} (uncalibrated)</p>
|
|
84
|
+
<p>Phoneme accuracy: {{ accuracy }}</p>
|
|
85
|
+
<p>Overall local pronunciation score: {{ overall }}</p>
|
|
86
|
+
@for (warning of assessment.warnings; track $index) { <p>{{ warning }}</p> }
|
|
67
87
|
}
|
|
68
88
|
<p role="alert">{{ error }}</p>
|
|
69
89
|
</main>
|
|
70
90
|
`,
|
|
71
91
|
})
|
|
72
92
|
export class AppComponent implements OnDestroy {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
93
|
+
readonly referenceText = 'The cat is sitting on the mat.';
|
|
94
|
+
audio: File | null = null;
|
|
95
|
+
audioUrl = '';
|
|
96
|
+
assessment: PronunciationAssessment | null = null;
|
|
97
|
+
error = '';
|
|
98
|
+
busy = false;
|
|
99
|
+
private controller?: AbortController;
|
|
100
|
+
private destroyed = false;
|
|
101
|
+
|
|
102
|
+
constructor(private readonly speaking: SpeakingService) {}
|
|
103
|
+
|
|
104
|
+
get overall(): string {
|
|
105
|
+
const value = this.assessment?.overall;
|
|
106
|
+
return value?.status === 'estimated' && value.score != null
|
|
107
|
+
? value.score.toFixed(1) + ' / ' + value.scale + ' (local estimate)'
|
|
108
|
+
: value?.reason ?? 'Unavailable: upgrade the server if needed';
|
|
80
109
|
}
|
|
81
|
-
onFailed(error: Error): void { this.error = error.message; }
|
|
82
|
-
ngOnDestroy(): void { if (this.audioUrl) URL.revokeObjectURL(this.audioUrl); }
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
110
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
```
|
|
111
|
+
get accuracy(): string {
|
|
112
|
+
const value = this.assessment?.breakdown?.accuracy;
|
|
113
|
+
return value?.status === 'estimated' && value.score != null
|
|
114
|
+
? value.score.toFixed(1) + ' / 100 (estimate)'
|
|
115
|
+
: 'Unavailable';
|
|
116
|
+
}
|
|
93
117
|
|
|
94
|
-
|
|
118
|
+
selectFile(event: Event): void {
|
|
119
|
+
this.setAudio((event.target as HTMLInputElement).files?.[0] ?? null);
|
|
120
|
+
}
|
|
95
121
|
|
|
96
|
-
|
|
122
|
+
onCompleted(result: SpeakingResult): void { this.setAudio(result.audio); }
|
|
123
|
+
onFailed(error: Error): void { this.error = error.message; }
|
|
97
124
|
|
|
98
|
-
|
|
125
|
+
private setAudio(file: File | null): void {
|
|
126
|
+
if (this.audioUrl) URL.revokeObjectURL(this.audioUrl);
|
|
127
|
+
this.audio = file;
|
|
128
|
+
this.audioUrl = file ? URL.createObjectURL(file) : '';
|
|
129
|
+
this.assessment = null;
|
|
130
|
+
this.error = '';
|
|
131
|
+
}
|
|
99
132
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
133
|
+
async assess(): Promise<void> {
|
|
134
|
+
if (!this.audio || this.busy) return;
|
|
135
|
+
this.busy = true;
|
|
136
|
+
this.error = '';
|
|
137
|
+
this.assessment = null;
|
|
138
|
+
this.controller = new AbortController();
|
|
139
|
+
try {
|
|
140
|
+
const result = await this.speaking.pronunciation.assessAudio(this.audio, {
|
|
141
|
+
referenceText: this.referenceText,
|
|
142
|
+
filename: this.audio.name,
|
|
143
|
+
signal: this.controller.signal,
|
|
144
|
+
});
|
|
145
|
+
if (!this.destroyed) this.assessment = result;
|
|
146
|
+
} catch (error) {
|
|
147
|
+
if (!this.destroyed) {
|
|
148
|
+
this.error = error instanceof SpeakingError
|
|
149
|
+
? error.code + ': ' + error.message
|
|
150
|
+
: 'Pronunciation assessment failed.';
|
|
151
|
+
}
|
|
152
|
+
} finally {
|
|
153
|
+
if (!this.destroyed) this.busy = false;
|
|
154
|
+
this.controller = undefined;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
107
157
|
|
|
108
|
-
|
|
158
|
+
cancel(): void { this.controller?.abort(); }
|
|
109
159
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
160
|
+
ngOnDestroy(): void {
|
|
161
|
+
this.destroyed = true;
|
|
162
|
+
this.cancel();
|
|
163
|
+
if (this.audioUrl) URL.revokeObjectURL(this.audioUrl);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
115
166
|
```
|
|
116
167
|
|
|
117
|
-
|
|
168
|
+
Run npx ng serve and open the local address printed by Angular. Microphone capture requires HTTPS or localhost and user permission. The SDK does not automatically record on page load. The component currently uses its built-in interface labels; the example's own labels and comments are English.
|
|
118
169
|
|
|
119
|
-
|
|
170
|
+
SpeakingService must be provided at the screen/component level as shown. provideSpeakingApp configures application identity; it does not replace that provider. The fsel-speaking component owns its recording/transcription lifecycle. Assessment consumes an additional session after recording/transcription. For upload-only pronunciation, the file input calls the pronunciation client directly without first creating a transcription job.
|
|
120
171
|
|
|
121
|
-
|
|
122
|
-
npx ng serve
|
|
123
|
-
```
|
|
172
|
+
## 4. Reference text and optional phonemes
|
|
124
173
|
|
|
125
|
-
|
|
174
|
+
Pronunciation supports en-US only. referenceText is the exact word, sentence or paragraph being read (1–4096 characters). Omit expectedPhonemes for normal passages; server-side text-to-phoneme support must be installed.
|
|
126
175
|
|
|
127
|
-
|
|
176
|
+
For a specific word, add expectedPhonemes: ['k', 'æ', 't'] and set referenceText: 'cat' in the assessment options. These are complete model vocabulary tokens, not individual IPA characters. Do not include enclosing slashes or reuse this sequence for another passage.
|
|
128
177
|
|
|
129
|
-
|
|
130
|
-
- `serviceType="upload"`: chọn file audio, trả transcript và chính File đầu vào, giữ tên/định dạng.
|
|
131
|
-
- Không đặt `serviceType`: hiện cả hai cách. `uploadEnabled=false` ẩn upload.
|
|
132
|
-
- `initialLanguage`: `en` (Anh), `ja` (Nhật), `ko` (Hàn), `zh` (Trung), `vi` (Việt, mặc định).
|
|
178
|
+
Audio must be nonempty, at most 120 seconds and 25 MiB. WAV PCM16 mono at 16 kHz is suitable; the service validates duration/formats. Realtime transcription itself permits 300 seconds, so stop within 120 seconds for pronunciation. The assessment request timeout defaults to 11 minutes. AbortSignal cancels the client request; it does not refund quota or guarantee server inference cancellation. There is no automatic retry.
|
|
133
179
|
|
|
134
|
-
|
|
180
|
+
## 5. Read the assessment
|
|
135
181
|
|
|
136
|
-
|
|
182
|
+
| Field | Use |
|
|
183
|
+
| --- | --- |
|
|
184
|
+
| phoneme_similarity / phoneme_error_rate | Edit-based phoneme comparison, not an official grade |
|
|
185
|
+
| comparisons | match/substitution/deletion/insertion; expected/observed tokens and approximate seconds |
|
|
186
|
+
| observed_phonemes | Recognized tokens and approximate times |
|
|
187
|
+
| breakdown | Optional criteria, errors, signal and limitations |
|
|
188
|
+
| acoustic_frames / psd_frequencies_hz | Formants, pitch, intensity and spectral data |
|
|
189
|
+
| warnings | Interpretation and model limitations |
|
|
137
190
|
|
|
138
|
-
|
|
191
|
+
breakdown may be absent or null with older services. Each criterion has score (0–100 or null), status (estimated/unavailable), method and reason. Display unavailable as "Unavailable", never zero. Display methods/reasons/limitations alongside estimates. Missing sounds can have null timestamps; counts refer to phonemes, not words.
|
|
139
192
|
|
|
140
|
-
|
|
141
|
-
| --- | --- |
|
|
142
|
-
| `text` | String nhận dạng cuối; rỗng khi không có lời nói |
|
|
143
|
-
| `audio` | File, dùng createObjectURL/FormData/arrayBuffer; realtime có tên speaking.wav |
|
|
144
|
-
| `language` | en/ja/ko/zh/vi |
|
|
145
|
-
| `serviceType` | realtime/upload |
|
|
146
|
-
| `status` | succeeded/no_speech; các metadata gốc vẫn được giữ |
|
|
147
|
-
| `result` | Transcript chi tiết từ server nếu có |
|
|
193
|
+
Accuracy = 100*M/(M+S+I); completeness = 100*(N-D)/N, with matches/substitutions/omissions/insertions M/S/D/I and reference count N. Completeness includes substitutions as covered. Similarity = 100*max(0, 1-(S+D+I)/N) and differs from accuracy. Fluency is an acoustic energy-continuity proxy affected by noise/intentional pauses. Prosody has pitch measurements without a score. Overall pronunciation is the harmonic mean of Accuracy and Completeness. Vocabulary, grammar and topic scores are unavailable. calibrated=false; approximate timing is not forced alignment. Do not use these diagnostics as educational grades, Azure scores or pass/fail thresholds.
|
|
148
194
|
|
|
149
|
-
|
|
195
|
+
## 6. Existing transcription component
|
|
150
196
|
|
|
151
|
-
|
|
197
|
+
Use serviceType="realtime" for microphone transcription; serviceType="upload" for audio-file transcription. Omitting serviceType displays both; [uploadEnabled]="false" hides upload. initialLanguage supports en/ja/ko/zh/vi (default vi).
|
|
152
198
|
|
|
153
|
-
|
|
199
|
+
completed emits SpeakingResult with text, audio (File), language, serviceType, status and optional detailed result. Realtime audio is WAV PCM16 mono at 16 kHz; upload preserves the selected file. An empty transcript may indicate no_speech. failed emits an Error; cancellation/failure does not emit successful audio. Use object URLs for playback/download and revoke them when no longer needed. Use FormData to store audio; files are not automatically persisted to permanent storage.
|
|
154
200
|
|
|
155
|
-
|
|
201
|
+
## 7. Quotas and troubleshooting
|
|
156
202
|
|
|
157
|
-
|
|
203
|
+
Basic quota defaults to 5 sessions per IP/day and 100 per instance/day (UTC), subject to operator changes. New sessions consume quota even on processing failure. Application-key quota is managed by FSEL. Realtime buffers approximately 9.6 MB PCM; upload UI accepts up to 25 MiB and polls up to 10 minutes. Leaving the component stops capture/polling, although accepted server jobs may continue. There is no automatic reconnect/replay.
|
|
158
204
|
|
|
205
|
+
Handle SpeakingError.code/status/message: INVALID_REFERENCE/INVALID_AUDIO for input, INVALID_APP_KEY/401 for key issues, QUOTA_EXCEEDED/429 for quota, 415 for unsupported formats, 422 for validation/no recognized phonemes, 404 for missing functionality and 503 for service/model readiness. Check browser microphone permissions and application network/CSP policies for capture/connection failures.
|
|
159
206
|
|
|
160
|
-
|
|
207
|
+
The bundle installs clients; it does not deploy models or prove hosted readiness. Physical microphone/playback and real learner scoring require separate device/service verification.
|
|
161
208
|
|
|
162
|
-
Pass the application key provided by FSEL as `appKey`. The SDK handles service
|
|
163
|
-
connections automatically. Quotas and key status are managed by the service.
|
|
164
|
-
App keys identify an application and are visible in browser/mobile applications.
|
|
165
209
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
210
|
+
## Overall pronunciation output (0.6.0)
|
|
211
|
+
|
|
212
|
+
Use `result.overall?.score` for the overall chart.
|
|
213
|
+
It is a local estimate, the harmonic mean of unrounded Accuracy and Completeness:
|
|
214
|
+
`2*A*C/(A+C)`, or 0 if A+C=0. Fluency and Prosody are excluded. This is not an
|
|
215
|
+
Azure or calibrated educational grade. `phoneme_similarity` is a separate legacy
|
|
216
|
+
edit-distance diagnostic and can be zero while the overall score is positive.
|
|
169
217
|
|
|
218
|
+
The overall object includes `version=local-accuracy-completeness-v1`, `scale=100`,
|
|
219
|
+
`calibrated=false`, `status`, `method`, `reason`, `components` and
|
|
220
|
+
`excluded_components` (Flutter: `excludedComponents`).
|
|
221
|
+
Render null/unavailable scores as unavailable; preserve valid zero values.
|
|
222
|
+
An older server can omit `overall`; the SDK never computes a replacement score.
|
|
223
|
+
`breakdown.pronunciation` mirrors the overall criterion for compatibility.
|
|
224
|
+
The server must be upgraded as well as the SDK.
|
|
170
225
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
vocabulary, grammar and topic. Each has score (0–100 or null), status
|
|
175
|
-
(estimated/unavailable), method and reason. These are local diagnostics, not Azure
|
|
176
|
-
scores or calibrated grades. Older services may omit breakdown.
|
|
177
|
-
|
|
178
|
-
- Accuracy = 100 * matches / (matches + substitutions + insertions), at phoneme level.
|
|
179
|
-
- Completeness = 100 * (reference phonemes - omissions) / reference phonemes.
|
|
180
|
-
Substitutions count as covered; this is coverage, not correctness.
|
|
181
|
-
- Fluency is an energy continuity proxy = 100 * (1 - internal pause seconds / active span).
|
|
182
|
-
20 ms RMS windows, threshold=max(0.005, 0.1*peak RMS), internal gaps >=250 ms.
|
|
183
|
-
Excludes leading/trailing silence; requires >=2 s audio and >=1 s active span.
|
|
184
|
-
Noise may inflate the value and intentional pauses may lower it; this is not VAD/native fluency.
|
|
185
|
-
- Prosody has no score. Pitch P90-P10 and standard deviation (semitones) are reported
|
|
186
|
-
with >=20 voiced frames and >=2 s audio. Variation does not imply correct intonation.
|
|
187
|
-
- Overall pronunciation and content scores remain null: no calibrated composite,
|
|
188
|
-
stress model, transcript/grammar evaluator or topic evaluator is configured.
|
|
189
|
-
|
|
190
|
-
errors counts phoneme matches/substitutions/omissions/insertions. signal.pauses are
|
|
191
|
-
acoustic intervals, not linguistic unexpected/missing breaks. Consult limitations
|
|
192
|
-
and version=local-diagnostics-v1 before interpreting estimates.
|
|
226
|
+
```json
|
|
227
|
+
{"overall":{"score":50,"status":"estimated","method":"accuracy_completeness_hmean: 2*A*C/(A+C); zero if A+C=0","reason":null,"version":"local-accuracy-completeness-v1","scale":100,"calibrated":false,"components":["accuracy","completeness"],"excluded_components":["fluency","prosody"]}}
|
|
228
|
+
```
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hoanghong/speaking-angular",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Angular 18 SDK for speech transcription, audio upload and versioned local pronunciation assessment with typed overall and component scores.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"peerDependencies": {
|
|
7
7
|
"@angular/common": ">=18 <19",
|
|
@@ -11,13 +11,19 @@
|
|
|
11
11
|
"sideEffects": false,
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@hoanghong/speaking-core": "^0.
|
|
14
|
+
"@hoanghong/speaking-core": "^0.6.0",
|
|
15
15
|
"tslib": "^2.3.0"
|
|
16
16
|
},
|
|
17
17
|
"publishConfig": {
|
|
18
18
|
"access": "public",
|
|
19
19
|
"registry": "https://registry.npmjs.org/"
|
|
20
20
|
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"speech",
|
|
23
|
+
"pronunciation-assessment",
|
|
24
|
+
"speech-to-text",
|
|
25
|
+
"sdk"
|
|
26
|
+
],
|
|
21
27
|
"module": "fesm2022/hoanghong-speaking-angular.mjs",
|
|
22
28
|
"typings": "index.d.ts",
|
|
23
29
|
"exports": {
|