Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| Incremental refresh orchestrator. Runs the full pipeline in order, using | |
| --since for papers and --upsert for trials to avoid full re-ingestion. | |
| State is tracked in data/.refresh_state.json. On first run (no state file), | |
| defaults to fetching papers since 2024-12-31 (end of the initial corpus window). | |
| Usage: | |
| uv run python scripts/refresh.py # incremental from last state | |
| uv run python scripts/refresh.py --since 2025-01-01 | |
| uv run python scripts/refresh.py --dry-run | |
| uv run python scripts/refresh.py --skip-papers # trials + graph only | |
| uv run python scripts/refresh.py --full-rebuild # ignore state, full re-ingest | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import subprocess | |
| import sys | |
| from datetime import date | |
| from pathlib import Path | |
| sys.path.insert(0, str(Path(__file__).parent.parent)) | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| from rich.console import Console | |
| from config import REFRESH_STATE_PATH | |
| console = Console() | |
| _SCRIPTS_DIR = Path(__file__).parent | |
| _DEFAULT_SINCE = "2024-12-31" | |
| def _load_state() -> dict: | |
| if REFRESH_STATE_PATH.exists(): | |
| return json.loads(REFRESH_STATE_PATH.read_text()) | |
| return {} | |
| def _save_state(state: dict) -> None: | |
| REFRESH_STATE_PATH.parent.mkdir(parents=True, exist_ok=True) | |
| REFRESH_STATE_PATH.write_text(json.dumps(state, indent=2)) | |
| def _run(script: str, *args: str, dry_run: bool = False) -> None: | |
| cmd = [sys.executable, str(_SCRIPTS_DIR / script), *args] | |
| console.print(f"[cyan]{'(dry-run) ' if dry_run else ''}Running:[/cyan] {' '.join(cmd)}") | |
| if dry_run: | |
| return | |
| result = subprocess.run(cmd, check=False) | |
| if result.returncode != 0: | |
| console.print(f"[red]Script {script} exited with code {result.returncode}[/red]") | |
| sys.exit(result.returncode) | |
| def main() -> None: | |
| parser = argparse.ArgumentParser(description="Incremental pipeline refresh") | |
| parser.add_argument("--since", metavar="YYYY-MM-DD", help="Override since-date for paper ingestion") | |
| parser.add_argument("--dry-run", action="store_true", help="Print what would run without executing") | |
| parser.add_argument("--skip-papers", action="store_true", help="Skip paper ingestion (trials + graph only)") | |
| parser.add_argument("--full-rebuild", action="store_true", help="Full re-ingest, ignoring state") | |
| args = parser.parse_args() | |
| state = _load_state() | |
| today = str(date.today()) | |
| if args.full_rebuild: | |
| console.print("[yellow]Full rebuild requested — ignoring refresh state[/yellow]") | |
| since_date = None | |
| elif args.since: | |
| since_date = args.since | |
| else: | |
| since_date = state.get("last_papers_ingest", _DEFAULT_SINCE) | |
| console.print(f"[bold]Candle-fire incremental refresh[/bold] — {today}") | |
| if not args.full_rebuild and not args.skip_papers: | |
| console.print(f" Fetching papers since: {since_date}") | |
| # 1. Papers | |
| if not args.skip_papers: | |
| if args.full_rebuild or since_date is None: | |
| _run("ingest_papers.py", "--skip-fulltext", "--skip-citations", dry_run=args.dry_run) | |
| else: | |
| _run("ingest_papers.py", "--since", since_date, "--skip-fulltext", "--skip-citations", dry_run=args.dry_run) | |
| # 2. Trials | |
| _run("ingest_trials.py", "--upsert", dry_run=args.dry_run) | |
| # 3. Entity extraction (auto-resumes via .progress.json) | |
| _run("extract_entities.py", dry_run=args.dry_run) | |
| # 4. Derive seeds | |
| _run("derive_seeds.py", dry_run=args.dry_run) | |
| # 5. Build graph | |
| _run("build_graph.py", dry_run=args.dry_run) | |
| # 6. Build index (idempotent — skips existing chunks) | |
| _run("build_index.py", dry_run=args.dry_run) | |
| if not args.dry_run: | |
| new_state = {**state, "last_papers_ingest": today, "last_trials_ingest": today} | |
| _save_state(new_state) | |
| console.print(f"\n[bold green]Refresh complete.[/bold green] State written to {REFRESH_STATE_PATH}") | |
| else: | |
| console.print("\n[yellow]Dry run complete — no changes made.[/yellow]") | |
| if __name__ == "__main__": | |
| main() | |