diff --git a/src/gui.py b/src/gui.py index c3778e6..06c4427 100644 --- a/src/gui.py +++ b/src/gui.py @@ -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"项目目录: {self.project_config.get('output_dir', 'N/A')}")) + + # 视频源 + video_src = self.project_config.get('video_src', 'N/A') + layout.addWidget(QLabel(f"视频: {video_src}")) + + # PPT 源 + ppt_src = self.project_config.get('ppt_src', 'N/A') + layout.addWidget(QLabel(f"PPT: {ppt_src}")) + + # Clips 数量 + clips = self.project_config.get('clips', []) + layout.addWidget(QLabel(f"Clips 数量: {len(clips)}")) + + # Clips 列表 + if clips: + list_label = QLabel("Clips 列表:") + 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}")