drewThomasson commited on
Commit
9a27def
1 Parent(s): 5132ddc

Upload 4 files

Browse files
Files changed (2) hide show
  1. app.py +4 -9
  2. lib/functions.py +76 -34
app.py CHANGED
@@ -144,24 +144,21 @@ Linux/Mac:
144
  if arg.startswith('--') and arg not in options:
145
  print(f'Error: Unrecognized option "{arg}"')
146
  sys.exit(1)
147
-
148
  args = vars(parser.parse_args())
149
 
150
  # Check if the port is already in use to prevent multiple launches
151
  if not args['headless'] and is_port_in_use(interface_port):
152
  print(f'Error: Port {interface_port} is already in use. The web interface may already be running.')
153
  sys.exit(1)
154
-
155
  args['script_mode'] = args['script_mode'] if args['script_mode'] else NATIVE
156
  args['share'] = args['share'] if args['share'] else False
157
-
158
  if args['script_mode'] == NATIVE:
159
  check_pkg = check_and_install_requirements(requirements_file)
160
  if check_pkg:
161
- print('Package requirements ok')
162
- if check_dictionary():
163
- print ('Dictionary ok')
164
- else:
165
  sys.exit(1)
166
  else:
167
  print('Some packages could not be installed')
@@ -191,8 +188,6 @@ Linux/Mac:
191
  new_ebooks_dir = os.path.abspath(args['ebooks_dir'])
192
  else:
193
  print(f'Error: The provided --ebooks_dir "{args["ebooks_dir"]}" does not exist.')
194
-
195
-
196
  sys.exit(1)
197
 
198
  if os.path.exists(new_ebooks_dir):
 
144
  if arg.startswith('--') and arg not in options:
145
  print(f'Error: Unrecognized option "{arg}"')
146
  sys.exit(1)
147
+
148
  args = vars(parser.parse_args())
149
 
150
  # Check if the port is already in use to prevent multiple launches
151
  if not args['headless'] and is_port_in_use(interface_port):
152
  print(f'Error: Port {interface_port} is already in use. The web interface may already be running.')
153
  sys.exit(1)
154
+
155
  args['script_mode'] = args['script_mode'] if args['script_mode'] else NATIVE
156
  args['share'] = args['share'] if args['share'] else False
157
+
158
  if args['script_mode'] == NATIVE:
159
  check_pkg = check_and_install_requirements(requirements_file)
160
  if check_pkg:
161
+ if not check_dictionary():
 
 
 
162
  sys.exit(1)
163
  else:
164
  print('Some packages could not be installed')
 
188
  new_ebooks_dir = os.path.abspath(args['ebooks_dir'])
189
  else:
190
  print(f'Error: The provided --ebooks_dir "{args["ebooks_dir"]}" does not exist.')
 
 
191
  sys.exit(1)
192
 
193
  if os.path.exists(new_ebooks_dir):
lib/functions.py CHANGED
@@ -2,6 +2,7 @@ import argparse
2
  import csv
3
  import docker
4
  import ebooklib
 
5
  import gradio as gr
6
  import hashlib
7
  import json
@@ -287,7 +288,7 @@ def has_metadata(f):
287
 
288
  def convert_to_epub(session):
289
  if session['cancellation_requested']:
290
- stop_and_detach_tts()
291
  print('Cancel requested')
292
  return False
293
  if session['script_mode'] == DOCKER_UTILS:
@@ -330,7 +331,7 @@ def convert_to_epub(session):
330
  def get_cover(session):
331
  try:
332
  if session['cancellation_requested']:
333
- stop_and_detach_tts()
334
  print('Cancel requested')
335
  return False
336
  cover_image = False
@@ -354,7 +355,7 @@ def get_cover(session):
354
  def get_chapters(language, session):
355
  try:
356
  if session['cancellation_requested']:
357
- stop_and_detach_tts()
358
  print('Cancel requested')
359
  return False
360
  all_docs = list(session['epub'].get_items_of_type(ebooklib.ITEM_DOCUMENT))
@@ -445,7 +446,7 @@ def get_sentences(sentence, language, max_pauses=9):
445
  def convert_chapters_to_audio(session):
446
  try:
447
  if session['cancellation_requested']:
448
- stop_and_detach_tts()
449
  print('Cancel requested')
450
  return False
451
  progress_bar = None
@@ -531,10 +532,11 @@ def convert_chapters_to_audio(session):
531
  chapter_num = x + 1
532
  chapter_audio_file = f'chapter_{chapter_num}.{audioproc_format}'
533
  sentences = session['chapters'][x]
 
534
  start = current_sentence # Mark the starting sentence of the chapter
535
- print(f"\nChapter {chapter_num} containing {len(sentences)} sentences...")
536
  for i, sentence in enumerate(sentences):
537
- if current_sentence >= resume_sentence and resume_sentence > 0 or resume_sentence == 0:
538
  params['sentence_audio_file'] = os.path.join(session['chapters_dir_sentences'], f'{current_sentence}.{audioproc_format}')
539
  params['sentence'] = sentence
540
  if convert_sentence_to_audio(params, session):
@@ -549,11 +551,13 @@ def convert_chapters_to_audio(session):
549
  return False
550
  current_sentence += 1
551
  end = current_sentence - 1
552
- if combine_audio_sentences(chapter_audio_file, start, end, session):
553
- print(f'Combining chapter {chapter_num} to audio, sentence {start} to {end}')
554
- else:
555
- print('combine_audio_sentences() failed!')
556
- return False
 
 
557
  return True
558
  except Exception as e:
559
  raise DependencyError(e)
@@ -561,7 +565,7 @@ def convert_chapters_to_audio(session):
561
  def convert_sentence_to_audio(params, session):
562
  try:
563
  if session['cancellation_requested']:
564
- stop_and_detach_tts(params['tts'])
565
  print('Cancel requested')
566
  return False
567
  generation_params = {
@@ -624,7 +628,7 @@ def combine_audio_sentences(chapter_audio_file, start, end, session):
624
  ]
625
  for file in selected_files:
626
  if session['cancellation_requested']:
627
- stop_and_detach_tts(params['tts'])
628
  print('Cancel requested')
629
  return False
630
  if session['cancellation_requested']:
@@ -751,8 +755,11 @@ def combine_audio_chapters(session):
751
  ffmpeg_cmd += ['-c:v', 'copy', '-disposition:v', 'attached_pic'] # JPEG cover (no re-encoding needed)
752
  if ffmpeg_cover is not None and ffmpeg_cover.endswith('.png'):
753
  ffmpeg_cmd += ['-pix_fmt', 'yuv420p']
754
- ffmpeg_cmd += ['-af', 'agate=threshold=-33dB:ratio=2:attack=5:release=100,acompressor=threshold=-20dB:ratio=2.5:attack=50:release=200:makeup=0dB,loudnorm=I=-19:TP=-3:LRA=7:linear=true']
755
- ffmpeg_cmd += ['-movflags', '+faststart', '-y', ffmpeg_final_file]
 
 
 
756
  if session['script_mode'] == DOCKER_UTILS:
757
  try:
758
  container = session['client'].containers.run(
@@ -795,7 +802,6 @@ def combine_audio_chapters(session):
795
  docker_final_file = os.path.join(session['tmp_dir'], final_name)
796
  final_file = os.path.join(session['audiobooks_dir'], final_name)
797
  if export_audio():
798
- shutil.rmtree(session['tmp_dir'])
799
  return final_file
800
  return None
801
  except Exception as e:
@@ -846,7 +852,7 @@ def replace_roman_numbers(text):
846
  text = roman_chapter_pattern.sub(replace_chapter_match, text)
847
  text = roman_numerals_with_period.sub(replace_numeral_with_period, text)
848
  return text
849
-
850
  def stop_and_detach_tts(tts=None):
851
  if tts is not None:
852
  if next(tts.parameters()).is_cuda:
@@ -854,7 +860,7 @@ def stop_and_detach_tts(tts=None):
854
  del tts
855
  if torch.cuda.is_available():
856
  torch.cuda.empty_cache()
857
-
858
  def delete_old_web_folders(root_dir):
859
  try:
860
  if not os.path.exists(root_dir):
@@ -937,7 +943,6 @@ def convert_ebook(args):
937
 
938
  session['tmp_dir'] = os.path.join(processes_dir, f"ebook-{session['id']}")
939
  session['chapters_dir'] = os.path.join(session['tmp_dir'], f"chapters_{hashlib.md5(args['ebook'].encode()).hexdigest()}")
940
-
941
  session['chapters_dir_sentences'] = os.path.join(session['chapters_dir'], 'sentences')
942
 
943
  if not is_gui_process:
@@ -995,6 +1000,20 @@ def convert_ebook(args):
995
  if convert_chapters_to_audio(session):
996
  final_file = combine_audio_chapters(session)
997
  if final_file is not None:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
998
  progress_status = f'Audiobook {os.path.basename(final_file)} created!'
999
  return progress_status, final_file
1000
  else:
@@ -1011,7 +1030,6 @@ def convert_ebook(args):
1011
  error = 'convert_to_epub() failed!'
1012
  else:
1013
  error = f"Temporary directory {session['tmp_dir']} not removed due to failure."
1014
-
1015
  else:
1016
  error = f"Language {args['language']} is not supported."
1017
  if session['cancellation_requested']:
@@ -1116,7 +1134,7 @@ def web_interface(args):
1116
  with gr.Group():
1117
  gr_ebook_file = gr.File(label='EBook File (.epub, .mobi, .azw3, fb2, lrf, rb, snb, tcr, .pdf, .txt, .rtf, doc, .docx, .html, .odt, .azw)', file_types=['.epub', '.mobi', '.azw3', 'fb2', 'lrf', 'rb', 'snb', 'tcr', '.pdf', '.txt', '.rtf', 'doc', '.docx', '.html', '.odt', '.azw'])
1118
  with gr.Group():
1119
- gr_voice_file = gr.File(label='*Cloning Voice (a .wav 24000hz for XTTS base model and 16000hz for FAIRSEQ base model, no more than 6 sec)', file_types=['.wav'], visible=interface_component_options['gr_voice_file'])
1120
  gr.Markdown('<p>&nbsp;&nbsp;* Optional</p>')
1121
  with gr.Group():
1122
  gr_device = gr.Radio(label='Processor Unit', choices=['CPU', 'GPU'], value='CPU')
@@ -1267,7 +1285,7 @@ def web_interface(args):
1267
  def update_interface():
1268
  nonlocal is_converting
1269
  is_converting = False
1270
- return gr.update('Convert', variant='primary', interactive=False), gr.update(), gr.update(value=audiobook_file), update_audiobooks_ddn(), hide_modal()
1271
 
1272
  def refresh_audiobook_list():
1273
  files = []
@@ -1284,13 +1302,17 @@ def web_interface(args):
1284
  return link, link, gr.update(visible=True)
1285
  return None, None, gr.update(visible=False)
1286
 
1287
- def update_convert_btn(upload_file, custom_model_file, session_id):
1288
- session = context.get_session(session_id)
1289
- if hasattr(upload_file, 'name') and not hasattr(custom_model_file, 'name'):
1290
- yield gr.update(variant='primary', interactive=True)
1291
  else:
1292
- yield gr.update(variant='primary', interactive=False)
1293
- return
 
 
 
 
1294
 
1295
  def update_audiobooks_ddn():
1296
  files = refresh_audiobook_list()
@@ -1375,6 +1397,12 @@ def web_interface(args):
1375
  yield gr.update(), gr.update(), gr.update(value=f'Error: {str(e)}')
1376
  return
1377
 
 
 
 
 
 
 
1378
  def change_gr_fine_tuned(fine_tuned):
1379
  visible = False
1380
  if fine_tuned == 'std':
@@ -1440,20 +1468,25 @@ def web_interface(args):
1440
  }
1441
 
1442
  if args["ebook"] is None:
1443
- return gr.update(value='Error: a file is required.')
 
1444
 
1445
  try:
1446
  is_converting = True
1447
  progress_status, audiobook_file = convert_ebook(args)
1448
  if audiobook_file is None:
1449
  if is_converting:
1450
- return gr.update(value='Conversion cancelled.')
 
1451
  else:
1452
- return gr.update(value='Conversion failed.')
 
1453
  else:
1454
- return progress_status
 
1455
  except Exception as e:
1456
- return DependencyError(e)
 
1457
 
1458
  gr_ebook_file.change(
1459
  fn=update_convert_btn,
@@ -1484,6 +1517,11 @@ def web_interface(args):
1484
  inputs=gr_custom_model_list,
1485
  outputs=gr_fine_tuned
1486
  )
 
 
 
 
 
1487
  gr_fine_tuned.change(
1488
  fn=change_gr_fine_tuned,
1489
  inputs=gr_fine_tuned,
@@ -1511,6 +1549,10 @@ def web_interface(args):
1511
  outputs=[gr_data, gr_session_status, gr_session, gr_audiobooks_ddn, gr_custom_model_list]
1512
  )
1513
  gr_convert_btn.click(
 
 
 
 
1514
  fn=submit_convert_btn,
1515
  inputs=[
1516
  gr_session, gr_device, gr_ebook_file, gr_voice_file, gr_language,
@@ -1521,7 +1563,7 @@ def web_interface(args):
1521
  ).then(
1522
  fn=update_interface,
1523
  inputs=None,
1524
- outputs=[gr_convert_btn, gr_ebook_file, gr_audio_player, gr_audiobooks_ddn, gr_modal_html]
1525
  )
1526
  interface.load(
1527
  fn=None,
 
2
  import csv
3
  import docker
4
  import ebooklib
5
+ import fnmatch
6
  import gradio as gr
7
  import hashlib
8
  import json
 
288
 
289
  def convert_to_epub(session):
290
  if session['cancellation_requested']:
291
+ #stop_and_detach_tts()
292
  print('Cancel requested')
293
  return False
294
  if session['script_mode'] == DOCKER_UTILS:
 
331
  def get_cover(session):
332
  try:
333
  if session['cancellation_requested']:
334
+ #stop_and_detach_tts()
335
  print('Cancel requested')
336
  return False
337
  cover_image = False
 
355
  def get_chapters(language, session):
356
  try:
357
  if session['cancellation_requested']:
358
+ #stop_and_detach_tts()
359
  print('Cancel requested')
360
  return False
361
  all_docs = list(session['epub'].get_items_of_type(ebooklib.ITEM_DOCUMENT))
 
446
  def convert_chapters_to_audio(session):
447
  try:
448
  if session['cancellation_requested']:
449
+ #stop_and_detach_tts()
450
  print('Cancel requested')
451
  return False
452
  progress_bar = None
 
532
  chapter_num = x + 1
533
  chapter_audio_file = f'chapter_{chapter_num}.{audioproc_format}'
534
  sentences = session['chapters'][x]
535
+ sentences_count = len(sentences)
536
  start = current_sentence # Mark the starting sentence of the chapter
537
+ print(f"\nChapter {chapter_num} containing {sentences_count} sentences...")
538
  for i, sentence in enumerate(sentences):
539
+ if current_sentence >= resume_sentence:
540
  params['sentence_audio_file'] = os.path.join(session['chapters_dir_sentences'], f'{current_sentence}.{audioproc_format}')
541
  params['sentence'] = sentence
542
  if convert_sentence_to_audio(params, session):
 
551
  return False
552
  current_sentence += 1
553
  end = current_sentence - 1
554
+ print(f"\nEnd of Chapter {chapter_num}")
555
+ if start >= resume_sentence:
556
+ if combine_audio_sentences(chapter_audio_file, start, end, session):
557
+ print(f'Combining chapter {chapter_num} to audio, sentence {start} to {end}')
558
+ else:
559
+ print('combine_audio_sentences() failed!')
560
+ return False
561
  return True
562
  except Exception as e:
563
  raise DependencyError(e)
 
565
  def convert_sentence_to_audio(params, session):
566
  try:
567
  if session['cancellation_requested']:
568
+ #stop_and_detach_tts(params['tts'])
569
  print('Cancel requested')
570
  return False
571
  generation_params = {
 
628
  ]
629
  for file in selected_files:
630
  if session['cancellation_requested']:
631
+ #stop_and_detach_tts(params['tts'])
632
  print('Cancel requested')
633
  return False
634
  if session['cancellation_requested']:
 
755
  ffmpeg_cmd += ['-c:v', 'copy', '-disposition:v', 'attached_pic'] # JPEG cover (no re-encoding needed)
756
  if ffmpeg_cover is not None and ffmpeg_cover.endswith('.png'):
757
  ffmpeg_cmd += ['-pix_fmt', 'yuv420p']
758
+ ffmpeg_cmd += [
759
+ '-af',
760
+ 'agate=threshold=-35dB:ratio=1.5:attack=10:release=200,acompressor=threshold=-20dB:ratio=2:attack=80:release=200:makeup=1dB,loudnorm=I=-19:TP=-3:LRA=7:linear=true,afftdn=nf=-50,equalizer=f=150:t=q:w=2:g=2,equalizer=f=250:t=q:w=2:g=-2,equalizer=f=12000:t=q:w=2:g=2',
761
+ '-movflags', '+faststart', '-y', ffmpeg_final_file
762
+ ]
763
  if session['script_mode'] == DOCKER_UTILS:
764
  try:
765
  container = session['client'].containers.run(
 
802
  docker_final_file = os.path.join(session['tmp_dir'], final_name)
803
  final_file = os.path.join(session['audiobooks_dir'], final_name)
804
  if export_audio():
 
805
  return final_file
806
  return None
807
  except Exception as e:
 
852
  text = roman_chapter_pattern.sub(replace_chapter_match, text)
853
  text = roman_numerals_with_period.sub(replace_numeral_with_period, text)
854
  return text
855
+ '''
856
  def stop_and_detach_tts(tts=None):
857
  if tts is not None:
858
  if next(tts.parameters()).is_cuda:
 
860
  del tts
861
  if torch.cuda.is_available():
862
  torch.cuda.empty_cache()
863
+ '''
864
  def delete_old_web_folders(root_dir):
865
  try:
866
  if not os.path.exists(root_dir):
 
943
 
944
  session['tmp_dir'] = os.path.join(processes_dir, f"ebook-{session['id']}")
945
  session['chapters_dir'] = os.path.join(session['tmp_dir'], f"chapters_{hashlib.md5(args['ebook'].encode()).hexdigest()}")
 
946
  session['chapters_dir_sentences'] = os.path.join(session['chapters_dir'], 'sentences')
947
 
948
  if not is_gui_process:
 
1000
  if convert_chapters_to_audio(session):
1001
  final_file = combine_audio_chapters(session)
1002
  if final_file is not None:
1003
+ chapters_dirs = [
1004
+ dir_name for dir_name in os.listdir(session['tmp_dir'])
1005
+ if fnmatch.fnmatch(dir_name, "chapters_*") and os.path.isdir(os.path.join(session['tmp_dir'], dir_name))
1006
+ ]
1007
+ if len(chapters_dirs) > 1:
1008
+ if os.path.exists(session['chapters_dir']):
1009
+ shutil.rmtree(session['chapters_dir'])
1010
+ if os.path.exists(session['epub_path']):
1011
+ os.remove(session['epub_path'])
1012
+ if os.path.exists(session['cover']):
1013
+ os.remove(session['cover'])
1014
+ else:
1015
+ if os.path.exists(session['tmp_dir']):
1016
+ shutil.rmtree(session['tmp_dir'])
1017
  progress_status = f'Audiobook {os.path.basename(final_file)} created!'
1018
  return progress_status, final_file
1019
  else:
 
1030
  error = 'convert_to_epub() failed!'
1031
  else:
1032
  error = f"Temporary directory {session['tmp_dir']} not removed due to failure."
 
1033
  else:
1034
  error = f"Language {args['language']} is not supported."
1035
  if session['cancellation_requested']:
 
1134
  with gr.Group():
1135
  gr_ebook_file = gr.File(label='EBook File (.epub, .mobi, .azw3, fb2, lrf, rb, snb, tcr, .pdf, .txt, .rtf, doc, .docx, .html, .odt, .azw)', file_types=['.epub', '.mobi', '.azw3', 'fb2', 'lrf', 'rb', 'snb', 'tcr', '.pdf', '.txt', '.rtf', 'doc', '.docx', '.html', '.odt', '.azw'])
1136
  with gr.Group():
1137
+ gr_voice_file = gr.File(label='*Cloning Voice (a .wav 24khz for XTTS base model and 16khz for FAIRSEQ base model, no more than 6 sec)', file_types=['.wav'], visible=interface_component_options['gr_voice_file'])
1138
  gr.Markdown('<p>&nbsp;&nbsp;* Optional</p>')
1139
  with gr.Group():
1140
  gr_device = gr.Radio(label='Processor Unit', choices=['CPU', 'GPU'], value='CPU')
 
1285
  def update_interface():
1286
  nonlocal is_converting
1287
  is_converting = False
1288
+ return gr.update('Convert', variant='primary', interactive=False), gr.update(value=None), gr.update(value=None), gr.update(value=audiobook_file), update_audiobooks_ddn(), hide_modal()
1289
 
1290
  def refresh_audiobook_list():
1291
  files = []
 
1302
  return link, link, gr.update(visible=True)
1303
  return None, None, gr.update(visible=False)
1304
 
1305
+ def update_convert_btn(upload_file=None, custom_model_file=None, session_id=None):
1306
+ if session_id is None:
1307
+ yield gr.update(variant='primary', interactive=False)
1308
+ return
1309
  else:
1310
+ session = context.get_session(session_id)
1311
+ if hasattr(upload_file, 'name') and not hasattr(custom_model_file, 'name'):
1312
+ yield gr.update(variant='primary', interactive=True)
1313
+ else:
1314
+ yield gr.update(variant='primary', interactive=False)
1315
+ return
1316
 
1317
  def update_audiobooks_ddn():
1318
  files = refresh_audiobook_list()
 
1397
  yield gr.update(), gr.update(), gr.update(value=f'Error: {str(e)}')
1398
  return
1399
 
1400
+ def change_gr_tts_engine(engine):
1401
+ if engine == 'xtts':
1402
+ return gr.update(visible=True)
1403
+ else:
1404
+ return gr.update(visible=False)
1405
+
1406
  def change_gr_fine_tuned(fine_tuned):
1407
  visible = False
1408
  if fine_tuned == 'std':
 
1468
  }
1469
 
1470
  if args["ebook"] is None:
1471
+ yield gr.update(value='Error: a file is required.')
1472
+ return
1473
 
1474
  try:
1475
  is_converting = True
1476
  progress_status, audiobook_file = convert_ebook(args)
1477
  if audiobook_file is None:
1478
  if is_converting:
1479
+ yield gr.update(value='Conversion cancelled.')
1480
+ return
1481
  else:
1482
+ yield gr.update(value='Conversion failed.')
1483
+ return
1484
  else:
1485
+ yield progress_status
1486
+ return
1487
  except Exception as e:
1488
+ yield DependencyError(e)
1489
+ return
1490
 
1491
  gr_ebook_file.change(
1492
  fn=update_convert_btn,
 
1517
  inputs=gr_custom_model_list,
1518
  outputs=gr_fine_tuned
1519
  )
1520
+ gr_tts_engine.change(
1521
+ fn=change_gr_tts_engine,
1522
+ inputs=gr_tts_engine,
1523
+ outputs=gr_tab_preferences
1524
+ )
1525
  gr_fine_tuned.change(
1526
  fn=change_gr_fine_tuned,
1527
  inputs=gr_fine_tuned,
 
1549
  outputs=[gr_data, gr_session_status, gr_session, gr_audiobooks_ddn, gr_custom_model_list]
1550
  )
1551
  gr_convert_btn.click(
1552
+ fn=update_convert_btn,
1553
+ inputs=None,
1554
+ outputs=gr_convert_btn
1555
+ ).then(
1556
  fn=submit_convert_btn,
1557
  inputs=[
1558
  gr_session, gr_device, gr_ebook_file, gr_voice_file, gr_language,
 
1563
  ).then(
1564
  fn=update_interface,
1565
  inputs=None,
1566
+ outputs=[gr_convert_btn, gr_ebook_file, gr_voice_file, gr_audio_player, gr_audiobooks_ddn, gr_modal_html]
1567
  )
1568
  interface.load(
1569
  fn=None,