Various improvements and modifications in code and documentation

This commit is contained in:
Deniz Şafak
2025-07-10 23:27:19 +03:00
parent 0c7a52fd86
commit 6ede337658
16 changed files with 232 additions and 127 deletions
+1 -1
View File
@@ -1 +1 @@
1.0.9
1.1.0
+1 -1
View File
@@ -1,4 +1,4 @@
from utils import get_version
from abogen.utils import get_version
# Program Information
PROGRAM_NAME = "abogen"
+48 -7
View File
@@ -6,11 +6,11 @@ import chardet
import charset_normalizer
import hashlib # For generating unique cache filenames
from platformdirs import user_desktop_dir
from PyQt5.QtCore import QThread, pyqtSignal, Qt
from PyQt5.QtCore import QThread, pyqtSignal, Qt, QTimer
from PyQt5.QtWidgets import QCheckBox, QVBoxLayout, QDialog, QLabel, QDialogButtonBox
import soundfile as sf
from utils import clean_text, create_process
from constants import PROGRAM_NAME, LANGUAGE_DESCRIPTIONS, SAMPLE_VOICE_TEXTS
from constants import PROGRAM_NAME, LANGUAGE_DESCRIPTIONS, SAMPLE_VOICE_TEXTS, COLORS
from voice_formulas import get_new_voice
import hf_tracker
import static_ffmpeg
@@ -61,7 +61,7 @@ class ChapterOptionsDialog(QDialog):
self.merge_at_end_checkbox = QCheckBox("Create a merged version at the end")
# Set default states
self.save_separately_checkbox.setChecked(True)
self.save_separately_checkbox.setChecked(False)
self.merge_at_end_checkbox.setChecked(True)
# Connect checkbox state change signal
@@ -72,14 +72,36 @@ class ChapterOptionsDialog(QDialog):
layout.addWidget(self.save_separately_checkbox)
layout.addWidget(self.merge_at_end_checkbox)
# Countdown label
self.countdown_seconds = 30
self.countdown_label = QLabel(f"Auto-accepting in {self.countdown_seconds} seconds...")
self.countdown_label.setStyleSheet(f"color: {COLORS['GREEN']};")
layout.addWidget(self.countdown_label)
# Add OK button
button_box = QDialogButtonBox(QDialogButtonBox.Ok)
button_box.accepted.connect(self.accept)
layout.addWidget(button_box)
# Timer for countdown
self._timer = QTimer(self)
self._timer.timeout.connect(self._on_timer_tick)
self._timer.start(1000) # 1 second interval
# Store button_box for later use
self._button_box = button_box
# Initialize merge checkbox state
self.update_merge_checkbox_state()
def _on_timer_tick(self):
self.countdown_seconds -= 1
if self.countdown_seconds > 0:
self.countdown_label.setText(f"Auto-accepting in {self.countdown_seconds} seconds...")
else:
self._timer.stop()
self._button_box.accepted.emit() # Simulate OK click
def update_merge_checkbox_state(self):
# Enable merge checkbox only if save separately is checked
self.merge_at_end_checkbox.setEnabled(self.save_separately_checkbox.isChecked())
@@ -131,6 +153,7 @@ class ConversionThread(QThread):
start_time,
total_char_count,
use_gpu=True,
from_queue=False
): # Add use_gpu parameter
super().__init__()
self._chapter_options_event = threading.Event()
@@ -145,6 +168,7 @@ class ConversionThread(QThread):
self.subtitle_mode = subtitle_mode
self.cancel_requested = False
self.output_format = output_format
self.from_queue = from_queue
self.start_time = start_time # Store start_time
self.total_char_count = total_char_count # Use passed total character count
self.processed_char_count = 0 # Initialize processed character count
@@ -316,8 +340,13 @@ class ConversionThread(QThread):
hf_tracker.set_log_callback(lambda msg: self.log_updated.emit(msg))
# Show configuration
self.log_updated.emit("Configuration:")
# Use display_path for logs if available, otherwise use the actual file name
display_file = self.display_path if self.display_path else self.file_name
# Use file_name for logs if from_queue, otherwise use display_path if available
if getattr(self, "from_queue", False):
display_file = self.file_name
else:
display_file = self.display_path if self.display_path else self.file_name
self.log_updated.emit(f"- Input File: {display_file}")
# Use file size string passed from GUI
@@ -447,7 +476,14 @@ class ConversionThread(QThread):
save_chapters_separately = getattr(self, "save_chapters_separately", False)
chapters_out_dir = None
suffix = ""
base_path = self.display_path if self.display_path else self.file_name
# Use file_name for logs if from_queue, otherwise use display_path if available
if getattr(self, "from_queue", False):
base_path = self.file_name
else:
base_path = self.display_path if self.display_path else self.file_name
base_name = os.path.splitext(os.path.basename(base_path))[0]
if self.save_option == "Save to Desktop":
parent_dir = user_desktop_dir()
@@ -946,8 +982,13 @@ class ConversionThread(QThread):
genre_match = re.search(r"<<METADATA_GENRE:([^>]*)>>", text)
# Use display path or filename as fallback for title
filename = os.path.splitext(os.path.basename(self.display_path if self.display_path else self.file_name))[0]
# Use file_name for logs if from_queue, otherwise use display_path if available
if getattr(self, "from_queue", False):
filename = os.path.splitext(os.path.basename(self.file_name))[0]
else:
filename = os.path.splitext(os.path.basename(self.display_path if self.display_path else self.file_name))[0]
if title_match:
metadata_options.extend(["-metadata", f"title={title_match.group(1)}"])
else:
+112 -69
View File
@@ -6,7 +6,7 @@ import base64
import re
from abogen.queue_manager_gui import QueueManager
from abogen.queued_item import QueuedItem
import hf_tracker
import abogen.hf_tracker as hf_tracker
import hashlib # Added for cache path generation
from PyQt5.QtWidgets import (
QApplication,
@@ -53,7 +53,7 @@ from PyQt5.QtGui import (
QColor,
QMovie,
)
from utils import (
from abogen.utils import (
load_config,
save_config,
get_gpu_acceleration,
@@ -64,9 +64,9 @@ from utils import (
get_resource_path,
LoadPipelineThread,
)
from conversion import ConversionThread, VoicePreviewThread, PlayAudioThread
from book_handler import HandlerDialog
from constants import (
from abogen.conversion import ConversionThread, VoicePreviewThread, PlayAudioThread
from abogen.book_handler import HandlerDialog
from abogen.constants import (
PROGRAM_NAME,
VERSION,
GITHUB_URL,
@@ -77,8 +77,8 @@ from constants import (
COLORS
)
from threading import Thread
from voice_formula_gui import VoiceFormulaDialog
from voice_profiles import load_profiles
from abogen.voice_formula_gui import VoiceFormulaDialog
from abogen.voice_profiles import load_profiles
# Import ctypes for Windows-specific taskbar icon
if platform.system() == "Windows":
@@ -300,6 +300,9 @@ class InputBox(QLabel):
self.window().btn_add_to_queue.setEnabled(True)
self.chapters_btn.adjustSize()
# Reset the input_box_cleared_by_queue flag after setting file info
if hasattr(self.window(), 'input_box_cleared_by_queue'):
self.window().input_box_cleared_by_queue = False
def set_error(self, message):
self.setText(message)
@@ -329,6 +332,9 @@ class InputBox(QLabel):
# Disable add to queue button when input is cleared
if hasattr(self.window(), 'btn_add_to_queue'):
self.window().btn_add_to_queue.setEnabled(False)
# Reset the input_box_cleared_by_queue flag after setting file info
if hasattr(self.window(), 'input_box_cleared_by_queue'):
self.window().input_box_cleared_by_queue = True
def _human_readable_size(self, size, decimal_places=2):
for unit in ["B", "KB", "MB", "GB", "TB"]:
@@ -343,15 +349,38 @@ class InputBox(QLabel):
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
ext = event.mimeData().urls()[0].toLocalFile().lower()
if ext.endswith(".txt") or ext.endswith(".epub") or ext.endswith(".pdf"):
event.acceptProposedAction()
return
urls = event.mimeData().urls()
if urls:
ext = urls[0].toLocalFile().lower()
if ext.endswith(".txt") or ext.endswith(".epub") or ext.endswith(".pdf"):
event.acceptProposedAction()
# Set hover style based on current state
if self.styleSheet().find(self.STYLE_ACTIVE) != -1:
self.setStyleSheet(f"QLabel {{ {self.STYLE_ACTIVE} }} QLabel:hover {{ {self.STYLE_ACTIVE_HOVER} }} {self.STYLE_ACTIVE_HOVER}")
elif self.styleSheet().find(self.STYLE_ERROR) != -1:
self.setStyleSheet(f"QLabel {{ {self.STYLE_ERROR} }} QLabel:hover {{ {self.STYLE_ERROR_HOVER} }} {self.STYLE_ERROR_HOVER}")
else:
self.setStyleSheet(f"QLabel {{ {self.STYLE_DEFAULT} }} QLabel:hover {{ {self.STYLE_DEFAULT_HOVER} }} {self.STYLE_DEFAULT_HOVER}")
return
event.ignore()
def dragLeaveEvent(self, event):
# Restore the style based on current state
if self.styleSheet().find(self.STYLE_ACTIVE) != -1:
self.setStyleSheet(f"QLabel {{ {self.STYLE_ACTIVE} }} QLabel:hover {{ {self.STYLE_ACTIVE_HOVER} }}")
elif self.styleSheet().find(self.STYLE_ERROR) != -1:
self.setStyleSheet(f"QLabel {{ {self.STYLE_ERROR} }} QLabel:hover {{ {self.STYLE_ERROR_HOVER} }}")
else:
self.setStyleSheet(f"QLabel {{ {self.STYLE_DEFAULT} }} QLabel:hover {{ {self.STYLE_DEFAULT_HOVER} }}")
event.accept()
def dropEvent(self, event):
if event.mimeData().hasUrls():
file_path = event.mimeData().urls()[0].toLocalFile()
urls = event.mimeData().urls()
if not urls:
event.ignore()
return
file_path = urls[0].toLocalFile()
win = self.window()
if file_path.lower().endswith(".txt"):
win.selected_file, win.selected_file_type = file_path, "txt"
@@ -642,7 +671,7 @@ class abogen(QWidget):
self.voice_combo.setCurrentIndex(idx)
# If a profile is selected at startup, load voices and language
if self.selected_profile_name:
from voice_profiles import load_profiles
from abogen.voice_profiles import load_profiles
entry = load_profiles().get(self.selected_profile_name, {})
if isinstance(entry, dict):
@@ -706,11 +735,11 @@ class abogen(QWidget):
self.btn_manage_queue.setEnabled(True)
self.btn_manage_queue.clicked.connect(self.manage_queue)
queue_row.addWidget(self.btn_manage_queue)
self.btn_start_queue = QPushButton("Clear Queue", self)
self.btn_start_queue.setFixedHeight(40)
self.btn_start_queue.setEnabled(False)
self.btn_start_queue.clicked.connect(self.clear_queue)
queue_row.addWidget(self.btn_start_queue)
self.btn_clear_queue = QPushButton("Clear Queue", self)
self.btn_clear_queue.setFixedHeight(40)
self.btn_clear_queue.setEnabled(False)
self.btn_clear_queue.clicked.connect(self.clear_queue)
queue_row.addWidget(self.btn_clear_queue)
container_layout.addWidget(self.queue_row_widget)
self.log_text = QTextEdit(self)
self.log_text.setReadOnly(True)
@@ -1026,6 +1055,9 @@ class abogen(QWidget):
self.setLayout(outer_layout)
self.populate_profiles_in_voice_combo()
# Initialize flag to track if input box was cleared by queue
self.input_box_cleared_by_queue = False
def open_file_dialog(self):
if self.is_converting:
return
@@ -1255,7 +1287,7 @@ class abogen(QWidget):
if isinstance(data, str) and data.startswith("profile:"):
pname = data.split(":", 1)[1]
self.selected_profile_name = pname
from voice_profiles import load_profiles
from abogen.voice_profiles import load_profiles
entry = load_profiles().get(pname, {})
# set mixed voices and language
@@ -1288,7 +1320,7 @@ class abogen(QWidget):
self.subtitle_combo.setEnabled(False)
def update_subtitle_combo_for_profile(self, profile_name):
from voice_profiles import load_profiles
from abogen.voice_profiles import load_profiles
entry = load_profiles().get(profile_name, {})
lang = entry.get("language") if isinstance(entry, dict) else None
@@ -1398,7 +1430,7 @@ class abogen(QWidget):
def enable_disable_queue_buttons(self):
enabled = bool(self.queued_items)
self.btn_start_queue.setEnabled(enabled)
self.btn_clear_queue.setEnabled(enabled)
# Update Manage Queue button text with count
if enabled:
self.btn_manage_queue.setText(f"Manage Queue ({len(self.queued_items)})")
@@ -1434,15 +1466,18 @@ class abogen(QWidget):
return self.queued_items
def add_to_queue(self):
if not self.selected_file:
# Use the file currently displayed in the input box
file_to_queue = self.displayed_file_path if self.displayed_file_path else self.selected_file
if not file_to_queue:
self.input_box.set_error("Please add a file.")
return
actual_subtitle_mode = self.get_actual_subtitle_mode()
voice_formula = self.get_voice_formula()
selected_lang = self.get_selected_lang(voice_formula)
item = QueuedItem(
file_name=self.selected_file,
item_queue = QueuedItem(
file_name=file_to_queue,
lang_code=selected_lang,
speed=self.speed_slider.value() / 100.0,
voice=voice_formula,
@@ -1457,23 +1492,24 @@ class abogen(QWidget):
# Prevent adding duplicate items to the queue
for queued_item in self.queued_items:
if (
queued_item.file_name == item.file_name and
queued_item.lang_code == item.lang_code and
queued_item.speed == item.speed and
queued_item.voice == item.voice and
queued_item.save_option == item.save_option and
queued_item.output_folder == item.output_folder and
queued_item.subtitle_mode == item.subtitle_mode and
queued_item.output_format == item.output_format and
queued_item.total_char_count == item.total_char_count and
getattr(queued_item, "replace_single_newlines", False) == item.replace_single_newlines
queued_item.file_name == item_queue.file_name and
queued_item.lang_code == item_queue.lang_code and
queued_item.speed == item_queue.speed and
queued_item.voice == item_queue.voice and
queued_item.save_option == item_queue.save_option and
queued_item.output_folder == item_queue.output_folder and
queued_item.subtitle_mode == item_queue.subtitle_mode and
queued_item.output_format == item_queue.output_format and
getattr(queued_item, "replace_single_newlines", False) == item_queue.replace_single_newlines
):
QMessageBox.warning(self, "Duplicate Item", "This item is already in the queue.")
return
self.enqueue(item)
print("Adding:", item_queue)
self.enqueue(item_queue)
# Clear input after adding to queue
self.input_box.clear_input()
self.input_box_cleared_by_queue = True # Set flag
self.enable_disable_queue_buttons()
def clear_queue(self):
@@ -1505,18 +1541,18 @@ class abogen(QWidget):
def start_next_queued_item(self):
if self.current_queue_index < len(self.queued_items):
item = self.queued_items[self.current_queue_index]
self.selected_file = item.file_name
self.selected_lang = item.lang_code
self.speed_slider.setValue(int(item.speed * 100))
self.selected_voice = item.voice
self.save_option = item.save_option
self.selected_output_folder = item.output_folder
self.subtitle_mode = item.subtitle_mode
self.selected_format = item.output_format
self.char_count = item.total_char_count
self.replace_single_newlines = getattr(item, "replace_single_newlines", False)
self.start_conversion()
queued_item = self.queued_items[self.current_queue_index]
self.selected_file = queued_item.file_name
self.selected_lang = queued_item.lang_code
self.speed_slider.setValue(int(queued_item.speed * 100))
self.selected_voice = queued_item.voice
self.save_option = queued_item.save_option
self.selected_output_folder = queued_item.output_folder
self.subtitle_mode = queued_item.subtitle_mode
self.selected_format = queued_item.output_format
self.char_count = queued_item.total_char_count
self.replace_single_newlines = getattr(queued_item, "replace_single_newlines", False)
self.start_conversion(from_queue=True)
else:
# Queue finished, reset index
self.current_queue_index = 0
@@ -1542,7 +1578,7 @@ class abogen(QWidget):
def get_selected_lang(self, voice_formula) -> str:
if self.selected_profile_name:
from voice_profiles import load_profiles
from abogen.voice_profiles import load_profiles
entry = load_profiles().get(self.selected_profile_name, {})
selected_lang = entry.get("language")
else:
@@ -1560,7 +1596,7 @@ class abogen(QWidget):
else self.subtitle_mode
)
def start_conversion(self):
def start_conversion(self, from_queue=False):
if not self.selected_file:
self.input_box.set_error("Please add a file.")
return
@@ -1624,6 +1660,7 @@ class abogen(QWidget):
start_time=self.start_time,
total_char_count=self.char_count,
use_gpu=self.gpu_ok,
from_queue=from_queue,
) # Use gpu_ok status
# Pass the displayed file path to the log_updated signal handler in ConversionThread
self.conversion_thread.display_path = display_path
@@ -1695,11 +1732,13 @@ class abogen(QWidget):
if self.displayed_file_path
else self.selected_file
)
# Check if the file exists before trying to set file info
if display_path and os.path.exists(display_path):
self.input_box.set_file_info(display_path)
# Only repopulate if not cleared by queue
if not getattr(self, 'input_box_cleared_by_queue', False):
if display_path and os.path.exists(display_path):
self.input_box.set_file_info(display_path)
else:
self.input_box.clear_input()
else:
# Clear the input if the file no longer exists
self.input_box.clear_input()
return
@@ -1738,8 +1777,6 @@ class abogen(QWidget):
def reset_ui(self):
try:
self.restore_input_box()
self.input_box.clear_input() # Reset text and style
self.etr_label.hide() # Hide ETR label
self.progress_bar.setValue(0)
self.progress_bar.hide()
@@ -1762,6 +1799,8 @@ class abogen(QWidget):
pass # Ignore error if not connected
self.btn_start.clicked.connect(self.start_conversion)
self.enable_disable_queue_buttons()
self.restore_input_box()
self.input_box.clear_input() # Reset text and style
except Exception as e:
self._show_error_message_box("Reset Error", f"Could not reset UI:\n{e}")
@@ -1777,11 +1816,13 @@ class abogen(QWidget):
self.displayed_file_path if self.displayed_file_path else self.selected_file
)
# Check if the file exists before trying to set file info
if display_path and os.path.exists(display_path):
self.input_box.set_file_info(display_path)
# Only repopulate if not cleared by queue
if not getattr(self, 'input_box_cleared_by_queue', False):
if display_path and os.path.exists(display_path):
self.input_box.set_file_info(display_path)
else:
self.input_box.clear_input()
else:
# Clear the input if the file no longer exists
self.input_box.clear_input()
# Ensure open file button is visible when going back
@@ -1868,7 +1909,7 @@ class abogen(QWidget):
voice_formula = " + ".join(filter(None, components))
voice_to_cache = voice_formula
if self.selected_profile_name:
from voice_profiles import load_profiles
from abogen.voice_profiles import load_profiles
entry = load_profiles().get(self.selected_profile_name, {})
lang_to_cache = entry.get("language")
else:
@@ -2002,7 +2043,7 @@ class abogen(QWidget):
voice = " + ".join(filter(None, components))
# determine language: use profile setting, else explicit mixer selection, else fallback to first voice code
if self.selected_profile_name:
from voice_profiles import load_profiles
from abogen.voice_profiles import load_profiles
entry = load_profiles().get(self.selected_profile_name, {})
lang = entry.get("language")
@@ -2151,11 +2192,13 @@ class abogen(QWidget):
if self.displayed_file_path
else self.selected_file
)
# Check if the file exists before trying to set file info
if display_path and os.path.exists(display_path):
self.input_box.set_file_info(display_path)
# Only repopulate if not cleared by queue
if not getattr(self, 'input_box_cleared_by_queue', False):
if display_path and os.path.exists(display_path):
self.input_box.set_file_info(display_path)
else:
self.input_box.clear_input()
else:
# Clear the input if the file no longer exists
self.input_box.clear_input()
if (
hasattr(self, "conversion_thread")
@@ -2213,7 +2256,7 @@ class abogen(QWidget):
def show_chapter_options_dialog(self, chapter_count):
"""Show dialog to ask user about chapter processing options when chapters are detected in a .txt file"""
from conversion import ChapterOptionsDialog
from abogen.conversion import ChapterOptionsDialog
dialog = ChapterOptionsDialog(chapter_count, parent=self)
dialog.setWindowModality(Qt.ApplicationModal)
@@ -2458,7 +2501,7 @@ class abogen(QWidget):
def reveal_config_in_explorer(self):
"""Open the configuration file location in file explorer."""
from utils import get_user_config_path
from abogen.utils import get_user_config_path
try:
config_path = get_user_config_path()
@@ -2490,7 +2533,7 @@ class abogen(QWidget):
"""Create a desktop shortcut to this program using PowerShell."""
import sys
from platformdirs import user_desktop_dir
from utils import create_process
from abogen.utils import create_process
try:
if platform.system() == "Windows":
@@ -2625,7 +2668,7 @@ Categories=AudioVideo;Audio;Utility;
save_config(self.config)
def show_voice_formula_dialog(self):
from voice_profiles import load_profiles
from abogen.voice_profiles import load_profiles
profiles = load_profiles()
initial_state = None
+3 -3
View File
@@ -7,9 +7,9 @@ from PyQt5.QtCore import qInstallMessageHandler, QtMsgType
# Add the directory to Python path
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
from gui import abogen
from utils import get_resource_path
from constants import PROGRAM_NAME, VERSION
from abogen.gui import abogen
from abogen.utils import get_resource_path
from abogen.constants import PROGRAM_NAME, VERSION
# Set environment variables for AMD ROCm
os.environ["MIOPEN_FIND_MODE"] = "FAST"
+11 -15
View File
@@ -16,7 +16,7 @@ from PyQt5.QtWidgets import (
QSizePolicy,
)
from PyQt5.QtCore import QFileInfo, Qt
from constants import COLORS
from abogen.constants import COLORS
from copy import deepcopy
from PyQt5.QtGui import QFontMetrics
@@ -243,26 +243,23 @@ class QueueManager(QDialog):
items = self.listwidget.selectedItems()
if not items:
return
import os
from PyQt5.QtWidgets import QMessageBox
display_names = [item.text() for item in items]
to_remove = []
for q in self.queue:
if os.path.basename(q.file_name) in display_names:
to_remove.append(q)
# Remove by index to ensure correct mapping
rows = sorted([self.listwidget.row(item) for item in items], reverse=True)
# Warn user if removing multiple files
if len(to_remove) > 1:
if len(rows) > 1:
reply = QMessageBox.question(
self,
"Confirm Remove",
f"Are you sure you want to remove {len(to_remove)} selected items from the queue?",
f"Are you sure you want to remove {len(rows)} selected items from the queue?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No
)
if reply != QMessageBox.Yes:
return
for item in to_remove:
self.queue.remove(item)
for row in rows:
if 0 <= row < len(self.queue):
del self.queue[row]
self.process_queue()
self.update_button_states()
@@ -328,7 +325,7 @@ class QueueManager(QDialog):
return attrs
def add_files_from_paths(self, file_paths):
from utils import calculate_text_length
from abogen.utils import calculate_text_length
from PyQt5.QtWidgets import QMessageBox
import os
current_attrs = self.get_current_attributes()
@@ -378,9 +375,8 @@ class QueueManager(QDialog):
self.update_button_states()
def add_more_files(self):
from PyQt5.QtWidgets import QFileDialog, QMessageBox
import os
from utils import calculate_text_length # import the function
from PyQt5.QtWidgets import QFileDialog
from abogen.utils import calculate_text_length # import the function
# Only allow .txt files
files, _ = QFileDialog.getOpenFileNames(self, "Select .txt files", "", "Text Files (*.txt)")
if not files:
+4 -4
View File
@@ -28,7 +28,7 @@ from PyQt5.QtWidgets import (
)
from PyQt5.QtCore import Qt, QTimer, QPoint, QRect, QSize
from PyQt5.QtGui import QPixmap, QIcon
from constants import (
from abogen.constants import (
VOICES_INTERNAL,
SUPPORTED_LANGUAGES_FOR_SUBTITLE_GENERATION,
LANGUAGE_DESCRIPTIONS,
@@ -36,8 +36,8 @@ from constants import (
)
import re
import platform
from utils import get_resource_path
from voice_profiles import (
from abogen.utils import get_resource_path
from abogen.voice_profiles import (
load_profiles,
save_profiles,
delete_profile,
@@ -1084,7 +1084,7 @@ class VoiceFormulaDialog(QDialog):
self, "Import Profiles", "", "JSON Files (*.json)"
)
if path:
from voice_profiles import load_profiles, save_profiles
from abogen.voice_profiles import load_profiles, save_profiles
# Try to read the file and count profiles
try:
+1 -2
View File
@@ -1,6 +1,5 @@
import re
from constants import VOICES_INTERNAL
from abogen.constants import VOICES_INTERNAL
# Calls parsing and loads the voice to gpu or cpu
def get_new_voice(pipeline, formula, use_gpu):
+1 -1
View File
@@ -1,6 +1,6 @@
import os
import json
from utils import get_user_config_path
from abogen.utils import get_user_config_path
def _get_profiles_path():