File size: 7,553 Bytes
0061c9d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
import tkinter as tk
from tkinter import messagebox
from tkinter import ttk
import json,subprocess
import random
from TTS.api import TTS
class VoiceProfile:
def __init__(self, name, voice):
self.name = name
self.voice = voice
def to_dict(self):
return {
'name': self.name,
'voice': self.voice
}
@classmethod
def from_dict(cls, profile_dict):
return cls(
profile_dict['name'],
profile_dict['voice']
)
def configure_tts(self):
# Set Festival voice
subprocess.run(["festival", "--tts", "(voice_" + self.voice + ")"])
class VoiceProfileManager:
def __init__(self, filename="voice_profiles.json"):
self.filename = filename
self.profiles = []
self.load_profiles()
def load_profiles(self):
try:
with open(self.filename, 'r') as file:
profiles_data = json.load(file)
self.profiles = [VoiceProfile.from_dict(profile) for profile in profiles_data]
except FileNotFoundError:
print(f"File '{self.filename}' not found. Starting with an empty profile list.")
self.profiles = []
def save_profiles(self):
profiles_data = [profile.to_dict() for profile in self.profiles]
with open(self.filename, 'w') as file:
json.dump(profiles_data, file, indent=4)
print(f"Profiles saved to '{self.filename}'.")
def add_profile(self, profile):
self.profiles.append(profile)
def generate_random_profile(self):
name = f"Profile-{len(self.profiles) + 1}"
voices = ["cmu_us_slt", "cmu_us_awb", "cmu_us_rms", "cmu_us_bdl"] # Example Festival voices
voice = random.choice(voices)
new_profile = VoiceProfile(name, voice)
self.add_profile(new_profile)
return new_profile
def list_profiles(self):
if not self.profiles:
return "No profiles found."
else:
profiles_list = []
for idx, profile in enumerate(self.profiles, start=1):
profiles_list.append(f"Profile {idx}: {profile.name} - Voice: {profile.voice}")
return profiles_list
def get_profile_by_name(self, profile_name):
for profile in self.profiles:
if profile.name == profile_name:
return profile
return None
class VoiceProfileTool:
def __init__(self, root):
self.root = root
self.root.title("Voice Profile Manager")
self.profile_manager = VoiceProfileManager()
self.create_widgets()
def create_widgets(self):
# Frame for profile list and operations
profile_frame = ttk.LabelFrame(self.root, text="Voice Profiles")
profile_frame.grid(row=0, column=0, padx=10, pady=10, sticky=tk.W+tk.E+tk.N+tk.S)
# Listbox to display profiles
self.profiles_listbox = tk.Listbox(profile_frame, width=50, height=10)
self.profiles_listbox.grid(row=0, column=0, padx=10, pady=10, sticky=tk.W+tk.E+tk.N+tk.S)
# Scrollbar for the listbox
scrollbar = ttk.Scrollbar(profile_frame, orient=tk.VERTICAL, command=self.profiles_listbox.yview)
scrollbar.grid(row=0, column=1, pady=10, sticky=tk.N+tk.S)
self.profiles_listbox.config(yscrollcommand=scrollbar.set)
# Button to generate random profile
generate_btn = ttk.Button(profile_frame, text="Generate Random Profile", command=self.generate_random_profile)
generate_btn.grid(row=1, column=0, padx=10, pady=5, sticky=tk.W+tk.E)
# Button to refresh profile list
refresh_btn = ttk.Button(profile_frame, text="Refresh List", command=self.refresh_profiles_list)
refresh_btn.grid(row=1, column=1, padx=10, pady=5, sticky=tk.W+tk.E)
# Frame for TTS operations
tts_frame = ttk.LabelFrame(self.root, text="Text-to-Speech (TTS)")
tts_frame.grid(row=1, column=0, padx=10, pady=10, sticky=tk.W+tk.E+tk.N+tk.S)
# Text entry for TTS input
ttk.Label(tts_frame, text="Enter text to speak:").grid(row=0, column=0, padx=10, pady=5, sticky=tk.W)
self.tts_text_entry = ttk.Entry(tts_frame, width=50)
self.tts_text_entry.grid(row=0, column=1, padx=10, pady=5, sticky=tk.W+tk.E)
# Combobox to select profile for TTS
ttk.Label(tts_frame, text="Select profile:").grid(row=1, column=0, padx=10, pady=5, sticky=tk.W)
self.profile_combobox = ttk.Combobox(tts_frame, width=48, state="readonly")
self.profile_combobox.grid(row=1, column=1, padx=10, pady=5, sticky=tk.W+tk.E)
# Button to speak text
speak_btn = ttk.Button(tts_frame, text="Speak", command=self.speak_text)
speak_btn.grid(row=2, column=1, padx=10, pady=10, sticky=tk.W+tk.E)
# Populate initial profiles list
self.refresh_profiles_list()
def refresh_profiles_list(self):
# Clear current listbox and combobox
self.profiles_listbox.delete(0, tk.END)
self.profile_combobox['values'] = []
# Load profiles from manager
profiles = self.profile_manager.list_profiles()
if profiles:
for profile in profiles:
self.profiles_listbox.insert(tk.END, profile)
self.profile_combobox['values'] += (profile.split(':')[0],) # Add profile name to combobox options
def generate_random_profile(self):
new_profile = self.profile_manager.generate_random_profile()
messagebox.showinfo("Profile Generated", f"Generated new profile: {new_profile.name}")
self.refresh_profiles_list()
def speak_text(self):
text_to_speak = self.tts_text_entry.get().strip()
selected_profile_name = self.profile_combobox.get().strip()
if not text_to_speak:
messagebox.showwarning("Input Required", "Please enter text to speak.")
return
if not selected_profile_name:
messagebox.showwarning("Profile Required", "Please select a profile.")
return
profile = self.profile_manager.get_profile_by_name(selected_profile_name)
if profile:
profile.configure_tts()
subprocess.Popen(["festival", "--tts"], stdin=subprocess.PIPE).communicate(bytes(text_to_speak, 'utf-8'))
messagebox.showinfo("Text-to-Speech", f"Text: {text_to_speak}\nProfile: {profile.name}\nVoice: {profile.voice}")
else:
messagebox.showerror("Profile Not Found", f"Profile '{selected_profile_name}' not found.")
# Main program
if __name__ == "__main__":
root = tk.Tk()
app = VoiceProfileTool(root)
root.mainloop()
""" Explanation:
Integration with piper_tts: This example uses the TTS class from piper_tts for text-to-speech synthesis. The configure_tts method in VoiceProfile class is used to set parameters (language, pitch, speaking_rate) on the TTS engine before synthesizing speech.
Tkinter GUI: The GUI interface (VoiceProfileTool class) is built using Tkinter widgets (Listbox, Entry, Combobox, Button, etc.) to manage voice profiles (list, generate random profile) and perform TTS (enter text, select profile, speak).
Profile Management: VoiceProfileManager handles loading/saving profiles from/to JSON file, generating random profiles, listing profiles, and retrieving profiles by name.
Handling TTS Output: After synthesizing speech with piper_tts, the example shows a message box with details about the synthesized text and the selected profile.
"""
|