binary-husky/gpt_academic · error · RuntimeError

Nougat解析论文失败。

Error message

Nougat解析论文失败。

What it means

Raised as RuntimeError by the Nougat paper-parsing helper when the external 'nougat' CLI ran but produced zero .mmd files under the output directory (glob(dst/'*.mmd') is empty). It means the nougat process exited without generating output — the command itself is not checked, only its result files. The lock is released before raising, so the failure is clean but uninformative.

Solutions

  1. Run the exact command manually to see nougat's stderr: nougat --out /tmp/nout path/to/paper.pdf
  2. Verify nougat is correctly installed and on PATH: which nougat && nougat --version (pip install nougat-ocr, NOT pip install nougat which is a different package)
  3. Check the dst log folder for partial output/nougat error traces left by the run
  4. If the PDF is scanned/image-only, OCR it first or use a different parser — nougat needs a text layer
  5. For very large PDFs, raise the timeout or split the document

Example fix

// before
self.nougat_with_timeout(command, cwd=os.getcwd(), timeout=3600)
res = glob.glob(os.path.join(dst, '*.mmd'))
if len(res) == 0:
    self.threadLock.release()
    raise RuntimeError("Nougat解析论文失败。")

// after
ret = self.nougat_with_timeout(command, cwd=os.getcwd(), timeout=3600)
res = glob.glob(os.path.join(dst, '*.mmd'))
if len(res) == 0:
    self.threadLock.release()
    raise RuntimeError(f"Nougat解析论文失败 (exit={getattr(ret, 'returncode', '?')}, out={dst})")
Defensive patterns

Strategy: validation

Validate before calling

import shutil, subprocess

def nougat_ready(pdf_path: str) -> tuple[bool, str]:
    if shutil.which('nougat') is None:
        return False, 'nougat not on PATH'
    if not Path(pdf_path).suffix.lower() == '.pdf':
        return False, 'input must be a .pdf'
    return True, 'ok'

Type guard

def has_text_layer(pdf_path: str) -> bool:
    """Nougat needs extractable text; scanned-only PDFs usually fail."""
    try:
        from pypdf import PdfReader
        return any(p.extract_text().strip() for p in PdfReader(pdf_path).pages[:3])
    except Exception:
        return False

Try / catch

try:
    mmd = nougat_parse(fp)
except RuntimeError as e:
    if 'Nougat' in str(e):
        log.error('nougat produced no .mmd; run `nougat --out /tmp/nout %s` manually', fp)
        mmd = fallback_pdf_to_markdown(fp)  # e.g. markitdown route
    else:
        raise

Prevention

When it happens

Trigger: nougat_with_timeout(['nougat', '--out', dst, fp]) completes but nougat crashes on the PDF (corrupt/scanned pages), nougat is a stub/wrong binary, the PDF path contains characters nougat mishandles, or the 3600s timeout silently killed the run mid-processing.

Common situations: First-run environments where nougat's model download failed or its deps (torch/pypdf) are broken; scanned/image-only PDFs with no text layer; nougat not on PATH resolves to something else (exit 0, no output); very large PDFs hitting the 1-hour timeout.

Related errors


AI-assisted analysis of binary-husky/gpt_academic@d6bde0fa54 (2026-08-14). Data as JSON: /api/errors/0a423e435cc8cd7e. Report an issue: GitHub.

Appendix: source

Thrown at crazy_functions/crazy_utils.py:630

    def NOUGAT_parse_pdf(self, fp, chatbot, history):
        from toolbox import update_ui_latest_msg

        yield from update_ui_latest_msg("正在解析论文, 请稍候。进度:正在排队, 等待线程锁...",
                                         chatbot=chatbot, history=history, delay=0)
        self.threadLock.acquire()
        import glob, threading, os
        from toolbox import get_log_folder, gen_time_str
        dst = os.path.join(get_log_folder(plugin_name='nougat'), gen_time_str())
        os.makedirs(dst)

        yield from update_ui_latest_msg("正在解析论文, 请稍候。进度:正在加载NOUGAT... (提示:首次运行需要花费较长时间下载NOUGAT参数)",
                                         chatbot=chatbot, history=history, delay=0)
        command = ['nougat', '--out', os.path.abspath(dst), os.path.abspath(fp)]
        self.nougat_with_timeout(command, cwd=os.getcwd(), timeout=3600)
        res = glob.glob(os.path.join(dst,'*.mmd'))
        if len(res) == 0:
            self.threadLock.release()
            raise RuntimeError("Nougat解析论文失败。")
        self.threadLock.release()
        return res[0]




def try_install_deps(deps, reload_m=[]):
    import subprocess, sys, importlib
    for dep in deps:
        subprocess.check_call([sys.executable, '-m', 'pip', 'install', '--user', dep])
    import site
    importlib.reload(site)
    for m in reload_m:
        importlib.reload(__import__(m))


def get_plugin_arg(plugin_kwargs, key, default):
    # 如果参数是空的

View on GitHub (pinned to d6bde0fa54)