Beispiel #1
0
        /// <summary>
        /// API Handler when the Auto Segment button is clicked
        ///
        /// Replies with true if AutoSegment completed successfully, or false if there was an error. In addition, a NonFatal message/exception may be reported with the error
        /// </summary>
        public void AutoSegment(ApiRequest request)
        {
            Logger.WriteEvent("AudioSegmentationApi.AutoSegment(): AutoSegment started.");

            // Parse the JSON containing the text segmentation data.
            string             json = request.RequiredPostJson();
            AutoSegmentRequest requestParameters = ParseJson(json);

            string        audioFilenameToSegment;
            List <string> fragmentIds;
            var           timingStartEndRangeList = GetAeneasTimings(requestParameters, out audioFilenameToSegment, out fragmentIds);

            if (timingStartEndRangeList == null)
            {
                request.ReplyWithBoolean(false);
                return;
            }

            try
            {
                ExtractAudioSegments(fragmentIds, timingStartEndRangeList, audioFilenameToSegment);
            }
            catch (Exception e)
            {
                ProblemReportApi.ShowProblemDialog(null, e,
                                                   "AudioSegmentationApi.AutoSegment(): Exception thrown during split/extract stage", "nonfatal");
                request.ReplyWithBoolean(false);
                return;
            }

            Logger.WriteEvent("AudioSegmentationApi.AutoSegment(): Completed successfully.");

            request.ReplyWithBoolean(true);             // Success
        }
Beispiel #2
0
        internal List <Tuple <string, string> > GetAeneasTimings(AutoSegmentRequest requestParameters, out string audioFilenameToSegment, out List <string> fragmentIds)
        {
            fragmentIds = null;

            // The client was supposed to validate this already, but double-check in case something strange happened.
            string directoryName = GetAudioDirectory();

            audioFilenameToSegment = GetFileNameToSegment(directoryName, requestParameters.audioFilenameBase);
            if (string.IsNullOrEmpty(audioFilenameToSegment))
            {
                Logger.WriteEvent("AudioSegmentationApi.GetAeneasTimings(): No input audio file found.");
                ErrorReport.ReportNonFatalMessageWithStackTrace("No audio file found. Please record audio first.");
                return(null);
            }

            IEnumerable <AudioTextFragment> audioTextFragments = requestParameters.audioTextFragments;
            string requestedLangCode = requestParameters.lang;

            // The client was supposed to validate this already, but double-check in case something strange happened.
            // Since this is basically a desperate fallback that shouldn't ever happen we won't try to make the message
            // contain a hot link here. That code is in Typescript.
            string message;

            if (!AreAutoSegmentDependenciesMet(out message))
            {
                var localizedFormatString = L10NSharp.LocalizationManager.GetString("EditTab.Toolbox.TalkingBook.MissingDependency",
                                                                                    "To split recordings into sentences, first install this {0} system.",
                                                                                    "The placeholder {0} will be replaced with the dependency that needs to be installed.");
                ErrorReport.ReportNonFatalMessageWithStackTrace(string.Format(localizedFormatString, message));
                return(null);
            }

            // When using TTS overrides, there's no Aeneas error message that tells us if the language is unsupported.
            // Therefore, we explicitly test if the language is supported by the dependency (eSpeak) before getting started.
            string stdOut;
            string stdErr;
            string langCode = GetBestSupportedLanguage(requestedLangCode, out stdOut, out stdErr);

            if (string.IsNullOrEmpty(langCode))
            {
                // FYI: The error message is expected to be in stdError with an empty stdOut, but I included both just in case.
                Logger.WriteEvent("AudioSegmentationApi.GetAeneasTimings(): eSpeak error.");
                ErrorReport.ReportNonFatalMessageWithStackTrace($"eSpeak error: {stdOut}\n{stdErr}");
                return(null);
            }
            Logger.WriteMinorEvent($"AudioSegmentationApi.GetAeneasTimings(): Attempting to segment with langCode={langCode}");

            string textFragmentsFilename = Path.Combine(directoryName, $"{requestParameters.audioFilenameBase}_fragments.txt");
            string audioTimingsFilename  = Path.Combine(directoryName, $"{requestParameters.audioFilenameBase}_timings.{kTimingsOutputFormat}");

            // Clean up the fragments
            audioTextFragments = audioTextFragments.Where(obj => !String.IsNullOrWhiteSpace(obj.fragmentText));             // Remove entries containing only whitespace
            var fragmentList = audioTextFragments.Select(obj => TextUtils.TrimEndNewlines(obj.fragmentText));

            if (langCode != requestedLangCode)
            {
                string collectionPath = _bookSelection.CurrentSelection.CollectionSettings.FolderPath;
                string orthographyConversionMappingPath = Path.Combine(collectionPath, $"convert_{requestedLangCode}_to_{langCode}.txt");
                if (File.Exists(orthographyConversionMappingPath))
                {
                    fragmentList = ApplyOrthographyConversion(fragmentList, orthographyConversionMappingPath);
                }
            }

            // Get the GUID filenames (without extension)
            fragmentIds = audioTextFragments.Select(obj => obj.id).ToList();

            List <Tuple <string, string> > timingStartEndRangeList = null;

            try
            {
                File.WriteAllLines(textFragmentsFilename, fragmentList);

                timingStartEndRangeList = GetSplitStartEndTimings(audioFilenameToSegment, textFragmentsFilename, audioTimingsFilename, langCode);
            }
            catch (Exception e)
            {
                ProblemReportApi.ShowProblemDialog(null, e,
                                                   "AudioSegmentationApi.GetAeneasTimings(): Exception thrown during split stage", "nonfatal");
                return(null);
            }

            try
            {
                RobustFile.Delete(textFragmentsFilename);
            }
            catch (Exception e)
            {
                // These exceptions are unfortunate but not bad enough that we need to inform the user
                Debug.Assert(false, $"Attempted to delete {textFragmentsFilename} but it threw an exception. Message={e.Message}, Stack={e.StackTrace}");
            }

            try
            {
                RobustFile.Delete(audioTimingsFilename);
            }
            catch (Exception e)
            {
                // These exceptions are unfortunate but not bad enough that we need to inform the user
                Debug.Assert(false, $"Attempted to delete {audioTimingsFilename} but it threw an exception. Message={e.Message}, Stack={e.StackTrace}");
            }

            return(timingStartEndRangeList);
        }