UNPKG

@hahnpro/ms-speech-sdk

Version:
1 lines 19 kB
{"version":3,"sources":["src/common.speech/TranslationServiceRecognizer.ts"],"names":[],"mappings":"AAGA,OAAO,EAEH,YAAY,EAGf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACH,qBAAqB,EACrB,kBAAkB,EAIlB,uBAAuB,EAIvB,qBAAqB,EAIxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAEH,6BAA6B,EAQhC,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAGhF,qBAAa,4BAA6B,SAAQ,6BAA6B;IAC3E,OAAO,CAAC,yBAAyB,CAAwB;gBAGrD,cAAc,EAAE,eAAe,EAC/B,iBAAiB,EAAE,kBAAkB,EACrC,WAAW,EAAE,YAAY,EACzB,gBAAgB,EAAE,gBAAgB,EAClC,qBAAqB,EAAE,qBAAqB;cAYhC,2BAA2B,CAAC,iBAAiB,EAAE,uBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC;IA0MzG,SAAS,CAAC,iBAAiB,CACvB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,kBAAkB,EACtC,SAAS,EAAE,qBAAqB,EAChC,KAAK,EAAE,MAAM,GAAG,IAAI;IAyCxB,SAAS,CAAC,yBAAyB,CAAC,MAAM,EAAE,uBAAuB,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAW7G,SAAS,CAAC,wBAAwB,CAAC,MAAM,EAAE,uBAAuB,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAU5G,OAAO,CAAC,kBAAkB;IAyC1B,OAAO,CAAC,kBAAkB;CAgB7B","file":"TranslationServiceRecognizer.d.ts","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT license.\n\nimport {\n ConnectionEvent,\n IAudioSource,\n MessageType,\n TranslationStatus,\n} from \"../common/Exports.js\";\nimport {\n CancellationErrorCode,\n CancellationReason,\n PropertyCollection,\n PropertyId,\n ResultReason,\n SpeechRecognitionResult,\n TranslationRecognitionCanceledEventArgs,\n TranslationRecognitionEventArgs,\n TranslationRecognitionResult,\n TranslationRecognizer,\n Translations,\n TranslationSynthesisEventArgs,\n TranslationSynthesisResult,\n} from \"../sdk/Exports.js\";\nimport {\n CancellationErrorCodePropertyName,\n ConversationServiceRecognizer,\n EnumTranslation,\n ITranslationHypothesis,\n RecognitionStatus,\n SynthesisStatus,\n TranslationHypothesis,\n TranslationPhrase,\n TranslationSynthesisEnd,\n} from \"./Exports.js\";\nimport { IAuthentication } from \"./IAuthentication.js\";\nimport { IConnectionFactory } from \"./IConnectionFactory.js\";\nimport { RecognizerConfig } from \"./RecognizerConfig.js\";\nimport { ITranslationPhrase } from \"./ServiceMessages/TranslationPhrase.js\";\nimport { SpeechConnectionMessage } from \"./SpeechConnectionMessage.Internal.js\";\n\n// eslint-disable-next-line max-classes-per-file\nexport class TranslationServiceRecognizer extends ConversationServiceRecognizer {\n private privTranslationRecognizer: TranslationRecognizer;\n\n public constructor(\n authentication: IAuthentication,\n connectionFactory: IConnectionFactory,\n audioSource: IAudioSource,\n recognizerConfig: RecognizerConfig,\n translationRecognizer: TranslationRecognizer) {\n\n super(authentication, connectionFactory, audioSource, recognizerConfig, translationRecognizer);\n this.privTranslationRecognizer = translationRecognizer;\n this.connectionEvents.attach((connectionEvent: ConnectionEvent): void => {\n if (connectionEvent.name === \"ConnectionEstablishedEvent\") {\n this.privTranslationRecognizer.onConnection();\n }\n });\n\n }\n\n protected async processTypeSpecificMessages(connectionMessage: SpeechConnectionMessage): Promise<boolean> {\n\n const resultProps: PropertyCollection = new PropertyCollection();\n let processed: boolean = await this.processSpeechMessages(connectionMessage);\n if (processed) {\n return true;\n }\n\n const handleTranslationPhrase = async (translatedPhrase: TranslationPhrase): Promise<void> => {\n resultProps.setProperty(PropertyId.SpeechServiceResponse_JsonResult, translatedPhrase.asJson());\n this.privRequestSession.onPhraseRecognized(translatedPhrase.Offset + translatedPhrase.Duration);\n\n if (translatedPhrase.RecognitionStatus === RecognitionStatus.Success) {\n\n // OK, the recognition was successful. How'd the translation do?\n const result: TranslationRecognitionEventArgs = this.fireEventForResult(translatedPhrase, resultProps);\n if (!!this.privTranslationRecognizer.recognized) {\n try {\n this.privTranslationRecognizer.recognized(this.privTranslationRecognizer, result);\n /* eslint-disable no-empty */\n } catch (error) {\n // Not going to let errors in the event handler\n // trip things up.\n }\n }\n\n // report result to promise.\n if (!!this.privSuccessCallback) {\n try {\n this.privSuccessCallback(result.result);\n } catch (e) {\n if (!!this.privErrorCallback) {\n this.privErrorCallback(e as string);\n }\n }\n // Only invoke the call back once.\n // and if it's successful don't invoke the\n // error after that.\n this.privSuccessCallback = undefined;\n this.privErrorCallback = undefined;\n }\n } else {\n const reason: ResultReason = EnumTranslation.implTranslateRecognitionResult(translatedPhrase.RecognitionStatus);\n\n const result = new TranslationRecognitionResult(\n undefined,\n this.privRequestSession.requestId,\n reason,\n translatedPhrase.Text,\n translatedPhrase.Duration,\n translatedPhrase.Offset,\n translatedPhrase.Language,\n translatedPhrase.Confidence,\n undefined,\n translatedPhrase.asJson(),\n resultProps);\n\n if (reason === ResultReason.Canceled) {\n const cancelReason: CancellationReason = EnumTranslation.implTranslateCancelResult(translatedPhrase.RecognitionStatus);\n const cancellationErrorCode: CancellationErrorCode = EnumTranslation.implTranslateCancelErrorCode(translatedPhrase.RecognitionStatus);\n\n await this.cancelRecognitionLocal(\n cancelReason,\n cancellationErrorCode,\n EnumTranslation.implTranslateErrorDetails(cancellationErrorCode));\n\n } else {\n if (translatedPhrase.RecognitionStatus !== RecognitionStatus.EndOfDictation) {\n const ev = new TranslationRecognitionEventArgs(result, result.offset, this.privRequestSession.sessionId);\n\n if (!!this.privTranslationRecognizer.recognized) {\n try {\n this.privTranslationRecognizer.recognized(this.privTranslationRecognizer, ev);\n /* eslint-disable no-empty */\n } catch (error) {\n // Not going to let errors in the event handler\n // trip things up.\n }\n }\n\n // report result to promise.\n if (!!this.privSuccessCallback) {\n try {\n this.privSuccessCallback(result);\n } catch (e) {\n if (!!this.privErrorCallback) {\n this.privErrorCallback(e as string);\n }\n }\n // Only invoke the call back once.\n // and if it's successful don't invoke the\n // error after that.\n this.privSuccessCallback = undefined;\n this.privErrorCallback = undefined;\n }\n }\n }\n processed = true;\n }\n\n };\n\n const handleTranslationHypothesis = (hypothesis: TranslationHypothesis): void => {\n resultProps.setProperty(PropertyId.SpeechServiceResponse_JsonResult, hypothesis.asJson());\n\n const result: TranslationRecognitionEventArgs = this.fireEventForResult(hypothesis, resultProps);\n this.privRequestSession.onHypothesis(result.offset);\n\n if (!!this.privTranslationRecognizer.recognizing) {\n try {\n this.privTranslationRecognizer.recognizing(this.privTranslationRecognizer, result);\n /* eslint-disable no-empty */\n } catch (error) {\n // Not going to let errors in the event handler\n // trip things up.\n }\n }\n processed = true;\n };\n\n if (connectionMessage.messageType === MessageType.Text) {\n resultProps.setProperty(PropertyId.SpeechServiceResponse_JsonResult, connectionMessage.textBody);\n }\n\n switch (connectionMessage.path.toLowerCase()) {\n case \"translation.hypothesis\":\n handleTranslationHypothesis(TranslationHypothesis.fromJSON(connectionMessage.textBody, this.privRequestSession.currentTurnAudioOffset));\n break;\n\n case \"translation.response\":\n const phrase: { SpeechPhrase: ITranslationPhrase } = JSON.parse(connectionMessage.textBody) as { SpeechPhrase: ITranslationPhrase };\n if (!!phrase.SpeechPhrase) {\n await handleTranslationPhrase(TranslationPhrase.fromTranslationResponse(phrase, this.privRequestSession.currentTurnAudioOffset));\n } else {\n const hypothesis: { SpeechHypothesis: ITranslationHypothesis } = JSON.parse(connectionMessage.textBody) as { SpeechHypothesis: ITranslationHypothesis };\n if (!!hypothesis.SpeechHypothesis) {\n handleTranslationHypothesis(TranslationHypothesis.fromTranslationResponse(hypothesis, this.privRequestSession.currentTurnAudioOffset));\n }\n }\n break;\n case \"translation.phrase\":\n await handleTranslationPhrase(TranslationPhrase.fromJSON(connectionMessage.textBody, this.privRequestSession.currentTurnAudioOffset));\n break;\n\n case \"translation.synthesis\":\n case \"audio\":\n this.sendSynthesisAudio(connectionMessage.binaryBody, this.privRequestSession.sessionId);\n processed = true;\n break;\n\n case \"audio.end\":\n case \"translation.synthesis.end\":\n const synthEnd: TranslationSynthesisEnd = TranslationSynthesisEnd.fromJSON(connectionMessage.textBody);\n\n switch (synthEnd.SynthesisStatus) {\n case SynthesisStatus.Error:\n if (!!this.privTranslationRecognizer.synthesizing) {\n const result = new TranslationSynthesisResult(ResultReason.Canceled, undefined);\n const retEvent: TranslationSynthesisEventArgs = new TranslationSynthesisEventArgs(result, this.privRequestSession.sessionId);\n\n try {\n this.privTranslationRecognizer.synthesizing(this.privTranslationRecognizer, retEvent);\n /* eslint-disable no-empty */\n } catch (error) {\n // Not going to let errors in the event handler\n // trip things up.\n }\n }\n\n if (!!this.privTranslationRecognizer.canceled) {\n // And raise a canceled event to send the rich(er) error message back.\n const canceledResult: TranslationRecognitionCanceledEventArgs = new TranslationRecognitionCanceledEventArgs(\n this.privRequestSession.sessionId,\n CancellationReason.Error,\n synthEnd.FailureReason,\n CancellationErrorCode.ServiceError,\n null);\n\n try {\n this.privTranslationRecognizer.canceled(this.privTranslationRecognizer, canceledResult);\n /* eslint-disable no-empty */\n } catch (error) {\n // Not going to let errors in the event handler\n // trip things up.\n }\n }\n break;\n case SynthesisStatus.Success:\n this.sendSynthesisAudio(undefined, this.privRequestSession.sessionId);\n break;\n default:\n break;\n }\n processed = true;\n break;\n default:\n break;\n }\n return processed;\n }\n\n // Cancels recognition.\n protected cancelRecognition(\n sessionId: string,\n requestId: string,\n cancellationReason: CancellationReason,\n errorCode: CancellationErrorCode,\n error: string): void {\n\n const properties: PropertyCollection = new PropertyCollection();\n properties.setProperty(CancellationErrorCodePropertyName, CancellationErrorCode[errorCode]);\n\n if (!!this.privTranslationRecognizer.canceled) {\n\n const cancelEvent: TranslationRecognitionCanceledEventArgs = new TranslationRecognitionCanceledEventArgs(\n sessionId,\n cancellationReason,\n error,\n errorCode,\n undefined);\n\n try {\n this.privTranslationRecognizer.canceled(this.privTranslationRecognizer, cancelEvent);\n /* eslint-disable no-empty */\n } catch { }\n }\n\n if (!!this.privSuccessCallback) {\n const result: TranslationRecognitionResult = new TranslationRecognitionResult(\n undefined, // Translations\n requestId,\n ResultReason.Canceled,\n undefined, // Text\n undefined, // Druation\n undefined, // Offset\n undefined, // Language\n undefined, // LanguageDetectionConfidence\n error,\n undefined, // Json\n properties);\n try {\n this.privSuccessCallback(result);\n /* eslint-disable no-empty */\n this.privSuccessCallback = undefined;\n } catch { }\n }\n }\n\n protected handleRecognizingCallback(result: SpeechRecognitionResult, offset: number, sessionId: string): void {\n try {\n const ev = new TranslationRecognitionEventArgs(TranslationRecognitionResult.fromSpeechRecognitionResult(result), offset, sessionId);\n this.privTranslationRecognizer.recognizing(this.privTranslationRecognizer, ev);\n /* eslint-disable no-empty */\n } catch (error) {\n // Not going to let errors in the event handler\n // trip things up.\n }\n }\n\n protected handleRecognizedCallback(result: SpeechRecognitionResult, offset: number, sessionId: string): void {\n try {\n const ev = new TranslationRecognitionEventArgs(TranslationRecognitionResult.fromSpeechRecognitionResult(result), offset, sessionId);\n this.privTranslationRecognizer.recognized(this.privTranslationRecognizer, ev);\n } catch (error) {\n // Not going to let errors in the event handler\n // trip things up.\n }\n }\n\n private fireEventForResult(serviceResult: TranslationHypothesis | TranslationPhrase, properties: PropertyCollection): TranslationRecognitionEventArgs {\n let translations: Translations;\n\n if (undefined !== serviceResult.Translation.Translations) {\n translations = new Translations();\n for (const translation of serviceResult.Translation.Translations) {\n translations.set(translation.Language, translation.Text || translation.DisplayText);\n }\n }\n\n let resultReason: ResultReason;\n let confidence: string;\n if (serviceResult instanceof TranslationPhrase) {\n if (!!serviceResult.Translation && serviceResult.Translation.TranslationStatus === TranslationStatus.Success) {\n resultReason = ResultReason.TranslatedSpeech;\n } else {\n resultReason = ResultReason.RecognizedSpeech;\n }\n confidence = serviceResult.Confidence;\n } else {\n resultReason = ResultReason.TranslatingSpeech;\n }\n const language = serviceResult.Language;\n\n const result = new TranslationRecognitionResult(\n translations,\n this.privRequestSession.requestId,\n resultReason,\n serviceResult.Text,\n serviceResult.Duration,\n serviceResult.Offset,\n language,\n confidence,\n serviceResult.Translation.FailureReason,\n serviceResult.asJson(),\n properties);\n\n const ev = new TranslationRecognitionEventArgs(result, serviceResult.Offset, this.privRequestSession.sessionId);\n return ev;\n }\n\n private sendSynthesisAudio(audio: ArrayBuffer, sessionId: string): void {\n const reason = (undefined === audio) ? ResultReason.SynthesizingAudioCompleted : ResultReason.SynthesizingAudio;\n const result = new TranslationSynthesisResult(reason, audio);\n const retEvent: TranslationSynthesisEventArgs = new TranslationSynthesisEventArgs(result, sessionId);\n\n if (!!this.privTranslationRecognizer.synthesizing) {\n try {\n this.privTranslationRecognizer.synthesizing(this.privTranslationRecognizer, retEvent);\n /* eslint-disable no-empty */\n } catch (error) {\n // Not going to let errors in the event handler\n // trip things up.\n }\n }\n\n }\n}\n"]}