Dongjin1203/QLoRA_RAG_test
0
1"""2평가 데이터셋 생성 도구3 4실제 RFP 문서에서 질문-답변 쌍을 만들어5Ground Truth가 있는 평가 데이터셋을 생성합니다.6 7사용법:8 python create_eval_dataset.py --input data/rag_chunks_final.csv --output data/eval_dataset.json9"""10 11import json12import csv13import argparse14from pathlib import Path15from typing import List, Dict, Any16 17 18class EvalDatasetCreator:19 """평가 데이터셋 생성 클래스"""20 21 def __init__(self):22 self.dataset = {23 "metadata": {24 "version": "1.0",25 "description": "RFPilot 평가 데이터셋",26 "created_by": "manual_annotation"27 },28 "in_distribution": [],29 "out_distribution": []30 }31 32 def add_in_distribution_sample(33 self,34 query: str,35 expected_answer: str,36 category: str,37 source_doc: str = None,38 metadata: Dict[str, Any] = None39 ):40 """In-Distribution 샘플 추가"""41 sample = {42 "query": query,43 "expected_answer": expected_answer,44 "category": category,45 "expected_type": "document",46 "source_doc": source_doc,47 "metadata": metadata or {}48 }49 self.dataset["in_distribution"].append(sample)50 51 def add_out_distribution_sample(52 self,53 query: str,54 expected_answer: str,55 category: str,56 metadata: Dict[str, Any] = None57 ):58 """Out-Distribution 샘플 추가"""59 sample = {60 "query": query,61 "expected_answer": expected_answer,62 "category": category,63 "expected_type": "out_of_scope",64 "metadata": metadata or {}65 }66 self.dataset["out_distribution"].append(sample)67 68 def create_template_dataset(self):69 """템플릿 데이터셋 생성 (수동 작성용)"""70 print("📝 템플릿 데이터셋 생성 중...")71 72 # In-Distribution 템플릿73 in_dist_templates = [74 {75 "query": "사업 제안서 제출 마감일은 언제인가요?",76 "expected_answer": "2024년 3월 15일까지입니다.", # 실제 문서에서 추출77 "category": "deadline",78 "source_doc": "RFP_2024_001.hwp",79 "metadata": {"difficulty": "easy"}80 },81 {82 "query": "제안 요청서의 제출 서류는 무엇인가요?",83 "expected_answer": "기술제안서, 가격제안서, 사업자등록증, 회사소개서가 필요합니다.",84 "category": "requirements",85 "source_doc": "RFP_2024_001.hwp",86 "metadata": {"difficulty": "medium"}87 },88 {89 "query": "사업 예산 규모는 얼마인가요?",90 "expected_answer": "총 5억원입니다.",91 "category": "budget",92 "source_doc": "RFP_2024_002.hwp",93 "metadata": {"difficulty": "easy"}94 },95 ]96 97 # Out-Distribution 템플릿98 out_dist_templates = [99 {100 "query": "한국의 수도는 어디인가요?",101 "expected_answer": "서울입니다.",102 "category": "general_knowledge",103 "metadata": {"difficulty": "easy"}104 },105 {106 "query": "파이썬에서 리스트와 튜플의 차이는 무엇인가요?",107 "expected_answer": "리스트는 가변(mutable)이고, 튜플은 불변(immutable)입니다.",108 "category": "programming",109 "metadata": {"difficulty": "medium"}110 },111 ]112 113 # 데이터셋에 추가114 for sample in in_dist_templates:115 self.add_in_distribution_sample(**sample)116 117 for sample in out_dist_templates:118 self.add_out_distribution_sample(**sample)119 120 print(f"✅ 템플릿 생성 완료")121 print(f" - In-Distribution: {len(in_dist_templates)}개")122 print(f" - Out-Distribution: {len(out_dist_templates)}개")123 print(f"\n⚠️ 이 템플릿을 수정하여 실제 데이터를 채워주세요!")124 125 def load_from_csv(self, csv_path: str):126 """CSV에서 데이터셋 로드"""127 print(f"📥 CSV 로드 중: {csv_path}")128 129 with open(csv_path, 'r', encoding='utf-8') as f:130 reader = csv.DictReader(f)131 for row in reader:132 distribution = row.get('distribution', 'in_distribution')133 134 if distribution == 'in_distribution':135 self.add_in_distribution_sample(136 query=row['query'],137 expected_answer=row['expected_answer'],138 category=row['category'],139 source_doc=row.get('source_doc'),140 metadata=json.loads(row.get('metadata', '{}'))141 )142 else:143 self.add_out_distribution_sample(144 query=row['query'],145 expected_answer=row['expected_answer'],146 category=row['category'],147 metadata=json.loads(row.get('metadata', '{}'))148 )149 150 print(f"✅ CSV 로드 완료")151 152 def save_json(self, output_path: str):153 """JSON 형식으로 저장"""154 output_path = Path(output_path)155 output_path.parent.mkdir(parents=True, exist_ok=True)156 157 with open(output_path, 'w', encoding='utf-8') as f:158 json.dump(self.dataset, f, ensure_ascii=False, indent=2)159 160 print(f"💾 저장 완료: {output_path}")161 162 def save_csv_template(self, output_path: str):163 """수동 작성용 CSV 템플릿 저장"""164 output_path = Path(output_path)165 output_path.parent.mkdir(parents=True, exist_ok=True)166 167 with open(output_path, 'w', encoding='utf-8', newline='') as f:168 writer = csv.DictWriter(f, fieldnames=[169 'distribution', 'query', 'expected_answer', 170 'category', 'source_doc', 'metadata'171 ])172 writer.writeheader()173 174 # In-Distribution 예시175 writer.writerow({176 'distribution': 'in_distribution',177 'query': '사업 제안서 제출 마감일은 언제인가요?',178 'expected_answer': '2024년 3월 15일까지입니다.',179 'category': 'deadline',180 'source_doc': 'RFP_2024_001.hwp',181 'metadata': '{"difficulty": "easy"}'182 })183 184 # Out-Distribution 예시185 writer.writerow({186 'distribution': 'out_distribution',187 'query': '한국의 수도는 어디인가요?',188 'expected_answer': '서울입니다.',189 'category': 'general_knowledge',190 'source_doc': '',191 'metadata': '{"difficulty": "easy"}'192 })193 194 print(f"📄 CSV 템플릿 저장: {output_path}")195 print(f" → 이 파일을 수정하여 실제 데이터를 채워주세요!")196 197 def print_summary(self):198 """데이터셋 요약 출력"""199 print("\n" + "="*60)200 print("데이터셋 요약")201 print("="*60)202 print(f"In-Distribution: {len(self.dataset['in_distribution'])}개")203 print(f"Out-Distribution: {len(self.dataset['out_distribution'])}개")204 print(f"총 샘플: {len(self.dataset['in_distribution']) + len(self.dataset['out_distribution'])}개")205 print("="*60 + "\n")206 207 208def main():209 parser = argparse.ArgumentParser(description='평가 데이터셋 생성')210 parser.add_argument('--mode', choices=['template', 'csv'], default='template',211 help='생성 모드: template (템플릿 생성) 또는 csv (CSV에서 로드)')212 parser.add_argument('--input', type=str, help='입력 CSV 파일 경로')213 parser.add_argument('--output', type=str, default='data/eval_dataset.json',214 help='출력 JSON 파일 경로')215 parser.add_argument('--csv-template', type=str, default='data/eval_template.csv',216 help='CSV 템플릿 저장 경로')217 218 args = parser.parse_args()219 220 creator = EvalDatasetCreator()221 222 if args.mode == 'template':223 print("📝 템플릿 모드")224 creator.create_template_dataset()225 creator.save_json(args.output)226 creator.save_csv_template(args.csv_template)227 228 elif args.mode == 'csv':229 if not args.input:230 print("❌ CSV 모드에서는 --input 옵션이 필요합니다.")231 return232 233 print("📥 CSV 모드")234 creator.load_from_csv(args.input)235 creator.save_json(args.output)236 237 creator.print_summary()238 239 print("\n✅ 완료!")240 print(f"\n다음 단계:")241 print(f"1. {args.csv_template} 파일을 열어서 실제 데이터 작성")242 print(f"2. python create_eval_dataset.py --mode csv --input {args.csv_template} --output {args.output}")243 print(f"3. 생성된 {args.output}을 실험에 사용")244 245 246if __name__ == "__main__":247 main()