feat(gui): add two startup modes (new/open project)
This commit is contained in:
+146
-12
@@ -10,6 +10,7 @@ import os
|
|||||||
import threading
|
import threading
|
||||||
import logging
|
import logging
|
||||||
import configparser
|
import configparser
|
||||||
|
import yaml
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# 设置环境
|
# 设置环境
|
||||||
@@ -63,16 +64,150 @@ class GUI(QMainWindow):
|
|||||||
|
|
||||||
self.signaller = Signaller()
|
self.signaller = Signaller()
|
||||||
self.worker_thread = None
|
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.log_signal.connect(self._append_log)
|
||||||
self.signaller.finished_signal.connect(self._on_finished)
|
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.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.setGeometry(100, 100, 700, 500)
|
||||||
|
|
||||||
|
self._clear_ui()
|
||||||
central = QWidget()
|
central = QWidget()
|
||||||
self.setCentralWidget(central)
|
self.setCentralWidget(central)
|
||||||
layout = QVBoxLayout(central)
|
layout = QVBoxLayout(central)
|
||||||
@@ -124,12 +259,11 @@ class GUI(QMainWindow):
|
|||||||
# === 按钮区 ===
|
# === 按钮区 ===
|
||||||
btn_layout = QHBoxLayout()
|
btn_layout = QHBoxLayout()
|
||||||
self.start_btn = QPushButton("开始处理")
|
self.start_btn = QPushButton("开始处理")
|
||||||
self.start_btn.clicked.connect(self._on_start)
|
self.start_btn.clicked.connect(self._on_start_new)
|
||||||
self.clear_btn = QPushButton("清空日志")
|
self.back_btn = QPushButton("返回")
|
||||||
self.clear_btn.clicked.connect(lambda: self.log_area.clear())
|
self.back_btn.clicked.connect(self._setup_start_page)
|
||||||
btn_layout.addWidget(self.start_btn)
|
btn_layout.addWidget(self.start_btn)
|
||||||
btn_layout.addWidget(self.clear_btn)
|
btn_layout.addWidget(self.back_btn)
|
||||||
btn_layout.addStretch()
|
|
||||||
layout.addLayout(btn_layout)
|
layout.addLayout(btn_layout)
|
||||||
|
|
||||||
def _select_file(self, edit, filter_str):
|
def _select_file(self, edit, filter_str):
|
||||||
@@ -156,8 +290,8 @@ class GUI(QMainWindow):
|
|||||||
else:
|
else:
|
||||||
QMessageBox.critical(self, "错误", message)
|
QMessageBox.critical(self, "错误", message)
|
||||||
|
|
||||||
def _on_start(self):
|
def _on_start_new(self):
|
||||||
# 收集参数
|
"""开始新建项目流程"""
|
||||||
video_path = self.video_edit.text().strip()
|
video_path = self.video_edit.text().strip()
|
||||||
ppt_path = self.ppt_edit.text().strip()
|
ppt_path = self.ppt_edit.text().strip()
|
||||||
output_dir = self.output_edit.text().strip()
|
output_dir = self.output_edit.text().strip()
|
||||||
@@ -182,12 +316,13 @@ class GUI(QMainWindow):
|
|||||||
|
|
||||||
# 后台线程执行
|
# 后台线程执行
|
||||||
self.worker_thread = threading.Thread(
|
self.worker_thread = threading.Thread(
|
||||||
target=self._worker,
|
target=self._worker_new,
|
||||||
args=(video_path, ppt_path, output_dir, api_key, api_host)
|
args=(video_path, ppt_path, output_dir, api_key, api_host)
|
||||||
)
|
)
|
||||||
self.worker_thread.start()
|
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:
|
try:
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
|
|
||||||
@@ -217,7 +352,6 @@ class GUI(QMainWindow):
|
|||||||
|
|
||||||
# 保存配置
|
# 保存配置
|
||||||
config_path = os.path.join(output_dir, 'generated_config.yaml')
|
config_path = os.path.join(output_dir, 'generated_config.yaml')
|
||||||
import yaml
|
|
||||||
with open(config_path, 'w', encoding='utf-8') as f:
|
with open(config_path, 'w', encoding='utf-8') as f:
|
||||||
yaml.dump(config, f, allow_unicode=True, default_flow_style=False)
|
yaml.dump(config, f, allow_unicode=True, default_flow_style=False)
|
||||||
self.signaller.log_signal.emit(f"配置已保存: {config_path}")
|
self.signaller.log_signal.emit(f"配置已保存: {config_path}")
|
||||||
|
|||||||
Reference in New Issue
Block a user