Spaces:
Sleeping
Sleeping
| """ | |
| src/data/generate_all.py | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| λ°μ΄ν°μ μμ± μ€μΌμ€νΈλ μ΄ν° CLI | |
| λͺ¨λ λ°μ΄ν°μ μ ν λ²μ λͺ λ ΉμΌλ‘ μμλλ‘ μμ±ν©λλ€. | |
| router λ¨κ³κ° e2e λ°μ΄ν°μ μ κ²Έν©λλ€ (QA_ONLY/ACTION_ONLY/BOTH κ· λ± μμ±). | |
| μ€ν μμ: | |
| # μ 체 μμ± (κΆμ₯ μ€ν μμ: text2sql β router) | |
| python -m src.data.generate_all | |
| # νΉμ νκ²λ§ μ ν | |
| python -m src.data.generate_all --text2sql | |
| python -m src.data.generate_all --router | |
| # νλΌλ―Έν° μ‘°μ | |
| python -m src.data.generate_all --n-per-label 15 --n-sql 10 | |
| # λΉ λ₯Έ ν μ€νΈ μ€ν (μλλ§ μμ±) | |
| python -m src.data.generate_all --dry-run | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import logging | |
| import sys | |
| import time | |
| from pathlib import Path | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| sys.stdout.reconfigure(encoding="utf-8", errors="replace") | |
| _ROOT_FOR_LOG = Path(__file__).resolve().parent.parent.parent | |
| _LOG_DIR = _ROOT_FOR_LOG / "logs" | |
| _LOG_DIR.mkdir(parents=True, exist_ok=True) | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format="%(asctime)s [%(levelname)s] %(message)s", | |
| handlers=[ | |
| logging.FileHandler(_LOG_DIR / "data_generation.log", encoding="utf-8"), | |
| logging.StreamHandler(sys.stdout), | |
| ], | |
| force=True, | |
| ) | |
| logger = logging.getLogger(__name__) | |
| _ROOT = Path(__file__).resolve().parent.parent.parent | |
| # --------------------------------------------------------------------------- | |
| # κΈ°λ³Έ μΆλ ₯ κ²½λ‘ | |
| # --------------------------------------------------------------------------- | |
| OUTPUTS = { | |
| "text2sql": str(_ROOT / "data" / "eval" / "text2sql_test_cases_gen.json"), | |
| "router": str(_ROOT / "data" / "eval" / "router_test_cases_gen.json"), | |
| } | |
| # --------------------------------------------------------------------------- | |
| # μμ± λ¨κ³ μ€ν ν¨μ | |
| # --------------------------------------------------------------------------- | |
| def _step_text2sql(args: argparse.Namespace) -> bool: | |
| from src.data.generate_text2sql_dataset import generate_text2sql_dataset | |
| print("\n" + "β" * 70) | |
| print(" STEP 1/2 β Text-to-SQL Dataset Generation") | |
| print("β" * 70) | |
| try: | |
| generate_text2sql_dataset( | |
| n_samples=args.n_sql, | |
| output_path=args.out_text2sql, | |
| db_path=str(_ROOT / "data" / "sap_erp.db"), | |
| seed=args.seed, | |
| append=args.append, | |
| ) | |
| return True | |
| except Exception as e: | |
| logger.error("text2sql generation failed: %s", e, exc_info=True) | |
| return False | |
| def _step_router(args: argparse.Namespace) -> bool: | |
| from src.data.generate_router_dataset import generate_router_dataset | |
| print("\n" + "β" * 70) | |
| print(" STEP 2/2 β Router + E2E Dataset Generation (QA_ONLY / ACTION_ONLY / BOTH)") | |
| print("β" * 70) | |
| try: | |
| generate_router_dataset( | |
| n_per_label=args.n_per_label, | |
| output_path=args.out_router, | |
| db_path=str(_ROOT / "data" / "sap_erp.db"), | |
| delay=args.delay, | |
| max_chunks=args.max_chunks, | |
| model_name=args.model, | |
| append=args.append, | |
| seed=args.seed, | |
| ) | |
| return True | |
| except Exception as e: | |
| logger.error("Router generation failed: %s", e, exc_info=True) | |
| return False | |
| # --------------------------------------------------------------------------- | |
| # λ©μΈ | |
| # --------------------------------------------------------------------------- | |
| def main() -> None: | |
| args = _parse_args() | |
| # --dry-run : μλλ§ λΉ λ₯΄κ² ν μ€νΈ | |
| if args.dry_run: | |
| logger.info("Dry-run mode: executing each step with a small amount of data.") | |
| args.n_sql = 10 | |
| args.n_per_label = 30 | |
| args.max_chunks = 3 | |
| # μ€νν λ¨κ³ κ²°μ (νλκ·Έ μμΌλ©΄ μ 체 μ€ν) | |
| run_all = not (args.text2sql or args.router) | |
| steps: list[tuple[str, callable]] = [] | |
| if run_all or args.text2sql: | |
| steps.append(("text2sql", _step_text2sql)) | |
| if run_all or args.router: | |
| steps.append(("router", _step_router)) | |
| print("\n" + "=" * 70) | |
| print(" SAP ERP AI Agent Dataset Generation Pipeline") | |
| print(f" Execution steps: {[s[0] for s in steps]}") | |
| print("=" * 70) | |
| t_start = time.perf_counter() | |
| results: dict[str, bool] = {} | |
| for name, fn in steps: | |
| results[name] = fn(args) | |
| if not results[name]: | |
| logger.warning("[%s] Step failed β proceeding to next step.", name) | |
| elapsed = time.perf_counter() - t_start | |
| # μ΅μ’ μμ½ | |
| print("\n" + "=" * 70) | |
| print(" Final Result Summary") | |
| print("=" * 70) | |
| for name, ok in results.items(): | |
| status = "β Success" if ok else "β Failed" | |
| print(f" {name:<12}: {status}") | |
| print(f" Total duration : {elapsed / 60:.1f} mins") | |
| print("=" * 70) | |
| # μΆλ ₯ νμΌ κ²½λ‘ μλ΄ | |
| print("\n Generated Files:") | |
| path_map = { | |
| "text2sql": args.out_text2sql, | |
| "router (= e2e)": args.out_router, | |
| } | |
| for label, path in path_map.items(): | |
| name = label.split()[0] | |
| if name in results: | |
| exists = Path(path).exists() | |
| mark = "β" if exists else "β" | |
| print(f" [{mark}] {label:<20}: {path}") | |
| # --------------------------------------------------------------------------- | |
| # CLI μ μ | |
| # --------------------------------------------------------------------------- | |
| def _parse_args() -> argparse.Namespace: | |
| parser = argparse.ArgumentParser( | |
| description="SAP ERP AI Agent μ 체 λ°μ΄ν°μ μμ± μ€μΌμ€νΈλ μ΄ν°", | |
| formatter_class=argparse.RawDescriptionHelpFormatter, | |
| epilog=""" | |
| μμ: | |
| python -m src.data.generate_all # μ 체 μ€ν | |
| python -m src.data.generate_all --dry-run # λΉ λ₯Έ ν μ€νΈ (μλ) | |
| python -m src.data.generate_all --router --n-per-label 20 | |
| python -m src.data.generate_all --text2sql --n-sql 30 | |
| """, | |
| ) | |
| # ββ λ¨κ³ μ ν ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| step_group = parser.add_argument_group("μ€ν λ¨κ³ μ ν (λ―Έμ§μ μ μ 체 μ€ν)") | |
| step_group.add_argument("--text2sql", action="store_true", help="Text-to-SQL μΌμ΄μ€ μμ±") | |
| step_group.add_argument("--router", action="store_true", help="Router + E2E μΌμ΄μ€ μμ±") | |
| # ββ μμ± νλΌλ―Έν° ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| param_group = parser.add_argument_group("μμ± νλΌλ―Έν°") | |
| param_group.add_argument( | |
| "--n-per-label", type=int, default=30, | |
| help="Router: ν΄λμ€(QA/ACTION/BOTH)λ³ μμ± μ (κΈ°λ³Έ: 30, μ΄ β 90)", | |
| ) | |
| param_group.add_argument( | |
| "--n-sql", type=int, default=10, | |
| help="Text-to-SQL: μλ리μ€λΉ μν μ (κΈ°λ³Έ: 10)", | |
| ) | |
| param_group.add_argument( | |
| "--max-chunks", type=int, default=100, | |
| help="Router: μ΅λ μ²λ¦¬ μ²ν¬ μ (κΈ°λ³Έ: 100)", | |
| ) | |
| param_group.add_argument( | |
| "--delay", type=float, default=1.5, | |
| help="API νΈμΆ κ°κ²© μ΄ (κΈ°λ³Έ: 1.5)", | |
| ) | |
| param_group.add_argument( | |
| "--seed", type=int, default=42, | |
| help="λλ€ μλ (κΈ°λ³Έ: 42)", | |
| ) | |
| param_group.add_argument( | |
| "--model", default=None, | |
| help="OpenRouter λͺ¨λΈλͺ μ€λ²λΌμ΄λ (κΈ°λ³Έ: configs.yaml worker_a)", | |
| ) | |
| param_group.add_argument( | |
| "--append", action="store_true", | |
| help="κΈ°μ‘΄ νμΌμ κ²°κ³Ό μΆκ° (κΈ°λ³Έ: μλ‘ μμ±)", | |
| ) | |
| param_group.add_argument( | |
| "--dry-run", action="store_true", | |
| help="μλλ§ μ€ννλ λΉ λ₯Έ ν μ€νΈ λͺ¨λ", | |
| ) | |
| # ββ μΆλ ₯ κ²½λ‘ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| out_group = parser.add_argument_group("μΆλ ₯ κ²½λ‘ μ€λ²λΌμ΄λ") | |
| out_group.add_argument("--out-text2sql", default=OUTPUTS["text2sql"]) | |
| out_group.add_argument("--out-router", default=OUTPUTS["router"]) | |
| return parser.parse_args() | |
| if __name__ == "__main__": | |
| main() | |