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.
package/README.org ADDED
@@ -0,0 +1,92 @@
1
+ #+TITLE: SpeechState
2
+
3
+ * SDK
4
+
5
+ ** Spawn SpeechState
6
+ #+begin_src typescript
7
+ import { speechstate } from "speechstate";
8
+
9
+ // start with this action in your state chart
10
+ assign({
11
+ spstRef: ({ spawn }) => {
12
+ return spawn(speechstate, {
13
+ input: {
14
+ settings: ...
15
+ },
16
+ });
17
+ },
18
+ }),
19
+ #+end_src
20
+
21
+ #+begin_src typescript
22
+ interface AzureCredentials {
23
+ endpoint: string;
24
+ key: string;
25
+ }
26
+
27
+ interface Settings {
28
+ locale: string;
29
+ azureCredentials: string | AzureCredentials; // you can use proxy URL or full credentials
30
+ asrDefaultCompleteTimeout: number;
31
+ }
32
+ #+end_src
33
+
34
+
35
+ ** Events
36
+ Example action:
37
+ #+begin_src typescript
38
+ ({ context }) =>
39
+ context.spstRef.send({
40
+ type: "SPEAK",
41
+ value: { utterance: "Hello world", voice: "en-GB-RyanNeural" },
42
+ });
43
+ #+end_src
44
+
45
+ *** DM to SpeechState
46
+ - ~{ type: "PREPARE" }~
47
+ - ~{ type: "SPEAK"; value: Agenda }~
48
+ - ~{ type: "LISTEN" }~
49
+ - ~{ type: "CONTROL" }~
50
+ - ~{ type: "STOP" }~
51
+
52
+
53
+ *** SpeechState to DM
54
+ - ~{ type: "ASRTTS_READY" }~
55
+ - ~{ type: "ASR_NOINPUT" }~
56
+ - ~{ type: "RECOGNISED"; value: Hypothesis[] }~
57
+ - ~{ type: "SPEAK_COMPLETE" }~
58
+ - ~{ type: "ASR_STARTED" }~
59
+ - ~{ type: "TTS_STARTED" }~
60
+ ** Types:
61
+ #+begin_src typescript
62
+ interface Hypothesis {
63
+ utterance: string;
64
+ confidence: number;
65
+ }
66
+
67
+ interface Agenda {
68
+ utterance: string;
69
+ voice?: string; // defaults to "en-US-DavisNeural"
70
+ streamURL?: string;
71
+ }
72
+ #+end_src
73
+
74
+
75
+ * How to run ~SpeechState~
76
+ ** Create Azure account and enable speech services
77
+ 1. Apply for free student credits
78
+ https://azure.microsoft.com/en-us/free/students/. You should be
79
+ able to login with your GU account.
80
+ 2. Make sure that you are logged into the Azure portal (https://portal.azure.com/).
81
+ 3. Create a *Resource group* (you can use search field):
82
+ - Subscription: *Azure for students*
83
+ - Resource group: any name
84
+ - Region: *(Europe) North Europe*
85
+ 4. Create a *Speech service*:
86
+ - Name: any name
87
+ - Subscription: *Azure for students*
88
+ - Location: *(Europe) North Europe*
89
+ - Pricing tier: *Free (F0)*
90
+ - Resource group: group name from the previous step
91
+ 5. Within your Speech Service go to: *Resourse management → Keys and
92
+ Endpoint* and copy your KEY 1.
package/dist/asr.d.ts ADDED
@@ -0,0 +1,54 @@
1
+ /// <reference types="webspeechapi" />
2
+ import { RecogniseParameters, Hypothesis, AzureCredentials } from "./types";
3
+ interface MySpeechRecognition extends SpeechRecognition {
4
+ new (): any;
5
+ }
6
+ interface MySpeechGrammarList extends SpeechGrammarList {
7
+ new (): any;
8
+ }
9
+ type ASREvent = {
10
+ type: "READY";
11
+ value: {
12
+ wsaASR: MySpeechRecognition;
13
+ wsaGrammarList: MySpeechGrammarList;
14
+ };
15
+ } | {
16
+ type: "ERROR";
17
+ } | {
18
+ type: "NOINPUT";
19
+ } | {
20
+ type: "CONTROL";
21
+ } | {
22
+ type: "START";
23
+ value?: RecogniseParameters;
24
+ } | {
25
+ type: "STARTED";
26
+ value: {
27
+ wsaASRinstance: MySpeechRecognition;
28
+ };
29
+ } | {
30
+ type: "STARTSPEECH";
31
+ } | {
32
+ type: "RECOGNISED";
33
+ } | {
34
+ type: "RESULT";
35
+ value: Hypothesis[];
36
+ };
37
+ interface ASRContext extends ASRInit {
38
+ azureAuthorizationToken?: string;
39
+ wsaASR?: MySpeechRecognition;
40
+ wsaASRinstance?: MySpeechRecognition;
41
+ wsaGrammarList?: MySpeechGrammarList;
42
+ result?: Hypothesis[];
43
+ params?: RecogniseParameters;
44
+ }
45
+ interface ASRInit {
46
+ asrDefaultCompleteTimeout: number;
47
+ asrDefaultNoInputTimeout: number;
48
+ locale: string;
49
+ audioContext: AudioContext;
50
+ azureCredentials: string | AzureCredentials;
51
+ }
52
+ export declare const asrMachine: import("xstate").StateMachine<ASRContext, ASREvent, Record<string, import("xstate").AnyActorRef>, import("xstate").ProvidedActor, import("xstate").ParameterizedObject, import("xstate").ParameterizedObject, string, import("xstate").StateValue, string, ASRInit, {}, import("xstate").ResolveTypegenMeta<import("xstate").TypegenDisabled, ASREvent, import("xstate").ProvidedActor, import("xstate").ParameterizedObject, import("xstate").ParameterizedObject, string, string>>;
53
+ export {};
54
+ //# sourceMappingURL=asr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asr.d.ts","sourceRoot":"","sources":["../src/asr.ts"],"names":[],"mappings":";AAaA,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC5E,UAAU,mBAAoB,SAAQ,iBAAiB;IACrD,YAAO;CACR;AAED,UAAU,mBAAoB,SAAQ,iBAAiB;IACrD,YAAO;CACR;AAED,KAAK,QAAQ,GACT;IACE,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE;QACL,MAAM,EAAE,mBAAmB,CAAC;QAC5B,cAAc,EAAE,mBAAmB,CAAC;KACrC,CAAC;CACH,GACD;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IACE,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,mBAAmB,CAAC;CAC7B,GACD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE;QAAE,cAAc,EAAE,mBAAmB,CAAA;KAAE,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC;AAE5C,UAAU,UAAW,SAAQ,OAAO;IAClC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC9B;AAED,UAAU,OAAO;IACf,yBAAyB,EAAE,MAAM,CAAC;IAClC,wBAAwB,EAAE,MAAM,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,YAAY,CAAC;IAC3B,gBAAgB,EAAE,MAAM,GAAG,gBAAgB,CAAC;CAC7C;AAED,eAAO,MAAM,UAAU,sdAyQtB,CAAC"}
package/dist/asr.js ADDED
@@ -0,0 +1,247 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.asrMachine = void 0;
4
+ const xstate_1 = require("xstate");
5
+ const getToken_1 = require("./getToken");
6
+ const SpeechToText_1 = require("web-speech-cognitive-services/lib/SpeechServices/SpeechToText");
7
+ const REGION = "northeurope";
8
+ exports.asrMachine = (0, xstate_1.createMachine)({
9
+ id: "asr",
10
+ types: {},
11
+ context: ({ input }) => ({
12
+ asrDefaultCompleteTimeout: input.asrDefaultCompleteTimeout || 0,
13
+ asrDefaultNoInputTimeout: input.asrDefaultNoInputTimeout || 5000,
14
+ locale: input.locale || "en-US",
15
+ audioContext: input.audioContext,
16
+ azureCredentials: input.azureCredentials,
17
+ }),
18
+ initial: "GetToken",
19
+ on: {
20
+ READY: {
21
+ target: ".Ready",
22
+ actions: [
23
+ (0, xstate_1.assign)({
24
+ wsaASR: ({ event }) => event.value.wsaASR,
25
+ wsaGrammarList: ({ event }) => event.value.wsaGrammarList,
26
+ }),
27
+ (0, xstate_1.sendParent)({ type: "ASR_READY" }),
28
+ ],
29
+ },
30
+ },
31
+ states: {
32
+ Fail: {},
33
+ Ready: {
34
+ on: {
35
+ START: {
36
+ target: "Recognising",
37
+ actions: (0, xstate_1.assign)({ params: ({ event }) => event.value }),
38
+ },
39
+ },
40
+ },
41
+ Recognising: {
42
+ initial: "WaitForRecogniser",
43
+ invoke: {
44
+ id: "recStart",
45
+ input: ({ context }) => ({
46
+ wsaASR: context.wsaASR,
47
+ wsaGrammarList: context.wsaGrammarList,
48
+ locale: context.locale,
49
+ phrases: (context.params || {}).hints || [],
50
+ }),
51
+ src: "recStart",
52
+ },
53
+ exit: "recStop",
54
+ on: {
55
+ RESULT: {
56
+ actions: [
57
+ (0, xstate_1.assign)({
58
+ result: ({ event }) => event.value,
59
+ }),
60
+ (0, xstate_1.cancel)("completeTimeout"),
61
+ ],
62
+ target: ".Match",
63
+ },
64
+ RECOGNISED: {
65
+ target: "Ready",
66
+ actions: [
67
+ (0, xstate_1.sendParent)(({ context }) => ({
68
+ type: "RECOGNISED",
69
+ value: context.result,
70
+ })),
71
+ ],
72
+ },
73
+ CONTROL: {
74
+ target: "Pause",
75
+ },
76
+ NOINPUT: {
77
+ actions: (0, xstate_1.sendParent)({ type: "ASR_NOINPUT" }),
78
+ target: "Ready",
79
+ },
80
+ },
81
+ states: {
82
+ WaitForRecogniser: {
83
+ on: {
84
+ STARTED: {
85
+ target: "NoInput",
86
+ actions: [
87
+ (0, xstate_1.assign)({
88
+ wsaASRinstance: ({ event }) => event.value.wsaASRinstance,
89
+ }),
90
+ (0, xstate_1.sendParent)({ type: "ASR_STARTED" }),
91
+ ],
92
+ },
93
+ },
94
+ },
95
+ NoInput: {
96
+ entry: [
97
+ (0, xstate_1.raise)({ type: "NOINPUT" }, {
98
+ delay: ({ context }) => (context.params || {}).noInputTimeout ||
99
+ context.asrDefaultNoInputTimeout,
100
+ id: "timeout",
101
+ }),
102
+ ],
103
+ on: {
104
+ STARTSPEECH: {
105
+ target: "InProgress",
106
+ actions: (0, xstate_1.cancel)("completeTimeout"),
107
+ },
108
+ },
109
+ exit: [(0, xstate_1.cancel)("timeout")],
110
+ },
111
+ InProgress: {
112
+ entry: () => console.debug("[ASR] in progress"),
113
+ },
114
+ Match: {
115
+ entry: [
116
+ ({ context }) => console.debug("RECOGNISED will be sent in (ms)", (context.params || {}).completeTimeout ||
117
+ context.asrDefaultCompleteTimeout),
118
+ (0, xstate_1.raise)({ type: "RECOGNISED" }, {
119
+ delay: ({ context }) => (context.params || {}).completeTimeout ||
120
+ context.asrDefaultCompleteTimeout,
121
+ id: "completeTimeout",
122
+ }),
123
+ ],
124
+ },
125
+ },
126
+ },
127
+ Pause: {
128
+ entry: (0, xstate_1.sendParent)({ type: "ASR_PAUSED" }),
129
+ on: {
130
+ CONTROL: {
131
+ target: "Recognising",
132
+ // ///// todo? reset noInputTimeout
133
+ // // actions: assign({
134
+ // // params: {
135
+ // // noInputTimeout: ({ context }) =>
136
+ // // context.asrDefaultNoInputTimeout,
137
+ // // completeTimeout: 0,
138
+ // // locale: "0",
139
+ // // hints: [""],
140
+ // // },
141
+ // // }),} },
142
+ },
143
+ },
144
+ },
145
+ GetToken: {
146
+ invoke: {
147
+ id: "getAuthorizationToken",
148
+ input: ({ context }) => ({
149
+ credentials: context.azureCredentials,
150
+ }),
151
+ src: "getToken",
152
+ onDone: {
153
+ target: "Ponyfill",
154
+ actions: [
155
+ (0, xstate_1.assign)(({ event }) => {
156
+ return { azureAuthorizationToken: event.output };
157
+ }),
158
+ ],
159
+ },
160
+ onError: {
161
+ target: "Fail",
162
+ },
163
+ },
164
+ },
165
+ Ponyfill: {
166
+ invoke: {
167
+ id: "ponyASR",
168
+ src: "ponyfill",
169
+ input: ({ context }) => ({
170
+ audioContext: context.audioContext,
171
+ azureAuthorizationToken: context.azureAuthorizationToken,
172
+ locale: context.locale,
173
+ }),
174
+ },
175
+ },
176
+ },
177
+ }, {
178
+ actions: {
179
+ recStop: ({ context }) => {
180
+ context.wsaASRinstance.abort();
181
+ console.debug("[ASR] stopped");
182
+ },
183
+ },
184
+ actors: {
185
+ getToken: getToken_1.getToken,
186
+ ponyfill: (0, xstate_1.fromCallback)(({ sendBack, input }) => {
187
+ const { SpeechGrammarList, SpeechRecognition } = (0, SpeechToText_1.default)({
188
+ audioContext: input.audioContext,
189
+ credentials: {
190
+ region: REGION,
191
+ authorizationToken: input.azureAuthorizationToken,
192
+ },
193
+ });
194
+ sendBack({
195
+ type: "READY",
196
+ value: {
197
+ wsaASR: SpeechRecognition,
198
+ wsaGrammarList: SpeechGrammarList,
199
+ },
200
+ });
201
+ console.debug("[ASR] READY");
202
+ }),
203
+ recStart: (0, xstate_1.fromCallback)(({ sendBack, input }) => {
204
+ let asr = new input.wsaASR();
205
+ asr.grammars = new input.wsaGrammarList();
206
+ asr.grammars.phrases = input.phrases || [];
207
+ asr.lang = input.locale;
208
+ asr.continuous = true;
209
+ asr.interimResults = true;
210
+ asr.onresult = function (event) {
211
+ if (event.results[event.results.length - 1].isFinal) {
212
+ const transcript = event.results
213
+ .map((x) => x[0].transcript.replace(/\.$/, ""))
214
+ .join(" ");
215
+ const confidence = event.results
216
+ .map((x) => x[0].confidence)
217
+ .reduce((a, b) => a + b) /
218
+ event.results.length;
219
+ const res = [
220
+ {
221
+ utterance: transcript,
222
+ confidence: confidence,
223
+ },
224
+ ];
225
+ sendBack({
226
+ type: "RESULT",
227
+ value: res,
228
+ });
229
+ console.debug("[ASR] RESULT (pre-final)", res);
230
+ }
231
+ else {
232
+ sendBack({ type: "STARTSPEECH" });
233
+ }
234
+ };
235
+ asr.addEventListener("start", () => {
236
+ sendBack({ type: "STARTED", value: { wsaASRinstance: asr } });
237
+ });
238
+ // receive((event) => {
239
+ // console.debug("bla");
240
+ // if (event.type === "STOP") {
241
+ // asr.abort();
242
+ // }
243
+ // });
244
+ asr.start();
245
+ }),
246
+ },
247
+ });
@@ -0,0 +1,2 @@
1
+ export declare const getToken: import("xstate").PromiseActorLogic<string, any>;
2
+ //# sourceMappingURL=getToken.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getToken.d.ts","sourceRoot":"","sources":["../src/getToken.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,QAAQ,iDAanB,CAAC"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getToken = void 0;
13
+ const xstate_1 = require("xstate");
14
+ exports.getToken = (0, xstate_1.fromPromise)(({ input }) => __awaiter(void 0, void 0, void 0, function* () {
15
+ if (typeof input.credentials === "string") {
16
+ return fetch(new Request(input.credentials)).then((data) => data.text());
17
+ }
18
+ else {
19
+ return fetch(new Request(input.credentials.endpoint, {
20
+ method: "POST",
21
+ headers: {
22
+ "Ocp-Apim-Subscription-Key": input.credentials.key,
23
+ },
24
+ })).then((data) => data.text());
25
+ }
26
+ }));
@@ -0,0 +1,3 @@
1
+ export { speechstate } from "./speechstate";
2
+ export { AzureCredentials, Settings, Hypothesis, Agenda, RecogniseParameters, } from "./types";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EACL,gBAAgB,EAChB,QAAQ,EACR,UAAU,EACV,MAAM,EACN,mBAAmB,GACpB,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.speechstate = void 0;
4
+ var speechstate_1 = require("./speechstate");
5
+ Object.defineProperty(exports, "speechstate", { enumerable: true, get: function () { return speechstate_1.speechstate; } });
@@ -0,0 +1,39 @@
1
+ import { Settings, Agenda, Hypothesis } from "./types";
2
+ interface SSContext {
3
+ settings: Settings;
4
+ audioContext?: AudioContext;
5
+ asrRef?: any;
6
+ ttsRef?: any;
7
+ }
8
+ type SSEvent = {
9
+ type: "PREPARE";
10
+ } | {
11
+ type: "CONTROL";
12
+ } | {
13
+ type: "STOP";
14
+ } | {
15
+ type: "SPEAK";
16
+ value: Agenda;
17
+ } | {
18
+ type: "TTS_READY";
19
+ } | {
20
+ type: "TTS_STARTED";
21
+ } | {
22
+ type: "TTS_ERROR";
23
+ } | {
24
+ type: "SPEAK_COMPLETE";
25
+ } | {
26
+ type: "ASR_READY";
27
+ } | {
28
+ type: "LISTEN";
29
+ } | {
30
+ type: "ASR_STARTED";
31
+ } | {
32
+ type: "ASR_NOINPUT";
33
+ } | {
34
+ type: "RECOGNISED";
35
+ value: Hypothesis[];
36
+ };
37
+ declare const speechstate: import("xstate").StateMachine<SSContext, SSEvent, Record<string, import("xstate").AnyActorRef>, import("xstate").ProvidedActor, import("xstate").ParameterizedObject, import("xstate").ParameterizedObject, string, import("xstate").StateValue, string, Settings, {}, import("xstate").ResolveTypegenMeta<import("xstate").TypegenDisabled, SSEvent, import("xstate").ProvidedActor, import("xstate").ParameterizedObject, import("xstate").ParameterizedObject, string, string>>;
38
+ export { speechstate };
39
+ //# sourceMappingURL=speechstate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"speechstate.d.ts","sourceRoot":"","sources":["../src/speechstate.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACvD,UAAU,SAAS;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,MAAM,CAAC,EAAE,GAAG,CAAC;CACd;AAED,KAAK,OAAO,GACR;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC;AAEhD,QAAA,MAAM,WAAW,odAuPhB,CAAC;AAEF,OAAO,EAAE,WAAW,EAAE,CAAC"}