@codingame/monaco-vscode-speech-service-override 3.2.3 → 4.0.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codingame/monaco-vscode-speech-service-override",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"keywords": [],
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "CodinGame",
|
|
@@ -18,6 +18,6 @@
|
|
|
18
18
|
"module": "index.js",
|
|
19
19
|
"types": "index.d.ts",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"vscode": "npm:@codingame/monaco-vscode-api@
|
|
21
|
+
"vscode": "npm:@codingame/monaco-vscode-api@4.0.0"
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
|
|
2
|
+
import { localizeWithPath } from 'vscode/vscode/vs/nls';
|
|
2
3
|
import { firstOrDefault } from 'vscode/vscode/vs/base/common/arrays';
|
|
3
4
|
import { CancellationTokenSource } from 'vscode/vscode/vs/base/common/cancellation';
|
|
4
5
|
import { Emitter, Event } from 'vscode/vscode/vs/base/common/event';
|
|
@@ -7,24 +8,63 @@ import { IContextKeyService } from 'vscode/vscode/vs/platform/contextkey/common/
|
|
|
7
8
|
import { ILogService } from 'vscode/vscode/vs/platform/log/common/log';
|
|
8
9
|
import { IHostService } from 'vscode/vscode/vs/workbench/services/host/browser/host';
|
|
9
10
|
import { DeferredPromise } from 'vscode/vscode/vs/base/common/async';
|
|
10
|
-
import { HasSpeechProvider, SpeechToTextInProgress, SpeechToTextStatus, KeywordRecognitionStatus } from 'vscode/vscode/vs/workbench/contrib/speech/common/speechService';
|
|
11
|
+
import { HasSpeechProvider, SpeechToTextInProgress, speechLanguageConfigToLanguage, SPEECH_LANGUAGE_CONFIG, SpeechToTextStatus, KeywordRecognitionStatus } from 'vscode/vscode/vs/workbench/contrib/speech/common/speechService';
|
|
11
12
|
import { ITelemetryService } from 'vscode/vscode/vs/platform/telemetry/common/telemetry';
|
|
12
13
|
import { IConfigurationService } from 'vscode/vscode/vs/platform/configuration/common/configuration';
|
|
14
|
+
import { AccessibilitySignal, IAccessibilitySignalService } from 'vscode/vscode/vs/platform/accessibilitySignal/browser/accessibilitySignalService';
|
|
15
|
+
import { ExtensionsRegistry } from 'vscode/vscode/vs/workbench/services/extensions/common/extensionsRegistry';
|
|
16
|
+
import { IExtensionService } from 'vscode/vscode/vs/workbench/services/extensions/common/extensions';
|
|
13
17
|
|
|
18
|
+
const speechProvidersExtensionPoint = ExtensionsRegistry.registerExtensionPoint({
|
|
19
|
+
extensionPoint: 'speechProviders',
|
|
20
|
+
jsonSchema: {
|
|
21
|
+
description: ( localizeWithPath(
|
|
22
|
+
'vs/workbench/contrib/speech/browser/speechService',
|
|
23
|
+
'vscode.extension.contributes.speechProvider',
|
|
24
|
+
'Contributes a Speech Provider'
|
|
25
|
+
)),
|
|
26
|
+
type: 'array',
|
|
27
|
+
items: {
|
|
28
|
+
additionalProperties: false,
|
|
29
|
+
type: 'object',
|
|
30
|
+
defaultSnippets: [{ body: { name: '', description: '' } }],
|
|
31
|
+
required: ['name'],
|
|
32
|
+
properties: {
|
|
33
|
+
name: {
|
|
34
|
+
description: ( localizeWithPath(
|
|
35
|
+
'vs/workbench/contrib/speech/browser/speechService',
|
|
36
|
+
'speechProviderName',
|
|
37
|
+
"Unique name for this Speech Provider."
|
|
38
|
+
)),
|
|
39
|
+
type: 'string'
|
|
40
|
+
},
|
|
41
|
+
description: {
|
|
42
|
+
description: ( localizeWithPath(
|
|
43
|
+
'vs/workbench/contrib/speech/browser/speechService',
|
|
44
|
+
'speechProviderDescription',
|
|
45
|
+
"A description of this Speech Provider, shown in the UI."
|
|
46
|
+
)),
|
|
47
|
+
type: 'string'
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
14
53
|
let SpeechService = class SpeechService extends Disposable {
|
|
15
|
-
get hasSpeechProvider() { return this.providers.size > 0; }
|
|
16
|
-
constructor(logService, contextKeyService, hostService, telemetryService, configurationService) {
|
|
54
|
+
get hasSpeechProvider() { return this.providerDescriptors.size > 0 || this.providers.size > 0; }
|
|
55
|
+
constructor(logService, contextKeyService, hostService, telemetryService, configurationService, accessibilitySignalService, extensionService) {
|
|
17
56
|
super();
|
|
18
57
|
this.logService = logService;
|
|
19
58
|
this.contextKeyService = contextKeyService;
|
|
20
59
|
this.hostService = hostService;
|
|
21
60
|
this.telemetryService = telemetryService;
|
|
22
61
|
this.configurationService = configurationService;
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
25
|
-
this.
|
|
26
|
-
this.
|
|
62
|
+
this.accessibilitySignalService = accessibilitySignalService;
|
|
63
|
+
this.extensionService = extensionService;
|
|
64
|
+
this._onDidChangeHasSpeechProvider = this._register(( new Emitter()));
|
|
65
|
+
this.onDidChangeHasSpeechProvider = this._onDidChangeHasSpeechProvider.event;
|
|
27
66
|
this.providers = ( new Map());
|
|
67
|
+
this.providerDescriptors = ( new Map());
|
|
28
68
|
this.hasSpeechProviderContext = HasSpeechProvider.bindTo(this.contextKeyService);
|
|
29
69
|
this._onDidStartSpeechToTextSession = this._register(( new Emitter()));
|
|
30
70
|
this.onDidStartSpeechToTextSession = this._onDidStartSpeechToTextSession.event;
|
|
@@ -37,45 +77,68 @@ let SpeechService = class SpeechService extends Disposable {
|
|
|
37
77
|
this._onDidEndKeywordRecognition = this._register(( new Emitter()));
|
|
38
78
|
this.onDidEndKeywordRecognition = this._onDidEndKeywordRecognition.event;
|
|
39
79
|
this._activeKeywordRecognitionSession = undefined;
|
|
80
|
+
this.handleAndRegisterSpeechExtensions();
|
|
81
|
+
}
|
|
82
|
+
handleAndRegisterSpeechExtensions() {
|
|
83
|
+
speechProvidersExtensionPoint.setHandler((extensions, delta) => {
|
|
84
|
+
const oldHasSpeechProvider = this.hasSpeechProvider;
|
|
85
|
+
for (const extension of delta.removed) {
|
|
86
|
+
for (const descriptor of extension.value) {
|
|
87
|
+
this.providerDescriptors.delete(descriptor.name);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
for (const extension of delta.added) {
|
|
91
|
+
for (const descriptor of extension.value) {
|
|
92
|
+
this.providerDescriptors.set(descriptor.name, descriptor);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (oldHasSpeechProvider !== this.hasSpeechProvider) {
|
|
96
|
+
this.handleHasSpeechProviderChange();
|
|
97
|
+
}
|
|
98
|
+
});
|
|
40
99
|
}
|
|
41
100
|
registerSpeechProvider(identifier, provider) {
|
|
42
101
|
if (( this.providers.has(identifier))) {
|
|
43
102
|
throw new Error(`Speech provider with identifier ${identifier} is already registered.`);
|
|
44
103
|
}
|
|
104
|
+
const oldHasSpeechProvider = this.hasSpeechProvider;
|
|
45
105
|
this.providers.set(identifier, provider);
|
|
46
|
-
this.
|
|
47
|
-
|
|
106
|
+
if (oldHasSpeechProvider !== this.hasSpeechProvider) {
|
|
107
|
+
this.handleHasSpeechProviderChange();
|
|
108
|
+
}
|
|
48
109
|
return toDisposable(() => {
|
|
110
|
+
const oldHasSpeechProvider = this.hasSpeechProvider;
|
|
49
111
|
this.providers.delete(identifier);
|
|
50
|
-
this.
|
|
51
|
-
|
|
52
|
-
this.hasSpeechProviderContext.set(false);
|
|
112
|
+
if (oldHasSpeechProvider !== this.hasSpeechProvider) {
|
|
113
|
+
this.handleHasSpeechProviderChange();
|
|
53
114
|
}
|
|
54
115
|
});
|
|
55
116
|
}
|
|
117
|
+
handleHasSpeechProviderChange() {
|
|
118
|
+
this.hasSpeechProviderContext.set(this.hasSpeechProvider);
|
|
119
|
+
this._onDidChangeHasSpeechProvider.fire();
|
|
120
|
+
}
|
|
56
121
|
get hasActiveSpeechToTextSession() { return !!this._activeSpeechToTextSession; }
|
|
57
|
-
createSpeechToTextSession(token, context = 'speech') {
|
|
58
|
-
const provider =
|
|
59
|
-
|
|
60
|
-
throw new Error(`No Speech provider is registered.`);
|
|
61
|
-
}
|
|
62
|
-
else if (this.providers.size > 1) {
|
|
63
|
-
this.logService.warn(`Multiple speech providers registered. Picking first one: ${provider.metadata.displayName}`);
|
|
64
|
-
}
|
|
65
|
-
const language = this.configurationService.getValue('accessibility.voice.speechLanguage');
|
|
122
|
+
async createSpeechToTextSession(token, context = 'speech') {
|
|
123
|
+
const provider = await this.getProvider();
|
|
124
|
+
const language = speechLanguageConfigToLanguage(this.configurationService.getValue(SPEECH_LANGUAGE_CONFIG));
|
|
66
125
|
const session = this._activeSpeechToTextSession = provider.createSpeechToTextSession(token, typeof language === 'string' ? { language } : undefined);
|
|
67
126
|
const sessionStart = Date.now();
|
|
68
127
|
let sessionRecognized = false;
|
|
128
|
+
let sessionContentLength = 0;
|
|
69
129
|
const disposables = ( new DisposableStore());
|
|
70
130
|
const onSessionStoppedOrCanceled = () => {
|
|
71
131
|
if (session === this._activeSpeechToTextSession) {
|
|
72
132
|
this._activeSpeechToTextSession = undefined;
|
|
73
133
|
this.speechToTextInProgress.reset();
|
|
134
|
+
this.accessibilitySignalService.playSignal(AccessibilitySignal.voiceRecordingStopped, { allowManyInParallel: true });
|
|
74
135
|
this._onDidEndSpeechToTextSession.fire();
|
|
75
136
|
this.telemetryService.publicLog2('speechToTextSession', {
|
|
76
137
|
context,
|
|
77
|
-
|
|
78
|
-
|
|
138
|
+
sessionDuration: Date.now() - sessionStart,
|
|
139
|
+
sessionRecognized,
|
|
140
|
+
sessionContentLength,
|
|
141
|
+
sessionLanguage: language
|
|
79
142
|
});
|
|
80
143
|
}
|
|
81
144
|
disposables.dispose();
|
|
@@ -90,12 +153,17 @@ let SpeechService = class SpeechService extends Disposable {
|
|
|
90
153
|
if (session === this._activeSpeechToTextSession) {
|
|
91
154
|
this.speechToTextInProgress.set(true);
|
|
92
155
|
this._onDidStartSpeechToTextSession.fire();
|
|
156
|
+
this.accessibilitySignalService.playSignal(AccessibilitySignal.voiceRecordingStarted);
|
|
93
157
|
}
|
|
94
158
|
break;
|
|
95
159
|
case SpeechToTextStatus.Recognizing:
|
|
96
|
-
case SpeechToTextStatus.Recognized:
|
|
97
160
|
sessionRecognized = true;
|
|
98
161
|
break;
|
|
162
|
+
case SpeechToTextStatus.Recognized:
|
|
163
|
+
if (typeof e.text === 'string') {
|
|
164
|
+
sessionContentLength += e.text.length;
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
99
167
|
case SpeechToTextStatus.Stopped:
|
|
100
168
|
onSessionStoppedOrCanceled();
|
|
101
169
|
break;
|
|
@@ -103,9 +171,21 @@ let SpeechService = class SpeechService extends Disposable {
|
|
|
103
171
|
}));
|
|
104
172
|
return session;
|
|
105
173
|
}
|
|
174
|
+
async getProvider() {
|
|
175
|
+
await this.extensionService.activateByEvent('onSpeech');
|
|
176
|
+
const provider = firstOrDefault(Array.from(( this.providers.values())));
|
|
177
|
+
if (!provider) {
|
|
178
|
+
throw new Error(`No Speech provider is registered.`);
|
|
179
|
+
}
|
|
180
|
+
else if (this.providers.size > 1) {
|
|
181
|
+
this.logService.warn(`Multiple speech providers registered. Picking first one: ${provider.metadata.displayName}`);
|
|
182
|
+
}
|
|
183
|
+
return provider;
|
|
184
|
+
}
|
|
106
185
|
get hasActiveKeywordRecognition() { return !!this._activeKeywordRecognitionSession; }
|
|
107
186
|
async recognizeKeyword(token) {
|
|
108
187
|
const result = ( new DeferredPromise());
|
|
188
|
+
await this.extensionService.activateByEvent('onSpeech');
|
|
109
189
|
const disposables = ( new DisposableStore());
|
|
110
190
|
disposables.add(token.onCancellationRequested(() => {
|
|
111
191
|
disposables.dispose();
|
|
@@ -147,18 +227,12 @@ let SpeechService = class SpeechService extends Disposable {
|
|
|
147
227
|
disposables.dispose();
|
|
148
228
|
}
|
|
149
229
|
this.telemetryService.publicLog2('keywordRecognition', {
|
|
150
|
-
|
|
230
|
+
keywordRecognized: status === KeywordRecognitionStatus.Recognized
|
|
151
231
|
});
|
|
152
232
|
return status;
|
|
153
233
|
}
|
|
154
234
|
async doRecognizeKeyword(token) {
|
|
155
|
-
const provider =
|
|
156
|
-
if (!provider) {
|
|
157
|
-
throw new Error(`No Speech provider is registered.`);
|
|
158
|
-
}
|
|
159
|
-
else if (this.providers.size > 1) {
|
|
160
|
-
this.logService.warn(`Multiple speech providers registered. Picking first one: ${provider.metadata.displayName}`);
|
|
161
|
-
}
|
|
235
|
+
const provider = await this.getProvider();
|
|
162
236
|
const session = this._activeKeywordRecognitionSession = provider.createKeywordRecognitionSession(token);
|
|
163
237
|
this._onDidStartKeywordRecognition.fire();
|
|
164
238
|
const disposables = ( new DisposableStore());
|
|
@@ -191,7 +265,9 @@ SpeechService = ( __decorate([
|
|
|
191
265
|
( __param(1, IContextKeyService)),
|
|
192
266
|
( __param(2, IHostService)),
|
|
193
267
|
( __param(3, ITelemetryService)),
|
|
194
|
-
( __param(4, IConfigurationService))
|
|
268
|
+
( __param(4, IConfigurationService)),
|
|
269
|
+
( __param(5, IAccessibilitySignalService)),
|
|
270
|
+
( __param(6, IExtensionService))
|
|
195
271
|
], SpeechService));
|
|
196
272
|
|
|
197
273
|
export { SpeechService };
|