Merge branch 'master' of github.com:microsoft/cognitive-services-speech-sdk-js into yulin/avatar

This commit is contained in:
Yulin Li 2023-06-20 14:07:41 +08:00
Родитель e218f4f4ea 9fff0733c4
Коммит b676e4daa5
23 изменённых файлов: 448 добавлений и 409 удалений

Просмотреть файл

@ -3,11 +3,6 @@ Microsoft Azure Cognitive Services Speech SDK Javascript
Copyright (c) Microsoft Corporation
All rights reserved.
Component.
ocsp (https://github.com/indutny/ocsp)
Open Source License/Copyright Notice.
Copyright Fedor Indutny, 2015.
Component.
uuid (https://github.com/uuidjs/uuid)
Open Source License/Copyright Notice.
@ -22,4 +17,4 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------- END OF LICENSE ------------------------------------------
----------------------------------------------- END OF LICENSE ------------------------------------------

Просмотреть файл

@ -16,14 +16,6 @@ Notwithstanding any other terms, you may reverse engineer this software to the
extent required to debug changes to any libraries licensed under the GNU Lesser
General Public License.
Component.
ocsp (https://github.com/indutny/ocsp)
Open Source License/Copyright Notice.
This software is licensed under the MIT License.
Copyright Fedor Indutny, 2015.
Component.
uuid (https://github.com/uuidjs/uuid)

99
package-lock.json сгенерированный
Просмотреть файл

@ -1,12 +1,12 @@
{
"name": "microsoft-cognitiveservices-speech-sdk",
"version": "1.27.0-alpha.0.1",
"version": "1.30.0-alpha.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "microsoft-cognitiveservices-speech-sdk",
"version": "1.27.0-alpha.0.1",
"version": "1.30.0-alpha.0.1",
"license": "MIT",
"dependencies": {
"agent-base": "^6.0.1",
@ -41,7 +41,6 @@
"gulp-typescript": "^5.0.1",
"jest": "^27.0.0",
"jest-junit": "^12.0.0",
"ocsp": "^1.2.0",
"rimraf": "^3.0.2",
"semver": "^6.3.0",
"source-map-loader": "^3.0.1",
@ -2315,11 +2314,6 @@
"node": ">=4"
}
},
"node_modules/async": {
"version": "1.5.2",
"dev": true,
"license": "MIT"
},
"node_modules/async-done": {
"version": "1.3.2",
"dev": true,
@ -8321,47 +8315,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/ocsp": {
"version": "1.2.0",
"dev": true,
"license": "MIT",
"dependencies": {
"asn1.js": "^4.8.0",
"asn1.js-rfc2560": "^4.0.0",
"asn1.js-rfc5280": "^2.0.0",
"async": "^1.5.2",
"simple-lru-cache": "0.0.2"
}
},
"node_modules/ocsp/node_modules/asn1.js": {
"version": "4.10.1",
"dev": true,
"license": "MIT",
"dependencies": {
"bn.js": "^4.0.0",
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0"
}
},
"node_modules/ocsp/node_modules/asn1.js-rfc2560": {
"version": "4.0.6",
"dev": true,
"license": "MIT",
"dependencies": {
"asn1.js-rfc5280": "^2.0.0"
},
"peerDependencies": {
"asn1.js": "^4.4.0"
}
},
"node_modules/ocsp/node_modules/asn1.js-rfc5280": {
"version": "2.0.1",
"dev": true,
"license": "MIT",
"dependencies": {
"asn1.js": "^4.5.0"
}
},
"node_modules/once": {
"version": "1.4.0",
"dev": true,
@ -9294,10 +9247,6 @@
"dev": true,
"license": "ISC"
},
"node_modules/simple-lru-cache": {
"version": "0.0.2",
"dev": true
},
"node_modules/sisteransi": {
"version": "1.0.5",
"dev": true,
@ -12679,10 +12628,6 @@
"version": "1.0.0",
"dev": true
},
"async": {
"version": "1.5.2",
"dev": true
},
"async-done": {
"version": "1.3.2",
"dev": true,
@ -16742,42 +16687,6 @@
"es-abstract": "^1.19.1"
}
},
"ocsp": {
"version": "1.2.0",
"dev": true,
"requires": {
"asn1.js": "^4.8.0",
"asn1.js-rfc2560": "^4.0.0",
"asn1.js-rfc5280": "^2.0.0",
"async": "^1.5.2",
"simple-lru-cache": "0.0.2"
},
"dependencies": {
"asn1.js": {
"version": "4.10.1",
"dev": true,
"requires": {
"bn.js": "^4.0.0",
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0"
}
},
"asn1.js-rfc2560": {
"version": "4.0.6",
"dev": true,
"requires": {
"asn1.js-rfc5280": "^2.0.0"
}
},
"asn1.js-rfc5280": {
"version": "2.0.1",
"dev": true,
"requires": {
"asn1.js": "^4.5.0"
}
}
}
},
"once": {
"version": "1.4.0",
"dev": true,
@ -17354,10 +17263,6 @@
"version": "3.0.3",
"dev": true
},
"simple-lru-cache": {
"version": "0.0.2",
"dev": true
},
"sisteransi": {
"version": "1.0.5",
"dev": true

Просмотреть файл

@ -2,7 +2,7 @@
"name": "microsoft-cognitiveservices-speech-sdk",
"author": "Microsoft Corporation",
"homepage": "https://docs.microsoft.com/azure/cognitive-services/speech-service/",
"version": "1.27.0-alpha.0.1",
"version": "1.30.0-alpha.0.1",
"license": "MIT",
"description": "Microsoft Cognitive Services Speech SDK for JavaScript",
"keywords": [
@ -73,7 +73,6 @@
"gulp-typescript": "^5.0.1",
"jest": "^27.0.0",
"jest-junit": "^12.0.0",
"ocsp": "^1.2.0",
"rimraf": "^3.0.2",
"semver": "^6.3.0",
"source-map-loader": "^3.0.1",

Просмотреть файл

@ -1,102 +0,0 @@
/* eslint-disable import/order */
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as http from "http";
import * as tls from "tls";
import { ProxyInfo } from "./ProxyInfo";
import Agent from "agent-base";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import HttpsProxyAgent from "https-proxy-agent";
import * as net from "net";
export class CertCheckAgent {
// Test hook to enable forcing expiration / refresh to happen.
public static testTimeOffset: number = 0;
// Test hook to disable stapling for cache testing.
public static forceDisableOCSPStapling: boolean = false;
private privProxyInfo: ProxyInfo;
public constructor(proxyInfo?: ProxyInfo) {
if (!!proxyInfo) {
this.privProxyInfo = proxyInfo;
}
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public GetAgent(): http.Agent {
// eslint-disable-next-line @typescript-eslint/unbound-method
const agent: any = new Agent.Agent(this.CreateConnection);
if (this.privProxyInfo !== undefined &&
this.privProxyInfo.HostName !== undefined &&
this.privProxyInfo.Port > 0) {
const proxyName: string = "privProxyInfo";
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
agent[proxyName] = this.privProxyInfo;
}
return agent as http.Agent;
}
private static GetProxyAgent(proxyInfo: ProxyInfo): HttpsProxyAgent {
const httpProxyOptions: HttpsProxyAgent.HttpsProxyAgentOptions = {
host: proxyInfo.HostName,
port: proxyInfo.Port,
};
if (!!proxyInfo.UserName) {
httpProxyOptions.headers = {
"Proxy-Authentication": "Basic " + new Buffer(`${proxyInfo.UserName}:${(proxyInfo.Password === undefined) ? "" : proxyInfo.Password}`).toString("base64"),
};
} else {
httpProxyOptions.headers = {};
}
httpProxyOptions.headers.requestOCSP = "true";
const httpProxyAgent: HttpsProxyAgent = new HttpsProxyAgent(httpProxyOptions);
return httpProxyAgent;
}
private CreateConnection(request: Agent.ClientRequest, options: Agent.RequestOptions): Promise<net.Socket> {
let socketPromise: Promise<net.Socket>;
options = {
...options,
...{
requestOCSP: !CertCheckAgent.forceDisableOCSPStapling,
servername: options.host
}
};
if (!!this.privProxyInfo) {
const httpProxyAgent: HttpsProxyAgent = CertCheckAgent.GetProxyAgent(this.privProxyInfo);
const baseAgent: Agent.Agent = httpProxyAgent as unknown as Agent.Agent;
socketPromise = new Promise<net.Socket>((resolve: (value: net.Socket) => void, reject: (error: string | Error) => void): void => {
baseAgent.callback(request, options, (error: Error, socket: net.Socket): void => {
if (!!error) {
reject(error);
} else {
resolve(socket);
}
});
});
} else {
if (!!options.secureEndpoint) {
socketPromise = Promise.resolve(tls.connect(options));
} else {
socketPromise = Promise.resolve(net.connect(options));
}
}
return socketPromise;
}
}

Просмотреть файл

@ -2,6 +2,14 @@
// Licensed under the MIT license.
// Node.JS specific web socket / browser support.
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import * as http from "http";
import * as net from "net";
import * as tls from "tls";
import Agent from "agent-base";
import HttpsProxyAgent from "https-proxy-agent";
import ws from "ws";
import { HeaderNames } from "../common.speech/HeaderNames";
import {
@ -27,8 +35,6 @@ import {
} from "../common/Exports";
import { ProxyInfo } from "./ProxyInfo";
import { CertCheckAgent } from "./CertChecks";
interface ISendItem {
Message: ConnectionMessage;
RawWebsocketMessage: RawWebsocketMessage;
@ -115,9 +121,8 @@ export class WebsocketMessageAdapter {
const options: ws.ClientOptions = { headers: this.privHeaders, perMessageDeflate: this.privEnableCompression };
// The ocsp library will handle validation for us and fail the connection if needed.
this.privCertificateValidatedDeferral.resolve();
const checkAgent: CertCheckAgent = new CertCheckAgent(this.proxyInfo);
options.agent = checkAgent.GetAgent();
options.agent = this.getAgent();
// Workaround for https://github.com/microsoft/cognitive-services-speech-sdk-js/issues/465
// Which is root caused by https://github.com/TooTallNate/node-agent-base/issues/61
const uri = new URL(this.privUri);
@ -322,6 +327,75 @@ export class WebsocketMessageAdapter {
Events.instance.onEvent(event);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
private getAgent(): http.Agent {
// eslint-disable-next-line @typescript-eslint/unbound-method
const agent: { proxyInfo: ProxyInfo } = new Agent.Agent(this.createConnection) as unknown as { proxyInfo: ProxyInfo } ;
if (this.proxyInfo !== undefined &&
this.proxyInfo.HostName !== undefined &&
this.proxyInfo.Port > 0) {
agent.proxyInfo = this.proxyInfo;
}
return agent as unknown as http.Agent;
}
private static GetProxyAgent(proxyInfo: ProxyInfo): HttpsProxyAgent {
const httpProxyOptions: HttpsProxyAgent.HttpsProxyAgentOptions = {
host: proxyInfo.HostName,
port: proxyInfo.Port,
};
if (!!proxyInfo.UserName) {
httpProxyOptions.headers = {
"Proxy-Authentication": "Basic " + new Buffer(`${proxyInfo.UserName}:${(proxyInfo.Password === undefined) ? "" : proxyInfo.Password}`).toString("base64"),
};
} else {
httpProxyOptions.headers = {};
}
httpProxyOptions.headers.requestOCSP = "true";
const httpProxyAgent: HttpsProxyAgent = new HttpsProxyAgent(httpProxyOptions);
return httpProxyAgent;
}
private createConnection(request: Agent.ClientRequest, options: Agent.RequestOptions): Promise<net.Socket> {
let socketPromise: Promise<net.Socket>;
options = {
...options,
...{
requestOCSP: true,
servername: options.host
}
};
if (!!this.proxyInfo) {
const httpProxyAgent: HttpsProxyAgent = WebsocketMessageAdapter.GetProxyAgent(this.proxyInfo);
const baseAgent: Agent.Agent = httpProxyAgent as unknown as Agent.Agent;
socketPromise = new Promise<net.Socket>((resolve: (value: net.Socket) => void, reject: (error: string | Error) => void): void => {
baseAgent.callback(request, options, (error: Error, socket: net.Socket): void => {
if (!!error) {
reject(error);
} else {
resolve(socket);
}
});
});
} else {
if (!!options.secureEndpoint) {
socketPromise = Promise.resolve(tls.connect(options));
} else {
socketPromise = Promise.resolve(net.connect(options));
}
}
return socketPromise;
}
private get isWebsocketOpen(): boolean {
return this.privWebsocketClient && this.privWebsocketClient.readyState === this.privWebsocketClient.OPEN;
}

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT license.
import { Contracts } from "../../sdk/Contracts";
import { ITranslations, RecognitionStatus } from "../Exports";
import { IPrimaryLanguage, ITranslations, RecognitionStatus } from "../Exports";
import { TranslationStatus } from "../TranslationStatus";
// translation.phrase
@ -13,6 +13,7 @@ export interface ITranslationPhrase {
Translation?: ITranslations;
Text: string;
DisplayText?: string;
PrimaryLanguage?: IPrimaryLanguage;
}
export class TranslationPhrase implements ITranslationPhrase {
@ -55,6 +56,14 @@ export class TranslationPhrase implements ITranslationPhrase {
return this.privTranslationPhrase.Text;
}
public get Language(): string {
return this.privTranslationPhrase.PrimaryLanguage?.Language;
}
public get Confidence(): string {
return this.privTranslationPhrase.PrimaryLanguage?.Confidence;
}
public get Translation(): ITranslations {
return this.privTranslationPhrase.Translation;
}

Просмотреть файл

@ -5,8 +5,9 @@ import { SynthesisStatus } from "../Exports";
// translation.synthesis.end
export interface ITranslationSynthesisEnd {
SynthesisStatus: SynthesisStatus;
FailureReason: string;
SynthesisStatus?: SynthesisStatus;
FailureReason?: string;
Status?: SynthesisStatus;
}
export class TranslationSynthesisEnd implements ITranslationSynthesisEnd {
@ -14,7 +15,12 @@ export class TranslationSynthesisEnd implements ITranslationSynthesisEnd {
private constructor(json: string) {
this.privSynthesisEnd = JSON.parse(json) as ITranslationSynthesisEnd;
this.privSynthesisEnd.SynthesisStatus = SynthesisStatus[this.privSynthesisEnd.SynthesisStatus as unknown as keyof typeof SynthesisStatus];
if (!!this.privSynthesisEnd.SynthesisStatus) {
this.privSynthesisEnd.SynthesisStatus = SynthesisStatus[this.privSynthesisEnd.SynthesisStatus as unknown as keyof typeof SynthesisStatus];
}
if (!!this.privSynthesisEnd.Status) {
this.privSynthesisEnd.SynthesisStatus = SynthesisStatus[this.privSynthesisEnd.Status as unknown as keyof typeof SynthesisStatus];
}
}
public static fromJSON(json: string): TranslationSynthesisEnd {

Просмотреть файл

@ -50,6 +50,28 @@ import { IConnectionFactory } from "./IConnectionFactory";
import { RecognizerConfig } from "./RecognizerConfig";
import { SpeechConnectionMessage } from "./SpeechConnectionMessage.Internal";
interface CustomModel {
language: string;
endpoint: string;
}
interface PhraseDetection {
customModels?: CustomModel[];
onInterim?: { action: string };
onSuccess?: { action: string };
mode?: string;
INTERACTIVE?: Segmentation;
CONVERSATION?: Segmentation;
DICTATION?: Segmentation;
}
interface Segmentation {
segmentation: {
mode: "Custom";
segmentationSilenceTimeoutMs: number;
};
}
export abstract class ServiceRecognizerBase implements IDisposable {
private privAuthentication: IAuthentication;
private privConnectionFactory: IConnectionFactory;
@ -136,6 +158,69 @@ export abstract class ServiceRecognizerBase implements IDisposable {
}
}
});
const phraseDetection: PhraseDetection = {};
if (recognizerConfig.autoDetectSourceLanguages !== undefined) {
const sourceLanguages: string[] = recognizerConfig.autoDetectSourceLanguages.split(",");
let speechContextLidMode;
if (recognizerConfig.languageIdMode === "Continuous") {
speechContextLidMode = "DetectContinuous";
} else {// recognizerConfig.languageIdMode === "AtStart"
speechContextLidMode = "DetectAtAudioStart";
}
this.privSpeechContext.setSection("languageId", {
Priority: "PrioritizeLatency",
languages: sourceLanguages,
mode: speechContextLidMode,
onSuccess: { action: "Recognize" },
onUnknown: { action: "None" }
});
this.privSpeechContext.setSection("phraseOutput", {
interimResults: {
resultType: "Auto"
},
phraseResults: {
resultType: "Always"
}
});
const customModels: CustomModel[] = recognizerConfig.sourceLanguageModels;
if (customModels !== undefined) {
phraseDetection.customModels = customModels;
phraseDetection.onInterim = { action: "None" };
phraseDetection.onSuccess = { action: "None" };
}
}
const isEmpty = (obj: object): boolean => {
// eslint-disable-next-line guard-for-in, brace-style
for (const x in obj) { return false; }
return true;
};
if (!isEmpty(phraseDetection)) {
this.privSpeechContext.setSection("phraseDetection", phraseDetection);
}
}
protected setSpeechSegmentationTimeout(): void{
const speechSegmentationTimeout: string = this.privRecognizerConfig.parameters.getProperty(PropertyId.Speech_SegmentationSilenceTimeoutMs, undefined);
if (speechSegmentationTimeout !== undefined) {
const mode = this.recognitionMode === RecognitionMode.Conversation ? "CONVERSATION" :
this.recognitionMode === RecognitionMode.Dictation ? "DICTATION" : "INTERACTIVE";
const segmentationSilenceTimeoutMs: number = parseInt(speechSegmentationTimeout, 10);
const phraseDetection = this.privSpeechContext.getSection("phraseDetection") as PhraseDetection;
phraseDetection.mode = mode;
phraseDetection[mode] = {
segmentation: {
mode: "Custom",
segmentationSilenceTimeoutMs
}
};
this.privSpeechContext.setSection("phraseDetection", phraseDetection);
}
}
public get audioSource(): IAudioSource {
@ -457,11 +542,6 @@ export abstract class ServiceRecognizerBase implements IDisposable {
json = "{ Offset: 0 }";
}
const speechStopDetected: SpeechDetected = SpeechDetected.fromJSON(json);
// Only shrink the buffers for continuous recognition.
// For single shot, the speech.phrase message will come after the speech.end and it should own buffer shrink.
if (this.privRecognizerConfig.isContinuousRecognition) {
this.privRequestSession.onServiceRecognized(speechStopDetected.Offset + this.privRequestSession.currentTurnAudioOffset);
}
const speechStopEventArgs = new RecognitionEventArgs(speechStopDetected.Offset + this.privRequestSession.currentTurnAudioOffset, this.privRequestSession.sessionId);
if (!!this.privRecognizer.speechEndDetected) {
this.privRecognizer.speechEndDetected(this.privRecognizer, speechStopEventArgs);
@ -502,10 +582,6 @@ export abstract class ServiceRecognizerBase implements IDisposable {
}
}
protected setSpeechSegmentationTimeout(): void {
return;
}
protected sendSpeechContext(connection: IConnection, generateNewRequestId: boolean): Promise<void> {
const speechContextJson = this.speechContext.toJSON();
if (generateNewRequestId) {

Просмотреть файл

@ -26,31 +26,9 @@ import {
} from "./Exports";
import { IAuthentication } from "./IAuthentication";
import { IConnectionFactory } from "./IConnectionFactory";
import { RecognitionMode, RecognizerConfig } from "./RecognizerConfig";
import { RecognizerConfig } from "./RecognizerConfig";
import { SpeechConnectionMessage } from "./SpeechConnectionMessage.Internal";
interface CustomModel {
language: string;
endpoint: string;
}
interface PhraseDetection {
customModels?: CustomModel[];
onInterim?: { action: string };
onSuccess?: { action: string };
mode?: string;
INTERACTIVE?: Segmentation;
CONVERSATION?: Segmentation;
DICTATION?: Segmentation;
}
interface Segmentation {
segmentation: {
mode: "Custom";
segmentationSilenceTimeoutMs: number;
};
}
// eslint-disable-next-line max-classes-per-file
export class SpeechServiceRecognizer extends ServiceRecognizerBase {
@ -65,68 +43,6 @@ export class SpeechServiceRecognizer extends ServiceRecognizerBase {
super(authentication, connectionFactory, audioSource, recognizerConfig, speechRecognizer);
this.privSpeechRecognizer = speechRecognizer;
const phraseDetection: PhraseDetection = {};
if (recognizerConfig.autoDetectSourceLanguages !== undefined) {
const sourceLanguages: string[] = recognizerConfig.autoDetectSourceLanguages.split(",");
let speechContextLidMode;
if (recognizerConfig.languageIdMode === "Continuous") {
speechContextLidMode = "DetectContinuous";
} else {// recognizerConfig.languageIdMode === "AtStart"
speechContextLidMode = "DetectAtAudioStart";
}
this.privSpeechContext.setSection("languageId", {
Priority: "PrioritizeLatency",
languages: sourceLanguages,
mode: speechContextLidMode,
onSuccess: { action: "Recognize" },
onUnknown: { action: "None" }
});
this.privSpeechContext.setSection("phraseOutput", {
interimResults: {
resultType: "Auto"
},
phraseResults: {
resultType: "Always"
}
});
const customModels: CustomModel[] = recognizerConfig.sourceLanguageModels;
if (customModels !== undefined) {
phraseDetection.customModels = customModels;
phraseDetection.onInterim = { action: "None" };
phraseDetection.onSuccess = { action: "None" };
}
}
const isEmpty = (obj: object): boolean => {
// eslint-disable-next-line guard-for-in, brace-style
for (const x in obj) { return false; }
return true;
};
if (!isEmpty(phraseDetection)) {
this.privSpeechContext.setSection("phraseDetection", phraseDetection);
}
}
protected setSpeechSegmentationTimeout(): void{
const speechSegmentationTimeout: string = this.privRecognizerConfig.parameters.getProperty(PropertyId.Speech_SegmentationSilenceTimeoutMs, undefined);
if (speechSegmentationTimeout !== undefined) {
const mode = this.recognitionMode === RecognitionMode.Conversation ? "CONVERSATION" :
this.recognitionMode === RecognitionMode.Dictation ? "DICTATION" : "INTERACTIVE";
const segmentationSilenceTimeoutMs: number = parseInt(speechSegmentationTimeout, 10);
const phraseDetection = this.privSpeechContext.getSection("phraseDetection") as PhraseDetection;
phraseDetection.mode = mode;
phraseDetection[mode] = {
segmentation: {
mode: "Custom",
segmentationSilenceTimeoutMs
}
};
this.privSpeechContext.setSection("phraseDetection", phraseDetection);
}
}
protected async processTypeSpecificMessages(connectionMessage: SpeechConnectionMessage): Promise<boolean> {

Просмотреть файл

@ -34,6 +34,10 @@ export class TranslationConnectionFactory extends ConnectionFactoryBase {
const endpoint: string = this.getEndpointUrl(config);
const queryParams: IStringDictionary<string> = {};
if (config.autoDetectSourceLanguages !== undefined) {
queryParams[QueryParameterNames.EnableLanguageId] = "true";
}
this.setQueryParams(queryParams, config, endpoint);
const headers: IStringDictionary<string> = {};
@ -55,8 +59,13 @@ export class TranslationConnectionFactory extends ConnectionFactoryBase {
let endpointUrl: string = config.parameters.getProperty(PropertyId.SpeechServiceConnection_Endpoint, undefined);
if (!endpointUrl) {
const host: string = config.parameters.getProperty(PropertyId.SpeechServiceConnection_Host, "wss://{region}.s2s.speech" + hostSuffix);
endpointUrl = host + "/speech/translation/cognitiveservices/v1";
if (config.autoDetectSourceLanguages !== undefined) {
const host: string = config.parameters.getProperty(PropertyId.SpeechServiceConnection_Host, "wss://{region}.stt.speech" + hostSuffix);
endpointUrl = host + "/speech/universal/v2";
} else {
const host: string = config.parameters.getProperty(PropertyId.SpeechServiceConnection_Host, "wss://{region}.s2s.speech" + hostSuffix);
endpointUrl = host + "/speech/translation/cognitiveservices/v1";
}
}
if (returnRegionPlaceholder === true) {

Просмотреть файл

@ -111,6 +111,8 @@ export class TranslationServiceRecognizer extends ConversationServiceRecognizer
translatedPhrase.Text,
translatedPhrase.Duration,
this.privRequestSession.currentTurnAudioOffset + translatedPhrase.Offset,
translatedPhrase.Language,
translatedPhrase.Confidence,
undefined,
connectionMessage.textBody,
resultProps);
@ -197,6 +199,7 @@ export class TranslationServiceRecognizer extends ConversationServiceRecognizer
processed = true;
break;
case "audio.end":
case "translation.synthesis.end":
const synthEnd: TranslationSynthesisEnd = TranslationSynthesisEnd.fromJSON(connectionMessage.textBody);
@ -281,6 +284,8 @@ export class TranslationServiceRecognizer extends ConversationServiceRecognizer
undefined, // Text
undefined, // Druation
undefined, // Offset
undefined, // Language
undefined, // LanguageDetectionConfidence
error,
undefined, // Json
properties);
@ -324,12 +329,16 @@ export class TranslationServiceRecognizer extends ConversationServiceRecognizer
}
let resultReason: ResultReason;
let language: string;
let confidence: string;
if (serviceResult instanceof TranslationPhrase) {
if (!!serviceResult.Translation && serviceResult.Translation.TranslationStatus === TranslationStatus.Success) {
resultReason = ResultReason.TranslatedSpeech;
} else {
resultReason = ResultReason.RecognizedSpeech;
}
language = serviceResult.Language;
confidence = serviceResult.Confidence;
} else {
resultReason = ResultReason.TranslatingSpeech;
}
@ -343,6 +352,8 @@ export class TranslationServiceRecognizer extends ConversationServiceRecognizer
serviceResult.Text,
serviceResult.Duration,
offset,
language,
confidence,
serviceResult.Translation.FailureReason,
JSON.stringify(serviceResult),
properties);

Просмотреть файл

@ -193,10 +193,10 @@ export abstract class SpeechTranslationConfig extends SpeechConfig {
* @member SpeechTranslationConfig.prototype.setProperty
* @function
* @public
* @param {string} name - The name of the property.
* @param {string} value - The value.
* @param {string | PropertyId} name - The name of the property to set.
* @param {string} value - The new value of the property.
*/
public abstract setProperty(name: string, value: string): void;
public abstract setProperty(name: string | PropertyId, value: string): void;
/**
* Dispose of associated resources.
@ -401,7 +401,7 @@ export class SpeechTranslationConfigImpl extends SpeechTranslationConfig {
* @member SpeechTranslationConfigImpl.prototype.setProperty
* @function
* @public
* @param {string} name - The name of the property.
* @param {string | PropertyId} name - The name of the property to set.
* @param {string} value - The value of the property.
*/
public setProperty(name: string | PropertyId, value: string): void {

Просмотреть файл

@ -22,7 +22,7 @@ export class SynthesisVoicesResult extends SynthesisResult {
super(requestId, ResultReason.VoicesListRetrieved, undefined, new PropertyCollection());
this.privVoices = [];
for (const item of json) {
this.privVoices.push(new VoiceInfo(item as { Name: string; LocalName: string; ShortName: string; Gender: string; VoiceType: string; Locale: string; StyleList: string[] }));
this.privVoices.push(new VoiceInfo(item as { Name: string; LocalName: string; LocaleName: string; ShortName: string; Gender: string; VoiceType: string; Locale: string; StyleList: string[] }));
}
} else {
super(requestId, ResultReason.Canceled, errorDetails ? errorDetails : "Error information unavailable", new PropertyCollection());

Просмотреть файл

@ -22,7 +22,7 @@ export class ConversationTranslationResult extends TranslationRecognitionResult
errorDetails?: string,
json?: string,
properties?: PropertyCollection) {
super(translations, resultId, reason, text, duration, offset, errorDetails, json, properties);
super(translations, resultId, reason, text, duration, offset, undefined, undefined, errorDetails, json, properties);
this.privId = participantId;
this.privOrigLang = originalLanguage;
}

Просмотреть файл

@ -19,20 +19,23 @@ export class TranslationRecognitionResult extends SpeechRecognitionResult {
* @param {string} text - The recognized text.
* @param {number} duration - The duration.
* @param {number} offset - The offset into the stream.
* @param {string} language - Primary Language detected, if provided.
* @param {string} languageDetectionConfidence - Primary Language confidence ("Unknown," "Low," "Medium," "High"...), if provided.
* @param {string} errorDetails - Error details, if provided.
* @param {string} json - Additional Json, if provided.
* @param {PropertyCollection} properties - Additional properties, if provided.
*/
public constructor(translations: Translations, resultId?: string, reason?: ResultReason,
text?: string, duration?: number, offset?: number, errorDetails?: string,
text?: string, duration?: number, offset?: number, language?: string,
languageDetectionConfidence?: string, errorDetails?: string,
json?: string, properties?: PropertyCollection) {
super(resultId, reason, text, duration, offset, undefined, undefined, undefined, errorDetails, json, properties);
super(resultId, reason, text, duration, offset, language, languageDetectionConfidence, undefined, errorDetails, json, properties);
this.privTranslations = translations;
}
public static fromSpeechRecognitionResult(result: SpeechRecognitionResult): TranslationRecognitionResult {
return new TranslationRecognitionResult(undefined, result.resultId, result.reason, result.text, result.duration, result.offset, result.errorDetails, result.json, result.properties);
return new TranslationRecognitionResult(undefined, result.resultId, result.reason, result.text, result.duration, result.offset, result.language, result.languageDetectionConfidence, result.errorDetails, result.json, result.properties);
}
/**

Просмотреть файл

@ -17,6 +17,7 @@ import { Connection } from "./Connection";
import { Contracts } from "./Contracts";
import {
AudioConfig,
AutoDetectSourceLanguageConfig,
PropertyCollection,
PropertyId,
Recognizer,
@ -97,6 +98,19 @@ export class TranslationRecognizer extends Recognizer {
}
/**
* TranslationRecognizer constructor.
* @constructor
* @param {SpeechTranslationConfig} speechTranslationConfig - an set of initial properties for this recognizer
* @param {AutoDetectSourceLanguageConfig} autoDetectSourceLanguageConfig - An source language detection configuration associated with the recognizer
* @param {AudioConfig} audioConfig - An optional audio configuration associated with the recognizer
*/
public static FromConfig(speechTranslationConfig: SpeechTranslationConfig, autoDetectSourceLanguageConfig: AutoDetectSourceLanguageConfig, audioConfig?: AudioConfig): TranslationRecognizer {
const speechTranslationConfigImpl: SpeechTranslationConfigImpl = speechTranslationConfig as SpeechTranslationConfigImpl;
autoDetectSourceLanguageConfig.properties.mergeTo(speechTranslationConfigImpl.properties);
return new TranslationRecognizer(speechTranslationConfig, audioConfig);
}
/**
* Gets the language name that was set when the recognizer was created.
* @member TranslationRecognizer.prototype.speechRecognitionLanguage

Просмотреть файл

@ -34,17 +34,19 @@ export class VoiceInfo {
private privLocale: string;
private privShortName: string;
private privLocalName: string;
private privLocaleName: string;
private privGender: SynthesisVoiceGender;
private privVoiceType: SynthesisVoiceType;
private privStyleList: string[] = [];
private privVoicePath: string;
public constructor(json: { Name: string; LocalName: string; ShortName: string; Gender: string; VoiceType: string; Locale: string; StyleList: string[] }) {
public constructor(json: { Name: string; LocalName: string; ShortName: string; Gender: string; VoiceType: string; LocaleName: string ; Locale: string; StyleList: string[] }) {
this.privVoicePath = "";
if (!!json) {
this.privName = json.Name;
this.privLocale = json.Locale;
this.privShortName = json.ShortName;
this.privLocaleName = json.LocaleName;
this.privLocalName = json.LocalName;
this.privVoiceType = json.VoiceType.endsWith("Standard") ? SynthesisVoiceType.OnlineStandard : SynthesisVoiceType.OnlineNeural;
this.privGender = json.Gender === "Male" ? SynthesisVoiceGender.Male : json.Gender === "Female" ? SynthesisVoiceGender.Female : SynthesisVoiceGender.Unknown;
@ -72,6 +74,10 @@ export class VoiceInfo {
return this.privLocalName;
}
public get localeName(): string {
return this.privLocaleName;
}
public get gender(): SynthesisVoiceGender {
return this.privGender;
}

Просмотреть файл

@ -76,6 +76,35 @@ export const BuildRecognizer: (speechConfig?: sdk.SpeechConfig, autoConfig?: sdk
return r;
};
export const BuildTranslationRecognizer: (speechTranslationConfig?: sdk.SpeechTranslationConfig, autoConfig?: sdk.AutoDetectSourceLanguageConfig, fileName?: string) => sdk.TranslationRecognizer = (speechTranslationConfig?: sdk.SpeechTranslationConfig, autoConfig?: sdk.AutoDetectSourceLanguageConfig, fileName?: string): sdk.TranslationRecognizer => {
let s: sdk.SpeechTranslationConfig = speechTranslationConfig;
if (s === undefined) {
s = BuildSpeechTranslationConfig();
// Since we're not going to return it, mark it for closure.
objsToClose.push(s);
}
let a: sdk.AutoDetectSourceLanguageConfig = autoConfig;
if (a === undefined) {
a = BuildAutoConfig();
// Since we're not going to return it, mark it for closure.
objsToClose.push(a);
}
const config: sdk.AudioConfig = WaveFileAudioInput.getAudioConfigFromFile(fileName === undefined ? Settings.WaveFile : fileName);
const language: string = Settings.WaveFileLanguage;
if (s.getProperty(sdk.PropertyId[sdk.PropertyId.SpeechServiceConnection_RecoLanguage]) === undefined) {
s.speechRecognitionLanguage = language;
}
s.addTargetLanguage("de-DE");
const r: sdk.TranslationRecognizer = sdk.TranslationRecognizer.FromConfig(s, a, config);
expect(r).not.toBeUndefined();
return r;
};
export const BuildRecognizerFromPushStream: (speechConfig: sdk.SpeechConfig, audioConfig: sdk.AudioConfig, autoConfig?: sdk.AutoDetectSourceLanguageConfig) => sdk.SpeechRecognizer = (speechConfig: sdk.SpeechConfig, audioConfig: sdk.AudioConfig, autoConfig?: sdk.AutoDetectSourceLanguageConfig): sdk.SpeechRecognizer => {
let a: sdk.AutoDetectSourceLanguageConfig = autoConfig;
if (a === undefined) {
@ -106,6 +135,23 @@ const BuildSpeechConfig: () => sdk.SpeechConfig = (): sdk.SpeechConfig => {
return s;
};
const BuildSpeechTranslationConfig: () => sdk.SpeechTranslationConfig = (): sdk.SpeechTranslationConfig => {
let s: sdk.SpeechTranslationConfig;
if (undefined === Settings.SpeechEndpoint) {
s = sdk.SpeechTranslationConfig.fromSubscription(Settings.SpeechSubscriptionKey, Settings.SpeechRegion);
} else {
s = sdk.SpeechTranslationConfig.fromEndpoint(new URL(Settings.SpeechEndpoint), Settings.SpeechSubscriptionKey);
}
if (undefined !== Settings.proxyServer) {
s.setProxy(Settings.proxyServer, Settings.proxyPort);
}
expect(s).not.toBeUndefined();
return s;
};
const BuildAutoConfig: (s?: sdk.SourceLanguageConfig[]) => sdk.AutoDetectSourceLanguageConfig = (s?: sdk.SourceLanguageConfig[]): sdk.AutoDetectSourceLanguageConfig => {
let a: sdk.AutoDetectSourceLanguageConfig;
if ((s === undefined) || (s.length < 1)) {
@ -223,50 +269,8 @@ describe.each([true, false])("Service based tests", (forceNodeWebSocket: boolean
});
}); // testRecognizeOnceFromSourceLanguageConfig
test("testRecognizeOnceWithContinuousLIDGeneratesServiceError", (done: jest.DoneCallback): void => {
// eslint-disable-next-line no-console
console.info("Name: testRecognizeOnceWithContinuousLIDGeneratesServiceError");
const s: sdk.SpeechConfig = BuildSpeechConfig();
objsToClose.push(s);
const configs: sdk.SourceLanguageConfig[] = BuildSourceLanguageConfigs();
configs.forEach((c: sdk.SourceLanguageConfig) => { objsToClose.push(c); });
const a: sdk.AutoDetectSourceLanguageConfig = BuildAutoConfig(configs);
a.mode = sdk.LanguageIdMode.Continuous;
a.properties.setProperty(sdk.PropertyId.SpeechServiceConnection_RecognitionEndpointVersion, "1");
objsToClose.push(a);
const r: sdk.SpeechRecognizer = BuildRecognizer(s, a);
objsToClose.push(r);
r.canceled = (o: sdk.Recognizer, e: sdk.SpeechRecognitionCanceledEventArgs): void => {
try {
expect(e.errorDetails).not.toBeUndefined();
expect(e.errorDetails).toEqual("Language identification with DetectContinuous not supported on v1. websocket error code: 1007");
done();
} catch (error) {
done(error);
}
};
r.recognizeOnceAsync((result: sdk.SpeechRecognitionResult) => {
try {
expect(result).not.toBeUndefined();
expect(result.errorDetails).not.toBeUndefined();
expect(result.errorDetails).toEqual("Language identification with DetectContinuous not supported on v1. websocket error code: 1007");
done();
} catch (error) {
done(error);
}
}, (error: string) => {
done(error);
});
}); // testRecognizeOnceFromSourceLanguageConfig
// For review: v2 service appears to be responding to silence after speech
// with Recognized result that has empty text. Expected?
test("Silence After Speech - AutoDetect set", (done: jest.DoneCallback) => {
// eslint-disable-next-line no-console
console.info("Name: Silence After Speech - AutoDetect set");
@ -286,6 +290,7 @@ describe.each([true, false])("Service based tests", (forceNodeWebSocket: boolean
let speechRecognized: boolean = false;
let noMatchCount: number = 0;
let emptyTextRecognizedCount: number = 0;
let speechEnded: number = 0;
let canceled: boolean = false;
let inTurn: boolean = false;
@ -293,19 +298,23 @@ describe.each([true, false])("Service based tests", (forceNodeWebSocket: boolean
r.recognized = (o: sdk.Recognizer, e: sdk.SpeechRecognitionEventArgs) => {
try {
if (e.result.reason === sdk.ResultReason.RecognizedSpeech) {
expect(speechRecognized).toEqual(false);
speechRecognized = true;
speechEnded--;
expect(sdk.ResultReason[e.result.reason]).toEqual(sdk.ResultReason[sdk.ResultReason.RecognizedSpeech]);
expect(e.result.text).toEqual("What's the weather like?");
expect(e.result.properties).not.toBeUndefined();
expect(e.result.properties.getProperty(sdk.PropertyId.SpeechServiceResponse_JsonResult)).not.toBeUndefined();
expect(e.result.language).not.toBeUndefined();
expect(e.result.languageDetectionConfidence).not.toBeUndefined();
const autoDetectResult: sdk.AutoDetectSourceLanguageResult = sdk.AutoDetectSourceLanguageResult.fromResult(e.result);
expect(autoDetectResult).not.toBeUndefined();
expect(autoDetectResult.language).not.toBeUndefined();
expect(autoDetectResult.languageDetectionConfidence).not.toBeUndefined();
if (!!e.result.text && e.result.text !== "") {
expect(speechRecognized).toEqual(false);
speechRecognized = true;
speechEnded--;
expect(sdk.ResultReason[e.result.reason]).toEqual(sdk.ResultReason[sdk.ResultReason.RecognizedSpeech]);
expect(e.result.text).toEqual("What's the weather like?");
expect(e.result.properties).not.toBeUndefined();
expect(e.result.properties.getProperty(sdk.PropertyId.SpeechServiceResponse_JsonResult)).not.toBeUndefined();
expect(e.result.language).not.toBeUndefined();
expect(e.result.languageDetectionConfidence).not.toBeUndefined();
const autoDetectResult: sdk.AutoDetectSourceLanguageResult = sdk.AutoDetectSourceLanguageResult.fromResult(e.result);
expect(autoDetectResult).not.toBeUndefined();
expect(autoDetectResult.language).not.toBeUndefined();
expect(autoDetectResult.languageDetectionConfidence).not.toBeUndefined();
} else {
emptyTextRecognizedCount++;
}
} else if (e.result.reason === sdk.ResultReason.NoMatch) {
expect(speechRecognized).toEqual(true);
noMatchCount++;
@ -342,7 +351,8 @@ describe.each([true, false])("Service based tests", (forceNodeWebSocket: boolean
r.stopContinuousRecognitionAsync(() => {
try {
expect(speechEnded).toEqual(noMatchCount);
expect(noMatchCount).toBeGreaterThanOrEqual(2);
// expect(noMatchCount).toBeGreaterThanOrEqual(2);
expect(emptyTextRecognizedCount).toBeGreaterThanOrEqual(1);
done();
} catch (error) {
done(error);
@ -429,9 +439,103 @@ describe.each([true, false])("Service based tests", (forceNodeWebSocket: boolean
}, 10000); // testAddLIDCustomModels
test("testTransationContinuousRecoWithContinuousLID", (done: jest.DoneCallback) => {
// eslint-disable-next-line no-console
console.info("Name: testTransationContinuousRecoWithContinuousLID");
const configs: sdk.SourceLanguageConfig[] = BuildSourceLanguageConfigs();
configs.forEach((c: sdk.SourceLanguageConfig) => { objsToClose.push(c); });
const a: sdk.AutoDetectSourceLanguageConfig = BuildAutoConfig(configs);
a.mode = sdk.LanguageIdMode.Continuous;
expect(a.properties.getProperty(sdk.PropertyId.SpeechServiceConnection_LanguageIdMode)).toEqual("Continuous");
objsToClose.push(a);
const s: sdk.SpeechTranslationConfig = BuildSpeechTranslationConfig();
const segSilenceTimeoutMs = 1100;
s.setProperty(sdk.PropertyId.Speech_SegmentationSilenceTimeoutMs, segSilenceTimeoutMs.toString());
objsToClose.push(s);
const r: sdk.TranslationRecognizer = BuildTranslationRecognizer(s, a);
objsToClose.push(r);
let speechRecognized: boolean = false;
let speechContextSent: boolean = false;
const con: sdk.Connection = sdk.Connection.fromRecognizer(r);
const expectedRecognitionMode = "CONVERSATION";
const segmentationField = "segmentation";
con.messageSent = (args: sdk.ConnectionMessageEventArgs): void => {
if (args.message.path === "speech.context" && args.message.isTextMessage) {
const message = JSON.parse(args.message.TextMessage);
try {
expect(message.languageId).not.toBeUndefined();
expect(message.languageId.mode).not.toBeUndefined();
expect(message.languageId.mode).toEqual("DetectContinuous");
expect(message.languageId.Priority).not.toBeUndefined();
expect(message.languageId.Priority).toEqual("PrioritizeLatency");
expect(message.phraseDetection.mode).toEqual(expectedRecognitionMode);
expect(message.phraseDetection[expectedRecognitionMode][segmentationField].segmentationSilenceTimeoutMs).toEqual(segSilenceTimeoutMs);
speechContextSent = true;
} catch (error) {
done(error);
}
}
};
r.recognized = (o: sdk.Recognizer, e: sdk.TranslationRecognitionEventArgs) => {
try {
if (e.result.reason === sdk.ResultReason.RecognizedSpeech) {
expect(speechRecognized).toEqual(false);
speechRecognized = true;
expect(sdk.ResultReason[e.result.reason]).toEqual(sdk.ResultReason[sdk.ResultReason.RecognizedSpeech]);
expect(e.result.text).toEqual("What's the weather like?");
expect(e.result.properties).not.toBeUndefined();
expect(e.result.properties.getProperty(sdk.PropertyId.SpeechServiceResponse_JsonResult)).not.toBeUndefined();
const autoDetectResult: sdk.AutoDetectSourceLanguageResult = sdk.AutoDetectSourceLanguageResult.fromResult(e.result);
expect(autoDetectResult).not.toBeUndefined();
expect(autoDetectResult.language).not.toBeUndefined();
expect(autoDetectResult.languageDetectionConfidence).not.toBeUndefined();
} else if (e.result.reason === sdk.ResultReason.NoMatch) {
expect(speechRecognized).toEqual(true);
}
} catch (error) {
done(error);
}
};
r.canceled = (o: sdk.Recognizer, e: sdk.TranslationRecognitionCanceledEventArgs): void => {
try {
expect(e.errorDetails).toBeUndefined();
} catch (error) {
done(error);
}
};
r.startContinuousRecognitionAsync(() => {
WaitForCondition(() => (speechContextSent), () => {
r.stopContinuousRecognitionAsync(() => {
try {
done();
} catch (error) {
done(error);
}
}, (error: string) => {
done(error);
});
});
},
(err: string) => {
done(err);
});
}, 30000); // testTranslationContinuousRecoWithContinuousLID
// TODO: Update this test to use multilingual WAV file and check for language detection results
// TODO: Test that the connection URL uses v2 endpoint
test("testContinuousRecoWithContinuousLID", (done: jest.DoneCallback) => {
test.skip("testContinuousRecoWithContinuousLID", (done: jest.DoneCallback) => {
// eslint-disable-next-line no-console
console.info("Name: testContinuousRecoWithContinuousLID");

Просмотреть файл

@ -323,7 +323,10 @@ describe.each([true])("Service based tests", (forceNodeWebSocket: boolean) => {
});
});
test("InitialSilenceTimeout Continuous", (done: jest.DoneCallback) => {
// For review: v2 endpoint does not appear to be setting a default
// initial silence timeout of < 70s, disabling until clarification received
// from service team
test.skip("InitialSilenceTimeout Continuous", (done: jest.DoneCallback) => {
// eslint-disable-next-line no-console
console.info("Name: InitialSilenceTimeout Continuous");
const s: sdk.SpeechConfig = BuildSpeechConfig();
@ -381,7 +384,10 @@ describe.each([true])("Service based tests", (forceNodeWebSocket: boolean) => {
}, 30000);
test("Silence After Speech", (done: jest.DoneCallback) => {
// For review: v2 endpoint does not appear to be sending a NoMatch result
// on end silence timeout, instead sends a Recognized result with empty text
// disabling until clarification received from service team
test.skip("Silence After Speech", (done: jest.DoneCallback) => {
// eslint-disable-next-line no-console
console.info("Name: Silence After Speech");
// Pump valid speech and then silence until at least one speech end cycle hits.
@ -462,7 +468,10 @@ describe.each([true])("Service based tests", (forceNodeWebSocket: boolean) => {
});
}, 30000);
test("Silence Then Speech", (done: jest.DoneCallback) => {
// For review: v2 endpoint does not appear to be setting a default
// initial silence timeout of < 70s, disabling until clarification received
// from service team
test.skip("Silence Then Speech", (done: jest.DoneCallback) => {
// eslint-disable-next-line no-console
console.info("Name: Silence Then Speech");
// Pump valid speech and then silence until at least one speech end cycle hits.

Просмотреть файл

@ -48,7 +48,7 @@ afterEach(async (): Promise<void> => {
await closeAsyncObjects(objsToClose);
});
const BuildRecognizerFromWaveFile: (speechConfig?: sdk.SpeechTranslationConfig) => sdk.TranslationRecognizer = (speechConfig?: sdk.SpeechTranslationConfig): sdk.TranslationRecognizer => {
const BuildRecognizerFromWaveFile: (speechConfig?: sdk.SpeechTranslationConfig, audioConfig?: sdk.AudioConfig) => sdk.TranslationRecognizer = (speechConfig?: sdk.SpeechTranslationConfig, audioConfig?: sdk.AudioConfig): sdk.TranslationRecognizer => {
let s: sdk.SpeechTranslationConfig = speechConfig;
if (s === undefined) {
@ -56,8 +56,13 @@ const BuildRecognizerFromWaveFile: (speechConfig?: sdk.SpeechTranslationConfig)
// Since we're not going to return it, mark it for closure.
objsToClose.push(s);
}
let a: sdk.AudioConfig = audioConfig;
if (a === undefined) {
a = WaveFileAudioInput.getAudioConfigFromFile(Settings.WaveFile);
// Since we're not going to return it, mark it for closure.
objsToClose.push(a);
}
const config: sdk.AudioConfig = WaveFileAudioInput.getAudioConfigFromFile(Settings.WaveFile);
const language: string = Settings.WaveFileLanguage;
if (s.getProperty(sdk.PropertyId[sdk.PropertyId.SpeechServiceConnection_RecoLanguage]) === undefined) {
@ -65,7 +70,7 @@ const BuildRecognizerFromWaveFile: (speechConfig?: sdk.SpeechTranslationConfig)
}
s.addTargetLanguage("de-DE");
const r: sdk.TranslationRecognizer = new sdk.TranslationRecognizer(s, config);
const r: sdk.TranslationRecognizer = new sdk.TranslationRecognizer(s, a);
expect(r).not.toBeUndefined();
return r;
@ -150,7 +155,13 @@ describe.each([false])("Service based tests", (forceNodeWebSocket: boolean) => {
test("RecognizeOnceAsync1", (done: jest.DoneCallback) => {
// eslint-disable-next-line no-console
console.info("Name: RecognizeOnceAsync1");
const r: sdk.TranslationRecognizer = BuildRecognizerFromWaveFile();
const s: sdk.SpeechTranslationConfig = sdk.SpeechTranslationConfig.fromSubscription(Settings.SpeechSubscriptionKey, Settings.SpeechRegion);
objsToClose.push(s);
const a: sdk.AudioConfig = WaveFileAudioInput.getAudioConfigFromFile(Settings.LongerWaveFile);
objsToClose.push(a);
const r: sdk.TranslationRecognizer = BuildRecognizerFromWaveFile(s, a);
objsToClose.push(r);
let telemetryEvents: number = 0;
@ -172,7 +183,7 @@ describe.each([false])("Service based tests", (forceNodeWebSocket: boolean) => {
json.indexOf(sessionId) > 0) {
try {
expect(hypoCounter).toBeGreaterThanOrEqual(1);
validateTelemetry(json, 2, hypoCounter); // 2 phrases because the extra silence at the end of conversation mode.
validateTelemetry(json, 1, hypoCounter);
} catch (error) {
done(error);
}
@ -197,14 +208,17 @@ describe.each([false])("Service based tests", (forceNodeWebSocket: boolean) => {
}
};
const expectedText = "Hello. It's a good day for me to teach you the sound of my voice. You have learned what I look like";
const expectedTranslation = "Hallo. Es ist ein guter Tag für mich, um dir den Klang meiner Stimme beizubringen. Du hast gelernt";
r.recognizeOnceAsync(
(res: sdk.TranslationRecognitionResult) => {
expect(res).not.toBeUndefined();
expect(res.errorDetails).toBeUndefined();
expect(sdk.ResultReason[res.reason]).toEqual(sdk.ResultReason[sdk.ResultReason.TranslatedSpeech]);
expect(res.translations.get("de", undefined) !== undefined).toEqual(true);
expect("Wie ist das Wetter?").toEqual(res.translations.get("de", ""));
expect(res.text).toEqual("What's the weather like?");
expect(res.translations.get("de", "")).toContain(expectedTranslation);
expect(res.text).toContain(expectedText);
},
(error: string) => {
done(error);
@ -307,8 +321,8 @@ describe.each([false])("Service based tests", (forceNodeWebSocket: boolean) => {
// Translation uses the continuous endpoint for all recos, so the order is
// recognized then speech end.
expect((LAST_RECORDED_EVENT_ID - 1)).toEqual(eventsMap[SpeechEndDetectedEvent]);
expect((LAST_RECORDED_EVENT_ID - 2)).toEqual(eventsMap[Recognized]);
// expect((LAST_RECORDED_EVENT_ID - 1)).toEqual(eventsMap[SpeechEndDetectedEvent]);
// expect((LAST_RECORDED_EVENT_ID - 2)).toEqual(eventsMap[Recognized]);
// Speech ends before the session stops.
expect(eventsMap[SpeechEndDetectedEvent]).toBeLessThan(eventsMap[SessionStoppedEvent]);
@ -783,8 +797,8 @@ describe.each([false])("Service based tests", (forceNodeWebSocket: boolean) => {
WaitForCondition(() => (canceled && !inTurn), () => {
r.stopContinuousRecognitionAsync(() => {
try {
expect(speechEnded).toEqual(noMatchCount);
expect(noMatchCount).toEqual(2);
expect(speechEnded).toBeGreaterThanOrEqual(noMatchCount);
expect(noMatchCount).toBeGreaterThanOrEqual(3);
done();
} catch (error) {
done(error);

Просмотреть файл

@ -208,7 +208,6 @@ describe.each([false])("Service based tests", (forceNodeWebSocket: boolean) => {
expect(res).not.toBeUndefined();
expect(res.errorDetails).not.toBeUndefined();
expect(sdk.ResultReason[res.reason]).toEqual(sdk.ResultReason[sdk.ResultReason.RecognizedSpeech]);
expect(res.translations).toBeUndefined();
expect(res.text).toEqual("What's the weather like?");
done();
},
@ -232,8 +231,8 @@ describe.each([false])("Service based tests", (forceNodeWebSocket: boolean) => {
r.canceled = (o: sdk.Recognizer, e: sdk.TranslationRecognitionCanceledEventArgs) => {
try {
expect(sdk.CancellationReason[e.reason]).toEqual(sdk.CancellationReason[sdk.CancellationReason.Error]);
expect(sdk.CancellationErrorCode[e.errorCode]).toEqual(sdk.CancellationErrorCode[sdk.CancellationErrorCode.ConnectionFailure]);
expect(e.errorDetails).toContain("1006");
expect(sdk.CancellationErrorCode[e.errorCode]).toEqual(sdk.CancellationErrorCode[sdk.CancellationErrorCode.BadRequestParameters]);
expect(e.errorDetails).toContain("1007");
doneCount++;
} catch (error) {
done(error);
@ -244,8 +243,8 @@ describe.each([false])("Service based tests", (forceNodeWebSocket: boolean) => {
try {
const e: sdk.CancellationDetails = sdk.CancellationDetails.fromResult(result);
expect(sdk.CancellationReason[e.reason]).toEqual(sdk.CancellationReason[sdk.CancellationReason.Error]);
expect(sdk.CancellationErrorCode[e.ErrorCode]).toEqual(sdk.CancellationErrorCode[sdk.CancellationErrorCode.ConnectionFailure]);
expect(e.errorDetails).toContain("1006");
expect(sdk.CancellationErrorCode[e.ErrorCode]).toEqual(sdk.CancellationErrorCode[sdk.CancellationErrorCode.BadRequestParameters]);
expect(e.errorDetails).toContain("1007");
doneCount++;
} catch (error) {
done(error);

Просмотреть файл

@ -223,7 +223,7 @@ test("TranslateVoiceInvalidVoice", (done: jest.DoneCallback) => {
try {
stopReco = true;
if (!pass) {
expect(e.errorDetails).toEqual("Synthesis service failed with code: - Could not identify the voice 'Microsoft Server Speech Text to Speech Voice (BadVoice)' for the text to speech service ");
expect(e.errorDetails).toEqual("Translation request failed with status code: BadRequest Reason: Unsupported voice Microsoft Server Speech Text to Speech Voice (BadVoice).");
} else {
expect(sdk.CancellationReason[e.reason]).toEqual(sdk.CancellationReason[sdk.CancellationReason.EndOfStream]);
}
@ -493,7 +493,7 @@ test("MultiPhrase", (done: jest.DoneCallback) => {
() => {
r2.stopContinuousRecognitionAsync(() => {
try {
expect(synthCount).toEqual(numPhrases);
expect(synthCount).toBeGreaterThanOrEqual(numPhrases);
expect(numEvents).toEqual(numPhrases);
done();
} catch (error) {