修改日志结构
This commit is contained in:
@@ -187,11 +187,12 @@ def toggle_ai_image_panel(self):
|
||||
# ---------------- 列表 / 选中 ----------------
|
||||
|
||||
|
||||
def reload_ai_image_list(self):
|
||||
def reload_ai_image_list(self, auto_select_first=True):
|
||||
"""重新扫描缓存并刷新列表。
|
||||
|
||||
按 ``session_id`` 分组:每个会话用一行不可选的分隔头(``── 会话 #N · 时间 ──``),
|
||||
其下列出该轮生成的所有图片。会话按"最近使用"倒序,组内按时间倒序。
|
||||
auto_select_first: 是否自动选中第一张图片(默认 True)。
|
||||
"""
|
||||
self.ai_image_records = _svc.list_records()
|
||||
self.ai_image_listbox.delete(0, tk.END)
|
||||
@@ -222,7 +223,7 @@ def reload_ai_image_list(self):
|
||||
flat.append(rec)
|
||||
# 替换为按显示顺序展平后的列表,便于其它逻辑(前一张/后一张等)
|
||||
self.ai_image_records = flat
|
||||
if self.ai_image_records:
|
||||
if self.ai_image_records and auto_select_first:
|
||||
# 选中第一张实际记录
|
||||
for row, ridx in enumerate(self._ai_image_row_map):
|
||||
if ridx is not None:
|
||||
@@ -333,7 +334,7 @@ def _start_new_session(self):
|
||||
return
|
||||
_svc.reset_session()
|
||||
self.ai_image_status_var.set("已开启新对话")
|
||||
reload_ai_image_list(self)
|
||||
reload_ai_image_list(self, auto_select_first=False)
|
||||
|
||||
|
||||
def _session_id_for_row(self, row: int) -> str:
|
||||
@@ -372,8 +373,7 @@ def _update_request_progress(self):
|
||||
if not getattr(self, "_ai_image_requesting", False):
|
||||
self._ai_image_progress_job = None
|
||||
return
|
||||
phases = ["后端处理中…", "正在生成图片…", "正在下载结果…", "即将完成…"]
|
||||
self.ai_image_status_var.set(phases[self._ai_image_progress_phase % len(phases)])
|
||||
self.ai_image_status_var.set("正在生成图片…")
|
||||
self._ai_image_progress_phase += 1
|
||||
self._ai_image_progress_job = self.root.after(900, lambda: _update_request_progress(self))
|
||||
|
||||
|
||||
@@ -1,8 +1,22 @@
|
||||
import logging
|
||||
import threading
|
||||
from datetime import datetime
|
||||
import tkinter as tk
|
||||
import ttkbootstrap as ttk
|
||||
|
||||
|
||||
# 与 app.logging_setup 共享的映射;放在这里避免循环 import
|
||||
_GUI_LEVEL_TO_LOG = {
|
||||
"debug": logging.DEBUG,
|
||||
"info": logging.INFO,
|
||||
"success": logging.INFO,
|
||||
"warning": logging.WARNING,
|
||||
"error": logging.ERROR,
|
||||
"separator": logging.INFO,
|
||||
"blank": logging.DEBUG,
|
||||
}
|
||||
|
||||
|
||||
class PQLogGUI(ttk.Frame):
|
||||
VALID_LEVELS = {"info", "success", "warning", "error", "debug", "separator", "blank"}
|
||||
|
||||
@@ -10,6 +24,8 @@ class PQLogGUI(ttk.Frame):
|
||||
super().__init__(parent)
|
||||
self._line_count = 0
|
||||
self._max_lines = 1500
|
||||
# 与 stdlib logging 联通的 logger,由 logging_setup 配置 file handler
|
||||
self._logger = logging.getLogger("pq.gui")
|
||||
self.create_widgets()
|
||||
|
||||
def create_widgets(self):
|
||||
@@ -62,13 +78,25 @@ class PQLogGUI(ttk.Frame):
|
||||
self._configure_tags()
|
||||
self.log_text.config(state=tk.DISABLED)
|
||||
|
||||
def log(self, message, level="info"):
|
||||
def log(self, message, level="info", _from_logging=False):
|
||||
if threading.current_thread() is not threading.main_thread():
|
||||
self.after(0, self.log, message, level)
|
||||
self.after(0, self.log, message, level, _from_logging)
|
||||
return
|
||||
|
||||
text = "" if message is None else str(message)
|
||||
normalized_level = self._normalize_level(level, text)
|
||||
|
||||
# 转发到 stdlib logging,落到文件(_from_logging=True 表示来源已是
|
||||
# logging,不再回写避免重复)。带 _from_gui 标记,TkLogHandler 会跳过。
|
||||
if not _from_logging and normalized_level != "blank":
|
||||
log_level = _GUI_LEVEL_TO_LOG.get(normalized_level, logging.INFO)
|
||||
try:
|
||||
self._logger.log(
|
||||
log_level, text, extra={"_from_gui": True}
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.log_text.config(state=tk.NORMAL)
|
||||
self._append_message(text, normalized_level)
|
||||
self.log_text.see(tk.END)
|
||||
|
||||
Reference in New Issue
Block a user