Spaces:
Sleeping
Sleeping
File size: 3,234 Bytes
c42f4ef | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | """Command line: python -m mrag {ingest,ask,stats,reset}"""
from __future__ import annotations
import argparse
import json
import logging
import shutil
import sys
from pathlib import Path
from .config import Config
def main(argv: list[str] | None = None) -> int:
ap = argparse.ArgumentParser(prog="mrag", description="Multimodal RAG with free local models")
ap.add_argument("--config", help="JSON config file (env vars MRAG_* override)")
ap.add_argument("--data-dir")
ap.add_argument("-v", "--verbose", action="store_true")
sub = ap.add_subparsers(dest="cmd", required=True)
p = sub.add_parser("ingest", help="index files / folders (pdf, docx, images, txt/md)")
p.add_argument("paths", nargs="+")
p.add_argument("--force", action="store_true", help="re-index unchanged files")
p = sub.add_parser("ask", help="ask a question")
p.add_argument("question")
p.add_argument("--backend", choices=["ollama", "openai", "extractive"])
p.add_argument("--model")
p.add_argument("--url")
p.add_argument("--no-stream", action="store_true")
p.add_argument("--show-context", action="store_true")
p.add_argument("--json", action="store_true", help="machine-readable output")
sub.add_parser("stats", help="index statistics")
sub.add_parser("reset", help="delete the index and extracted assets")
a = ap.parse_args(argv)
logging.basicConfig(level=logging.INFO if a.verbose else logging.WARNING, format="%(levelname)s %(message)s")
over = {"data_dir": a.data_dir}
if a.cmd == "ask":
over.update(llm_backend=a.backend, llm_model=a.model, llm_url=a.url)
cfg = Config.load(a.config, **over)
if a.cmd == "reset":
d = Path(cfg.data_dir)
if d.exists():
shutil.rmtree(d)
print(f"removed {d}")
return 0
from .pipeline import MultimodalRAG
rag = MultimodalRAG(cfg)
try:
if a.cmd == "ingest":
stats = rag.ingest(a.paths, force=a.force, progress=lambda m: print(m, file=sys.stderr))
print(json.dumps(stats, indent=2))
return 1 if stats["errors"] else 0
if a.cmd == "stats":
print(json.dumps(rag.stats(), indent=2))
return 0
stream = not (a.no_stream or a.json)
res = rag.ask(a.question, stream=stream)
if a.json:
print(json.dumps({
"answer": res["answer"],
"texts": [vars(t) for t in res["texts"]],
"images": [vars(i) for i in res["images"]],
}, indent=2, default=str))
return 0
if a.show_context:
for i, t in enumerate(res["texts"], 1):
print(f"[{i}] {Path(t.source).name} p.{t.page} ({t.kind}): {t.text[:160]}...")
for i, im in enumerate(res["images"], 1):
print(f"[Img {i}] {Path(im.source).name} p.{im.page} {im.why} -> {im.path}")
print("-" * 60)
if stream:
for piece in res["answer"]:
print(piece, end="", flush=True)
print()
else:
print(res["answer"])
return 0
finally:
rag.close()
if __name__ == "__main__":
raise SystemExit(main())
|