import
tkinter as tk
from
tkinter
import
ttk, scrolledtext, messagebox
from
kokoro_onnx
import
Kokoro
import
soundfile as sf
import
threading
import
pygame
import
time
from
functools
import
wraps
from
datetime
import
datetime
now
=
datetime.now()
formatted_time
=
now.strftime(
'%Y%m%d_%H%M'
)
VOICE_NAME
=
[
'af'
,
'af_bella'
,
'af_sarah'
,
'am_adam'
,
'am_michael'
,
'bf_emma'
,
'bf_isabella'
,
'bm_george'
,
'bm_lewis'
,
'af_nicole'
,
'af_sky'
,
]
LANG_NAME
=
[
"en-us"
,
"en-gb"
,
"fr-fr"
,
"ja"
,
"ko"
,
"cmn"
,
]
def
play_mp3(file_path):
pygame.mixer.init()
pygame.mixer.music.load(file_path)
pygame.mixer.music.play()
while
pygame.mixer.music.get_busy():
continue
pygame.mixer.music.unload()
pygame.mixer.quit()
class
TTSApp:
def
__init__(
self
, root):
self
.root
=
root
self
.root.title(
"Kokoro TTS GUI"
)
self
.kokoro
=
None
self
.create_widgets()
def
create_widgets(
self
):
ttk.Label(
self
.root, text
=
"文本朗读内容:"
).grid(row
=
0
, column
=
0
, sticky
=
"w"
, padx
=
5
, pady
=
5
)
self
.text_area
=
scrolledtext.ScrolledText(
self
.root, wrap
=
tk.WORD, width
=
60
, height
=
10
)
self
.text_area.grid(row
=
1
, column
=
0
, columnspan
=
3
, padx
=
5
, pady
=
5
)
ttk.Label(
self
.root, text
=
"音量:"
).grid(row
=
2
, column
=
0
, sticky
=
"w"
, padx
=
5
, pady
=
5
)
self
.voice_var
=
tk.StringVar(value
=
"af"
)
self
.voice_combobox
=
ttk.Combobox(
self
.root, textvariable
=
self
.voice_var, values
=
VOICE_NAME)
self
.voice_combobox.grid(row
=
2
, column
=
1
, sticky
=
"ew"
, padx
=
5
, pady
=
5
)
ttk.Label(
self
.root, text
=
"速度 (0.5-2.0):"
).grid(row
=
3
, column
=
0
, sticky
=
"w"
, padx
=
5
, pady
=
5
)
self
.speed_var
=
tk.DoubleVar(value
=
1.0
)
self
.speed_entry
=
ttk.Entry(
self
.root, textvariable
=
self
.speed_var)
self
.speed_entry.grid(row
=
3
, column
=
1
, sticky
=
"ew"
, padx
=
5
, pady
=
5
)
ttk.Label(
self
.root, text
=
"语言:"
).grid(row
=
4
, column
=
0
, sticky
=
"w"
, padx
=
5
, pady
=
5
)
self
.lang_var
=
tk.StringVar(value
=
"en-us"
)
self
.lang_entry
=
ttk.Entry(
self
.root, textvariable
=
self
.lang_var)
self
.lang_entry.grid(row
=
4
, column
=
1
, sticky
=
"ew"
, padx
=
5
, pady
=
5
)
self
.info
=
ttk.Label(
self
.root, text
=
"")
self
.info.grid(row
=
5
, column
=
1
, sticky
=
"ew"
, padx
=
5
, pady
=
5
,columnspan
=
10
)
self
.run_button
=
ttk.Button(
self
.root, text
=
"生成语音"
, command
=
self
.run_tts)
self
.run_button.grid(row
=
6
, column
=
0
, columnspan
=
3
, pady
=
10
)
self
.root.columnconfigure(
1
,weight
=
1
)
def
run_tts(
self
):
text
=
self
.text_area.get(
"1.0"
,
"end-1c"
).strip()
voice
=
self
.voice_var.get()
try
:
speed
=
float
(
self
.speed_var.get())
if
not
0.5
<
=
speed <
=
2.0
:
messagebox.showerror(
"错误"
,
"速度必须介于 0.5 和 2.0 之间"
)
return
except
ValueError:
messagebox.showerror(
"错误"
,
"速度值无效。"
)
return
lang
=
self
.lang_var.get()
if
not
text:
messagebox.showerror(
"错误"
,
"请输入文字说话."
)
return
self
.run_button.config(text
=
'处理中'
,state
=
tk.DISABLED)
threading.Thread(target
=
self
.perform_tts, args
=
(text, voice, speed, lang)).start()
def
perform_tts(
self
, text, voice, speed, lang,audio_format
=
'mp3'
):
self
.info.config(text
=
'处理中'
)
try
:
if
self
.kokoro
is
None
:
self
.kokoro
=
Kokoro(
"kokoro-v0_19.onnx"
,
"voices.bin"
)
samples, sample_rate
=
self
.kokoro.create(text,voice
=
voice,speed
=
speed,lang
=
lang)
output_file
=
f
"audio_{voice}_{formatted_time}.{audio_format}"
sf.write(output_file, samples, sample_rate)
self
.info.config(text
=
'音频生成成功,正在播放...'
)
self
.run_button.config(text
=
'正在播放'
,state
=
tk.DISABLED)
play_mp3(output_file)
self
.run_button.config(text
=
'生成语音'
,state
=
tk.NORMAL)
self
.info.config(text
=
'')
except
Exception as e:
messagebox.showerror(
"错误"
, f
"发生错误: {e}"
)
finally
:
self
.run_button.config(state
=
tk.NORMAL)
if
__name__
=
=
"__main__"
:
root
=
tk.Tk()
app
=
TTSApp(root)
root.mainloop()