speechstate 2.0.0-beta.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.
@@ -0,0 +1,235 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.speechstate = void 0;
4
+ const xstate_1 = require("xstate");
5
+ const tts_1 = require("./tts");
6
+ const asr_1 = require("./asr");
7
+ const speechstate = (0, xstate_1.createMachine)({
8
+ types: {},
9
+ context: ({ input }) => ({
10
+ settings: input,
11
+ }),
12
+ id: "speechstate",
13
+ type: "parallel",
14
+ states: {
15
+ asrTtsSpawner: {
16
+ initial: "idle",
17
+ states: {
18
+ idle: { on: { PREPARE: "createAudioContext" } },
19
+ createAudioContext: {
20
+ invoke: {
21
+ id: "createAudioContext",
22
+ src: "audioContext",
23
+ onDone: {
24
+ target: "spawn",
25
+ actions: (0, xstate_1.assign)({ audioContext: ({ event }) => event.output }),
26
+ },
27
+ },
28
+ },
29
+ spawn: {
30
+ entry: [
31
+ (0, xstate_1.assign)({
32
+ ttsRef: ({ context, spawn }) => {
33
+ return spawn(tts_1.ttsMachine, {
34
+ input: {
35
+ ttsDefaultVoice: context.settings.ttsDefaultVoice,
36
+ audioContext: context.audioContext,
37
+ azureCredentials: context.settings.azureCredentials,
38
+ },
39
+ });
40
+ },
41
+ }),
42
+ (0, xstate_1.assign)({
43
+ asrRef: ({ context, spawn }) => {
44
+ return spawn(asr_1.asrMachine, {
45
+ input: {
46
+ asrDefaultCompleteTimeout: context.settings.asrDefaultCompleteTimeout,
47
+ asrDefaultNoInputTimeout: context.settings.asrDefaultNoInputTimeout,
48
+ locale: context.settings.locale,
49
+ audioContext: context.audioContext,
50
+ azureCredentials: context.settings.azureCredentials,
51
+ },
52
+ });
53
+ },
54
+ }),
55
+ ],
56
+ after: {
57
+ 300000: {
58
+ target: "spawn",
59
+ },
60
+ },
61
+ },
62
+ },
63
+ },
64
+ asrTtsManager: {
65
+ initial: "initialize",
66
+ on: {
67
+ TTS_READY: {
68
+ actions: () => console.debug("[TTS→SpSt] TTS_READY"),
69
+ target: ".preReady",
70
+ },
71
+ ASR_READY: {
72
+ actions: () => console.debug("[ASR→SpSt] ASR_READY"),
73
+ target: ".preReady",
74
+ },
75
+ // ASR_ERROR not implemented
76
+ TTS_ERROR: {
77
+ actions: () => console.error("[TTS→SpSt] TTS_ERROR"),
78
+ target: ".fail",
79
+ },
80
+ ASR_NOINPUT: {
81
+ actions: [
82
+ () => console.debug("[ASR→SpSt] NOINPUT"),
83
+ (0, xstate_1.sendParent)({ type: "ASR_NOINPUT" }),
84
+ ],
85
+ target: ".ready",
86
+ },
87
+ },
88
+ states: {
89
+ initialize: {},
90
+ preReady: {
91
+ on: {
92
+ TTS_READY: {
93
+ actions: () => console.debug("[TTS→SpSt] TTS_READY"),
94
+ target: "ready",
95
+ },
96
+ ASR_READY: {
97
+ actions: () => console.debug("[ASR→SpSt] ASR_READY"),
98
+ target: "ready",
99
+ },
100
+ },
101
+ },
102
+ ready: {
103
+ initial: "idle",
104
+ entry: [
105
+ () => console.debug("[SpSt] All ready"),
106
+ (0, xstate_1.sendParent)({ type: "ASRTTS_READY" }),
107
+ ],
108
+ states: {
109
+ idle: {
110
+ on: {
111
+ LISTEN: { target: "waitForRecogniser" },
112
+ SPEAK: [
113
+ {
114
+ target: "speaking",
115
+ },
116
+ ],
117
+ },
118
+ },
119
+ speaking: {
120
+ entry: [
121
+ ({ event }) => console.debug("[SpSt→TTS] SPEAK", event.value),
122
+ ({ context, event }) => context.ttsRef.send({
123
+ type: "SPEAK",
124
+ value: event.value,
125
+ }),
126
+ ],
127
+ on: {
128
+ CONTROL: {
129
+ actions: [
130
+ () => console.debug("[SpSt→TTS] CONTROL"),
131
+ ({ context }) => context.ttsRef.send({
132
+ type: "CONTROL",
133
+ }),
134
+ ],
135
+ },
136
+ STOP: {
137
+ actions: [
138
+ () => console.debug("[SpSt→TTS] STOP"),
139
+ ({ context }) => context.ttsRef.send({
140
+ type: "STOP",
141
+ }),
142
+ ],
143
+ },
144
+ TTS_STARTED: {
145
+ actions: [
146
+ () => console.debug("[TTS→SpSt] TTS_STARTED"),
147
+ (0, xstate_1.sendParent)({ type: "TTS_STARTED" }),
148
+ ],
149
+ },
150
+ SPEAK_COMPLETE: {
151
+ target: "idle",
152
+ actions: [
153
+ () => console.debug("[TTS→SpSt] SPEAK_COMPLETE"),
154
+ (0, xstate_1.sendParent)({ type: "SPEAK_COMPLETE" }),
155
+ ],
156
+ },
157
+ },
158
+ },
159
+ waitForRecogniser: {
160
+ entry: [
161
+ ({ event }) => console.debug("[SpSt→ASR] START", event.value),
162
+ ({ context, event }) => context.asrRef.send({
163
+ type: "START",
164
+ value: event.value,
165
+ }),
166
+ ],
167
+ on: {
168
+ ASR_STARTED: {
169
+ target: "recognising",
170
+ actions: [
171
+ () => console.debug("[ASR→SpSt] ASR_STARTED"),
172
+ (0, xstate_1.sendParent)({ type: "ASR_STARTED" }),
173
+ ],
174
+ },
175
+ },
176
+ },
177
+ recognising: {
178
+ on: {
179
+ CONTROL: {
180
+ actions: [
181
+ () => console.debug("[SpSt→ASR] CONTROL"),
182
+ ({ context }) => context.asrRef.send({
183
+ type: "CONTROL",
184
+ }),
185
+ ],
186
+ },
187
+ RECOGNISED: {
188
+ actions: [
189
+ ({ event }) => console.debug("[ASR→SpSt] RECOGNISED", event.value),
190
+ (0, xstate_1.sendParent)(({ event }) => ({
191
+ type: "RECOGNISED",
192
+ value: event.value,
193
+ })),
194
+ ],
195
+ target: "idle",
196
+ },
197
+ },
198
+ },
199
+ },
200
+ },
201
+ fail: {},
202
+ },
203
+ },
204
+ },
205
+ }, {
206
+ actors: {
207
+ audioContext: (0, xstate_1.fromPromise)(() => {
208
+ const audioContext = new (window.AudioContext ||
209
+ window.webkitAudioContext)();
210
+ navigator.mediaDevices
211
+ .getUserMedia({ audio: true })
212
+ .then(function (stream) {
213
+ audioContext.createMediaStreamSource(stream);
214
+ });
215
+ return audioContext;
216
+ }),
217
+ },
218
+ actions: {
219
+ // logRecResult: ({ event }) => {
220
+ // console.log("U>", (event as any).value[0]["utterance"], {
221
+ // confidence: (event as any).value[0]["confidence"],
222
+ // });
223
+ // },
224
+ // logAgenda: ({ context, event }) => {
225
+ // console.log("S>", (event as any).value, {
226
+ // passivity: `${context.tdmPassivity ?? "∞"} ms`,
227
+ // speechCompleteTimeout: `${
228
+ // context.tdmSpeechCompleteTimeout ||
229
+ // context.settings.completeTimeout
230
+ // } ms`,
231
+ // });
232
+ // },
233
+ },
234
+ });
235
+ exports.speechstate = speechstate;
package/dist/tts.d.ts ADDED
@@ -0,0 +1,42 @@
1
+ import { AzureCredentials, Agenda } from "./types";
2
+ interface MySpeechSynthesisUtterance extends SpeechSynthesisUtterance {
3
+ new (s: string): any;
4
+ }
5
+ interface TTSInit {
6
+ audioContext: AudioContext;
7
+ azureCredentials: string | AzureCredentials;
8
+ ttsDefaultVoice: string;
9
+ }
10
+ interface TTSContext extends TTSInit {
11
+ azureAuthorizationToken?: string;
12
+ ttsLexicon?: string;
13
+ wsaTTS?: SpeechSynthesis;
14
+ wsaVoice?: SpeechSynthesisVoice;
15
+ wsaUtt?: MySpeechSynthesisUtterance;
16
+ agenda?: Agenda;
17
+ }
18
+ type TTSEvent = {
19
+ type: "PREPARE";
20
+ } | {
21
+ type: "CONTROL";
22
+ } | {
23
+ type: "STOP";
24
+ } | {
25
+ type: "READY";
26
+ value: {
27
+ wsaTTS: SpeechSynthesis;
28
+ wsaUtt: MySpeechSynthesisUtterance;
29
+ };
30
+ } | {
31
+ type: "ERROR";
32
+ } | {
33
+ type: "SPEAK";
34
+ value: Agenda;
35
+ } | {
36
+ type: "TTS_STARTED";
37
+ } | {
38
+ type: "SPEAK_COMPLETE";
39
+ };
40
+ export declare const ttsMachine: import("xstate").StateMachine<TTSContext, TTSEvent, Record<string, import("xstate").AnyActorRef>, import("xstate").ProvidedActor, import("xstate").ParameterizedObject, import("xstate").ParameterizedObject, string, import("xstate").StateValue, string, TTSInit, {}, import("xstate").ResolveTypegenMeta<import("xstate").TypegenDisabled, TTSEvent, import("xstate").ProvidedActor, import("xstate").ParameterizedObject, import("xstate").ParameterizedObject, string, string>>;
41
+ export {};
42
+ //# sourceMappingURL=tts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tts.d.ts","sourceRoot":"","sources":["../src/tts.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEnD,UAAU,0BAA2B,SAAQ,wBAAwB;IACnE,KAAK,CAAC,EAAE,MAAM,OAAE;CACjB;AAED,UAAU,OAAO;IACf,YAAY,EAAE,YAAY,CAAC;IAC3B,gBAAgB,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC5C,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,UAAW,SAAQ,OAAO;IAClC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,MAAM,CAAC,EAAE,0BAA0B,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,KAAK,QAAQ,GACT;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IACE,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE;QACL,MAAM,EAAE,eAAe,CAAC;QACxB,MAAM,EAAE,0BAA0B,CAAC;KACpC,CAAC;CACH,GACD;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAE/B,eAAO,MAAM,UAAU,sdA+KtB,CAAC"}
package/dist/tts.js ADDED
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ttsMachine = void 0;
4
+ const xstate_1 = require("xstate");
5
+ const getToken_1 = require("./getToken");
6
+ const TextToSpeech_1 = require("web-speech-cognitive-services/lib/SpeechServices/TextToSpeech");
7
+ const REGION = "northeurope";
8
+ exports.ttsMachine = (0, xstate_1.createMachine)({
9
+ id: "tts",
10
+ types: {},
11
+ context: ({ input }) => ({
12
+ ttsDefaultVoice: input.ttsDefaultVoice || "en-US-DavisNeural",
13
+ audioContext: input.audioContext,
14
+ azureCredentials: input.azureCredentials,
15
+ }),
16
+ initial: "GetToken",
17
+ on: {
18
+ READY: {
19
+ target: ".Ready",
20
+ actions: [
21
+ (0, xstate_1.assign)({
22
+ wsaTTS: ({ event }) => event.value.wsaTTS,
23
+ wsaUtt: ({ event }) => event.value.wsaUtt,
24
+ }),
25
+ (0, xstate_1.sendParent)({ type: "TTS_READY" }),
26
+ ],
27
+ },
28
+ ERROR: { actions: (0, xstate_1.sendParent)({ type: "TTS_ERROR" }) },
29
+ },
30
+ states: {
31
+ Ready: {
32
+ initial: "Idle",
33
+ states: {
34
+ Idle: {
35
+ on: {
36
+ SPEAK: {
37
+ target: "Speaking",
38
+ actions: (0, xstate_1.assign)({ agenda: ({ event }) => event.value }),
39
+ },
40
+ },
41
+ },
42
+ Speaking: {
43
+ initial: "Go",
44
+ on: {
45
+ STOP: {
46
+ target: "Idle",
47
+ },
48
+ TTS_STARTED: {
49
+ actions: (0, xstate_1.sendParent)({ type: "TTS_STARTED" }),
50
+ },
51
+ SPEAK_COMPLETE: {
52
+ target: "Idle",
53
+ },
54
+ },
55
+ exit: (0, xstate_1.sendParent)({ type: "SPEAK_COMPLETE" }),
56
+ states: {
57
+ Go: {
58
+ invoke: {
59
+ src: "start",
60
+ input: ({ context }) => ({
61
+ wsaTTS: context.wsaTTS,
62
+ wsaUtt: context.wsaUtt,
63
+ ttsLexicon: context.ttsLexicon,
64
+ voice: context.agenda.voice || context.ttsDefaultVoice,
65
+ // streamURL: context.agenda.streamURL,
66
+ utterance: context.agenda.utterance,
67
+ }),
68
+ },
69
+ on: {
70
+ CONTROL: "Paused",
71
+ },
72
+ exit: "ttsStop",
73
+ },
74
+ Paused: {
75
+ on: {
76
+ CONTROL: "Go",
77
+ },
78
+ },
79
+ },
80
+ },
81
+ },
82
+ },
83
+ Fail: {},
84
+ GetToken: {
85
+ invoke: {
86
+ id: "getAuthorizationToken",
87
+ input: ({ context }) => ({
88
+ credentials: context.azureCredentials,
89
+ }),
90
+ src: "getToken",
91
+ onDone: {
92
+ target: "Ponyfill",
93
+ actions: [
94
+ (0, xstate_1.assign)(({ event }) => {
95
+ return { azureAuthorizationToken: event.output };
96
+ }),
97
+ ],
98
+ },
99
+ onError: {
100
+ actions: ({ event }) => console.error("[TTS] getToken error", event),
101
+ target: "Fail",
102
+ },
103
+ },
104
+ },
105
+ Ponyfill: {
106
+ invoke: {
107
+ id: "ponyTTS",
108
+ src: "ponyfill",
109
+ input: ({ context }) => ({
110
+ audioContext: context.audioContext,
111
+ azureAuthorizationToken: context.azureAuthorizationToken,
112
+ }),
113
+ },
114
+ },
115
+ },
116
+ }, {
117
+ actions: {
118
+ ttsStop: ({ context }) => {
119
+ context.wsaTTS.cancel();
120
+ },
121
+ },
122
+ actors: {
123
+ getToken: getToken_1.getToken,
124
+ ponyfill: (0, xstate_1.fromCallback)(({ sendBack, input }) => {
125
+ const ponyfill = (0, TextToSpeech_1.default)({
126
+ audioContext: input.audioContext,
127
+ credentials: {
128
+ region: REGION,
129
+ authorizationToken: input.azureAuthorizationToken,
130
+ },
131
+ });
132
+ const { speechSynthesis, SpeechSynthesisUtterance } = ponyfill;
133
+ const tts = speechSynthesis;
134
+ const ttsUtterance = SpeechSynthesisUtterance;
135
+ tts.addEventListener("voiceschanged", () => {
136
+ const voices = tts.getVoices();
137
+ if (voices.length > 0) {
138
+ console.debug("[TTS] READY");
139
+ sendBack({
140
+ type: "READY",
141
+ value: { wsaTTS: tts, wsaUtt: ttsUtterance },
142
+ });
143
+ }
144
+ else {
145
+ console.error("[TTS] No voices available");
146
+ sendBack({ type: "ERROR" });
147
+ }
148
+ });
149
+ }),
150
+ start: (0, xstate_1.fromCallback)(({ sendBack, input }) => {
151
+ if (["", " "].includes(input.utterance)) {
152
+ console.debug("[TTS] SPEAK: ", input.utterance);
153
+ input.wsaTTS.speak("");
154
+ }
155
+ else {
156
+ console.debug("[TTS] SPEAK: ", input.utterance);
157
+ const content = wrapSSML(input.utterance, input.voice, input.ttsLexicon, 1); // todo speech rate;
158
+ const utterance = new input.wsaUtt(content);
159
+ utterance.addEventListener("start", () => {
160
+ sendBack({ type: "TTS_STARTED" });
161
+ console.debug("[TTS] TTS_STARTED");
162
+ });
163
+ utterance.addEventListener("end", () => {
164
+ sendBack({ type: "SPEAK_COMPLETE" });
165
+ console.debug("[TTS] SPEAK_COMPLETE");
166
+ });
167
+ input.wsaTTS.speak(utterance);
168
+ }
169
+ }),
170
+ },
171
+ });
172
+ const wrapSSML = (text, voice, lexicon, speechRate) => {
173
+ let content = `<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xml:lang="en-US"><voice name="${voice}">`;
174
+ if (lexicon) {
175
+ content = content + `<lexicon uri="${lexicon}"/>`;
176
+ }
177
+ content =
178
+ content +
179
+ `<prosody rate="${speechRate}">` +
180
+ `${text}</prosody></voice></speak>`;
181
+ return content;
182
+ };
@@ -0,0 +1,27 @@
1
+ export interface AzureCredentials {
2
+ endpoint: string;
3
+ key: string;
4
+ }
5
+ export interface Settings {
6
+ locale: string;
7
+ azureCredentials: string | AzureCredentials;
8
+ asrDefaultCompleteTimeout: number;
9
+ asrDefaultNoInputTimeout: number;
10
+ ttsDefaultVoice: string;
11
+ }
12
+ export interface Agenda {
13
+ utterance: string;
14
+ voice?: string;
15
+ stream?: ReadableStream<string>;
16
+ }
17
+ export interface Hypothesis {
18
+ utterance: string;
19
+ confidence: number;
20
+ }
21
+ export interface RecogniseParameters {
22
+ noInputTimeout?: number;
23
+ completeTimeout?: number;
24
+ locale?: string;
25
+ hints?: string[];
26
+ }
27
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,GAAG,gBAAgB,CAAC;IAC5C,yBAAyB,EAAE,MAAM,CAAC;IAClC,wBAAwB,EAAE,MAAM,CAAC;IACjC,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,MAAM;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "speechstate",
3
+ "version": "2.0.0-beta.0",
4
+ "license": "GPL-3.0",
5
+ "homepage": "http://localhost/speechstate",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": ["/dist"],
9
+ "dependencies": {
10
+ "microsoft-cognitiveservices-speech-sdk": "^1.31.0",
11
+ "web-speech-cognitive-services": "^7.1.2",
12
+ "xstate": "^5.5.1"
13
+ },
14
+ "scripts": {
15
+ "dev": "vite",
16
+ "test": "jest --silent=false"
17
+ },
18
+ "eslintConfig": {
19
+ "extends": ["react-app", "react-app/jest"]
20
+ },
21
+ "browserslist": {
22
+ "production": [">0.2%", "not dead", "not op_mini all"],
23
+ "development": [
24
+ "last 1 chrome version",
25
+ "last 1 firefox version",
26
+ "last 1 safari version"
27
+ ]
28
+ },
29
+ "devDependencies": {
30
+ "@mermaid-js/mermaid-cli": "^10.6.1",
31
+ "@parcel/transformer-typescript-types": "2.9.3",
32
+ "@types/jest": "^29.5.2",
33
+ "@types/webspeechapi": "^0.0.29",
34
+ "buffer": "^5.5.0||^6.0.0",
35
+ "jest": "^29.5.0",
36
+ "jest-environment-jsdom": "^29.5.0",
37
+ "parcel-reporter-static-files-copy": "^1.5.2",
38
+ "process": "^0.11.10",
39
+ "ts-jest": "^29.1.0",
40
+ "typescript": "^5.0.4",
41
+ "vite": "^5.0.11"
42
+ },
43
+ "packageManager": "yarn@3.6.4",
44
+ "description": "* SDK",
45
+ "directories": {
46
+ "doc": "docs",
47
+ "test": "test"
48
+ },
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+ssh://git@github.com/vladmaraev/speechstate.git"
52
+ },
53
+ "author": "Vlad Maraev",
54
+ "bugs": {
55
+ "url": "https://github.com/vladmaraev/speechstate/issues"
56
+ }
57
+ }