{"record":{"id":"0a423e435cc8cd7e","repo":"binary-husky/gpt_academic","slug":"nougat","errorCode":null,"errorMessage":"Nougat解析论文失败。","messagePattern":"Nougat解析论文失败。","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"crazy_functions/crazy_utils.py","lineNumber":630,"sourceCode":"    def NOUGAT_parse_pdf(self, fp, chatbot, history):\n        from toolbox import update_ui_latest_msg\n\n        yield from update_ui_latest_msg(\"正在解析论文, 请稍候。进度：正在排队, 等待线程锁...\",\n                                         chatbot=chatbot, history=history, delay=0)\n        self.threadLock.acquire()\n        import glob, threading, os\n        from toolbox import get_log_folder, gen_time_str\n        dst = os.path.join(get_log_folder(plugin_name='nougat'), gen_time_str())\n        os.makedirs(dst)\n\n        yield from update_ui_latest_msg(\"正在解析论文, 请稍候。进度：正在加载NOUGAT... （提示：首次运行需要花费较长时间下载NOUGAT参数）\",\n                                         chatbot=chatbot, history=history, delay=0)\n        command = ['nougat', '--out', os.path.abspath(dst), os.path.abspath(fp)]\n        self.nougat_with_timeout(command, cwd=os.getcwd(), timeout=3600)\n        res = glob.glob(os.path.join(dst,'*.mmd'))\n        if len(res) == 0:\n            self.threadLock.release()\n            raise RuntimeError(\"Nougat解析论文失败。\")\n        self.threadLock.release()\n        return res[0]\n\n\n\n\ndef try_install_deps(deps, reload_m=[]):\n    import subprocess, sys, importlib\n    for dep in deps:\n        subprocess.check_call([sys.executable, '-m', 'pip', 'install', '--user', dep])\n    import site\n    importlib.reload(site)\n    for m in reload_m:\n        importlib.reload(__import__(m))\n\n\ndef get_plugin_arg(plugin_kwargs, key, default):\n    # 如果参数是空的","sourceCodeStart":612,"sourceCodeEnd":648,"githubUrl":"https://github.com/binary-husky/gpt_academic/blob/d6bde0fa54373309bd05823a49bda8da019d2c77/crazy_functions/crazy_utils.py#L612-L648","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Run the exact command manually to see nougat's stderr: nougat --out /tmp/nout path/to/paper.pdf","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)","Check the dst log folder for partial output/nougat error traces left by the run","If the PDF is scanned/image-only, OCR it first or use a different parser — nougat needs a text layer","For very large PDFs, raise the timeout or split the document"],"exampleFix":"// before\nself.nougat_with_timeout(command, cwd=os.getcwd(), timeout=3600)\nres = glob.glob(os.path.join(dst, '*.mmd'))\nif len(res) == 0:\n    self.threadLock.release()\n    raise RuntimeError(\"Nougat解析论文失败。\")\n\n// after\nret = self.nougat_with_timeout(command, cwd=os.getcwd(), timeout=3600)\nres = glob.glob(os.path.join(dst, '*.mmd'))\nif len(res) == 0:\n    self.threadLock.release()\n    raise RuntimeError(f\"Nougat解析论文失败 (exit={getattr(ret, 'returncode', '?')}, out={dst})\")","handlingStrategy":"validation","validationCode":"import shutil, subprocess\n\ndef nougat_ready(pdf_path: str) -> tuple[bool, str]:\n    if shutil.which('nougat') is None:\n        return False, 'nougat not on PATH'\n    if not Path(pdf_path).suffix.lower() == '.pdf':\n        return False, 'input must be a .pdf'\n    return True, 'ok'","typeGuard":"def has_text_layer(pdf_path: str) -> bool:\n    \"\"\"Nougat needs extractable text; scanned-only PDFs usually fail.\"\"\"\n    try:\n        from pypdf import PdfReader\n        return any(p.extract_text().strip() for p in PdfReader(pdf_path).pages[:3])\n    except Exception:\n        return False","tryCatchPattern":"try:\n    mmd = nougat_parse(fp)\nexcept RuntimeError as e:\n    if 'Nougat' in str(e):\n        log.error('nougat produced no .mmd; run `nougat --out /tmp/nout %s` manually', fp)\n        mmd = fallback_pdf_to_markdown(fp)  # e.g. markitdown route\n    else:\n        raise","preventionTips":["Pin the correct package: nougat-ocr, and verify `which nougat` before first use","Smoke-test one small PDF after install; first run downloads model weights","Pre-filter scanned PDFs (no text layer) to another parser","Budget timeout against document size — 3600s is not enough for very large PDFs on CPU"],"tags":["nougat","pdf-parsing","subprocess","ocr","python"],"backgroundTag":null,"analyzedSha":"d6bde0fa54373309bd05823a49bda8da019d2c77","analyzedAt":"2026-08-14T22:48:35.038Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}