| """ |
| Convert file Markdown (.md) sang Word (.docx) / HTML / PDF bang pandoc. |
| |
| CACH DUNG: chi can BAM CHAY (Run trong VSCode/PyCharm, hoac double-click). |
| Khong can go lenh / khong can nhap args. Chinh cau hinh o khoi CONFIG ben duoi. |
| |
| CAI 1 LAN (neu chua co): python -m pip install pypandoc_binary |
| """ |
|
|
| |
| |
| |
|
|
| |
| |
| |
| |
| INPUT = "methodology_rewrite.md" |
|
|
| |
| OUTPUT_FORMAT = "docx" |
|
|
| |
| OUTPUT_NAME = None |
|
|
| |
| |
| |
| COMBINE = ["report_front.md", "report_part1.md", "methodology_rewrite.md", "report_part4_5.md"] |
| COMBINE_OUTPUT = "report.docx" |
|
|
| |
| |
| |
|
|
| import sys |
| from pathlib import Path |
|
|
| HERE = Path(__file__).resolve().parent |
|
|
|
|
| def ensure_pypandoc(): |
| try: |
| import pypandoc |
| return |
| except ImportError: |
| print("[!] Chua co pypandoc. Dang cai 'pypandoc_binary' (kem san pandoc)...") |
| import subprocess |
| subprocess.check_call( |
| [sys.executable, "-m", "pip", "install", "--quiet", "pypandoc_binary"] |
| ) |
| print("[+] Cai xong.") |
|
|
|
|
| def convert_one(md_path: Path, to_fmt: str, out_path: Path | None) -> Path: |
| import pypandoc |
|
|
| if not md_path.exists(): |
| raise FileNotFoundError(f"Khong tim thay file: {md_path}") |
|
|
| if out_path is None: |
| out_path = md_path.with_suffix("." + to_fmt) |
|
|
| |
| extra_args = ["--toc", "--toc-depth=3", "--resource-path", str(md_path.parent)] |
| if to_fmt == "html": |
| extra_args += ["--standalone", "--mathjax", "--embed-resources"] |
| elif to_fmt == "pdf": |
| extra_args += ["-V", "geometry:margin=2.5cm"] |
|
|
| pypandoc.convert_file( |
| str(md_path), to_fmt, outputfile=str(out_path), extra_args=extra_args |
| ) |
| return out_path |
|
|
|
|
| def combine_files(names, out_name) -> Path: |
| """Gop nhieu file .md (theo thu tu) thanh 1 file dau ra duy nhat.""" |
| import pypandoc |
|
|
| parts = [] |
| for n in names: |
| p = (HERE / n) if not Path(n).is_absolute() else Path(n) |
| if not p.exists(): |
| raise FileNotFoundError(f"Khong tim thay file: {p}") |
| parts.append(p.read_text(encoding="utf-8")) |
| text = "\n\n".join(parts) |
|
|
| to_fmt = Path(out_name).suffix.lstrip(".") or "docx" |
| out_path = (HERE / out_name) if not Path(out_name).is_absolute() else Path(out_name) |
| extra_args = ["--toc", "--toc-depth=3", "--resource-path", str(HERE)] |
| if to_fmt == "html": |
| extra_args += ["--standalone", "--mathjax", "--embed-resources"] |
| pypandoc.convert_text(text, to_fmt, format="markdown", |
| outputfile=str(out_path), extra_args=extra_args) |
| return out_path |
|
|
|
|
| def resolve_inputs(inp) -> list[Path]: |
| if isinstance(inp, str) and inp.upper() == "ALL": |
| return sorted(HERE.glob("*.md")) |
| if isinstance(inp, (list, tuple)): |
| return [(HERE / x) if not Path(x).is_absolute() else Path(x) for x in inp] |
| p = Path(inp) |
| return [p if p.is_absolute() else HERE / p] |
|
|
|
|
| def main(): |
| ensure_pypandoc() |
|
|
| |
| if COMBINE: |
| try: |
| out = combine_files(COMBINE, COMBINE_OUTPUT) |
| print(f"[+] Gop {len(COMBINE)} file -> {out.name}") |
| except Exception as e: |
| print(f"[x] Loi khi gop: {e}") |
| return |
|
|
| md_files = resolve_inputs(INPUT) |
| if not md_files: |
| print("[!] Khong tim thay file .md nao de convert.") |
| return |
|
|
| many = len(md_files) > 1 |
| for md in md_files: |
| out = None |
| if OUTPUT_NAME and not many: |
| out = Path(OUTPUT_NAME) |
| if not out.is_absolute(): |
| out = HERE / out |
| try: |
| result = convert_one(md, OUTPUT_FORMAT, out) |
| print(f"[+] {md.name} -> {result.name}") |
| except Exception as e: |
| print(f"[x] Loi voi {md.name}: {e}") |
| if OUTPUT_FORMAT == "pdf": |
| print(" -> PDF can mot LaTeX engine (MiKTeX/TeX Live). " |
| "Thu doi OUTPUT_FORMAT='html' roi in PDF tu trinh duyet.") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
| |
| try: |
| if sys.stdin and sys.stdin.isatty(): |
| input("\nXong. Nhan Enter de dong...") |
| except Exception: |
| pass |
|
|