fix: 加载动画在非 TTY 环境不再污染输出流

_generate_response_with_animation 的 show_animation 用 print("\r...")
逐帧输出情话+spinner,仅真终端能原地覆盖;被聊天前端/管道/
日志镜像捕获时每帧(10/s)变成一行垃圾混进对话显示。

- 加 sys.stdout.isatty() 守卫:非 TTY 只输出一行静态
  "AI 正在思考中…",不跑逐帧 \r 动画
- 两处清行动画行的 print("\r" + " "*80 + "\r") 也加 is_tty 守卫
- TUI 模式(tui_output_callback)本就跳过动画,不受影响

已验证:非 TTY 输出单行静态提示、TTY 仍正常逐帧动画。
This commit is contained in:
shuiyu67 committed 2026-08-07 19:29:50 +08:00
1 parent 273cdc8e76
commit c81914ab87
1 file changed
+13
+13
View File
@@ -963,6 +963,10 @@ multi 操作支持一次修改多处:
response_ready = threading.Event() response_ready = threading.Event()
response_result = [None] # 用列表存储,方便线程内修改 response_result = [None] # 用列表存储,方便线程内修改
# 是否真实交互终端:非 TTY(管道 / 日志镜像 / 聊天前端捕获 stdout)时,
# \r 无法原地覆盖,逐帧动画会污染输出流,必须禁用。
is_tty = sys.stdout.isatty()
love_sentences = [] love_sentences = []
love_file_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), LOVE_FILE_PATH) love_file_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), LOVE_FILE_PATH)
if os.path.exists(love_file_path): if os.path.exists(love_file_path):
@@ -1015,6 +1019,13 @@ multi 操作支持一次修改多处:
# ── 动画线程 ── # ── 动画线程 ──
def show_animation(): def show_animation():
# 非 TTY:只输出一行静态提示,不跑逐帧 \r 动画(避免残帧进入捕获流)
if not is_tty:
try:
print("⏳ AI 正在思考中…", flush=True)
except Exception:
pass
return
last_change_time = time.time() last_change_time = time.time()
current_sentence = random.choice(love_sentences) current_sentence = random.choice(love_sentences)
while animation_running.is_set(): while animation_running.is_set():
@@ -1058,6 +1069,7 @@ multi 操作支持一次修改多处:
# ESC 被按下 → 取消 # ESC 被按下 → 取消
if esc_pressed.is_set(): if esc_pressed.is_set():
# 清除动画行 # 清除动画行
if is_tty:
print("\r" + " " * 80 + "\r", end="", flush=True) print("\r" + " " * 80 + "\r", end="", flush=True)
print(f"\n{Fore.YELLOW}⚡ AI 请求已取消 (ESC){Style.RESET_ALL}") print(f"\n{Fore.YELLOW}⚡ AI 请求已取消 (ESC){Style.RESET_ALL}")
return "[AI请求已取消]" return "[AI请求已取消]"
@@ -1066,6 +1078,7 @@ multi 操作支持一次修改多处:
response = response_result[0] response = response_result[0]
if response: if response:
# 清除动画行后再输出 # 清除动画行后再输出
if is_tty:
print("\r" + " " * 80 + "\r", end="", flush=True) print("\r" + " " * 80 + "\r", end="", flush=True)
self._typeprint(response, Fore.CYAN) self._typeprint(response, Fore.CYAN)