Update clipboard-to-tts.py

This commit is contained in:
erew123 authored and GitHub committed 2024-07-17 13:41:38 +01:00
1 parent c31e1f68b5
commit b03e08405e
1 file changed
+156 -27
+156 -27
View File
@@ -1,12 +1,28 @@
import sys import sys
import time import time
import signal import signal
import json
import warnings
import pyperclip import pyperclip
import requests import requests
from PyQt5.QtWidgets import QApplication, QSystemTrayIcon, QMenu, QWidget, QVBoxLayout, QLabel, QLineEdit, QPushButton from PyQt5.QtWidgets import (QApplication, QSystemTrayIcon, QMenu, QWidget, QVBoxLayout, QLabel,
QLineEdit, QPushButton, QMessageBox, QComboBox, QSlider)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon
# Suppress the specific warning
warnings.filterwarnings("ignore", category=UserWarning, module="charset_normalizer")
SETTINGS_FILE = "tts_settings.json"
TTS_SERVER_URL = "http://127.0.0.1:7851"
LANGUAGES = {
"ar": "Arabic", "zh-cn": "Chinese (Simplified)", "cs": "Czech", "nl": "Dutch",
"en": "English", "fr": "French", "de": "German", "hi": "Hindi (limited support)",
"hu": "Hungarian", "it": "Italian", "ja": "Japanese", "ko": "Korean",
"pl": "Polish", "pt": "Portuguese", "ru": "Russian", "es": "Spanish", "tr": "Turkish"
}
class ClipboardMonitor(QThread): class ClipboardMonitor(QThread):
text_changed = pyqtSignal(str) text_changed = pyqtSignal(str)
@@ -27,6 +43,8 @@ class ClipboardMonitor(QThread):
self.running = False self.running = False
class TTSWorker(QThread): class TTSWorker(QThread):
error_occurred = pyqtSignal(str)
def __init__(self, api_url, params): def __init__(self, api_url, params):
super().__init__() super().__init__()
self.api_url = api_url self.api_url = api_url
@@ -47,62 +65,143 @@ class TTSWorker(QThread):
def send_to_tts(self, text): def send_to_tts(self, text):
params = self.params.copy() params = self.params.copy()
params["text_input"] = text params["text_input"] = text
params["language"] = params["language"][:2] # Ensure we only send the 2-letter code
try: try:
response = requests.post(self.api_url, data=params) response = requests.post(f"{self.api_url}/api/tts-generate", data=params)
if response.status_code != 200: if response.status_code != 200:
print(f"TTS generation failed with status code: {response.status_code}") error_message = f"TTS generation failed with status code: {response.status_code}. Response: {response.text}"
print(error_message)
self.error_occurred.emit(error_message)
except requests.RequestException as e: except requests.RequestException as e:
print(f"Error sending request to TTS API: {e}") error_message = f"Error sending request to TTS API: {e}"
print(error_message)
self.error_occurred.emit(error_message)
class SettingsWindow(QWidget): class SettingsWindow(QWidget):
settings_updated = pyqtSignal(dict)
def __init__(self, tts_worker): def __init__(self, tts_worker):
super().__init__() super().__init__()
self.tts_worker = tts_worker self.tts_worker = tts_worker
self.voices = []
self.init_ui() self.init_ui()
def init_ui(self): def init_ui(self):
layout = QVBoxLayout() layout = QVBoxLayout()
self.setLayout(layout) self.setLayout(layout)
layout.addWidget(QLabel("TTS API URL:")) layout.addWidget(QLabel("AllTalk API URL:"))
self.api_url_input = QLineEdit(self.tts_worker.api_url) self.api_url_input = QLineEdit(self.tts_worker.api_url)
layout.addWidget(self.api_url_input) layout.addWidget(self.api_url_input)
layout.addWidget(QLabel("Voice:")) layout.addWidget(QLabel("Voice:"))
self.voice_input = QLineEdit(self.tts_worker.params["character_voice_gen"]) self.voice_combo = QComboBox()
layout.addWidget(self.voice_input) layout.addWidget(self.voice_combo)
layout.addWidget(QLabel("Language:"))
self.language_combo = QComboBox()
for code, name in LANGUAGES.items():
self.language_combo.addItem(f"{name} ({code})", code)
current_lang = self.tts_worker.params.get("language", "en")
index = self.language_combo.findData(current_lang)
if index >= 0:
self.language_combo.setCurrentIndex(index)
layout.addWidget(self.language_combo)
layout.addWidget(QLabel("Text Filtering:"))
self.text_filtering_input = QLineEdit(self.tts_worker.params["text_filtering"])
layout.addWidget(self.text_filtering_input)
layout.addWidget(QLabel("Playback Volume:"))
self.volume_slider = QSlider(Qt.Horizontal)
self.volume_slider.setRange(1, 10)
self.volume_slider.setValue(int(float(self.tts_worker.params["autoplay_volume"]) * 10))
layout.addWidget(self.volume_slider)
save_button = QPushButton("Save") save_button = QPushButton("Save")
save_button.clicked.connect(self.save_settings) save_button.clicked.connect(self.save_settings)
layout.addWidget(save_button) layout.addWidget(save_button)
self.setWindowTitle("TTS Settings") refresh_button = QPushButton("Refresh Voices")
self.setGeometry(300, 300, 300, 150) refresh_button.clicked.connect(self.refresh_voices)
layout.addWidget(refresh_button)
self.setWindowTitle("AllTalk Clipboard TTS")
self.setGeometry(300, 300, 300, 400)
self.refresh_voices()
def refresh_voices(self):
try:
response = requests.get(f"{self.tts_worker.api_url}/api/voices")
if response.status_code == 200:
data = response.json()
if data["status"] == "success" and "voices" in data:
self.voices = data["voices"]
self.voice_combo.clear()
for voice in self.voices:
self.voice_combo.addItem(voice)
if self.voices:
current_voice = self.tts_worker.params["character_voice_gen"]
if current_voice in self.voices:
self.voice_combo.setCurrentText(current_voice)
else:
self.voice_combo.setCurrentIndex(0)
else:
QMessageBox.warning(self, "Error", "Failed to fetch voices: Unexpected response format")
else:
QMessageBox.warning(self, "Error", f"Failed to fetch voices. Status code: {response.status_code}")
except requests.RequestException as e:
QMessageBox.warning(self, "Error", f"Failed to fetch voices: {str(e)}")
def save_settings(self): def save_settings(self):
self.tts_worker.api_url = self.api_url_input.text() new_settings = {
self.tts_worker.params["character_voice_gen"] = self.voice_input.text() "api_url": self.api_url_input.text(),
self.close() "params": {
"character_voice_gen": self.voice_combo.currentText(),
"language": self.language_combo.currentData(),
"text_filtering": self.text_filtering_input.text(),
"output_file_name": "clipboard_tts",
"output_file_timestamp": "true",
"autoplay": "true",
"autoplay_volume": str(self.volume_slider.value() / 10.0)
}
}
self.settings_updated.emit(new_settings)
self.hide()
class TTSApp(QSystemTrayIcon): class TTSApp(QSystemTrayIcon):
def __init__(self, app): def __init__(self, app):
super().__init__(parent=app) super().__init__(parent=app)
self.app = app self.app = app
self.load_settings()
self.init_ui() self.init_ui()
def init_ui(self): def load_settings(self):
self.tts_worker = TTSWorker( try:
api_url="http://127.0.0.1:7851/api/tts-generate", with open(SETTINGS_FILE, 'r') as f:
params={ self.settings = json.load(f)
"text_filtering": "standard", except FileNotFoundError:
"character_voice_gen": "female_01.wav", self.settings = {
"language": "en", "api_url": TTS_SERVER_URL,
"output_file_name": "clipboard_tts", "params": {
"output_file_timestamp": "true", "text_filtering": "standard",
"autoplay": "true", "character_voice_gen": "",
"autoplay_volume": "0.8" "language": "en",
"output_file_name": "clipboard_tts",
"output_file_timestamp": "true",
"autoplay": "true",
"autoplay_volume": "0.8"
}
} }
)
def save_settings(self):
with open(SETTINGS_FILE, 'w') as f:
json.dump(self.settings, f)
def init_ui(self):
self.tts_worker = TTSWorker(self.settings["api_url"], self.settings["params"])
self.tts_worker.error_occurred.connect(self.show_error_message)
self.tts_worker.start() self.tts_worker.start()
self.clipboard_monitor = ClipboardMonitor() self.clipboard_monitor = ClipboardMonitor()
@@ -123,6 +222,7 @@ class TTSApp(QSystemTrayIcon):
self.setContextMenu(menu) self.setContextMenu(menu)
self.settings_window = SettingsWindow(self.tts_worker) self.settings_window = SettingsWindow(self.tts_worker)
self.settings_window.settings_updated.connect(self.update_settings)
def on_text_changed(self, text): def on_text_changed(self, text):
self.tts_worker.add_text(text) self.tts_worker.add_text(text)
@@ -138,23 +238,50 @@ class TTSApp(QSystemTrayIcon):
def show_settings(self): def show_settings(self):
self.settings_window.show() self.settings_window.show()
def update_settings(self, new_settings):
self.settings = new_settings
self.tts_worker.api_url = new_settings["api_url"]
self.tts_worker.params = new_settings["params"]
self.save_settings()
self.showMessage("TTS App", "Settings updated successfully")
def show_error_message(self, message):
QMessageBox.critical(None, "Error", message)
def exit_app(self): def exit_app(self):
self.clipboard_monitor.stop() self.clipboard_monitor.stop()
self.tts_worker.quit() self.tts_worker.quit()
QApplication.instance().quit() QApplication.instance().quit()
def check_server_ready(url, timeout=10):
start_time = time.time()
while time.time() - start_time < timeout:
try:
response = requests.get(f"{url}/api/ready")
if response.status_code == 200 and response.text == "Ready":
return True
except requests.RequestException:
pass
time.sleep(1)
return False
def signal_handler(signal, frame): def signal_handler(signal, frame):
print("[Clipboard to TTS] Exiting...")
QApplication.instance().quit() QApplication.instance().quit()
if __name__ == "__main__": if __name__ == "__main__":
print("[AllTalk TTS] AllTalk Clipboard to TTS is starting...") print("[Clipboard to TTS] AllTalk Clipboard to TTS is starting...")
print("[AllTalk TTS] Press Ctrl+C to exit")
if not check_server_ready(TTS_SERVER_URL):
print("[Clipboard to TTS] Error: AllTalk TTS server is not ready. Please start the AllTalk server and try again.")
sys.exit(1)
signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGINT, signal_handler)
app = QApplication(sys.argv) app = QApplication(sys.argv)
if not QSystemTrayIcon.isSystemTrayAvailable(): if not QSystemTrayIcon.isSystemTrayAvailable():
print("System tray is not available on this system.") print("[Clipboard to TTS] System tray is not available on this system.")
sys.exit(1) sys.exit(1)
tts_app = TTSApp(app) tts_app = TTSApp(app)
@@ -164,4 +291,6 @@ if __name__ == "__main__":
timer.start(500) timer.start(500)
timer.timeout.connect(lambda: None) timer.timeout.connect(lambda: None)
print("[Clipboard to TTS] AllTalk Clipboard to TTS is running... Check your system tray for the icon.")
print("[Clipboard to TTS] Press Ctrl+C to exit")
sys.exit(app.exec_()) sys.exit(app.exec_())