binary-husky/gpt_academic · error · RuntimeError
用户取消了程序。
Error message
用户取消了程序。
What it means
RuntimeError ('用户取消了程序。') raised by the watchdog in the ChatGPT streaming reader. observe_window[1] holds a timestamp that the Gradio UI refreshes on every tick; if it ages past watch_dog_patience (5 s) while delta content is still arriving, the bridge concludes the user pressed stop (or the UI thread died) and aborts the stream. It is a deliberate cooperative-cancellation check evaluated only when new content chunks arrive.
Source
Thrown at request_llms/bridge_chatgpt.py:214
if len(delta) == 0:
is_termination_certain = False
if (has_choices) and (chunkjson['choices'][0].get('finish_reason', 'null') == 'stop'): is_termination_certain = True
if is_termination_certain: break
else: continue # 对于不符合规范的狗屎接口,这里需要继续
if (not has_content) and has_role: continue
if (not has_content) and (not has_role): continue # raise RuntimeError("发现不标准的第三方接口:"+delta)
if has_content: # has_role = True/False
result += delta["content"]
if not console_silence: print(delta["content"], end='')
if observe_window is not None:
# 观测窗,把已经获取的数据显示出去
if len(observe_window) >= 1:
observe_window[0] += delta["content"]
# 看门狗,如果超过期限没有喂狗,则终止
if len(observe_window) >= 2:
if (time.time()-observe_window[1]) > watch_dog_patience:
raise RuntimeError("用户取消了程序。")
else: raise RuntimeError("意外Json结构:"+delta)
finish_reason = json_data.get('finish_reason', None) if json_data else None
if finish_reason == 'content_filter':
raise RuntimeError("由于提问含不合规内容被过滤。")
if finish_reason == 'length':
raise ConnectionAbortedError("正常结束,但显示Token不足,导致输出不完整,请削减单次输入的文本量。")
return result
def predict(inputs:str, llm_kwargs:dict, plugin_kwargs:dict, chatbot:ChatBotWithCookies,
history:list=[], system_prompt:str='', stream:bool=True, additional_fn:str=None):
"""
发送至chatGPT,流式获取输出。
用于基础的对话功能。
inputs 是本次问询的输入
top_p, temperature是chatGPT的内部调优参数View on GitHub (pinned to d6bde0fa54)
Solutions
- If you stopped generation deliberately, no fix is needed — re-ask the question.
- Keep the gpt_academic browser tab in the foreground and responsive during generation so the UI keeps feeding the watchdog.
- Custom callers must run a loop setting observe_window[1] = time.time() at least every few seconds for the whole stream.
- For systematically slow setups, raise watch_dog_patience in request_llms/bridge_chatgpt.py.
Example fix
# caller-side feeding loop
import threading, time
def feed_watchdog(observe_window, stop_event):
while not stop_event.is_set():
observe_window[1] = time.time()
time.sleep(1) Defensive patterns
Strategy: validation
Try / catch
try:
reply = predict_no_ui_long_connection(inputs, llm_kwargs, history, sys_prompt, observe_window=win)
except RuntimeError as e:
if e.args[0] == '用户取消了程序。' and user_pressed_stop:
acknowledge_cancel()
else:
raise # watchdog fired but nobody cancelled -> UI feeding problem Prevention
- Maintain the feeder thread updating observe_window[1] for the entire stream lifetime.
- Join/stop the feeder thread when the request ends so it can't mask later cancellations.
- Keep the Gradio tab foregrounded during long generations.
- Correlate watchdog aborts with your own cancel flag to distinguish user stops from UI stalls.
When it happens
Trigger: User clicks the stop button in the gpt_academic UI during generation; the UI thread stops updating observe_window[1] (browser tab suspended, Gradio queue stalled); the caller passes observe_window with a stale [1] timestamp and never refreshes it while content streams.
Common situations: Intentional stop mid-answer; mobile browser backgrounding the tab freezes the Gradio polling; long generations on slow relays combined with an unresponsive UI thread; plugin code copying the observe_window pattern but forgetting the feeding thread.
Related errors
AI-assisted analysis of binary-husky/gpt_academic@d6bde0fa54 (2026-08-14).
Data as JSON: /api/errors/4edae61431acfb90.
Report an issue: GitHub.