Skip to content

Commit 36fd155

Browse files
committed
Ver 1.0: emotion control
1 parent b453933 commit 36fd155

10 files changed

Lines changed: 325 additions & 48 deletions

File tree

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
# fish-speech-gui
22

3-
<img src="fish/assets/example.png" width="800" />
3+
## Basic Setup
4+
5+
<img src="fish/assets/example_1_basic.png" width="800" />
6+
7+
## Text to Speech
8+
9+
<img src="fish/assets/example_1_tts.png" width="800" />
410

511
# Build from Source
612

@@ -12,6 +18,13 @@ pdm install
1218
pdm run build.py
1319
```
1420

21+
# Debug
22+
23+
```bash
24+
conda activate pyqt
25+
python fish/__main__.py
26+
```
27+
1528
# Run
1629

1730
```

fish/assets/example_1_basic.png

135 KB
Loading

fish/assets/example_1_tts.png

176 KB
Loading

fish/config.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ class Config:
2929
mp3_bitrate: int = 64
3030
opus_bitrate: int = -1000
3131

32-
chunk_length: int = 100
33-
max_new_tokens: int = 1024
32+
chunk_length: int = 200
33+
max_new_tokens: int = 0
3434
top_p: int = 700
3535
repetition_penalty: int = 1200
3636
temperature: int = 700
@@ -39,6 +39,9 @@ class Config:
3939
volume: int = 50
4040
speed: int = 100
4141

42+
font_size: int = 10
43+
font_family: str = "Microsoft YaHei UI"
44+
4245
# Plugins
4346
current_plugin: str | None = None
4447
plugins: dict[str, dict] = field(default_factory=dict)

fish/gui.py

Lines changed: 65 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
QMessageBox,
2727
QPushButton,
2828
QSlider,
29-
QTextEdit,
29+
QTabWidget,
3030
QVBoxLayout,
3131
QWidget,
3232
)
@@ -35,6 +35,7 @@
3535
from fish.config import application_path, config, load_config, save_config
3636
from fish.file import *
3737
from fish.i18n import _t, language_map
38+
from fish.input import TextEditorWidget
3839

3940

4041
class MainWindow(QWidget):
@@ -49,18 +50,16 @@ def __init__(self):
4950
self.setWindowTitle(_t("title").format(version=version))
5051

5152
self.main_layout = QVBoxLayout()
53+
self.tab_widget = QTabWidget()
54+
55+
self.tab_widget.addTab(self.create_settings_tab1(), _t("tab.page1"))
56+
self.tab_widget.addTab(self.create_settings_tab2(), _t("tab.page2"))
57+
5258
# Stick to the top
5359
self.main_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
60+
self.main_layout.addWidget(self.tab_widget)
61+
self.setup_action_buttons(self.main_layout)
5462

55-
self.setup_ui_settings()
56-
self.setup_backend_settings()
57-
self.setup_device_settings()
58-
self.setup_audio_settings()
59-
self.setup_reference_settings()
60-
self.setup_textinput_settings()
61-
self.setup_audioplayer_settings()
62-
63-
self.setup_action_buttons()
6463
self.setLayout(self.main_layout)
6564

6665
# Use size hint to set a reasonable size
@@ -69,6 +68,29 @@ def __init__(self):
6968

7069
self.files = []
7170

71+
def create_settings_tab1(self):
72+
tab1 = QWidget()
73+
layout1 = QVBoxLayout()
74+
75+
self.setup_ui_settings(layout1)
76+
self.setup_backend_settings(layout1)
77+
self.setup_device_settings(layout1)
78+
self.setup_audio_settings(layout1)
79+
self.setup_reference_settings(layout1)
80+
81+
tab1.setLayout(layout1)
82+
return tab1
83+
84+
def create_settings_tab2(self):
85+
tab2 = QWidget()
86+
layout2 = QVBoxLayout()
87+
88+
self.setup_textinput_settings(layout2)
89+
self.setup_audioplayer_settings(layout2)
90+
91+
tab2.setLayout(layout2)
92+
return tab2
93+
7294
def center(self):
7395
screen = QApplication.primaryScreen()
7496
screen_geometry = screen.availableGeometry()
@@ -77,7 +99,7 @@ def center(self):
7799
y = (screen_geometry.height() - window_geometry.height()) // 4
78100
self.move(x, y)
79101

80-
def setup_ui_settings(self):
102+
def setup_ui_settings(self, layout: QVBoxLayout):
81103
# we have language and backend settings in the first row
82104
row = QHBoxLayout()
83105
row.setAlignment(Qt.AlignmentFlag.AlignLeft)
@@ -115,9 +137,9 @@ def setup_ui_settings(self):
115137
self.load_button.clicked.connect(self.load_config)
116138
row.addWidget(self.load_button)
117139

118-
self.main_layout.addLayout(row)
140+
layout.addLayout(row)
119141

120-
def setup_device_settings(self):
142+
def setup_device_settings(self, layout: QVBoxLayout):
121143
# second row: a group box for audio device settings
122144
row = QGroupBox(_t("audio_device.name"))
123145
row_layout = QGridLayout()
@@ -165,12 +187,11 @@ def setup_device_settings(self):
165187

166188
self.input_device_combo.setFixedWidth(300)
167189
row_layout.addWidget(self.output_device_combo, 1, 1)
168-
190+
row.setMaximumHeight(100)
169191
row.setLayout(row_layout)
192+
layout.addWidget(row)
170193

171-
self.main_layout.addWidget(row)
172-
173-
def setup_audio_settings(self):
194+
def setup_audio_settings(self, layout: QVBoxLayout):
174195
# third row: a group box for audio settings
175196
row = QGroupBox(_t("audio.name"))
176197
row_layout = QGridLayout()
@@ -193,7 +214,8 @@ def setup_audio_settings(self):
193214

194215
row_layout.addWidget(QLabel(_t("audio.max_new_tokens")), 0, 3)
195216
self.max_new_tokens_slider = QSlider(Qt.Orientation.Horizontal)
196-
self.max_new_tokens_slider.setMinimum(1024)
217+
self.max_new_tokens_slider.setToolTip("0 means no limit")
218+
self.max_new_tokens_slider.setMinimum(0)
197219
self.max_new_tokens_slider.setMaximum(4096)
198220
self.max_new_tokens_slider.setSingleStep(128)
199221
self.max_new_tokens_slider.setTickInterval(128)
@@ -270,9 +292,10 @@ def setup_audio_settings(self):
270292
row_layout.addWidget(self.mp3_bitrate_combo, 2, 4)
271293

272294
row.setLayout(row_layout)
273-
self.main_layout.addWidget(row)
295+
row.setMaximumHeight(200)
296+
layout.addWidget(row)
274297

275-
def setup_reference_settings(self):
298+
def setup_reference_settings(self, layout: QVBoxLayout):
276299
row = QGroupBox()
277300
row.setTitle(_t("reference.name"))
278301
row_layout = QGridLayout()
@@ -288,8 +311,7 @@ def setup_reference_settings(self):
288311

289312
self.file_list_widget = QListWidget()
290313
# self.file_list_widget.setFixedWidth(300)
291-
self.file_list_widget.setMinimumHeight(50)
292-
self.file_list_widget.setMaximumHeight(100)
314+
self.file_list_widget.setMinimumHeight(100)
293315
self.file_list_widget.setVerticalScrollBarPolicy(
294316
Qt.ScrollBarPolicy.ScrollBarAsNeeded
295317
)
@@ -308,26 +330,19 @@ def setup_reference_settings(self):
308330
row_layout.addWidget(self.upload_button, 3, 2, 1, 1)
309331

310332
row.setLayout(row_layout)
311-
self.main_layout.addWidget(row)
333+
layout.addWidget(row)
312334

313-
def setup_textinput_settings(self):
335+
def setup_textinput_settings(self, layout: QVBoxLayout):
314336
row = QGroupBox()
315337
row.setTitle(_t("tts_input.name"))
316-
row.setFixedHeight(150)
317-
row_layout = QGridLayout()
318-
self.text_edit = QTextEdit()
319-
320-
self.text_edit.setLineWrapMode(QTextEdit.LineWrapMode.WidgetWidth)
321-
self.text_edit.setHorizontalScrollBarPolicy(
322-
Qt.ScrollBarPolicy.ScrollBarAlwaysOff
323-
)
324-
self.text_edit.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
325-
row_layout.addWidget(self.text_edit, 0, 0)
326338

339+
row_layout = QGridLayout()
340+
self.text_editor = TextEditorWidget()
341+
row_layout.addWidget(self.text_editor)
327342
row.setLayout(row_layout)
328-
self.main_layout.addWidget(row)
343+
layout.addWidget(row)
329344

330-
def setup_audioplayer_settings(self):
345+
def setup_audioplayer_settings(self, layout: QVBoxLayout):
331346
row = QGroupBox()
332347
row.setTitle(_t("tts_output.name"))
333348
row_layout = QGridLayout()
@@ -370,7 +385,7 @@ def setup_audioplayer_settings(self):
370385

371386
self.speed_slider = QSlider(Qt.Orientation.Horizontal)
372387
self.speed_slider.setRange(50, 200) # 50% 到 200% 的播放速率
373-
self.speed_slider.setValue(100) # 初始速率为 100%
388+
self.speed_slider.setValue(config.speed) # 初始速率为 100%
374389
self.speed_slider.sliderMoved.connect(self.set_speed)
375390
row_layout.addWidget(
376391
QLabel(_t("tts_output.speed") + " >>"),
@@ -400,14 +415,14 @@ def setup_audioplayer_settings(self):
400415
self.save_audio_path.setPlaceholderText(_t("tts_output.save_audio_input"))
401416
self.save_audio_path.setText(f"{config.save_path}")
402417
row_layout.addWidget(self.save_audio_path, 3, 1, 1, 4)
403-
418+
row.setMaximumHeight(200)
404419
row.setLayout(row_layout)
405420

406421
self.player.positionChanged.connect(self.update_position)
407422
self.player.durationChanged.connect(self.update_duration)
408-
self.main_layout.addWidget(row)
423+
layout.addWidget(row)
409424

410-
def setup_backend_settings(self):
425+
def setup_backend_settings(self, layout: QVBoxLayout):
411426
widget = QGroupBox()
412427
widget.setTitle(_t("backend.title"))
413428
row = QHBoxLayout()
@@ -431,9 +446,10 @@ def setup_backend_settings(self):
431446
row.addWidget(self.test_button)
432447

433448
widget.setLayout(row)
434-
self.main_layout.addWidget(widget)
449+
widget.setMaximumHeight(100)
450+
layout.addWidget(widget)
435451

436-
def setup_action_buttons(self):
452+
def setup_action_buttons(self, layout: QVBoxLayout):
437453
row = QWidget()
438454
row_layout = QHBoxLayout()
439455
self.now_audio = QLabel(_t("action.audio").format(audio_name="(null)"))
@@ -452,8 +468,9 @@ def setup_action_buttons(self):
452468
self.latency_label = QLabel(_t("action.latency").format(latency=0))
453469
row_layout.addWidget(self.latency_label)
454470

471+
row.setMaximumHeight(100)
455472
row.setLayout(row_layout)
456-
self.main_layout.addWidget(row)
473+
layout.addWidget(row)
457474

458475
def change_theme(self, index):
459476
config.theme = self.theme_combo.itemData(index)
@@ -537,6 +554,10 @@ def save_config(self, save_to_file=True):
537554
config.mp3_bitrate = int(self.mp3_bitrate_combo.currentText())
538555
config.ref_id = self.ref_id_input.text()
539556
config.save_path = self.save_audio_path.text()
557+
config.speed = self.speed_slider.value()
558+
config.volume = self.volume_slider.value()
559+
config.font_size = self.text_editor.font_size_spin.value()
560+
config.font_family = self.text_editor.font_combo.currentText()
540561

541562
save_config()
542563

@@ -645,7 +666,7 @@ def start_conversion(self):
645666
self.stop_button.setEnabled(True)
646667

647668
now = datetime.datetime.now()
648-
text = self.text_edit.toPlainText()
669+
text = self.text_editor.input_edit.toPlainText()
649670

650671
audio_name = now.strftime("%Y%m%d_%H%M%S") + "_" + text[:5]
651672
audio_path = Path(self.save_audio_path.text()) / f"{audio_name}.mp3"

0 commit comments

Comments
 (0)