SAP-ERP-AI-Agent / src /data /generate_all.py
daisysooyeon's picture
deploy: SAP ERP AI Agent (HF Spaces docker)
50efdc6
Raw
History Blame Contribute Delete
8.66 kB
"""
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()