# 主要优化点:
# 1. 增加了多图片批量处理功能
# 2. 添加了历史记录保存和加载功能
# 3. 实现了结果导出功能(TXT/PDF/HTML)
# 4. 优化了UI布局和主题系统
# 5. 增加了模型参数配置预设
# 6. 添加了系统托盘支持
# 7. 实现了结果自动保存
import sys
import os
import base64
import json
import requests
import webbrowser
from datetime import datetime
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QPushButton, QTextEdit, QFileDialog, QGroupBox, QSlider,
QDoubleSpinBox, QProgressBar, QSplitter, QMessageBox,
QListWidget, QListWidgetItem, QSystemTrayIcon, QMenu, QAction,
QComboBox, QTabWidget, QScrollArea, QCheckBox)
from PyQt5.QtGui import (QPixmap, QFont, QPalette, QColor, QTextCursor, QIcon,
QTextDocumentWriter, QTextDocument)
from PyQt5.QtCore import Qt, QSize, QThread, pyqtSignal, QTimer, QSettings
# 配置OLLAMA API设置
OLLAMA_HOST = "http://localhost:11434"
HISTORY_FILE = "history.json"
SETTINGS_FILE = "settings.ini"
class EnhancedListWidgetItem(QListWidgetItem):
"""增强的列表项,支持图标和状态显示"""
def __init__(self, text, is_title=False, icon=None, parent=None):
super().__init__(text, parent)
self.is_title = is_title
if icon:
self.setIcon(icon)
if is_title:
self.setSizeHint(QSize(200, 35))
font = QFont("Microsoft YaHei UI", 10, QFont.Bold)
self.setFont(font)
self.setForeground(QColor("#64ffda"))
self.setFlags(Qt.NoItemFlags)
self.setBackground(QColor("#112240"))
class ModelLoaderThread(QThread):
# ...保持原有实现...
class ImageAnalysisThread(QThread):
# ...保持原有实现...
class ExportThread(QThread):
export_finished = pyqtSignal(str, bool)
def __init__(self, content, file_path, format_type, parent=None):
super().__init__(parent)
self.content = content
self.file_path = file_path
self.format_type = format_type
def run(self):
try:
if self.format_type == "html":
with open(self.file_path, "w", encoding="utf-8") as f:
f.write(self.content)
elif self.format_type == "txt":
with open(self.file_path, "w", encoding="utf-8") as f:
f.write(self.content)
elif self.format_type == "pdf":
doc = QTextDocument()
doc.setHtml(self.content)
writer = QTextDocumentWriter(self.file_path)
writer.write(doc)
self.export_finished.emit(self.file_path, True)
except Exception as e:
self.export_finished.emit(str(e), False)
class MultiModalApp(QMainWindow):
def __init__(self):
super().__init__()
self.image_paths = []
self.current_image_index = 0
self.history = []
self.settings = QSettings(SETTINGS_FILE, QSettings.IniFormat)
self.initUI()
self.load_settings()
self.setWindowTitle("增强版多模态大模型图像解读系统")
self.setGeometry(100, 100, 1920, 1000)
# 初始化系统托盘
self.init_tray_icon()
QTimer.singleShot(500, self.load_models)
def initUI(self):
# 创建暗色主题样式表
self.setStyleSheet("""
/* 主窗口样式 */
QMainWindow {
background-color: #0a192f;
}
/* 分组框样式 */
QGroupBox {
border: 2px solid #64ffda;
border-radius: 10px;
margin-top: 1ex;
color: #ccd6f6;
font-weight: bold;
}
/* 标签样式 */
QLabel {
color: #ccd6f6;
}
/* 按钮样式 */
QPushButton {
background-color: #112240;
color: #64ffda;
border: 1px solid #64ffda;
border-radius: 5px;
padding: 5px 10px;
font-weight: bold;
}
/* 文本框样式 */
QTextEdit {
background-color: #0a192f;
color: #a8b2d1;
border: 1px solid #64ffda;
border-radius: 5px;
padding: 5px;
font-size: 12pt;
}
/* 选项卡样式 */
QTabWidget::pane {
border: 1px solid #64ffda;
border-radius: 5px;
background: #0a192f;
}
QTabBar::tab {
background: #112240;
color: #ccd6f6;
padding: 8px;
border: 1px solid #64ffda;
border-bottom: none;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
QTabBar::tab:selected {
background: #233554;
color: #64ffda;
}
""")
# 设置主窗口布局
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
# 标题区域
title_layout = QHBoxLayout()
self.title_label = QLabel("增强版多模态大模型图像解读系统")
self.title_label.setStyleSheet("font-size: 24pt; font-weight: bold; color: #64ffda;")
title_layout.addWidget(self.title_label)
# 添加主题切换按钮
self.theme_button = QPushButton("切换主题")
self.theme_button.clicked.connect(self.toggle_theme)
title_layout.addWidget(self.theme_button)
main_layout.addLayout(title_layout)
# 主内容区域
splitter = QSplitter(Qt.Horizontal)
# 左侧控制面板
left_panel = QWidget()
left_layout = QVBoxLayout(left_panel)
# 图片预览区域(改为选项卡形式)
self.image_tabs = QTabWidget()
self.image_tabs.setTabsClosable(True)
self.image_tabs.tabCloseRequested.connect(self.close_image_tab)
left_layout.addWidget(self.image_tabs)
# 控制面板区域
control_tabs = QTabWidget()
# 模型控制选项卡
model_tab = QWidget()
self.setup_model_tab(model_tab)
control_tabs.addTab(model_tab, "模型设置")
# 参数控制选项卡
param_tab = QWidget()
self.setup_param_tab(param_tab)
control_tabs.addTab(param_tab, "参数设置")
# 预设控制选项卡
preset_tab = QWidget()
self.setup_preset_tab(preset_tab)
control_tabs.addTab(preset_tab, "预设管理")
left_layout.addWidget(control_tabs)
# 右侧结果面板
right_panel = QWidget()
right_layout = QVBoxLayout(right_panel)
# 结果展示区域
result_tabs = QTabWidget()
# 分析结果选项卡
self.result_tab = QWidget()
self.setup_result_tab(self.result_tab)
result_tabs.addTab(self.result_tab, "分析结果")
# 历史记录选项卡
self.history_tab = QWidget()
self.setup_history_tab(self.history_tab)
result_tabs.addTab(self.history_tab, "历史记录")
right_layout.addWidget(result_tabs)
# 添加面板到分割器
splitter.addWidget(left_panel)
splitter.addWidget(right_panel)
splitter.setSizes([800, 1100])
main_layout.addWidget(splitter)
# 状态栏
self.status_bar = self.statusBar()
self.status_bar.setStyleSheet("background-color: #112240; color: #64ffda;")
self.progress_bar = QProgressBar()
self.progress_bar.setRange(0, 100)
self.status_bar.addPermanentWidget(self.progress_bar)
self.status_bar.showMessage("系统已就绪")
def setup_model_tab(self, tab):
layout = QVBoxLayout(tab)
# 模型选择区域
model_group = QGroupBox("模型选择")
model_layout = QVBoxLayout()
self.model_list = QListWidget()
self.model_list.setMaximumHeight(150)
self.model_list.addItem("正在加载模型...")
self.refresh_models_button = QPushButton("刷新模型列表")
self.refresh_models_button.clicked.connect(self.load_models)
model_layout.addWidget(self.model_list)
model_layout.addWidget(self.refresh_models_button)
model_group.setLayout(model_layout)
layout.addWidget(model_group)
# 图片操作区域
image_group = QGroupBox("图片操作")
image_layout = QVBoxLayout()
self.load_button = QPushButton("加载图片")
self.load_button.clicked.connect(self.load_image)
self.load_multiple_button = QPushButton("批量加载图片")
self.load_multiple_button.clicked.connect(self.load_multiple_images)
self.clear_images_button = QPushButton("清除所有图片")
self.clear_images_button.clicked.connect(self.clear_all_images)
image_layout.addWidget(self.load_button)
image_layout.addWidget(self.load_multiple_button)
image_layout.addWidget(self.clear_images_button)
image_group.setLayout(image_layout)
layout.addWidget(image_group)
# 分析控制区域
control_group = QGroupBox("分析控制")
control_layout = QVBoxLayout()
self.analyze_button = QPushButton("分析当前图片")
self.analyze_button.clicked.connect(self.analyze_image)
self.analyze_button.setEnabled(False)
self.analyze_all_button = QPushButton("批量分析所有图片")
self.analyze_all_button.clicked.connect(self.analyze_all_images)
self.analyze_all_button.setEnabled(False)
self.stop_button = QPushButton("停止分析")
self.stop_button.clicked.connect(self.stop_analysis)
self.stop_button.setEnabled(False)
control_layout.addWidget(self.analyze_button)
control_layout.addWidget(self.analyze_all_button)
control_layout.addWidget(self.stop_button)
control_group.setLayout(control_layout)
layout.addWidget(control_group)
def setup_param_tab(self, tab):
layout = QVBoxLayout(tab)
# 温度控制
temp_group = QGroupBox("温度控制")
temp_layout = QHBoxLayout()
self.temp_slider = QSlider(Qt.Horizontal)
self.temp_slider.setRange(0, 100)
self.temp_slider.setValue(50)
self.temp_value = QDoubleSpinBox()
self.temp_value.setRange(0.0, 1.0)
self.temp_value.setSingleStep(0.1)
self.temp_value.setValue(0.5)
self.temp_value.setDecimals(1)
self.temp_slider.valueChanged.connect(lambda val: self.temp_value.setValue(val / 100))
self.temp_value.valueChanged.connect(lambda val: self.temp_slider.setValue(int(val * 100)))
temp_layout.addWidget(self.temp_slider)
temp_layout.addWidget(self.temp_value)
temp_group.setLayout(temp_layout)
layout.addWidget(temp_group)
# Token控制
token_group = QGroupBox("Token控制")
token_layout = QHBoxLayout()
self.token_spin = QDoubleSpinBox()
self.token_spin.setRange(100, 5000)
self.token_spin.setValue(1000)
self.token_spin.setSingleStep(100)
token_layout.addWidget(QLabel("最大Token:"))
token_layout.addWidget(self.token_spin)
token_group.setLayout(token_layout)
layout.addWidget(token_group)
# 提示词区域
prompt_group = QGroupBox("提示词设置")
prompt_layout = QVBoxLayout()
self.prompt_edit = QTextEdit()
self.prompt_edit.setPlainText("请用中文详细描述这张图片的内容,要求描述清晰、有条理,分段落呈现,各段首行按要求缩进2个汉字。")
prompt_layout.addWidget(self.prompt_edit)
prompt_group.setLayout(prompt_layout)
layout.addWidget(prompt_group)
def setup_preset_tab(self, tab):
layout = QVBoxLayout(tab)
# 预设管理
preset_group = QGroupBox("预设管理")
preset_layout = QVBoxLayout()
self.preset_combo = QComboBox()
self.preset_combo.addItems(["默认预设", "详细描述", "创意写作", "技术分析"])
button_layout = QHBoxLayout()
self.load_preset_button = QPushButton("加载预设")
self.load_preset_button.clicked.connect(self.load_preset)
self.save_preset_button = QPushButton("保存预设")
self.save_preset_button.clicked.connect(self.save_preset)
self.delete_preset_button = QPushButton("删除预设")
self.delete_preset_button.clicked.connect(self.delete_preset)
button_layout.addWidget(self.load_preset_button)
button_layout.addWidget(self.save_preset_button)
button_layout.addWidget(self.delete_preset_button)
preset_layout.addWidget(self.preset_combo)
preset_layout.addLayout(button_layout)
preset_group.setLayout(preset_layout)
layout.addWidget(preset_group)
# 自动保存设置
auto_save_group = QGroupBox("自动保存设置")
auto_save_layout = QVBoxLayout()
self.auto_save_check = QCheckBox("自动保存分析结果")
self.auto_save_check.setChecked(True)
self.auto_save_path_button = QPushButton("选择保存路径")
self.auto_save_path_button.clicked.connect(self.select_auto_save_path)
self.auto_save_path_label = QLabel("默认保存位置: 程序目录/results")
self.auto_save_path_label.setWordWrap(True)
auto_save_layout.addWidget(self.auto_save_check)
auto_save_layout.addWidget(self.auto_save_path_button)
auto_save_layout.addWidget(self.auto_save_path_label)
auto_save_group.setLayout(auto_save_layout)
layout.addWidget(auto_save_group)
def setup_result_tab(self, tab):
layout = QVBoxLayout(tab)
# 结果展示区域
result_group = QGroupBox("分析结果")
result_layout = QVBoxLayout()
self.result_edit = QTextEdit()
self.result_edit.setReadOnly(True)
# 结果操作按钮
button_layout = QHBoxLayout()
self.save_result_button = QPushButton("保存结果")
self.save_result_button.clicked.connect(self.save_result)
self.copy_result_button = QPushButton("复制结果")
self.copy_result_button.clicked.connect(self.copy_result)
self.clear_result_button = QPushButton("清除结果")
self.clear_result_button.clicked.connect(self.clear_results)
button_layout.addWidget(self.save_result_button)
button_layout.addWidget(self.copy_result_button)
button_layout.addWidget(self.clear_result_button)
result_layout.addWidget(self.result_edit)
result_layout.addLayout(button_layout)
result_group.setLayout(result_layout)
layout.addWidget(result_group)
def setup_history_tab(self, tab):
layout = QVBoxLayout(tab)
# 历史记录区域
history_group = QGroupBox("历史记录")
history_layout = QVBoxLayout()
self.history_list = QListWidget()
self.history_list.itemDoubleClicked.connect(self.load_history_item)
# 历史操作按钮
button_layout = QHBoxLayout()
self.load_history_button = QPushButton("加载历史")
self.load_history_button.clicked.connect(self.load_history)
self.clear_history_button = QPushButton("清除历史")
self.clear_history_button.clicked.connect(self.clear_history)
button_layout.addWidget(self.load_history_button)
button_layout.addWidget(self.clear_history_button)
history_layout.addWidget(self.history_list)
history_layout.addLayout(button_layout)
history_group.setLayout(history_layout)
layout.addWidget(history_group)
def init_tray_icon(self):
"""初始化系统托盘图标"""
self.tray_icon = QSystemTrayIcon(self)
self.tray_icon.setIcon(QIcon(":/icons/app_icon.png"))
tray_menu = QMenu()
show_action = QAction("显示窗口", self)
show_action.triggered.connect(self.show_normal)
tray_menu.addAction(show_action)
exit_action = QAction("退出", self)
exit_action.triggered.connect(self.close)
tray_menu.addAction(exit_action)
self.tray_icon.setContextMenu(tray_menu)
self.tray_icon.show()
# 托盘图标点击事件
self.tray_icon.activated.connect(self.tray_icon_clicked)
def show_normal(self):
"""从托盘恢复窗口显示"""
self.showNormal()
self.activateWindow()
def tray_icon_clicked(self, reason):
"""处理托盘图标点击事件"""
if reason == QSystemTrayIcon.DoubleClick:
self.show_normal()
def toggle_theme(self):
"""切换主题"""
if self.theme_button.text() == "切换主题":
# 切换到浅色主题
self.setStyleSheet("""
QMainWindow {
background-color: #f5f5f5;
}
QGroupBox {
border: 2px solid #2c3e50;
border-radius: 10px;
margin-top: 1ex;
color: #2c3e50;
font-weight: bold;
}
QLabel {
color: #2c3e50;
}
QPushButton {
background-color: #ecf0f1;
color: #2c3e50;
border: 1px solid #bdc3c7;
border-radius: 5px;
padding: 5px 10px;
font-weight: bold;
}
QTextEdit {
background-color: #ffffff;
color: #2c3e50;
border: 1px solid #bdc3c7;
border-radius: 5px;
padding: 5px;
font-size: 12pt;
}
""")
self.theme_button.setText("切换回暗色")
self.title_label.setStyleSheet("font-size: 24pt; font-weight: bold; color: #2c3e50;")
self.status_bar.setStyleSheet("background-color: #ecf0f1; color: #2c3e50;")
else:
# 切换回暗色主题
self.setStyleSheet("""
QMainWindow {
background-color: #0a192f;
}
QGroupBox {
border: 2px solid #64ffda;
border-radius: 10px;
margin-top: 1ex;
color: #ccd6f6;
font-weight: bold;
}
QLabel {
color: #ccd6f6;
}
QPushButton {
background-color: #112240;
color: #64ffda;
border: 1px solid #64ffda;
border-radius: 5px;
padding: 5px 10px;
font-weight: bold;
}
QTextEdit {
background-color: #0a192f;
color: #a8b2d1;
border: 1px solid #64ffda;
border-radius: 5px;
padding: 5px;
font-size: 12pt;
}
""")
self.theme_button.setText("切换主题")
self.title_label.setStyleSheet("font-size: 24pt; font-weight: bold; color: #64ffda;")
self.status_bar.setStyleSheet("background-color: #112240; color: #64ffda;")
def load_settings(self):
"""加载程序设置"""
self.settings.beginGroup("MainWindow")
self.restoreGeometry(self.settings.value("geometry", self.saveGeometry()))
self.restoreState(self.settings.value("windowState", self.saveState()))
self.settings.endGroup()
# 加载历史记录
self.load_history()
def save_settings(self):
"""保存程序设置"""
self.settings.beginGroup("MainWindow")
self.settings.setValue("geometry", self.saveGeometry())
self.settings.setValue("windowState", self.saveState())
self.settings.endGroup()
# 保存历史记录
self.save_history()
def load_image(self):
"""加载单张图片"""
file_path, _ = QFileDialog.getOpenFileName(
self, "选择图片", "",
"图片文件 (*.png *.jpg *.jpeg *.bmp *.gif)"
)
if file_path:
self.add_image_tab(file_path)
def load_multiple_images(self):
"""批量加载多张图片"""
file_paths, _ = QFileDialog.getOpenFileNames(
self, "选择多张图片", "",
"图片文件 (*.png *.jpg *.jpeg *.bmp *.gif)"
)
if file_paths:
for file_path in file_paths:
self.add_image_tab(file_path)
def add_image_tab(self, file_path):
"""添加图片选项卡"""
try:
pixmap = QPixmap(file_path)
if pixmap.isNull():
raise Exception("无法加载图片文件,可能格式不支持或文件已损坏")
scroll_area = QScrollArea()
scroll_area.setWidgetResizable(True)
image_label = QLabel()
image_label.setPixmap(pixmap.scaled(
scroll_area.width(), scroll_area.height(),
Qt.KeepAspectRatio, Qt.SmoothTransformation
))
image_label.setAlignment(Qt.AlignCenter)
scroll_area.setWidget(image_label)
tab_index = self.image_tabs.addTab(
scroll_area, os.path.basename(file_path)
)
self.image_tabs.setCurrentIndex(tab_index)
self.image_paths.append(file_path)
self.analyze_button.setEnabled(True)
self.analyze_all_button.setEnabled(True)
self.status_bar.showMessage(f"已加载图片: {os.path.basename(file_path)}")
# 更新当前图片索引
self.current_image_index = tab_index
except Exception as e:
self.status_bar.showMessage(f"错误: {str(e)}")
self.show_error_dialog("图片加载错误", f"无法加载图片:\n{str(e)}")
def close_image_tab(self, index):
"""关闭图片选项卡"""
if index < len(self.image_paths):
self.image_paths.pop(index)
self.image_tabs.removeTab(index)
if not self.image_paths:
self.analyze_button.setEnabled(False)
self.analyze_all_button.setEnabled(False)
def clear_all_images(self):
"""清除所有图片"""
self.image_tabs.clear()
self.image_paths.clear()
self.analyze_button.setEnabled(False)
self.analyze_all_button.setEnabled(False)
self.status_bar.showMessage("已清除所有图片")
def analyze_image(self):
"""分析当前图片"""
current_index = self.image_tabs.currentIndex()
if current_index < 0 or current_index >= len(self.image_paths):
self.status_bar.showMessage("错误: 没有可分析的图片")
return
self.current_image_index = current_index
self._analyze_image(self.image_paths[current_index])
def analyze_all_images(self):
"""批量分析所有图片"""
if not self.image_paths:
self.status_bar.showMessage("错误: 没有可分析的图片")
return
# 保存当前索引
saved_index = self.current_image_index
# 逐个分析图片
for i, image_path in enumerate(self.image_paths):
self.current_image_index = i
self.image_tabs.setCurrentIndex(i)
self._analyze_image(image_path)
# 等待分析完成
while self.analysis_thread and self.analysis_thread.isRunning():
QApplication.processEvents()
# 恢复原始索引
self.current_image_index = saved_index
self.image_tabs.setCurrentIndex(saved_index)
def _analyze_image(self, image_path):
"""实际执行图片分析的内部方法"""
selected_items = self.model_list.selectedItems()
if not selected_items:
self.status_bar.showMessage("错误: 请选择模型")
return
model_name = selected_items[0].data(Qt.UserRole)
self.result_edit.clear()
self.progress_bar.setValue(0)
self.progress_bar.setFormat("正在分析图片...")
self.set_buttons_enabled(False)
self.stop_button.setEnabled(True)
temperature = self.temp_value.value()
max_tokens = int(self.token_spin.value())
prompt = self.prompt_edit.toPlainText().strip()
self.analysis_thread = ImageAnalysisThread(
model_name, image_path, temperature, max_tokens, prompt
)
self.analysis_thread.analysis_complete.connect(self.handle_analysis_result)
self.analysis_thread.progress_updated.connect(self.update_progress)
self.analysis_thread.error_occurred.connect(self.handle_analysis_error)
self.analysis_thread.stream_data.connect(self.analysis_stream_data)
self.analysis_thread.finished.connect(self.analysis_finished)
self.analysis_thread.start()
def handle_analysis_result(self, result):
"""处理分析结果"""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
selected_items = self.model_list.selectedItems()
model_name = selected_items[0].text()[2:] if selected_items else "未知模型"
# 获取当前图片文件名
image_name = os.path.basename(self.image_paths[self.current_image_index])
# 格式化结果
formatted_result = self.format_result(result)
result_html = f"""
<div style='color:#64ffda; font-size:14pt; font-weight:bold; margin-bottom:10px;'>
图片分析结果: {image_name}
</div>
<div style='color:#ccd6f6; font-size:12pt; line-height:1.6;'>{formatted_result}</div>
<div style='margin-top: 20px; color: #8892b0; font-size: 10pt; border-top: 1px solid #233554; padding-top: 10px;'>
模型: <span style='color: #64ffda;'>{model_name}</span> |
时间: <span style='color: #64ffda;'>{timestamp}</span>
</div>
"""
self.result_edit.setHtml(result_html)
self.status_bar.showMessage(f"图片分析完成: {image_name}")
# 添加到历史记录
self.add_to_history(image_name, model_name, timestamp, result_html)
# 自动保存结果
if self.auto_save_check.isChecked():
self.auto_save_result(image_name, result_html)
def add_to_history(self, image_name, model_name, timestamp, content):
"""添加到历史记录"""
history_item = {
"image": image_name,
"model": model_name,
"time": timestamp,
"content": content
}
self.history.insert(0, history_item)
self.update_history_list()
def update_history_list(self):
"""更新历史记录列表"""
self.history_list.clear()
for item in self.history[:50]: # 最多显示50条历史记录
list_item = QListWidgetItem(f"{item['image']} - {item['time']}")
list_item.setData(Qt.UserRole, item)
self.history_list.addItem(list_item)
def load_history_item(self, item):
"""加载历史记录项"""
history_data = item.data(Qt.UserRole)
self.result_edit.setHtml(history_data["content"])
def load_history(self):
"""从文件加载历史记录"""
try:
if os.path.exists(HISTORY_FILE):
with open(HISTORY_FILE, "r", encoding="utf-8") as f:
self.history = json.load(f)
self.update_history_list()
except Exception as e:
print(f"加载历史记录失败: {str(e)}")
def save_history(self):
"""保存历史记录到文件"""
try:
with open(HISTORY_FILE, "w", encoding="utf-8") as f:
json.dump(self.history, f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"保存历史记录失败: {str(e)}")
def clear_history(self):
"""清除历史记录"""
self.history.clear()
self.history_list.clear()
def auto_save_result(self, image_name, content):
"""自动保存结果"""
try:
save_dir = self.settings.value("AutoSave/path", "results")
if not os.path.exists(save_dir):
os.makedirs(save_dir)
# 生成文件名
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
base_name = os.path.splitext(image_name)[0]
file_name = f"{base_name}_{timestamp}.html"
file_path = os.path.join(save_dir, file_name)
# 保存文件
with open(file_path, "w", encoding="utf-8") as f:
f.write(content)
self.status_bar.showMessage(f"结果已自动保存到: {file_path}")
except Exception as e:
print(f"自动保存失败: {str(e)}")
def select_auto_save_path(self):
"""选择自动保存路径"""
save_dir = QFileDialog.getExistingDirectory(
self, "选择自动保存目录",
self.settings.value("AutoSave/path", "results")
)
if save_dir:
self.settings.setValue("AutoSave/path", save_dir)
self.auto_save_path_label.setText(f"保存位置: {save_dir}")
def save_result(self):
"""保存结果到文件"""
if not self.result_edit.toPlainText():
self.status_bar.showMessage("错误: 没有可保存的内容")
return
file_path, _ = QFileDialog.getSaveFileName(
self, "保存结果", "",
"HTML文件 (*.html);;文本文件 (*.txt);;PDF文件 (*.pdf)"
)
if file_path:
format_type = "html"
if file_path.endswith(".txt"):
format_type = "txt"
elif file_path.endswith(".pdf"):
format_type = "pdf"
content = self.result_edit.toHtml() if format_type != "txt" else self.result_edit.toPlainText()
self.export_thread = ExportThread(content, file_path, format_type)
self.export_thread.export_finished.connect(self.handle_export_finished)
self.export_thread.start()
self.status_bar.showMessage("正在导出结果...")
def handle_export_finished(self, message, success):
"""处理导出完成"""
if success:
self.status_bar.showMessage(f"结果已保存到: {message}")
if message.endswith(".html"):
webbrowser.open(message)
else:
self.status_bar.showMessage(f"导出失败: {message}")
self.show_error_dialog("导出错误", f"无法保存结果:\n{message}")
def copy_result(self):
"""复制结果到剪贴板"""
self.result_edit.selectAll()
self.result_edit.copy()
self.status_bar.showMessage("结果已复制到剪贴板")
def clear_results(self):
"""清除结果"""
self.result_edit.clear()
self.status_bar.showMessage("已清除结果")
def load_preset(self):
"""加载预设"""
preset_name = self.preset_combo.currentText()
if preset_name == "默认预设":
self.temp_value.setValue(0.5)
self.token_spin.setValue(1000)
self.prompt_edit.setPlainText("请用中文详细描述这张图片的内容,要求描述清晰、有条理,分段落呈现,各段首行按要求缩进2个汉字。")
elif preset_name == "详细描述":
self.temp_value.setValue(0.3)
self.token_spin.setValue(1500)
self.prompt_edit.setPlainText("请用中文详细描述这张图片中的每一个细节,包括但不限于场景、人物、物体、颜色、空间关系等。要求描述系统全面,层次分明,每段描述一个方面。")
elif preset_name == "创意写作":
self.temp_value.setValue(0.7)
self.token_spin.setValue(2000)
self.prompt_edit.setPlainText("请根据这张图片创作一个富有想象力的故事或诗歌。要求内容生动有趣,语言优美,可以适当发挥想象力,但不要偏离图片内容太远。")
elif preset_name == "技术分析":
self.temp_value.setValue(0.2)
self.token_spin.setValue(1200)
self.prompt_edit.setPlainText("请从技术角度分析这张图片,包括但不限于构图、色彩、光线、透视等专业要素。要求分析专业准确,使用适当的专业术语。")
self.status_bar.showMessage(f"已加载预设: {preset_name}")
def save_preset(self):
"""保存当前设置为预设"""
preset_name, ok = QInputDialog.getText(
self, "保存预设", "请输入预设名称:",
QLineEdit.Normal, self.preset_combo.currentText()
)
if ok and preset_name:
# 检查是否已存在
index = self.preset_combo.findText(preset_name)
if index == -1:
self.preset_combo.addItem(preset_name)
self.preset_combo.setCurrentText(preset_name)
self.status_bar.showMessage(f"预设 '{preset_name}' 已保存")
def delete_preset(self):
"""删除预设"""
preset_name = self.preset_combo.currentText()
if preset_name in ["默认预设", "详细描述", "创意写作", "技术分析"]:
QMessageBox.warning(self, "警告", "系统预设不能被删除")
return
reply = QMessageBox.question(
self, "确认删除",
f"确定要删除预设 '{preset_name}' 吗?",
QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
index = self.preset_combo.currentIndex()
self.preset_combo.removeItem(index)
self.status_bar.showMessage(f"预设 '{preset_name}' 已删除")
def closeEvent(self, event):
"""关闭窗口事件"""
if self.analysis_thread and self.analysis_thread.isRunning():
self.analysis_thread.stop()
if self.model_loader_thread and self.model_loader_thread.isRunning():
self.model_loader_thread.terminate()
self.model_loader_thread.wait(2000)
self.save_settings()
event.accept()
if __name__ == "__main__":
def exception_handler(exctype, value, traceback):
error_msg = f"程序发生未捕获的异常:\n\n类型: {exctype.__name__}\n\n描述: {value}"
print(error_msg)
try:
app = QApplication.instance()
if app is not None:
msg = QMessageBox()
最新发布