AI_Menu_Search / scripts /01_generate_descriptions.py
Juhaha
HF Spaces 데모 배포 (Streamlit + Qdrant 임베디드, 색인 빌드타임 생성)
fbd1091
Raw
History Blame Contribute Delete
4.44 kB
"""
Step 1: GPT-4.1 mini로 메뉴별 Description 자동 생성
실행:
python scripts/01_generate_descriptions.py
python scripts/01_generate_descriptions.py --input data/raw/real_menus.json
python scripts/01_generate_descriptions.py --input data/raw/real_menus.json --async
결과: data/generated/menu_descriptions.jsonl
증분 생성 지원:
- 이미 생성된 menu_id는 자동으로 스킵 (API 비용/시간 절약)
- 신규 메뉴만 GPT 호출 후 기존 jsonl에 append
- 재실행해도 기존 데이터 변경 없음
--async 플래그:
- 비동기 병렬 처리 (동시 10개 요청)
- 901개 기준 약 5분 (순차 대비 4배 빠름)
- Azure rate limit 초과 시 --concurrency 값을 낮추세요
"""
import argparse
import json
import jsonlines
import sys
import time
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
from config import RAW_DIR, GENERATED_DIR
from core.llm_client import LLMClient
def load_existing_ids(output_path: Path) -> set:
"""기존 jsonl에서 이미 생성된 menu_id 집합 반환. 파일 없으면 빈 집합."""
if not output_path.exists():
return set()
existing_ids = set()
with jsonlines.open(output_path, mode="r") as reader:
for item in reader:
mid = item.get("menu_id")
if mid:
existing_ids.add(mid)
return existing_ids
def main():
parser = argparse.ArgumentParser(description="GPT로 메뉴 description 자동 생성")
parser.add_argument(
"--input",
default=str(RAW_DIR / "sample_menus.json"),
help="입력 JSON 파일 경로 (기본값: data/raw/sample_menus.json)"
)
parser.add_argument(
"--async", dest="use_async",
action="store_true",
help="비동기 병렬 처리 사용 (기본: 순차)"
)
parser.add_argument(
"--concurrency",
type=int,
default=10,
help="비동기 모드 동시 요청 수 (기본: 10, rate limit 초과 시 낮추세요)"
)
args = parser.parse_args()
raw_path = Path(args.input)
if not raw_path.is_absolute():
raw_path = Path(__file__).parent.parent / raw_path
if not raw_path.exists():
print(f"[오류] 입력 파일이 없습니다: {raw_path}")
sys.exit(1)
menus = json.loads(raw_path.read_text(encoding="utf-8"))
GENERATED_DIR.mkdir(parents=True, exist_ok=True)
output_path = GENERATED_DIR / "menu_descriptions.jsonl"
# ── 증분 처리: 이미 생성된 메뉴 스킵 ────────────────────────────────────
existing_ids = load_existing_ids(output_path)
new_menus = [m for m in menus if m["menu_id"] not in existing_ids]
print(f"전체 메뉴: {len(menus)}개")
print(f"기존 생성 완료: {len(existing_ids)}개 (스킵)")
print(f"신규 생성 대상: {len(new_menus)}개\n")
if not new_menus:
print("[완료] 모든 메뉴가 이미 생성되어 있습니다. 재실행 불필요.")
return
# ── 신규 메뉴만 GPT 호출 ─────────────────────────────────────────────────
client = LLMClient()
start = time.time()
if args.use_async:
print(f"[비동기 모드] 동시 {args.concurrency}개 요청으로 생성 중...")
new_descriptions = client.generate_batch_async(
new_menus,
pass_keywords=True,
concurrency=args.concurrency,
)
else:
print("[순차 모드] 1건씩 순차 생성 중...")
new_descriptions = client.generate_batch(new_menus, pass_keywords=True)
elapsed = time.time() - start
print(f"\n소요 시간: {elapsed:.1f}초 ({elapsed/60:.1f}분)")
# ── 기존 jsonl에 append (mode="a") ───────────────────────────────────────
with jsonlines.open(output_path, mode="a") as writer:
for desc in new_descriptions:
writer.write(desc)
total_in_file = len(existing_ids) + len(new_descriptions)
print(f"\n[완료] {output_path}")
print(f" 신규 추가: {len(new_descriptions)}개")
print(f" 파일 내 총 항목: {total_in_file}개")
if __name__ == "__main__":
main()