feat(gui): add two startup modes (new/open project)

This commit is contained in:
hmo
2026-05-04 00:28:40 +08:00
parent c99d05e42e
commit 5f3396378f
+146 -12
View File
@@ -10,6 +10,7 @@ import os
import threading
import logging
import configparser
import yaml
from pathlib import Path
# 设置环境
@@ -63,16 +64,150 @@ class GUI(QMainWindow):
self.signaller = Signaller()
self.worker_thread = None
self._setup_ui()
self.pipeline = None # 当前 Pipeline 实例
self.project_config = None # 当前项目配置
# 连接信号
self.signaller.log_signal.connect(self._append_log)
self.signaller.finished_signal.connect(self._on_finished)
def _setup_ui(self):
# 显示启动页
self._setup_start_page()
def _clear_ui(self):
"""清空当前 UI"""
central = self.centralWidget()
if central:
central.deleteLater()
def _setup_start_page(self):
"""启动页:新建项目 / 打开已有项目"""
self.setWindowTitle("Piano Highlight Generator - GUI")
self.setGeometry(100, 100, 500, 300)
self._clear_ui()
central = QWidget()
self.setCentralWidget(central)
layout = QVBoxLayout(central)
layout.setAlignment(Qt.AlignCenter)
# 标题
title = QLabel("Piano Highlight Generator")
title.setStyleSheet("font-size: 24px; font-weight: bold;")
title.setAlignment(Qt.AlignCenter)
layout.addWidget(title)
layout.addSpacing(40)
# 按钮
self.new_project_btn = QPushButton("新建项目")
self.new_project_btn.setMinimumHeight(50)
self.new_project_btn.clicked.connect(self._on_new_project)
layout.addWidget(self.new_project_btn)
self.open_project_btn = QPushButton("打开已有项目")
self.open_project_btn.setMinimumHeight(50)
self.open_project_btn.clicked.connect(self._on_open_project)
layout.addWidget(self.open_project_btn)
layout.addStretch()
def _on_new_project(self):
"""新建项目:切换到文件选择界面"""
self._setup_new_project_ui()
def _on_open_project(self):
"""打开已有项目"""
dir_path = QFileDialog.getExistingDirectory(self, "选择项目目录")
if not dir_path:
return
self.load_project(dir_path)
def load_project(self, output_dir):
"""
加载已有项目,加载 generated_config.yaml,显示 clip 列表
"""
config_path = os.path.join(output_dir, 'generated_config.yaml')
if not os.path.exists(config_path):
QMessageBox.critical(self, "错误", f"不是有效的项目目录:\n{config_path}")
return
with open(config_path, 'r', encoding='utf-8') as f:
self.project_config = yaml.safe_load(f)
self.project_config['output_dir'] = output_dir
# 初始化 Pipeline
self.pipeline = Pipeline(self.project_config)
# 显示项目信息(Task 9 完成后替换为完整编辑界面)
self._show_project_info()
def _show_project_info(self):
"""显示项目基本信息(临时,过渡用)"""
self.setWindowTitle("项目信息 - Piano Highlight Generator")
self.setGeometry(100, 100, 600, 400)
self._clear_ui()
central = QWidget()
self.setCentralWidget(central)
layout = QVBoxLayout(central)
# 项目路径
layout.addWidget(QLabel(f"<b>项目目录:</b> {self.project_config.get('output_dir', 'N/A')}"))
# 视频源
video_src = self.project_config.get('video_src', 'N/A')
layout.addWidget(QLabel(f"<b>视频:</b> {video_src}"))
# PPT 源
ppt_src = self.project_config.get('ppt_src', 'N/A')
layout.addWidget(QLabel(f"<b>PPT:</b> {ppt_src}"))
# Clips 数量
clips = self.project_config.get('clips', [])
layout.addWidget(QLabel(f"<b>Clips 数量:</b> {len(clips)}"))
# Clips 列表
if clips:
list_label = QLabel("<b>Clips 列表:</b>")
layout.addWidget(list_label)
for i, clip in enumerate(clips[:10]): # 只显示前10个
title = clip.get('title', clip.get('content', 'N/A'))[:50]
start = clip.get('start_time', 'N/A')
end = clip.get('end_time', 'N/A')
layout.addWidget(QLabel(f" {i+1}. [{start}-{end}] {title}"))
if len(clips) > 10:
layout.addWidget(QLabel(f" ... 还有 {len(clips) - 10}"))
layout.addStretch()
# 按钮区
btn_layout = QHBoxLayout()
self.edit_btn = QPushButton("进入编辑模式")
self.edit_btn.clicked.connect(self._setup_edit_ui) # Task 9 实现
back_btn = QPushButton("返回")
back_btn.clicked.connect(self._setup_start_page)
btn_layout.addWidget(self.edit_btn)
btn_layout.addWidget(back_btn)
layout.addLayout(btn_layout)
def _setup_edit_ui(self):
"""
编辑界面(Task 9 实现)
目前显示 TODO 提示
"""
QMessageBox.information(
self, "提示",
"编辑模式将在 Task 9 中实现\n目前可以手动编辑 generated_config.yaml 后重新运行"
)
def _setup_new_project_ui(self):
"""新建项目的文件选择界面"""
self.setWindowTitle("新建项目 - Piano Highlight Generator")
self.setGeometry(100, 100, 700, 500)
self._clear_ui()
central = QWidget()
self.setCentralWidget(central)
layout = QVBoxLayout(central)
@@ -124,12 +259,11 @@ class GUI(QMainWindow):
# === 按钮区 ===
btn_layout = QHBoxLayout()
self.start_btn = QPushButton("开始处理")
self.start_btn.clicked.connect(self._on_start)
self.clear_btn = QPushButton("清空日志")
self.clear_btn.clicked.connect(lambda: self.log_area.clear())
self.start_btn.clicked.connect(self._on_start_new)
self.back_btn = QPushButton("返回")
self.back_btn.clicked.connect(self._setup_start_page)
btn_layout.addWidget(self.start_btn)
btn_layout.addWidget(self.clear_btn)
btn_layout.addStretch()
btn_layout.addWidget(self.back_btn)
layout.addLayout(btn_layout)
def _select_file(self, edit, filter_str):
@@ -156,8 +290,8 @@ class GUI(QMainWindow):
else:
QMessageBox.critical(self, "错误", message)
def _on_start(self):
# 收集参数
def _on_start_new(self):
"""开始新建项目流程"""
video_path = self.video_edit.text().strip()
ppt_path = self.ppt_edit.text().strip()
output_dir = self.output_edit.text().strip()
@@ -182,12 +316,13 @@ class GUI(QMainWindow):
# 后台线程执行
self.worker_thread = threading.Thread(
target=self._worker,
target=self._worker_new,
args=(video_path, ppt_path, output_dir, api_key, api_host)
)
self.worker_thread.start()
def _worker(self, video_path, ppt_path, output_dir, api_key, api_host):
def _worker_new(self, video_path, ppt_path, output_dir, api_key, api_host):
"""新建项目的工作线程"""
try:
os.makedirs(output_dir, exist_ok=True)
@@ -217,7 +352,6 @@ class GUI(QMainWindow):
# 保存配置
config_path = os.path.join(output_dir, 'generated_config.yaml')
import yaml
with open(config_path, 'w', encoding='utf-8') as f:
yaml.dump(config, f, allow_unicode=True, default_flow_style=False)
self.signaller.log_signal.emit(f"配置已保存: {config_path}")