def go( input_filename, output_xml_filename, output_fsg_filename, output_dict_filename, unit, word_unit, out_orth, ): xml = load_xml(input_filename) xml, fsg, dct = end_to_end(xml, input_filename, unit, word_unit, out_orth) save_xml(output_xml_filename, xml) save_txt(output_fsg_filename, fsg) save_txt(output_dict_filename, dct)
def go(seg_path, text_path, audio_path, output_path): results = make_smil(text_path, audio_path, parse_hypseg(seg_path)) save_txt(output_path, results)
def save_readalong( # noqa C901 # noqa C901 - ignore the complexity of this function # this * forces all arguments to be passed by name, because I don't want any # code to depend on their order in the future *, align_results: Dict[str, List], output_dir: str, output_basename: str, config=None, audiofile: str, audiosegment: AudioSegment = None, output_formats=(), ): """Save the results from align_audio() into the output files required for a readalong Args: align_results(Dict[str,List]): return value from align_audio() output_dir (str): directory where to save the readalong, output_dir should already exist, files it contains may be overwritten output_basename (str): basename of the files to save in output_dir config ([type TODO], optional): alignment configuration loaded from the json audiofile (str): path to the audio file passed to align_audio() output_formats (List[str], optional): list of desired output formats audiosegment (AudioSegment): a pydub.AudioSegment object of processed audio. if None, then original audio will be saved at `audiofile` Returns: None Raises: [TODO] """ # Round all times to three digits, anything more is excess precision # poluting the output files, and usually due to float rounding errors anyway. for w in align_results["words"]: w["start"] = round(w["start"], 3) w["end"] = round(w["end"], 3) output_base = os.path.join(output_dir, output_basename) # Create textgrid object if outputting to TextGrid or eaf if "TextGrid" in output_formats or "eaf" in output_formats: audio = read_audio_from_file(audiofile) duration = audio.frame_count() / audio.frame_rate words, sentences = return_words_and_sentences(align_results) textgrid = write_to_text_grid(words, sentences, duration) if "TextGrid" in output_formats: textgrid.to_file(output_base + ".TextGrid") if "eaf" in output_formats: textgrid.to_eaf().to_file(output_base + ".eaf") # Create webvtt object if outputting to vtt or srt if "srt" in output_formats or "vtt" in output_formats: words, sentences = return_words_and_sentences(align_results) cc_sentences = write_to_subtitles(sentences) cc_words = write_to_subtitles(words) if "srt" in output_formats: cc_sentences.save_as_srt(output_base + "_sentences.srt") cc_words.save_as_srt(output_base + "_words.srt") if "vtt" in output_formats: cc_words.save(output_base + "_words.vtt") cc_sentences.save(output_base + "_sentences.vtt") tokenized_xml_path = output_base + ".xml" save_xml(tokenized_xml_path, align_results["tokenized"]) if "xhtml" in output_formats: convert_to_xhtml(align_results["tokenized"]) tokenized_xhtml_path = output_base + ".xhtml" save_xml(tokenized_xhtml_path, align_results["tokenized"]) _, audio_ext = os.path.splitext(audiofile) audio_path = output_base + audio_ext audio_format = audio_ext[1:] if audiosegment: if audio_format in ["m4a", "aac"]: audio_format = "ipod" try: audiosegment.export(audio_path, format=audio_format) except CouldntEncodeError: LOGGER.warning(f"The audio file at {audio_path} could \ not be exported in the {audio_format} format. \ Please ensure your installation of ffmpeg has \ the necessary codecs.") audio_path = output_base + ".wav" audiosegment.export(audio_path, format="wav") else: shutil.copy(audiofile, audio_path) smil_path = output_base + ".smil" smil = make_smil( os.path.basename(tokenized_xml_path), os.path.basename(audio_path), align_results, ) save_txt(smil_path, smil) if "html" in output_formats: html_out_path = output_base + ".html" html_out = create_web_component_html(tokenized_xml_path, smil_path, audio_path) with open(html_out_path, "w") as f: f.write(html_out) save_minimal_index_html( os.path.join(output_dir, "index.html"), os.path.basename(tokenized_xml_path), os.path.basename(smil_path), os.path.basename(audio_path), ) # Copy the image files to the output's asset directory, if any are found if config and "images" in config: assets_dir = os.path.join(output_dir, "assets") try: os.mkdir(assets_dir) except FileExistsError: if not os.path.isdir(assets_dir): raise for _, image in config["images"].items(): if image[0:4] == "http": LOGGER.warning( f"Please make sure {image} is accessible to clients using your read-along." ) else: try: shutil.copy(image, assets_dir) except Exception as e: LOGGER.warning( f"Please copy {image} to {assets_dir} before deploying your read-along. ({e})" ) if os.path.basename(image) != image: LOGGER.warning( f"Read-along images were tested with absolute urls (starting with http(s):// " f"and filenames without a path. {image} might not work as specified." )
def go(input_filename, output_filename, unit): xml = load_xml(input_filename) fsg = make_fsg(xml.xpath(".//" + unit), input_filename, unit) save_txt(output_filename, fsg)
def go(input_filename, output_filename, unit): xml = load_xml(input_filename) fsg = make_fsg(xml, input_filename, unit) save_txt(output_filename, fsg)
def align(**kwargs): """Align TEXTFILE and AUDIOFILE and create output files as OUTPUT_BASE.* in directory OUTPUT_BASE/. TEXTFILE: Input text file path (in XML, or plain text with -i) AUDIOFILE: Input audio file path, in any format supported by ffmpeg OUTPUT_BASE: Base name for output files """ config = kwargs.get("config", None) if config: if config.endswith("json"): try: with open(config) as f: config = json.load(f) except json.decoder.JSONDecodeError: LOGGER.error(f"Config file at {config} is not valid json.") else: raise click.BadParameter(f"Config file '{config}' must be in JSON format") output_dir = kwargs["output_base"] if os.path.exists(output_dir): if not os.path.isdir(output_dir): raise click.UsageError( f"Output folder '{output_dir}' already exists but is a not a directory." ) if not kwargs["force_overwrite"]: raise click.UsageError( f"Output folder '{output_dir}' already exists, use -f to overwrite." ) else: os.mkdir(output_dir) # Make sure we can write to the output directory, for early error checking and user # friendly error messages. try: with TemporaryFile(dir=output_dir): pass except Exception: raise click.UsageError( f"Cannot write into output folder '{output_dir}'. Please verify permissions." ) output_basename = os.path.basename(output_dir) output_base = os.path.join(output_dir, output_basename) temp_base = None if kwargs["save_temps"]: temp_dir = os.path.join(output_dir, "tempfiles") if not os.path.isdir(temp_dir): if os.path.exists(temp_dir) and kwargs["force_overwrite"]: os.unlink(temp_dir) os.mkdir(temp_dir) temp_base = os.path.join(temp_dir, output_basename) if kwargs["debug"]: LOGGER.setLevel("DEBUG") if kwargs["text_input"]: if not kwargs["language"]: LOGGER.warn("No input language provided, using undetermined mapping") tempfile, kwargs["textfile"] = create_input_tei( input_file_name=kwargs["textfile"], text_language=kwargs["language"], save_temps=temp_base, ) if kwargs["output_xhtml"]: tokenized_xml_path = "%s.xhtml" % output_base else: _, input_ext = os.path.splitext(kwargs["textfile"]) tokenized_xml_path = "%s%s" % (output_base, input_ext) if os.path.exists(tokenized_xml_path) and not kwargs["force_overwrite"]: raise click.BadParameter( "Output file %s exists already, use -f to overwrite." % tokenized_xml_path ) smil_path = output_base + ".smil" if os.path.exists(smil_path) and not kwargs["force_overwrite"]: raise click.BadParameter( "Output file %s exists already, use -f to overwrite." % smil_path ) _, audio_ext = os.path.splitext(kwargs["audiofile"]) audio_path = output_base + audio_ext if os.path.exists(audio_path) and not kwargs["force_overwrite"]: raise click.BadParameter( "Output file %s exists already, use -f to overwrite." % audio_path ) unit = kwargs.get("unit", "w") bare = kwargs.get("bare", False) if ( not unit ): # .get() above should handle this but apparently the way kwargs is implemented unit = "w" # unit could still be None here. try: results = align_audio( kwargs["textfile"], kwargs["audiofile"], unit=unit, bare=bare, config=config, save_temps=temp_base, ) except RuntimeError as e: LOGGER.error(e) exit(1) if kwargs["text_grid"]: audio = read_audio_from_file(kwargs["audiofile"]) duration = audio.frame_count() / audio.frame_rate words, sentences = return_words_and_sentences(results) textgrid = write_to_text_grid(words, sentences, duration) textgrid.to_file(output_base + ".TextGrid") textgrid.to_eaf().to_file(output_base + ".eaf") if kwargs["closed_captioning"]: words, sentences = return_words_and_sentences(results) webvtt_sentences = write_to_subtitles(sentences) webvtt_sentences.save(output_base + "_sentences.vtt") webvtt_sentences.save_as_srt(output_base + "_sentences.srt") webvtt_words = write_to_subtitles(words) webvtt_words.save(output_base + "_words.vtt") webvtt_words.save_as_srt(output_base + "_words.srt") if kwargs["output_xhtml"]: convert_to_xhtml(results["tokenized"]) save_minimal_index_html( os.path.join(output_dir, "index.html"), os.path.basename(tokenized_xml_path), os.path.basename(smil_path), os.path.basename(audio_path), ) save_xml(tokenized_xml_path, results["tokenized"]) smil = make_smil( os.path.basename(tokenized_xml_path), os.path.basename(audio_path), results ) shutil.copy(kwargs["audiofile"], audio_path) save_txt(smil_path, smil)
def go(input_filename, output_filename, unit): xml = load_xml(input_filename) jsgf = make_jsgf(xml, input_filename, unit) save_txt(output_filename, jsgf)
def save_txt_to_dir(output_path, dest_path, txt): """Save text to a directory, mimicking the interface of save_txt_zip.""" save_txt(os.path.join(output_path, dest_path), txt)
def go(input_filename, output_filename, unit): xml = load_xml(input_filename) dct = make_dict(xml.xpath(".//" + unit), input_filename, unit) save_txt(output_filename, dct)