diff --git a/.gitignore b/.gitignore
index e0b82c1..ddbb497 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,12 +19,12 @@ wheels/
*.egg-info/
.installed.cfg
*.egg
-data/*
+
# Virtual Environment
venv/
env/
ENV/
-.venv
+.venv/
# IDE
.vscode/
@@ -34,51 +34,69 @@ ENV/
*~
.DS_Store
+# Claude Code
+.claude/
+
# API Keys - 중요!
.env
-.env.local
-.env.development
-.env.test
-.env.production
-
+.env.*
apis/gemini_keys.yaml
-!apis/gemini_keys.yaml.template
+apis/*.yaml
+!apis/*-example.yaml
+!apis/*.template.yaml
# Logs
*.log
+logs/
# Jupyter Notebook
-.ipynb_checkpoints
+.ipynb_checkpoints/
# pytest
.pytest_cache/
.coverage
+htmlcov/
# MyPy
.mypy_cache/
.dmypy.json
dmypy.json
-# database
+# Data - 원본 데이터
+data/
+
+# Output - 생성된 결과물
+output/
+output_*/
+I_origin_*/
+
+# Temp - 임시 파일
+temp/
+
+# Archives
+*.zip
+*.tar.gz
+*.rar
+
+# Generated JSON (except input templates)
+pipeline_output*.json
+qa_difficulty_analysis_*.json
+qa_for_review_*.json
+eval_results_*.json
+
+# Keep input templates
+!test_*_input.json
+
+# Database/Token
info/
token.json
-*.json
-test_input.json
-# env
+# Docs (if generated)
.bemad/
-docs/
-pipeline_ui/backend/checkpoints/*
-pipeline_ui/backend/output/*
-pipeline_ui/backend/uploads/*
-# Frontend (Node.js)
-pipeline_ui/frontend/node_modules/*
+# Pipeline UI
+pipeline_ui/backend/checkpoints/
+pipeline_ui/backend/output/
+pipeline_ui/backend/uploads/
+pipeline_ui/frontend/node_modules/
pipeline_ui/frontend/package-lock.json
-
-
-I_origin_0/*
-I_origin_1/*
-I_origin_2/*
-
-output/*
\ No newline at end of file
diff --git a/capture_html_images.py b/capture_html_images.py
new file mode 100644
index 0000000..4491bcb
--- /dev/null
+++ b/capture_html_images.py
@@ -0,0 +1,127 @@
+"""
+Capture HTML files from output_* directories as images using Playwright.
+"""
+import argparse
+import asyncio
+from pathlib import Path
+from typing import List
+
+from playwright.async_api import async_playwright
+
+
+async def capture_html_file_async(
+ html_path: Path,
+ output_path: Path,
+ width: int = 800,
+) -> None:
+ """Capture a single HTML file as an image."""
+ html_content = html_path.read_text(encoding="utf-8")
+
+ async with async_playwright() as p:
+ browser = await p.chromium.launch(headless=True)
+ try:
+ page = await browser.new_page(viewport={"width": width, "height": 600})
+ await page.set_content(html_content)
+ await page.screenshot(path=output_path, full_page=True)
+ finally:
+ await browser.close()
+
+
+async def capture_batch_async(
+ html_files: List[Path],
+ output_dir: Path,
+ width: int = 800,
+) -> None:
+ """Capture multiple HTML files, reusing a single browser instance."""
+ async with async_playwright() as p:
+ browser = await p.chromium.launch(headless=True)
+ try:
+ for html_path in html_files:
+ output_path = output_dir / f"{html_path.stem}.png"
+ if output_path.exists():
+ print(f" [SKIP] {output_path.name} already exists")
+ continue
+
+ try:
+ html_content = html_path.read_text(encoding="utf-8")
+ page = await browser.new_page(viewport={"width": width, "height": 600})
+ await page.set_content(html_content)
+ await page.screenshot(path=output_path, full_page=True)
+ await page.close()
+ print(f" [OK] {html_path.name} -> {output_path.name}")
+ except Exception as e:
+ print(f" [ERROR] {html_path.name}: {e}")
+ finally:
+ await browser.close()
+
+
+def main():
+ parser = argparse.ArgumentParser(description="Capture HTML files as images")
+ parser.add_argument(
+ "--output-dirs",
+ nargs="+",
+ default=None,
+ help="Specific output directories to process (e.g., output_academic output_finance)",
+ )
+ parser.add_argument(
+ "--width",
+ type=int,
+ default=800,
+ help="Viewport width for rendering (default: 800)",
+ )
+ parser.add_argument(
+ "--force",
+ action="store_true",
+ help="Overwrite existing images",
+ )
+ args = parser.parse_args()
+
+ base_dir = Path(__file__).parent
+
+ # Find output_* directories
+ if args.output_dirs:
+ output_dirs = [base_dir / d for d in args.output_dirs]
+ else:
+ output_dirs = sorted(base_dir.glob("output_*"))
+ output_dirs = [d for d in output_dirs if d.is_dir()]
+
+ if not output_dirs:
+ print("No output_* directories found.")
+ return
+
+ print(f"Found {len(output_dirs)} output directories to process")
+
+ for output_dir in output_dirs:
+ html_dir = output_dir / "html"
+ if not html_dir.exists():
+ print(f"\n[SKIP] {output_dir.name}: no html/ subdirectory")
+ continue
+
+ # Create images directory
+ images_dir = output_dir / "images"
+ images_dir.mkdir(exist_ok=True)
+
+ html_files = sorted(html_dir.glob("*.html"))
+ if not html_files:
+ print(f"\n[SKIP] {output_dir.name}: no HTML files found")
+ continue
+
+ # Filter out already processed files unless --force
+ if not args.force:
+ html_files = [
+ f for f in html_files
+ if not (images_dir / f"{f.stem}.png").exists()
+ ]
+
+ if not html_files:
+ print(f"\n[SKIP] {output_dir.name}: all files already processed")
+ continue
+
+ print(f"\n[Processing] {output_dir.name}: {len(html_files)} HTML files")
+ asyncio.run(capture_batch_async(html_files, images_dir, args.width))
+
+ print("\nDone!")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/eval/__init__.py b/eval/__init__.py
index 65cc49f..4bdd2ee 100644
--- a/eval/__init__.py
+++ b/eval/__init__.py
@@ -28,6 +28,13 @@
evaluate_predictions,
run_evaluation,
)
+from .evaluate_vllm import (
+ EvalConfig,
+ load_qa_from_pipeline_output,
+ evaluate_domain,
+ evaluate_all_domains,
+ DOMAIN_DIRS,
+)
__all__ = [
# Dataset
@@ -50,4 +57,10 @@
# Evaluate
"evaluate_predictions",
"run_evaluation",
+ # vLLM Evaluate
+ "EvalConfig",
+ "load_qa_from_pipeline_output",
+ "evaluate_domain",
+ "evaluate_all_domains",
+ "DOMAIN_DIRS",
]
diff --git a/eval/evaluate_vllm.py b/eval/evaluate_vllm.py
new file mode 100644
index 0000000..aa9740d
--- /dev/null
+++ b/eval/evaluate_vllm.py
@@ -0,0 +1,648 @@
+#!/usr/bin/env python3
+"""
+vLLM 서버를 사용한 Table QA 평가 스크립트.
+
+output_* 디렉토리의 HTML 테이블 이미지와 QA 데이터를 사용하여
+멀티모달 모델의 Table QA 성능을 평가합니다.
+
+Usage:
+ # 단일 도메인 평가
+ python -m eval.evaluate_vllm --domain public --vllm-url http://localhost:8000/v1
+
+ # 모든 도메인 평가
+ python -m eval.evaluate_vllm --all-domains --vllm-url http://localhost:8000/v1
+
+ # 특정 모델 사용
+ python -m eval.evaluate_vllm --domain business --model Qwen/Qwen2-VL-7B-Instruct
+
+ # LLM-as-Judge 포함
+ python -m eval.evaluate_vllm --domain finance --use-judge --judge-model gpt-4o
+"""
+
+from __future__ import annotations
+
+import argparse
+import asyncio
+import json
+import logging
+import os
+import sys
+from dataclasses import dataclass, field
+from datetime import datetime
+from pathlib import Path
+from typing import List, Dict, Any, Optional
+
+# 프로젝트 루트를 path에 추가
+project_root = Path(__file__).parent.parent
+if str(project_root) not in sys.path:
+ sys.path.insert(0, str(project_root))
+
+from eval.dataset import QAItem, EvalDataset
+from eval.inference import VLLMClient, InferenceRequest, InferenceResponse, run_inference
+from eval.metrics import compute_metrics, aggregate_metrics, EvalResult, AggregatedMetrics
+from eval.evaluate import evaluate_predictions, generate_report, print_report
+from eval.llm_judge import create_judge_client
+
+logging.basicConfig(
+ level=logging.INFO,
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
+)
+logger = logging.getLogger(__name__)
+
+
+# 도메인별 output 디렉토리 매핑
+DOMAIN_DIRS = {
+ "academic": "output_academic",
+ "business": "output_business",
+ "finance": "output_finance",
+ "medical": "output_medical",
+ "public": "output_public",
+}
+
+# 기본 프롬프트 템플릿
+DEFAULT_PROMPT_TEMPLATE = """당신은 테이블 이미지를 분석하여 질문에 답하는 AI 어시스턴트입니다.
+주어진 테이블 이미지를 주의 깊게 분석한 후, 질문에 대해 정확하고 간결하게 답변해주세요.
+
+질문: {question}
+
+답변:"""
+
+# Context가 있는 경우의 프롬프트 템플릿
+CONTEXT_PROMPT_TEMPLATE = """당신은 테이블 이미지를 분석하여 질문에 답하는 AI 어시스턴트입니다.
+주어진 테이블 이미지와 아래 문맥을 함께 고려하여 질문에 정확하고 간결하게 답변해주세요.
+
+[문맥]
+{context}
+
+질문: {question}
+
+답변:"""
+
+
+@dataclass
+class EvalConfig:
+ """평가 설정"""
+ domain: str
+ vllm_url: str = "http://localhost:8000/v1"
+ model: str = "default"
+ max_tokens: int = 512
+ temperature: float = 0.0
+ max_concurrent: int = 10
+ timeout: float = 120.0
+ use_judge: bool = False
+ judge_provider: str = "openai"
+ judge_model: Optional[str] = None
+ judge_api_key: Optional[str] = None
+ output_dir: Optional[Path] = None
+ limit: Optional[int] = None # 평가할 최대 샘플 수 (디버깅용)
+ qa_types: Optional[List[str]] = None # 특정 QA 타입만 평가
+
+
+def find_table_images(
+ output_dir: Path,
+ pair_id: str,
+ image_paths: List[str],
+) -> List[Path]:
+ """
+ QA 항목에 해당하는 테이블 이미지를 찾습니다.
+
+ HTML 파일이 이미지로 캡처되었다고 가정하고,
+ output_dir/images/ 디렉토리에서 이미지를 찾습니다.
+
+ 파일명 패턴:
+ - pair_id: "B_origin_3_3_0"
+ - HTML: "B_origin_3_3_0_table_0.html", "B_origin_3_3_0_table_1.html"
+ - Images: "B_origin_3_3_0_table_0.png", "B_origin_3_3_0_table_1.png"
+
+ Args:
+ output_dir: output_* 디렉토리 경로
+ pair_id: QA pair ID
+ image_paths: 원본 이미지 경로 리스트 (data/Public/Table/P_origin_0/...)
+
+ Returns:
+ 찾은 이미지 경로 리스트
+ """
+ found_images = []
+
+ images_dir = output_dir / "images"
+ html_dir = output_dir / "html"
+
+ # 1. images/ 디렉토리에서 캡처된 이미지 찾기 (pair_id_table_*.png 패턴)
+ if images_dir.exists():
+ # pair_id_table_N.png 패턴으로 찾기
+ for img_file in sorted(images_dir.glob(f"{pair_id}_table_*.png")):
+ found_images.append(img_file)
+
+ # 못 찾았으면 pair_id*.png 패턴으로 시도
+ if not found_images:
+ for img_file in sorted(images_dir.glob(f"{pair_id}*.png")):
+ found_images.append(img_file)
+
+ # 2. html/ 디렉토리의 HTML 파일에 대응하는 이미지 찾기
+ if not found_images and html_dir.exists() and images_dir.exists():
+ for html_file in sorted(html_dir.glob(f"{pair_id}*.html")):
+ img_path = images_dir / f"{html_file.stem}.png"
+ if img_path.exists():
+ found_images.append(img_path)
+
+ # 3. 원본 이미지 경로가 존재하면 사용 (fallback)
+ if not found_images:
+ for orig_path in image_paths:
+ p = Path(orig_path)
+ if p.exists():
+ found_images.append(p)
+ else:
+ # 프로젝트 루트 기준 상대 경로 시도
+ full_path = project_root / orig_path
+ if full_path.exists():
+ found_images.append(full_path)
+
+ return sorted(set(found_images)) # 중복 제거 및 정렬
+
+
+def load_qa_from_pipeline_output(
+ output_dir: Path,
+ limit: Optional[int] = None,
+ qa_types: Optional[List[str]] = None,
+) -> EvalDataset:
+ """
+ pipeline_output.json에서 QA 데이터를 로드합니다.
+
+ Args:
+ output_dir: output_* 디렉토리
+ limit: 최대 로드할 샘플 수
+ qa_types: 특정 QA 타입만 로드
+
+ Returns:
+ EvalDataset
+ """
+ pipeline_output = output_dir / "pipeline_output.json"
+
+ if not pipeline_output.exists():
+ logger.warning(f"pipeline_output.json not found in {output_dir}")
+ return EvalDataset()
+
+ with open(pipeline_output, "r", encoding="utf-8") as f:
+ data = json.load(f)
+
+ items = []
+ skipped_no_images = 0
+ skipped_qa_type = 0
+
+ for entry in data:
+ pair_id = entry.get("pair_id", entry.get("name", "unknown"))
+ image_paths = entry.get("image_paths", [])
+ domain = entry.get("domain", "unknown")
+ qa_results = entry.get("qa_results", [])
+
+ # 테이블 이미지 찾기
+ table_images = find_table_images(output_dir, pair_id, image_paths)
+
+ for idx, qa in enumerate(qa_results):
+ qa_type = qa.get("type", "unknown")
+
+ # QA 타입 필터링
+ if qa_types and qa_type not in qa_types:
+ skipped_qa_type += 1
+ continue
+
+ item_id = f"{pair_id}_{idx}"
+
+ # 이미지 경로 결정
+ if table_images:
+ item_image_paths = [str(p) for p in table_images]
+ elif image_paths:
+ # 원본 경로 사용 (fallback)
+ item_image_paths = image_paths
+ else:
+ skipped_no_images += 1
+ continue
+
+ item = QAItem(
+ id=item_id,
+ question=qa.get("question", ""),
+ answer=qa.get("answer", ""),
+ qa_type=qa_type,
+ image_paths=item_image_paths,
+ reasoning_annotation=qa.get("reasoning_annotation"),
+ context=qa.get("context"),
+ source_file=str(pipeline_output),
+ )
+ items.append(item)
+
+ if limit and len(items) >= limit:
+ break
+
+ if limit and len(items) >= limit:
+ break
+
+ if skipped_no_images:
+ logger.warning(f"Skipped {skipped_no_images} QA items without images")
+ if skipped_qa_type:
+ logger.info(f"Skipped {skipped_qa_type} QA items due to type filter")
+
+ dataset = EvalDataset(
+ items=items,
+ metadata={
+ "source": str(pipeline_output),
+ "domain": output_dir.name,
+ "total_entries": len(data),
+ "loaded_qa_count": len(items),
+ }
+ )
+
+ return dataset
+
+
+def create_inference_requests(
+ dataset: EvalDataset,
+ prompt_template: Optional[str] = None,
+) -> List[InferenceRequest]:
+ """
+ 추론 요청을 생성합니다.
+
+ Args:
+ dataset: 평가 데이터셋
+ prompt_template: 프롬프트 템플릿
+
+ Returns:
+ InferenceRequest 리스트
+ """
+ requests = []
+
+ for item in dataset:
+ # context가 있으면 context 템플릿 사용
+ if item.context:
+ template = prompt_template or CONTEXT_PROMPT_TEMPLATE
+ prompt = template.format(
+ question=item.question,
+ context=item.context,
+ )
+ else:
+ template = prompt_template or DEFAULT_PROMPT_TEMPLATE
+ prompt = template.format(question=item.question)
+
+ request = InferenceRequest(
+ id=item.id,
+ prompt=prompt,
+ ground_truth=item.answer,
+ qa_type=item.qa_type,
+ image_paths=item.image_paths,
+ )
+ requests.append(request)
+
+ return requests
+
+
+async def evaluate_domain(
+ config: EvalConfig,
+) -> tuple[List[EvalResult], AggregatedMetrics, Dict[str, Any]]:
+ """
+ 단일 도메인에 대해 평가를 실행합니다.
+
+ Args:
+ config: 평가 설정
+
+ Returns:
+ (개별 결과, 집계 메트릭, 메타데이터)
+ """
+ domain_dir_name = DOMAIN_DIRS.get(config.domain)
+ if not domain_dir_name:
+ raise ValueError(f"Unknown domain: {config.domain}. Available: {list(DOMAIN_DIRS.keys())}")
+
+ output_dir = project_root / domain_dir_name
+ if not output_dir.exists():
+ raise FileNotFoundError(f"Output directory not found: {output_dir}")
+
+ logger.info(f"Evaluating domain: {config.domain}")
+ logger.info(f"Output directory: {output_dir}")
+
+ # 1. 데이터셋 로드
+ dataset = load_qa_from_pipeline_output(
+ output_dir,
+ limit=config.limit,
+ qa_types=config.qa_types,
+ )
+
+ if len(dataset) == 0:
+ logger.error("No QA items loaded. Check if pipeline_output.json exists and contains valid data.")
+ return [], AggregatedMetrics(), {}
+
+ logger.info(f"Loaded {len(dataset)} QA items")
+ logger.info(f"Type distribution: {dataset.get_type_distribution()}")
+
+ # 2. 추론 요청 생성
+ requests = create_inference_requests(dataset)
+
+ # 3. vLLM 클라이언트 생성
+ client = VLLMClient(
+ base_url=config.vllm_url,
+ model=config.model,
+ max_tokens=config.max_tokens,
+ temperature=config.temperature,
+ timeout=config.timeout,
+ max_concurrent=config.max_concurrent,
+ )
+
+ # 4. 추론 실행
+ inference_output = None
+ if config.output_dir:
+ config.output_dir.mkdir(parents=True, exist_ok=True)
+ inference_output = config.output_dir / f"{config.domain}_inference.json"
+
+ logger.info(f"Running inference on {len(requests)} requests...")
+ responses = await run_inference(client, requests, output_path=inference_output)
+
+ # 5. 평가
+ predictions = [
+ {
+ "id": r.id,
+ "prediction": r.prediction,
+ "ground_truth": r.ground_truth,
+ "qa_type": r.qa_type,
+ "question": dataset.items[i].question if i < len(dataset.items) else "",
+ }
+ for i, r in enumerate(responses)
+ ]
+
+ # Judge 클라이언트 설정
+ judge_client = None
+ if config.use_judge:
+ judge_client = create_judge_client(
+ provider=config.judge_provider,
+ model=config.judge_model,
+ api_key=config.judge_api_key,
+ )
+
+ questions = [item.question for item in dataset.items]
+ results, aggregated = await evaluate_predictions(
+ predictions,
+ use_judge=config.use_judge,
+ judge_client=judge_client,
+ questions=questions,
+ )
+
+ # 메타데이터
+ metadata = {
+ "domain": config.domain,
+ "model": config.model,
+ "vllm_url": config.vllm_url,
+ "total_items": len(dataset),
+ "type_distribution": dataset.get_type_distribution(),
+ "timestamp": datetime.now().isoformat(),
+ }
+
+ return results, aggregated, metadata
+
+
+async def evaluate_all_domains(
+ config: EvalConfig,
+) -> Dict[str, tuple[List[EvalResult], AggregatedMetrics]]:
+ """
+ 모든 도메인에 대해 평가를 실행합니다.
+
+ Args:
+ config: 기본 평가 설정 (domain 필드는 무시됨)
+
+ Returns:
+ 도메인별 결과 딕셔너리
+ """
+ all_results = {}
+
+ for domain in DOMAIN_DIRS.keys():
+ domain_config = EvalConfig(
+ domain=domain,
+ vllm_url=config.vllm_url,
+ model=config.model,
+ max_tokens=config.max_tokens,
+ temperature=config.temperature,
+ max_concurrent=config.max_concurrent,
+ timeout=config.timeout,
+ use_judge=config.use_judge,
+ judge_provider=config.judge_provider,
+ judge_model=config.judge_model,
+ judge_api_key=config.judge_api_key,
+ output_dir=config.output_dir,
+ limit=config.limit,
+ qa_types=config.qa_types,
+ )
+
+ try:
+ results, aggregated, metadata = await evaluate_domain(domain_config)
+ all_results[domain] = (results, aggregated, metadata)
+ print_report(aggregated)
+ except Exception as e:
+ logger.error(f"Failed to evaluate domain {domain}: {e}")
+ all_results[domain] = ([], AggregatedMetrics(), {"error": str(e)})
+
+ return all_results
+
+
+def save_results(
+ results: List[EvalResult],
+ aggregated: AggregatedMetrics,
+ metadata: Dict[str, Any],
+ output_dir: Path,
+ domain: str,
+) -> None:
+ """결과를 파일로 저장합니다."""
+ output_dir.mkdir(parents=True, exist_ok=True)
+
+ # 전체 리포트
+ report = generate_report(results, aggregated, metadata)
+ report_path = output_dir / f"{domain}_evaluation_report.json"
+ with open(report_path, "w", encoding="utf-8") as f:
+ json.dump(report, ensure_ascii=False, indent=2, fp=f)
+ logger.info(f"Saved report to {report_path}")
+
+ # 요약 결과 (CSV 친화적)
+ summary_path = output_dir / f"{domain}_summary.json"
+ summary = {
+ "domain": domain,
+ "total_count": aggregated.total_count,
+ "exact_match": aggregated.exact_match_avg,
+ "f1_score": aggregated.f1_score_avg,
+ "contains_match": aggregated.contains_match_avg,
+ "bleu_score": aggregated.bleu_score_avg,
+ "by_type": aggregated.by_type,
+ }
+ if aggregated.judge_overall_avg is not None:
+ summary["judge_overall"] = aggregated.judge_overall_avg
+ summary["judge_accuracy"] = aggregated.judge_accuracy
+
+ with open(summary_path, "w", encoding="utf-8") as f:
+ json.dump(summary, ensure_ascii=False, indent=2, fp=f)
+ logger.info(f"Saved summary to {summary_path}")
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="vLLM 서버를 사용한 Table QA 평가",
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ epilog="""
+Examples:
+ # 단일 도메인 평가
+ python -m eval.evaluate_vllm --domain public --vllm-url http://localhost:8000/v1
+
+ # 모든 도메인 평가
+ python -m eval.evaluate_vllm --all-domains --vllm-url http://localhost:8000/v1
+
+ # 특정 모델 사용
+ python -m eval.evaluate_vllm --domain business --model Qwen/Qwen2-VL-7B-Instruct
+
+ # LLM-as-Judge 포함
+ python -m eval.evaluate_vllm --domain finance --use-judge --judge-model gpt-4o
+
+ # 특정 QA 타입만 평가
+ python -m eval.evaluate_vllm --domain public --qa-types lookup compare
+
+ # 제한된 샘플로 테스트
+ python -m eval.evaluate_vllm --domain public --limit 10
+ """,
+ )
+
+ # 필수 인자
+ parser.add_argument(
+ "--domain",
+ choices=list(DOMAIN_DIRS.keys()),
+ help="평가할 도메인",
+ )
+ parser.add_argument(
+ "--all-domains",
+ action="store_true",
+ help="모든 도메인 평가",
+ )
+
+ # vLLM 설정
+ parser.add_argument(
+ "--vllm-url",
+ default="http://localhost:8000/v1",
+ help="vLLM 서버 URL (default: http://localhost:8000/v1)",
+ )
+ parser.add_argument(
+ "--model",
+ default="default",
+ help="사용할 모델 이름 (default: vLLM에서 로드된 모델 사용)",
+ )
+ parser.add_argument(
+ "--max-tokens",
+ type=int,
+ default=512,
+ help="최대 생성 토큰 수 (default: 512)",
+ )
+ parser.add_argument(
+ "--temperature",
+ type=float,
+ default=0.0,
+ help="생성 온도 (default: 0.0)",
+ )
+ parser.add_argument(
+ "--max-concurrent",
+ type=int,
+ default=10,
+ help="최대 동시 요청 수 (default: 10)",
+ )
+ parser.add_argument(
+ "--timeout",
+ type=float,
+ default=120.0,
+ help="요청 타임아웃(초) (default: 120.0)",
+ )
+
+ # Judge 설정
+ parser.add_argument(
+ "--use-judge",
+ action="store_true",
+ help="LLM-as-Judge 평가 사용",
+ )
+ parser.add_argument(
+ "--judge-provider",
+ default="openai",
+ choices=["openai", "anthropic"],
+ help="Judge 제공자 (default: openai)",
+ )
+ parser.add_argument(
+ "--judge-model",
+ help="Judge 모델 (default: gpt-4o-mini)",
+ )
+ parser.add_argument(
+ "--judge-api-key",
+ help="Judge API 키 (환경변수에서 가져오지 않을 경우)",
+ )
+
+ # 출력 설정
+ parser.add_argument(
+ "--output-dir",
+ type=Path,
+ default=Path("eval_results"),
+ help="결과 저장 디렉토리 (default: eval_results)",
+ )
+
+ # 필터링 옵션
+ parser.add_argument(
+ "--limit",
+ type=int,
+ help="평가할 최대 샘플 수 (디버깅용)",
+ )
+ parser.add_argument(
+ "--qa-types",
+ nargs="+",
+ help="특정 QA 타입만 평가 (예: lookup compare arithmetic)",
+ )
+
+ args = parser.parse_args()
+
+ # 인자 검증
+ if not args.domain and not args.all_domains:
+ parser.error("--domain 또는 --all-domains 중 하나를 지정해야 합니다.")
+
+ # 설정 생성
+ config = EvalConfig(
+ domain=args.domain or "public", # all-domains일 때 기본값
+ vllm_url=args.vllm_url,
+ model=args.model,
+ max_tokens=args.max_tokens,
+ temperature=args.temperature,
+ max_concurrent=args.max_concurrent,
+ timeout=args.timeout,
+ use_judge=args.use_judge,
+ judge_provider=args.judge_provider,
+ judge_model=args.judge_model,
+ judge_api_key=args.judge_api_key,
+ output_dir=args.output_dir,
+ limit=args.limit,
+ qa_types=args.qa_types,
+ )
+
+ # 평가 실행
+ if args.all_domains:
+ all_results = asyncio.run(evaluate_all_domains(config))
+
+ # 전체 요약 저장
+ if config.output_dir:
+ config.output_dir.mkdir(parents=True, exist_ok=True)
+
+ all_summary = {}
+ for domain, (results, aggregated, metadata) in all_results.items():
+ if results:
+ save_results(results, aggregated, metadata, config.output_dir, domain)
+ all_summary[domain] = {
+ "total_count": aggregated.total_count,
+ "exact_match": aggregated.exact_match_avg,
+ "f1_score": aggregated.f1_score_avg,
+ }
+
+ summary_path = config.output_dir / "all_domains_summary.json"
+ with open(summary_path, "w", encoding="utf-8") as f:
+ json.dump(all_summary, ensure_ascii=False, indent=2, fp=f)
+ logger.info(f"Saved all-domains summary to {summary_path}")
+ else:
+ results, aggregated, metadata = asyncio.run(evaluate_domain(config))
+ print_report(aggregated)
+
+ if config.output_dir and results:
+ save_results(results, aggregated, metadata, config.output_dir, config.domain)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/filter_qa_by_difficulty.py b/filter_qa_by_difficulty.py
new file mode 100755
index 0000000..1469baa
--- /dev/null
+++ b/filter_qa_by_difficulty.py
@@ -0,0 +1,595 @@
+#!/usr/bin/env python3
+"""
+vLLM 서버를 사용하여 QA 난이도를 측정하고 필터링하는 스크립트.
+
+모델이 너무 쉽게 맞추는 문제(10/10)는 제외하고,
+적당한 난이도(3-6/10 정확도)의 QA만 검수 대상으로 추출합니다.
+
+Usage:
+ # 기본 사용 (business 도메인)
+ python filter_qa_by_difficulty.py --domain business
+
+ # 여러 도메인
+ python filter_qa_by_difficulty.py --all
+
+ # 커스텀 설정
+ python filter_qa_by_difficulty.py --domain business --trials 10 --min-acc 0.3 --max-acc 0.6
+
+ # vLLM 서버 URL 지정
+ python filter_qa_by_difficulty.py --domain business --vllm-url http://localhost:8000/v1
+"""
+
+import argparse
+import base64
+import json
+import logging
+import os
+import sys
+from dataclasses import dataclass, field
+from datetime import datetime
+from pathlib import Path
+from typing import Any, Dict, List, Optional, Tuple
+from concurrent.futures import ThreadPoolExecutor, as_completed
+
+from dotenv import load_dotenv
+
+load_dotenv()
+
+project_root = Path(__file__).parent
+sys.path.insert(0, str(project_root))
+
+from eval.metrics import normalize_answer, exact_match, f1_score
+
+logging.basicConfig(
+ level=logging.INFO,
+ format="%(asctime)s - %(levelname)s - %(message)s"
+)
+logger = logging.getLogger(__name__)
+
+DOMAIN_DIRS = {
+ "academic": "output_academic",
+ "business": "output_business",
+ "finance": "output_finance",
+ "medical": "output_medical",
+ "public": "output_public",
+}
+
+
+@dataclass
+class FilterConfig:
+ """필터링 설정"""
+ vllm_url: str = "http://localhost:8000/v1"
+ model_name: str = "" # vLLM 서버에서 자동 감지
+ trials: int = 10 # 각 QA당 시도 횟수
+ min_accuracy: float = 0.3 # 최소 정확도 (이상)
+ max_accuracy: float = 0.6 # 최대 정확도 (이하)
+ temperature: float = 0.7 # 다양한 응답을 위해
+ max_tokens: int = 512
+ timeout: int = 60
+ max_workers: int = 4 # 병렬 처리
+
+
+@dataclass
+class QADifficultyResult:
+ """QA 난이도 측정 결과"""
+ pair_id: str
+ table_index: int
+ qa_index: int
+ question: str
+ answer: str
+ qa_type: str
+ correct_count: int
+ total_trials: int
+ accuracy: float
+ responses: List[str] = field(default_factory=list)
+ difficulty_category: str = "" # easy, medium, hard, very_hard
+
+ def to_dict(self) -> Dict[str, Any]:
+ return {
+ "pair_id": self.pair_id,
+ "table_index": self.table_index,
+ "qa_index": self.qa_index,
+ "question": self.question,
+ "answer": self.answer,
+ "qa_type": self.qa_type,
+ "correct_count": self.correct_count,
+ "total_trials": self.total_trials,
+ "accuracy": self.accuracy,
+ "difficulty_category": self.difficulty_category,
+ "sample_responses": self.responses[:3], # 샘플만 저장
+ }
+
+
+def get_vllm_model_name(vllm_url: str) -> str:
+ """vLLM 서버에서 모델 이름 가져오기"""
+ import requests
+ try:
+ response = requests.get(f"{vllm_url}/models", timeout=10)
+ response.raise_for_status()
+ models = response.json().get("data", [])
+ if models:
+ return models[0]["id"]
+ except Exception as e:
+ logger.warning(f"Failed to get model name from vLLM: {e}")
+ return "default"
+
+
+def find_table_images(output_dir: Path, pair_id: str) -> List[Path]:
+ """pair_id에 해당하는 테이블 이미지 찾기"""
+ images_dir = output_dir / "images"
+ if not images_dir.exists():
+ return []
+
+ found_images = []
+ for img_file in sorted(images_dir.glob(f"{pair_id}_table_*.png")):
+ found_images.append(img_file)
+
+ return found_images
+
+
+def encode_image_base64(image_path: Path) -> str:
+ """이미지를 base64로 인코딩"""
+ with open(image_path, "rb") as f:
+ return base64.b64encode(f.read()).decode("utf-8")
+
+
+def run_single_inference(
+ vllm_url: str,
+ model_name: str,
+ image_base64: str,
+ question: str,
+ config: FilterConfig,
+) -> Optional[str]:
+ """단일 추론 실행"""
+ import requests
+
+ messages = [
+ {
+ "role": "user",
+ "content": [
+ {
+ "type": "image_url",
+ "image_url": {
+ "url": f"data:image/png;base64,{image_base64}"
+ }
+ },
+ {
+ "type": "text",
+ "text": f"Based on the table image, answer the following question concisely.\n\nQuestion: {question}\n\nAnswer:"
+ }
+ ]
+ }
+ ]
+
+ try:
+ response = requests.post(
+ f"{vllm_url}/chat/completions",
+ json={
+ "model": model_name,
+ "messages": messages,
+ "max_tokens": config.max_tokens,
+ "temperature": config.temperature,
+ },
+ timeout=config.timeout,
+ )
+ response.raise_for_status()
+ result = response.json()
+ return result["choices"][0]["message"]["content"].strip()
+ except Exception as e:
+ logger.debug(f"Inference failed: {e}")
+ return None
+
+
+def check_answer_correct(prediction: str, ground_truth: str) -> bool:
+ """답변이 맞는지 확인 (EM 또는 F1 > 0.8)"""
+ if not prediction:
+ return False
+
+ # Exact match
+ if exact_match(prediction, ground_truth):
+ return True
+
+ # F1 score > 0.8
+ if f1_score(prediction, ground_truth) > 0.8:
+ return True
+
+ # 정규화된 답변이 포함되는지 확인
+ norm_pred = normalize_answer(prediction)
+ norm_gt = normalize_answer(ground_truth)
+ if norm_gt in norm_pred or norm_pred in norm_gt:
+ return True
+
+ return False
+
+
+def measure_qa_difficulty(
+ vllm_url: str,
+ model_name: str,
+ image_base64: str,
+ question: str,
+ answer: str,
+ config: FilterConfig,
+) -> Tuple[int, List[str]]:
+ """QA 난이도 측정 (여러 번 시도)"""
+ correct_count = 0
+ responses = []
+
+ for trial in range(config.trials):
+ response = run_single_inference(
+ vllm_url, model_name, image_base64, question, config
+ )
+ if response:
+ responses.append(response)
+ if check_answer_correct(response, answer):
+ correct_count += 1
+
+ return correct_count, responses
+
+
+def categorize_difficulty(accuracy: float) -> str:
+ """정확도에 따라 난이도 분류"""
+ if accuracy >= 0.9:
+ return "too_easy"
+ elif accuracy >= 0.7:
+ return "easy"
+ elif accuracy >= 0.3:
+ return "medium" # 목표 범위
+ elif accuracy > 0:
+ return "hard"
+ else:
+ return "very_hard"
+
+
+def filter_qa_for_domain(
+ domain: str,
+ config: FilterConfig,
+ limit: Optional[int] = None,
+ dry_run: bool = False,
+) -> Dict[str, Any]:
+ """도메인의 QA를 필터링"""
+ domain_dir = DOMAIN_DIRS.get(domain)
+ if not domain_dir:
+ raise ValueError(f"Unknown domain: {domain}")
+
+ output_dir = project_root / domain_dir
+ pipeline_output_path = output_dir / "pipeline_output.json"
+
+ if not pipeline_output_path.exists():
+ raise FileNotFoundError(f"pipeline_output.json not found: {pipeline_output_path}")
+
+ # 이미지 디렉토리
+ images_dir = output_dir / "images"
+
+ # 데이터 로드
+ with open(pipeline_output_path, "r", encoding="utf-8") as f:
+ data = json.load(f)
+
+ logger.info(f"Loaded {len(data)} entries from {pipeline_output_path}")
+
+ if limit:
+ data = data[:limit]
+ logger.info(f"Limited to {limit} entries")
+
+ if dry_run:
+ # QA 수 확인만 (이미지 없어도 OK)
+ total_qa = sum(len(entry.get("qa_results", [])) for entry in data)
+ images_exist = images_dir.exists()
+ image_count = len(list(images_dir.glob("*.png"))) if images_exist else 0
+ logger.info(f"Dry run: {len(data)} entries, {total_qa} QA pairs")
+ logger.info(f"Images directory: {'exists' if images_exist else 'NOT FOUND'} ({image_count} images)")
+ if not images_exist:
+ logger.warning("이미지 디렉토리가 없습니다. 먼저 capture_html_to_images.py를 실행하세요.")
+ return {
+ "domain": domain,
+ "entries": len(data),
+ "total_qa": total_qa,
+ "images_exist": images_exist,
+ "image_count": image_count,
+ "dry_run": True,
+ }
+
+ # 이미지 디렉토리 확인 (실제 실행 시)
+ if not images_dir.exists():
+ raise FileNotFoundError(
+ f"Images directory not found: {images_dir}\n"
+ "먼저 capture_html_to_images.py를 실행하여 HTML을 이미지로 변환하세요."
+ )
+
+ # vLLM 모델 이름 가져오기
+ model_name = config.model_name or get_vllm_model_name(config.vllm_url)
+ logger.info(f"Using model: {model_name}")
+
+ # 결과 수집
+ all_results: List[QADifficultyResult] = []
+ stats = {
+ "total_qa": 0,
+ "too_easy": 0,
+ "easy": 0,
+ "medium": 0,
+ "hard": 0,
+ "very_hard": 0,
+ "skipped": 0,
+ }
+
+ for entry_idx, entry in enumerate(data):
+ pair_id = entry.get("pair_id", entry.get("name", f"entry_{entry_idx}"))
+ qa_results = entry.get("qa_results", [])
+
+ if not qa_results:
+ continue
+
+ # 이미지 찾기
+ image_files = find_table_images(output_dir, pair_id)
+ if not image_files:
+ logger.warning(f"No images found for {pair_id}, skipping")
+ stats["skipped"] += len(qa_results)
+ continue
+
+ # 첫 번째 이미지 사용 (TODO: 멀티 이미지 지원)
+ image_base64 = encode_image_base64(image_files[0])
+
+ logger.info(f"[{entry_idx + 1}/{len(data)}] Processing {pair_id} ({len(qa_results)} QAs)")
+
+ for qa_idx, qa in enumerate(qa_results):
+ question = qa.get("question", "")
+ answer = qa.get("answer", "")
+ qa_type = qa.get("type", "unknown")
+
+ if not question or not answer:
+ stats["skipped"] += 1
+ continue
+
+ stats["total_qa"] += 1
+
+ # 난이도 측정
+ correct_count, responses = measure_qa_difficulty(
+ config.vllm_url,
+ model_name,
+ image_base64,
+ question,
+ answer,
+ config,
+ )
+
+ accuracy = correct_count / config.trials if config.trials > 0 else 0
+ difficulty = categorize_difficulty(accuracy)
+ stats[difficulty] += 1
+
+ result = QADifficultyResult(
+ pair_id=pair_id,
+ table_index=0,
+ qa_index=qa_idx,
+ question=question,
+ answer=answer,
+ qa_type=qa_type,
+ correct_count=correct_count,
+ total_trials=config.trials,
+ accuracy=accuracy,
+ responses=responses,
+ difficulty_category=difficulty,
+ )
+ all_results.append(result)
+
+ # 진행 상황 로그
+ status = "✓" if config.min_accuracy <= accuracy <= config.max_accuracy else "✗"
+ logger.info(f" [{qa_idx + 1}/{len(qa_results)}] {qa_type}: {correct_count}/{config.trials} ({accuracy:.0%}) [{difficulty}] {status}")
+
+ # 필터링 (목표 난이도 범위)
+ filtered_results = [
+ r for r in all_results
+ if config.min_accuracy <= r.accuracy <= config.max_accuracy
+ ]
+
+ # 결과 저장
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+ output_file = output_dir / f"qa_difficulty_analysis_{timestamp}.json"
+
+ output_data = {
+ "domain": domain,
+ "config": {
+ "vllm_url": config.vllm_url,
+ "model_name": model_name,
+ "trials": config.trials,
+ "min_accuracy": config.min_accuracy,
+ "max_accuracy": config.max_accuracy,
+ "temperature": config.temperature,
+ },
+ "stats": stats,
+ "filtered_count": len(filtered_results),
+ "all_results": [r.to_dict() for r in all_results],
+ "filtered_for_review": [r.to_dict() for r in filtered_results],
+ "timestamp": timestamp,
+ }
+
+ with open(output_file, "w", encoding="utf-8") as f:
+ json.dump(output_data, f, ensure_ascii=False, indent=2)
+
+ logger.info(f"Results saved to {output_file}")
+
+ # 검수용 간단 리스트 저장
+ review_file = output_dir / f"qa_for_review_{timestamp}.json"
+ review_data = {
+ "domain": domain,
+ "description": f"QA pairs with accuracy between {config.min_accuracy:.0%} and {config.max_accuracy:.0%}",
+ "count": len(filtered_results),
+ "items": [
+ {
+ "pair_id": r.pair_id,
+ "qa_type": r.qa_type,
+ "question": r.question,
+ "answer": r.answer,
+ "accuracy": f"{r.accuracy:.0%} ({r.correct_count}/{r.total_trials})",
+ "sample_model_responses": r.responses[:3],
+ }
+ for r in filtered_results
+ ],
+ }
+
+ with open(review_file, "w", encoding="utf-8") as f:
+ json.dump(review_data, f, ensure_ascii=False, indent=2)
+
+ logger.info(f"Review list saved to {review_file}")
+
+ return {
+ "domain": domain,
+ "total_qa": stats["total_qa"],
+ "stats": stats,
+ "filtered_for_review": len(filtered_results),
+ "output_file": str(output_file),
+ "review_file": str(review_file),
+ }
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="vLLM을 사용하여 QA 난이도를 측정하고 검수 대상을 필터링합니다.",
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ epilog="""
+Examples:
+ # business 도메인 필터링
+ python filter_qa_by_difficulty.py --domain business
+
+ # 모든 도메인
+ python filter_qa_by_difficulty.py --all
+
+ # 커스텀 설정 (5회 시도, 20-50% 정확도)
+ python filter_qa_by_difficulty.py --domain business --trials 5 --min-acc 0.2 --max-acc 0.5
+
+ # vLLM 서버 지정
+ python filter_qa_by_difficulty.py --domain business --vllm-url http://localhost:8000/v1
+
+ # 테스트 (3개 entry만)
+ python filter_qa_by_difficulty.py --domain business --limit 3
+
+Difficulty Categories:
+ - too_easy: 90-100% accuracy (제외)
+ - easy: 70-89% accuracy
+ - medium: 30-69% accuracy (검수 대상)
+ - hard: 1-29% accuracy
+ - very_hard: 0% accuracy
+ """
+ )
+
+ parser.add_argument(
+ "--domain",
+ nargs="+",
+ choices=list(DOMAIN_DIRS.keys()),
+ help="필터링할 도메인(들)",
+ )
+ parser.add_argument(
+ "--all",
+ action="store_true",
+ help="모든 도메인 필터링",
+ )
+ parser.add_argument(
+ "--vllm-url",
+ default="http://localhost:8000/v1",
+ help="vLLM 서버 URL (default: http://localhost:8000/v1)",
+ )
+ parser.add_argument(
+ "--model",
+ default="",
+ help="모델 이름 (미지정시 vLLM에서 자동 감지)",
+ )
+ parser.add_argument(
+ "--trials",
+ type=int,
+ default=10,
+ help="각 QA당 시도 횟수 (default: 10)",
+ )
+ parser.add_argument(
+ "--min-acc",
+ type=float,
+ default=0.3,
+ help="최소 정확도 (default: 0.3)",
+ )
+ parser.add_argument(
+ "--max-acc",
+ type=float,
+ default=0.6,
+ help="최대 정확도 (default: 0.6)",
+ )
+ parser.add_argument(
+ "--temperature",
+ type=float,
+ default=0.7,
+ help="샘플링 temperature (default: 0.7)",
+ )
+ parser.add_argument(
+ "--limit",
+ type=int,
+ help="처리할 최대 entry 수 (테스트용)",
+ )
+ parser.add_argument(
+ "--dry-run",
+ action="store_true",
+ help="실제 추론 없이 확인만",
+ )
+
+ args = parser.parse_args()
+
+ # 도메인 결정
+ if args.all:
+ domains = list(DOMAIN_DIRS.keys())
+ elif args.domain:
+ domains = args.domain
+ else:
+ parser.error("--domain 또는 --all을 지정해야 합니다.")
+
+ # 설정
+ config = FilterConfig(
+ vllm_url=args.vllm_url,
+ model_name=args.model,
+ trials=args.trials,
+ min_accuracy=args.min_acc,
+ max_accuracy=args.max_acc,
+ temperature=args.temperature,
+ )
+
+ logger.info(f"Domains: {domains}")
+ logger.info(f"Config: trials={config.trials}, accuracy range={config.min_accuracy:.0%}-{config.max_accuracy:.0%}")
+
+ # 각 도메인 처리
+ results = []
+ for domain in domains:
+ logger.info(f"\n{'='*60}")
+ logger.info(f"Processing domain: {domain}")
+ logger.info(f"{'='*60}")
+
+ try:
+ result = filter_qa_for_domain(
+ domain=domain,
+ config=config,
+ limit=args.limit,
+ dry_run=args.dry_run,
+ )
+ results.append(result)
+ except Exception as e:
+ logger.error(f"Failed to process {domain}: {e}")
+ results.append({"domain": domain, "error": str(e)})
+
+ # 요약
+ print("\n" + "=" * 60)
+ print(" QA Difficulty Filtering Summary")
+ print("=" * 60)
+ for result in results:
+ domain = result.get("domain", "unknown")
+ if "error" in result:
+ print(f" {domain}: ERROR - {result['error']}")
+ elif result.get("dry_run"):
+ img_status = "✓" if result.get("images_exist") else "✗ (run capture_html_to_images.py first)"
+ print(f" {domain}: {result.get('total_qa', 0)} QA pairs, {result.get('image_count', 0)} images {img_status} (dry run)")
+ else:
+ stats = result.get("stats", {})
+ filtered = result.get("filtered_for_review", 0)
+ total = result.get("total_qa", 0)
+ print(f" {domain}:")
+ print(f" Total QA: {total}")
+ print(f" too_easy: {stats.get('too_easy', 0)}, easy: {stats.get('easy', 0)}")
+ print(f" medium: {stats.get('medium', 0)}, hard: {stats.get('hard', 0)}, very_hard: {stats.get('very_hard', 0)}")
+ print(f" → For review: {filtered} ({filtered/total*100:.1f}% of total)" if total > 0 else "")
+ print("=" * 60)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/generate_synthetic_table/flow.py b/generate_synthetic_table/flow.py
index 8be68dd..ce2d976 100644
--- a/generate_synthetic_table/flow.py
+++ b/generate_synthetic_table/flow.py
@@ -49,6 +49,7 @@ class TableState(TypedDict, total=False):
synthetic_json: dict # 파싱된 합성 데이터 JSON
qa_results: List[Dict] # 생성된 QA 쌍
token_usage: int # QA 생성에 사용된 총 토큰 수
+ is_multi_image: bool # 다중 이미지 입력 여부 (cross-image QA 생성됨)
def _encode_image(image_path: Path) -> str:
@@ -684,12 +685,65 @@ def _node(state: TableState) -> TableState:
return _node
+def generate_long_sequence_node(llm: ChatOpenAI) -> Callable[[TableState], TableState]:
+ """Generate long_sequence QA pair separately (context-dependent questions)."""
+
+ def _node(state: TableState) -> TableState:
+ logger.info("Entering node: generate_long_sequence")
+
+ # Try to load long_sequence prompt, skip if not available
+ try:
+ prompt_template = _load_prompt("generate_long_sequence", state.get("domain"))
+ except ValueError:
+ logger.info("No generate_long_sequence prompt found, skipping long_sequence generation")
+ return state
+
+ if state.get("errors"):
+ return state
+
+ synthetic_html = state.get("synthetic_table")
+ if not synthetic_html:
+ logger.warning("No synthetic table for long_sequence generation, skipping")
+ return state
+
+ try:
+ prompt = prompt_template.format(synthetic_html=synthetic_html)
+ except KeyError as e:
+ logger.warning(f"long_sequence prompt missing placeholder: {e}, skipping")
+ return state
+
+ response_text, token_usage = _call_llm(llm, prompt, return_token_usage=True)
+
+ logger.info(f"Long sequence generation token usage: {token_usage}")
+
+ response_json = robust_json_parse(response_text)
+
+ if response_json and "qa_pairs" in response_json:
+ long_seq_qa = response_json["qa_pairs"]
+ # Append to existing qa_results
+ existing_qa = list(state.get("qa_results", []))
+ existing_qa.extend(long_seq_qa)
+ # Update token usage
+ existing_token_usage = state.get("token_usage", 0)
+ total_token_usage = existing_token_usage + token_usage
+ logger.info(f"Added {len(long_seq_qa)} long_sequence QA pairs. Total QA: {len(existing_qa)}")
+ return {**state, "qa_results": existing_qa, "token_usage": total_token_usage}
+ else:
+ logger.warning("long_sequence generation did not return valid JSON or 'qa_pairs' key.")
+ return state
+
+ return _node
+
+
def generate_qa_from_image_node(llm: ChatOpenAI) -> Callable[[TableState], TableState]:
- """Generate QA pairs directly from image (QA-only mode)."""
+ """Generate QA pairs directly from image (QA-only mode).
+
+ If multiple images are provided, uses 'generate_qa_from_multi_image' prompt
+ to generate cross-image QA pairs that require understanding multiple tables.
+ """
def _node(state: TableState) -> TableState:
logger.info("Entering node: generate_qa_from_image")
- prompt_template = _load_prompt("generate_qa_from_image", state.get("domain"))
if state.get("errors"):
return state
@@ -711,6 +765,18 @@ def _node(state: TableState) -> TableState:
else:
logger.warning(f"Skipping missing image in batch: {img_p}")
+ # Use multi-image prompt if there are multiple images
+ is_multi_image = len(image_data_urls) > 1
+ if is_multi_image:
+ logger.info(f"Multi-image mode detected: {len(image_data_urls)} images. Using cross-image QA prompt.")
+ try:
+ prompt_template = _load_prompt("generate_qa_from_multi_image", state.get("domain"))
+ except ValueError:
+ logger.warning("Multi-image prompt not found, falling back to single-image prompt")
+ prompt_template = _load_prompt("generate_qa_from_image", state.get("domain"))
+ else:
+ prompt_template = _load_prompt("generate_qa_from_image", state.get("domain"))
+
prompt = prompt_template
response_text, token_usage = _call_llm(llm, prompt, image_urls=image_data_urls, return_token_usage=True)
@@ -727,7 +793,10 @@ def _node(state: TableState) -> TableState:
logger.warning("QA generation from image did not return valid JSON or 'qa_pairs' key.")
logger.info(f"Returning token_usage: {token_usage}")
- return {**state, "qa_results": qa_results, "token_usage": token_usage}
+ result_state = {**state, "qa_results": qa_results, "token_usage": token_usage}
+ if is_multi_image:
+ result_state["is_multi_image"] = True
+ return result_state
return _node
@@ -800,6 +869,7 @@ def build_synthetic_table_graph(
if not skip_qa:
graph.add_node("generate_qa", generate_qa_node(llm))
+ graph.add_node("generate_long_sequence", generate_long_sequence_node(llm))
# Routing based on provider and input type
def route_start(state: TableState) -> str:
@@ -852,7 +922,8 @@ def route_start(state: TableState) -> str:
graph.add_edge("parse_synthetic_table", END)
else:
graph.add_edge("parse_synthetic_table", "generate_qa")
- graph.add_edge("generate_qa", END)
+ graph.add_edge("generate_qa", "generate_long_sequence")
+ graph.add_edge("generate_long_sequence", END)
return graph
diff --git a/generate_synthetic_table/prompts/academic.yaml b/generate_synthetic_table/prompts/academic.yaml
index 87543eb..ea2caed 100644
--- a/generate_synthetic_table/prompts/academic.yaml
+++ b/generate_synthetic_table/prompts/academic.yaml
@@ -6,7 +6,7 @@ generate_qa: |
{synthetic_html}
### [Instructions]
- 1. **Candidate Generation & Filtering**: Internally generate 10 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 10 pairs)
+ 1. **Candidate Generation & Filtering**: Internally generate 9 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 9 pairs)
2. **Domain Suitability**: Questions must maintain an academic tone and accurately handle experimental results, performance metrics (Accuracy, F1-score, etc.), model names, and statistical significance.
3. **Strict Constraints**:
- Answers must be derived ONLY from the table (and provided context). No external knowledge.
@@ -14,6 +14,7 @@ generate_qa: |
- Output format must strictly follow JSON.
- Questions and Answers MUST be written in Korean.
- reasoning_annotation MUST be written in English and MUST be a single string (not a list).
+ - **DO NOT use real model/dataset names** (e.g., BERT, GPT, ResNet, ImageNet). Use fictional names like "Model-A", "Dataset-X", "Method-알파".
### [Validation Criteria]
- Is the answer uniquely determined within the table?
@@ -21,16 +22,15 @@ generate_qa: |
- Is the question clear and unambiguous? (e.g., "Best model" -> "Model with highest Accuracy")
### [Reasoning Type Definitions (Academic Domain)]
- (1) lookup: Retrieve specific model performance or value without condition/calculation. (e.g., "What is the ImageNet Top-1 Accuracy of ResNet-50?")
+ (1) lookup: Retrieve specific model performance or value without condition/calculation. (e.g., "What is the Top-1 Accuracy of Model-A?")
(2) filter: Select rows/columns meeting specific conditions (performance, params, etc.). (e.g., "List all models with parameters under 10M.")
- (3) aggregate: Statistical aggregation of experimental results (Sum, Avg, Max, Min, Count). (e.g., "What is the average F1-score of all BERT variants?")
- (4) compare: Compare performance against baseline or between models. (e.g., "Does the Proposed Method have a higher BLEU score than SOTA?")
+ (3) aggregate: Statistical aggregation of experimental results (Sum, Avg, Max, Min, Count). (e.g., "What is the average F1-score of all model variants?")
+ (4) compare: Compare performance against baseline or between models. (e.g., "Does the Proposed Method have a higher BLEU score than the baseline?")
(5) arithmetic: Specific calculation beyond simple comparison (difference, growth rate). (e.g., "What is the percentage improvement of Large model over Base model?")
(6) temporal: Deduce trends over years or epochs. (e.g., "Which model published after 2020 has the best performance?")
(7) multi_hop: Multi-step inference finding a value first, then using it as a key. (e.g., "What is the Precision of the model with the highest Recall?")
(8) implicit_reference: Referring to specific metrics contextually without explicit column name. (e.g., "Which is the best performing model?" -> implies Bolded value or Accuracy column)
(9) ellipsis: Recovering omitted comparisons or criteria from table structure. (e.g., "How much did performance drop in 'w/o attention'?" -> implies comparison to Full Model)
- (10) long_sequence (Context-Dependent): Requires interpreting 'Experimental Setup' or 'Hypothesis' text (Context) to filter table data. **Requirement**: Must generate a hypothetical [Context] paragraph needed to solve the question.
### [Output Format (JSON)]
{{
@@ -42,7 +42,7 @@ generate_qa: |
"reasoning_annotation": "Step-by-step logic to derive answer (MUST be a string, not a list)",
"context": null
}},
- ... (One per Reasoning Type => Total 10)
+ ... (One per Reasoning Type => Total 9)
]
}}
@@ -51,7 +51,7 @@ generate_qa_from_image: |
Your mission is to analyze the provided academic table image and generate Question-Answer (QA) pairs that fit the specified Reasoning Type definitions.
### [Instructions]
- 1. **Candidate Generation & Filtering**: Internally generate 10 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 10 pairs)
+ 1. **Candidate Generation & Filtering**: Internally generate 9 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 9 pairs)
2. **Domain Suitability**: Questions must maintain an academic tone and accurately handle experimental results, performance metrics (Accuracy, F1-score, etc.), model names, and statistical significance.
3. **Strict Constraints**:
- Answers must be derived ONLY from the table (and provided context). No external knowledge.
@@ -59,6 +59,7 @@ generate_qa_from_image: |
- Output format must strictly follow JSON.
- Questions and Answers MUST be written in Korean.
- reasoning_annotation MUST be written in English and MUST be a single string (not a list).
+ - **DO NOT use real model/dataset names** (e.g., BERT, GPT, ResNet, ImageNet). Use fictional names like "Model-A", "Dataset-X", "Method-알파".
### [Validation Criteria]
- Is the answer uniquely determined within the table?
@@ -66,16 +67,15 @@ generate_qa_from_image: |
- Is the question clear and unambiguous? (e.g., "Best model" -> "Model with highest Accuracy")
### [Reasoning Type Definitions (Academic Domain)]
- (1) lookup: Retrieve specific model performance or value without condition/calculation. (e.g., "What is the ImageNet Top-1 Accuracy of ResNet-50?")
+ (1) lookup: Retrieve specific model performance or value without condition/calculation. (e.g., "What is the Top-1 Accuracy of Model-A?")
(2) filter: Select rows/columns meeting specific conditions (performance, params, etc.). (e.g., "List all models with parameters under 10M.")
- (3) aggregate: Statistical aggregation of experimental results (Sum, Avg, Max, Min, Count). (e.g., "What is the average F1-score of all BERT variants?")
- (4) compare: Compare performance against baseline or between models. (e.g., "Does the Proposed Method have a higher BLEU score than SOTA?")
+ (3) aggregate: Statistical aggregation of experimental results (Sum, Avg, Max, Min, Count). (e.g., "What is the average F1-score of all model variants?")
+ (4) compare: Compare performance against baseline or between models. (e.g., "Does the Proposed Method have a higher BLEU score than the baseline?")
(5) arithmetic: Specific calculation beyond simple comparison (difference, growth rate). (e.g., "What is the percentage improvement of Large model over Base model?")
(6) temporal: Deduce trends over years or epochs. (e.g., "Which model published after 2020 has the best performance?")
(7) multi_hop: Multi-step inference finding a value first, then using it as a key. (e.g., "What is the Precision of the model with the highest Recall?")
(8) implicit_reference: Referring to specific metrics contextually without explicit column name. (e.g., "Which is the best performing model?" -> implies Bolded value or Accuracy column)
(9) ellipsis: Recovering omitted comparisons or criteria from table structure. (e.g., "How much did performance drop in 'w/o attention'?" -> implies comparison to Full Model)
- (10) long_sequence (Context-Dependent): Requires interpreting 'Experimental Setup' or 'Hypothesis' text (Context) to filter table data. **Requirement**: Must generate a hypothetical [Context] paragraph needed to solve the question.
### [Output Format (JSON)]
{{
@@ -87,7 +87,59 @@ generate_qa_from_image: |
"reasoning_annotation": "Step-by-step logic to derive answer (MUST be a string, not a list)",
"context": null
}},
- ... (One per Reasoning Type => Total 10)
+ ... (One per Reasoning Type => Total 9)
+ ]
+ }}
+ Return ONLY the JSON object.
+
+generate_qa_from_multi_image: |
+ You are an 'AI Data Researcher' specialized in building high-quality QA datasets that require understanding MULTIPLE academic/scientific table images together.
+ Your mission is to analyze ALL provided academic table images and generate Question-Answer (QA) pairs that REQUIRE information from MULTIPLE images to answer.
+
+ **⚠️ CRITICAL REQUIREMENT: CROSS-IMAGE REASONING ⚠️**
+ - Every QA pair MUST require information from AT LEAST TWO images to answer correctly.
+ - Questions answerable from a single image are INVALID.
+ - Focus on comparisons, aggregations, or inferences that span multiple experimental results, model comparisons, or benchmark tables.
+
+ ### [Instructions]
+ 1. **Analyze All Images**: First, understand what data each image contains and how they relate (e.g., different datasets, different model ablations, training vs test results).
+ 2. **Generate Cross-Image QA**: Create 9 diverse QA pairs where each question requires synthesizing information from multiple images.
+ 3. **Strict Constraints**:
+ - Answers must be derived from combining data across images. No external knowledge.
+ - Each QA pair must correspond to exactly one Reasoning Type.
+ - Output format must strictly follow JSON.
+ - Questions and Answers MUST be written in Korean.
+ - reasoning_annotation MUST be written in English, MUST be a single string, and MUST specify which images were used.
+ - **DO NOT use real model/dataset names** (e.g., BERT, GPT, ImageNet). Use fictional names like "Model-A", "Dataset-X", "Method-알파".
+
+ ### [Validation Criteria]
+ - Does the answer REQUIRE data from multiple images? (Single-image answers are INVALID)
+ - Is the reasoning process logically flawless?
+ - Is the question clear about what experimental data is being compared or combined?
+
+ ### [Cross-Image Reasoning Type Definitions (Academic Domain)]
+ (1) cross_lookup: Retrieve and combine performance values from different result tables. (e.g., "What is Model-A's accuracy on both Dataset-X and Dataset-Y from the two tables?")
+ (2) cross_filter: Filter models across benchmark tables based on conditions. (e.g., "Which models achieve >90% accuracy on both datasets shown in the two images?")
+ (3) cross_aggregate: Aggregate experimental results spanning multiple benchmarks. (e.g., "What is the average F1-score of Method-가 across all evaluation tables?")
+ (4) cross_compare: Compare model performance between different experimental settings. (e.g., "Does the proposed method outperform the baseline on both in-domain and out-of-domain tests?")
+ (5) cross_arithmetic: Calculate performance differences using data from multiple tables. (e.g., "What is the accuracy improvement of Model-A from the ablation table to the full model table?")
+ (6) cross_temporal: Identify experimental trends by combining multiple result tables. (e.g., "Based on both training curves, which model converges faster?")
+ (7) cross_multi_hop: Multi-step academic inference across tables. (e.g., "Find the best model on Dataset-X in Image 1, then find its parameters in Image 2.")
+ (8) cross_implicit: Answer questions requiring implicit understanding of relationships between results. (e.g., "Which approach is most efficient?" requires combining accuracy and parameter count from multiple tables)
+ (9) cross_synthesis: Synthesize research insights only possible by viewing all tables together. (e.g., "Based on both the main results and ablation study, which component contributes most to performance?")
+
+ ### [Output Format (JSON)]
+ {{
+ "qa_pairs": [
+ {{
+ "question": "Question requiring multiple academic images to answer",
+ "answer": "Answer derived from multiple images",
+ "type": "cross_lookup",
+ "reasoning_annotation": "Step 1: From Image 1, extract X. Step 2: From Image 2, extract Y. Step 3: Combine to get answer.",
+ "context": null,
+ "images_used": ["image_1", "image_2"]
+ }},
+ ... (One per Reasoning Type => Total 9)
]
}}
Return ONLY the JSON object.
@@ -111,8 +163,9 @@ generate_synthetic_table: |
3. **⚠️ Data Transformation - ABSOLUTELY MANDATORY ⚠️:**
- **ALL data cell values MUST be replaced with completely new synthetic values.**
- **NEVER copy any original data values** - generate fresh, realistic alternatives.
- - For student/model names: Generate DIFFERENT names
- - For university names: Generate DIFFERENT names
+ - **NEVER use real model/dataset/university names** (BERT, GPT, ResNet, ImageNet, MIT, Stanford, etc.). Use fictional names like "Model-A", "Dataset-X", "University-가".
+ - For student/model names: Generate DIFFERENT fictional names
+ - For university names: Generate DIFFERENT fictional names
- For grades/scores: Generate DIFFERENT realistic values
- For course/research topics: Generate DIFFERENT titles
- For dates: Generate DIFFERENT plausible dates
@@ -151,7 +204,8 @@ generate_synthetic_table_from_image: |
3. **⚠️ Data Generation - ABSOLUTELY CRITICAL ⚠️:**
- **NEVER copy the data values from the image** - this is NOT an OCR task
- **ALL cell content must be completely NEW and DIFFERENT**
- - For student/model names: Generate DIFFERENT names
+ - **NEVER use real model/dataset/university names** (BERT, GPT, ResNet, ImageNet, MIT, Stanford, etc.). Use fictional names like "Model-A", "Dataset-X", "University-가".
+ - For student/model names: Generate DIFFERENT fictional names
- For grades/scores: Generate DIFFERENT values
- For course/research topics: Generate DIFFERENT titles
4. **Styling:** Use **Tailwind CSS** classes exclusively (NO inline styles).
@@ -170,3 +224,40 @@ generate_synthetic_table_from_image: |
- Score in image: "점수A" → Generate: "점수B"
⚠️ If the generated content is identical or very similar to the image, the output is INVALID.
+
+generate_long_sequence: |
+ You are an 'AI Data Researcher' specialized in creating context-dependent QA pairs for academic/scientific tables.
+ Your mission is to generate a single high-quality "long_sequence" type QA pair that requires interpreting external context to answer questions about the table.
+
+ **Input Table:**
+ {synthetic_html}
+
+ ### [Instructions]
+ 1. **Generate ONE long_sequence QA pair** that requires reading and understanding a context paragraph to filter or interpret the table data.
+ 2. **Create a realistic academic context** (e.g., "Experimental Setup", "Research Hypothesis", "Ablation Study Goals") that provides information needed to answer the question.
+ 3. **The question must be unanswerable without the context** - the context should contain key criteria or conditions.
+ 4. **Strict Constraints**:
+ - Answer must be derived from BOTH the table AND the context. Neither alone is sufficient.
+ - Questions and Answers MUST be written in Korean.
+ - reasoning_annotation MUST be written in English and MUST be a single string.
+ - Context must be written in Korean and be 2-4 sentences long.
+ - **DO NOT use real model/dataset names** (e.g., BERT, GPT, ResNet). Use fictional names.
+
+ ### [Example Scenarios (Academic)]
+ - Context describes experimental conditions (dataset size, hardware) → Question asks which models meet the criteria
+ - Context outlines baseline comparison requirements → Question asks which methods show improvement
+ - Context specifies evaluation metrics of interest → Question asks for rankings based on those metrics
+
+ ### [Output Format (JSON)]
+ {{
+ "qa_pairs": [
+ {{
+ "question": "Question requiring context to answer",
+ "answer": "Answer derived from table + context",
+ "type": "long_sequence",
+ "reasoning_annotation": "Step 1: Extract key criteria from context. Step 2: Apply criteria to table. Step 3: Derive answer.",
+ "context": "실험 설정에 따르면... (2-4 sentences of academic context in Korean)"
+ }}
+ ]
+ }}
+ Return ONLY the JSON object.
diff --git a/generate_synthetic_table/prompts/business.yaml b/generate_synthetic_table/prompts/business.yaml
index 18ebc27..40594c5 100644
--- a/generate_synthetic_table/prompts/business.yaml
+++ b/generate_synthetic_table/prompts/business.yaml
@@ -6,7 +6,7 @@ generate_qa: |
{synthetic_html}
### [Instructions]
- 1. **Candidate Generation & Filtering**: Internally generate 10 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 10 pairs)
+ 1. **Candidate Generation & Filtering**: Internally generate 9 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 9 pairs)
2. **Domain Suitability**: Questions must maintain a business tone and accurately handle revenue, profit margins, growth rates, market share, and employee performance metrics.
3. **Strict Constraints**:
- Answers must be derived ONLY from the table (and provided context). No external knowledge.
@@ -14,6 +14,7 @@ generate_qa: |
- Output format must strictly follow JSON.
- Questions and Answers MUST be written in Korean.
- reasoning_annotation MUST be written in English and MUST be a single string (not a list).
+ - **DO NOT use real company names** (e.g., Samsung, Apple, Google). Use fictional names like "A사", "B기업", "가나다 주식회사".
### [Validation Criteria]
- Is the answer uniquely determined within the table?
@@ -30,7 +31,6 @@ generate_qa: |
(7) multi_hop: Multi-step inference finding a value first, then using it as a key. (e.g., "What is the name of the Branch Manager of the branch with the #1 Revenue?")
(8) implicit_reference: Referring to specific metrics contextually without explicit column name. (e.g., "Which is the most profitable project?" -> implies Profit Margin column)
(9) ellipsis: Recovering omitted comparisons or criteria from table structure. (e.g., "What is Q4 performance?" -> implies continuation from Q1-Q3 context)
- (10) long_sequence (Context-Dependent): Requires interpreting 'Management Goals' or 'Market Conditions' text (Context) to filter table data. **Requirement**: Must generate a hypothetical [Context] paragraph needed to solve the question.
### [Output Format (JSON)]
{{
@@ -42,7 +42,7 @@ generate_qa: |
"reasoning_annotation": "Step-by-step logic to derive answer (MUST be a string, not a list)",
"context": null
}},
- ... (One per Reasoning Type => Total 10)
+ ... (One per Reasoning Type => Total 9)
]
}}
@@ -51,7 +51,7 @@ generate_qa_from_image: |
Your mission is to analyze the provided business table image and generate Question-Answer (QA) pairs that fit the specified Reasoning Type definitions.
### [Instructions]
- 1. **Candidate Generation & Filtering**: Internally generate 10 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 10 pairs)
+ 1. **Candidate Generation & Filtering**: Internally generate 9 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 9 pairs)
2. **Domain Suitability**: Questions must maintain a business tone and accurately handle revenue, profit margins, growth rates, market share, and employee performance metrics.
3. **Strict Constraints**:
- Answers must be derived ONLY from the table (and provided context). No external knowledge.
@@ -59,6 +59,7 @@ generate_qa_from_image: |
- Output format must strictly follow JSON.
- Questions and Answers MUST be written in Korean.
- reasoning_annotation MUST be written in English and MUST be a single string (not a list).
+ - **DO NOT use real company names** (e.g., Samsung, Apple, Google). Use fictional names like "A사", "B기업", "가나다 주식회사".
### [Validation Criteria]
- Is the answer uniquely determined within the table?
@@ -75,7 +76,6 @@ generate_qa_from_image: |
(7) multi_hop: Multi-step inference finding a value first, then using it as a key. (e.g., "What is the name of the Branch Manager of the branch with the #1 Revenue?")
(8) implicit_reference: Referring to specific metrics contextually without explicit column name. (e.g., "Which is the most profitable project?" -> implies Profit Margin column)
(9) ellipsis: Recovering omitted comparisons or criteria from table structure. (e.g., "What is Q4 performance?" -> implies continuation from Q1-Q3 context)
- (10) long_sequence (Context-Dependent): Requires interpreting 'Management Goals' or 'Market Conditions' text (Context) to filter table data. **Requirement**: Must generate a hypothetical [Context] paragraph needed to solve the question.
### [Output Format (JSON)]
{{
@@ -87,7 +87,59 @@ generate_qa_from_image: |
"reasoning_annotation": "Step-by-step logic to derive answer (MUST be a string, not a list)",
"context": null
}},
- ... (One per Reasoning Type => Total 10)
+ ... (One per Reasoning Type => Total 9)
+ ]
+ }}
+ Return ONLY the JSON object.
+
+generate_qa_from_multi_image: |
+ You are an 'AI Data Researcher' specialized in building high-quality QA datasets that require understanding MULTIPLE table images together.
+ Your mission is to analyze ALL provided business table images and generate Question-Answer (QA) pairs that REQUIRE information from MULTIPLE images to answer.
+
+ **⚠️ CRITICAL REQUIREMENT: CROSS-IMAGE REASONING ⚠️**
+ - Every QA pair MUST require information from AT LEAST TWO images to answer correctly.
+ - Questions answerable from a single image are INVALID.
+ - Focus on comparisons, aggregations, or inferences that span multiple tables.
+
+ ### [Instructions]
+ 1. **Analyze All Images**: First, understand what data each image contains and how they relate to each other (e.g., same company different periods, different departments, related metrics).
+ 2. **Generate Cross-Image QA**: Create 9 diverse QA pairs where each question requires synthesizing information from multiple images.
+ 3. **Strict Constraints**:
+ - Answers must be derived from combining data across images. No external knowledge.
+ - Each QA pair must correspond to exactly one Reasoning Type.
+ - Output format must strictly follow JSON.
+ - Questions and Answers MUST be written in Korean.
+ - reasoning_annotation MUST be written in English, MUST be a single string, and MUST specify which images were used.
+ - **DO NOT use real company names** (e.g., Samsung, Apple, Google). Use fictional names like "A사", "B기업", "가나다 주식회사".
+
+ ### [Validation Criteria]
+ - Does the answer REQUIRE data from multiple images? (Single-image answers are INVALID)
+ - Is the reasoning process logically flawless?
+ - Is the question clear about what is being compared or combined?
+
+ ### [Cross-Image Reasoning Type Definitions (Business Domain)]
+ (1) cross_lookup: Retrieve and combine specific values from different images. (e.g., "What is the total Q1 revenue of Branch A from both Table 1 and Table 2?")
+ (2) cross_filter: Filter rows across tables based on conditions spanning multiple images. (e.g., "Which departments appear in both tables and have positive profit margins in both?")
+ (3) cross_aggregate: Aggregate data spanning multiple images. (e.g., "What is the combined total revenue across all branches shown in both images?")
+ (4) cross_compare: Compare values or trends between different images. (e.g., "Which table shows higher average profit margin - Table 1 or Table 2?")
+ (5) cross_arithmetic: Calculate differences, ratios, or changes using data from multiple images. (e.g., "What is the revenue growth rate from the Q1 table to the Q2 table for Branch A?")
+ (6) cross_temporal: Identify trends or changes by combining time-series data from multiple images. (e.g., "Combining both annual reports, which department showed continuous growth?")
+ (7) cross_multi_hop: Multi-step inference requiring lookups across images. (e.g., "Find the top performer in Image 1, then find their metrics in Image 2.")
+ (8) cross_implicit: Answer questions requiring implicit understanding of relationships between images. (e.g., "Which region improved the most?" when improvement requires comparing two period tables)
+ (9) cross_synthesis: Synthesize insights that are only possible by viewing all images together. (e.g., "Based on both the budget table and the results table, which projects exceeded their targets?")
+
+ ### [Output Format (JSON)]
+ {{
+ "qa_pairs": [
+ {{
+ "question": "Question requiring multiple images to answer",
+ "answer": "Answer derived from multiple images",
+ "type": "cross_lookup",
+ "reasoning_annotation": "Step 1: From Image 1, extract X. Step 2: From Image 2, extract Y. Step 3: Combine to get answer.",
+ "context": null,
+ "images_used": ["image_1", "image_2"]
+ }},
+ ... (One per Reasoning Type => Total 9)
]
}}
Return ONLY the JSON object.
@@ -112,7 +164,8 @@ generate_synthetic_table: |
3. **⚠️ Data Transformation - ABSOLUTELY MANDATORY ⚠️:**
- **ALL data cell values MUST be replaced with completely new synthetic values.**
- **NEVER copy any original data values** - generate fresh, realistic alternatives.
- - For company/team names: Generate DIFFERENT names (e.g., "A팀" → "B팀")
+ - **NEVER use real company/brand names** (Samsung, Apple, Google, 현대, LG, etc.). Use fictional names like "A사", "가나다 기업", "XYZ Corp".
+ - For company/team names: Generate DIFFERENT fictional names (e.g., "A팀" → "B팀")
- For employee names: Generate DIFFERENT Korean names (e.g., "김OO" → "박OO")
- For business metrics: Generate DIFFERENT numbers (e.g., "100억" → "150억")
- For strategy/description text: Write DIFFERENT content with similar structure
@@ -156,8 +209,9 @@ generate_synthetic_table_from_image: |
3. **⚠️ Data Generation - ABSOLUTELY CRITICAL ⚠️:**
- **NEVER copy the data values from the image** - this is NOT an OCR task
- **ALL cell content must be completely NEW and DIFFERENT from the original**
+ - **NEVER use real company/brand names** (Samsung, Apple, Google, 현대, LG, etc.). Use fictional names like "A사", "가나다 기업", "XYZ Corp".
- Generate COMPLETELY NEW synthetic business values for all data cells:
- * For company/team names: Generate DIFFERENT names (e.g., "A팀" → "B팀")
+ * For company/team names: Generate DIFFERENT fictional names (e.g., "A팀" → "B팀")
* For business metrics: Generate DIFFERENT numbers (e.g., "100억" → "150억")
* For strategy/description text: Write DIFFERENT content with similar structure
* For bullet point items: Create DIFFERENT but domain-appropriate items
@@ -181,3 +235,40 @@ generate_synthetic_table_from_image: |
⚠️ If the generated content is identical or very similar to the image, the output is INVALID.
Remember: The output should be a new synthetic business dataset, not a transcription of the original.
+
+generate_long_sequence: |
+ You are an 'AI Data Researcher' specialized in creating context-dependent QA pairs for business tables.
+ Your mission is to generate a single high-quality "long_sequence" type QA pair that requires interpreting external context to answer questions about the table.
+
+ **Input Table:**
+ {synthetic_html}
+
+ ### [Instructions]
+ 1. **Generate ONE long_sequence QA pair** that requires reading and understanding a context paragraph to filter or interpret the table data.
+ 2. **Create a realistic business context** (e.g., "Management Goals", "Market Conditions", "Strategic Guidelines") that provides information needed to answer the question.
+ 3. **The question must be unanswerable without the context** - the context should contain key criteria or conditions.
+ 4. **Strict Constraints**:
+ - Answer must be derived from BOTH the table AND the context. Neither alone is sufficient.
+ - Questions and Answers MUST be written in Korean.
+ - reasoning_annotation MUST be written in English and MUST be a single string.
+ - Context must be written in Korean and be 2-4 sentences long.
+ - **DO NOT use real company names** (e.g., Samsung, Apple, Google). Use fictional names.
+
+ ### [Example Scenarios (Business)]
+ - Context describes a target market condition → Question asks which products/departments meet the criteria
+ - Context outlines budget constraints → Question asks which projects are feasible
+ - Context specifies performance thresholds → Question asks which teams qualify
+
+ ### [Output Format (JSON)]
+ {{
+ "qa_pairs": [
+ {{
+ "question": "Question requiring context to answer",
+ "answer": "Answer derived from table + context",
+ "type": "long_sequence",
+ "reasoning_annotation": "Step 1: Extract key criteria from context. Step 2: Apply criteria to table. Step 3: Derive answer.",
+ "context": "경영 목표에 따르면... (2-4 sentences of business context in Korean)"
+ }}
+ ]
+ }}
+ Return ONLY the JSON object.
diff --git a/generate_synthetic_table/prompts/default.yaml b/generate_synthetic_table/prompts/default.yaml
index 0ca2645..4940e0a 100644
--- a/generate_synthetic_table/prompts/default.yaml
+++ b/generate_synthetic_table/prompts/default.yaml
@@ -77,6 +77,52 @@ generate_qa_from_image: |
Return ONLY the JSON object, no additional text.
+generate_qa_from_multi_image: |
+ You are an expert in creating educational and reasoning questions from tabular data.
+ Your task is to analyze ALL provided table images and generate Question-Answer (QA) pairs that REQUIRE information from MULTIPLE images to answer.
+
+ **⚠️ CRITICAL REQUIREMENT: CROSS-IMAGE REASONING ⚠️**
+ - Every QA pair MUST require information from AT LEAST TWO images to answer correctly.
+ - Questions answerable from a single image are INVALID.
+ - Focus on comparisons, aggregations, or inferences that span multiple tables.
+
+ ### [Instructions]
+ 1. **Analyze All Images**: First, understand what data each image contains and how they relate to each other.
+ 2. **Generate Cross-Image QA**: Create 5 diverse QA pairs where each question requires synthesizing information from multiple images.
+ 3. **Strict Constraints**:
+ - Answers must be derived from combining data across images. No external knowledge.
+ - Output format must strictly follow JSON.
+ - Questions and Answers MUST be written in Korean.
+ - reasoning_annotation MUST be written in English, MUST be a single string, and MUST specify which images were used.
+ - **DO NOT use real company/institution names**. Use fictional names.
+
+ ### [Validation Criteria]
+ - Does the answer REQUIRE data from multiple images? (Single-image answers are INVALID)
+ - Is the reasoning process logically flawless?
+ - Is the question clear about what is being compared or combined?
+
+ ### [Cross-Image Reasoning Types]
+ - **cross_lookup**: Retrieve and combine specific values from different images.
+ - **cross_compare**: Compare values or trends between different images.
+ - **cross_aggregate**: Aggregate data spanning multiple images.
+ - **cross_arithmetic**: Calculate using data from multiple images.
+ - **cross_synthesis**: Synthesize insights only possible by viewing all images together.
+
+ ### [Output Format (JSON)]
+ {{
+ "qa_pairs": [
+ {{
+ "question": "Question requiring multiple images to answer",
+ "answer": "Answer derived from multiple images",
+ "type": "cross_lookup",
+ "reasoning_annotation": "Step 1: From Image 1, extract X. Step 2: From Image 2, extract Y. Step 3: Combine to get answer.",
+ "images_used": ["image_1", "image_2"]
+ }},
+ ... (Total 5 cross-image QA pairs)
+ ]
+ }}
+ Return ONLY the JSON object.
+
generate_synthetic_table: |
You are a Synthetic Data Generator specialized in creating completely NEW data while preserving table structure.
@@ -329,3 +375,40 @@ validate_parsed_table: |
Return a JSON object with the following keys:
- "valid": boolean (true if valid, false otherwise)
- "reason": string (brief explanation of the decision)
+
+generate_long_sequence: |
+ You are an 'AI Data Researcher' specialized in creating context-dependent QA pairs for tables.
+ Your mission is to generate a single high-quality "long_sequence" type QA pair that requires interpreting external context to answer questions about the table.
+
+ **Input Table:**
+ {synthetic_html}
+
+ ### [Instructions]
+ 1. **Generate ONE long_sequence QA pair** that requires reading and understanding a context paragraph to filter or interpret the table data.
+ 2. **Create a realistic context paragraph** (e.g., guidelines, criteria, conditions) that provides information needed to answer the question.
+ 3. **The question must be unanswerable without the context** - the context should contain key criteria or conditions.
+ 4. **Strict Constraints**:
+ - Answer must be derived from BOTH the table AND the context. Neither alone is sufficient.
+ - Questions and Answers MUST be written in Korean.
+ - reasoning_annotation MUST be written in English and MUST be a single string.
+ - Context must be written in Korean and be 2-4 sentences long.
+ - **DO NOT use real company/institution names**. Use fictional names.
+
+ ### [Example Scenarios]
+ - Context describes selection criteria → Question asks which items meet the criteria
+ - Context outlines rules/thresholds → Question asks which entries qualify
+ - Context specifies conditions → Question asks for items matching those conditions
+
+ ### [Output Format (JSON)]
+ {{
+ "qa_pairs": [
+ {{
+ "question": "Question requiring context to answer",
+ "answer": "Answer derived from table + context",
+ "type": "long_sequence",
+ "reasoning_annotation": "Step 1: Extract key criteria from context. Step 2: Apply criteria to table. Step 3: Derive answer.",
+ "context": "조건에 따르면... (2-4 sentences of context in Korean)"
+ }}
+ ]
+ }}
+ Return ONLY the JSON object.
diff --git a/generate_synthetic_table/prompts/finance.yaml b/generate_synthetic_table/prompts/finance.yaml
index 77d9927..6e700e0 100644
--- a/generate_synthetic_table/prompts/finance.yaml
+++ b/generate_synthetic_table/prompts/finance.yaml
@@ -6,7 +6,7 @@ generate_qa: |
{synthetic_html}
### [Instructions]
- 1. **Candidate Generation & Filtering**: Internally generate 10 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 10 pairs)
+ 1. **Candidate Generation & Filtering**: Internally generate 9 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 9 pairs)
2. **Domain Suitability**: Questions must maintain a financial professional tone and accurately handle stock prices, financial statements (Assets, Liabilities, Equity), investment metrics (PER, PBR, ROE), interest rates, and exchange rates.
3. **Strict Constraints**:
- Answers must be derived ONLY from the table (and provided context). No external knowledge.
@@ -14,6 +14,7 @@ generate_qa: |
- Output format must strictly follow JSON.
- Questions and Answers MUST be written in Korean.
- reasoning_annotation MUST be written in English and MUST be a single string (not a list).
+ - **DO NOT use real company names** (e.g., Samsung, Apple, Google, 현대, SK). Use fictional names like "A사", "B기업", "가나다 주식회사".
### [Validation Criteria]
- Is the answer uniquely determined within the table?
@@ -21,7 +22,7 @@ generate_qa: |
- Is the question clear and unambiguous? (e.g., "Most undervalued stock" -> "Stock with lowest PER")
### [Reasoning Type Definitions (Finance Domain)]
- (1) lookup: Retrieve specific stock price or financial figures without condition/calculation. (e.g., "What is Samsung Electronics' 2023 dividend?")
+ (1) lookup: Retrieve specific stock price or financial figures without condition/calculation. (e.g., "What is Company A's 2023 dividend?")
(2) filter: Select rows/columns meeting specific conditions (Market Cap cap, specific sector). (e.g., "List all companies with Debt Ratio under 100%.")
(3) aggregate: Statistical aggregation of portfolio or time-series data using Sum/Avg etc. (e.g., "What is the total valuation of held stocks?")
(4) compare: Compare financial health between companies or investment metrics. (e.g., "Which company has a higher ROE, Company A or B?")
@@ -30,7 +31,6 @@ generate_qa: |
(7) multi_hop: Multi-step inference finding a value first, then using it as a key. (e.g., "Who is the largest shareholder of the company with #1 Market Cap?")
(8) implicit_reference: Referring to specific metrics contextually without explicit column name. (e.g., "Which stock has strong dividend tendency?" -> implies Dividend Yield column)
(9) ellipsis: Recovering omitted comparisons or criteria from table structure. (e.g., "What is Net Income?" -> implies continuation from Operating Profit column context)
- (10) long_sequence (Context-Dependent): Requires interpreting 'Market Outlook' or 'Investment Strategy' text (Context) to filter table data. **Requirement**: Must generate a hypothetical [Context] paragraph needed to solve the question.
### [Output Format (JSON)]
{{
@@ -42,7 +42,7 @@ generate_qa: |
"reasoning_annotation": "Step-by-step logic to derive answer (MUST be a string, not a list)",
"context": null
}},
- ... (One per Reasoning Type => Total 10)
+ ... (One per Reasoning Type => Total 9)
]
}}
@@ -51,7 +51,7 @@ generate_qa_from_image: |
Your mission is to analyze the provided financial table image and generate Question-Answer (QA) pairs that fit the specified Reasoning Type definitions.
### [Instructions]
- 1. **Candidate Generation & Filtering**: Internally generate 10 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 10 pairs)
+ 1. **Candidate Generation & Filtering**: Internally generate 9 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 9 pairs)
2. **Domain Suitability**: Questions must maintain a financial professional tone and accurately handle stock prices, financial statements (Assets, Liabilities, Equity), investment metrics (PER, PBR, ROE), interest rates, and exchange rates.
3. **Strict Constraints**:
- Answers must be derived ONLY from the table (and provided context). No external knowledge.
@@ -59,6 +59,7 @@ generate_qa_from_image: |
- Output format must strictly follow JSON.
- Questions and Answers MUST be written in Korean.
- reasoning_annotation MUST be written in English and MUST be a single string (not a list).
+ - **DO NOT use real company names** (e.g., Samsung, Apple, Google, 현대, SK). Use fictional names like "A사", "B기업", "가나다 주식회사".
### [Validation Criteria]
- Is the answer uniquely determined within the table?
@@ -66,7 +67,7 @@ generate_qa_from_image: |
- Is the question clear and unambiguous? (e.g., "Most undervalued stock" -> "Stock with lowest PER")
### [Reasoning Type Definitions (Finance Domain)]
- (1) lookup: Retrieve specific stock price or financial figures without condition/calculation. (e.g., "What is Samsung Electronics' 2023 dividend?")
+ (1) lookup: Retrieve specific stock price or financial figures without condition/calculation. (e.g., "What is Company A's 2023 dividend?")
(2) filter: Select rows/columns meeting specific conditions (Market Cap cap, specific sector). (e.g., "List all companies with Debt Ratio under 100%.")
(3) aggregate: Statistical aggregation of portfolio or time-series data using Sum/Avg etc. (e.g., "What is the total valuation of held stocks?")
(4) compare: Compare financial health between companies or investment metrics. (e.g., "Which company has a higher ROE, Company A or B?")
@@ -75,7 +76,6 @@ generate_qa_from_image: |
(7) multi_hop: Multi-step inference finding a value first, then using it as a key. (e.g., "Who is the largest shareholder of the company with #1 Market Cap?")
(8) implicit_reference: Referring to specific metrics contextually without explicit column name. (e.g., "Which stock has strong dividend tendency?" -> implies Dividend Yield column)
(9) ellipsis: Recovering omitted comparisons or criteria from table structure. (e.g., "What is Net Income?" -> implies continuation from Operating Profit column context)
- (10) long_sequence (Context-Dependent): Requires interpreting 'Market Outlook' or 'Investment Strategy' text (Context) to filter table data. **Requirement**: Must generate a hypothetical [Context] paragraph needed to solve the question.
### [Output Format (JSON)]
{{
@@ -87,7 +87,59 @@ generate_qa_from_image: |
"reasoning_annotation": "Step-by-step logic to derive answer (MUST be a string, not a list)",
"context": null
}},
- ... (One per Reasoning Type => Total 10)
+ ... (One per Reasoning Type => Total 9)
+ ]
+ }}
+ Return ONLY the JSON object.
+
+generate_qa_from_multi_image: |
+ You are an 'AI Data Researcher' specialized in building high-quality QA datasets that require understanding MULTIPLE financial table images together.
+ Your mission is to analyze ALL provided financial table images and generate Question-Answer (QA) pairs that REQUIRE information from MULTIPLE images to answer.
+
+ **⚠️ CRITICAL REQUIREMENT: CROSS-IMAGE REASONING ⚠️**
+ - Every QA pair MUST require information from AT LEAST TWO images to answer correctly.
+ - Questions answerable from a single image are INVALID.
+ - Focus on comparisons, aggregations, or inferences that span multiple financial statements or reports.
+
+ ### [Instructions]
+ 1. **Analyze All Images**: First, understand what data each image contains and how they relate (e.g., different fiscal periods, income statement vs balance sheet, different securities).
+ 2. **Generate Cross-Image QA**: Create 9 diverse QA pairs where each question requires synthesizing information from multiple images.
+ 3. **Strict Constraints**:
+ - Answers must be derived from combining data across images. No external knowledge.
+ - Each QA pair must correspond to exactly one Reasoning Type.
+ - Output format must strictly follow JSON.
+ - Questions and Answers MUST be written in Korean.
+ - reasoning_annotation MUST be written in English, MUST be a single string, and MUST specify which images were used.
+ - **DO NOT use real company/fund names** (e.g., Samsung, Apple, Vanguard). Use fictional names like "A사", "B펀드", "가나다증권".
+
+ ### [Validation Criteria]
+ - Does the answer REQUIRE data from multiple images? (Single-image answers are INVALID)
+ - Is the reasoning process logically flawless?
+ - Is the question clear about what is being compared or combined?
+
+ ### [Cross-Image Reasoning Type Definitions (Finance Domain)]
+ (1) cross_lookup: Retrieve and combine specific financial values from different statements. (e.g., "What is the total assets combining both Q1 and Q2 balance sheets?")
+ (2) cross_filter: Filter entries across financial statements based on conditions. (e.g., "Which accounts show positive growth in both the income statement and cash flow statement?")
+ (3) cross_aggregate: Aggregate financial data spanning multiple periods or statements. (e.g., "What is the total revenue across all quarterly reports shown?")
+ (4) cross_compare: Compare financial ratios or metrics between different periods or portfolios. (e.g., "Did the debt-to-equity ratio improve from Table 1 to Table 2?")
+ (5) cross_arithmetic: Calculate financial metrics using data from multiple statements. (e.g., "Calculate the year-over-year revenue growth using data from both annual reports.")
+ (6) cross_temporal: Identify financial trends by combining multiple period data. (e.g., "Based on all quarterly statements, what is the profit margin trend?")
+ (7) cross_multi_hop: Multi-step financial inference across statements. (e.g., "Find the highest dividend stock in Image 1, then find its P/E ratio in Image 2.")
+ (8) cross_implicit: Answer questions requiring understanding relationships between financial statements. (e.g., "Which company is more leveraged?" requires comparing debt from multiple sources)
+ (9) cross_synthesis: Synthesize financial insights only possible by viewing all statements together. (e.g., "Based on both income and cash flow statements, which segments are cash-generative?")
+
+ ### [Output Format (JSON)]
+ {{
+ "qa_pairs": [
+ {{
+ "question": "Question requiring multiple financial images to answer",
+ "answer": "Answer derived from multiple images",
+ "type": "cross_lookup",
+ "reasoning_annotation": "Step 1: From Image 1, extract X. Step 2: From Image 2, extract Y. Step 3: Combine to get answer.",
+ "context": null,
+ "images_used": ["image_1", "image_2"]
+ }},
+ ... (One per Reasoning Type => Total 9)
]
}}
Return ONLY the JSON object.
@@ -111,7 +163,8 @@ generate_synthetic_table: |
3. **⚠️ Data Transformation - ABSOLUTELY MANDATORY ⚠️:**
- **ALL data cell values MUST be replaced with completely new synthetic values.**
- **NEVER copy any original data values** - generate fresh, realistic alternatives.
- - For company names: Generate DIFFERENT names (e.g., "A회사" → "B회사")
+ - **NEVER use real company/brand names** (Samsung, Apple, Google, 현대, SK, LG, etc.). Use fictional names like "A사", "가나다 기업", "XYZ Corp".
+ - For company names: Generate DIFFERENT fictional names (e.g., "A회사" → "B회사")
- For financial figures: Generate DIFFERENT amounts (similar magnitude, different values)
- For percentages/ratios: Generate DIFFERENT metrics
- For dates: Generate DIFFERENT plausible dates
@@ -150,7 +203,8 @@ generate_synthetic_table_from_image: |
3. **⚠️ Data Generation - ABSOLUTELY CRITICAL ⚠️:**
- **NEVER copy the data values from the image** - this is NOT an OCR task
- **ALL cell content must be completely NEW and DIFFERENT**
- - For company names: Generate DIFFERENT names
+ - **NEVER use real company/brand names** (Samsung, Apple, Google, 현대, SK, LG, etc.). Use fictional names like "A사", "가나다 기업", "XYZ Corp".
+ - For company names: Generate DIFFERENT fictional names
- For financial figures: Generate DIFFERENT amounts
- For percentages/ratios: Generate DIFFERENT metrics
4. **Styling:** Use **Tailwind CSS** classes exclusively (NO inline styles).
@@ -169,3 +223,40 @@ generate_synthetic_table_from_image: |
- Amount in image: "50억" → Generate: "80억"
⚠️ If the generated content is identical or very similar to the image, the output is INVALID.
+
+generate_long_sequence: |
+ You are an 'AI Data Researcher' specialized in creating context-dependent QA pairs for financial tables.
+ Your mission is to generate a single high-quality "long_sequence" type QA pair that requires interpreting external context to answer questions about the table.
+
+ **Input Table:**
+ {synthetic_html}
+
+ ### [Instructions]
+ 1. **Generate ONE long_sequence QA pair** that requires reading and understanding a context paragraph to filter or interpret the table data.
+ 2. **Create a realistic financial context** (e.g., "Market Outlook", "Investment Strategy", "Risk Guidelines") that provides information needed to answer the question.
+ 3. **The question must be unanswerable without the context** - the context should contain key criteria or conditions.
+ 4. **Strict Constraints**:
+ - Answer must be derived from BOTH the table AND the context. Neither alone is sufficient.
+ - Questions and Answers MUST be written in Korean.
+ - reasoning_annotation MUST be written in English and MUST be a single string.
+ - Context must be written in Korean and be 2-4 sentences long.
+ - **DO NOT use real company names** (e.g., Samsung, Apple, Google). Use fictional names.
+
+ ### [Example Scenarios (Finance)]
+ - Context describes investment criteria (PER < 15, ROE > 10%) → Question asks which stocks qualify
+ - Context outlines risk tolerance levels → Question asks which portfolio allocation is appropriate
+ - Context specifies sector preferences → Question asks which companies match the strategy
+
+ ### [Output Format (JSON)]
+ {{
+ "qa_pairs": [
+ {{
+ "question": "Question requiring context to answer",
+ "answer": "Answer derived from table + context",
+ "type": "long_sequence",
+ "reasoning_annotation": "Step 1: Extract key criteria from context. Step 2: Apply criteria to table. Step 3: Derive answer.",
+ "context": "투자 전략에 따르면... (2-4 sentences of financial context in Korean)"
+ }}
+ ]
+ }}
+ Return ONLY the JSON object.
diff --git a/generate_synthetic_table/prompts/medical.yaml b/generate_synthetic_table/prompts/medical.yaml
index 7bf995c..eb16745 100644
--- a/generate_synthetic_table/prompts/medical.yaml
+++ b/generate_synthetic_table/prompts/medical.yaml
@@ -6,7 +6,7 @@ generate_qa: |
{synthetic_html}
### [Instructions]
- 1. **Candidate Generation & Filtering**: Internally generate 10 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 10 pairs)
+ 1. **Candidate Generation & Filtering**: Internally generate 9 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 9 pairs)
2. **Domain Suitability**: Questions must maintain medical professionalism and accurately handle patient vital signs, diagnosis names, medication dosages, lab values, and prognosis.
3. **Strict Constraints**:
- Answers must be derived ONLY from the table (and provided context). No external knowledge.
@@ -15,6 +15,7 @@ generate_qa: |
- **Privacy**: Assume patient names/IDs are pseudonymized synthetic data.
- Questions and Answers MUST be written in Korean.
- reasoning_annotation MUST be written in English and MUST be a single string (not a list).
+ - **DO NOT use real hospital/drug/institution names**. Use fictional names like "A병원", "약물-X", "환자ID-001".
### [Validation Criteria]
- Is the answer uniquely determined within the table?
@@ -22,7 +23,7 @@ generate_qa: |
- Is the question clear and unambiguous? (e.g., "Patient in bad condition" -> "Patient with systolic BP under 90mmHg")
### [Reasoning Type Definitions (Medical Domain)]
- (1) lookup: Retrieve specific patient lab results or medication info without condition/calculation. (e.g., "What is the blood glucose level of Patient ID-101?")
+ (1) lookup: Retrieve specific patient lab results or medication info without condition/calculation. (e.g., "What is the blood glucose level of Patient ID-001?")
(2) filter: Select rows/columns meeting specific conditions (abnormal range, specific disease). (e.g., "List all patients with temperature above 38°C.")
(3) aggregate: Statistical aggregation of patient group data (Mean LOS, Prevalence). (e.g., "What is the average age of patients in Ward A?")
(4) compare: Compare efficacy between treatment groups or patient status pre/post. (e.g., "Is cholesterol level lower post-medication than pre-medication?")
@@ -31,7 +32,6 @@ generate_qa: |
(7) multi_hop: Multi-step inference finding a value first, then using it as a key. (e.g., "Who is the attending physician of the patient prescribed the highest dosage?")
(8) implicit_reference: Referring to specific metrics contextually without explicit column name. (e.g., "Which group is at risk of hypertension?" -> implies Systolic/Diastolic BP columns)
(9) ellipsis: Recovering omitted comparisons or criteria from table structure. (e.g., "What is the 2nd test result?" -> implies column next to 1st test)
- (10) long_sequence (Context-Dependent): Requires interpreting 'Clinical Protocol' or 'Exclusion Criteria' text (Context) to filter table data. **Requirement**: Must generate a hypothetical [Context] paragraph needed to solve the question.
### [Output Format (JSON)]
{{
@@ -43,7 +43,7 @@ generate_qa: |
"reasoning_annotation": "Step-by-step logic to derive answer (MUST be a string, not a list)",
"context": null
}},
- ... (One per Reasoning Type => Total 10)
+ ... (One per Reasoning Type => Total 9)
]
}}
@@ -52,7 +52,7 @@ generate_qa_from_image: |
Your mission is to analyze the provided medical table image and generate Question-Answer (QA) pairs that fit the specified Reasoning Type definitions.
### [Instructions]
- 1. **Candidate Generation & Filtering**: Internally generate 10 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 10 pairs)
+ 1. **Candidate Generation & Filtering**: Internally generate 9 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 9 pairs)
2. **Domain Suitability**: Questions must maintain medical professionalism and accurately handle patient vital signs, diagnosis names, medication dosages, lab values, and prognosis.
3. **Strict Constraints**:
- Answers must be derived ONLY from the table (and provided context). No external knowledge.
@@ -60,6 +60,7 @@ generate_qa_from_image: |
- Output format must strictly follow JSON.
- Questions and Answers MUST be written in Korean.
- reasoning_annotation MUST be written in English.
+ - **DO NOT use real hospital/drug/institution names**. Use fictional names like "A병원", "약물-X", "환자ID-001".
### [Validation Criteria]
- Is the answer uniquely determined within the table?
@@ -67,7 +68,7 @@ generate_qa_from_image: |
- Is the question clear and unambiguous? (e.g., "Patient in bad condition" -> "Patient with systolic BP under 90mmHg")
### [Reasoning Type Definitions (Medical Domain)]
- (1) lookup: Retrieve specific patient lab results or medication info without condition/calculation. (e.g., "What is the blood glucose level of Patient ID-101?")
+ (1) lookup: Retrieve specific patient lab results or medication info without condition/calculation. (e.g., "What is the blood glucose level of Patient ID-001?")
(2) filter: Select rows/columns meeting specific conditions (abnormal range, specific disease). (e.g., "List all patients with temperature above 38°C.")
(3) aggregate: Statistical aggregation of patient group data (Mean LOS, Prevalence). (e.g., "What is the average age of patients in Ward A?")
(4) compare: Compare efficacy between treatment groups or patient status pre/post. (e.g., "Is cholesterol level lower post-medication than pre-medication?")
@@ -76,7 +77,6 @@ generate_qa_from_image: |
(7) multi_hop: Multi-step inference finding a value first, then using it as a key. (e.g., "Who is the attending physician of the patient prescribed the highest dosage?")
(8) implicit_reference: Referring to specific metrics contextually without explicit column name. (e.g., "Which group is at risk of hypertension?" -> implies Systolic/Diastolic BP columns)
(9) ellipsis: Recovering omitted comparisons or criteria from table structure. (e.g., "What is the 2nd test result?" -> implies column next to 1st test)
- (10) long_sequence (Context-Dependent): Requires interpreting 'Clinical Protocol' or 'Exclusion Criteria' text (Context) to filter table data. **Requirement**: Must generate a hypothetical [Context] paragraph needed to solve the question.
### [Output Format (JSON)]
{{
@@ -88,7 +88,59 @@ generate_qa_from_image: |
"reasoning_annotation": "Step-by-step logic to derive answer",
"context": null
}},
- ... (One per Reasoning Type => Total 10)
+ ... (One per Reasoning Type => Total 9)
+ ]
+ }}
+ Return ONLY the JSON object.
+
+generate_qa_from_multi_image: |
+ You are an 'AI Data Researcher' specialized in building high-quality QA datasets that require understanding MULTIPLE medical/clinical table images together.
+ Your mission is to analyze ALL provided medical table images and generate Question-Answer (QA) pairs that REQUIRE information from MULTIPLE images to answer.
+
+ **⚠️ CRITICAL REQUIREMENT: CROSS-IMAGE REASONING ⚠️**
+ - Every QA pair MUST require information from AT LEAST TWO images to answer correctly.
+ - Questions answerable from a single image are INVALID.
+ - Focus on comparisons, aggregations, or inferences that span multiple clinical records, lab results, or patient cohorts.
+
+ ### [Instructions]
+ 1. **Analyze All Images**: First, understand what data each image contains and how they relate (e.g., different time points, different patient groups, lab results vs vital signs).
+ 2. **Generate Cross-Image QA**: Create 9 diverse QA pairs where each question requires synthesizing information from multiple images.
+ 3. **Strict Constraints**:
+ - Answers must be derived from combining data across images. No external knowledge.
+ - Each QA pair must correspond to exactly one Reasoning Type.
+ - Output format must strictly follow JSON.
+ - Questions and Answers MUST be written in Korean.
+ - reasoning_annotation MUST be written in English, MUST be a single string, and MUST specify which images were used.
+ - **DO NOT use real hospital/drug names**. Use fictional names like "A병원", "약물-X", "환자ID-001".
+
+ ### [Validation Criteria]
+ - Does the answer REQUIRE data from multiple images? (Single-image answers are INVALID)
+ - Is the reasoning process logically flawless?
+ - Is the question clear about what clinical data is being compared or combined?
+
+ ### [Cross-Image Reasoning Type Definitions (Medical Domain)]
+ (1) cross_lookup: Retrieve and combine patient data from different clinical records. (e.g., "What is the patient's blood glucose level before and after treatment from both tables?")
+ (2) cross_filter: Filter patients across clinical datasets based on conditions. (e.g., "Which patients appear in both the treatment and follow-up tables with improved vitals?")
+ (3) cross_aggregate: Aggregate clinical data spanning multiple patient cohorts. (e.g., "What is the average age of patients across both study groups?")
+ (4) cross_compare: Compare clinical outcomes between different time points or treatment groups. (e.g., "Did the treatment group in Table 2 show better outcomes than the control in Table 1?")
+ (5) cross_arithmetic: Calculate clinical metrics using data from multiple records. (e.g., "What is the change in BMI from the baseline table to the 6-month follow-up table?")
+ (6) cross_temporal: Identify patient progression by combining multiple visit records. (e.g., "Based on both admission and discharge tables, which patients showed improvement?")
+ (7) cross_multi_hop: Multi-step clinical inference across records. (e.g., "Find the patient with highest creatinine in Image 1, then find their blood pressure in Image 2.")
+ (8) cross_implicit: Answer questions requiring implicit understanding of clinical relationships. (e.g., "Which patients are at higher risk?" requires combining data from multiple clinical assessments)
+ (9) cross_synthesis: Synthesize clinical insights only possible by viewing all records together. (e.g., "Based on both lab results and medication tables, which patients may need dose adjustment?")
+
+ ### [Output Format (JSON)]
+ {{
+ "qa_pairs": [
+ {{
+ "question": "Question requiring multiple clinical images to answer",
+ "answer": "Answer derived from multiple images",
+ "type": "cross_lookup",
+ "reasoning_annotation": "Step 1: From Image 1, extract X. Step 2: From Image 2, extract Y. Step 3: Combine to get answer.",
+ "context": null,
+ "images_used": ["image_1", "image_2"]
+ }},
+ ... (One per Reasoning Type => Total 9)
]
}}
Return ONLY the JSON object.
@@ -112,9 +164,10 @@ generate_synthetic_table: |
3. **⚠️ Data Transformation - ABSOLUTELY MANDATORY ⚠️:**
- **ALL data cell values MUST be replaced with completely new synthetic values.**
- **NEVER copy any original data values** - generate fresh, realistic alternatives.
+ - **NEVER use real hospital/drug/institution names**. Use fictional names like "A병원", "약물-X", "제약사-가".
- For patient names/IDs: Generate DIFFERENT pseudonymized identifiers
- For lab values: Generate DIFFERENT realistic values
- - For diagnoses/medications: Generate DIFFERENT names and codes
+ - For diagnoses/medications: Generate DIFFERENT fictional names and codes
- For dates: Generate DIFFERENT plausible dates
4. **Styling:** Use **Tailwind CSS** classes (NO inline styles). **Observe and mimic the original image's visual style:**
- Look at the original image's color scheme and design
@@ -151,9 +204,10 @@ generate_synthetic_table_from_image: |
3. **⚠️ Data Generation - ABSOLUTELY CRITICAL ⚠️:**
- **NEVER copy the data values from the image** - this is NOT an OCR task
- **ALL cell content must be completely NEW and DIFFERENT**
+ - **NEVER use real hospital/drug/institution names**. Use fictional names like "A병원", "약물-X", "제약사-가".
- For patient names/IDs: Generate DIFFERENT pseudonymized identifiers
- For lab values: Generate DIFFERENT realistic values
- - For diagnoses/medications: Generate DIFFERENT names
+ - For diagnoses/medications: Generate DIFFERENT fictional names
4. **Styling:** Use **Tailwind CSS** classes exclusively (NO inline styles).
- `
`: `class="w-full border-collapse text-sm"`
- ``: `class="bg-gradient-to-r from-teal-700 to-teal-800 text-white"`
@@ -170,3 +224,40 @@ generate_synthetic_table_from_image: |
- Value in image: "수치A" → Generate: "수치B"
⚠️ If the generated content is identical or very similar to the image, the output is INVALID.
+
+generate_long_sequence: |
+ You are an 'AI Data Researcher' specialized in creating context-dependent QA pairs for medical/clinical tables.
+ Your mission is to generate a single high-quality "long_sequence" type QA pair that requires interpreting external context to answer questions about the table.
+
+ **Input Table:**
+ {synthetic_html}
+
+ ### [Instructions]
+ 1. **Generate ONE long_sequence QA pair** that requires reading and understanding a context paragraph to filter or interpret the table data.
+ 2. **Create a realistic clinical context** (e.g., "Clinical Protocol", "Exclusion Criteria", "Treatment Guidelines") that provides information needed to answer the question.
+ 3. **The question must be unanswerable without the context** - the context should contain key criteria or conditions.
+ 4. **Strict Constraints**:
+ - Answer must be derived from BOTH the table AND the context. Neither alone is sufficient.
+ - Questions and Answers MUST be written in Korean.
+ - reasoning_annotation MUST be written in English and MUST be a single string.
+ - Context must be written in Korean and be 2-4 sentences long.
+ - **DO NOT use real hospital/drug names**. Use fictional names like "A병원", "약물-X".
+
+ ### [Example Scenarios (Medical)]
+ - Context describes patient exclusion criteria (age, comorbidities) → Question asks which patients are eligible
+ - Context outlines dosage adjustment rules → Question asks which patients need dose modification
+ - Context specifies lab value thresholds for intervention → Question asks which patients require treatment
+
+ ### [Output Format (JSON)]
+ {{
+ "qa_pairs": [
+ {{
+ "question": "Question requiring context to answer",
+ "answer": "Answer derived from table + context",
+ "type": "long_sequence",
+ "reasoning_annotation": "Step 1: Extract key criteria from context. Step 2: Apply criteria to table. Step 3: Derive answer.",
+ "context": "임상 프로토콜에 따르면... (2-4 sentences of clinical context in Korean)"
+ }}
+ ]
+ }}
+ Return ONLY the JSON object.
diff --git a/generate_synthetic_table/prompts/public.yaml b/generate_synthetic_table/prompts/public.yaml
index b0c4099..4fc21e2 100644
--- a/generate_synthetic_table/prompts/public.yaml
+++ b/generate_synthetic_table/prompts/public.yaml
@@ -6,7 +6,7 @@ generate_qa: |
{synthetic_html}
### [Instructions]
- 1. **Candidate Generation & Filtering**: Internally generate 10 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 10 pairs)
+ 1. **Candidate Generation & Filtering**: Internally generate 9 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 9 pairs)
2. **Domain Suitability**: Questions must maintain a public/objective tone and accurately handle demographics, budgets, administrative region names, policy beneficiaries, and annual indicators.
3. **Strict Constraints**:
- Answers must be derived ONLY from the table (and provided context). No external knowledge.
@@ -14,6 +14,7 @@ generate_qa: |
- Output format must strictly follow JSON.
- Questions and Answers MUST be written in Korean.
- reasoning_annotation MUST be written in English and MUST be a single string (not a list).
+ - **DO NOT use real place names** (e.g., Seoul, Busan, Gyeonggi). Use fictional names like "A시", "나구", "다군".
### [Validation Criteria]
- Is the answer uniquely determined within the table?
@@ -21,16 +22,15 @@ generate_qa: |
- Is the question clear and unambiguous? (e.g., "Place with most people" -> "District with highest Population")
### [Reasoning Type Definitions (Public Domain)]
- (1) lookup: Retrieve specific regional or annual statistics without condition/calculation. (e.g., "What is the total population of Seoul in 2023?")
+ (1) lookup: Retrieve specific regional or annual statistics without condition/calculation. (e.g., "What is the total population of Region A in 2023?")
(2) filter: Select rows/columns meeting specific conditions (above/below value, specific region). (e.g., "List all departments with budget execution rate over 90%.")
- (3) aggregate: Statistical aggregation of regional/annual data (Sum, Avg). (e.g., "What is the average number of births in the 17 provinces?")
- (4) compare: Compare regional gaps or annual trends. (e.g., "Which has higher incoming migration, Gyeonggi or Seoul?")
+ (3) aggregate: Statistical aggregation of regional/annual data (Sum, Avg). (e.g., "What is the average number of births in all provinces?")
+ (4) compare: Compare regional gaps or annual trends. (e.g., "Which has higher incoming migration, Region A or Region B?")
(5) arithmetic: Specific calculation beyond simple comparison (population density, YoY growth). (e.g., "What is the population density of District A?")
(6) temporal: Deduce policy effects or long-term statistical trends. (e.g., "Which region shows a decreasing crime rate trend over the last 5 years?")
(7) multi_hop: Multi-step inference finding a value first, then using it as a key. (e.g., "Who is the Mayor of the city with the highest financial independence?")
(8) implicit_reference: Referring to specific metrics contextually without explicit column name. (e.g., "Which is the most aged city?" -> implies 65+ Population Ratio column)
(9) ellipsis: Recovering omitted comparisons or criteria from table structure. (e.g., "What is next year's target?" -> implies column next to this year's value)
- (10) long_sequence (Context-Dependent): Requires interpreting 'Policy Guidelines' or 'Legal Requirements' text (Context) to filter table data. **Requirement**: Must generate a hypothetical [Context] paragraph needed to solve the question.
### [Output Format (JSON)]
{{
@@ -42,7 +42,7 @@ generate_qa: |
"reasoning_annotation": "Step-by-step logic to derive answer (MUST be a string, not a list)",
"context": null
}},
- ... (One per Reasoning Type => Total 10)
+ ... (One per Reasoning Type => Total 9)
]
}}
@@ -51,7 +51,7 @@ generate_qa_from_image: |
Your mission is to analyze the provided public/administrative table image and generate Question-Answer (QA) pairs that fit the specified Reasoning Type definitions.
### [Instructions]
- 1. **Candidate Generation & Filtering**: Internally generate 10 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 10 pairs)
+ 1. **Candidate Generation & Filtering**: Internally generate 9 diverse QA pairs first. Then, for each Reasoning Type, select and output only the single most perfect QA pair that passes the [Validation Criteria]. (Total 9 pairs)
2. **Domain Suitability**: Questions must maintain a public/objective tone and accurately handle demographics, budgets, administrative region names, policy beneficiaries, and annual indicators.
3. **Strict Constraints**:
- Answers must be derived ONLY from the table (and provided context). No external knowledge.
@@ -59,6 +59,7 @@ generate_qa_from_image: |
- Output format must strictly follow JSON.
- Questions and Answers MUST be written in Korean.
- reasoning_annotation MUST be written in English.
+ - **DO NOT use real place names** (e.g., Seoul, Busan, Gyeonggi). Use fictional names like "A시", "나구", "다군".
### [Validation Criteria]
- Is the answer uniquely determined within the table?
@@ -66,16 +67,15 @@ generate_qa_from_image: |
- Is the question clear and unambiguous? (e.g., "Place with most people" -> "District with highest Population")
### [Reasoning Type Definitions (Public Domain)]
- (1) lookup: Retrieve specific regional or annual statistics without condition/calculation. (e.g., "What is the total population of Seoul in 2023?")
+ (1) lookup: Retrieve specific regional or annual statistics without condition/calculation. (e.g., "What is the total population of Region A in 2023?")
(2) filter: Select rows/columns meeting specific conditions (above/below value, specific region). (e.g., "List all departments with budget execution rate over 90%.")
- (3) aggregate: Statistical aggregation of regional/annual data (Sum, Avg). (e.g., "What is the average number of births in the 17 provinces?")
- (4) compare: Compare regional gaps or annual trends. (e.g., "Which has higher incoming migration, Gyeonggi or Seoul?")
+ (3) aggregate: Statistical aggregation of regional/annual data (Sum, Avg). (e.g., "What is the average number of births in all provinces?")
+ (4) compare: Compare regional gaps or annual trends. (e.g., "Which has higher incoming migration, Region A or Region B?")
(5) arithmetic: Specific calculation beyond simple comparison (population density, YoY growth). (e.g., "What is the population density of District A?")
(6) temporal: Deduce policy effects or long-term statistical trends. (e.g., "Which region shows a decreasing crime rate trend over the last 5 years?")
(7) multi_hop: Multi-step inference finding a value first, then using it as a key. (e.g., "Who is the Mayor of the city with the highest financial independence?")
(8) implicit_reference: Referring to specific metrics contextually without explicit column name. (e.g., "Which is the most aged city?" -> implies 65+ Population Ratio column)
(9) ellipsis: Recovering omitted comparisons or criteria from table structure. (e.g., "What is next year's target?" -> implies column next to this year's value)
- (10) long_sequence (Context-Dependent): Requires interpreting 'Policy Guidelines' or 'Legal Requirements' text (Context) to filter table data. **Requirement**: Must generate a hypothetical [Context] paragraph needed to solve the question.
### [Output Format (JSON)]
{{
@@ -87,7 +87,59 @@ generate_qa_from_image: |
"reasoning_annotation": "Step-by-step logic to derive answer",
"context": null
}},
- ... (One per Reasoning Type => Total 10)
+ ... (One per Reasoning Type => Total 9)
+ ]
+ }}
+ Return ONLY the JSON object.
+
+generate_qa_from_multi_image: |
+ You are an 'AI Data Researcher' specialized in building high-quality QA datasets that require understanding MULTIPLE public/government table images together.
+ Your mission is to analyze ALL provided public data table images and generate Question-Answer (QA) pairs that REQUIRE information from MULTIPLE images to answer.
+
+ **⚠️ CRITICAL REQUIREMENT: CROSS-IMAGE REASONING ⚠️**
+ - Every QA pair MUST require information from AT LEAST TWO images to answer correctly.
+ - Questions answerable from a single image are INVALID.
+ - Focus on comparisons, aggregations, or inferences that span multiple regional statistics, budget tables, or policy data.
+
+ ### [Instructions]
+ 1. **Analyze All Images**: First, understand what data each image contains and how they relate (e.g., different fiscal years, different regions, budget vs expenditure).
+ 2. **Generate Cross-Image QA**: Create 9 diverse QA pairs where each question requires synthesizing information from multiple images.
+ 3. **Strict Constraints**:
+ - Answers must be derived from combining data across images. No external knowledge.
+ - Each QA pair must correspond to exactly one Reasoning Type.
+ - Output format must strictly follow JSON.
+ - Questions and Answers MUST be written in Korean.
+ - reasoning_annotation MUST be written in English, MUST be a single string, and MUST specify which images were used.
+ - **DO NOT use real place names** (e.g., Seoul, Busan, Gyeonggi). Use fictional names like "A시", "나구", "다군".
+
+ ### [Validation Criteria]
+ - Does the answer REQUIRE data from multiple images? (Single-image answers are INVALID)
+ - Is the reasoning process logically flawless?
+ - Is the question clear about what public data is being compared or combined?
+
+ ### [Cross-Image Reasoning Type Definitions (Public Domain)]
+ (1) cross_lookup: Retrieve and combine regional statistics from different data tables. (e.g., "What is the total population of A시 combining both census tables?")
+ (2) cross_filter: Filter regions across datasets based on conditions. (e.g., "Which districts appear in both tables with budget execution rate >80%?")
+ (3) cross_aggregate: Aggregate public data spanning multiple regions or years. (e.g., "What is the total government expenditure across all departments in both fiscal year reports?")
+ (4) cross_compare: Compare regional performance between different periods or metrics. (e.g., "Did the unemployment rate improve from the 2022 table to the 2023 table for Region A?")
+ (5) cross_arithmetic: Calculate public metrics using data from multiple sources. (e.g., "What is the year-over-year population growth rate using data from both census tables?")
+ (6) cross_temporal: Identify policy trends by combining multiple year data. (e.g., "Based on both annual reports, which region shows consistent improvement in education metrics?")
+ (7) cross_multi_hop: Multi-step inference across public data tables. (e.g., "Find the region with highest tax revenue in Image 1, then find its population density in Image 2.")
+ (8) cross_implicit: Answer questions requiring implicit understanding of relationships between datasets. (e.g., "Which region is most fiscally efficient?" requires combining budget and outcome data from multiple sources)
+ (9) cross_synthesis: Synthesize policy insights only possible by viewing all tables together. (e.g., "Based on both the budget allocation and service satisfaction tables, which programs are underperforming?")
+
+ ### [Output Format (JSON)]
+ {{
+ "qa_pairs": [
+ {{
+ "question": "Question requiring multiple public data images to answer",
+ "answer": "Answer derived from multiple images",
+ "type": "cross_lookup",
+ "reasoning_annotation": "Step 1: From Image 1, extract X. Step 2: From Image 2, extract Y. Step 3: Combine to get answer.",
+ "context": null,
+ "images_used": ["image_1", "image_2"]
+ }},
+ ... (One per Reasoning Type => Total 9)
]
}}
Return ONLY the JSON object.
@@ -111,7 +163,8 @@ generate_synthetic_table: |
3. **⚠️ Data Transformation - ABSOLUTELY MANDATORY ⚠️:**
- **ALL data cell values MUST be replaced with completely new synthetic values.**
- **NEVER copy any original data values** - generate fresh, realistic alternatives.
- - For regions: Generate DIFFERENT administrative region names
+ - **NEVER use real place names** (Seoul, Busan, Gyeonggi, etc.). Use fictional names like "A시", "나구", "다군", "라도".
+ - For regions: Generate DIFFERENT fictional administrative region names
- For departments: Generate DIFFERENT department names
- For statistics: Generate DIFFERENT numbers (similar magnitude)
- For dates: Generate DIFFERENT plausible dates
@@ -150,7 +203,8 @@ generate_synthetic_table_from_image: |
3. **⚠️ Data Generation - ABSOLUTELY CRITICAL ⚠️:**
- **NEVER copy the data values from the image** - this is NOT an OCR task
- **ALL cell content must be completely NEW and DIFFERENT**
- - For regions: Generate DIFFERENT administrative region names
+ - **NEVER use real place names** (Seoul, Busan, Gyeonggi, etc.). Use fictional names like "A시", "나구", "다군", "라도".
+ - For regions: Generate DIFFERENT fictional administrative region names
- For statistics: Generate DIFFERENT numbers
- For departments: Generate DIFFERENT names
4. **Styling:** Use **Tailwind CSS** classes exclusively (NO inline styles).
@@ -169,3 +223,40 @@ generate_synthetic_table_from_image: |
- Statistic in image: "수치A" → Generate: "수치B"
⚠️ If the generated content is identical or very similar to the image, the output is INVALID.
+
+generate_long_sequence: |
+ You are an 'AI Data Researcher' specialized in creating context-dependent QA pairs for public/government data tables.
+ Your mission is to generate a single high-quality "long_sequence" type QA pair that requires interpreting external context to answer questions about the table.
+
+ **Input Table:**
+ {synthetic_html}
+
+ ### [Instructions]
+ 1. **Generate ONE long_sequence QA pair** that requires reading and understanding a context paragraph to filter or interpret the table data.
+ 2. **Create a realistic public policy context** (e.g., "Policy Guidelines", "Legal Requirements", "Budget Allocation Rules") that provides information needed to answer the question.
+ 3. **The question must be unanswerable without the context** - the context should contain key criteria or conditions.
+ 4. **Strict Constraints**:
+ - Answer must be derived from BOTH the table AND the context. Neither alone is sufficient.
+ - Questions and Answers MUST be written in Korean.
+ - reasoning_annotation MUST be written in English and MUST be a single string.
+ - Context must be written in Korean and be 2-4 sentences long.
+ - **DO NOT use real place names** (e.g., Seoul, Busan). Use fictional names.
+
+ ### [Example Scenarios (Public)]
+ - Context describes eligibility criteria for a subsidy → Question asks which regions qualify
+ - Context outlines budget allocation rules → Question asks which departments receive funding
+ - Context specifies demographic thresholds → Question asks which areas need intervention
+
+ ### [Output Format (JSON)]
+ {{
+ "qa_pairs": [
+ {{
+ "question": "Question requiring context to answer",
+ "answer": "Answer derived from table + context",
+ "type": "long_sequence",
+ "reasoning_annotation": "Step 1: Extract key criteria from context. Step 2: Apply criteria to table. Step 3: Derive answer.",
+ "context": "정책 지침에 따르면... (2-4 sentences of policy context in Korean)"
+ }}
+ ]
+ }}
+ Return ONLY the JSON object.
diff --git a/multi_image_json_list/test_academic_input.json b/multi_image_json_list/test_academic_input.json
new file mode 100755
index 0000000..478bf45
--- /dev/null
+++ b/multi_image_json_list/test_academic_input.json
@@ -0,0 +1,192 @@
+[
+ {
+ "index": 0,
+ "pair_id": "A_origin_0_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_0/A_table_0.png",
+ "data/Academic/Table/A_origin_0/A_table_1.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 1,
+ "pair_id": "A_origin_0_1",
+ "image_paths": [
+ "data/Academic/Table/A_origin_0/A_table_2.png",
+ "data/Academic/Table/A_origin_0/A_table_3.png",
+ "data/Academic/Table/A_origin_0/A_table_4.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 2,
+ "pair_id": "A_origin_1_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_1/A_table_5.png",
+ "data/Academic/Table/A_origin_1/A_table_6.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 3,
+ "pair_id": "A_origin_2_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_2/A_table_8.png",
+ "data/Academic/Table/A_origin_2/A_table_9.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 4,
+ "pair_id": "A_origin_3_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_3/A_table_10.png",
+ "data/Academic/Table/A_origin_3/A_table_11.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 5,
+ "pair_id": "A_origin_4_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_4/A_table_12.png",
+ "data/Academic/Table/A_origin_4/A_table_13.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 6,
+ "pair_id": "A_origin_5_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_5/A_table_14.png",
+ "data/Academic/Table/A_origin_5/A_table_15.png",
+ "data/Academic/Table/A_origin_5/A_table_16.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 7,
+ "pair_id": "A_origin_6_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_6/A_table_17.png",
+ "data/Academic/Table/A_origin_6/A_table_18.png",
+ "data/Academic/Table/A_origin_6/A_table_19.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 8,
+ "pair_id": "A_origin_7_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_7/A_table_20.png",
+ "data/Academic/Table/A_origin_7/A_table_21.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 9,
+ "pair_id": "A_origin_8_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_8/A_table_22.png",
+ "data/Academic/Table/A_origin_8/A_table_23.png",
+ "data/Academic/Table/A_origin_8/A_table_24.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 10,
+ "pair_id": "A_origin_9_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_9/A_table_25.png",
+ "data/Academic/Table/A_origin_9/A_table_26.png",
+ "data/Academic/Table/A_origin_9/A_table_27.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 11,
+ "pair_id": "A_origin_10_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_10/A_table_28.png",
+ "data/Academic/Table/A_origin_10/A_table_29.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 12,
+ "pair_id": "A_origin_11_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_11/A_table_30.png",
+ "data/Academic/Table/A_origin_11/A_table_31.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 13,
+ "pair_id": "A_origin_12_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_12/A_table_32.png",
+ "data/Academic/Table/A_origin_12/A_table_33.png",
+ "data/Academic/Table/A_origin_12/A_table_34.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 14,
+ "pair_id": "A_origin_14_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_14/A_table_39.png",
+ "data/Academic/Table/A_origin_14/A_table_40.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 15,
+ "pair_id": "A_origin_18_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_18/A_table_47.png",
+ "data/Academic/Table/A_origin_18/A_table_48.png",
+ "data/Academic/Table/A_origin_18/A_table_49.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 16,
+ "pair_id": "A_origin_26_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_26/A_table_59_01.png",
+ "data/Academic/Table/A_origin_26/A_table_59_02.png",
+ "data/Academic/Table/A_origin_26/A_table_60.png",
+ "data/Academic/Table/A_origin_26/A_table_61.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 17,
+ "pair_id": "A_origin_28_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_28/A_table_63_01.png",
+ "data/Academic/Table/A_origin_28/A_table_63_02.png",
+ "data/Academic/Table/A_origin_28/A_table_64.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 18,
+ "pair_id": "A_origin_36_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_36/A_table_73.png",
+ "data/Academic/Table/A_origin_36/A_table_75.png"
+ ],
+ "domain": "academic"
+ },
+ {
+ "index": 19,
+ "pair_id": "A_origin_43_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_43/A_table_89.png",
+ "data/Academic/Table/A_origin_43/A_table_90.png"
+ ],
+ "domain": "academic"
+ }
+]
\ No newline at end of file
diff --git a/multi_image_json_list/test_business_input.json b/multi_image_json_list/test_business_input.json
new file mode 100755
index 0000000..ace8a1f
--- /dev/null
+++ b/multi_image_json_list/test_business_input.json
@@ -0,0 +1,173 @@
+[
+ {
+ "index": 0,
+ "pair_id": "B_origin_0_0_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_0/B_table_0_0.png",
+ "data/Business/Table/B_origin_0/B_table_1_0.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 1,
+ "pair_id": "B_origin_3_3_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_3/B_table_10_0.png",
+ "data/Business/Table/B_origin_3/B_table_11_0.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 2,
+ "pair_id": "B_origin_4_4_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_4/B_table_16_0.png",
+ "data/Business/Table/B_origin_4/B_table_16_1.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 3,
+ "pair_id": "B_origin_4_4_1",
+ "image_paths": [
+ "data/Business/Table/B_origin_4/B_table_14_0.png",
+ "data/Business/Table/B_origin_4/B_table_15_0.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 4,
+ "pair_id": "B_origin_6_6_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_6/B_table_20_0.png",
+ "data/Business/Table/B_origin_6/B_table_21_0.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 5,
+ "pair_id": "B_origin_2_10_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_2/B_table_6_0.png",
+ "data/Business/Table/B_origin_6/B_table_23_0.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 7,
+ "pair_id": "B_origin_14_14_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_14/B_table_45_0.png",
+ "data/Business/Table/B_origin_14/B_table_45_1.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 8,
+ "pair_id": "B_origin_15_15_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_15/B_table_51_0.png",
+ "data/Business/Table/B_origin_15/B_table_51_1.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 9,
+ "pair_id": "B_origin_10_15_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_10/B_table_33_0.png",
+ "data/Business/Table/B_origin_15/B_table_52_0.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 10,
+ "pair_id": "B_origin_18_18_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_18/B_table_63_0.png",
+ "data/Business/Table/B_origin_18/B_table_63_1.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 11,
+ "pair_id": "B_origin_18_18_1",
+ "image_paths": [
+ "data/Business/Table/B_origin_18/B_table_61_0.png",
+ "data/Business/Table/B_origin_18/B_table_64_0.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 12,
+ "pair_id": "B_origin_20_20_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_20/B_table_68_0.png",
+ "data/Business/Table/B_origin_20/B_table_69_0.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 13,
+ "pair_id": "B_origin_21_21_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_21/B_table_70_0.png",
+ "data/Business/Table/B_origin_21/B_table_71_0.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 14,
+ "pair_id": "B_origin_21_21_1",
+ "image_paths": [
+ "data/Business/Table/B_origin_21/B_table_72_0.png",
+ "data/Business/Table/B_origin_21/B_table_72_1.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 15,
+ "pair_id": "B_origin_23_23_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_23/B_table_80_0.png",
+ "data/Business/Table/B_origin_23/B_table_81_0.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 16,
+ "pair_id": "B_origin_23_23_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_23/B_table_80_0.png",
+ "data/Business/Table/B_origin_23/B_table_81_0.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 17,
+ "pair_id": "B_origin_24_24_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_24/B_table_83_0.png",
+ "data/Business/Table/B_origin_24/B_table_84_0.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 18,
+ "pair_id": "B_origin_32_32_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_32/B_table_110_0.png",
+ "data/Business/Table/B_origin_32/B_table_112_0.png"
+ ],
+ "domain": "Business"
+ },
+ {
+ "index": 19,
+ "pair_id": "B_origin_37_37_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_37/B_table_132_0.png",
+ "data/Business/Table/B_origin_37/B_table_132_1.png"
+ ],
+ "domain": "Business"
+ }
+]
\ No newline at end of file
diff --git a/multi_image_json_list/test_finance_input.json b/multi_image_json_list/test_finance_input.json
new file mode 100755
index 0000000..98b7491
--- /dev/null
+++ b/multi_image_json_list/test_finance_input.json
@@ -0,0 +1,182 @@
+[
+ {
+ "index": 0,
+ "pair_id": "F_table_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_0/F_table_0_0.png",
+ "data/Finance/Table/F_origin_3/F_table_5_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 1,
+ "pair_id": "F_table_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_4/F_table_6_0.png",
+ "data/Finance/Table/F_origin_6/F_table_8_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 2,
+ "pair_id": "F_table_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_10/F_table_14_0.png",
+ "data/Finance/Table/F_origin_16/F_table_16_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 3,
+ "pair_id": "F_table_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_21/F_table_71_0.png",
+ "data/Finance/Table/F_origin_23/F_table_74_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 4,
+ "pair_id": "F_table_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_38/F_table_122_0.png",
+ "data/Finance/Table/F_origin_39/F_table_123_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 5,
+ "pair_id": "F_table_5",
+ "image_paths": [
+ "data/Finance/Table/F_origin_41/F_table_129_0.png",
+ "data/Finance/Table/F_origin_42/F_table_130_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 6,
+ "pair_id": "F_table_6",
+ "image_paths": [
+ "data/Finance/Table/F_origin_43/F_table_131_0.png",
+ "data/Finance/Table/F_origin_44/F_table_132_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 7,
+ "pair_id": "F_table_7",
+ "image_paths": [
+ "data/Finance/Table/F_origin_45/F_table_136_0.png",
+ "data/Finance/Table/F_origin_49/F_table_146_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 8,
+ "pair_id": "F_table_8",
+ "image_paths": [
+ "data/Finance/Table/F_origin_0/F_table_0_0.png",
+ "data/Finance/Table/F_origin_0/F_table_1_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 9,
+ "pair_id": "F_table_9",
+ "image_paths": [
+ "data/Finance/Table/F_origin_2/F_table_3_1.png",
+ "data/Finance/Table/F_origin_2/F_table_4_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 10,
+ "pair_id": "F_table_10",
+ "image_paths": [
+ "data/Finance/Table/F_origin_6/F_table_8_1.png",
+ "data/Finance/Table/F_origin_6/F_table_9_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 11,
+ "pair_id": "F_table_11",
+ "image_paths": [
+ "data/Finance/Table/F_origin_16/F_table_39_0.png",
+ "data/Finance/Table/F_origin_16/F_table_45_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 12,
+ "pair_id": "F_table_12",
+ "image_paths": [
+ "data/Finance/Table/F_origin_1/F_table_2_0.png",
+ "data/Finance/Table/F_origin_11/F_table_15_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 13,
+ "pair_id": "F_table_13",
+ "image_paths": [
+ "data/Finance/Table/F_origin_3/F_table_5_0.png",
+ "data/Finance/Table/F_origin_13/F_table_21_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 14,
+ "pair_id": "F_table_14",
+ "image_paths": [
+ "data/Finance/Table/F_origin_4/F_table_6_0.png",
+ "data/Finance/Table/F_origin_23/F_table_74_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 15,
+ "pair_id": "F_table_15",
+ "image_paths": [
+ "data/Finance/Table/F_origin_10/F_table_14_0.png",
+ "data/Finance/Table/F_origin_21/F_table_71_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 16,
+ "pair_id": "F_table_16",
+ "image_paths": [
+ "data/Finance/Table/F_origin_12/F_table_16_0.png",
+ "data/Finance/Table/F_origin_45/F_table_136_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 17,
+ "pair_id": "F_table_17",
+ "image_paths": [
+ "data/Finance/Table/F_origin_17/F_table_49_0.png",
+ "data/Finance/Table/F_origin_48/F_table_143_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 18,
+ "pair_id": "F_table_18",
+ "image_paths": [
+ "data/Finance/Table/F_origin_38/F_table_122_0.png",
+ "data/Finance/Table/F_origin_45/F_table_136_0.png"
+ ],
+ "domain": "finance"
+ },
+ {
+ "index": 19,
+ "pair_id": "F_table_19",
+ "image_paths": [
+ "data/Finance/Table/F_origin_43/F_table_131_0.png",
+ "data/Finance/Table/F_origin_49/F_table_146_0.png"
+ ],
+ "domain": "finance"
+ }
+]
\ No newline at end of file
diff --git a/multi_image_json_list/test_medical_input.json b/multi_image_json_list/test_medical_input.json
new file mode 100755
index 0000000..279ef70
--- /dev/null
+++ b/multi_image_json_list/test_medical_input.json
@@ -0,0 +1,164 @@
+[
+ {
+ "index": 0,
+ "pair_id": "M_origin_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_0_0_0.png",
+ "data/Medical/Table/M_table_0_1_0.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 1,
+ "pair_id": "M_origin_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_0_0.png",
+ "data/Medical/Table/M_table_2_1_0.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 2,
+ "pair_id": "M_origin_3",
+ "image_paths": [
+ "data/Medical/Table/M_table_3_0_1.png",
+ "data/Medical/Table/M_table_3_0_2.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 3,
+ "pair_id": "M_origin_4",
+ "image_paths": [
+ "data/Medical/Table/M_table_4_0_0.png",
+ "data/Medical/Table/M_table_4_0_1.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 4,
+ "pair_id": "M_revised_2_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_2_0.png",
+ "data/Medical/Table/M_table_2_2_1.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 5,
+ "pair_id": "M_revised_3_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_3_0_0.png",
+ "data/Medical/Table/M_table_3_0_1.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 6,
+ "pair_id": "M_revised_4_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_4_0_0.png",
+ "data/Medical/Table/M_table_4_0_1.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 7,
+ "pair_id": "M_revised_6_3",
+ "image_paths": [
+ "data/Medical/Table/M_table_6_3_0.png",
+ "data/Medical/Table/M_table_6_3_1.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 8,
+ "pair_id": "M_revised_8_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_8_0_0.png",
+ "data/Medical/Table/M_table_8_0_1.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 9,
+ "pair_id": "M_revised_9_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_9_0_0.png",
+ "data/Medical/Table/M_table_9_0_1.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 10,
+ "pair_id": "M_revised_10_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_0_0.png",
+ "data/Medical/Table/M_table_10_0_1.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 11,
+ "pair_id": "M_revised_11_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_11_0_0.png",
+ "data/Medical/Table/M_table_11_0_1.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 12,
+ "pair_id": "M_revised_13_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_13_0_0.png",
+ "data/Medical/Table/M_table_13_0_1.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 13,
+ "pair_id": "M_revised_14_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_14_0_0.png",
+ "data/Medical/Table/M_table_14_0_1.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 14,
+ "pair_id": "M_revised_15_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_0_0.png",
+ "data/Medical/Table/M_table_15_0_1.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 15,
+ "pair_id": "M_revised_16_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_16_0_0.png",
+ "data/Medical/Table/M_table_16_0_1.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 16,
+ "pair_id": "M_revised_2_3",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_3_0.png",
+ "data/Medical/Table/M_table_2_3_1.png"
+ ],
+ "domain": "medical"
+ },
+ {
+ "index": 17,
+ "pair_id": "M_revised_10_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_1_0.png",
+ "data/Medical/Table/M_table_10_1_1.png"
+ ],
+ "domain": "medical"
+ }
+]
\ No newline at end of file
diff --git a/multi_image_json_list/test_public_input.json b/multi_image_json_list/test_public_input.json
new file mode 100755
index 0000000..832ef44
--- /dev/null
+++ b/multi_image_json_list/test_public_input.json
@@ -0,0 +1,182 @@
+[
+ {
+ "index": 0,
+ "pair_id": "P_origin_0_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_0/P_origin_0_1_0.png",
+ "data/Public/Table/P_origin_0/P_origin_0_1_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 1,
+ "pair_id": "P_origin_0_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_0/P_origin_0_2_1.png",
+ "data/Public/Table/P_origin_0/P_origin_0_2_2.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 2,
+ "pair_id": "P_origin_1_9",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_9_0.png",
+ "data/Public/Table/P_origin_1/P_origin_1_9_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 3,
+ "pair_id": "P_origin_1_10",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_10_0.png",
+ "data/Public/Table/P_origin_1/P_origin_1_10_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 4,
+ "pair_id": "P_origin_1_12",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_12_0.png",
+ "data/Public/Table/P_origin_1/P_origin_1_12_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 5,
+ "pair_id": "P_origin_1_16",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_16_0.png",
+ "data/Public/Table/P_origin_1/P_origin_1_16_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 6,
+ "pair_id": "P_origin_1_17",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_17_0.png",
+ "data/Public/Table/P_origin_1/P_origin_1_17_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 7,
+ "pair_id": "P_origin_1_18",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_18_0.png",
+ "data/Public/Table/P_origin_1/P_origin_1_18_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 8,
+ "pair_id": "P_origin_1_23",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_23_0.png",
+ "data/Public/Table/P_origin_1/P_origin_1_23_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 9,
+ "pair_id": "P_origin_2_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_2/P_origin_2_0_0.png",
+ "data/Public/Table/P_origin_2/P_origin_2_0_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 10,
+ "pair_id": "P_origin_3_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_3/P_origin_3_2_0.png",
+ "data/Public/Table/P_origin_3/P_origin_3_2_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 11,
+ "pair_id": "P_origin_4_9",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_9_0.png",
+ "data/Public/Table/P_origin_4/P_origin_4_9_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 12,
+ "pair_id": "P_origin_4_11",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_11_0.png",
+ "data/Public/Table/P_origin_4/P_origin_4_11_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 13,
+ "pair_id": "P_origin_5_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_1_0.png",
+ "data/Public/Table/P_origin_5/P_origin_5_1_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 14,
+ "pair_id": "P_origin_5_17",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_17_0.png",
+ "data/Public/Table/P_origin_5/P_origin_5_17_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 15,
+ "pair_id": "P_origin_6_12",
+ "image_paths": [
+ "data/Public/Table/P_origin_6/P_origin_6_12_0.png",
+ "data/Public/Table/P_origin_6/P_origin_6_12_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 16,
+ "pair_id": "P_origin_7_4",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_4_0.png",
+ "data/Public/Table/P_origin_7/P_origin_7_4_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 17,
+ "pair_id": "P_origin_7_8",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_8_0.png",
+ "data/Public/Table/P_origin_7/P_origin_7_8_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 18,
+ "pair_id": "P_origin_8_14",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_14_0.png",
+ "data/Public/Table/P_origin_8/P_origin_8_14_1.png"
+ ],
+ "domain": "public"
+ },
+ {
+ "index": 19,
+ "pair_id": "P_origin_9_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_0_1.png",
+ "data/Public/Table/P_origin_9/P_origin_9_0_2.png"
+ ],
+ "domain": "public"
+ }
+]
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 513cc81..8d5c460 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -32,4 +32,5 @@ dependencies = [
"pymongo>=4.6.1",
"langgraph-checkpoint-sqlite>=3.0.1",
"notion-client>=2.0.0",
+ "playwright>=1.57.0",
]
diff --git a/regenerate_qa.py b/regenerate_qa.py
new file mode 100755
index 0000000..008dac4
--- /dev/null
+++ b/regenerate_qa.py
@@ -0,0 +1,455 @@
+#!/usr/bin/env python3
+"""
+기존 synthetic 테이블에서 QA를 재생성하는 스크립트.
+
+output_*/html/ 디렉토리의 HTML 파일을 직접 읽어서 새로운 QA pairs를 생성합니다.
+pipeline_output.json은 entry 목록과 결과 저장에만 사용됩니다.
+
+Usage:
+ # 특정 도메인 재생성
+ python regenerate_qa.py --domain business
+
+ # 여러 도메인 재생성
+ python regenerate_qa.py --domain business finance academic medical
+
+ # 모든 도메인 재생성 (output_public 제외)
+ python regenerate_qa.py --all
+
+ # 특정 provider/model 사용
+ python regenerate_qa.py --domain business --provider openai --model gpt-4o
+"""
+
+import argparse
+import json
+import logging
+import os
+import re
+import sys
+from pathlib import Path
+from typing import List, Dict, Any, Optional
+from concurrent.futures import ThreadPoolExecutor, as_completed
+from datetime import datetime
+
+from dotenv import load_dotenv
+
+load_dotenv()
+
+# Add project root to path
+project_root = Path(__file__).parent
+sys.path.insert(0, str(project_root))
+
+from generate_synthetic_table.flow import (
+ _load_prompt,
+ _call_llm,
+ robust_json_parse,
+)
+
+logging.basicConfig(
+ level=logging.INFO,
+ format="%(asctime)s - %(levelname)s - %(message)s"
+)
+logger = logging.getLogger(__name__)
+
+# 도메인별 output 디렉토리
+DOMAIN_DIRS = {
+ "academic": "output_academic",
+ "business": "output_business",
+ "finance": "output_finance",
+ "medical": "output_medical",
+ # "public": "output_public", # 제외
+}
+
+
+def get_llm_client(provider: str, model: str):
+ """LLM 클라이언트 생성"""
+ from langchain_openai import ChatOpenAI
+ from langchain_anthropic import ChatAnthropic
+ from langchain_google_genai import ChatGoogleGenerativeAI
+
+ if provider == "openai":
+ return ChatOpenAI(
+ model=model,
+ temperature=0.7,
+ api_key=os.getenv("OPENAI_API_KEY"),
+ )
+ elif provider in ["claude", "anthropic"]:
+ return ChatAnthropic(
+ model=model,
+ temperature=0.7,
+ api_key=os.getenv("ANTHROPIC_API_KEY"),
+ )
+ elif provider in ["gemini", "google"]:
+ return ChatGoogleGenerativeAI(
+ model=model,
+ temperature=0.7,
+ google_api_key=os.getenv("GOOGLE_API_KEY"),
+ )
+ else:
+ raise ValueError(f"Unknown provider: {provider}")
+
+
+def find_html_files(output_dir: Path, pair_id: str) -> List[Path]:
+ """
+ output_dir/html/ 디렉토리에서 pair_id에 해당하는 HTML 파일들을 찾습니다.
+
+ 파일 패턴: {pair_id}_table_*.html
+ 예: B_origin_0_0_0_table_0.html, B_origin_0_0_0_table_1.html
+ """
+ html_dir = output_dir / "html"
+ if not html_dir.exists():
+ return []
+
+ # pair_id로 시작하는 HTML 파일 찾기
+ pattern = f"{pair_id}_table_*.html"
+ html_files = sorted(html_dir.glob(pattern))
+
+ return html_files
+
+
+def read_html_files(html_files: List[Path]) -> List[str]:
+ """
+ HTML 파일들을 읽어서 내용을 반환합니다.
+ """
+ html_contents = []
+ for html_file in html_files:
+ try:
+ with open(html_file, "r", encoding="utf-8") as f:
+ content = f.read().strip()
+ if content:
+ html_contents.append(content)
+ except Exception as e:
+ logger.warning(f"Failed to read {html_file}: {e}")
+
+ return html_contents
+
+
+def generate_qa_for_table(
+ llm,
+ synthetic_html: str,
+ domain: str,
+) -> List[Dict[str, Any]]:
+ """단일 synthetic table에 대해 QA를 생성합니다."""
+ try:
+ prompt_template = _load_prompt("generate_qa", domain)
+ prompt = prompt_template.format(synthetic_html=synthetic_html)
+
+ response_text, _ = _call_llm(llm, prompt, return_token_usage=True)
+ response_json = robust_json_parse(response_text)
+
+ if response_json and "qa_pairs" in response_json:
+ return response_json["qa_pairs"]
+ else:
+ logger.warning("QA generation did not return valid qa_pairs")
+ return []
+ except Exception as e:
+ logger.error(f"Failed to generate QA: {e}")
+ return []
+
+
+def generate_long_sequence_for_table(
+ llm,
+ synthetic_html: str,
+ domain: str,
+) -> List[Dict[str, Any]]:
+ """단일 synthetic table에 대해 long_sequence QA를 생성합니다."""
+ try:
+ prompt_template = _load_prompt("generate_long_sequence", domain)
+ prompt = prompt_template.format(synthetic_html=synthetic_html)
+
+ response_text, _ = _call_llm(llm, prompt, return_token_usage=True)
+ response_json = robust_json_parse(response_text)
+
+ if response_json and "qa_pairs" in response_json:
+ return response_json["qa_pairs"]
+ else:
+ return []
+ except ValueError:
+ # generate_long_sequence prompt not found
+ return []
+ except Exception as e:
+ logger.warning(f"Failed to generate long_sequence QA: {e}")
+ return []
+
+
+def regenerate_qa_for_entry(
+ llm,
+ entry: Dict[str, Any],
+ output_dir: Path,
+ domain: str,
+ include_long_sequence: bool = True,
+) -> Dict[str, Any]:
+ """
+ 단일 entry에 대해 QA를 재생성합니다.
+
+ html/ 디렉토리에서 HTML 파일을 직접 읽어서 QA를 생성합니다.
+ 여러 테이블이 있는 경우, 각 테이블에 대해 QA를 생성하고 합칩니다.
+ """
+ pair_id = entry.get("pair_id", entry.get("name", "unknown"))
+
+ # HTML 파일 찾기 및 읽기
+ html_files = find_html_files(output_dir, pair_id)
+ if not html_files:
+ logger.warning(f"No HTML files found for {pair_id} in {output_dir}/html/")
+ return entry
+
+ synthetic_tables = read_html_files(html_files)
+ if not synthetic_tables:
+ logger.warning(f"Failed to read HTML files for {pair_id}")
+ return entry
+
+ logger.info(f" Found {len(html_files)} HTML files: {[f.name for f in html_files]}")
+
+ all_qa_results = []
+
+ # 각 테이블에 대해 QA 생성
+ for idx, synthetic_html in enumerate(synthetic_tables):
+ logger.info(f" Generating QA for table {idx + 1}/{len(synthetic_tables)}")
+
+ # 기본 QA 생성 (9개 타입)
+ qa_results = generate_qa_for_table(llm, synthetic_html, domain)
+ all_qa_results.extend(qa_results)
+
+ # long_sequence QA 생성 (선택적)
+ if include_long_sequence:
+ long_seq_results = generate_long_sequence_for_table(llm, synthetic_html, domain)
+ all_qa_results.extend(long_seq_results)
+
+ # 결과 업데이트
+ updated_entry = entry.copy()
+ updated_entry["qa_results"] = all_qa_results
+ updated_entry["qa_regenerated_at"] = datetime.now().isoformat()
+ updated_entry["html_files_used"] = [f.name for f in html_files]
+
+ return updated_entry
+
+
+def regenerate_qa_for_domain(
+ domain: str,
+ provider: str = "claude",
+ model: str = "claude-sonnet-4-5",
+ include_long_sequence: bool = True,
+ limit: Optional[int] = None,
+ dry_run: bool = False,
+) -> Dict[str, Any]:
+ """
+ 특정 도메인의 모든 entry에 대해 QA를 재생성합니다.
+ """
+ domain_dir = DOMAIN_DIRS.get(domain)
+ if not domain_dir:
+ raise ValueError(f"Unknown domain: {domain}")
+
+ output_dir = project_root / domain_dir
+ pipeline_output_path = output_dir / "pipeline_output.json"
+
+ if not pipeline_output_path.exists():
+ raise FileNotFoundError(f"pipeline_output.json not found: {pipeline_output_path}")
+
+ # Load existing data
+ with open(pipeline_output_path, "r", encoding="utf-8") as f:
+ data = json.load(f)
+
+ logger.info(f"Loaded {len(data)} entries from {pipeline_output_path}")
+
+ if limit:
+ data = data[:limit]
+ logger.info(f"Limited to {limit} entries")
+
+ if dry_run:
+ logger.info("Dry run mode - not regenerating QA")
+ # HTML 파일 존재 여부 확인
+ html_dir = output_dir / "html"
+ if not html_dir.exists():
+ logger.warning(f"HTML directory not found: {html_dir}")
+ return {"domain": domain, "entries": len(data), "dry_run": True, "html_dir_exists": False}
+
+ # 각 entry에 대해 HTML 파일 수 확인
+ entries_with_html = 0
+ total_html_files = 0
+ for entry in data:
+ pair_id = entry.get("pair_id", entry.get("name", ""))
+ html_files = find_html_files(output_dir, pair_id)
+ if html_files:
+ entries_with_html += 1
+ total_html_files += len(html_files)
+ logger.info(f" {pair_id}: {len(html_files)} HTML files")
+
+ logger.info(f"Summary: {entries_with_html}/{len(data)} entries have HTML files ({total_html_files} total)")
+ return {
+ "domain": domain,
+ "entries": len(data),
+ "entries_with_html": entries_with_html,
+ "total_html_files": total_html_files,
+ "dry_run": True,
+ }
+
+ # Create LLM client
+ llm = get_llm_client(provider, model)
+
+ # Regenerate QA for each entry
+ updated_data = []
+ success_count = 0
+ error_count = 0
+
+ for i, entry in enumerate(data):
+ pair_id = entry.get("pair_id", entry.get("name", f"entry_{i}"))
+ logger.info(f"[{i + 1}/{len(data)}] Processing: {pair_id}")
+
+ try:
+ updated_entry = regenerate_qa_for_entry(
+ llm,
+ entry,
+ output_dir,
+ domain,
+ include_long_sequence=include_long_sequence,
+ )
+ updated_data.append(updated_entry)
+
+ qa_count = len(updated_entry.get("qa_results", []))
+ logger.info(f" Generated {qa_count} QA pairs")
+ success_count += 1
+ except Exception as e:
+ logger.error(f" Failed: {e}")
+ updated_data.append(entry) # Keep original
+ error_count += 1
+
+ # Backup original file
+ backup_path = output_dir / f"pipeline_output_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
+ with open(backup_path, "w", encoding="utf-8") as f:
+ json.dump(data, f, ensure_ascii=False, indent=2)
+ logger.info(f"Backed up original to {backup_path}")
+
+ # Save updated data
+ with open(pipeline_output_path, "w", encoding="utf-8") as f:
+ json.dump(updated_data, f, ensure_ascii=False, indent=2)
+ logger.info(f"Saved updated data to {pipeline_output_path}")
+
+ return {
+ "domain": domain,
+ "total_entries": len(data),
+ "success": success_count,
+ "errors": error_count,
+ "backup": str(backup_path),
+ }
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="기존 synthetic 테이블에서 QA를 재생성합니다.",
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ epilog="""
+Examples:
+ # 특정 도메인 재생성
+ python regenerate_qa.py --domain business
+
+ # 여러 도메인 재생성
+ python regenerate_qa.py --domain business finance
+
+ # 모든 도메인 재생성 (output_public 제외)
+ python regenerate_qa.py --all
+
+ # OpenAI 사용
+ python regenerate_qa.py --domain business --provider openai --model gpt-4o
+
+ # 테스트 (5개만)
+ python regenerate_qa.py --domain business --limit 5
+
+ # Dry run (실제 재생성 없이 확인만)
+ python regenerate_qa.py --domain business --dry-run
+ """
+ )
+
+ parser.add_argument(
+ "--domain",
+ nargs="+",
+ choices=list(DOMAIN_DIRS.keys()),
+ help="재생성할 도메인(들)",
+ )
+ parser.add_argument(
+ "--all",
+ action="store_true",
+ help="모든 도메인 재생성 (output_public 제외)",
+ )
+ parser.add_argument(
+ "--provider",
+ default="claude",
+ choices=["claude", "anthropic", "openai", "gemini", "google"],
+ help="LLM 제공자 (default: claude)",
+ )
+ parser.add_argument(
+ "--model",
+ default="claude-sonnet-4-5",
+ help="모델 이름 (default: claude-sonnet-4-5)",
+ )
+ parser.add_argument(
+ "--no-long-sequence",
+ action="store_true",
+ help="long_sequence QA 생성 스킵",
+ )
+ parser.add_argument(
+ "--limit",
+ type=int,
+ help="처리할 최대 entry 수 (테스트용)",
+ )
+ parser.add_argument(
+ "--dry-run",
+ action="store_true",
+ help="실제 재생성 없이 확인만",
+ )
+
+ args = parser.parse_args()
+
+ # Determine domains to process
+ if args.all:
+ domains = list(DOMAIN_DIRS.keys())
+ elif args.domain:
+ domains = args.domain
+ else:
+ parser.error("--domain 또는 --all을 지정해야 합니다.")
+
+ logger.info(f"Domains to process: {domains}")
+ logger.info(f"Provider: {args.provider}, Model: {args.model}")
+
+ # Process each domain
+ results = []
+ for domain in domains:
+ logger.info(f"\n{'='*60}")
+ logger.info(f"Processing domain: {domain}")
+ logger.info(f"{'='*60}")
+
+ try:
+ result = regenerate_qa_for_domain(
+ domain=domain,
+ provider=args.provider,
+ model=args.model,
+ include_long_sequence=not args.no_long_sequence,
+ limit=args.limit,
+ dry_run=args.dry_run,
+ )
+ results.append(result)
+ logger.info(f"Completed: {result}")
+ except Exception as e:
+ logger.error(f"Failed to process {domain}: {e}")
+ results.append({"domain": domain, "error": str(e)})
+
+ # Summary
+ print("\n" + "=" * 60)
+ print(" QA Regeneration Summary")
+ print("=" * 60)
+ for result in results:
+ domain = result.get("domain", "unknown")
+ if "error" in result:
+ print(f" {domain}: ERROR - {result['error']}")
+ elif result.get("dry_run"):
+ html_info = ""
+ if "entries_with_html" in result:
+ html_info = f", {result['entries_with_html']}/{result['entries']} with HTML ({result['total_html_files']} files)"
+ elif result.get("html_dir_exists") is False:
+ html_info = ", NO html/ directory!"
+ print(f" {domain}: {result.get('entries', 0)} entries (dry run){html_info}")
+ else:
+ print(f" {domain}: {result.get('success', 0)}/{result.get('total_entries', 0)} success, {result.get('errors', 0)} errors")
+ print("=" * 60)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/run_all.sh b/run_all.sh
new file mode 100755
index 0000000..87ed09f
--- /dev/null
+++ b/run_all.sh
@@ -0,0 +1,536 @@
+#!/bin/bash
+
+# ==============================================================================
+# TableMagnifier - Master Pipeline Script
+# ==============================================================================
+#
+# 전체 파이프라인을 통합 실행합니다:
+# 1. Synthetic Table 생성 (from JSON input)
+# 2. HTML → Image 변환
+# 3. QA 재생성 (선택)
+# 4. QA 난이도 필터링 (vLLM 필요)
+# 5. 평가 (vLLM 필요)
+#
+# Usage:
+# ./run_all.sh --input data.json --domain business [OPTIONS]
+#
+# Examples:
+# # 기본 파이프라인 (테이블 생성 + 이미지 변환)
+# ./run_all.sh --input test.json --domain business
+#
+# # 전체 파이프라인 (vLLM 평가 포함)
+# ./run_all.sh --input test.json --domain business --with-eval --vllm-url http://localhost:8000/v1
+#
+# # QA 재생성만
+# ./run_all.sh --domain business --regenerate-qa-only
+#
+# # 필터링 + 평가만 (이미 테이블/이미지가 있는 경우)
+# ./run_all.sh --domain business --filter-only --with-eval
+#
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+cd "$SCRIPT_DIR"
+
+# ==============================================================================
+# Configuration
+# ==============================================================================
+
+# Default values
+INPUT_JSON=""
+DOMAIN=""
+OUTPUT_DIR=""
+PROVIDER="claude"
+MODEL="claude-sonnet-4-5"
+VLLM_URL="http://localhost:8000/v1"
+
+# Pipeline steps (default: generate + capture)
+DO_GENERATE=true
+DO_CAPTURE=true
+DO_REGENERATE_QA=false
+DO_FILTER=false
+DO_EVAL=false
+
+# Options
+LIMIT=""
+DRY_RUN=false
+SKIP_QA=false
+FILTER_TRIALS=10
+FILTER_MIN_ACC=0.3
+FILTER_MAX_ACC=0.6
+
+# Colors
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+RED='\033[0;31m'
+BLUE='\033[0;34m'
+CYAN='\033[0;36m'
+BOLD='\033[1m'
+NC='\033[0m'
+
+# ==============================================================================
+# Helper Functions
+# ==============================================================================
+
+echo_header() {
+ echo ""
+ echo -e "${BLUE}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
+ echo -e "${BLUE}${BOLD} $1${NC}"
+ echo -e "${BLUE}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
+}
+
+echo_step() {
+ echo ""
+ echo -e "${CYAN}▶ STEP $1: $2${NC}"
+ echo -e "${CYAN}─────────────────────────────────────────────────────────────${NC}"
+}
+
+echo_info() {
+ echo -e "${GREEN}[INFO]${NC} $1"
+}
+
+echo_warn() {
+ echo -e "${YELLOW}[WARN]${NC} $1"
+}
+
+echo_error() {
+ echo -e "${RED}[ERROR]${NC} $1"
+}
+
+echo_success() {
+ echo -e "${GREEN}[SUCCESS]${NC} $1"
+}
+
+show_help() {
+ cat << 'EOF'
+Usage: ./run_all.sh [OPTIONS]
+
+TableMagnifier 전체 파이프라인을 통합 실행합니다.
+
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+ Required Options
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+ --domain DOMAIN 도메인 (business, finance, academic, medical, public)
+
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+ Pipeline Steps
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+ --input FILE 입력 JSON 파일 (테이블 생성 시 필수)
+ --regenerate-qa QA 재생성 포함
+ --regenerate-qa-only QA 재생성만 실행 (테이블 생성 스킵)
+ --with-filter vLLM으로 QA 난이도 필터링 포함
+ --filter-only 필터링만 실행 (테이블/이미지 생성 스킵)
+ --with-eval vLLM으로 평가 포함
+ --eval-only 평가만 실행
+
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+ Generation Options
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+ --output-dir DIR 출력 디렉토리 (default: output_{domain})
+ --provider PROVIDER LLM 제공자: claude, openai, gemini (default: claude)
+ --model MODEL 모델 이름 (default: claude-sonnet-4-5)
+ --skip-qa 테이블 생성 시 QA 생성 스킵
+
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+ vLLM Options (for filter/eval)
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+ --vllm-url URL vLLM 서버 URL (default: http://localhost:8000/v1)
+ --filter-trials N 필터링 시 QA당 시도 횟수 (default: 10)
+ --filter-min-acc FLOAT 필터링 최소 정확도 (default: 0.3)
+ --filter-max-acc FLOAT 필터링 최대 정확도 (default: 0.6)
+
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+ Other Options
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+ --limit N 처리할 최대 entry 수 (테스트용)
+ --dry-run 실제 실행 없이 확인만
+ -h, --help 도움말 표시
+
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+ Examples
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+ # 1. 기본 파이프라인 (테이블 생성 → 이미지 변환)
+ ./run_all.sh --input test.json --domain business
+
+ # 2. 전체 파이프라인 (생성 → 이미지 → 필터링 → 평가)
+ ./run_all.sh --input test.json --domain business --with-filter --with-eval
+
+ # 3. QA만 재생성 (기존 테이블 유지)
+ ./run_all.sh --domain business --regenerate-qa-only
+
+ # 4. 필터링만 (이미 이미지가 있는 경우)
+ ./run_all.sh --domain business --filter-only
+
+ # 5. 평가만
+ ./run_all.sh --domain business --eval-only
+
+ # 6. OpenAI 사용
+ ./run_all.sh --input test.json --domain business --provider openai --model gpt-4o
+
+ # 7. 테스트 (3개만)
+ ./run_all.sh --input test.json --domain business --limit 3 --dry-run
+
+EOF
+}
+
+# ==============================================================================
+# Argument Parsing
+# ==============================================================================
+
+# Parse first argument as JSON file if it ends with .json
+if [[ "$1" == *.json ]]; then
+ INPUT_JSON="$1"
+ shift
+fi
+
+while [[ $# -gt 0 ]]; do
+ case $1 in
+ --input)
+ INPUT_JSON="$2"
+ shift 2
+ ;;
+ --domain)
+ DOMAIN="$2"
+ shift 2
+ ;;
+ --output-dir)
+ OUTPUT_DIR="$2"
+ shift 2
+ ;;
+ --provider)
+ PROVIDER="$2"
+ shift 2
+ ;;
+ --model)
+ MODEL="$2"
+ shift 2
+ ;;
+ --vllm-url)
+ VLLM_URL="$2"
+ shift 2
+ ;;
+ --regenerate-qa)
+ DO_REGENERATE_QA=true
+ shift
+ ;;
+ --regenerate-qa-only)
+ DO_GENERATE=false
+ DO_CAPTURE=false
+ DO_REGENERATE_QA=true
+ shift
+ ;;
+ --with-filter)
+ DO_FILTER=true
+ shift
+ ;;
+ --filter-only)
+ DO_GENERATE=false
+ DO_CAPTURE=false
+ DO_FILTER=true
+ shift
+ ;;
+ --with-eval)
+ DO_EVAL=true
+ shift
+ ;;
+ --eval-only)
+ DO_GENERATE=false
+ DO_CAPTURE=false
+ DO_EVAL=true
+ shift
+ ;;
+ --filter-trials)
+ FILTER_TRIALS="$2"
+ shift 2
+ ;;
+ --filter-min-acc)
+ FILTER_MIN_ACC="$2"
+ shift 2
+ ;;
+ --filter-max-acc)
+ FILTER_MAX_ACC="$2"
+ shift 2
+ ;;
+ --skip-qa)
+ SKIP_QA=true
+ shift
+ ;;
+ --limit)
+ LIMIT="$2"
+ shift 2
+ ;;
+ --dry-run)
+ DRY_RUN=true
+ shift
+ ;;
+ -h|--help)
+ show_help
+ exit 0
+ ;;
+ *)
+ echo_error "Unknown option: $1"
+ echo "Use -h or --help for usage information."
+ exit 1
+ ;;
+ esac
+done
+
+# ==============================================================================
+# Validation
+# ==============================================================================
+
+# Domain is always required
+if [[ -z "$DOMAIN" ]]; then
+ echo_error "--domain is required"
+ echo "Use -h or --help for usage information."
+ exit 1
+fi
+
+# Input JSON required for generation
+if [[ "$DO_GENERATE" == true ]] && [[ -z "$INPUT_JSON" ]]; then
+ echo_error "--input is required for table generation"
+ echo "Use --regenerate-qa-only, --filter-only, or --eval-only to skip generation."
+ exit 1
+fi
+
+# Check input file exists
+if [[ -n "$INPUT_JSON" ]] && [[ ! -f "$INPUT_JSON" ]]; then
+ echo_error "Input file not found: $INPUT_JSON"
+ exit 1
+fi
+
+# Set default output directory
+if [[ -z "$OUTPUT_DIR" ]]; then
+ OUTPUT_DIR="output_${DOMAIN}"
+fi
+
+# ==============================================================================
+# Check Dependencies
+# ==============================================================================
+
+check_vllm_connection() {
+ if curl -s --connect-timeout 5 "${VLLM_URL}/models" > /dev/null 2>&1; then
+ VLLM_MODEL=$(curl -s "${VLLM_URL}/models" | python3 -c "import sys, json; data = json.load(sys.stdin); print(data['data'][0]['id'] if data.get('data') else 'unknown')" 2>/dev/null || echo "unknown")
+ echo_info "vLLM connected: ${VLLM_MODEL}"
+ return 0
+ else
+ return 1
+ fi
+}
+
+check_api_key() {
+ case $PROVIDER in
+ claude|anthropic)
+ if [[ -z "$ANTHROPIC_API_KEY" ]]; then
+ echo_warn "ANTHROPIC_API_KEY is not set"
+ fi
+ ;;
+ openai)
+ if [[ -z "$OPENAI_API_KEY" ]]; then
+ echo_warn "OPENAI_API_KEY is not set"
+ fi
+ ;;
+ gemini|google)
+ if [[ -z "$GOOGLE_API_KEY" ]]; then
+ echo_warn "GOOGLE_API_KEY is not set"
+ fi
+ ;;
+ esac
+}
+
+# ==============================================================================
+# Main Pipeline
+# ==============================================================================
+
+echo_header "TableMagnifier - Master Pipeline"
+
+echo ""
+echo "Configuration:"
+echo " Domain: $DOMAIN"
+echo " Output Dir: $OUTPUT_DIR"
+echo " Provider: $PROVIDER"
+echo " Model: $MODEL"
+if [[ -n "$INPUT_JSON" ]]; then
+ echo " Input JSON: $INPUT_JSON"
+fi
+if [[ -n "$LIMIT" ]]; then
+ echo " Limit: $LIMIT entries"
+fi
+if [[ "$DRY_RUN" == true ]]; then
+ echo " Mode: DRY RUN"
+fi
+echo ""
+echo "Pipeline Steps:"
+echo " 1. Generate Tables: $([ "$DO_GENERATE" == true ] && echo "✓" || echo "✗")"
+echo " 2. Capture Images: $([ "$DO_CAPTURE" == true ] && echo "✓" || echo "✗")"
+echo " 3. Regenerate QA: $([ "$DO_REGENERATE_QA" == true ] && echo "✓" || echo "✗")"
+echo " 4. Filter QA: $([ "$DO_FILTER" == true ] && echo "✓" || echo "✗")"
+echo " 5. Evaluate: $([ "$DO_EVAL" == true ] && echo "✓" || echo "✗")"
+echo ""
+
+# Check API key for generation steps
+if [[ "$DO_GENERATE" == true ]] || [[ "$DO_REGENERATE_QA" == true ]]; then
+ check_api_key
+fi
+
+# Check vLLM for filter/eval steps
+if [[ "$DO_FILTER" == true ]] || [[ "$DO_EVAL" == true ]]; then
+ echo_info "Checking vLLM connection..."
+ if ! check_vllm_connection; then
+ echo_error "Cannot connect to vLLM server at ${VLLM_URL}"
+ echo_error "Please ensure vLLM server is running for filter/eval steps."
+ exit 1
+ fi
+fi
+
+STEP_NUM=0
+
+# ------------------------------------------------------------------------------
+# Step 1: Generate Synthetic Tables
+# ------------------------------------------------------------------------------
+if [[ "$DO_GENERATE" == true ]]; then
+ STEP_NUM=$((STEP_NUM + 1))
+ echo_step $STEP_NUM "Generate Synthetic Tables"
+
+ GENERATE_ARGS="--input \"$INPUT_JSON\" --output-dir \"$OUTPUT_DIR\" --provider \"$PROVIDER\" --model \"$MODEL\" --domain \"$DOMAIN\""
+
+ if [[ "$SKIP_QA" == true ]]; then
+ GENERATE_ARGS="$GENERATE_ARGS --skip-qa"
+ fi
+
+ if [[ -n "$LIMIT" ]]; then
+ GENERATE_ARGS="$GENERATE_ARGS --limit $LIMIT"
+ fi
+
+ if [[ "$DRY_RUN" == true ]]; then
+ echo_info "[DRY RUN] Would run: uv run python run_pipeline_json.py $GENERATE_ARGS"
+ else
+ eval "uv run python run_pipeline_json.py $GENERATE_ARGS"
+ echo_success "Table generation completed"
+ fi
+fi
+
+# ------------------------------------------------------------------------------
+# Step 2: Capture HTML to Images
+# ------------------------------------------------------------------------------
+if [[ "$DO_CAPTURE" == true ]]; then
+ STEP_NUM=$((STEP_NUM + 1))
+ echo_step $STEP_NUM "Capture HTML to Images"
+
+ CAPTURE_ARGS="--output-dirs $OUTPUT_DIR"
+
+ if [[ "$DRY_RUN" == true ]]; then
+ echo_info "[DRY RUN] Would run: uv run python capture_html_images.py $CAPTURE_ARGS"
+ else
+ uv run python capture_html_images.py $CAPTURE_ARGS
+ echo_success "Image capture completed"
+ fi
+fi
+
+# ------------------------------------------------------------------------------
+# Step 3: Regenerate QA (Optional)
+# ------------------------------------------------------------------------------
+if [[ "$DO_REGENERATE_QA" == true ]]; then
+ STEP_NUM=$((STEP_NUM + 1))
+ echo_step $STEP_NUM "Regenerate QA"
+
+ REGEN_ARGS="--domain $DOMAIN --provider $PROVIDER --model $MODEL"
+
+ if [[ -n "$LIMIT" ]]; then
+ REGEN_ARGS="$REGEN_ARGS --limit $LIMIT"
+ fi
+
+ if [[ "$DRY_RUN" == true ]]; then
+ REGEN_ARGS="$REGEN_ARGS --dry-run"
+ fi
+
+ uv run python regenerate_qa.py $REGEN_ARGS
+ echo_success "QA regeneration completed"
+fi
+
+# ------------------------------------------------------------------------------
+# Step 4: Filter QA by Difficulty (Optional)
+# ------------------------------------------------------------------------------
+if [[ "$DO_FILTER" == true ]]; then
+ STEP_NUM=$((STEP_NUM + 1))
+ echo_step $STEP_NUM "Filter QA by Difficulty"
+
+ FILTER_ARGS="--domain $DOMAIN --vllm-url $VLLM_URL --trials $FILTER_TRIALS --min-acc $FILTER_MIN_ACC --max-acc $FILTER_MAX_ACC"
+
+ if [[ -n "$LIMIT" ]]; then
+ FILTER_ARGS="$FILTER_ARGS --limit $LIMIT"
+ fi
+
+ if [[ "$DRY_RUN" == true ]]; then
+ FILTER_ARGS="$FILTER_ARGS --dry-run"
+ fi
+
+ uv run python filter_qa_by_difficulty.py $FILTER_ARGS
+ echo_success "QA filtering completed"
+fi
+
+# ------------------------------------------------------------------------------
+# Step 5: Evaluate (Optional)
+# ------------------------------------------------------------------------------
+if [[ "$DO_EVAL" == true ]]; then
+ STEP_NUM=$((STEP_NUM + 1))
+ echo_step $STEP_NUM "Evaluate with vLLM"
+
+ EVAL_ARGS="--domain $DOMAIN --vllm-url $VLLM_URL"
+
+ if [[ -n "$LIMIT" ]]; then
+ EVAL_ARGS="$EVAL_ARGS --limit $LIMIT"
+ fi
+
+ if [[ "$DRY_RUN" == true ]]; then
+ EVAL_ARGS="$EVAL_ARGS --dry-run"
+ fi
+
+ uv run python -m eval.evaluate_vllm $EVAL_ARGS
+ echo_success "Evaluation completed"
+fi
+
+# ==============================================================================
+# Summary
+# ==============================================================================
+
+echo_header "Pipeline Completed"
+
+echo ""
+echo "Output Directory: $OUTPUT_DIR/"
+echo ""
+echo "Generated Files:"
+
+if [[ -d "$OUTPUT_DIR" ]]; then
+ # Count files
+ JSON_COUNT=$(find "$OUTPUT_DIR" -maxdepth 1 -name "*.json" 2>/dev/null | wc -l)
+ HTML_COUNT=$(find "$OUTPUT_DIR/html" -name "*.html" 2>/dev/null | wc -l)
+ IMAGE_COUNT=$(find "$OUTPUT_DIR/images" -name "*.png" 2>/dev/null | wc -l)
+
+ echo " - JSON files: $JSON_COUNT"
+ echo " - HTML files: $HTML_COUNT (in html/)"
+ echo " - Images: $IMAGE_COUNT (in images/)"
+
+ if [[ "$DO_FILTER" == true ]] && [[ "$DRY_RUN" != true ]]; then
+ REVIEW_FILE=$(ls -t "$OUTPUT_DIR"/qa_for_review_*.json 2>/dev/null | head -1)
+ if [[ -n "$REVIEW_FILE" ]]; then
+ REVIEW_COUNT=$(python3 -c "import json; print(json.load(open('$REVIEW_FILE'))['count'])" 2>/dev/null || echo "?")
+ echo ""
+ echo " Review File: $(basename $REVIEW_FILE)"
+ echo " QA for Review: $REVIEW_COUNT items"
+ fi
+ fi
+
+ if [[ "$DO_EVAL" == true ]] && [[ "$DRY_RUN" != true ]]; then
+ EVAL_FILE=$(ls -t "$OUTPUT_DIR"/eval_results_*.json 2>/dev/null | head -1)
+ if [[ -n "$EVAL_FILE" ]]; then
+ echo ""
+ echo " Eval Results: $(basename $EVAL_FILE)"
+ fi
+ fi
+fi
+
+echo ""
+echo -e "${GREEN}Done!${NC}"
diff --git a/run_capture_html.sh b/run_capture_html.sh
new file mode 100755
index 0000000..fb3a9df
--- /dev/null
+++ b/run_capture_html.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# ==============================================================================
+# HTML to Image Capture Script
+# Captures HTML files from output_*/html/ directories as PNG images
+# ==============================================================================
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+echo "==================================="
+echo " HTML to Image Capture"
+echo "==================================="
+
+# Check if playwright is installed
+if ! uv run python -c "import playwright" 2>/dev/null; then
+ echo "[INFO] Installing playwright..."
+ uv add playwright
+ uv run playwright install chromium
+fi
+
+# Run the capture script
+uv run python "$SCRIPT_DIR/capture_html_images.py" "$@"
diff --git a/run_evaluate_vllm.sh b/run_evaluate_vllm.sh
new file mode 100755
index 0000000..762a672
--- /dev/null
+++ b/run_evaluate_vllm.sh
@@ -0,0 +1,255 @@
+#!/bin/bash
+#
+# vLLM 서버를 사용한 Table QA 평가 스크립트
+#
+# 사전 요구사항:
+# 1. vLLM 서버가 실행 중이어야 합니다
+# 2. HTML 파일들이 이미지로 캡처되어 있어야 합니다 (./run_capture_html.sh 실행)
+#
+# Usage:
+# ./run_evaluate_vllm.sh [OPTIONS]
+#
+# Examples:
+# # 모든 도메인 평가
+# ./run_evaluate_vllm.sh --all-domains
+#
+# # 단일 도메인 평가
+# ./run_evaluate_vllm.sh --domain public
+#
+# # 커스텀 vLLM URL
+# ./run_evaluate_vllm.sh --domain public --vllm-url http://gpu-server:8000/v1
+#
+# # 특정 모델 사용
+# ./run_evaluate_vllm.sh --domain business --model Qwen/Qwen2.5-VL-7B-Instruct
+#
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+cd "$SCRIPT_DIR"
+
+# 기본 설정
+VLLM_URL="${VLLM_URL:-http://localhost:8000/v1}"
+MODEL="${MODEL:-default}"
+OUTPUT_DIR="${OUTPUT_DIR:-eval_results}"
+
+# 색상 정의
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+echo_info() {
+ echo -e "${GREEN}[INFO]${NC} $1"
+}
+
+echo_warn() {
+ echo -e "${YELLOW}[WARN]${NC} $1"
+}
+
+echo_error() {
+ echo -e "${RED}[ERROR]${NC} $1"
+}
+
+# 헬프 메시지
+show_help() {
+ cat << EOF
+Usage: $0 [OPTIONS]
+
+vLLM 서버를 사용한 Table QA 평가
+
+Options:
+ --domain DOMAIN 평가할 도메인 (academic, business, finance, medical, public)
+ --all-domains 모든 도메인 평가
+ --vllm-url URL vLLM 서버 URL (default: $VLLM_URL)
+ --model MODEL 사용할 모델 이름 (default: $MODEL)
+ --output-dir DIR 결과 저장 디렉토리 (default: $OUTPUT_DIR)
+ --use-judge LLM-as-Judge 평가 사용
+ --judge-model MODEL Judge 모델 (default: gpt-4o-mini)
+ --limit N 평가할 최대 샘플 수 (디버깅용)
+ --qa-types TYPES 특정 QA 타입만 평가 (예: "lookup compare")
+ --capture-html 평가 전 HTML을 이미지로 캡처
+ -h, --help 이 도움말 표시
+
+Environment Variables:
+ VLLM_URL vLLM 서버 URL
+ MODEL 사용할 모델 이름
+ OUTPUT_DIR 결과 저장 디렉토리
+ OPENAI_API_KEY LLM-as-Judge 사용 시 OpenAI API 키
+
+Examples:
+ # 모든 도메인 평가
+ $0 --all-domains
+
+ # public 도메인만 평가
+ $0 --domain public
+
+ # LLM-as-Judge 포함 평가
+ $0 --domain finance --use-judge --judge-model gpt-4o
+
+ # 10개 샘플로 빠른 테스트
+ $0 --domain public --limit 10
+EOF
+}
+
+# vLLM 서버 연결 확인
+check_vllm_connection() {
+ local url=$1
+ echo_info "vLLM 서버 연결 확인: $url"
+
+ # /v1/models 엔드포인트로 연결 테스트
+ if curl -s --connect-timeout 5 "$url/models" > /dev/null 2>&1; then
+ echo_info "vLLM 서버 연결 성공"
+ return 0
+ else
+ echo_error "vLLM 서버에 연결할 수 없습니다: $url"
+ echo_error "vLLM 서버가 실행 중인지 확인하세요."
+ return 1
+ fi
+}
+
+# 이미지 디렉토리 확인
+check_images() {
+ local domains=("academic" "business" "finance" "medical" "public")
+ local missing=0
+
+ for domain in "${domains[@]}"; do
+ local output_dir="output_${domain}"
+ local images_dir="${output_dir}/images"
+
+ if [[ -d "$output_dir" ]]; then
+ if [[ ! -d "$images_dir" ]] || [[ -z "$(ls -A "$images_dir" 2>/dev/null)" ]]; then
+ echo_warn "$domain: 이미지 디렉토리가 비어있거나 없습니다 ($images_dir)"
+ ((missing++))
+ fi
+ fi
+ done
+
+ if [[ $missing -gt 0 ]]; then
+ echo_warn "일부 도메인에 이미지가 없습니다. HTML 캡처가 필요할 수 있습니다."
+ echo_warn "실행: ./run_capture_html.sh"
+ fi
+}
+
+# 인자 파싱
+DOMAIN=""
+ALL_DOMAINS=false
+CAPTURE_HTML=false
+USE_JUDGE=false
+JUDGE_MODEL=""
+LIMIT=""
+QA_TYPES=""
+
+while [[ $# -gt 0 ]]; do
+ case $1 in
+ --domain)
+ DOMAIN="$2"
+ shift 2
+ ;;
+ --all-domains)
+ ALL_DOMAINS=true
+ shift
+ ;;
+ --vllm-url)
+ VLLM_URL="$2"
+ shift 2
+ ;;
+ --model)
+ MODEL="$2"
+ shift 2
+ ;;
+ --output-dir)
+ OUTPUT_DIR="$2"
+ shift 2
+ ;;
+ --use-judge)
+ USE_JUDGE=true
+ shift
+ ;;
+ --judge-model)
+ JUDGE_MODEL="$2"
+ shift 2
+ ;;
+ --limit)
+ LIMIT="$2"
+ shift 2
+ ;;
+ --qa-types)
+ QA_TYPES="$2"
+ shift 2
+ ;;
+ --capture-html)
+ CAPTURE_HTML=true
+ shift
+ ;;
+ -h|--help)
+ show_help
+ exit 0
+ ;;
+ *)
+ echo_error "알 수 없는 옵션: $1"
+ show_help
+ exit 1
+ ;;
+ esac
+done
+
+# 인자 검증
+if [[ -z "$DOMAIN" ]] && [[ "$ALL_DOMAINS" != true ]]; then
+ echo_error "--domain 또는 --all-domains를 지정해야 합니다."
+ show_help
+ exit 1
+fi
+
+# HTML 캡처 (옵션)
+if [[ "$CAPTURE_HTML" == true ]]; then
+ echo_info "HTML 파일을 이미지로 캡처합니다..."
+ if [[ -f "./run_capture_html.sh" ]]; then
+ ./run_capture_html.sh
+ else
+ echo_warn "run_capture_html.sh를 찾을 수 없습니다. 스킵합니다."
+ fi
+fi
+
+# vLLM 연결 확인
+check_vllm_connection "$VLLM_URL" || exit 1
+
+# 이미지 확인
+check_images
+
+# 평가 명령어 구성
+CMD="uv run python -m eval.evaluate_vllm"
+CMD="$CMD --vllm-url $VLLM_URL"
+CMD="$CMD --model $MODEL"
+CMD="$CMD --output-dir $OUTPUT_DIR"
+
+if [[ "$ALL_DOMAINS" == true ]]; then
+ CMD="$CMD --all-domains"
+elif [[ -n "$DOMAIN" ]]; then
+ CMD="$CMD --domain $DOMAIN"
+fi
+
+if [[ "$USE_JUDGE" == true ]]; then
+ CMD="$CMD --use-judge"
+ if [[ -n "$JUDGE_MODEL" ]]; then
+ CMD="$CMD --judge-model $JUDGE_MODEL"
+ fi
+fi
+
+if [[ -n "$LIMIT" ]]; then
+ CMD="$CMD --limit $LIMIT"
+fi
+
+if [[ -n "$QA_TYPES" ]]; then
+ CMD="$CMD --qa-types $QA_TYPES"
+fi
+
+# 평가 실행
+echo_info "평가 시작..."
+echo_info "Command: $CMD"
+echo ""
+
+eval $CMD
+
+echo ""
+echo_info "평가 완료. 결과: $OUTPUT_DIR/"
diff --git a/run_filter_qa.sh b/run_filter_qa.sh
new file mode 100755
index 0000000..8ed106b
--- /dev/null
+++ b/run_filter_qa.sh
@@ -0,0 +1,137 @@
+#!/bin/bash
+
+# ==============================================================================
+# TableMagnifier - QA Difficulty Filtering
+# ==============================================================================
+#
+# vLLM 서버를 사용하여 QA 난이도를 측정하고 검수 대상을 필터링합니다.
+# 모델이 너무 쉽게 맞추는 문제(90%+)는 제외하고,
+# 적당한 난이도(30-60%)의 QA만 검수 리스트로 추출합니다.
+#
+# Usage:
+# ./run_filter_qa.sh [OPTIONS]
+#
+# Examples:
+# ./run_filter_qa.sh --domain business
+# ./run_filter_qa.sh --all --trials 5
+# ./run_filter_qa.sh --domain business --vllm-url http://gpu-server:8000/v1
+#
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+cd "$SCRIPT_DIR"
+
+# Colors
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+RED='\033[0;31m'
+NC='\033[0m'
+
+echo_info() {
+ echo -e "${GREEN}[INFO]${NC} $1"
+}
+
+echo_warn() {
+ echo -e "${YELLOW}[WARN]${NC} $1"
+}
+
+echo_error() {
+ echo -e "${RED}[ERROR]${NC} $1"
+}
+
+show_help() {
+ cat << EOF
+Usage: $0 [OPTIONS]
+
+vLLM 서버를 사용하여 QA 난이도를 측정하고 검수 대상을 필터링합니다.
+
+Options:
+ --domain DOMAIN [...] 필터링할 도메인(들) (business, finance, academic, medical, public)
+ --all 모든 도메인 필터링
+ --vllm-url URL vLLM 서버 URL (default: http://localhost:8000/v1)
+ --model MODEL 모델 이름 (미지정시 자동 감지)
+ --trials N 각 QA당 시도 횟수 (default: 10)
+ --min-acc FLOAT 최소 정확도 (default: 0.3)
+ --max-acc FLOAT 최대 정확도 (default: 0.6)
+ --limit N 처리할 최대 entry 수 (테스트용)
+ --dry-run 실제 추론 없이 확인만
+ -h, --help 도움말 표시
+
+Difficulty Categories:
+ - too_easy: 90-100% (제외 - 모델이 다 맞춤)
+ - easy: 70-89%
+ - medium: 30-69% (검수 대상 ✓)
+ - hard: 1-29%
+ - very_hard: 0%
+
+Examples:
+ # business 도메인 필터링
+ $0 --domain business
+
+ # 빠른 테스트 (5회 시도, 2개 entry만)
+ $0 --domain business --trials 5 --limit 2
+
+ # 외부 vLLM 서버 사용
+ $0 --domain business --vllm-url http://gpu-server:8000/v1
+
+Output:
+ - qa_difficulty_analysis_*.json: 전체 분석 결과
+ - qa_for_review_*.json: 검수용 필터링된 QA 리스트
+EOF
+}
+
+# Check for help
+for arg in "$@"; do
+ if [[ "$arg" == "-h" ]] || [[ "$arg" == "--help" ]]; then
+ show_help
+ exit 0
+ fi
+done
+
+# Check for required arguments
+if [[ $# -eq 0 ]]; then
+ show_help
+ exit 1
+fi
+
+# Parse vllm-url for connection check
+VLLM_URL="http://localhost:8000/v1"
+for i in $(seq 1 $#); do
+ arg="${!i}"
+ if [[ "$arg" == "--vllm-url" ]]; then
+ next=$((i + 1))
+ VLLM_URL="${!next}"
+ break
+ fi
+done
+
+echo "=============================================="
+echo " TableMagnifier - QA Difficulty Filtering"
+echo "=============================================="
+echo ""
+
+# Check vLLM connection
+echo_info "Checking vLLM server connection..."
+if curl -s --connect-timeout 5 "${VLLM_URL}/models" > /dev/null 2>&1; then
+ MODEL_INFO=$(curl -s "${VLLM_URL}/models" | python3 -c "import sys, json; data = json.load(sys.stdin); print(data['data'][0]['id'] if data.get('data') else 'unknown')" 2>/dev/null || echo "unknown")
+ echo_info "vLLM server connected. Model: ${MODEL_INFO}"
+else
+ echo_error "Cannot connect to vLLM server at ${VLLM_URL}"
+ echo_error "Please ensure vLLM server is running."
+ exit 1
+fi
+
+echo ""
+echo_info "Starting QA difficulty filtering..."
+echo ""
+
+# Run the filter script
+uv run python filter_qa_by_difficulty.py "$@"
+
+echo ""
+echo_info "Filtering completed!"
+echo ""
+echo "Generated files:"
+echo " - qa_difficulty_analysis_*.json: Full analysis results"
+echo " - qa_for_review_*.json: Filtered QA for human review"
diff --git a/run_openai_public.sh b/run_openai_public.sh
deleted file mode 100644
index d90e1f6..0000000
--- a/run_openai_public.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/bash
-
-# ==============================================================================
-# TableMagnifier - JSON Pipeline (Public Domain)
-# ==============================================================================
-
-# Default Configuration
-INPUT_JSON="test_business.json"
-OUTPUT_DIR="output_business"
-DEFAULT_ARGS="--provider claude --model claude-sonnet-4-5 --domain business"
-
-# Check if the first argument is a JSON file path
-if [[ "$1" == *.json ]]; then
- INPUT_JSON="$1"
- shift
-fi
-
-echo "=============================================="
-echo " TableMagnifier - JSON Pipeline (Public)"
-echo "=============================================="
-echo "Input JSON: $INPUT_JSON"
-echo "Output Dir: $OUTPUT_DIR"
-echo "Provider: claude"
-echo "Model: claude-sonnet-4-5"
-echo "Domain: business"
-echo ""
-echo "💡 Tip: To upload to Notion during pipeline execution:"
-echo " Add --upload-to-notion flag to the command"
-echo ""
-echo "💡 To upload existing results later:"
-echo " python upload_to_notion_from_json.py $OUTPUT_DIR"
-echo ""
-
-# Check for ANTHROPIC_API_KEY
-if [[ -z "$ANTHROPIC_API_KEY" ]]; then
- echo "⚠️ Warning: ANTHROPIC_API_KEY is not set."
- echo " Please set it in your environment or .env file."
- echo ""
-fi
-
-# Run the pipeline
-# Note: "$@" appends any remaining arguments, allowing overrides of defaults
-uv run python run_pipeline_json.py --input "$INPUT_JSON" --output-dir "$OUTPUT_DIR" $DEFAULT_ARGS "$@"
\ No newline at end of file
diff --git a/run_pipeline.sh b/run_pipeline.sh
new file mode 100644
index 0000000..460929c
--- /dev/null
+++ b/run_pipeline.sh
@@ -0,0 +1,171 @@
+#!/bin/bash
+
+# ==============================================================================
+# TableMagnifier - JSON Pipeline
+# ==============================================================================
+#
+# Usage:
+# ./run_pipeline.sh [INPUT_JSON] [OPTIONS]
+#
+# Examples:
+# ./run_pipeline.sh test_public.json --domain public
+# ./run_pipeline.sh test_business.json --domain business --provider openai
+# ./run_pipeline.sh --input data.json --output-dir output_custom
+#
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+cd "$SCRIPT_DIR"
+
+# Default Configuration
+INPUT_JSON=""
+OUTPUT_DIR=""
+PROVIDER="claude"
+MODEL="claude-sonnet-4-5"
+DOMAIN="public"
+
+# Colors
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m'
+
+show_help() {
+ cat << EOF
+Usage: $0 [INPUT_JSON] [OPTIONS]
+
+TableMagnifier JSON Pipeline Runner
+
+Arguments:
+ INPUT_JSON Input JSON file path (optional, can use --input instead)
+
+Options:
+ --input FILE Input JSON file
+ --output-dir DIR Output directory (default: output_{domain})
+ --provider PROVIDER LLM provider: claude, openai, gemini (default: claude)
+ --model MODEL Model name (default: claude-sonnet-4-5)
+ --domain DOMAIN Domain: public, business, finance, medical, academic (default: public)
+ --qa-only Generate QA only (skip table generation)
+ --skip-qa Skip QA generation (table only)
+ --upload-to-notion Upload results to Notion
+ -h, --help Show this help
+
+Examples:
+ # Public domain with Claude
+ $0 test_public.json --domain public
+
+ # Business domain with OpenAI
+ $0 test_business.json --domain business --provider openai --model gpt-4o
+
+ # Finance domain, QA only mode
+ $0 test_finance.json --domain finance --qa-only
+
+ # Custom output directory
+ $0 data.json --output-dir my_output --domain medical
+EOF
+}
+
+# Parse first argument as JSON file if it ends with .json
+if [[ "$1" == *.json ]]; then
+ INPUT_JSON="$1"
+ shift
+fi
+
+# Parse remaining arguments
+EXTRA_ARGS=""
+while [[ $# -gt 0 ]]; do
+ case $1 in
+ --input)
+ INPUT_JSON="$2"
+ shift 2
+ ;;
+ --output-dir)
+ OUTPUT_DIR="$2"
+ shift 2
+ ;;
+ --provider)
+ PROVIDER="$2"
+ shift 2
+ ;;
+ --model)
+ MODEL="$2"
+ shift 2
+ ;;
+ --domain)
+ DOMAIN="$2"
+ shift 2
+ ;;
+ -h|--help)
+ show_help
+ exit 0
+ ;;
+ *)
+ EXTRA_ARGS="$EXTRA_ARGS $1"
+ shift
+ ;;
+ esac
+done
+
+# Set default output directory based on domain
+if [[ -z "$OUTPUT_DIR" ]]; then
+ OUTPUT_DIR="output_${DOMAIN}"
+fi
+
+# Validate input
+if [[ -z "$INPUT_JSON" ]]; then
+ echo -e "${YELLOW}[WARN]${NC} No input JSON specified."
+ show_help
+ exit 1
+fi
+
+if [[ ! -f "$INPUT_JSON" ]]; then
+ echo -e "${YELLOW}[ERROR]${NC} Input file not found: $INPUT_JSON"
+ exit 1
+fi
+
+echo "=============================================="
+echo " TableMagnifier - JSON Pipeline"
+echo "=============================================="
+echo "Input JSON: $INPUT_JSON"
+echo "Output Dir: $OUTPUT_DIR"
+echo "Provider: $PROVIDER"
+echo "Model: $MODEL"
+echo "Domain: $DOMAIN"
+echo ""
+
+# Check API keys based on provider
+case $PROVIDER in
+ claude|anthropic)
+ if [[ -z "$ANTHROPIC_API_KEY" ]]; then
+ echo -e "${YELLOW}[WARN]${NC} ANTHROPIC_API_KEY is not set."
+ fi
+ ;;
+ openai)
+ if [[ -z "$OPENAI_API_KEY" ]]; then
+ echo -e "${YELLOW}[WARN]${NC} OPENAI_API_KEY is not set."
+ fi
+ ;;
+ gemini|google)
+ if [[ -z "$GOOGLE_API_KEY" ]]; then
+ echo -e "${YELLOW}[WARN]${NC} GOOGLE_API_KEY is not set."
+ fi
+ ;;
+esac
+
+echo -e "${GREEN}[INFO]${NC} Starting pipeline..."
+echo ""
+
+# Run the pipeline
+uv run python run_pipeline_json.py \
+ --input "$INPUT_JSON" \
+ --output-dir "$OUTPUT_DIR" \
+ --provider "$PROVIDER" \
+ --model "$MODEL" \
+ --domain "$DOMAIN" \
+ $EXTRA_ARGS
+
+echo ""
+echo -e "${GREEN}[INFO]${NC} Pipeline completed. Results saved to: $OUTPUT_DIR/"
+echo ""
+echo "To upload results to Notion:"
+echo " python upload_to_notion_from_json.py $OUTPUT_DIR"
diff --git a/run_pipeline_json.py b/run_pipeline_json.py
index d8fef9c..b282e46 100644
--- a/run_pipeline_json.py
+++ b/run_pipeline_json.py
@@ -576,6 +576,7 @@ def main():
parser.add_argument("--max-workers", type=int, default=3, help="Maximum number of parallel workers (default: 3)")
parser.add_argument("--randomize-style", action="store_true", default=True, help="Randomize HTML table styles (fonts, colors) for diversity (default: True)")
parser.add_argument("--no-randomize-style", dest="randomize_style", action="store_false", help="Disable style randomization")
+ parser.add_argument("--limit", type=int, help="Limit number of entries to process (for testing)")
args = parser.parse_args()
@@ -596,6 +597,11 @@ def main():
print("Error: Input JSON must be a list of pairs.")
return
+ # Apply limit if specified
+ if args.limit:
+ input_data = input_data[:args.limit]
+ print(f"Limited to {len(input_data)} entries")
+
data_root = Path(args.data_root)
output_dir = Path(args.output_dir)
diff --git a/run_regenerate_qa.sh b/run_regenerate_qa.sh
new file mode 100755
index 0000000..58aa98d
--- /dev/null
+++ b/run_regenerate_qa.sh
@@ -0,0 +1,130 @@
+#!/bin/bash
+
+# ==============================================================================
+# TableMagnifier - QA Regeneration Script
+# ==============================================================================
+#
+# 기존 synthetic 테이블에서 QA를 재생성합니다.
+# output_public은 제외됩니다.
+#
+# Usage:
+# ./run_regenerate_qa.sh [OPTIONS]
+#
+# Examples:
+# ./run_regenerate_qa.sh --all # 모든 도메인
+# ./run_regenerate_qa.sh --domain business # 특정 도메인
+# ./run_regenerate_qa.sh --domain business finance # 여러 도메인
+#
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+cd "$SCRIPT_DIR"
+
+# Colors
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+RED='\033[0;31m'
+NC='\033[0m'
+
+echo_info() {
+ echo -e "${GREEN}[INFO]${NC} $1"
+}
+
+echo_warn() {
+ echo -e "${YELLOW}[WARN]${NC} $1"
+}
+
+echo_error() {
+ echo -e "${RED}[ERROR]${NC} $1"
+}
+
+show_help() {
+ cat << EOF
+Usage: $0 [OPTIONS]
+
+기존 synthetic 테이블에서 QA를 재생성합니다.
+
+Options:
+ --domain DOMAIN [DOMAIN ...] 재생성할 도메인(들) (business, finance, academic, medical)
+ --all 모든 도메인 재생성 (output_public 제외)
+ --provider PROVIDER LLM 제공자 (claude, openai, gemini) (default: claude)
+ --model MODEL 모델 이름 (default: claude-sonnet-4-5)
+ --no-long-sequence long_sequence QA 생성 스킵
+ --limit N 처리할 최대 entry 수 (테스트용)
+ --dry-run 실제 재생성 없이 확인만
+ -h, --help 도움말 표시
+
+Examples:
+ # 모든 도메인 재생성
+ $0 --all
+
+ # business 도메인만
+ $0 --domain business
+
+ # OpenAI 사용
+ $0 --domain business --provider openai --model gpt-4o
+
+ # 테스트 (5개만)
+ $0 --domain business --limit 5
+
+ # Dry run
+ $0 --all --dry-run
+EOF
+}
+
+# Check for required arguments
+if [[ $# -eq 0 ]]; then
+ show_help
+ exit 1
+fi
+
+# Check for help flag
+for arg in "$@"; do
+ if [[ "$arg" == "-h" ]] || [[ "$arg" == "--help" ]]; then
+ show_help
+ exit 0
+ fi
+done
+
+# Check API keys
+check_api_keys() {
+ local provider="$1"
+ case $provider in
+ claude|anthropic)
+ if [[ -z "$ANTHROPIC_API_KEY" ]]; then
+ echo_warn "ANTHROPIC_API_KEY is not set"
+ fi
+ ;;
+ openai)
+ if [[ -z "$OPENAI_API_KEY" ]]; then
+ echo_warn "OPENAI_API_KEY is not set"
+ fi
+ ;;
+ gemini|google)
+ if [[ -z "$GOOGLE_API_KEY" ]]; then
+ echo_warn "GOOGLE_API_KEY is not set"
+ fi
+ ;;
+ esac
+}
+
+# Parse provider from arguments
+PROVIDER="claude"
+for i in "${!@}"; do
+ if [[ "${!i}" == "--provider" ]]; then
+ next=$((i + 1))
+ PROVIDER="${!next}"
+ break
+ fi
+done
+
+check_api_keys "$PROVIDER"
+
+echo "=============================================="
+echo " TableMagnifier - QA Regeneration"
+echo "=============================================="
+echo ""
+
+# Run the regeneration script
+uv run python regenerate_qa.py "$@"
diff --git a/single_image_json_list/single_table_academic_input.json b/single_image_json_list/single_table_academic_input.json
new file mode 100644
index 0000000..483318f
--- /dev/null
+++ b/single_image_json_list/single_table_academic_input.json
@@ -0,0 +1,1602 @@
+[
+ {
+ "index": 0,
+ "pair_id": "A_origin_0_A_table_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_0/A_table_0.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_0",
+ "table_id": "A_table_0"
+ },
+ {
+ "index": 1,
+ "pair_id": "A_origin_0_A_table_1",
+ "image_paths": [
+ "data/Academic/Table/A_origin_0/A_table_1.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_0",
+ "table_id": "A_table_1"
+ },
+ {
+ "index": 2,
+ "pair_id": "A_origin_0_A_table_2",
+ "image_paths": [
+ "data/Academic/Table/A_origin_0/A_table_2.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_0",
+ "table_id": "A_table_2"
+ },
+ {
+ "index": 3,
+ "pair_id": "A_origin_0_A_table_3",
+ "image_paths": [
+ "data/Academic/Table/A_origin_0/A_table_3.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_0",
+ "table_id": "A_table_3"
+ },
+ {
+ "index": 4,
+ "pair_id": "A_origin_0_A_table_4",
+ "image_paths": [
+ "data/Academic/Table/A_origin_0/A_table_4.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_0",
+ "table_id": "A_table_4"
+ },
+ {
+ "index": 5,
+ "pair_id": "A_origin_1_A_table_5_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_1/A_table_5_0.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_1",
+ "table_id": "A_table_5_0"
+ },
+ {
+ "index": 6,
+ "pair_id": "A_origin_1_A_table_5_1",
+ "image_paths": [
+ "data/Academic/Table/A_origin_1/A_table_5_1.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_1",
+ "table_id": "A_table_5_1"
+ },
+ {
+ "index": 7,
+ "pair_id": "A_origin_1_A_table_6_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_1/A_table_6_0.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_1",
+ "table_id": "A_table_6_0"
+ },
+ {
+ "index": 8,
+ "pair_id": "A_origin_1_A_table_6_1",
+ "image_paths": [
+ "data/Academic/Table/A_origin_1/A_table_6_1.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_1",
+ "table_id": "A_table_6_1"
+ },
+ {
+ "index": 9,
+ "pair_id": "A_origin_1_A_table_7_0",
+ "image_paths": [
+ "data/Academic/Table/A_origin_1/A_table_7_0.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_1",
+ "table_id": "A_table_7_0"
+ },
+ {
+ "index": 10,
+ "pair_id": "A_origin_1_A_table_7_1",
+ "image_paths": [
+ "data/Academic/Table/A_origin_1/A_table_7_1.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_1",
+ "table_id": "A_table_7_1"
+ },
+ {
+ "index": 11,
+ "pair_id": "A_origin_10_A_table_28",
+ "image_paths": [
+ "data/Academic/Table/A_origin_10/A_table_28.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_10",
+ "table_id": "A_table_28"
+ },
+ {
+ "index": 12,
+ "pair_id": "A_origin_10_A_table_29",
+ "image_paths": [
+ "data/Academic/Table/A_origin_10/A_table_29.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_10",
+ "table_id": "A_table_29"
+ },
+ {
+ "index": 13,
+ "pair_id": "A_origin_11_A_table_30",
+ "image_paths": [
+ "data/Academic/Table/A_origin_11/A_table_30.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_11",
+ "table_id": "A_table_30"
+ },
+ {
+ "index": 14,
+ "pair_id": "A_origin_11_A_table_31",
+ "image_paths": [
+ "data/Academic/Table/A_origin_11/A_table_31.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_11",
+ "table_id": "A_table_31"
+ },
+ {
+ "index": 15,
+ "pair_id": "A_origin_12_A_table_32",
+ "image_paths": [
+ "data/Academic/Table/A_origin_12/A_table_32.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_12",
+ "table_id": "A_table_32"
+ },
+ {
+ "index": 16,
+ "pair_id": "A_origin_12_A_table_33",
+ "image_paths": [
+ "data/Academic/Table/A_origin_12/A_table_33.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_12",
+ "table_id": "A_table_33"
+ },
+ {
+ "index": 17,
+ "pair_id": "A_origin_12_A_table_34",
+ "image_paths": [
+ "data/Academic/Table/A_origin_12/A_table_34.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_12",
+ "table_id": "A_table_34"
+ },
+ {
+ "index": 18,
+ "pair_id": "A_origin_13_A_table_35",
+ "image_paths": [
+ "data/Academic/Table/A_origin_13/A_table_35.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_13",
+ "table_id": "A_table_35"
+ },
+ {
+ "index": 19,
+ "pair_id": "A_origin_13_A_table_36",
+ "image_paths": [
+ "data/Academic/Table/A_origin_13/A_table_36.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_13",
+ "table_id": "A_table_36"
+ },
+ {
+ "index": 20,
+ "pair_id": "A_origin_13_A_table_37",
+ "image_paths": [
+ "data/Academic/Table/A_origin_13/A_table_37.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_13",
+ "table_id": "A_table_37"
+ },
+ {
+ "index": 21,
+ "pair_id": "A_origin_13_A_table_38",
+ "image_paths": [
+ "data/Academic/Table/A_origin_13/A_table_38.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_13",
+ "table_id": "A_table_38"
+ },
+ {
+ "index": 22,
+ "pair_id": "A_origin_14_A_table_39",
+ "image_paths": [
+ "data/Academic/Table/A_origin_14/A_table_39.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_14",
+ "table_id": "A_table_39"
+ },
+ {
+ "index": 23,
+ "pair_id": "A_origin_14_A_table_40",
+ "image_paths": [
+ "data/Academic/Table/A_origin_14/A_table_40.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_14",
+ "table_id": "A_table_40"
+ },
+ {
+ "index": 24,
+ "pair_id": "A_origin_15_A_table_41",
+ "image_paths": [
+ "data/Academic/Table/A_origin_15/A_table_41.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_15",
+ "table_id": "A_table_41"
+ },
+ {
+ "index": 25,
+ "pair_id": "A_origin_16_A_table_42",
+ "image_paths": [
+ "data/Academic/Table/A_origin_16/A_table_42.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_16",
+ "table_id": "A_table_42"
+ },
+ {
+ "index": 26,
+ "pair_id": "A_origin_16_A_table_43",
+ "image_paths": [
+ "data/Academic/Table/A_origin_16/A_table_43.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_16",
+ "table_id": "A_table_43"
+ },
+ {
+ "index": 27,
+ "pair_id": "A_origin_17_A_table_44",
+ "image_paths": [
+ "data/Academic/Table/A_origin_17/A_table_44.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_17",
+ "table_id": "A_table_44"
+ },
+ {
+ "index": 28,
+ "pair_id": "A_origin_17_A_table_45",
+ "image_paths": [
+ "data/Academic/Table/A_origin_17/A_table_45.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_17",
+ "table_id": "A_table_45"
+ },
+ {
+ "index": 29,
+ "pair_id": "A_origin_17_A_table_46",
+ "image_paths": [
+ "data/Academic/Table/A_origin_17/A_table_46.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_17",
+ "table_id": "A_table_46"
+ },
+ {
+ "index": 30,
+ "pair_id": "A_origin_18_A_table_47",
+ "image_paths": [
+ "data/Academic/Table/A_origin_18/A_table_47.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_18",
+ "table_id": "A_table_47"
+ },
+ {
+ "index": 31,
+ "pair_id": "A_origin_18_A_table_48",
+ "image_paths": [
+ "data/Academic/Table/A_origin_18/A_table_48.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_18",
+ "table_id": "A_table_48"
+ },
+ {
+ "index": 32,
+ "pair_id": "A_origin_18_A_table_49",
+ "image_paths": [
+ "data/Academic/Table/A_origin_18/A_table_49.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_18",
+ "table_id": "A_table_49"
+ },
+ {
+ "index": 33,
+ "pair_id": "A_origin_19_A_table_50",
+ "image_paths": [
+ "data/Academic/Table/A_origin_19/A_table_50.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_19",
+ "table_id": "A_table_50"
+ },
+ {
+ "index": 34,
+ "pair_id": "A_origin_2_A_table_8",
+ "image_paths": [
+ "data/Academic/Table/A_origin_2/A_table_8.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_2",
+ "table_id": "A_table_8"
+ },
+ {
+ "index": 35,
+ "pair_id": "A_origin_2_A_table_9",
+ "image_paths": [
+ "data/Academic/Table/A_origin_2/A_table_9.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_2",
+ "table_id": "A_table_9"
+ },
+ {
+ "index": 36,
+ "pair_id": "A_origin_20_A_table_51",
+ "image_paths": [
+ "data/Academic/Table/A_origin_20/A_table_51.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_20",
+ "table_id": "A_table_51"
+ },
+ {
+ "index": 37,
+ "pair_id": "A_origin_20_A_table_52",
+ "image_paths": [
+ "data/Academic/Table/A_origin_20/A_table_52.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_20",
+ "table_id": "A_table_52"
+ },
+ {
+ "index": 38,
+ "pair_id": "A_origin_21_A_table_53",
+ "image_paths": [
+ "data/Academic/Table/A_origin_21/A_table_53.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_21",
+ "table_id": "A_table_53"
+ },
+ {
+ "index": 39,
+ "pair_id": "A_origin_21_A_table_54",
+ "image_paths": [
+ "data/Academic/Table/A_origin_21/A_table_54.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_21",
+ "table_id": "A_table_54"
+ },
+ {
+ "index": 40,
+ "pair_id": "A_origin_22_A_table_55",
+ "image_paths": [
+ "data/Academic/Table/A_origin_22/A_table_55.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_22",
+ "table_id": "A_table_55"
+ },
+ {
+ "index": 41,
+ "pair_id": "A_origin_23_A_table_56",
+ "image_paths": [
+ "data/Academic/Table/A_origin_23/A_table_56.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_23",
+ "table_id": "A_table_56"
+ },
+ {
+ "index": 42,
+ "pair_id": "A_origin_24_A_table_57",
+ "image_paths": [
+ "data/Academic/Table/A_origin_24/A_table_57.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_24",
+ "table_id": "A_table_57"
+ },
+ {
+ "index": 43,
+ "pair_id": "A_origin_25_A_table_58",
+ "image_paths": [
+ "data/Academic/Table/A_origin_25/A_table_58.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_25",
+ "table_id": "A_table_58"
+ },
+ {
+ "index": 44,
+ "pair_id": "A_origin_26_A_table_59_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_26/A_table_59_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_26",
+ "table_id": "A_table_59_01"
+ },
+ {
+ "index": 45,
+ "pair_id": "A_origin_26_A_table_59_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_26/A_table_59_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_26",
+ "table_id": "A_table_59_02"
+ },
+ {
+ "index": 46,
+ "pair_id": "A_origin_26_A_table_60",
+ "image_paths": [
+ "data/Academic/Table/A_origin_26/A_table_60.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_26",
+ "table_id": "A_table_60"
+ },
+ {
+ "index": 47,
+ "pair_id": "A_origin_26_A_table_61",
+ "image_paths": [
+ "data/Academic/Table/A_origin_26/A_table_61.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_26",
+ "table_id": "A_table_61"
+ },
+ {
+ "index": 48,
+ "pair_id": "A_origin_27_A_table_62_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_27/A_table_62_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_27",
+ "table_id": "A_table_62_01"
+ },
+ {
+ "index": 49,
+ "pair_id": "A_origin_27_A_table_62_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_27/A_table_62_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_27",
+ "table_id": "A_table_62_02"
+ },
+ {
+ "index": 50,
+ "pair_id": "A_origin_28_A_table_63_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_28/A_table_63_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_28",
+ "table_id": "A_table_63_01"
+ },
+ {
+ "index": 51,
+ "pair_id": "A_origin_28_A_table_63_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_28/A_table_63_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_28",
+ "table_id": "A_table_63_02"
+ },
+ {
+ "index": 52,
+ "pair_id": "A_origin_28_A_table_64",
+ "image_paths": [
+ "data/Academic/Table/A_origin_28/A_table_64.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_28",
+ "table_id": "A_table_64"
+ },
+ {
+ "index": 53,
+ "pair_id": "A_origin_29_A_table_65",
+ "image_paths": [
+ "data/Academic/Table/A_origin_29/A_table_65.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_29",
+ "table_id": "A_table_65"
+ },
+ {
+ "index": 54,
+ "pair_id": "A_origin_3_A_table_10",
+ "image_paths": [
+ "data/Academic/Table/A_origin_3/A_table_10.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_3",
+ "table_id": "A_table_10"
+ },
+ {
+ "index": 55,
+ "pair_id": "A_origin_3_A_table_11",
+ "image_paths": [
+ "data/Academic/Table/A_origin_3/A_table_11.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_3",
+ "table_id": "A_table_11"
+ },
+ {
+ "index": 56,
+ "pair_id": "A_origin_30_A_table_66_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_30/A_table_66_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_30",
+ "table_id": "A_table_66_01"
+ },
+ {
+ "index": 57,
+ "pair_id": "A_origin_30_A_table_66_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_30/A_table_66_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_30",
+ "table_id": "A_table_66_02"
+ },
+ {
+ "index": 58,
+ "pair_id": "A_origin_31_A_table_67_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_31/A_table_67_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_31",
+ "table_id": "A_table_67_01"
+ },
+ {
+ "index": 59,
+ "pair_id": "A_origin_31_A_table_67_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_31/A_table_67_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_31",
+ "table_id": "A_table_67_02"
+ },
+ {
+ "index": 60,
+ "pair_id": "A_origin_32_A_table_68_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_32/A_table_68_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_32",
+ "table_id": "A_table_68_01"
+ },
+ {
+ "index": 61,
+ "pair_id": "A_origin_32_A_table_68_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_32/A_table_68_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_32",
+ "table_id": "A_table_68_02"
+ },
+ {
+ "index": 62,
+ "pair_id": "A_origin_32_A_table_69_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_32/A_table_69_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_32",
+ "table_id": "A_table_69_01"
+ },
+ {
+ "index": 63,
+ "pair_id": "A_origin_32_A_table_69_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_32/A_table_69_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_32",
+ "table_id": "A_table_69_02"
+ },
+ {
+ "index": 64,
+ "pair_id": "A_origin_33_A_table_70_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_33/A_table_70_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_33",
+ "table_id": "A_table_70_01"
+ },
+ {
+ "index": 65,
+ "pair_id": "A_origin_33_A_table_70_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_33/A_table_70_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_33",
+ "table_id": "A_table_70_02"
+ },
+ {
+ "index": 66,
+ "pair_id": "A_origin_34_A_table_71_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_34/A_table_71_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_34",
+ "table_id": "A_table_71_01"
+ },
+ {
+ "index": 67,
+ "pair_id": "A_origin_34_A_table_71_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_34/A_table_71_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_34",
+ "table_id": "A_table_71_02"
+ },
+ {
+ "index": 68,
+ "pair_id": "A_origin_35_A_table_72",
+ "image_paths": [
+ "data/Academic/Table/A_origin_35/A_table_72.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_35",
+ "table_id": "A_table_72"
+ },
+ {
+ "index": 69,
+ "pair_id": "A_origin_36_A_table_73",
+ "image_paths": [
+ "data/Academic/Table/A_origin_36/A_table_73.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_36",
+ "table_id": "A_table_73"
+ },
+ {
+ "index": 70,
+ "pair_id": "A_origin_36_A_table_74",
+ "image_paths": [
+ "data/Academic/Table/A_origin_36/A_table_74.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_36",
+ "table_id": "A_table_74"
+ },
+ {
+ "index": 71,
+ "pair_id": "A_origin_36_A_table_75",
+ "image_paths": [
+ "data/Academic/Table/A_origin_36/A_table_75.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_36",
+ "table_id": "A_table_75"
+ },
+ {
+ "index": 72,
+ "pair_id": "A_origin_37_A_table_76_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_37/A_table_76_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_37",
+ "table_id": "A_table_76_01"
+ },
+ {
+ "index": 73,
+ "pair_id": "A_origin_37_A_table_76_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_37/A_table_76_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_37",
+ "table_id": "A_table_76_02"
+ },
+ {
+ "index": 74,
+ "pair_id": "A_origin_38_A_table_77",
+ "image_paths": [
+ "data/Academic/Table/A_origin_38/A_table_77.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_38",
+ "table_id": "A_table_77"
+ },
+ {
+ "index": 75,
+ "pair_id": "A_origin_38_A_table_78",
+ "image_paths": [
+ "data/Academic/Table/A_origin_38/A_table_78.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_38",
+ "table_id": "A_table_78"
+ },
+ {
+ "index": 76,
+ "pair_id": "A_origin_39_A_table_79",
+ "image_paths": [
+ "data/Academic/Table/A_origin_39/A_table_79.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_39",
+ "table_id": "A_table_79"
+ },
+ {
+ "index": 77,
+ "pair_id": "A_origin_39_A_table_80_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_39/A_table_80_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_39",
+ "table_id": "A_table_80_01"
+ },
+ {
+ "index": 78,
+ "pair_id": "A_origin_39_A_table_80_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_39/A_table_80_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_39",
+ "table_id": "A_table_80_02"
+ },
+ {
+ "index": 79,
+ "pair_id": "A_origin_4_A_table_12",
+ "image_paths": [
+ "data/Academic/Table/A_origin_4/A_table_12.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_4",
+ "table_id": "A_table_12"
+ },
+ {
+ "index": 80,
+ "pair_id": "A_origin_4_A_table_13",
+ "image_paths": [
+ "data/Academic/Table/A_origin_4/A_table_13.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_4",
+ "table_id": "A_table_13"
+ },
+ {
+ "index": 81,
+ "pair_id": "A_origin_40_A_table_81",
+ "image_paths": [
+ "data/Academic/Table/A_origin_40/A_table_81.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_40",
+ "table_id": "A_table_81"
+ },
+ {
+ "index": 82,
+ "pair_id": "A_origin_40_A_table_82",
+ "image_paths": [
+ "data/Academic/Table/A_origin_40/A_table_82.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_40",
+ "table_id": "A_table_82"
+ },
+ {
+ "index": 83,
+ "pair_id": "A_origin_40_A_table_83",
+ "image_paths": [
+ "data/Academic/Table/A_origin_40/A_table_83.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_40",
+ "table_id": "A_table_83"
+ },
+ {
+ "index": 84,
+ "pair_id": "A_origin_41_A_table_84",
+ "image_paths": [
+ "data/Academic/Table/A_origin_41/A_table_84.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_41",
+ "table_id": "A_table_84"
+ },
+ {
+ "index": 85,
+ "pair_id": "A_origin_41_A_table_85",
+ "image_paths": [
+ "data/Academic/Table/A_origin_41/A_table_85.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_41",
+ "table_id": "A_table_85"
+ },
+ {
+ "index": 86,
+ "pair_id": "A_origin_42_A_table_86",
+ "image_paths": [
+ "data/Academic/Table/A_origin_42/A_table_86.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_42",
+ "table_id": "A_table_86"
+ },
+ {
+ "index": 87,
+ "pair_id": "A_origin_42_A_table_87",
+ "image_paths": [
+ "data/Academic/Table/A_origin_42/A_table_87.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_42",
+ "table_id": "A_table_87"
+ },
+ {
+ "index": 88,
+ "pair_id": "A_origin_43_A_table_88",
+ "image_paths": [
+ "data/Academic/Table/A_origin_43/A_table_88.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_43",
+ "table_id": "A_table_88"
+ },
+ {
+ "index": 89,
+ "pair_id": "A_origin_43_A_table_89",
+ "image_paths": [
+ "data/Academic/Table/A_origin_43/A_table_89.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_43",
+ "table_id": "A_table_89"
+ },
+ {
+ "index": 90,
+ "pair_id": "A_origin_43_A_table_90",
+ "image_paths": [
+ "data/Academic/Table/A_origin_43/A_table_90.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_43",
+ "table_id": "A_table_90"
+ },
+ {
+ "index": 91,
+ "pair_id": "A_origin_44_A_table_91",
+ "image_paths": [
+ "data/Academic/Table/A_origin_44/A_table_91.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_44",
+ "table_id": "A_table_91"
+ },
+ {
+ "index": 92,
+ "pair_id": "A_origin_45_A_table_92",
+ "image_paths": [
+ "data/Academic/Table/A_origin_45/A_table_92.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_45",
+ "table_id": "A_table_92"
+ },
+ {
+ "index": 93,
+ "pair_id": "A_origin_45_A_table_93",
+ "image_paths": [
+ "data/Academic/Table/A_origin_45/A_table_93.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_45",
+ "table_id": "A_table_93"
+ },
+ {
+ "index": 94,
+ "pair_id": "A_origin_45_A_table_94",
+ "image_paths": [
+ "data/Academic/Table/A_origin_45/A_table_94.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_45",
+ "table_id": "A_table_94"
+ },
+ {
+ "index": 95,
+ "pair_id": "A_origin_45_A_table_95",
+ "image_paths": [
+ "data/Academic/Table/A_origin_45/A_table_95.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_45",
+ "table_id": "A_table_95"
+ },
+ {
+ "index": 96,
+ "pair_id": "A_origin_46_A_table_96",
+ "image_paths": [
+ "data/Academic/Table/A_origin_46/A_table_96.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_46",
+ "table_id": "A_table_96"
+ },
+ {
+ "index": 97,
+ "pair_id": "A_origin_47_A_table_97",
+ "image_paths": [
+ "data/Academic/Table/A_origin_47/A_table_97.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_47",
+ "table_id": "A_table_97"
+ },
+ {
+ "index": 98,
+ "pair_id": "A_origin_47_A_table_98",
+ "image_paths": [
+ "data/Academic/Table/A_origin_47/A_table_98.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_47",
+ "table_id": "A_table_98"
+ },
+ {
+ "index": 99,
+ "pair_id": "A_origin_48_A_table_99",
+ "image_paths": [
+ "data/Academic/Table/A_origin_48/A_table_99.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_48",
+ "table_id": "A_table_99"
+ },
+ {
+ "index": 100,
+ "pair_id": "A_origin_49_A_table_100",
+ "image_paths": [
+ "data/Academic/Table/A_origin_49/A_table_100.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_49",
+ "table_id": "A_table_100"
+ },
+ {
+ "index": 101,
+ "pair_id": "A_origin_49_A_table_101",
+ "image_paths": [
+ "data/Academic/Table/A_origin_49/A_table_101.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_49",
+ "table_id": "A_table_101"
+ },
+ {
+ "index": 102,
+ "pair_id": "A_origin_5_A_table_14",
+ "image_paths": [
+ "data/Academic/Table/A_origin_5/A_table_14.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_5",
+ "table_id": "A_table_14"
+ },
+ {
+ "index": 103,
+ "pair_id": "A_origin_5_A_table_15",
+ "image_paths": [
+ "data/Academic/Table/A_origin_5/A_table_15.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_5",
+ "table_id": "A_table_15"
+ },
+ {
+ "index": 104,
+ "pair_id": "A_origin_5_A_table_16",
+ "image_paths": [
+ "data/Academic/Table/A_origin_5/A_table_16.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_5",
+ "table_id": "A_table_16"
+ },
+ {
+ "index": 105,
+ "pair_id": "A_origin_50_A_table_102",
+ "image_paths": [
+ "data/Academic/Table/A_origin_50/A_table_102.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_50",
+ "table_id": "A_table_102"
+ },
+ {
+ "index": 106,
+ "pair_id": "A_origin_51_A_table_103",
+ "image_paths": [
+ "data/Academic/Table/A_origin_51/A_table_103.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_51",
+ "table_id": "A_table_103"
+ },
+ {
+ "index": 107,
+ "pair_id": "A_origin_51_A_table_104",
+ "image_paths": [
+ "data/Academic/Table/A_origin_51/A_table_104.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_51",
+ "table_id": "A_table_104"
+ },
+ {
+ "index": 108,
+ "pair_id": "A_origin_52_A_table_105",
+ "image_paths": [
+ "data/Academic/Table/A_origin_52/A_table_105.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_52",
+ "table_id": "A_table_105"
+ },
+ {
+ "index": 109,
+ "pair_id": "A_origin_53_A_table_106_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_53/A_table_106_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_53",
+ "table_id": "A_table_106_01"
+ },
+ {
+ "index": 110,
+ "pair_id": "A_origin_53_A_table_106_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_53/A_table_106_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_53",
+ "table_id": "A_table_106_02"
+ },
+ {
+ "index": 111,
+ "pair_id": "A_origin_53_A_table_107_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_53/A_table_107_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_53",
+ "table_id": "A_table_107_01"
+ },
+ {
+ "index": 112,
+ "pair_id": "A_origin_53_A_table_107_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_53/A_table_107_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_53",
+ "table_id": "A_table_107_02"
+ },
+ {
+ "index": 113,
+ "pair_id": "A_origin_53_A_table_108",
+ "image_paths": [
+ "data/Academic/Table/A_origin_53/A_table_108.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_53",
+ "table_id": "A_table_108"
+ },
+ {
+ "index": 114,
+ "pair_id": "A_origin_54_A_table_109",
+ "image_paths": [
+ "data/Academic/Table/A_origin_54/A_table_109.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_54",
+ "table_id": "A_table_109"
+ },
+ {
+ "index": 115,
+ "pair_id": "A_origin_54_A_table_110",
+ "image_paths": [
+ "data/Academic/Table/A_origin_54/A_table_110.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_54",
+ "table_id": "A_table_110"
+ },
+ {
+ "index": 116,
+ "pair_id": "A_origin_55_A_table_111",
+ "image_paths": [
+ "data/Academic/Table/A_origin_55/A_table_111.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_55",
+ "table_id": "A_table_111"
+ },
+ {
+ "index": 117,
+ "pair_id": "A_origin_55_A_table_112",
+ "image_paths": [
+ "data/Academic/Table/A_origin_55/A_table_112.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_55",
+ "table_id": "A_table_112"
+ },
+ {
+ "index": 118,
+ "pair_id": "A_origin_56_A_table_113",
+ "image_paths": [
+ "data/Academic/Table/A_origin_56/A_table_113.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_56",
+ "table_id": "A_table_113"
+ },
+ {
+ "index": 119,
+ "pair_id": "A_origin_56_A_table_114",
+ "image_paths": [
+ "data/Academic/Table/A_origin_56/A_table_114.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_56",
+ "table_id": "A_table_114"
+ },
+ {
+ "index": 120,
+ "pair_id": "A_origin_56_A_table_115",
+ "image_paths": [
+ "data/Academic/Table/A_origin_56/A_table_115.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_56",
+ "table_id": "A_table_115"
+ },
+ {
+ "index": 121,
+ "pair_id": "A_origin_57_A_table_116",
+ "image_paths": [
+ "data/Academic/Table/A_origin_57/A_table_116.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_57",
+ "table_id": "A_table_116"
+ },
+ {
+ "index": 122,
+ "pair_id": "A_origin_57_A_table_117",
+ "image_paths": [
+ "data/Academic/Table/A_origin_57/A_table_117.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_57",
+ "table_id": "A_table_117"
+ },
+ {
+ "index": 123,
+ "pair_id": "A_origin_57_A_table_118",
+ "image_paths": [
+ "data/Academic/Table/A_origin_57/A_table_118.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_57",
+ "table_id": "A_table_118"
+ },
+ {
+ "index": 124,
+ "pair_id": "A_origin_57_A_table_119",
+ "image_paths": [
+ "data/Academic/Table/A_origin_57/A_table_119.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_57",
+ "table_id": "A_table_119"
+ },
+ {
+ "index": 125,
+ "pair_id": "A_origin_57_A_table_120",
+ "image_paths": [
+ "data/Academic/Table/A_origin_57/A_table_120.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_57",
+ "table_id": "A_table_120"
+ },
+ {
+ "index": 126,
+ "pair_id": "A_origin_58_A_table_121",
+ "image_paths": [
+ "data/Academic/Table/A_origin_58/A_table_121.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_58",
+ "table_id": "A_table_121"
+ },
+ {
+ "index": 127,
+ "pair_id": "A_origin_58_A_table_122",
+ "image_paths": [
+ "data/Academic/Table/A_origin_58/A_table_122.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_58",
+ "table_id": "A_table_122"
+ },
+ {
+ "index": 128,
+ "pair_id": "A_origin_58_A_table_123_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_58/A_table_123_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_58",
+ "table_id": "A_table_123_01"
+ },
+ {
+ "index": 129,
+ "pair_id": "A_origin_58_A_table_123_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_58/A_table_123_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_58",
+ "table_id": "A_table_123_02"
+ },
+ {
+ "index": 130,
+ "pair_id": "A_origin_59_A_table_124_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_59/A_table_124_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_59",
+ "table_id": "A_table_124_01"
+ },
+ {
+ "index": 131,
+ "pair_id": "A_origin_59_A_table_124_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_59/A_table_124_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_59",
+ "table_id": "A_table_124_02"
+ },
+ {
+ "index": 132,
+ "pair_id": "A_origin_6_A_table_18",
+ "image_paths": [
+ "data/Academic/Table/A_origin_6/A_table_18.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_6",
+ "table_id": "A_table_18"
+ },
+ {
+ "index": 133,
+ "pair_id": "A_origin_6_A_table_19",
+ "image_paths": [
+ "data/Academic/Table/A_origin_6/A_table_19.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_6",
+ "table_id": "A_table_19"
+ },
+ {
+ "index": 134,
+ "pair_id": "A_origin_6_A_table_8",
+ "image_paths": [
+ "data/Academic/Table/A_origin_6/A_table_8.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_6",
+ "table_id": "A_table_8"
+ },
+ {
+ "index": 135,
+ "pair_id": "A_origin_60_A_table_125_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_60/A_table_125_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_60",
+ "table_id": "A_table_125_01"
+ },
+ {
+ "index": 136,
+ "pair_id": "A_origin_60_A_table_125_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_60/A_table_125_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_60",
+ "table_id": "A_table_125_02"
+ },
+ {
+ "index": 137,
+ "pair_id": "A_origin_61_A_table_126",
+ "image_paths": [
+ "data/Academic/Table/A_origin_61/A_table_126.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_61",
+ "table_id": "A_table_126"
+ },
+ {
+ "index": 138,
+ "pair_id": "A_origin_62_A_table_127_01",
+ "image_paths": [
+ "data/Academic/Table/A_origin_62/A_table_127_01.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_62",
+ "table_id": "A_table_127_01"
+ },
+ {
+ "index": 139,
+ "pair_id": "A_origin_62_A_table_127_02",
+ "image_paths": [
+ "data/Academic/Table/A_origin_62/A_table_127_02.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_62",
+ "table_id": "A_table_127_02"
+ },
+ {
+ "index": 140,
+ "pair_id": "A_origin_63_A_table_128",
+ "image_paths": [
+ "data/Academic/Table/A_origin_63/A_table_128.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_63",
+ "table_id": "A_table_128"
+ },
+ {
+ "index": 141,
+ "pair_id": "A_origin_63_A_table_129",
+ "image_paths": [
+ "data/Academic/Table/A_origin_63/A_table_129.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_63",
+ "table_id": "A_table_129"
+ },
+ {
+ "index": 142,
+ "pair_id": "A_origin_64_A_table_130",
+ "image_paths": [
+ "data/Academic/Table/A_origin_64/A_table_130.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_64",
+ "table_id": "A_table_130"
+ },
+ {
+ "index": 143,
+ "pair_id": "A_origin_64_A_table_131",
+ "image_paths": [
+ "data/Academic/Table/A_origin_64/A_table_131.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_64",
+ "table_id": "A_table_131"
+ },
+ {
+ "index": 144,
+ "pair_id": "A_origin_64_A_table_132",
+ "image_paths": [
+ "data/Academic/Table/A_origin_64/A_table_132.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_64",
+ "table_id": "A_table_132"
+ },
+ {
+ "index": 145,
+ "pair_id": "A_origin_65_A_table_133",
+ "image_paths": [
+ "data/Academic/Table/A_origin_65/A_table_133.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_65",
+ "table_id": "A_table_133"
+ },
+ {
+ "index": 146,
+ "pair_id": "A_origin_65_A_table_134",
+ "image_paths": [
+ "data/Academic/Table/A_origin_65/A_table_134.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_65",
+ "table_id": "A_table_134"
+ },
+ {
+ "index": 147,
+ "pair_id": "A_origin_66_A_table_135",
+ "image_paths": [
+ "data/Academic/Table/A_origin_66/A_table_135.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_66",
+ "table_id": "A_table_135"
+ },
+ {
+ "index": 148,
+ "pair_id": "A_origin_66_A_table_136",
+ "image_paths": [
+ "data/Academic/Table/A_origin_66/A_table_136.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_66",
+ "table_id": "A_table_136"
+ },
+ {
+ "index": 149,
+ "pair_id": "A_origin_66_A_table_137",
+ "image_paths": [
+ "data/Academic/Table/A_origin_66/A_table_137.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_66",
+ "table_id": "A_table_137"
+ },
+ {
+ "index": 150,
+ "pair_id": "A_origin_66_A_table_138",
+ "image_paths": [
+ "data/Academic/Table/A_origin_66/A_table_138.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_66",
+ "table_id": "A_table_138"
+ },
+ {
+ "index": 151,
+ "pair_id": "A_origin_67_A_table_139",
+ "image_paths": [
+ "data/Academic/Table/A_origin_67/A_table_139.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_67",
+ "table_id": "A_table_139"
+ },
+ {
+ "index": 152,
+ "pair_id": "A_origin_7_A_table_20",
+ "image_paths": [
+ "data/Academic/Table/A_origin_7/A_table_20.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_7",
+ "table_id": "A_table_20"
+ },
+ {
+ "index": 153,
+ "pair_id": "A_origin_7_A_table_21",
+ "image_paths": [
+ "data/Academic/Table/A_origin_7/A_table_21.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_7",
+ "table_id": "A_table_21"
+ },
+ {
+ "index": 154,
+ "pair_id": "A_origin_8_A_table_22",
+ "image_paths": [
+ "data/Academic/Table/A_origin_8/A_table_22.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_8",
+ "table_id": "A_table_22"
+ },
+ {
+ "index": 155,
+ "pair_id": "A_origin_8_A_table_23",
+ "image_paths": [
+ "data/Academic/Table/A_origin_8/A_table_23.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_8",
+ "table_id": "A_table_23"
+ },
+ {
+ "index": 156,
+ "pair_id": "A_origin_8_A_table_24",
+ "image_paths": [
+ "data/Academic/Table/A_origin_8/A_table_24.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_8",
+ "table_id": "A_table_24"
+ },
+ {
+ "index": 157,
+ "pair_id": "A_origin_9_A_table_25",
+ "image_paths": [
+ "data/Academic/Table/A_origin_9/A_table_25.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_9",
+ "table_id": "A_table_25"
+ },
+ {
+ "index": 158,
+ "pair_id": "A_origin_9_A_table_26",
+ "image_paths": [
+ "data/Academic/Table/A_origin_9/A_table_26.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_9",
+ "table_id": "A_table_26"
+ },
+ {
+ "index": 159,
+ "pair_id": "A_origin_9_A_table_27",
+ "image_paths": [
+ "data/Academic/Table/A_origin_9/A_table_27.png"
+ ],
+ "domain": "Academic",
+ "origin": "A_origin_9",
+ "table_id": "A_table_27"
+ }
+]
diff --git a/single_image_json_list/single_table_business_input.json b/single_image_json_list/single_table_business_input.json
new file mode 100644
index 0000000..7309657
--- /dev/null
+++ b/single_image_json_list/single_table_business_input.json
@@ -0,0 +1,1492 @@
+[
+ {
+ "index": 0,
+ "pair_id": "B_origin_0_B_table_0_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_0/B_table_0_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_0",
+ "table_id": "B_table_0_0"
+ },
+ {
+ "index": 1,
+ "pair_id": "B_origin_0_B_table_1_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_0/B_table_1_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_0",
+ "table_id": "B_table_1_0"
+ },
+ {
+ "index": 2,
+ "pair_id": "B_origin_0_B_table_2_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_0/B_table_2_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_0",
+ "table_id": "B_table_2_0"
+ },
+ {
+ "index": 3,
+ "pair_id": "B_origin_1_B_table_3_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_1/B_table_3_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_1",
+ "table_id": "B_table_3_0"
+ },
+ {
+ "index": 4,
+ "pair_id": "B_origin_1_B_table_4_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_1/B_table_4_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_1",
+ "table_id": "B_table_4_0"
+ },
+ {
+ "index": 5,
+ "pair_id": "B_origin_10_B_table_31_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_10/B_table_31_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_10",
+ "table_id": "B_table_31_0"
+ },
+ {
+ "index": 6,
+ "pair_id": "B_origin_10_B_table_32_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_10/B_table_32_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_10",
+ "table_id": "B_table_32_0"
+ },
+ {
+ "index": 7,
+ "pair_id": "B_origin_10_B_table_33_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_10/B_table_33_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_10",
+ "table_id": "B_table_33_0"
+ },
+ {
+ "index": 8,
+ "pair_id": "B_origin_10_B_table_34_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_10/B_table_34_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_10",
+ "table_id": "B_table_34_0"
+ },
+ {
+ "index": 9,
+ "pair_id": "B_origin_11_B_table_35_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_11/B_table_35_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_11",
+ "table_id": "B_table_35_0"
+ },
+ {
+ "index": 10,
+ "pair_id": "B_origin_11_B_table_36_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_11/B_table_36_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_11",
+ "table_id": "B_table_36_0"
+ },
+ {
+ "index": 11,
+ "pair_id": "B_origin_11_B_table_37_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_11/B_table_37_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_11",
+ "table_id": "B_table_37_0"
+ },
+ {
+ "index": 12,
+ "pair_id": "B_origin_11_B_table_38_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_11/B_table_38_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_11",
+ "table_id": "B_table_38_0"
+ },
+ {
+ "index": 13,
+ "pair_id": "B_origin_12_B_table_39_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_12/B_table_39_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_12",
+ "table_id": "B_table_39_0"
+ },
+ {
+ "index": 14,
+ "pair_id": "B_origin_12_B_table_40_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_12/B_table_40_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_12",
+ "table_id": "B_table_40_0"
+ },
+ {
+ "index": 15,
+ "pair_id": "B_origin_13_B_table_41_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_13/B_table_41_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_13",
+ "table_id": "B_table_41_0"
+ },
+ {
+ "index": 16,
+ "pair_id": "B_origin_13_B_table_42_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_13/B_table_42_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_13",
+ "table_id": "B_table_42_0"
+ },
+ {
+ "index": 17,
+ "pair_id": "B_origin_13_B_table_43_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_13/B_table_43_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_13",
+ "table_id": "B_table_43_0"
+ },
+ {
+ "index": 18,
+ "pair_id": "B_origin_13_B_table_44_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_13/B_table_44_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_13",
+ "table_id": "B_table_44_0"
+ },
+ {
+ "index": 19,
+ "pair_id": "B_origin_14_B_table_45_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_14/B_table_45_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_14",
+ "table_id": "B_table_45_0"
+ },
+ {
+ "index": 20,
+ "pair_id": "B_origin_14_B_table_45_1",
+ "image_paths": [
+ "data/Business/Table/B_origin_14/B_table_45_1.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_14",
+ "table_id": "B_table_45_1"
+ },
+ {
+ "index": 21,
+ "pair_id": "B_origin_14_B_table_45_2",
+ "image_paths": [
+ "data/Business/Table/B_origin_14/B_table_45_2.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_14",
+ "table_id": "B_table_45_2"
+ },
+ {
+ "index": 22,
+ "pair_id": "B_origin_14_B_table_46_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_14/B_table_46_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_14",
+ "table_id": "B_table_46_0"
+ },
+ {
+ "index": 23,
+ "pair_id": "B_origin_14_B_table_47_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_14/B_table_47_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_14",
+ "table_id": "B_table_47_0"
+ },
+ {
+ "index": 24,
+ "pair_id": "B_origin_14_B_table_48_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_14/B_table_48_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_14",
+ "table_id": "B_table_48_0"
+ },
+ {
+ "index": 25,
+ "pair_id": "B_origin_15_B_table_49_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_15/B_table_49_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_15",
+ "table_id": "B_table_49_0"
+ },
+ {
+ "index": 26,
+ "pair_id": "B_origin_15_B_table_50_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_15/B_table_50_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_15",
+ "table_id": "B_table_50_0"
+ },
+ {
+ "index": 27,
+ "pair_id": "B_origin_15_B_table_51_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_15/B_table_51_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_15",
+ "table_id": "B_table_51_0"
+ },
+ {
+ "index": 28,
+ "pair_id": "B_origin_15_B_table_51_1",
+ "image_paths": [
+ "data/Business/Table/B_origin_15/B_table_51_1.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_15",
+ "table_id": "B_table_51_1"
+ },
+ {
+ "index": 29,
+ "pair_id": "B_origin_15_B_table_52_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_15/B_table_52_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_15",
+ "table_id": "B_table_52_0"
+ },
+ {
+ "index": 30,
+ "pair_id": "B_origin_15_B_table_53_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_15/B_table_53_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_15",
+ "table_id": "B_table_53_0"
+ },
+ {
+ "index": 31,
+ "pair_id": "B_origin_16_B_table_54_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_16/B_table_54_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_16",
+ "table_id": "B_table_54_0"
+ },
+ {
+ "index": 32,
+ "pair_id": "B_origin_17_B_table_55_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_17/B_table_55_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_17",
+ "table_id": "B_table_55_0"
+ },
+ {
+ "index": 33,
+ "pair_id": "B_origin_17_B_table_56_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_17/B_table_56_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_17",
+ "table_id": "B_table_56_0"
+ },
+ {
+ "index": 34,
+ "pair_id": "B_origin_17_B_table_57_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_17/B_table_57_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_17",
+ "table_id": "B_table_57_0"
+ },
+ {
+ "index": 35,
+ "pair_id": "B_origin_17_B_table_58_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_17/B_table_58_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_17",
+ "table_id": "B_table_58_0"
+ },
+ {
+ "index": 36,
+ "pair_id": "B_origin_17_B_table_59_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_17/B_table_59_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_17",
+ "table_id": "B_table_59_0"
+ },
+ {
+ "index": 37,
+ "pair_id": "B_origin_17_B_table_60_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_17/B_table_60_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_17",
+ "table_id": "B_table_60_0"
+ },
+ {
+ "index": 38,
+ "pair_id": "B_origin_18_B_table_61_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_18/B_table_61_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_18",
+ "table_id": "B_table_61_0"
+ },
+ {
+ "index": 39,
+ "pair_id": "B_origin_18_B_table_62_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_18/B_table_62_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_18",
+ "table_id": "B_table_62_0"
+ },
+ {
+ "index": 40,
+ "pair_id": "B_origin_18_B_table_63_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_18/B_table_63_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_18",
+ "table_id": "B_table_63_0"
+ },
+ {
+ "index": 41,
+ "pair_id": "B_origin_18_B_table_63_1",
+ "image_paths": [
+ "data/Business/Table/B_origin_18/B_table_63_1.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_18",
+ "table_id": "B_table_63_1"
+ },
+ {
+ "index": 42,
+ "pair_id": "B_origin_18_B_table_64_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_18/B_table_64_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_18",
+ "table_id": "B_table_64_0"
+ },
+ {
+ "index": 43,
+ "pair_id": "B_origin_18_B_table_65_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_18/B_table_65_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_18",
+ "table_id": "B_table_65_0"
+ },
+ {
+ "index": 44,
+ "pair_id": "B_origin_19_B_table_66_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_19/B_table_66_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_19",
+ "table_id": "B_table_66_0"
+ },
+ {
+ "index": 45,
+ "pair_id": "B_origin_2_B_table_5_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_2/B_table_5_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_2",
+ "table_id": "B_table_5_0"
+ },
+ {
+ "index": 46,
+ "pair_id": "B_origin_2_B_table_6_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_2/B_table_6_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_2",
+ "table_id": "B_table_6_0"
+ },
+ {
+ "index": 47,
+ "pair_id": "B_origin_2_B_table_7_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_2/B_table_7_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_2",
+ "table_id": "B_table_7_0"
+ },
+ {
+ "index": 48,
+ "pair_id": "B_origin_2_B_table_8_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_2/B_table_8_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_2",
+ "table_id": "B_table_8_0"
+ },
+ {
+ "index": 49,
+ "pair_id": "B_origin_2_B_table_9_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_2/B_table_9_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_2",
+ "table_id": "B_table_9_0"
+ },
+ {
+ "index": 50,
+ "pair_id": "B_origin_20_B_table_67_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_20/B_table_67_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_20",
+ "table_id": "B_table_67_0"
+ },
+ {
+ "index": 51,
+ "pair_id": "B_origin_20_B_table_68_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_20/B_table_68_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_20",
+ "table_id": "B_table_68_0"
+ },
+ {
+ "index": 52,
+ "pair_id": "B_origin_20_B_table_69_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_20/B_table_69_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_20",
+ "table_id": "B_table_69_0"
+ },
+ {
+ "index": 53,
+ "pair_id": "B_origin_21_B_table_70_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_21/B_table_70_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_21",
+ "table_id": "B_table_70_0"
+ },
+ {
+ "index": 54,
+ "pair_id": "B_origin_21_B_table_71_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_21/B_table_71_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_21",
+ "table_id": "B_table_71_0"
+ },
+ {
+ "index": 55,
+ "pair_id": "B_origin_21_B_table_72_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_21/B_table_72_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_21",
+ "table_id": "B_table_72_0"
+ },
+ {
+ "index": 56,
+ "pair_id": "B_origin_21_B_table_72_1",
+ "image_paths": [
+ "data/Business/Table/B_origin_21/B_table_72_1.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_21",
+ "table_id": "B_table_72_1"
+ },
+ {
+ "index": 57,
+ "pair_id": "B_origin_21_B_table_73_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_21/B_table_73_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_21",
+ "table_id": "B_table_73_0"
+ },
+ {
+ "index": 58,
+ "pair_id": "B_origin_21_B_table_74_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_21/B_table_74_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_21",
+ "table_id": "B_table_74_0"
+ },
+ {
+ "index": 59,
+ "pair_id": "B_origin_22_B_table_75_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_22/B_table_75_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_22",
+ "table_id": "B_table_75_0"
+ },
+ {
+ "index": 60,
+ "pair_id": "B_origin_22_B_table_76_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_22/B_table_76_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_22",
+ "table_id": "B_table_76_0"
+ },
+ {
+ "index": 61,
+ "pair_id": "B_origin_22_B_table_77_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_22/B_table_77_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_22",
+ "table_id": "B_table_77_0"
+ },
+ {
+ "index": 62,
+ "pair_id": "B_origin_22_B_table_78_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_22/B_table_78_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_22",
+ "table_id": "B_table_78_0"
+ },
+ {
+ "index": 63,
+ "pair_id": "B_origin_22_B_table_79_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_22/B_table_79_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_22",
+ "table_id": "B_table_79_0"
+ },
+ {
+ "index": 64,
+ "pair_id": "B_origin_23_B_table_79_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_23/B_table_79_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_23",
+ "table_id": "B_table_79_0"
+ },
+ {
+ "index": 65,
+ "pair_id": "B_origin_23_B_table_80_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_23/B_table_80_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_23",
+ "table_id": "B_table_80_0"
+ },
+ {
+ "index": 66,
+ "pair_id": "B_origin_23_B_table_81_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_23/B_table_81_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_23",
+ "table_id": "B_table_81_0"
+ },
+ {
+ "index": 67,
+ "pair_id": "B_origin_24_B_table_82_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_24/B_table_82_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_24",
+ "table_id": "B_table_82_0"
+ },
+ {
+ "index": 68,
+ "pair_id": "B_origin_24_B_table_83_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_24/B_table_83_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_24",
+ "table_id": "B_table_83_0"
+ },
+ {
+ "index": 69,
+ "pair_id": "B_origin_24_B_table_84_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_24/B_table_84_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_24",
+ "table_id": "B_table_84_0"
+ },
+ {
+ "index": 70,
+ "pair_id": "B_origin_25_B_table_85_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_25/B_table_85_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_25",
+ "table_id": "B_table_85_0"
+ },
+ {
+ "index": 71,
+ "pair_id": "B_origin_25_B_table_86_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_25/B_table_86_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_25",
+ "table_id": "B_table_86_0"
+ },
+ {
+ "index": 72,
+ "pair_id": "B_origin_26_B_table_87_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_26/B_table_87_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_26",
+ "table_id": "B_table_87_0"
+ },
+ {
+ "index": 73,
+ "pair_id": "B_origin_26_B_table_88_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_26/B_table_88_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_26",
+ "table_id": "B_table_88_0"
+ },
+ {
+ "index": 74,
+ "pair_id": "B_origin_27_B_table_89_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_27/B_table_89_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_27",
+ "table_id": "B_table_89_0"
+ },
+ {
+ "index": 75,
+ "pair_id": "B_origin_27_B_table_90_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_27/B_table_90_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_27",
+ "table_id": "B_table_90_0"
+ },
+ {
+ "index": 76,
+ "pair_id": "B_origin_27_B_table_91_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_27/B_table_91_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_27",
+ "table_id": "B_table_91_0"
+ },
+ {
+ "index": 77,
+ "pair_id": "B_origin_28_B_table_92_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_28/B_table_92_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_28",
+ "table_id": "B_table_92_0"
+ },
+ {
+ "index": 78,
+ "pair_id": "B_origin_28_B_table_93_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_28/B_table_93_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_28",
+ "table_id": "B_table_93_0"
+ },
+ {
+ "index": 79,
+ "pair_id": "B_origin_28_B_table_94_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_28/B_table_94_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_28",
+ "table_id": "B_table_94_0"
+ },
+ {
+ "index": 80,
+ "pair_id": "B_origin_28_B_table_95_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_28/B_table_95_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_28",
+ "table_id": "B_table_95_0"
+ },
+ {
+ "index": 81,
+ "pair_id": "B_origin_28_B_table_96_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_28/B_table_96_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_28",
+ "table_id": "B_table_96_0"
+ },
+ {
+ "index": 82,
+ "pair_id": "B_origin_28_B_table_97_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_28/B_table_97_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_28",
+ "table_id": "B_table_97_0"
+ },
+ {
+ "index": 83,
+ "pair_id": "B_origin_29_B_table_100_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_29/B_table_100_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_29",
+ "table_id": "B_table_100_0"
+ },
+ {
+ "index": 84,
+ "pair_id": "B_origin_29_B_table_98_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_29/B_table_98_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_29",
+ "table_id": "B_table_98_0"
+ },
+ {
+ "index": 85,
+ "pair_id": "B_origin_29_B_table_99_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_29/B_table_99_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_29",
+ "table_id": "B_table_99_0"
+ },
+ {
+ "index": 86,
+ "pair_id": "B_origin_3_B_table_10_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_3/B_table_10_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_3",
+ "table_id": "B_table_10_0"
+ },
+ {
+ "index": 87,
+ "pair_id": "B_origin_3_B_table_11_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_3/B_table_11_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_3",
+ "table_id": "B_table_11_0"
+ },
+ {
+ "index": 88,
+ "pair_id": "B_origin_3_B_table_12_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_3/B_table_12_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_3",
+ "table_id": "B_table_12_0"
+ },
+ {
+ "index": 89,
+ "pair_id": "B_origin_3_B_table_13_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_3/B_table_13_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_3",
+ "table_id": "B_table_13_0"
+ },
+ {
+ "index": 90,
+ "pair_id": "B_origin_30_B_table_101_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_30/B_table_101_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_30",
+ "table_id": "B_table_101_0"
+ },
+ {
+ "index": 91,
+ "pair_id": "B_origin_30_B_table_102_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_30/B_table_102_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_30",
+ "table_id": "B_table_102_0"
+ },
+ {
+ "index": 92,
+ "pair_id": "B_origin_30_B_table_103_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_30/B_table_103_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_30",
+ "table_id": "B_table_103_0"
+ },
+ {
+ "index": 93,
+ "pair_id": "B_origin_31_B_table_104_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_31/B_table_104_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_31",
+ "table_id": "B_table_104_0"
+ },
+ {
+ "index": 94,
+ "pair_id": "B_origin_31_B_table_105_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_31/B_table_105_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_31",
+ "table_id": "B_table_105_0"
+ },
+ {
+ "index": 95,
+ "pair_id": "B_origin_31_B_table_106_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_31/B_table_106_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_31",
+ "table_id": "B_table_106_0"
+ },
+ {
+ "index": 96,
+ "pair_id": "B_origin_31_B_table_107_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_31/B_table_107_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_31",
+ "table_id": "B_table_107_0"
+ },
+ {
+ "index": 97,
+ "pair_id": "B_origin_31_B_table_108_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_31/B_table_108_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_31",
+ "table_id": "B_table_108_0"
+ },
+ {
+ "index": 98,
+ "pair_id": "B_origin_32_B_table_109_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_32/B_table_109_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_32",
+ "table_id": "B_table_109_0"
+ },
+ {
+ "index": 99,
+ "pair_id": "B_origin_32_B_table_110_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_32/B_table_110_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_32",
+ "table_id": "B_table_110_0"
+ },
+ {
+ "index": 100,
+ "pair_id": "B_origin_32_B_table_111_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_32/B_table_111_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_32",
+ "table_id": "B_table_111_0"
+ },
+ {
+ "index": 101,
+ "pair_id": "B_origin_32_B_table_112_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_32/B_table_112_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_32",
+ "table_id": "B_table_112_0"
+ },
+ {
+ "index": 102,
+ "pair_id": "B_origin_33_B_table_113_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_33/B_table_113_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_33",
+ "table_id": "B_table_113_0"
+ },
+ {
+ "index": 103,
+ "pair_id": "B_origin_33_B_table_114_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_33/B_table_114_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_33",
+ "table_id": "B_table_114_0"
+ },
+ {
+ "index": 104,
+ "pair_id": "B_origin_33_B_table_115_9",
+ "image_paths": [
+ "data/Business/Table/B_origin_33/B_table_115_9.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_33",
+ "table_id": "B_table_115_9"
+ },
+ {
+ "index": 105,
+ "pair_id": "B_origin_33_B_table_116_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_33/B_table_116_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_33",
+ "table_id": "B_table_116_0"
+ },
+ {
+ "index": 106,
+ "pair_id": "B_origin_33_B_table_117_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_33/B_table_117_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_33",
+ "table_id": "B_table_117_0"
+ },
+ {
+ "index": 107,
+ "pair_id": "B_origin_34_B_table_118_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_34/B_table_118_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_34",
+ "table_id": "B_table_118_0"
+ },
+ {
+ "index": 108,
+ "pair_id": "B_origin_34_B_table_119_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_34/B_table_119_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_34",
+ "table_id": "B_table_119_0"
+ },
+ {
+ "index": 109,
+ "pair_id": "B_origin_34_B_table_120_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_34/B_table_120_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_34",
+ "table_id": "B_table_120_0"
+ },
+ {
+ "index": 110,
+ "pair_id": "B_origin_34_B_table_121_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_34/B_table_121_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_34",
+ "table_id": "B_table_121_0"
+ },
+ {
+ "index": 111,
+ "pair_id": "B_origin_35_B_table_122_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_35/B_table_122_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_35",
+ "table_id": "B_table_122_0"
+ },
+ {
+ "index": 112,
+ "pair_id": "B_origin_35_B_table_123_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_35/B_table_123_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_35",
+ "table_id": "B_table_123_0"
+ },
+ {
+ "index": 113,
+ "pair_id": "B_origin_35_B_table_124_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_35/B_table_124_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_35",
+ "table_id": "B_table_124_0"
+ },
+ {
+ "index": 114,
+ "pair_id": "B_origin_35_B_table_125_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_35/B_table_125_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_35",
+ "table_id": "B_table_125_0"
+ },
+ {
+ "index": 115,
+ "pair_id": "B_origin_35_B_table_126_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_35/B_table_126_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_35",
+ "table_id": "B_table_126_0"
+ },
+ {
+ "index": 116,
+ "pair_id": "B_origin_36_B_table_127_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_36/B_table_127_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_36",
+ "table_id": "B_table_127_0"
+ },
+ {
+ "index": 117,
+ "pair_id": "B_origin_36_B_table_128_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_36/B_table_128_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_36",
+ "table_id": "B_table_128_0"
+ },
+ {
+ "index": 118,
+ "pair_id": "B_origin_36_B_table_129_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_36/B_table_129_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_36",
+ "table_id": "B_table_129_0"
+ },
+ {
+ "index": 119,
+ "pair_id": "B_origin_36_B_table_130_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_36/B_table_130_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_36",
+ "table_id": "B_table_130_0"
+ },
+ {
+ "index": 120,
+ "pair_id": "B_origin_37_B_table_131_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_37/B_table_131_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_37",
+ "table_id": "B_table_131_0"
+ },
+ {
+ "index": 121,
+ "pair_id": "B_origin_37_B_table_132_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_37/B_table_132_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_37",
+ "table_id": "B_table_132_0"
+ },
+ {
+ "index": 122,
+ "pair_id": "B_origin_37_B_table_132_1",
+ "image_paths": [
+ "data/Business/Table/B_origin_37/B_table_132_1.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_37",
+ "table_id": "B_table_132_1"
+ },
+ {
+ "index": 123,
+ "pair_id": "B_origin_37_B_table_133_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_37/B_table_133_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_37",
+ "table_id": "B_table_133_0"
+ },
+ {
+ "index": 124,
+ "pair_id": "B_origin_37_B_table_134_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_37/B_table_134_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_37",
+ "table_id": "B_table_134_0"
+ },
+ {
+ "index": 125,
+ "pair_id": "B_origin_38_B_table_135_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_38/B_table_135_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_38",
+ "table_id": "B_table_135_0"
+ },
+ {
+ "index": 126,
+ "pair_id": "B_origin_38_B_table_136_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_38/B_table_136_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_38",
+ "table_id": "B_table_136_0"
+ },
+ {
+ "index": 127,
+ "pair_id": "B_origin_38_B_table_137_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_38/B_table_137_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_38",
+ "table_id": "B_table_137_0"
+ },
+ {
+ "index": 128,
+ "pair_id": "B_origin_38_B_table_138_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_38/B_table_138_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_38",
+ "table_id": "B_table_138_0"
+ },
+ {
+ "index": 129,
+ "pair_id": "B_origin_39_B_table_139_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_39/B_table_139_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_39",
+ "table_id": "B_table_139_0"
+ },
+ {
+ "index": 130,
+ "pair_id": "B_origin_39_B_table_140_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_39/B_table_140_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_39",
+ "table_id": "B_table_140_0"
+ },
+ {
+ "index": 131,
+ "pair_id": "B_origin_4_B_table_14_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_4/B_table_14_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_4",
+ "table_id": "B_table_14_0"
+ },
+ {
+ "index": 132,
+ "pair_id": "B_origin_4_B_table_15_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_4/B_table_15_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_4",
+ "table_id": "B_table_15_0"
+ },
+ {
+ "index": 133,
+ "pair_id": "B_origin_4_B_table_16_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_4/B_table_16_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_4",
+ "table_id": "B_table_16_0"
+ },
+ {
+ "index": 134,
+ "pair_id": "B_origin_4_B_table_16_1",
+ "image_paths": [
+ "data/Business/Table/B_origin_4/B_table_16_1.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_4",
+ "table_id": "B_table_16_1"
+ },
+ {
+ "index": 135,
+ "pair_id": "B_origin_5_B_table_17_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_5/B_table_17_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_5",
+ "table_id": "B_table_17_0"
+ },
+ {
+ "index": 136,
+ "pair_id": "B_origin_5_B_table_18_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_5/B_table_18_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_5",
+ "table_id": "B_table_18_0"
+ },
+ {
+ "index": 137,
+ "pair_id": "B_origin_6_B_table_19_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_6/B_table_19_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_6",
+ "table_id": "B_table_19_0"
+ },
+ {
+ "index": 138,
+ "pair_id": "B_origin_6_B_table_20_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_6/B_table_20_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_6",
+ "table_id": "B_table_20_0"
+ },
+ {
+ "index": 139,
+ "pair_id": "B_origin_6_B_table_21_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_6/B_table_21_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_6",
+ "table_id": "B_table_21_0"
+ },
+ {
+ "index": 140,
+ "pair_id": "B_origin_6_B_table_22_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_6/B_table_22_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_6",
+ "table_id": "B_table_22_0"
+ },
+ {
+ "index": 141,
+ "pair_id": "B_origin_7_B_table_23_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_7/B_table_23_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_7",
+ "table_id": "B_table_23_0"
+ },
+ {
+ "index": 142,
+ "pair_id": "B_origin_7_B_table_24_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_7/B_table_24_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_7",
+ "table_id": "B_table_24_0"
+ },
+ {
+ "index": 143,
+ "pair_id": "B_origin_7_B_table_25_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_7/B_table_25_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_7",
+ "table_id": "B_table_25_0"
+ },
+ {
+ "index": 144,
+ "pair_id": "B_origin_8_B_table_26_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_8/B_table_26_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_8",
+ "table_id": "B_table_26_0"
+ },
+ {
+ "index": 145,
+ "pair_id": "B_origin_8_B_table_27_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_8/B_table_27_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_8",
+ "table_id": "B_table_27_0"
+ },
+ {
+ "index": 146,
+ "pair_id": "B_origin_9_B_table_28_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_9/B_table_28_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_9",
+ "table_id": "B_table_28_0"
+ },
+ {
+ "index": 147,
+ "pair_id": "B_origin_9_B_table_29_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_9/B_table_29_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_9",
+ "table_id": "B_table_29_0"
+ },
+ {
+ "index": 148,
+ "pair_id": "B_origin_9_B_table_30_0",
+ "image_paths": [
+ "data/Business/Table/B_origin_9/B_table_30_0.png"
+ ],
+ "domain": "Business",
+ "origin": "B_origin_9",
+ "table_id": "B_table_30_0"
+ }
+]
\ No newline at end of file
diff --git a/single_image_json_list/single_table_finance_input.json b/single_image_json_list/single_table_finance_input.json
new file mode 100644
index 0000000..c40cdac
--- /dev/null
+++ b/single_image_json_list/single_table_finance_input.json
@@ -0,0 +1,3152 @@
+[
+ {
+ "index": 0,
+ "pair_id": "F_origin_0_F_table_0_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_0/F_table_0_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_0",
+ "table_id": "F_table_0_0"
+ },
+ {
+ "index": 1,
+ "pair_id": "F_origin_0_F_table_0_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_0/F_table_0_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_0",
+ "table_id": "F_table_0_1"
+ },
+ {
+ "index": 2,
+ "pair_id": "F_origin_0_F_table_0_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_0/F_table_0_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_0",
+ "table_id": "F_table_0_2"
+ },
+ {
+ "index": 3,
+ "pair_id": "F_origin_0_F_table_0_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_0/F_table_0_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_0",
+ "table_id": "F_table_0_3"
+ },
+ {
+ "index": 4,
+ "pair_id": "F_origin_0_F_table_0_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_0/F_table_0_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_0",
+ "table_id": "F_table_0_4"
+ },
+ {
+ "index": 5,
+ "pair_id": "F_origin_0_F_table_1_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_0/F_table_1_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_0",
+ "table_id": "F_table_1_0"
+ },
+ {
+ "index": 6,
+ "pair_id": "F_origin_0_F_table_1_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_0/F_table_1_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_0",
+ "table_id": "F_table_1_1"
+ },
+ {
+ "index": 7,
+ "pair_id": "F_origin_1_F_table_2_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_1/F_table_2_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_1",
+ "table_id": "F_table_2_0"
+ },
+ {
+ "index": 8,
+ "pair_id": "F_origin_1_F_table_2_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_1/F_table_2_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_1",
+ "table_id": "F_table_2_1"
+ },
+ {
+ "index": 9,
+ "pair_id": "F_origin_1_F_table_2_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_1/F_table_2_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_1",
+ "table_id": "F_table_2_2"
+ },
+ {
+ "index": 10,
+ "pair_id": "F_origin_1_F_table_2_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_1/F_table_2_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_1",
+ "table_id": "F_table_2_3"
+ },
+ {
+ "index": 11,
+ "pair_id": "F_origin_1_F_table_2_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_1/F_table_2_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_1",
+ "table_id": "F_table_2_4"
+ },
+ {
+ "index": 12,
+ "pair_id": "F_origin_10_F_table_14_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_10/F_table_14_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_10",
+ "table_id": "F_table_14_0"
+ },
+ {
+ "index": 13,
+ "pair_id": "F_origin_10_F_table_14_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_10/F_table_14_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_10",
+ "table_id": "F_table_14_1"
+ },
+ {
+ "index": 14,
+ "pair_id": "F_origin_10_F_table_14_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_10/F_table_14_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_10",
+ "table_id": "F_table_14_2"
+ },
+ {
+ "index": 15,
+ "pair_id": "F_origin_10_F_table_14_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_10/F_table_14_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_10",
+ "table_id": "F_table_14_3"
+ },
+ {
+ "index": 16,
+ "pair_id": "F_origin_10_F_table_14_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_10/F_table_14_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_10",
+ "table_id": "F_table_14_4"
+ },
+ {
+ "index": 17,
+ "pair_id": "F_origin_11_F_table_15_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_11/F_table_15_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_11",
+ "table_id": "F_table_15_0"
+ },
+ {
+ "index": 18,
+ "pair_id": "F_origin_11_F_table_15_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_11/F_table_15_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_11",
+ "table_id": "F_table_15_1"
+ },
+ {
+ "index": 19,
+ "pair_id": "F_origin_11_F_table_15_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_11/F_table_15_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_11",
+ "table_id": "F_table_15_2"
+ },
+ {
+ "index": 20,
+ "pair_id": "F_origin_11_F_table_15_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_11/F_table_15_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_11",
+ "table_id": "F_table_15_3"
+ },
+ {
+ "index": 21,
+ "pair_id": "F_origin_11_F_table_15_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_11/F_table_15_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_11",
+ "table_id": "F_table_15_4"
+ },
+ {
+ "index": 22,
+ "pair_id": "F_origin_11_F_table_15_5",
+ "image_paths": [
+ "data/Finance/Table/F_origin_11/F_table_15_5.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_11",
+ "table_id": "F_table_15_5"
+ },
+ {
+ "index": 23,
+ "pair_id": "F_origin_12_F_table_16_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_12/F_table_16_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_12",
+ "table_id": "F_table_16_0"
+ },
+ {
+ "index": 24,
+ "pair_id": "F_origin_12_F_table_17_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_12/F_table_17_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_12",
+ "table_id": "F_table_17_0"
+ },
+ {
+ "index": 25,
+ "pair_id": "F_origin_12_F_table_18_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_12/F_table_18_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_12",
+ "table_id": "F_table_18_0"
+ },
+ {
+ "index": 26,
+ "pair_id": "F_origin_12_F_table_19_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_12/F_table_19_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_12",
+ "table_id": "F_table_19_0"
+ },
+ {
+ "index": 27,
+ "pair_id": "F_origin_12_F_table_20_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_12/F_table_20_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_12",
+ "table_id": "F_table_20_0"
+ },
+ {
+ "index": 28,
+ "pair_id": "F_origin_12_F_table_21_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_12/F_table_21_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_12",
+ "table_id": "F_table_21_0"
+ },
+ {
+ "index": 29,
+ "pair_id": "F_origin_13_F_table_21_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_13/F_table_21_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_13",
+ "table_id": "F_table_21_0"
+ },
+ {
+ "index": 30,
+ "pair_id": "F_origin_13_F_table_22_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_13/F_table_22_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_13",
+ "table_id": "F_table_22_0"
+ },
+ {
+ "index": 31,
+ "pair_id": "F_origin_13_F_table_23_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_13/F_table_23_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_13",
+ "table_id": "F_table_23_0"
+ },
+ {
+ "index": 32,
+ "pair_id": "F_origin_13_F_table_24_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_13/F_table_24_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_13",
+ "table_id": "F_table_24_0"
+ },
+ {
+ "index": 33,
+ "pair_id": "F_origin_13_F_table_25_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_13/F_table_25_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_13",
+ "table_id": "F_table_25_0"
+ },
+ {
+ "index": 34,
+ "pair_id": "F_origin_14_F_table_26_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_14/F_table_26_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_14",
+ "table_id": "F_table_26_0"
+ },
+ {
+ "index": 35,
+ "pair_id": "F_origin_14_F_table_27_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_14/F_table_27_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_14",
+ "table_id": "F_table_27_0"
+ },
+ {
+ "index": 36,
+ "pair_id": "F_origin_14_F_table_28_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_14/F_table_28_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_14",
+ "table_id": "F_table_28_0"
+ },
+ {
+ "index": 37,
+ "pair_id": "F_origin_14_F_table_29_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_14/F_table_29_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_14",
+ "table_id": "F_table_29_0"
+ },
+ {
+ "index": 38,
+ "pair_id": "F_origin_14_F_table_30_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_14/F_table_30_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_14",
+ "table_id": "F_table_30_0"
+ },
+ {
+ "index": 39,
+ "pair_id": "F_origin_14_F_table_31_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_14/F_table_31_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_14",
+ "table_id": "F_table_31_0"
+ },
+ {
+ "index": 40,
+ "pair_id": "F_origin_15_F_table_32_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_15/F_table_32_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_15",
+ "table_id": "F_table_32_0"
+ },
+ {
+ "index": 41,
+ "pair_id": "F_origin_15_F_table_33_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_15/F_table_33_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_15",
+ "table_id": "F_table_33_0"
+ },
+ {
+ "index": 42,
+ "pair_id": "F_origin_15_F_table_34_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_15/F_table_34_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_15",
+ "table_id": "F_table_34_0"
+ },
+ {
+ "index": 43,
+ "pair_id": "F_origin_15_F_table_35_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_15/F_table_35_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_15",
+ "table_id": "F_table_35_0"
+ },
+ {
+ "index": 44,
+ "pair_id": "F_origin_15_F_table_36_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_15/F_table_36_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_15",
+ "table_id": "F_table_36_0"
+ },
+ {
+ "index": 45,
+ "pair_id": "F_origin_16_F_table_37_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_16/F_table_37_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_16",
+ "table_id": "F_table_37_0"
+ },
+ {
+ "index": 46,
+ "pair_id": "F_origin_16_F_table_38_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_16/F_table_38_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_16",
+ "table_id": "F_table_38_0"
+ },
+ {
+ "index": 47,
+ "pair_id": "F_origin_16_F_table_39_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_16/F_table_39_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_16",
+ "table_id": "F_table_39_0"
+ },
+ {
+ "index": 48,
+ "pair_id": "F_origin_16_F_table_40_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_16/F_table_40_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_16",
+ "table_id": "F_table_40_0"
+ },
+ {
+ "index": 49,
+ "pair_id": "F_origin_16_F_table_41_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_16/F_table_41_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_16",
+ "table_id": "F_table_41_0"
+ },
+ {
+ "index": 50,
+ "pair_id": "F_origin_16_F_table_42_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_16/F_table_42_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_16",
+ "table_id": "F_table_42_0"
+ },
+ {
+ "index": 51,
+ "pair_id": "F_origin_16_F_table_43_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_16/F_table_43_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_16",
+ "table_id": "F_table_43_0"
+ },
+ {
+ "index": 52,
+ "pair_id": "F_origin_16_F_table_44_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_16/F_table_44_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_16",
+ "table_id": "F_table_44_0"
+ },
+ {
+ "index": 53,
+ "pair_id": "F_origin_16_F_table_45_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_16/F_table_45_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_16",
+ "table_id": "F_table_45_0"
+ },
+ {
+ "index": 54,
+ "pair_id": "F_origin_17_F_table_46_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_17/F_table_46_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_17",
+ "table_id": "F_table_46_0"
+ },
+ {
+ "index": 55,
+ "pair_id": "F_origin_17_F_table_47_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_17/F_table_47_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_17",
+ "table_id": "F_table_47_0"
+ },
+ {
+ "index": 56,
+ "pair_id": "F_origin_17_F_table_48_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_17/F_table_48_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_17",
+ "table_id": "F_table_48_0"
+ },
+ {
+ "index": 57,
+ "pair_id": "F_origin_17_F_table_49_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_17/F_table_49_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_17",
+ "table_id": "F_table_49_0"
+ },
+ {
+ "index": 58,
+ "pair_id": "F_origin_17_F_table_50_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_17/F_table_50_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_17",
+ "table_id": "F_table_50_0"
+ },
+ {
+ "index": 59,
+ "pair_id": "F_origin_17_F_table_51_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_17/F_table_51_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_17",
+ "table_id": "F_table_51_0"
+ },
+ {
+ "index": 60,
+ "pair_id": "F_origin_17_F_table_52_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_17/F_table_52_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_17",
+ "table_id": "F_table_52_0"
+ },
+ {
+ "index": 61,
+ "pair_id": "F_origin_17_F_table_53_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_17/F_table_53_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_17",
+ "table_id": "F_table_53_0"
+ },
+ {
+ "index": 62,
+ "pair_id": "F_origin_17_F_table_54_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_17/F_table_54_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_17",
+ "table_id": "F_table_54_0"
+ },
+ {
+ "index": 63,
+ "pair_id": "F_origin_18_F_table_55_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_18/F_table_55_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_18",
+ "table_id": "F_table_55_0"
+ },
+ {
+ "index": 64,
+ "pair_id": "F_origin_18_F_table_56_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_18/F_table_56_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_18",
+ "table_id": "F_table_56_0"
+ },
+ {
+ "index": 65,
+ "pair_id": "F_origin_18_F_table_57_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_18/F_table_57_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_18",
+ "table_id": "F_table_57_0"
+ },
+ {
+ "index": 66,
+ "pair_id": "F_origin_18_F_table_58_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_18/F_table_58_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_18",
+ "table_id": "F_table_58_0"
+ },
+ {
+ "index": 67,
+ "pair_id": "F_origin_19_F_table_59_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_19/F_table_59_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_19",
+ "table_id": "F_table_59_0"
+ },
+ {
+ "index": 68,
+ "pair_id": "F_origin_19_F_table_59_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_19/F_table_59_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_19",
+ "table_id": "F_table_59_1"
+ },
+ {
+ "index": 69,
+ "pair_id": "F_origin_19_F_table_60_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_19/F_table_60_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_19",
+ "table_id": "F_table_60_0"
+ },
+ {
+ "index": 70,
+ "pair_id": "F_origin_19_F_table_61_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_19/F_table_61_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_19",
+ "table_id": "F_table_61_0"
+ },
+ {
+ "index": 71,
+ "pair_id": "F_origin_19_F_table_62_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_19/F_table_62_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_19",
+ "table_id": "F_table_62_0"
+ },
+ {
+ "index": 72,
+ "pair_id": "F_origin_19_F_table_63_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_19/F_table_63_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_19",
+ "table_id": "F_table_63_0"
+ },
+ {
+ "index": 73,
+ "pair_id": "F_origin_19_F_table_64_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_19/F_table_64_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_19",
+ "table_id": "F_table_64_0"
+ },
+ {
+ "index": 74,
+ "pair_id": "F_origin_19_F_table_65_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_19/F_table_65_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_19",
+ "table_id": "F_table_65_0"
+ },
+ {
+ "index": 75,
+ "pair_id": "F_origin_19_F_table_66_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_19/F_table_66_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_19",
+ "table_id": "F_table_66_0"
+ },
+ {
+ "index": 76,
+ "pair_id": "F_origin_2_F_table_3_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_2/F_table_3_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_2",
+ "table_id": "F_table_3_0"
+ },
+ {
+ "index": 77,
+ "pair_id": "F_origin_2_F_table_3_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_2/F_table_3_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_2",
+ "table_id": "F_table_3_1"
+ },
+ {
+ "index": 78,
+ "pair_id": "F_origin_2_F_table_3_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_2/F_table_3_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_2",
+ "table_id": "F_table_3_2"
+ },
+ {
+ "index": 79,
+ "pair_id": "F_origin_2_F_table_3_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_2/F_table_3_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_2",
+ "table_id": "F_table_3_3"
+ },
+ {
+ "index": 80,
+ "pair_id": "F_origin_2_F_table_3_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_2/F_table_3_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_2",
+ "table_id": "F_table_3_4"
+ },
+ {
+ "index": 81,
+ "pair_id": "F_origin_2_F_table_3_5",
+ "image_paths": [
+ "data/Finance/Table/F_origin_2/F_table_3_5.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_2",
+ "table_id": "F_table_3_5"
+ },
+ {
+ "index": 82,
+ "pair_id": "F_origin_2_F_table_4_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_2/F_table_4_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_2",
+ "table_id": "F_table_4_0"
+ },
+ {
+ "index": 83,
+ "pair_id": "F_origin_2_F_table_4_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_2/F_table_4_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_2",
+ "table_id": "F_table_4_1"
+ },
+ {
+ "index": 84,
+ "pair_id": "F_origin_20_F_table_67_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_20/F_table_67_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_20",
+ "table_id": "F_table_67_0"
+ },
+ {
+ "index": 85,
+ "pair_id": "F_origin_20_F_table_67_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_20/F_table_67_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_20",
+ "table_id": "F_table_67_1"
+ },
+ {
+ "index": 86,
+ "pair_id": "F_origin_20_F_table_68_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_20/F_table_68_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_20",
+ "table_id": "F_table_68_0"
+ },
+ {
+ "index": 87,
+ "pair_id": "F_origin_20_F_table_68_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_20/F_table_68_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_20",
+ "table_id": "F_table_68_1"
+ },
+ {
+ "index": 88,
+ "pair_id": "F_origin_20_F_table_68_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_20/F_table_68_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_20",
+ "table_id": "F_table_68_2"
+ },
+ {
+ "index": 89,
+ "pair_id": "F_origin_20_F_table_68_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_20/F_table_68_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_20",
+ "table_id": "F_table_68_3"
+ },
+ {
+ "index": 90,
+ "pair_id": "F_origin_20_F_table_68_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_20/F_table_68_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_20",
+ "table_id": "F_table_68_4"
+ },
+ {
+ "index": 91,
+ "pair_id": "F_origin_20_F_table_68_5",
+ "image_paths": [
+ "data/Finance/Table/F_origin_20/F_table_68_5.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_20",
+ "table_id": "F_table_68_5"
+ },
+ {
+ "index": 92,
+ "pair_id": "F_origin_20_F_table_68_6",
+ "image_paths": [
+ "data/Finance/Table/F_origin_20/F_table_68_6.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_20",
+ "table_id": "F_table_68_6"
+ },
+ {
+ "index": 93,
+ "pair_id": "F_origin_20_F_table_69_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_20/F_table_69_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_20",
+ "table_id": "F_table_69_0"
+ },
+ {
+ "index": 94,
+ "pair_id": "F_origin_21_F_table_70_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_21/F_table_70_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_21",
+ "table_id": "F_table_70_0"
+ },
+ {
+ "index": 95,
+ "pair_id": "F_origin_21_F_table_70_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_21/F_table_70_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_21",
+ "table_id": "F_table_70_1"
+ },
+ {
+ "index": 96,
+ "pair_id": "F_origin_21_F_table_70_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_21/F_table_70_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_21",
+ "table_id": "F_table_70_2"
+ },
+ {
+ "index": 97,
+ "pair_id": "F_origin_21_F_table_70_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_21/F_table_70_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_21",
+ "table_id": "F_table_70_3"
+ },
+ {
+ "index": 98,
+ "pair_id": "F_origin_21_F_table_71_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_21/F_table_71_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_21",
+ "table_id": "F_table_71_0"
+ },
+ {
+ "index": 99,
+ "pair_id": "F_origin_22_F_table_72_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_22/F_table_72_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_22",
+ "table_id": "F_table_72_0"
+ },
+ {
+ "index": 100,
+ "pair_id": "F_origin_22_F_table_72_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_22/F_table_72_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_22",
+ "table_id": "F_table_72_1"
+ },
+ {
+ "index": 101,
+ "pair_id": "F_origin_22_F_table_72_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_22/F_table_72_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_22",
+ "table_id": "F_table_72_2"
+ },
+ {
+ "index": 102,
+ "pair_id": "F_origin_22_F_table_72_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_22/F_table_72_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_22",
+ "table_id": "F_table_72_3"
+ },
+ {
+ "index": 103,
+ "pair_id": "F_origin_22_F_table_72_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_22/F_table_72_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_22",
+ "table_id": "F_table_72_4"
+ },
+ {
+ "index": 104,
+ "pair_id": "F_origin_22_F_table_72_5",
+ "image_paths": [
+ "data/Finance/Table/F_origin_22/F_table_72_5.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_22",
+ "table_id": "F_table_72_5"
+ },
+ {
+ "index": 105,
+ "pair_id": "F_origin_22_F_table_73_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_22/F_table_73_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_22",
+ "table_id": "F_table_73_0"
+ },
+ {
+ "index": 106,
+ "pair_id": "F_origin_23_F_table_74_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_23/F_table_74_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_23",
+ "table_id": "F_table_74_0"
+ },
+ {
+ "index": 107,
+ "pair_id": "F_origin_23_F_table_74_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_23/F_table_74_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_23",
+ "table_id": "F_table_74_1"
+ },
+ {
+ "index": 108,
+ "pair_id": "F_origin_23_F_table_74_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_23/F_table_74_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_23",
+ "table_id": "F_table_74_2"
+ },
+ {
+ "index": 109,
+ "pair_id": "F_origin_23_F_table_74_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_23/F_table_74_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_23",
+ "table_id": "F_table_74_3"
+ },
+ {
+ "index": 110,
+ "pair_id": "F_origin_23_F_table_74_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_23/F_table_74_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_23",
+ "table_id": "F_table_74_4"
+ },
+ {
+ "index": 111,
+ "pair_id": "F_origin_23_F_table_74_5",
+ "image_paths": [
+ "data/Finance/Table/F_origin_23/F_table_74_5.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_23",
+ "table_id": "F_table_74_5"
+ },
+ {
+ "index": 112,
+ "pair_id": "F_origin_23_F_table_75_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_23/F_table_75_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_23",
+ "table_id": "F_table_75_0"
+ },
+ {
+ "index": 113,
+ "pair_id": "F_origin_24_F_table_75_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_24/F_table_75_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_24",
+ "table_id": "F_table_75_0"
+ },
+ {
+ "index": 114,
+ "pair_id": "F_origin_24_F_table_75_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_24/F_table_75_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_24",
+ "table_id": "F_table_75_1"
+ },
+ {
+ "index": 115,
+ "pair_id": "F_origin_24_F_table_75_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_24/F_table_75_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_24",
+ "table_id": "F_table_75_2"
+ },
+ {
+ "index": 116,
+ "pair_id": "F_origin_24_F_table_75_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_24/F_table_75_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_24",
+ "table_id": "F_table_75_3"
+ },
+ {
+ "index": 117,
+ "pair_id": "F_origin_24_F_table_75_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_24/F_table_75_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_24",
+ "table_id": "F_table_75_4"
+ },
+ {
+ "index": 118,
+ "pair_id": "F_origin_24_F_table_75_5",
+ "image_paths": [
+ "data/Finance/Table/F_origin_24/F_table_75_5.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_24",
+ "table_id": "F_table_75_5"
+ },
+ {
+ "index": 119,
+ "pair_id": "F_origin_24_F_table_75_6",
+ "image_paths": [
+ "data/Finance/Table/F_origin_24/F_table_75_6.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_24",
+ "table_id": "F_table_75_6"
+ },
+ {
+ "index": 120,
+ "pair_id": "F_origin_24_F_table_75_7",
+ "image_paths": [
+ "data/Finance/Table/F_origin_24/F_table_75_7.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_24",
+ "table_id": "F_table_75_7"
+ },
+ {
+ "index": 121,
+ "pair_id": "F_origin_24_F_table_76_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_24/F_table_76_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_24",
+ "table_id": "F_table_76_0"
+ },
+ {
+ "index": 122,
+ "pair_id": "F_origin_24_F_table_76_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_24/F_table_76_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_24",
+ "table_id": "F_table_76_1"
+ },
+ {
+ "index": 123,
+ "pair_id": "F_origin_24_F_table_76_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_24/F_table_76_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_24",
+ "table_id": "F_table_76_2"
+ },
+ {
+ "index": 124,
+ "pair_id": "F_origin_24_F_table_76_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_24/F_table_76_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_24",
+ "table_id": "F_table_76_3"
+ },
+ {
+ "index": 125,
+ "pair_id": "F_origin_24_F_table_76_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_24/F_table_76_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_24",
+ "table_id": "F_table_76_4"
+ },
+ {
+ "index": 126,
+ "pair_id": "F_origin_24_F_table_77_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_24/F_table_77_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_24",
+ "table_id": "F_table_77_0"
+ },
+ {
+ "index": 127,
+ "pair_id": "F_origin_25_F_table_79_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_25/F_table_79_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_25",
+ "table_id": "F_table_79_0"
+ },
+ {
+ "index": 128,
+ "pair_id": "F_origin_25_F_table_80_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_25/F_table_80_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_25",
+ "table_id": "F_table_80_0"
+ },
+ {
+ "index": 129,
+ "pair_id": "F_origin_25_F_table_81_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_25/F_table_81_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_25",
+ "table_id": "F_table_81_0"
+ },
+ {
+ "index": 130,
+ "pair_id": "F_origin_25_F_table_82_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_25/F_table_82_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_25",
+ "table_id": "F_table_82_0"
+ },
+ {
+ "index": 131,
+ "pair_id": "F_origin_25_F_table_82_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_25/F_table_82_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_25",
+ "table_id": "F_table_82_1"
+ },
+ {
+ "index": 132,
+ "pair_id": "F_origin_25_F_table_82_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_25/F_table_82_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_25",
+ "table_id": "F_table_82_2"
+ },
+ {
+ "index": 133,
+ "pair_id": "F_origin_25_F_table_83_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_25/F_table_83_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_25",
+ "table_id": "F_table_83_0"
+ },
+ {
+ "index": 134,
+ "pair_id": "F_origin_26_F_table_84_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_26/F_table_84_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_26",
+ "table_id": "F_table_84_0"
+ },
+ {
+ "index": 135,
+ "pair_id": "F_origin_26_F_table_84_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_26/F_table_84_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_26",
+ "table_id": "F_table_84_1"
+ },
+ {
+ "index": 136,
+ "pair_id": "F_origin_26_F_table_85_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_26/F_table_85_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_26",
+ "table_id": "F_table_85_0"
+ },
+ {
+ "index": 137,
+ "pair_id": "F_origin_26_F_table_86_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_26/F_table_86_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_26",
+ "table_id": "F_table_86_0"
+ },
+ {
+ "index": 138,
+ "pair_id": "F_origin_26_F_table_87_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_26/F_table_87_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_26",
+ "table_id": "F_table_87_0"
+ },
+ {
+ "index": 139,
+ "pair_id": "F_origin_27_F_table_88_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_27/F_table_88_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_27",
+ "table_id": "F_table_88_0"
+ },
+ {
+ "index": 140,
+ "pair_id": "F_origin_27_F_table_88_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_27/F_table_88_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_27",
+ "table_id": "F_table_88_1"
+ },
+ {
+ "index": 141,
+ "pair_id": "F_origin_27_F_table_89_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_27/F_table_89_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_27",
+ "table_id": "F_table_89_0"
+ },
+ {
+ "index": 142,
+ "pair_id": "F_origin_27_F_table_89_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_27/F_table_89_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_27",
+ "table_id": "F_table_89_1"
+ },
+ {
+ "index": 143,
+ "pair_id": "F_origin_27_F_table_89_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_27/F_table_89_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_27",
+ "table_id": "F_table_89_2"
+ },
+ {
+ "index": 144,
+ "pair_id": "F_origin_27_F_table_90_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_27/F_table_90_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_27",
+ "table_id": "F_table_90_0"
+ },
+ {
+ "index": 145,
+ "pair_id": "F_origin_28_F_table_91_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_28/F_table_91_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_28",
+ "table_id": "F_table_91_0"
+ },
+ {
+ "index": 146,
+ "pair_id": "F_origin_28_F_table_91_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_28/F_table_91_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_28",
+ "table_id": "F_table_91_1"
+ },
+ {
+ "index": 147,
+ "pair_id": "F_origin_28_F_table_91_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_28/F_table_91_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_28",
+ "table_id": "F_table_91_2"
+ },
+ {
+ "index": 148,
+ "pair_id": "F_origin_28_F_table_91_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_28/F_table_91_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_28",
+ "table_id": "F_table_91_3"
+ },
+ {
+ "index": 149,
+ "pair_id": "F_origin_28_F_table_92_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_28/F_table_92_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_28",
+ "table_id": "F_table_92_0"
+ },
+ {
+ "index": 150,
+ "pair_id": "F_origin_29_F_table_93_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_29/F_table_93_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_29",
+ "table_id": "F_table_93_0"
+ },
+ {
+ "index": 151,
+ "pair_id": "F_origin_29_F_table_93_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_29/F_table_93_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_29",
+ "table_id": "F_table_93_1"
+ },
+ {
+ "index": 152,
+ "pair_id": "F_origin_29_F_table_93_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_29/F_table_93_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_29",
+ "table_id": "F_table_93_2"
+ },
+ {
+ "index": 153,
+ "pair_id": "F_origin_29_F_table_93_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_29/F_table_93_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_29",
+ "table_id": "F_table_93_3"
+ },
+ {
+ "index": 154,
+ "pair_id": "F_origin_29_F_table_93_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_29/F_table_93_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_29",
+ "table_id": "F_table_93_4"
+ },
+ {
+ "index": 155,
+ "pair_id": "F_origin_29_F_table_94_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_29/F_table_94_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_29",
+ "table_id": "F_table_94_0"
+ },
+ {
+ "index": 156,
+ "pair_id": "F_origin_3_F_table_5_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_3/F_table_5_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_3",
+ "table_id": "F_table_5_0"
+ },
+ {
+ "index": 157,
+ "pair_id": "F_origin_3_F_table_5_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_3/F_table_5_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_3",
+ "table_id": "F_table_5_1"
+ },
+ {
+ "index": 158,
+ "pair_id": "F_origin_3_F_table_5_10",
+ "image_paths": [
+ "data/Finance/Table/F_origin_3/F_table_5_10.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_3",
+ "table_id": "F_table_5_10"
+ },
+ {
+ "index": 159,
+ "pair_id": "F_origin_3_F_table_5_11",
+ "image_paths": [
+ "data/Finance/Table/F_origin_3/F_table_5_11.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_3",
+ "table_id": "F_table_5_11"
+ },
+ {
+ "index": 160,
+ "pair_id": "F_origin_3_F_table_5_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_3/F_table_5_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_3",
+ "table_id": "F_table_5_2"
+ },
+ {
+ "index": 161,
+ "pair_id": "F_origin_3_F_table_5_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_3/F_table_5_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_3",
+ "table_id": "F_table_5_3"
+ },
+ {
+ "index": 162,
+ "pair_id": "F_origin_3_F_table_5_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_3/F_table_5_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_3",
+ "table_id": "F_table_5_4"
+ },
+ {
+ "index": 163,
+ "pair_id": "F_origin_3_F_table_5_5",
+ "image_paths": [
+ "data/Finance/Table/F_origin_3/F_table_5_5.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_3",
+ "table_id": "F_table_5_5"
+ },
+ {
+ "index": 164,
+ "pair_id": "F_origin_3_F_table_5_6",
+ "image_paths": [
+ "data/Finance/Table/F_origin_3/F_table_5_6.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_3",
+ "table_id": "F_table_5_6"
+ },
+ {
+ "index": 165,
+ "pair_id": "F_origin_3_F_table_5_7",
+ "image_paths": [
+ "data/Finance/Table/F_origin_3/F_table_5_7.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_3",
+ "table_id": "F_table_5_7"
+ },
+ {
+ "index": 166,
+ "pair_id": "F_origin_3_F_table_5_8",
+ "image_paths": [
+ "data/Finance/Table/F_origin_3/F_table_5_8.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_3",
+ "table_id": "F_table_5_8"
+ },
+ {
+ "index": 167,
+ "pair_id": "F_origin_3_F_table_5_9",
+ "image_paths": [
+ "data/Finance/Table/F_origin_3/F_table_5_9.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_3",
+ "table_id": "F_table_5_9"
+ },
+ {
+ "index": 168,
+ "pair_id": "F_origin_30_F_table_95_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_30/F_table_95_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_30",
+ "table_id": "F_table_95_0"
+ },
+ {
+ "index": 169,
+ "pair_id": "F_origin_30_F_table_96_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_30/F_table_96_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_30",
+ "table_id": "F_table_96_0"
+ },
+ {
+ "index": 170,
+ "pair_id": "F_origin_30_F_table_97_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_30/F_table_97_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_30",
+ "table_id": "F_table_97_0"
+ },
+ {
+ "index": 171,
+ "pair_id": "F_origin_30_F_table_97_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_30/F_table_97_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_30",
+ "table_id": "F_table_97_1"
+ },
+ {
+ "index": 172,
+ "pair_id": "F_origin_30_F_table_97_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_30/F_table_97_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_30",
+ "table_id": "F_table_97_2"
+ },
+ {
+ "index": 173,
+ "pair_id": "F_origin_31_F_table_100_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_31/F_table_100_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_31",
+ "table_id": "F_table_100_0"
+ },
+ {
+ "index": 174,
+ "pair_id": "F_origin_31_F_table_100_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_31/F_table_100_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_31",
+ "table_id": "F_table_100_1"
+ },
+ {
+ "index": 175,
+ "pair_id": "F_origin_31_F_table_100_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_31/F_table_100_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_31",
+ "table_id": "F_table_100_2"
+ },
+ {
+ "index": 176,
+ "pair_id": "F_origin_31_F_table_98_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_31/F_table_98_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_31",
+ "table_id": "F_table_98_0"
+ },
+ {
+ "index": 177,
+ "pair_id": "F_origin_31_F_table_99_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_31/F_table_99_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_31",
+ "table_id": "F_table_99_0"
+ },
+ {
+ "index": 178,
+ "pair_id": "F_origin_32_F_table_101_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_32/F_table_101_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_32",
+ "table_id": "F_table_101_0"
+ },
+ {
+ "index": 179,
+ "pair_id": "F_origin_32_F_table_102_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_32/F_table_102_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_32",
+ "table_id": "F_table_102_0"
+ },
+ {
+ "index": 180,
+ "pair_id": "F_origin_32_F_table_103_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_32/F_table_103_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_32",
+ "table_id": "F_table_103_0"
+ },
+ {
+ "index": 181,
+ "pair_id": "F_origin_32_F_table_103_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_32/F_table_103_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_32",
+ "table_id": "F_table_103_1"
+ },
+ {
+ "index": 182,
+ "pair_id": "F_origin_32_F_table_103_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_32/F_table_103_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_32",
+ "table_id": "F_table_103_2"
+ },
+ {
+ "index": 183,
+ "pair_id": "F_origin_33_F_table_104_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_33/F_table_104_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_33",
+ "table_id": "F_table_104_0"
+ },
+ {
+ "index": 184,
+ "pair_id": "F_origin_33_F_table_105_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_33/F_table_105_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_33",
+ "table_id": "F_table_105_0"
+ },
+ {
+ "index": 185,
+ "pair_id": "F_origin_33_F_table_106_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_33/F_table_106_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_33",
+ "table_id": "F_table_106_0"
+ },
+ {
+ "index": 186,
+ "pair_id": "F_origin_33_F_table_106_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_33/F_table_106_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_33",
+ "table_id": "F_table_106_1"
+ },
+ {
+ "index": 187,
+ "pair_id": "F_origin_33_F_table_106_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_33/F_table_106_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_33",
+ "table_id": "F_table_106_2"
+ },
+ {
+ "index": 188,
+ "pair_id": "F_origin_34_F_table_107_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_34/F_table_107_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_34",
+ "table_id": "F_table_107_0"
+ },
+ {
+ "index": 189,
+ "pair_id": "F_origin_34_F_table_108_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_34/F_table_108_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_34",
+ "table_id": "F_table_108_0"
+ },
+ {
+ "index": 190,
+ "pair_id": "F_origin_34_F_table_109_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_34/F_table_109_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_34",
+ "table_id": "F_table_109_0"
+ },
+ {
+ "index": 191,
+ "pair_id": "F_origin_34_F_table_109_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_34/F_table_109_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_34",
+ "table_id": "F_table_109_1"
+ },
+ {
+ "index": 192,
+ "pair_id": "F_origin_34_F_table_109_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_34/F_table_109_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_34",
+ "table_id": "F_table_109_2"
+ },
+ {
+ "index": 193,
+ "pair_id": "F_origin_35_F_table_110_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_35/F_table_110_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_35",
+ "table_id": "F_table_110_0"
+ },
+ {
+ "index": 194,
+ "pair_id": "F_origin_35_F_table_111_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_35/F_table_111_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_35",
+ "table_id": "F_table_111_0"
+ },
+ {
+ "index": 195,
+ "pair_id": "F_origin_35_F_table_112_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_35/F_table_112_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_35",
+ "table_id": "F_table_112_0"
+ },
+ {
+ "index": 196,
+ "pair_id": "F_origin_35_F_table_112_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_35/F_table_112_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_35",
+ "table_id": "F_table_112_1"
+ },
+ {
+ "index": 197,
+ "pair_id": "F_origin_35_F_table_112_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_35/F_table_112_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_35",
+ "table_id": "F_table_112_2"
+ },
+ {
+ "index": 198,
+ "pair_id": "F_origin_36_F_table_113_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_36/F_table_113_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_36",
+ "table_id": "F_table_113_0"
+ },
+ {
+ "index": 199,
+ "pair_id": "F_origin_36_F_table_114_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_36/F_table_114_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_36",
+ "table_id": "F_table_114_0"
+ },
+ {
+ "index": 200,
+ "pair_id": "F_origin_36_F_table_115_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_36/F_table_115_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_36",
+ "table_id": "F_table_115_0"
+ },
+ {
+ "index": 201,
+ "pair_id": "F_origin_36_F_table_115_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_36/F_table_115_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_36",
+ "table_id": "F_table_115_1"
+ },
+ {
+ "index": 202,
+ "pair_id": "F_origin_36_F_table_115_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_36/F_table_115_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_36",
+ "table_id": "F_table_115_2"
+ },
+ {
+ "index": 203,
+ "pair_id": "F_origin_36_F_table_116_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_36/F_table_116_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_36",
+ "table_id": "F_table_116_0"
+ },
+ {
+ "index": 204,
+ "pair_id": "F_origin_37_F_table_117_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_37/F_table_117_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_37",
+ "table_id": "F_table_117_0"
+ },
+ {
+ "index": 205,
+ "pair_id": "F_origin_37_F_table_118_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_37/F_table_118_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_37",
+ "table_id": "F_table_118_0"
+ },
+ {
+ "index": 206,
+ "pair_id": "F_origin_37_F_table_119_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_37/F_table_119_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_37",
+ "table_id": "F_table_119_0"
+ },
+ {
+ "index": 207,
+ "pair_id": "F_origin_37_F_table_119_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_37/F_table_119_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_37",
+ "table_id": "F_table_119_1"
+ },
+ {
+ "index": 208,
+ "pair_id": "F_origin_37_F_table_119_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_37/F_table_119_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_37",
+ "table_id": "F_table_119_2"
+ },
+ {
+ "index": 209,
+ "pair_id": "F_origin_37_F_table_119_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_37/F_table_119_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_37",
+ "table_id": "F_table_119_3"
+ },
+ {
+ "index": 210,
+ "pair_id": "F_origin_37_F_table_119_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_37/F_table_119_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_37",
+ "table_id": "F_table_119_4"
+ },
+ {
+ "index": 211,
+ "pair_id": "F_origin_38_F_table_120_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_38/F_table_120_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_38",
+ "table_id": "F_table_120_0"
+ },
+ {
+ "index": 212,
+ "pair_id": "F_origin_38_F_table_121_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_38/F_table_121_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_38",
+ "table_id": "F_table_121_0"
+ },
+ {
+ "index": 213,
+ "pair_id": "F_origin_38_F_table_122_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_38/F_table_122_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_38",
+ "table_id": "F_table_122_0"
+ },
+ {
+ "index": 214,
+ "pair_id": "F_origin_38_F_table_122_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_38/F_table_122_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_38",
+ "table_id": "F_table_122_1"
+ },
+ {
+ "index": 215,
+ "pair_id": "F_origin_38_F_table_122_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_38/F_table_122_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_38",
+ "table_id": "F_table_122_2"
+ },
+ {
+ "index": 216,
+ "pair_id": "F_origin_39_F_table_123_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_39/F_table_123_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_39",
+ "table_id": "F_table_123_0"
+ },
+ {
+ "index": 217,
+ "pair_id": "F_origin_39_F_table_124_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_39/F_table_124_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_39",
+ "table_id": "F_table_124_0"
+ },
+ {
+ "index": 218,
+ "pair_id": "F_origin_39_F_table_125_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_39/F_table_125_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_39",
+ "table_id": "F_table_125_0"
+ },
+ {
+ "index": 219,
+ "pair_id": "F_origin_39_F_table_125_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_39/F_table_125_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_39",
+ "table_id": "F_table_125_1"
+ },
+ {
+ "index": 220,
+ "pair_id": "F_origin_39_F_table_125_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_39/F_table_125_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_39",
+ "table_id": "F_table_125_2"
+ },
+ {
+ "index": 221,
+ "pair_id": "F_origin_4_F_table_6_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_4/F_table_6_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_4",
+ "table_id": "F_table_6_0"
+ },
+ {
+ "index": 222,
+ "pair_id": "F_origin_4_F_table_6_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_4/F_table_6_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_4",
+ "table_id": "F_table_6_1"
+ },
+ {
+ "index": 223,
+ "pair_id": "F_origin_4_F_table_6_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_4/F_table_6_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_4",
+ "table_id": "F_table_6_2"
+ },
+ {
+ "index": 224,
+ "pair_id": "F_origin_4_F_table_6_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_4/F_table_6_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_4",
+ "table_id": "F_table_6_3"
+ },
+ {
+ "index": 225,
+ "pair_id": "F_origin_40_F_table_126_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_40/F_table_126_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_40",
+ "table_id": "F_table_126_0"
+ },
+ {
+ "index": 226,
+ "pair_id": "F_origin_40_F_table_127_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_40/F_table_127_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_40",
+ "table_id": "F_table_127_0"
+ },
+ {
+ "index": 227,
+ "pair_id": "F_origin_40_F_table_128_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_40/F_table_128_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_40",
+ "table_id": "F_table_128_0"
+ },
+ {
+ "index": 228,
+ "pair_id": "F_origin_40_F_table_128_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_40/F_table_128_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_40",
+ "table_id": "F_table_128_1"
+ },
+ {
+ "index": 229,
+ "pair_id": "F_origin_40_F_table_128_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_40/F_table_128_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_40",
+ "table_id": "F_table_128_2"
+ },
+ {
+ "index": 230,
+ "pair_id": "F_origin_41_F_table_129_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_41/F_table_129_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_41",
+ "table_id": "F_table_129_0"
+ },
+ {
+ "index": 231,
+ "pair_id": "F_origin_41_F_table_129_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_41/F_table_129_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_41",
+ "table_id": "F_table_129_1"
+ },
+ {
+ "index": 232,
+ "pair_id": "F_origin_41_F_table_129_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_41/F_table_129_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_41",
+ "table_id": "F_table_129_2"
+ },
+ {
+ "index": 233,
+ "pair_id": "F_origin_41_F_table_129_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_41/F_table_129_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_41",
+ "table_id": "F_table_129_3"
+ },
+ {
+ "index": 234,
+ "pair_id": "F_origin_41_F_table_129_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_41/F_table_129_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_41",
+ "table_id": "F_table_129_4"
+ },
+ {
+ "index": 235,
+ "pair_id": "F_origin_41_F_table_129_5",
+ "image_paths": [
+ "data/Finance/Table/F_origin_41/F_table_129_5.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_41",
+ "table_id": "F_table_129_5"
+ },
+ {
+ "index": 236,
+ "pair_id": "F_origin_42_F_table_130_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_42/F_table_130_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_42",
+ "table_id": "F_table_130_0"
+ },
+ {
+ "index": 237,
+ "pair_id": "F_origin_42_F_table_130_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_42/F_table_130_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_42",
+ "table_id": "F_table_130_1"
+ },
+ {
+ "index": 238,
+ "pair_id": "F_origin_42_F_table_130_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_42/F_table_130_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_42",
+ "table_id": "F_table_130_2"
+ },
+ {
+ "index": 239,
+ "pair_id": "F_origin_42_F_table_130_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_42/F_table_130_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_42",
+ "table_id": "F_table_130_3"
+ },
+ {
+ "index": 240,
+ "pair_id": "F_origin_42_F_table_130_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_42/F_table_130_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_42",
+ "table_id": "F_table_130_4"
+ },
+ {
+ "index": 241,
+ "pair_id": "F_origin_42_F_table_130_5",
+ "image_paths": [
+ "data/Finance/Table/F_origin_42/F_table_130_5.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_42",
+ "table_id": "F_table_130_5"
+ },
+ {
+ "index": 242,
+ "pair_id": "F_origin_43_F_table_131_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_43/F_table_131_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_43",
+ "table_id": "F_table_131_0"
+ },
+ {
+ "index": 243,
+ "pair_id": "F_origin_43_F_table_131_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_43/F_table_131_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_43",
+ "table_id": "F_table_131_1"
+ },
+ {
+ "index": 244,
+ "pair_id": "F_origin_43_F_table_131_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_43/F_table_131_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_43",
+ "table_id": "F_table_131_2"
+ },
+ {
+ "index": 245,
+ "pair_id": "F_origin_43_F_table_131_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_43/F_table_131_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_43",
+ "table_id": "F_table_131_3"
+ },
+ {
+ "index": 246,
+ "pair_id": "F_origin_43_F_table_131_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_43/F_table_131_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_43",
+ "table_id": "F_table_131_4"
+ },
+ {
+ "index": 247,
+ "pair_id": "F_origin_44_F_table_132_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_44/F_table_132_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_44",
+ "table_id": "F_table_132_0"
+ },
+ {
+ "index": 248,
+ "pair_id": "F_origin_44_F_table_132_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_44/F_table_132_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_44",
+ "table_id": "F_table_132_1"
+ },
+ {
+ "index": 249,
+ "pair_id": "F_origin_44_F_table_133_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_44/F_table_133_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_44",
+ "table_id": "F_table_133_0"
+ },
+ {
+ "index": 250,
+ "pair_id": "F_origin_44_F_table_133_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_44/F_table_133_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_44",
+ "table_id": "F_table_133_1"
+ },
+ {
+ "index": 251,
+ "pair_id": "F_origin_44_F_table_133_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_44/F_table_133_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_44",
+ "table_id": "F_table_133_2"
+ },
+ {
+ "index": 252,
+ "pair_id": "F_origin_44_F_table_134_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_44/F_table_134_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_44",
+ "table_id": "F_table_134_0"
+ },
+ {
+ "index": 253,
+ "pair_id": "F_origin_44_F_table_135_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_44/F_table_135_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_44",
+ "table_id": "F_table_135_0"
+ },
+ {
+ "index": 254,
+ "pair_id": "F_origin_44_F_table_135_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_44/F_table_135_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_44",
+ "table_id": "F_table_135_1"
+ },
+ {
+ "index": 255,
+ "pair_id": "F_origin_44_F_table_135_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_44/F_table_135_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_44",
+ "table_id": "F_table_135_2"
+ },
+ {
+ "index": 256,
+ "pair_id": "F_origin_45_F_table_136_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_45/F_table_136_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_45",
+ "table_id": "F_table_136_0"
+ },
+ {
+ "index": 257,
+ "pair_id": "F_origin_45_F_table_136_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_45/F_table_136_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_45",
+ "table_id": "F_table_136_1"
+ },
+ {
+ "index": 258,
+ "pair_id": "F_origin_45_F_table_136_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_45/F_table_136_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_45",
+ "table_id": "F_table_136_2"
+ },
+ {
+ "index": 259,
+ "pair_id": "F_origin_45_F_table_136_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_45/F_table_136_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_45",
+ "table_id": "F_table_136_3"
+ },
+ {
+ "index": 260,
+ "pair_id": "F_origin_45_F_table_136_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_45/F_table_136_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_45",
+ "table_id": "F_table_136_4"
+ },
+ {
+ "index": 261,
+ "pair_id": "F_origin_45_F_table_136_5",
+ "image_paths": [
+ "data/Finance/Table/F_origin_45/F_table_136_5.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_45",
+ "table_id": "F_table_136_5"
+ },
+ {
+ "index": 262,
+ "pair_id": "F_origin_46_F_table_137_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_46/F_table_137_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_46",
+ "table_id": "F_table_137_0"
+ },
+ {
+ "index": 263,
+ "pair_id": "F_origin_46_F_table_137_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_46/F_table_137_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_46",
+ "table_id": "F_table_137_1"
+ },
+ {
+ "index": 264,
+ "pair_id": "F_origin_46_F_table_138_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_46/F_table_138_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_46",
+ "table_id": "F_table_138_0"
+ },
+ {
+ "index": 265,
+ "pair_id": "F_origin_46_F_table_138_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_46/F_table_138_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_46",
+ "table_id": "F_table_138_1"
+ },
+ {
+ "index": 266,
+ "pair_id": "F_origin_46_F_table_139_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_46/F_table_139_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_46",
+ "table_id": "F_table_139_0"
+ },
+ {
+ "index": 267,
+ "pair_id": "F_origin_46_F_table_139_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_46/F_table_139_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_46",
+ "table_id": "F_table_139_1"
+ },
+ {
+ "index": 268,
+ "pair_id": "F_origin_47_F_table_140_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_47/F_table_140_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_47",
+ "table_id": "F_table_140_0"
+ },
+ {
+ "index": 269,
+ "pair_id": "F_origin_47_F_table_141_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_47/F_table_141_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_47",
+ "table_id": "F_table_141_0"
+ },
+ {
+ "index": 270,
+ "pair_id": "F_origin_47_F_table_141_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_47/F_table_141_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_47",
+ "table_id": "F_table_141_1"
+ },
+ {
+ "index": 271,
+ "pair_id": "F_origin_47_F_table_142_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_47/F_table_142_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_47",
+ "table_id": "F_table_142_0"
+ },
+ {
+ "index": 272,
+ "pair_id": "F_origin_47_F_table_142_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_47/F_table_142_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_47",
+ "table_id": "F_table_142_1"
+ },
+ {
+ "index": 273,
+ "pair_id": "F_origin_47_F_table_142_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_47/F_table_142_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_47",
+ "table_id": "F_table_142_2"
+ },
+ {
+ "index": 274,
+ "pair_id": "F_origin_47_F_table_142_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_47/F_table_142_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_47",
+ "table_id": "F_table_142_3"
+ },
+ {
+ "index": 275,
+ "pair_id": "F_origin_48_F_table_143_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_48/F_table_143_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_48",
+ "table_id": "F_table_143_0"
+ },
+ {
+ "index": 276,
+ "pair_id": "F_origin_48_F_table_144_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_48/F_table_144_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_48",
+ "table_id": "F_table_144_0"
+ },
+ {
+ "index": 277,
+ "pair_id": "F_origin_48_F_table_144_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_48/F_table_144_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_48",
+ "table_id": "F_table_144_1"
+ },
+ {
+ "index": 278,
+ "pair_id": "F_origin_48_F_table_145_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_48/F_table_145_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_48",
+ "table_id": "F_table_145_0"
+ },
+ {
+ "index": 279,
+ "pair_id": "F_origin_48_F_table_145_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_48/F_table_145_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_48",
+ "table_id": "F_table_145_1"
+ },
+ {
+ "index": 280,
+ "pair_id": "F_origin_49_F_table_146_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_49/F_table_146_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_49",
+ "table_id": "F_table_146_0"
+ },
+ {
+ "index": 281,
+ "pair_id": "F_origin_49_F_table_147_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_49/F_table_147_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_49",
+ "table_id": "F_table_147_0"
+ },
+ {
+ "index": 282,
+ "pair_id": "F_origin_49_F_table_147_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_49/F_table_147_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_49",
+ "table_id": "F_table_147_1"
+ },
+ {
+ "index": 283,
+ "pair_id": "F_origin_49_F_table_147_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_49/F_table_147_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_49",
+ "table_id": "F_table_147_2"
+ },
+ {
+ "index": 284,
+ "pair_id": "F_origin_49_F_table_148_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_49/F_table_148_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_49",
+ "table_id": "F_table_148_0"
+ },
+ {
+ "index": 285,
+ "pair_id": "F_origin_49_F_table_148_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_49/F_table_148_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_49",
+ "table_id": "F_table_148_1"
+ },
+ {
+ "index": 286,
+ "pair_id": "F_origin_5_F_table_7_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_5/F_table_7_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_5",
+ "table_id": "F_table_7_0"
+ },
+ {
+ "index": 287,
+ "pair_id": "F_origin_5_F_table_7_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_5/F_table_7_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_5",
+ "table_id": "F_table_7_1"
+ },
+ {
+ "index": 288,
+ "pair_id": "F_origin_5_F_table_7_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_5/F_table_7_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_5",
+ "table_id": "F_table_7_2"
+ },
+ {
+ "index": 289,
+ "pair_id": "F_origin_5_F_table_7_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_5/F_table_7_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_5",
+ "table_id": "F_table_7_3"
+ },
+ {
+ "index": 290,
+ "pair_id": "F_origin_5_F_table_7_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_5/F_table_7_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_5",
+ "table_id": "F_table_7_4"
+ },
+ {
+ "index": 291,
+ "pair_id": "F_origin_6_F_table_8_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_6/F_table_8_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_6",
+ "table_id": "F_table_8_0"
+ },
+ {
+ "index": 292,
+ "pair_id": "F_origin_6_F_table_8_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_6/F_table_8_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_6",
+ "table_id": "F_table_8_1"
+ },
+ {
+ "index": 293,
+ "pair_id": "F_origin_6_F_table_8_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_6/F_table_8_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_6",
+ "table_id": "F_table_8_2"
+ },
+ {
+ "index": 294,
+ "pair_id": "F_origin_6_F_table_8_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_6/F_table_8_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_6",
+ "table_id": "F_table_8_3"
+ },
+ {
+ "index": 295,
+ "pair_id": "F_origin_6_F_table_8_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_6/F_table_8_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_6",
+ "table_id": "F_table_8_4"
+ },
+ {
+ "index": 296,
+ "pair_id": "F_origin_6_F_table_9_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_6/F_table_9_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_6",
+ "table_id": "F_table_9_0"
+ },
+ {
+ "index": 297,
+ "pair_id": "F_origin_6_F_table_9_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_6/F_table_9_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_6",
+ "table_id": "F_table_9_1"
+ },
+ {
+ "index": 298,
+ "pair_id": "F_origin_7_F_table_10_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_7/F_table_10_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_7",
+ "table_id": "F_table_10_0"
+ },
+ {
+ "index": 299,
+ "pair_id": "F_origin_7_F_table_10_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_7/F_table_10_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_7",
+ "table_id": "F_table_10_1"
+ },
+ {
+ "index": 300,
+ "pair_id": "F_origin_7_F_table_10_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_7/F_table_10_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_7",
+ "table_id": "F_table_10_2"
+ },
+ {
+ "index": 301,
+ "pair_id": "F_origin_7_F_table_10_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_7/F_table_10_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_7",
+ "table_id": "F_table_10_3"
+ },
+ {
+ "index": 302,
+ "pair_id": "F_origin_7_F_table_10_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_7/F_table_10_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_7",
+ "table_id": "F_table_10_4"
+ },
+ {
+ "index": 303,
+ "pair_id": "F_origin_7_F_table_11_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_7/F_table_11_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_7",
+ "table_id": "F_table_11_0"
+ },
+ {
+ "index": 304,
+ "pair_id": "F_origin_7_F_table_11_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_7/F_table_11_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_7",
+ "table_id": "F_table_11_1"
+ },
+ {
+ "index": 305,
+ "pair_id": "F_origin_8_F_table_12_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_8/F_table_12_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_8",
+ "table_id": "F_table_12_0"
+ },
+ {
+ "index": 306,
+ "pair_id": "F_origin_8_F_table_12_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_8/F_table_12_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_8",
+ "table_id": "F_table_12_1"
+ },
+ {
+ "index": 307,
+ "pair_id": "F_origin_8_F_table_12_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_8/F_table_12_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_8",
+ "table_id": "F_table_12_2"
+ },
+ {
+ "index": 308,
+ "pair_id": "F_origin_8_F_table_12_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_8/F_table_12_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_8",
+ "table_id": "F_table_12_3"
+ },
+ {
+ "index": 309,
+ "pair_id": "F_origin_8_F_table_12_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_8/F_table_12_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_8",
+ "table_id": "F_table_12_4"
+ },
+ {
+ "index": 310,
+ "pair_id": "F_origin_9_F_table_13_0",
+ "image_paths": [
+ "data/Finance/Table/F_origin_9/F_table_13_0.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_9",
+ "table_id": "F_table_13_0"
+ },
+ {
+ "index": 311,
+ "pair_id": "F_origin_9_F_table_13_1",
+ "image_paths": [
+ "data/Finance/Table/F_origin_9/F_table_13_1.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_9",
+ "table_id": "F_table_13_1"
+ },
+ {
+ "index": 312,
+ "pair_id": "F_origin_9_F_table_13_2",
+ "image_paths": [
+ "data/Finance/Table/F_origin_9/F_table_13_2.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_9",
+ "table_id": "F_table_13_2"
+ },
+ {
+ "index": 313,
+ "pair_id": "F_origin_9_F_table_13_3",
+ "image_paths": [
+ "data/Finance/Table/F_origin_9/F_table_13_3.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_9",
+ "table_id": "F_table_13_3"
+ },
+ {
+ "index": 314,
+ "pair_id": "F_origin_9_F_table_13_4",
+ "image_paths": [
+ "data/Finance/Table/F_origin_9/F_table_13_4.png"
+ ],
+ "domain": "Finance",
+ "origin": "F_origin_9",
+ "table_id": "F_table_13_4"
+ }
+]
\ No newline at end of file
diff --git a/single_image_json_list/single_table_insurance_input.json b/single_image_json_list/single_table_insurance_input.json
new file mode 100644
index 0000000..73dc561
--- /dev/null
+++ b/single_image_json_list/single_table_insurance_input.json
@@ -0,0 +1,1572 @@
+[
+ {
+ "index": 0,
+ "pair_id": "I_origin_0_I_table_0",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_0.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_0"
+ },
+ {
+ "index": 1,
+ "pair_id": "I_origin_0_I_table_1",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_1.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_1"
+ },
+ {
+ "index": 2,
+ "pair_id": "I_origin_0_I_table_10",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_10.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_10"
+ },
+ {
+ "index": 3,
+ "pair_id": "I_origin_0_I_table_11",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_11.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_11"
+ },
+ {
+ "index": 4,
+ "pair_id": "I_origin_0_I_table_12_0",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_12_0.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_12_0"
+ },
+ {
+ "index": 5,
+ "pair_id": "I_origin_0_I_table_12_1",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_12_1.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_12_1"
+ },
+ {
+ "index": 6,
+ "pair_id": "I_origin_0_I_table_13",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_13.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_13"
+ },
+ {
+ "index": 7,
+ "pair_id": "I_origin_0_I_table_14",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_14.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_14"
+ },
+ {
+ "index": 8,
+ "pair_id": "I_origin_0_I_table_15",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_15.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_15"
+ },
+ {
+ "index": 9,
+ "pair_id": "I_origin_0_I_table_16",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_16.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_16"
+ },
+ {
+ "index": 10,
+ "pair_id": "I_origin_0_I_table_17",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_17.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_17"
+ },
+ {
+ "index": 11,
+ "pair_id": "I_origin_0_I_table_18",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_18.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_18"
+ },
+ {
+ "index": 12,
+ "pair_id": "I_origin_0_I_table_19_0",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_0.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_0"
+ },
+ {
+ "index": 13,
+ "pair_id": "I_origin_0_I_table_19_1",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_1.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_1"
+ },
+ {
+ "index": 14,
+ "pair_id": "I_origin_0_I_table_19_10",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_10.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_10"
+ },
+ {
+ "index": 15,
+ "pair_id": "I_origin_0_I_table_19_11",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_11.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_11"
+ },
+ {
+ "index": 16,
+ "pair_id": "I_origin_0_I_table_19_12",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_12.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_12"
+ },
+ {
+ "index": 17,
+ "pair_id": "I_origin_0_I_table_19_13",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_13.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_13"
+ },
+ {
+ "index": 18,
+ "pair_id": "I_origin_0_I_table_19_14",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_14.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_14"
+ },
+ {
+ "index": 19,
+ "pair_id": "I_origin_0_I_table_19_15",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_15.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_15"
+ },
+ {
+ "index": 20,
+ "pair_id": "I_origin_0_I_table_19_16",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_16.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_16"
+ },
+ {
+ "index": 21,
+ "pair_id": "I_origin_0_I_table_19_17",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_17.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_17"
+ },
+ {
+ "index": 22,
+ "pair_id": "I_origin_0_I_table_19_18",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_18.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_18"
+ },
+ {
+ "index": 23,
+ "pair_id": "I_origin_0_I_table_19_19",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_19.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_19"
+ },
+ {
+ "index": 24,
+ "pair_id": "I_origin_0_I_table_19_2",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_2.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_2"
+ },
+ {
+ "index": 25,
+ "pair_id": "I_origin_0_I_table_19_20",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_20.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_20"
+ },
+ {
+ "index": 26,
+ "pair_id": "I_origin_0_I_table_19_21",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_21.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_21"
+ },
+ {
+ "index": 27,
+ "pair_id": "I_origin_0_I_table_19_3",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_3.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_3"
+ },
+ {
+ "index": 28,
+ "pair_id": "I_origin_0_I_table_19_4",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_4.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_4"
+ },
+ {
+ "index": 29,
+ "pair_id": "I_origin_0_I_table_19_5",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_5.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_5"
+ },
+ {
+ "index": 30,
+ "pair_id": "I_origin_0_I_table_19_6",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_6.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_6"
+ },
+ {
+ "index": 31,
+ "pair_id": "I_origin_0_I_table_19_7",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_7.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_7"
+ },
+ {
+ "index": 32,
+ "pair_id": "I_origin_0_I_table_19_8",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_8.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_8"
+ },
+ {
+ "index": 33,
+ "pair_id": "I_origin_0_I_table_19_9",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_19_9.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_19_9"
+ },
+ {
+ "index": 34,
+ "pair_id": "I_origin_0_I_table_2",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_2.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_2"
+ },
+ {
+ "index": 35,
+ "pair_id": "I_origin_0_I_table_20_0",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_20_0.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_20_0"
+ },
+ {
+ "index": 36,
+ "pair_id": "I_origin_0_I_table_20_1",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_20_1.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_20_1"
+ },
+ {
+ "index": 37,
+ "pair_id": "I_origin_0_I_table_20_2",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_20_2.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_20_2"
+ },
+ {
+ "index": 38,
+ "pair_id": "I_origin_0_I_table_20_3",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_20_3.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_20_3"
+ },
+ {
+ "index": 39,
+ "pair_id": "I_origin_0_I_table_20_4",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_20_4.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_20_4"
+ },
+ {
+ "index": 40,
+ "pair_id": "I_origin_0_I_table_20_5",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_20_5.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_20_5"
+ },
+ {
+ "index": 41,
+ "pair_id": "I_origin_0_I_table_20_6",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_20_6.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_20_6"
+ },
+ {
+ "index": 42,
+ "pair_id": "I_origin_0_I_table_20_7",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_20_7.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_20_7"
+ },
+ {
+ "index": 43,
+ "pair_id": "I_origin_0_I_table_20_8",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_20_8.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_20_8"
+ },
+ {
+ "index": 44,
+ "pair_id": "I_origin_0_I_table_20_9",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_20_9.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_20_9"
+ },
+ {
+ "index": 45,
+ "pair_id": "I_origin_0_I_table_21",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_21.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_21"
+ },
+ {
+ "index": 46,
+ "pair_id": "I_origin_0_I_table_22",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_22.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_22"
+ },
+ {
+ "index": 47,
+ "pair_id": "I_origin_0_I_table_23",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_23.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_23"
+ },
+ {
+ "index": 48,
+ "pair_id": "I_origin_0_I_table_24",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_24.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_24"
+ },
+ {
+ "index": 49,
+ "pair_id": "I_origin_0_I_table_25",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_25.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_25"
+ },
+ {
+ "index": 50,
+ "pair_id": "I_origin_0_I_table_26",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_26.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_26"
+ },
+ {
+ "index": 51,
+ "pair_id": "I_origin_0_I_table_27",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_27.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_27"
+ },
+ {
+ "index": 52,
+ "pair_id": "I_origin_0_I_table_28",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_28.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_28"
+ },
+ {
+ "index": 53,
+ "pair_id": "I_origin_0_I_table_29",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_29.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_29"
+ },
+ {
+ "index": 54,
+ "pair_id": "I_origin_0_I_table_3",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_3.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_3"
+ },
+ {
+ "index": 55,
+ "pair_id": "I_origin_0_I_table_30",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_30.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_30"
+ },
+ {
+ "index": 56,
+ "pair_id": "I_origin_0_I_table_31",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_31.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_31"
+ },
+ {
+ "index": 57,
+ "pair_id": "I_origin_0_I_table_32",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_32.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_32"
+ },
+ {
+ "index": 58,
+ "pair_id": "I_origin_0_I_table_33",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_33.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_33"
+ },
+ {
+ "index": 59,
+ "pair_id": "I_origin_0_I_table_34",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_34.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_34"
+ },
+ {
+ "index": 60,
+ "pair_id": "I_origin_0_I_table_35",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_35.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_35"
+ },
+ {
+ "index": 61,
+ "pair_id": "I_origin_0_I_table_36",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_36.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_36"
+ },
+ {
+ "index": 62,
+ "pair_id": "I_origin_0_I_table_37",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_37.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_37"
+ },
+ {
+ "index": 63,
+ "pair_id": "I_origin_0_I_table_38",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_38.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_38"
+ },
+ {
+ "index": 64,
+ "pair_id": "I_origin_0_I_table_39",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_39.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_39"
+ },
+ {
+ "index": 65,
+ "pair_id": "I_origin_0_I_table_4",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_4.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_4"
+ },
+ {
+ "index": 66,
+ "pair_id": "I_origin_0_I_table_40_0",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_40_0.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_40_0"
+ },
+ {
+ "index": 67,
+ "pair_id": "I_origin_0_I_table_40_1",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_40_1.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_40_1"
+ },
+ {
+ "index": 68,
+ "pair_id": "I_origin_0_I_table_41",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_41.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_41"
+ },
+ {
+ "index": 69,
+ "pair_id": "I_origin_0_I_table_42",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_42.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_42"
+ },
+ {
+ "index": 70,
+ "pair_id": "I_origin_0_I_table_43",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_43.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_43"
+ },
+ {
+ "index": 71,
+ "pair_id": "I_origin_0_I_table_44",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_44.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_44"
+ },
+ {
+ "index": 72,
+ "pair_id": "I_origin_0_I_table_45",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_45.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_45"
+ },
+ {
+ "index": 73,
+ "pair_id": "I_origin_0_I_table_46",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_46.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_46"
+ },
+ {
+ "index": 74,
+ "pair_id": "I_origin_0_I_table_47",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_47.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_47"
+ },
+ {
+ "index": 75,
+ "pair_id": "I_origin_0_I_table_48",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_48.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_48"
+ },
+ {
+ "index": 76,
+ "pair_id": "I_origin_0_I_table_49",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_49.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_49"
+ },
+ {
+ "index": 77,
+ "pair_id": "I_origin_0_I_table_5",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_5.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_5"
+ },
+ {
+ "index": 78,
+ "pair_id": "I_origin_0_I_table_50",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_50.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_50"
+ },
+ {
+ "index": 79,
+ "pair_id": "I_origin_0_I_table_51",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_51.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_51"
+ },
+ {
+ "index": 80,
+ "pair_id": "I_origin_0_I_table_52",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_52.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_52"
+ },
+ {
+ "index": 81,
+ "pair_id": "I_origin_0_I_table_53",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_53.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_53"
+ },
+ {
+ "index": 82,
+ "pair_id": "I_origin_0_I_table_54",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_54.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_54"
+ },
+ {
+ "index": 83,
+ "pair_id": "I_origin_0_I_table_55",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_55.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_55"
+ },
+ {
+ "index": 84,
+ "pair_id": "I_origin_0_I_table_56",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_56.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_56"
+ },
+ {
+ "index": 85,
+ "pair_id": "I_origin_0_I_table_57",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_57.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_57"
+ },
+ {
+ "index": 86,
+ "pair_id": "I_origin_0_I_table_58",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_58.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_58"
+ },
+ {
+ "index": 87,
+ "pair_id": "I_origin_0_I_table_59",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_59.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_59"
+ },
+ {
+ "index": 88,
+ "pair_id": "I_origin_0_I_table_6",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_6.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_6"
+ },
+ {
+ "index": 89,
+ "pair_id": "I_origin_0_I_table_60",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_60.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_60"
+ },
+ {
+ "index": 90,
+ "pair_id": "I_origin_0_I_table_61",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_61.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_61"
+ },
+ {
+ "index": 91,
+ "pair_id": "I_origin_0_I_table_62",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_62.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_62"
+ },
+ {
+ "index": 92,
+ "pair_id": "I_origin_0_I_table_63",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_63.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_63"
+ },
+ {
+ "index": 93,
+ "pair_id": "I_origin_0_I_table_64_0",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_0.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_0"
+ },
+ {
+ "index": 94,
+ "pair_id": "I_origin_0_I_table_64_1",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_1.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_1"
+ },
+ {
+ "index": 95,
+ "pair_id": "I_origin_0_I_table_64_10",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_10.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_10"
+ },
+ {
+ "index": 96,
+ "pair_id": "I_origin_0_I_table_64_11",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_11.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_11"
+ },
+ {
+ "index": 97,
+ "pair_id": "I_origin_0_I_table_64_12",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_12.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_12"
+ },
+ {
+ "index": 98,
+ "pair_id": "I_origin_0_I_table_64_13",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_13.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_13"
+ },
+ {
+ "index": 99,
+ "pair_id": "I_origin_0_I_table_64_14",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_14.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_14"
+ },
+ {
+ "index": 100,
+ "pair_id": "I_origin_0_I_table_64_15",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_15.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_15"
+ },
+ {
+ "index": 101,
+ "pair_id": "I_origin_0_I_table_64_16",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_16.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_16"
+ },
+ {
+ "index": 102,
+ "pair_id": "I_origin_0_I_table_64_17",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_17.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_17"
+ },
+ {
+ "index": 103,
+ "pair_id": "I_origin_0_I_table_64_18",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_18.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_18"
+ },
+ {
+ "index": 104,
+ "pair_id": "I_origin_0_I_table_64_19",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_19.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_19"
+ },
+ {
+ "index": 105,
+ "pair_id": "I_origin_0_I_table_64_2",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_2.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_2"
+ },
+ {
+ "index": 106,
+ "pair_id": "I_origin_0_I_table_64_20",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_20.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_20"
+ },
+ {
+ "index": 107,
+ "pair_id": "I_origin_0_I_table_64_21",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_21.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_21"
+ },
+ {
+ "index": 108,
+ "pair_id": "I_origin_0_I_table_64_22",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_22.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_22"
+ },
+ {
+ "index": 109,
+ "pair_id": "I_origin_0_I_table_64_23",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_23.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_23"
+ },
+ {
+ "index": 110,
+ "pair_id": "I_origin_0_I_table_64_24",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_24.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_24"
+ },
+ {
+ "index": 111,
+ "pair_id": "I_origin_0_I_table_64_25",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_25.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_25"
+ },
+ {
+ "index": 112,
+ "pair_id": "I_origin_0_I_table_64_26",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_26.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_26"
+ },
+ {
+ "index": 113,
+ "pair_id": "I_origin_0_I_table_64_27",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_27.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_27"
+ },
+ {
+ "index": 114,
+ "pair_id": "I_origin_0_I_table_64_3",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_3.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_3"
+ },
+ {
+ "index": 115,
+ "pair_id": "I_origin_0_I_table_64_4",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_4.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_4"
+ },
+ {
+ "index": 116,
+ "pair_id": "I_origin_0_I_table_64_5",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_5.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_5"
+ },
+ {
+ "index": 117,
+ "pair_id": "I_origin_0_I_table_64_6",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_6.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_6"
+ },
+ {
+ "index": 118,
+ "pair_id": "I_origin_0_I_table_64_7",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_7.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_7"
+ },
+ {
+ "index": 119,
+ "pair_id": "I_origin_0_I_table_64_8",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_8.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_8"
+ },
+ {
+ "index": 120,
+ "pair_id": "I_origin_0_I_table_64_9",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_64_9.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_64_9"
+ },
+ {
+ "index": 121,
+ "pair_id": "I_origin_0_I_table_65_0",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_65_0.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_65_0"
+ },
+ {
+ "index": 122,
+ "pair_id": "I_origin_0_I_table_65_1",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_65_1.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_65_1"
+ },
+ {
+ "index": 123,
+ "pair_id": "I_origin_0_I_table_65_2",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_65_2.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_65_2"
+ },
+ {
+ "index": 124,
+ "pair_id": "I_origin_0_I_table_66",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_66.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_66"
+ },
+ {
+ "index": 125,
+ "pair_id": "I_origin_0_I_table_67",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_67.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_67"
+ },
+ {
+ "index": 126,
+ "pair_id": "I_origin_0_I_table_68",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_68.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_68"
+ },
+ {
+ "index": 127,
+ "pair_id": "I_origin_0_I_table_69",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_69.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_69"
+ },
+ {
+ "index": 128,
+ "pair_id": "I_origin_0_I_table_7",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_7.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_7"
+ },
+ {
+ "index": 129,
+ "pair_id": "I_origin_0_I_table_70",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_70.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_70"
+ },
+ {
+ "index": 130,
+ "pair_id": "I_origin_0_I_table_71",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_71.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_71"
+ },
+ {
+ "index": 131,
+ "pair_id": "I_origin_0_I_table_72",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_72.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_72"
+ },
+ {
+ "index": 132,
+ "pair_id": "I_origin_0_I_table_73",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_73.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_73"
+ },
+ {
+ "index": 133,
+ "pair_id": "I_origin_0_I_table_74",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_74.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_74"
+ },
+ {
+ "index": 134,
+ "pair_id": "I_origin_0_I_table_75",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_75.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_75"
+ },
+ {
+ "index": 135,
+ "pair_id": "I_origin_0_I_table_76",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_76.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_76"
+ },
+ {
+ "index": 136,
+ "pair_id": "I_origin_0_I_table_77",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_77.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_77"
+ },
+ {
+ "index": 137,
+ "pair_id": "I_origin_0_I_table_8",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_8.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_8"
+ },
+ {
+ "index": 138,
+ "pair_id": "I_origin_0_I_table_9",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_0/I_table_9.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_0",
+ "table_id": "I_table_9"
+ },
+ {
+ "index": 139,
+ "pair_id": "I_origin_1_I_table_78",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_1/I_table_78.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_1",
+ "table_id": "I_table_78"
+ },
+ {
+ "index": 140,
+ "pair_id": "I_origin_2_I_table_79",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_79.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_79"
+ },
+ {
+ "index": 141,
+ "pair_id": "I_origin_2_I_table_80",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_80.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_80"
+ },
+ {
+ "index": 142,
+ "pair_id": "I_origin_2_I_table_81",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_81.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_81"
+ },
+ {
+ "index": 143,
+ "pair_id": "I_origin_2_I_table_82",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_82.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_82"
+ },
+ {
+ "index": 144,
+ "pair_id": "I_origin_2_I_table_83",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_83.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_83"
+ },
+ {
+ "index": 145,
+ "pair_id": "I_origin_2_I_table_84",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_84.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_84"
+ },
+ {
+ "index": 146,
+ "pair_id": "I_origin_2_I_table_85",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_85.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_85"
+ },
+ {
+ "index": 147,
+ "pair_id": "I_origin_2_I_table_86",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_86.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_86"
+ },
+ {
+ "index": 148,
+ "pair_id": "I_origin_2_I_table_87",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_87.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_87"
+ },
+ {
+ "index": 149,
+ "pair_id": "I_origin_2_I_table_88",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_88.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_88"
+ },
+ {
+ "index": 150,
+ "pair_id": "I_origin_2_I_table_89",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_89.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_89"
+ },
+ {
+ "index": 151,
+ "pair_id": "I_origin_2_I_table_90",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_90.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_90"
+ },
+ {
+ "index": 152,
+ "pair_id": "I_origin_2_I_table_91",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_91.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_91"
+ },
+ {
+ "index": 153,
+ "pair_id": "I_origin_2_I_table_92",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_92.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_92"
+ },
+ {
+ "index": 154,
+ "pair_id": "I_origin_2_I_table_93",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_93.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_93"
+ },
+ {
+ "index": 155,
+ "pair_id": "I_origin_2_I_table_94",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_94.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_94"
+ },
+ {
+ "index": 156,
+ "pair_id": "I_origin_2_I_table_95",
+ "image_paths": [
+ "data/Insurance/Table/I_origin_2/I_table_95.png"
+ ],
+ "domain": "Insurance",
+ "origin": "I_origin_2",
+ "table_id": "I_table_95"
+ }
+]
\ No newline at end of file
diff --git a/single_image_json_list/single_table_medical_input.json b/single_image_json_list/single_table_medical_input.json
new file mode 100644
index 0000000..3978487
--- /dev/null
+++ b/single_image_json_list/single_table_medical_input.json
@@ -0,0 +1,1292 @@
+[
+ {
+ "index": 0,
+ "pair_id": "Medical_M_table_0_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_0_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_0_0_0"
+ },
+ {
+ "index": 1,
+ "pair_id": "Medical_M_table_0_1_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_0_1_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_0_1_0"
+ },
+ {
+ "index": 2,
+ "pair_id": "Medical_M_table_10_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_0_0"
+ },
+ {
+ "index": 3,
+ "pair_id": "Medical_M_table_10_0_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_0_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_0_1"
+ },
+ {
+ "index": 4,
+ "pair_id": "Medical_M_table_10_0_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_0_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_0_2"
+ },
+ {
+ "index": 5,
+ "pair_id": "Medical_M_table_10_1_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_1_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_1_0"
+ },
+ {
+ "index": 6,
+ "pair_id": "Medical_M_table_10_1_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_1_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_1_1"
+ },
+ {
+ "index": 7,
+ "pair_id": "Medical_M_table_10_1_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_1_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_1_2"
+ },
+ {
+ "index": 8,
+ "pair_id": "Medical_M_table_10_1_3",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_1_3.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_1_3"
+ },
+ {
+ "index": 9,
+ "pair_id": "Medical_M_table_10_2_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_2_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_2_0"
+ },
+ {
+ "index": 10,
+ "pair_id": "Medical_M_table_10_2_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_2_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_2_1"
+ },
+ {
+ "index": 11,
+ "pair_id": "Medical_M_table_10_2_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_2_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_2_2"
+ },
+ {
+ "index": 12,
+ "pair_id": "Medical_M_table_10_2_3",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_2_3.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_2_3"
+ },
+ {
+ "index": 13,
+ "pair_id": "Medical_M_table_10_2_4",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_2_4.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_2_4"
+ },
+ {
+ "index": 14,
+ "pair_id": "Medical_M_table_10_2_5",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_2_5.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_2_5"
+ },
+ {
+ "index": 15,
+ "pair_id": "Medical_M_table_10_3_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_3_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_3_0"
+ },
+ {
+ "index": 16,
+ "pair_id": "Medical_M_table_10_3_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_3_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_3_1"
+ },
+ {
+ "index": 17,
+ "pair_id": "Medical_M_table_10_3_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_3_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_3_2"
+ },
+ {
+ "index": 18,
+ "pair_id": "Medical_M_table_10_3_3",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_3_3.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_3_3"
+ },
+ {
+ "index": 19,
+ "pair_id": "Medical_M_table_10_3_4",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_3_4.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_3_4"
+ },
+ {
+ "index": 20,
+ "pair_id": "Medical_M_table_10_4_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_4_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_4_0"
+ },
+ {
+ "index": 21,
+ "pair_id": "Medical_M_table_10_4_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_4_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_4_1"
+ },
+ {
+ "index": 22,
+ "pair_id": "Medical_M_table_10_4_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_4_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_4_2"
+ },
+ {
+ "index": 23,
+ "pair_id": "Medical_M_table_10_4_3",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_4_3.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_4_3"
+ },
+ {
+ "index": 24,
+ "pair_id": "Medical_M_table_10_4_4",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_4_4.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_4_4"
+ },
+ {
+ "index": 25,
+ "pair_id": "Medical_M_table_10_5_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_10_5_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_10_5_0"
+ },
+ {
+ "index": 26,
+ "pair_id": "Medical_M_table_11_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_11_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_11_0_0"
+ },
+ {
+ "index": 27,
+ "pair_id": "Medical_M_table_11_0_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_11_0_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_11_0_1"
+ },
+ {
+ "index": 28,
+ "pair_id": "Medical_M_table_11_0_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_11_0_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_11_0_2"
+ },
+ {
+ "index": 29,
+ "pair_id": "Medical_M_table_11_0_3",
+ "image_paths": [
+ "data/Medical/Table/M_table_11_0_3.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_11_0_3"
+ },
+ {
+ "index": 30,
+ "pair_id": "Medical_M_table_11_0_4",
+ "image_paths": [
+ "data/Medical/Table/M_table_11_0_4.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_11_0_4"
+ },
+ {
+ "index": 31,
+ "pair_id": "Medical_M_table_12_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_12_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_12_0_0"
+ },
+ {
+ "index": 32,
+ "pair_id": "Medical_M_table_13_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_13_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_13_0_0"
+ },
+ {
+ "index": 33,
+ "pair_id": "Medical_M_table_13_0_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_13_0_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_13_0_1"
+ },
+ {
+ "index": 34,
+ "pair_id": "Medical_M_table_13_0_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_13_0_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_13_0_2"
+ },
+ {
+ "index": 35,
+ "pair_id": "Medical_M_table_13_0_3",
+ "image_paths": [
+ "data/Medical/Table/M_table_13_0_3.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_13_0_3"
+ },
+ {
+ "index": 36,
+ "pair_id": "Medical_M_table_13_1_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_13_1_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_13_1_0"
+ },
+ {
+ "index": 37,
+ "pair_id": "Medical_M_table_13_1_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_13_1_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_13_1_1"
+ },
+ {
+ "index": 38,
+ "pair_id": "Medical_M_table_13_1_10",
+ "image_paths": [
+ "data/Medical/Table/M_table_13_1_10.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_13_1_10"
+ },
+ {
+ "index": 39,
+ "pair_id": "Medical_M_table_13_1_11",
+ "image_paths": [
+ "data/Medical/Table/M_table_13_1_11.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_13_1_11"
+ },
+ {
+ "index": 40,
+ "pair_id": "Medical_M_table_13_1_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_13_1_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_13_1_2"
+ },
+ {
+ "index": 41,
+ "pair_id": "Medical_M_table_13_1_6",
+ "image_paths": [
+ "data/Medical/Table/M_table_13_1_6.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_13_1_6"
+ },
+ {
+ "index": 42,
+ "pair_id": "Medical_M_table_13_1_8",
+ "image_paths": [
+ "data/Medical/Table/M_table_13_1_8.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_13_1_8"
+ },
+ {
+ "index": 43,
+ "pair_id": "Medical_M_table_13_2_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_13_2_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_13_2_0"
+ },
+ {
+ "index": 44,
+ "pair_id": "Medical_M_table_13_2_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_13_2_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_13_2_1"
+ },
+ {
+ "index": 45,
+ "pair_id": "Medical_M_table_14_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_14_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_14_0_0"
+ },
+ {
+ "index": 46,
+ "pair_id": "Medical_M_table_14_0_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_14_0_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_14_0_1"
+ },
+ {
+ "index": 47,
+ "pair_id": "Medical_M_table_14_1_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_14_1_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_14_1_0"
+ },
+ {
+ "index": 48,
+ "pair_id": "Medical_M_table_14_2_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_14_2_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_14_2_0"
+ },
+ {
+ "index": 49,
+ "pair_id": "Medical_M_table_14_3_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_14_3_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_14_3_0"
+ },
+ {
+ "index": 50,
+ "pair_id": "Medical_M_table_14_3_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_14_3_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_14_3_1"
+ },
+ {
+ "index": 51,
+ "pair_id": "Medical_M_table_14_3_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_14_3_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_14_3_2"
+ },
+ {
+ "index": 52,
+ "pair_id": "Medical_M_table_14_3_3",
+ "image_paths": [
+ "data/Medical/Table/M_table_14_3_3.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_14_3_3"
+ },
+ {
+ "index": 53,
+ "pair_id": "Medical_M_table_14_3_4",
+ "image_paths": [
+ "data/Medical/Table/M_table_14_3_4.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_14_3_4"
+ },
+ {
+ "index": 54,
+ "pair_id": "Medical_M_table_15_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_0_0"
+ },
+ {
+ "index": 55,
+ "pair_id": "Medical_M_table_15_0_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_0_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_0_1"
+ },
+ {
+ "index": 56,
+ "pair_id": "Medical_M_table_15_0_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_0_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_0_2"
+ },
+ {
+ "index": 57,
+ "pair_id": "Medical_M_table_15_10_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_10_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_10_0"
+ },
+ {
+ "index": 58,
+ "pair_id": "Medical_M_table_15_10_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_10_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_10_1"
+ },
+ {
+ "index": 59,
+ "pair_id": "Medical_M_table_15_11_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_11_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_11_0"
+ },
+ {
+ "index": 60,
+ "pair_id": "Medical_M_table_15_12_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_12_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_12_0"
+ },
+ {
+ "index": 61,
+ "pair_id": "Medical_M_table_15_13_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_13_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_13_0"
+ },
+ {
+ "index": 62,
+ "pair_id": "Medical_M_table_15_1_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_1_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_1_0"
+ },
+ {
+ "index": 63,
+ "pair_id": "Medical_M_table_15_2_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_2_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_2_0"
+ },
+ {
+ "index": 64,
+ "pair_id": "Medical_M_table_15_3_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_3_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_3_0"
+ },
+ {
+ "index": 65,
+ "pair_id": "Medical_M_table_15_4_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_4_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_4_0"
+ },
+ {
+ "index": 66,
+ "pair_id": "Medical_M_table_15_5_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_5_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_5_0"
+ },
+ {
+ "index": 67,
+ "pair_id": "Medical_M_table_15_5_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_5_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_5_1"
+ },
+ {
+ "index": 68,
+ "pair_id": "Medical_M_table_15_5_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_5_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_5_2"
+ },
+ {
+ "index": 69,
+ "pair_id": "Medical_M_table_15_6_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_6_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_6_0"
+ },
+ {
+ "index": 70,
+ "pair_id": "Medical_M_table_15_7_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_7_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_7_0"
+ },
+ {
+ "index": 71,
+ "pair_id": "Medical_M_table_15_8_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_8_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_8_0"
+ },
+ {
+ "index": 72,
+ "pair_id": "Medical_M_table_15_9_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_15_9_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_15_9_0"
+ },
+ {
+ "index": 73,
+ "pair_id": "Medical_M_table_16_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_16_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_16_0_0"
+ },
+ {
+ "index": 74,
+ "pair_id": "Medical_M_table_16_0_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_16_0_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_16_0_1"
+ },
+ {
+ "index": 75,
+ "pair_id": "Medical_M_table_16_1_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_16_1_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_16_1_0"
+ },
+ {
+ "index": 76,
+ "pair_id": "Medical_M_table_16_1_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_16_1_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_16_1_1"
+ },
+ {
+ "index": 77,
+ "pair_id": "Medical_M_table_1_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_1_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_1_0_0"
+ },
+ {
+ "index": 78,
+ "pair_id": "Medical_M_table_2_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_0_0"
+ },
+ {
+ "index": 79,
+ "pair_id": "Medical_M_table_2_1_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_1_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_1_0"
+ },
+ {
+ "index": 80,
+ "pair_id": "Medical_M_table_2_2_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_2_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_2_0"
+ },
+ {
+ "index": 81,
+ "pair_id": "Medical_M_table_2_2_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_2_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_2_1"
+ },
+ {
+ "index": 82,
+ "pair_id": "Medical_M_table_2_3_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_3_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_3_0"
+ },
+ {
+ "index": 83,
+ "pair_id": "Medical_M_table_2_3_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_3_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_3_1"
+ },
+ {
+ "index": 84,
+ "pair_id": "Medical_M_table_2_4_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_4_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_4_0"
+ },
+ {
+ "index": 85,
+ "pair_id": "Medical_M_table_2_4_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_4_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_4_1"
+ },
+ {
+ "index": 86,
+ "pair_id": "Medical_M_table_2_5_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_5_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_5_0"
+ },
+ {
+ "index": 87,
+ "pair_id": "Medical_M_table_2_6_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_6_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_6_0"
+ },
+ {
+ "index": 88,
+ "pair_id": "Medical_M_table_2_6_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_6_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_6_1"
+ },
+ {
+ "index": 89,
+ "pair_id": "Medical_M_table_2_6_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_6_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_6_2"
+ },
+ {
+ "index": 90,
+ "pair_id": "Medical_M_table_2_6_3",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_6_3.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_6_3"
+ },
+ {
+ "index": 91,
+ "pair_id": "Medical_M_table_2_6_4",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_6_4.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_6_4"
+ },
+ {
+ "index": 92,
+ "pair_id": "Medical_M_table_2_6_5",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_6_5.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_6_5"
+ },
+ {
+ "index": 93,
+ "pair_id": "Medical_M_table_2_6_6",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_6_6.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_6_6"
+ },
+ {
+ "index": 94,
+ "pair_id": "Medical_M_table_2_6_7",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_6_7.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_6_7"
+ },
+ {
+ "index": 95,
+ "pair_id": "Medical_M_table_2_7_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_2_7_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_2_7_0"
+ },
+ {
+ "index": 96,
+ "pair_id": "Medical_M_table_3_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_3_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_3_0_0"
+ },
+ {
+ "index": 97,
+ "pair_id": "Medical_M_table_3_0_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_3_0_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_3_0_1"
+ },
+ {
+ "index": 98,
+ "pair_id": "Medical_M_table_3_0_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_3_0_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_3_0_2"
+ },
+ {
+ "index": 99,
+ "pair_id": "Medical_M_table_3_1_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_3_1_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_3_1_0"
+ },
+ {
+ "index": 100,
+ "pair_id": "Medical_M_table_3_1_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_3_1_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_3_1_1"
+ },
+ {
+ "index": 101,
+ "pair_id": "Medical_M_table_3_2_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_3_2_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_3_2_0"
+ },
+ {
+ "index": 102,
+ "pair_id": "Medical_M_table_3_2_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_3_2_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_3_2_1"
+ },
+ {
+ "index": 103,
+ "pair_id": "Medical_M_table_3_3_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_3_3_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_3_3_0"
+ },
+ {
+ "index": 104,
+ "pair_id": "Medical_M_table_3_3_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_3_3_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_3_3_1"
+ },
+ {
+ "index": 105,
+ "pair_id": "Medical_M_table_4_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_4_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_4_0_0"
+ },
+ {
+ "index": 106,
+ "pair_id": "Medical_M_table_4_0_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_4_0_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_4_0_1"
+ },
+ {
+ "index": 107,
+ "pair_id": "Medical_M_table_4_1_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_4_1_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_4_1_0"
+ },
+ {
+ "index": 108,
+ "pair_id": "Medical_M_table_5_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_5_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_5_0_0"
+ },
+ {
+ "index": 109,
+ "pair_id": "Medical_M_table_6_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_6_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_6_0_0"
+ },
+ {
+ "index": 110,
+ "pair_id": "Medical_M_table_6_1_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_6_1_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_6_1_0"
+ },
+ {
+ "index": 111,
+ "pair_id": "Medical_M_table_6_2_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_6_2_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_6_2_0"
+ },
+ {
+ "index": 112,
+ "pair_id": "Medical_M_table_6_3_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_6_3_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_6_3_0"
+ },
+ {
+ "index": 113,
+ "pair_id": "Medical_M_table_6_3_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_6_3_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_6_3_1"
+ },
+ {
+ "index": 114,
+ "pair_id": "Medical_M_table_8_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_8_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_8_0_0"
+ },
+ {
+ "index": 115,
+ "pair_id": "Medical_M_table_8_0_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_8_0_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_8_0_1"
+ },
+ {
+ "index": 116,
+ "pair_id": "Medical_M_table_8_0_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_8_0_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_8_0_2"
+ },
+ {
+ "index": 117,
+ "pair_id": "Medical_M_table_8_1_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_8_1_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_8_1_0"
+ },
+ {
+ "index": 118,
+ "pair_id": "Medical_M_table_8_2_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_8_2_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_8_2_0"
+ },
+ {
+ "index": 119,
+ "pair_id": "Medical_M_table_8_3_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_8_3_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_8_3_0"
+ },
+ {
+ "index": 120,
+ "pair_id": "Medical_M_table_9_0_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_9_0_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_9_0_0"
+ },
+ {
+ "index": 121,
+ "pair_id": "Medical_M_table_9_0_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_9_0_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_9_0_1"
+ },
+ {
+ "index": 122,
+ "pair_id": "Medical_M_table_9_0_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_9_0_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_9_0_2"
+ },
+ {
+ "index": 123,
+ "pair_id": "Medical_M_table_9_1_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_9_1_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_9_1_0"
+ },
+ {
+ "index": 124,
+ "pair_id": "Medical_M_table_9_1_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_9_1_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_9_1_1"
+ },
+ {
+ "index": 125,
+ "pair_id": "Medical_M_table_9_1_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_9_1_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_9_1_2"
+ },
+ {
+ "index": 126,
+ "pair_id": "Medical_M_table_9_2_0",
+ "image_paths": [
+ "data/Medical/Table/M_table_9_2_0.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_9_2_0"
+ },
+ {
+ "index": 127,
+ "pair_id": "Medical_M_table_9_2_1",
+ "image_paths": [
+ "data/Medical/Table/M_table_9_2_1.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_9_2_1"
+ },
+ {
+ "index": 128,
+ "pair_id": "Medical_M_table_9_2_2",
+ "image_paths": [
+ "data/Medical/Table/M_table_9_2_2.png"
+ ],
+ "domain": "Medical",
+ "origin": "Medical",
+ "table_id": "M_table_9_2_2"
+ }
+]
\ No newline at end of file
diff --git a/single_image_json_list/single_table_public_input.json b/single_image_json_list/single_table_public_input.json
new file mode 100644
index 0000000..b7d33d5
--- /dev/null
+++ b/single_image_json_list/single_table_public_input.json
@@ -0,0 +1,2492 @@
+[
+ {
+ "index": 0,
+ "pair_id": "P_origin_0_P_origin_0_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_0/P_origin_0_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_0",
+ "table_id": "P_origin_0_0"
+ },
+ {
+ "index": 1,
+ "pair_id": "P_origin_0_P_origin_0_1_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_0/P_origin_0_1_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_0",
+ "table_id": "P_origin_0_1_0"
+ },
+ {
+ "index": 2,
+ "pair_id": "P_origin_0_P_origin_0_1_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_0/P_origin_0_1_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_0",
+ "table_id": "P_origin_0_1_1"
+ },
+ {
+ "index": 3,
+ "pair_id": "P_origin_0_P_origin_0_1_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_0/P_origin_0_1_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_0",
+ "table_id": "P_origin_0_1_2"
+ },
+ {
+ "index": 4,
+ "pair_id": "P_origin_0_P_origin_0_1_3",
+ "image_paths": [
+ "data/Public/Table/P_origin_0/P_origin_0_1_3.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_0",
+ "table_id": "P_origin_0_1_3"
+ },
+ {
+ "index": 5,
+ "pair_id": "P_origin_0_P_origin_0_1_4",
+ "image_paths": [
+ "data/Public/Table/P_origin_0/P_origin_0_1_4.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_0",
+ "table_id": "P_origin_0_1_4"
+ },
+ {
+ "index": 6,
+ "pair_id": "P_origin_0_P_origin_0_1_5",
+ "image_paths": [
+ "data/Public/Table/P_origin_0/P_origin_0_1_5.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_0",
+ "table_id": "P_origin_0_1_5"
+ },
+ {
+ "index": 7,
+ "pair_id": "P_origin_0_P_origin_0_1_6",
+ "image_paths": [
+ "data/Public/Table/P_origin_0/P_origin_0_1_6.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_0",
+ "table_id": "P_origin_0_1_6"
+ },
+ {
+ "index": 8,
+ "pair_id": "P_origin_0_P_origin_0_2_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_0/P_origin_0_2_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_0",
+ "table_id": "P_origin_0_2_0"
+ },
+ {
+ "index": 9,
+ "pair_id": "P_origin_0_P_origin_0_2_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_0/P_origin_0_2_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_0",
+ "table_id": "P_origin_0_2_1"
+ },
+ {
+ "index": 10,
+ "pair_id": "P_origin_0_P_origin_0_2_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_0/P_origin_0_2_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_0",
+ "table_id": "P_origin_0_2_2"
+ },
+ {
+ "index": 11,
+ "pair_id": "P_origin_1_P_origin_1_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_0"
+ },
+ {
+ "index": 12,
+ "pair_id": "P_origin_1_P_origin_1_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_1"
+ },
+ {
+ "index": 13,
+ "pair_id": "P_origin_1_P_origin_1_10",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_10.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_10"
+ },
+ {
+ "index": 14,
+ "pair_id": "P_origin_1_P_origin_1_11_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_11_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_11_0"
+ },
+ {
+ "index": 15,
+ "pair_id": "P_origin_1_P_origin_1_11_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_11_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_11_1"
+ },
+ {
+ "index": 16,
+ "pair_id": "P_origin_1_P_origin_1_11_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_11_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_11_2"
+ },
+ {
+ "index": 17,
+ "pair_id": "P_origin_1_P_origin_1_12_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_12_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_12_0"
+ },
+ {
+ "index": 18,
+ "pair_id": "P_origin_1_P_origin_1_12_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_12_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_12_1"
+ },
+ {
+ "index": 19,
+ "pair_id": "P_origin_1_P_origin_1_12_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_12_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_12_2"
+ },
+ {
+ "index": 20,
+ "pair_id": "P_origin_1_P_origin_1_13_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_13_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_13_0"
+ },
+ {
+ "index": 21,
+ "pair_id": "P_origin_1_P_origin_1_13_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_13_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_13_1"
+ },
+ {
+ "index": 22,
+ "pair_id": "P_origin_1_P_origin_1_13_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_13_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_13_2"
+ },
+ {
+ "index": 23,
+ "pair_id": "P_origin_1_P_origin_1_14_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_14_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_14_0"
+ },
+ {
+ "index": 24,
+ "pair_id": "P_origin_1_P_origin_1_14_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_14_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_14_1"
+ },
+ {
+ "index": 25,
+ "pair_id": "P_origin_1_P_origin_1_14_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_14_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_14_2"
+ },
+ {
+ "index": 26,
+ "pair_id": "P_origin_1_P_origin_1_15_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_15_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_15_0"
+ },
+ {
+ "index": 27,
+ "pair_id": "P_origin_1_P_origin_1_15_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_15_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_15_1"
+ },
+ {
+ "index": 28,
+ "pair_id": "P_origin_1_P_origin_1_15_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_15_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_15_2"
+ },
+ {
+ "index": 29,
+ "pair_id": "P_origin_1_P_origin_1_16_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_16_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_16_0"
+ },
+ {
+ "index": 30,
+ "pair_id": "P_origin_1_P_origin_1_16_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_16_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_16_1"
+ },
+ {
+ "index": 31,
+ "pair_id": "P_origin_1_P_origin_1_16_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_16_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_16_2"
+ },
+ {
+ "index": 32,
+ "pair_id": "P_origin_1_P_origin_1_17_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_17_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_17_0"
+ },
+ {
+ "index": 33,
+ "pair_id": "P_origin_1_P_origin_1_17_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_17_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_17_1"
+ },
+ {
+ "index": 34,
+ "pair_id": "P_origin_1_P_origin_1_17_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_17_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_17_2"
+ },
+ {
+ "index": 35,
+ "pair_id": "P_origin_1_P_origin_1_18_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_18_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_18_0"
+ },
+ {
+ "index": 36,
+ "pair_id": "P_origin_1_P_origin_1_18_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_18_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_18_1"
+ },
+ {
+ "index": 37,
+ "pair_id": "P_origin_1_P_origin_1_19_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_19_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_19_0"
+ },
+ {
+ "index": 38,
+ "pair_id": "P_origin_1_P_origin_1_19_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_19_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_19_1"
+ },
+ {
+ "index": 39,
+ "pair_id": "P_origin_1_P_origin_1_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_2"
+ },
+ {
+ "index": 40,
+ "pair_id": "P_origin_1_P_origin_1_20_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_20_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_20_0"
+ },
+ {
+ "index": 41,
+ "pair_id": "P_origin_1_P_origin_1_20_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_20_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_20_1"
+ },
+ {
+ "index": 42,
+ "pair_id": "P_origin_1_P_origin_1_20_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_20_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_20_2"
+ },
+ {
+ "index": 43,
+ "pair_id": "P_origin_1_P_origin_1_21_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_21_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_21_0"
+ },
+ {
+ "index": 44,
+ "pair_id": "P_origin_1_P_origin_1_21_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_21_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_21_1"
+ },
+ {
+ "index": 45,
+ "pair_id": "P_origin_1_P_origin_1_21_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_21_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_21_2"
+ },
+ {
+ "index": 46,
+ "pair_id": "P_origin_1_P_origin_1_22_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_22_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_22_0"
+ },
+ {
+ "index": 47,
+ "pair_id": "P_origin_1_P_origin_1_22_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_22_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_22_1"
+ },
+ {
+ "index": 48,
+ "pair_id": "P_origin_1_P_origin_1_22_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_22_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_22_2"
+ },
+ {
+ "index": 49,
+ "pair_id": "P_origin_1_P_origin_1_23_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_23_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_23_0"
+ },
+ {
+ "index": 50,
+ "pair_id": "P_origin_1_P_origin_1_23_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_23_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_23_1"
+ },
+ {
+ "index": 51,
+ "pair_id": "P_origin_1_P_origin_1_23_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_23_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_23_2"
+ },
+ {
+ "index": 52,
+ "pair_id": "P_origin_1_P_origin_1_24",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_24.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_24"
+ },
+ {
+ "index": 53,
+ "pair_id": "P_origin_1_P_origin_1_25",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_25.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_25"
+ },
+ {
+ "index": 54,
+ "pair_id": "P_origin_1_P_origin_1_26",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_26.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_26"
+ },
+ {
+ "index": 55,
+ "pair_id": "P_origin_1_P_origin_1_3",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_3.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_3"
+ },
+ {
+ "index": 56,
+ "pair_id": "P_origin_1_P_origin_1_4",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_4.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_4"
+ },
+ {
+ "index": 57,
+ "pair_id": "P_origin_1_P_origin_1_5",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_5.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_5"
+ },
+ {
+ "index": 58,
+ "pair_id": "P_origin_1_P_origin_1_6",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_6.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_6"
+ },
+ {
+ "index": 59,
+ "pair_id": "P_origin_1_P_origin_1_7",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_7.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_7"
+ },
+ {
+ "index": 60,
+ "pair_id": "P_origin_1_P_origin_1_8_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_8_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_8_0"
+ },
+ {
+ "index": 61,
+ "pair_id": "P_origin_1_P_origin_1_8_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_8_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_8_1"
+ },
+ {
+ "index": 62,
+ "pair_id": "P_origin_1_P_origin_1_8_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_8_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_8_2"
+ },
+ {
+ "index": 63,
+ "pair_id": "P_origin_1_P_origin_1_9_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_9_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_9_0"
+ },
+ {
+ "index": 64,
+ "pair_id": "P_origin_1_P_origin_1_9_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_1/P_origin_1_9_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_1",
+ "table_id": "P_origin_1_9_1"
+ },
+ {
+ "index": 65,
+ "pair_id": "P_origin_10_P_origin_10_0_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_10/P_origin_10_0_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_10",
+ "table_id": "P_origin_10_0_0"
+ },
+ {
+ "index": 66,
+ "pair_id": "P_origin_10_P_origin_10_0_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_10/P_origin_10_0_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_10",
+ "table_id": "P_origin_10_0_1"
+ },
+ {
+ "index": 67,
+ "pair_id": "P_origin_10_P_origin_10_0_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_10/P_origin_10_0_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_10",
+ "table_id": "P_origin_10_0_2"
+ },
+ {
+ "index": 68,
+ "pair_id": "P_origin_10_P_origin_10_0_3",
+ "image_paths": [
+ "data/Public/Table/P_origin_10/P_origin_10_0_3.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_10",
+ "table_id": "P_origin_10_0_3"
+ },
+ {
+ "index": 69,
+ "pair_id": "P_origin_10_P_origin_10_0_4",
+ "image_paths": [
+ "data/Public/Table/P_origin_10/P_origin_10_0_4.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_10",
+ "table_id": "P_origin_10_0_4"
+ },
+ {
+ "index": 70,
+ "pair_id": "P_origin_11_P_origin_11_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_0"
+ },
+ {
+ "index": 71,
+ "pair_id": "P_origin_11_P_origin_11_10",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_10.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_10"
+ },
+ {
+ "index": 72,
+ "pair_id": "P_origin_11_P_origin_11_11",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_11.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_11"
+ },
+ {
+ "index": 73,
+ "pair_id": "P_origin_11_P_origin_11_12",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_12.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_12"
+ },
+ {
+ "index": 74,
+ "pair_id": "P_origin_11_P_origin_11_13",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_13.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_13"
+ },
+ {
+ "index": 75,
+ "pair_id": "P_origin_11_P_origin_11_14",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_14.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_14"
+ },
+ {
+ "index": 76,
+ "pair_id": "P_origin_11_P_origin_11_15",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_15.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_15"
+ },
+ {
+ "index": 77,
+ "pair_id": "P_origin_11_P_origin_11_16",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_16.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_16"
+ },
+ {
+ "index": 78,
+ "pair_id": "P_origin_11_P_origin_11_17",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_17.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_17"
+ },
+ {
+ "index": 79,
+ "pair_id": "P_origin_11_P_origin_11_18",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_18.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_18"
+ },
+ {
+ "index": 80,
+ "pair_id": "P_origin_11_P_origin_11_19",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_19.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_19"
+ },
+ {
+ "index": 81,
+ "pair_id": "P_origin_11_P_origin_11_1_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_1_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_1_0"
+ },
+ {
+ "index": 82,
+ "pair_id": "P_origin_11_P_origin_11_1_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_1_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_1_1"
+ },
+ {
+ "index": 83,
+ "pair_id": "P_origin_11_P_origin_11_1_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_1_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_1_2"
+ },
+ {
+ "index": 84,
+ "pair_id": "P_origin_11_P_origin_11_20",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_20.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_20"
+ },
+ {
+ "index": 85,
+ "pair_id": "P_origin_11_P_origin_11_2_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_2_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_2_0"
+ },
+ {
+ "index": 86,
+ "pair_id": "P_origin_11_P_origin_11_2_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_2_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_2_1"
+ },
+ {
+ "index": 87,
+ "pair_id": "P_origin_11_P_origin_11_3",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_3.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_3"
+ },
+ {
+ "index": 88,
+ "pair_id": "P_origin_11_P_origin_11_4",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_4.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_4"
+ },
+ {
+ "index": 89,
+ "pair_id": "P_origin_11_P_origin_11_5",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_5.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_5"
+ },
+ {
+ "index": 90,
+ "pair_id": "P_origin_11_P_origin_11_6",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_6.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_6"
+ },
+ {
+ "index": 91,
+ "pair_id": "P_origin_11_P_origin_11_7",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_7.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_7"
+ },
+ {
+ "index": 92,
+ "pair_id": "P_origin_11_P_origin_11_8",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_8.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_8"
+ },
+ {
+ "index": 93,
+ "pair_id": "P_origin_11_P_origin_11_9",
+ "image_paths": [
+ "data/Public/Table/P_origin_11/P_origin_11_9.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_11",
+ "table_id": "P_origin_11_9"
+ },
+ {
+ "index": 94,
+ "pair_id": "P_origin_2_P_origin_2_0_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_2/P_origin_2_0_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_2",
+ "table_id": "P_origin_2_0_0"
+ },
+ {
+ "index": 95,
+ "pair_id": "P_origin_2_P_origin_2_0_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_2/P_origin_2_0_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_2",
+ "table_id": "P_origin_2_0_1"
+ },
+ {
+ "index": 96,
+ "pair_id": "P_origin_2_P_origin_2_0_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_2/P_origin_2_0_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_2",
+ "table_id": "P_origin_2_0_2"
+ },
+ {
+ "index": 97,
+ "pair_id": "P_origin_2_P_origin_2_0_3",
+ "image_paths": [
+ "data/Public/Table/P_origin_2/P_origin_2_0_3.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_2",
+ "table_id": "P_origin_2_0_3"
+ },
+ {
+ "index": 98,
+ "pair_id": "P_origin_2_P_origin_2_1_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_2/P_origin_2_1_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_2",
+ "table_id": "P_origin_2_1_0"
+ },
+ {
+ "index": 99,
+ "pair_id": "P_origin_2_P_origin_2_1_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_2/P_origin_2_1_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_2",
+ "table_id": "P_origin_2_1_1"
+ },
+ {
+ "index": 100,
+ "pair_id": "P_origin_2_P_origin_2_1_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_2/P_origin_2_1_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_2",
+ "table_id": "P_origin_2_1_2"
+ },
+ {
+ "index": 101,
+ "pair_id": "P_origin_2_P_origin_2_2_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_2/P_origin_2_2_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_2",
+ "table_id": "P_origin_2_2_0"
+ },
+ {
+ "index": 102,
+ "pair_id": "P_origin_2_P_origin_2_2_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_2/P_origin_2_2_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_2",
+ "table_id": "P_origin_2_2_1"
+ },
+ {
+ "index": 103,
+ "pair_id": "P_origin_2_P_origin_2_2_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_2/P_origin_2_2_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_2",
+ "table_id": "P_origin_2_2_2"
+ },
+ {
+ "index": 104,
+ "pair_id": "P_origin_3_P_origin_3_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_3/P_origin_3_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_3",
+ "table_id": "P_origin_3_0"
+ },
+ {
+ "index": 105,
+ "pair_id": "P_origin_3_P_origin_3_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_3/P_origin_3_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_3",
+ "table_id": "P_origin_3_1"
+ },
+ {
+ "index": 106,
+ "pair_id": "P_origin_3_P_origin_3_2_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_3/P_origin_3_2_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_3",
+ "table_id": "P_origin_3_2_0"
+ },
+ {
+ "index": 107,
+ "pair_id": "P_origin_3_P_origin_3_2_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_3/P_origin_3_2_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_3",
+ "table_id": "P_origin_3_2_1"
+ },
+ {
+ "index": 108,
+ "pair_id": "P_origin_4_P_origin_4_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_0"
+ },
+ {
+ "index": 109,
+ "pair_id": "P_origin_4_P_origin_4_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_1"
+ },
+ {
+ "index": 110,
+ "pair_id": "P_origin_4_P_origin_4_10",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_10.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_10"
+ },
+ {
+ "index": 111,
+ "pair_id": "P_origin_4_P_origin_4_11_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_11_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_11_0"
+ },
+ {
+ "index": 112,
+ "pair_id": "P_origin_4_P_origin_4_11_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_11_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_11_1"
+ },
+ {
+ "index": 113,
+ "pair_id": "P_origin_4_P_origin_4_12",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_12.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_12"
+ },
+ {
+ "index": 114,
+ "pair_id": "P_origin_4_P_origin_4_13",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_13.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_13"
+ },
+ {
+ "index": 115,
+ "pair_id": "P_origin_4_P_origin_4_14",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_14.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_14"
+ },
+ {
+ "index": 116,
+ "pair_id": "P_origin_4_P_origin_4_15",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_15.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_15"
+ },
+ {
+ "index": 117,
+ "pair_id": "P_origin_4_P_origin_4_16",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_16.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_16"
+ },
+ {
+ "index": 118,
+ "pair_id": "P_origin_4_P_origin_4_17",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_17.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_17"
+ },
+ {
+ "index": 119,
+ "pair_id": "P_origin_4_P_origin_4_18",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_18.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_18"
+ },
+ {
+ "index": 120,
+ "pair_id": "P_origin_4_P_origin_4_19",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_19.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_19"
+ },
+ {
+ "index": 121,
+ "pair_id": "P_origin_4_P_origin_4_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_2"
+ },
+ {
+ "index": 122,
+ "pair_id": "P_origin_4_P_origin_4_3",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_3.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_3"
+ },
+ {
+ "index": 123,
+ "pair_id": "P_origin_4_P_origin_4_4",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_4.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_4"
+ },
+ {
+ "index": 124,
+ "pair_id": "P_origin_4_P_origin_4_5",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_5.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_5"
+ },
+ {
+ "index": 125,
+ "pair_id": "P_origin_4_P_origin_4_6",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_6.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_6"
+ },
+ {
+ "index": 126,
+ "pair_id": "P_origin_4_P_origin_4_7",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_7.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_7"
+ },
+ {
+ "index": 127,
+ "pair_id": "P_origin_4_P_origin_4_8",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_8.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_8"
+ },
+ {
+ "index": 128,
+ "pair_id": "P_origin_4_P_origin_4_9_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_9_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_9_0"
+ },
+ {
+ "index": 129,
+ "pair_id": "P_origin_4_P_origin_4_9_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_4/P_origin_4_9_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_4",
+ "table_id": "P_origin_4_9_1"
+ },
+ {
+ "index": 130,
+ "pair_id": "P_origin_5_P_origin_5_0_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_0_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_0_0"
+ },
+ {
+ "index": 131,
+ "pair_id": "P_origin_5_P_origin_5_0_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_0_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_0_1"
+ },
+ {
+ "index": 132,
+ "pair_id": "P_origin_5_P_origin_5_10",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_10.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_10"
+ },
+ {
+ "index": 133,
+ "pair_id": "P_origin_5_P_origin_5_11",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_11.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_11"
+ },
+ {
+ "index": 134,
+ "pair_id": "P_origin_5_P_origin_5_12",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_12.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_12"
+ },
+ {
+ "index": 135,
+ "pair_id": "P_origin_5_P_origin_5_13",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_13.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_13"
+ },
+ {
+ "index": 136,
+ "pair_id": "P_origin_5_P_origin_5_14",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_14.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_14"
+ },
+ {
+ "index": 137,
+ "pair_id": "P_origin_5_P_origin_5_16",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_16.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_16"
+ },
+ {
+ "index": 138,
+ "pair_id": "P_origin_5_P_origin_5_17_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_17_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_17_0"
+ },
+ {
+ "index": 139,
+ "pair_id": "P_origin_5_P_origin_5_17_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_17_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_17_1"
+ },
+ {
+ "index": 140,
+ "pair_id": "P_origin_5_P_origin_5_18",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_18.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_18"
+ },
+ {
+ "index": 141,
+ "pair_id": "P_origin_5_P_origin_5_19",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_19.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_19"
+ },
+ {
+ "index": 142,
+ "pair_id": "P_origin_5_P_origin_5_1_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_1_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_1_0"
+ },
+ {
+ "index": 143,
+ "pair_id": "P_origin_5_P_origin_5_1_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_1_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_1_1"
+ },
+ {
+ "index": 144,
+ "pair_id": "P_origin_5_P_origin_5_1_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_1_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_1_2"
+ },
+ {
+ "index": 145,
+ "pair_id": "P_origin_5_P_origin_5_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_2"
+ },
+ {
+ "index": 146,
+ "pair_id": "P_origin_5_P_origin_5_20",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_20.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_20"
+ },
+ {
+ "index": 147,
+ "pair_id": "P_origin_5_P_origin_5_21",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_21.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_21"
+ },
+ {
+ "index": 148,
+ "pair_id": "P_origin_5_P_origin_5_22",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_22.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_22"
+ },
+ {
+ "index": 149,
+ "pair_id": "P_origin_5_P_origin_5_23",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_23.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_23"
+ },
+ {
+ "index": 150,
+ "pair_id": "P_origin_5_P_origin_5_24",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_24.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_24"
+ },
+ {
+ "index": 151,
+ "pair_id": "P_origin_5_P_origin_5_25",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_25.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_25"
+ },
+ {
+ "index": 152,
+ "pair_id": "P_origin_5_P_origin_5_26_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_26_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_26_0"
+ },
+ {
+ "index": 153,
+ "pair_id": "P_origin_5_P_origin_5_26_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_26_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_26_1"
+ },
+ {
+ "index": 154,
+ "pair_id": "P_origin_5_P_origin_5_3",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_3.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_3"
+ },
+ {
+ "index": 155,
+ "pair_id": "P_origin_5_P_origin_5_4",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_4.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_4"
+ },
+ {
+ "index": 156,
+ "pair_id": "P_origin_5_P_origin_5_5",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_5.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_5"
+ },
+ {
+ "index": 157,
+ "pair_id": "P_origin_5_P_origin_5_6",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_6.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_6"
+ },
+ {
+ "index": 158,
+ "pair_id": "P_origin_5_P_origin_5_7",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_7.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_7"
+ },
+ {
+ "index": 159,
+ "pair_id": "P_origin_5_P_origin_5_8",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_8.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_8"
+ },
+ {
+ "index": 160,
+ "pair_id": "P_origin_5_P_origin_5_9",
+ "image_paths": [
+ "data/Public/Table/P_origin_5/P_origin_5_9.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_5",
+ "table_id": "P_origin_5_9"
+ },
+ {
+ "index": 161,
+ "pair_id": "P_origin_6_P_origin_6_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_6/P_origin_6_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_6",
+ "table_id": "P_origin_6_0"
+ },
+ {
+ "index": 162,
+ "pair_id": "P_origin_6_P_origin_6_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_6/P_origin_6_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_6",
+ "table_id": "P_origin_6_1"
+ },
+ {
+ "index": 163,
+ "pair_id": "P_origin_6_P_origin_6_10",
+ "image_paths": [
+ "data/Public/Table/P_origin_6/P_origin_6_10.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_6",
+ "table_id": "P_origin_6_10"
+ },
+ {
+ "index": 164,
+ "pair_id": "P_origin_6_P_origin_6_11",
+ "image_paths": [
+ "data/Public/Table/P_origin_6/P_origin_6_11.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_6",
+ "table_id": "P_origin_6_11"
+ },
+ {
+ "index": 165,
+ "pair_id": "P_origin_6_P_origin_6_12_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_6/P_origin_6_12_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_6",
+ "table_id": "P_origin_6_12_0"
+ },
+ {
+ "index": 166,
+ "pair_id": "P_origin_6_P_origin_6_12_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_6/P_origin_6_12_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_6",
+ "table_id": "P_origin_6_12_1"
+ },
+ {
+ "index": 167,
+ "pair_id": "P_origin_6_P_origin_6_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_6/P_origin_6_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_6",
+ "table_id": "P_origin_6_2"
+ },
+ {
+ "index": 168,
+ "pair_id": "P_origin_6_P_origin_6_3",
+ "image_paths": [
+ "data/Public/Table/P_origin_6/P_origin_6_3.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_6",
+ "table_id": "P_origin_6_3"
+ },
+ {
+ "index": 169,
+ "pair_id": "P_origin_6_P_origin_6_4",
+ "image_paths": [
+ "data/Public/Table/P_origin_6/P_origin_6_4.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_6",
+ "table_id": "P_origin_6_4"
+ },
+ {
+ "index": 170,
+ "pair_id": "P_origin_6_P_origin_6_5",
+ "image_paths": [
+ "data/Public/Table/P_origin_6/P_origin_6_5.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_6",
+ "table_id": "P_origin_6_5"
+ },
+ {
+ "index": 171,
+ "pair_id": "P_origin_6_P_origin_6_6",
+ "image_paths": [
+ "data/Public/Table/P_origin_6/P_origin_6_6.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_6",
+ "table_id": "P_origin_6_6"
+ },
+ {
+ "index": 172,
+ "pair_id": "P_origin_6_P_origin_6_7",
+ "image_paths": [
+ "data/Public/Table/P_origin_6/P_origin_6_7.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_6",
+ "table_id": "P_origin_6_7"
+ },
+ {
+ "index": 173,
+ "pair_id": "P_origin_6_P_origin_6_8",
+ "image_paths": [
+ "data/Public/Table/P_origin_6/P_origin_6_8.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_6",
+ "table_id": "P_origin_6_8"
+ },
+ {
+ "index": 174,
+ "pair_id": "P_origin_6_P_origin_6_9",
+ "image_paths": [
+ "data/Public/Table/P_origin_6/P_origin_6_9.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_6",
+ "table_id": "P_origin_6_9"
+ },
+ {
+ "index": 175,
+ "pair_id": "P_origin_7_P_origin_7_0_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_0_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_7",
+ "table_id": "P_origin_7_0_0"
+ },
+ {
+ "index": 176,
+ "pair_id": "P_origin_7_P_origin_7_0_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_0_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_7",
+ "table_id": "P_origin_7_0_1"
+ },
+ {
+ "index": 177,
+ "pair_id": "P_origin_7_P_origin_7_1_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_1_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_7",
+ "table_id": "P_origin_7_1_0"
+ },
+ {
+ "index": 178,
+ "pair_id": "P_origin_7_P_origin_7_1_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_1_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_7",
+ "table_id": "P_origin_7_1_1"
+ },
+ {
+ "index": 179,
+ "pair_id": "P_origin_7_P_origin_7_2_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_2_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_7",
+ "table_id": "P_origin_7_2_0"
+ },
+ {
+ "index": 180,
+ "pair_id": "P_origin_7_P_origin_7_2_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_2_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_7",
+ "table_id": "P_origin_7_2_1"
+ },
+ {
+ "index": 181,
+ "pair_id": "P_origin_7_P_origin_7_3",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_3.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_7",
+ "table_id": "P_origin_7_3"
+ },
+ {
+ "index": 182,
+ "pair_id": "P_origin_7_P_origin_7_4_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_4_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_7",
+ "table_id": "P_origin_7_4_0"
+ },
+ {
+ "index": 183,
+ "pair_id": "P_origin_7_P_origin_7_4_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_4_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_7",
+ "table_id": "P_origin_7_4_1"
+ },
+ {
+ "index": 184,
+ "pair_id": "P_origin_7_P_origin_7_5",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_5.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_7",
+ "table_id": "P_origin_7_5"
+ },
+ {
+ "index": 185,
+ "pair_id": "P_origin_7_P_origin_7_6",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_6.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_7",
+ "table_id": "P_origin_7_6"
+ },
+ {
+ "index": 186,
+ "pair_id": "P_origin_7_P_origin_7_7",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_7.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_7",
+ "table_id": "P_origin_7_7"
+ },
+ {
+ "index": 187,
+ "pair_id": "P_origin_7_P_origin_7_8_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_8_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_7",
+ "table_id": "P_origin_7_8_0"
+ },
+ {
+ "index": 188,
+ "pair_id": "P_origin_7_P_origin_7_8_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_8_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_7",
+ "table_id": "P_origin_7_8_1"
+ },
+ {
+ "index": 189,
+ "pair_id": "P_origin_7_P_origin_7_8_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_7/P_origin_7_8_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_7",
+ "table_id": "P_origin_7_8_2"
+ },
+ {
+ "index": 190,
+ "pair_id": "P_origin_8_P_origin_8_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_0"
+ },
+ {
+ "index": 191,
+ "pair_id": "P_origin_8_P_origin_8_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_1"
+ },
+ {
+ "index": 192,
+ "pair_id": "P_origin_8_P_origin_8_10_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_10_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_10_0"
+ },
+ {
+ "index": 193,
+ "pair_id": "P_origin_8_P_origin_8_10_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_10_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_10_1"
+ },
+ {
+ "index": 194,
+ "pair_id": "P_origin_8_P_origin_8_11",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_11.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_11"
+ },
+ {
+ "index": 195,
+ "pair_id": "P_origin_8_P_origin_8_12_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_12_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_12_0"
+ },
+ {
+ "index": 196,
+ "pair_id": "P_origin_8_P_origin_8_12_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_12_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_12_1"
+ },
+ {
+ "index": 197,
+ "pair_id": "P_origin_8_P_origin_8_13",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_13.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_13"
+ },
+ {
+ "index": 198,
+ "pair_id": "P_origin_8_P_origin_8_14_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_14_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_14_0"
+ },
+ {
+ "index": 199,
+ "pair_id": "P_origin_8_P_origin_8_14_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_14_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_14_1"
+ },
+ {
+ "index": 200,
+ "pair_id": "P_origin_8_P_origin_8_14_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_14_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_14_2"
+ },
+ {
+ "index": 201,
+ "pair_id": "P_origin_8_P_origin_8_14_3",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_14_3.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_14_3"
+ },
+ {
+ "index": 202,
+ "pair_id": "P_origin_8_P_origin_8_14_4",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_14_4.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_14_4"
+ },
+ {
+ "index": 203,
+ "pair_id": "P_origin_8_P_origin_8_14_5",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_14_5.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_14_5"
+ },
+ {
+ "index": 204,
+ "pair_id": "P_origin_8_P_origin_8_14_6",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_14_6.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_14_6"
+ },
+ {
+ "index": 205,
+ "pair_id": "P_origin_8_P_origin_8_14_7",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_14_7.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_14_7"
+ },
+ {
+ "index": 206,
+ "pair_id": "P_origin_8_P_origin_8_15",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_15.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_15"
+ },
+ {
+ "index": 207,
+ "pair_id": "P_origin_8_P_origin_8_16",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_16.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_16"
+ },
+ {
+ "index": 208,
+ "pair_id": "P_origin_8_P_origin_8_17_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_17_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_17_0"
+ },
+ {
+ "index": 209,
+ "pair_id": "P_origin_8_P_origin_8_17_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_17_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_17_1"
+ },
+ {
+ "index": 210,
+ "pair_id": "P_origin_8_P_origin_8_17_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_17_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_17_2"
+ },
+ {
+ "index": 211,
+ "pair_id": "P_origin_8_P_origin_8_17_3",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_17_3.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_17_3"
+ },
+ {
+ "index": 212,
+ "pair_id": "P_origin_8_P_origin_8_17_4",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_17_4.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_17_4"
+ },
+ {
+ "index": 213,
+ "pair_id": "P_origin_8_P_origin_8_17_5",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_17_5.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_17_5"
+ },
+ {
+ "index": 214,
+ "pair_id": "P_origin_8_P_origin_8_17_6",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_17_6.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_17_6"
+ },
+ {
+ "index": 215,
+ "pair_id": "P_origin_8_P_origin_8_17_7",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_17_7.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_17_7"
+ },
+ {
+ "index": 216,
+ "pair_id": "P_origin_8_P_origin_8_18",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_18.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_18"
+ },
+ {
+ "index": 217,
+ "pair_id": "P_origin_8_P_origin_8_19",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_19.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_19"
+ },
+ {
+ "index": 218,
+ "pair_id": "P_origin_8_P_origin_8_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_2"
+ },
+ {
+ "index": 219,
+ "pair_id": "P_origin_8_P_origin_8_3",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_3.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_3"
+ },
+ {
+ "index": 220,
+ "pair_id": "P_origin_8_P_origin_8_4",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_4.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_4"
+ },
+ {
+ "index": 221,
+ "pair_id": "P_origin_8_P_origin_8_5",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_5.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_5"
+ },
+ {
+ "index": 222,
+ "pair_id": "P_origin_8_P_origin_8_6",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_6.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_6"
+ },
+ {
+ "index": 223,
+ "pair_id": "P_origin_8_P_origin_8_7",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_7.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_7"
+ },
+ {
+ "index": 224,
+ "pair_id": "P_origin_8_P_origin_8_8",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_8.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_8"
+ },
+ {
+ "index": 225,
+ "pair_id": "P_origin_8_P_origin_8_9_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_9_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_9_0"
+ },
+ {
+ "index": 226,
+ "pair_id": "P_origin_8_P_origin_8_9_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_9_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_9_1"
+ },
+ {
+ "index": 227,
+ "pair_id": "P_origin_8_P_origin_8_9_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_8/P_origin_8_9_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_8",
+ "table_id": "P_origin_8_9_2"
+ },
+ {
+ "index": 228,
+ "pair_id": "P_origin_9_P_origin_9_0_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_0_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_0_0"
+ },
+ {
+ "index": 229,
+ "pair_id": "P_origin_9_P_origin_9_0_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_0_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_0_1"
+ },
+ {
+ "index": 230,
+ "pair_id": "P_origin_9_P_origin_9_0_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_0_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_0_2"
+ },
+ {
+ "index": 231,
+ "pair_id": "P_origin_9_P_origin_9_0_3",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_0_3.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_0_3"
+ },
+ {
+ "index": 232,
+ "pair_id": "P_origin_9_P_origin_9_10",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_10.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_10"
+ },
+ {
+ "index": 233,
+ "pair_id": "P_origin_9_P_origin_9_11",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_11.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_11"
+ },
+ {
+ "index": 234,
+ "pair_id": "P_origin_9_P_origin_9_1_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_1_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_1_0"
+ },
+ {
+ "index": 235,
+ "pair_id": "P_origin_9_P_origin_9_1_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_1_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_1_1"
+ },
+ {
+ "index": 236,
+ "pair_id": "P_origin_9_P_origin_9_1_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_1_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_1_2"
+ },
+ {
+ "index": 237,
+ "pair_id": "P_origin_9_P_origin_9_2_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_2_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_2_0"
+ },
+ {
+ "index": 238,
+ "pair_id": "P_origin_9_P_origin_9_2_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_2_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_2_1"
+ },
+ {
+ "index": 239,
+ "pair_id": "P_origin_9_P_origin_9_2_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_2_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_2_2"
+ },
+ {
+ "index": 240,
+ "pair_id": "P_origin_9_P_origin_9_3",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_3.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_3"
+ },
+ {
+ "index": 241,
+ "pair_id": "P_origin_9_P_origin_9_4",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_4.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_4"
+ },
+ {
+ "index": 242,
+ "pair_id": "P_origin_9_P_origin_9_5",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_5.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_5"
+ },
+ {
+ "index": 243,
+ "pair_id": "P_origin_9_P_origin_9_6_0",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_6_0.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_6_0"
+ },
+ {
+ "index": 244,
+ "pair_id": "P_origin_9_P_origin_9_6_1",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_6_1.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_6_1"
+ },
+ {
+ "index": 245,
+ "pair_id": "P_origin_9_P_origin_9_6_2",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_6_2.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_6_2"
+ },
+ {
+ "index": 246,
+ "pair_id": "P_origin_9_P_origin_9_7",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_7.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_7"
+ },
+ {
+ "index": 247,
+ "pair_id": "P_origin_9_P_origin_9_8",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_8.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_8"
+ },
+ {
+ "index": 248,
+ "pair_id": "P_origin_9_P_origin_9_9",
+ "image_paths": [
+ "data/Public/Table/P_origin_9/P_origin_9_9.png"
+ ],
+ "domain": "Public",
+ "origin": "P_origin_9",
+ "table_id": "P_origin_9_9"
+ }
+]
\ No newline at end of file
diff --git a/test_input.json b/test_input.json
deleted file mode 100644
index f51ecd0..0000000
--- a/test_input.json
+++ /dev/null
@@ -1,119 +0,0 @@
-[
- {
- "index": 0,
- "pair_id": "P_origin_0_1",
- "image_paths": [
- "data/Public/Table/P_origin_0/P_origin_0_1_0.png",
- "data/Public/Table/P_origin_0/P_origin_0_1_1.png"
- ],
- "domain": "public"
- },
- {
- "index": 1,
- "pair_id": "P_origin_0_2",
- "image_paths": [
- "data/Public/Table/P_origin_0/P_origin_0_2_1.png",
- "data/Public/Table/P_origin_0/P_origin_0_2_2.png"
- ],
- "domain": "public"
- },
- {
- "index": 2,
- "pair_id": "P_origin_1_0",
- "image_paths": [
- "data/Public/Table/P_origin_1/P_origin_1_0.png"
- ],
- "domain": "public"
- },
- {
- "index": 3,
- "pair_id": "P_origin_1_2",
- "image_paths": [
- "data/Public/Table/P_origin_1/P_origin_1_2.png"
- ],
- "domain": "public"
- },
- {
- "index": 4,
- "pair_id": "P_origin_1_4",
- "image_paths": [
- "data/Public/Table/P_origin_1/P_origin_1_4.png"
- ],
- "domain": "public"
- },
- {
- "index": 5,
- "pair_id": "P_origin_1_5",
- "image_paths": [
- "data/Public/Table/P_origin_1/P_origin_1_5.png"
- ],
- "domain": "public"
- },
- {
- "index": 6,
- "pair_id": "P_origin_1_7",
- "image_paths": [
- "data/Public/Table/P_origin_1/P_origin_1_7.png"
- ],
- "domain": "public"
- },
- {
- "index": 7,
- "pair_id": "P_origin_1_9",
- "image_paths": [
- "data/Public/Table/P_origin_1/P_origin_1_9_0.png",
- "data/Public/Table/P_origin_1/P_origin_1_9_1.png"
- ],
- "domain": "public"
- },
- {
- "index": 8,
- "pair_id": "P_origin_1_10",
- "image_paths": [
- "data/Public/Table/P_origin_1/P_origin_1_10_0.png",
- "data/Public/Table/P_origin_1/P_origin_1_10_1.png"
- ],
- "domain": "public"
- },
- {
- "index": 9,
- "pair_id": "P_origin_1_12",
- "image_paths": [
- "data/Public/Table/P_origin_1/P_origin_1_12_0.png",
- "data/Public/Table/P_origin_1/P_origin_1_12_1.png"
- ],
- "domain": "public"
- },
- {
- "index": 10,
- "pair_id": "P_origin_1_13",
- "image_paths": [
- "data/Public/Table/P_origin_1/P_origin_1_13_0.png"
- ],
- "domain": "public"
- },
- {
- "index": 11,
- "pair_id": "P_origin_1_14",
- "image_paths": [
- "data/Public/Table/P_origin_1/P_origin_1_14_0.png"
- ],
- "domain": "public"
- },
- {
- "index": 12,
- "pair_id": "P_origin_1_23",
- "image_paths": [
- "data/Public/Table/P_origin_1/P_origin_1_23_0.png"
- ],
- "domain": "public"
- },
- {
- "index": 13,
- "pair_id": "P_origin_4_6",
- "image_paths": [
- "data/Public/Table/P_origin_4/P_origin_4_6.png"
- ],
- "domain": "public"
- }
-]
\ No newline at end of file
diff --git a/tests/choi/QA_example/README.md b/tests/choi/QA_example/README.md
deleted file mode 100644
index 30f07f3..0000000
--- a/tests/choi/QA_example/README.md
+++ /dev/null
@@ -1,129 +0,0 @@
-# QA Dataset Generation Module
-
-보험 테이블 마크다운 데이터를 기반으로 고품질 QA(Question-Answer) 데이터셋을 생성하는 모듈입니다.
-
-## 주요 기능
-
-### 1. 난이도별 QA 생성
-- **IR (Information Retrieval)**: 단순 정보 검색 (Level 1)
-- **Analysis**: 분석적 질문 (Level 2)
-- **Compare (Multi-hop)**: 비교 및 다중 추론 (Level 3)
-- **Aggregation**: 집계 연산 (Level 4)
-- **Reasoning**: 복합 추론 (Level 5)
-- **Insight**: 통찰 도출 (Level 6)
-
-### 2. 다양한 답변 유형
-- **Exact Match**: 단답형 (숫자, 예/아니오) - 정확한 매칭 평가
-- **Descriptive**: 서술형 - LLM-as-Judge 평가
-- **Calculation**: 수치 계산 결과 - Python 코드로 검증
-
-### 3. 고급 기능
-- **Multi-Table QA**: 복수 테이블 참조 필요 질문
-- **Follow-up QA**: 꼬리 질문 체인 생성
-- **Evol-Instruct**: 질문 난이도 진화
-- **LLM-as-Judge**: 품질 평가
-
-## 사용법
-
-### 기본 사용
-
-```python
-from QA_example import InsuranceTableQAGenerator, QADifficulty
-
-# 테이블 데이터 준비
-tables = {
- "table_1": "| 구분 | 값 |\n|---|---|\n| A | 100 |",
- "table_2": "| 항목 | 금액 |\n|---|---|\n| B | 200 |"
-}
-
-# Generator 초기화
-generator = InsuranceTableQAGenerator()
-
-# 특정 난이도 QA 생성
-ir_qa = generator.generate_qa_by_difficulty(tables, QADifficulty.IR, num_questions=3)
-
-# 종합 데이터셋 생성
-dataset = generator.generate_comprehensive_qa_dataset(
- tables,
- questions_per_difficulty=2,
- include_followup=True,
- include_evolution=True
-)
-```
-
-### 간편 함수 사용
-
-```python
-from QA_example import generate_qa_from_tables
-
-# 모든 난이도 QA 생성
-all_qa = generate_qa_from_tables(tables, num_questions=2)
-
-# 특정 난이도만 생성
-ir_only = generate_qa_from_tables(tables, difficulty=QADifficulty.IR)
-```
-
-## 커버되는 QA 양상
-
-| # | 양상 | 설명 | 구현 방식 |
-|---|------|------|----------|
-| 1 | Multi-table QA | 복수 테이블 참조 | `generate_multi_table_qa()` |
-| 2 | 난이도별 QA | 6단계 난이도 체계 | `QADifficulty` Enum |
-| 3 | 다양한 답변 유형 | Exact Match, Descriptive | `QAType` Enum |
-| 4 | 수치 계산 QA | 집계, 비율 계산 | Aggregation 난이도 |
-| 5 | 꼬리 질문 | Q-A 체인 | `generate_followup_qa()` |
-| 6 | 셀 기반 측정 | 여러 셀 기반 | Compare, Aggregation |
-| 7 | 특정 셀 Q-A | 단일 셀 검색 | IR 난이도 |
-| 8 | 이미지 연관 QA | 테이블 구조 기반 | 테이블 마크다운 입력 |
-
-## 파일 구조
-
-```
-QA_example/
-├── __init__.py # 모듈 초기화
-├── prompts.py # 프롬프트 템플릿
-├── qa_generator.py # QA 생성 핵심 로직
-├── qa_generation.ipynb # 사용 예제 노트북
-├── README.md # 이 문서
-└── output/ # 생성된 데이터셋
-```
-
-## 프롬프트 전략
-
-### Chain-of-Table
-- 단계별 표 해석 과정 명시
-- 동적 계획법 기반 질문 생성
-
-### Program-of-Thought (PoT)
-- 수치 계산을 Python 코드로 생성
-- 계산 결과의 무결성 보장
-
-### Tabular Chain-of-Thought
-- 추론 과정을 표 형태로 구조화
-- Step → Sub-question → Evidence → Reasoning
-
-### Evol-Instruct
-- 제약 조건 추가 (Adding Constraints)
-- 심층 추론 (Deepening Reasoning)
-- 구체화 (Concretizing)
-- 입력 복잡도 증가 (Complicating Input)
-
-## 품질 평가 (LLM-as-Judge)
-
-생성된 QA의 품질을 5가지 차원으로 평가:
-
-1. **정확성 (Correctness)**: 답변의 사실적 정확성
-2. **충실성 (Faithfulness)**: 테이블 데이터에 대한 충실도
-3. **관련성 (Relevance)**: 보험 도메인 실용성
-4. **난이도 적절성**: 표기 난이도와 실제 난이도 일치
-5. **명확성 (Clarity)**: 질문과 답변의 명확성
-
-## 의존성
-
-- `polling_gemini`: Gemini API 풀링 시스템
-- `google-generativeai`: Google Gemini API
-- `pyyaml`: YAML 설정 파일 처리
-
-## 라이센스
-
-MIT License
diff --git a/tests/choi/QA_example/__init__.py b/tests/choi/QA_example/__init__.py
deleted file mode 100644
index 53e6823..0000000
--- a/tests/choi/QA_example/__init__.py
+++ /dev/null
@@ -1,20 +0,0 @@
-"""
-QA Dataset Generation Module for Insurance Tables
-보험 테이블 기반 QA 데이터셋 생성 모듈
-"""
-
-from .qa_generator import (
- InsuranceTableQAGenerator,
- QADifficulty,
- QAType,
- generate_qa_from_tables,
-)
-
-__all__ = [
- 'InsuranceTableQAGenerator',
- 'QADifficulty',
- 'QAType',
- 'generate_qa_from_tables',
-]
-
-__version__ = '0.1.0'
diff --git a/tests/choi/QA_example/prompts.py b/tests/choi/QA_example/prompts.py
deleted file mode 100644
index 9adfeb5..0000000
--- a/tests/choi/QA_example/prompts.py
+++ /dev/null
@@ -1,479 +0,0 @@
-"""
-QA Generation Prompts for Insurance Table Data
-보험 테이블 기반 QA 생성을 위한 프롬프트 템플릿
-
-난이도별 QA 유형:
-1. IR (Information Retrieval): 단순 정보 검색
-2. Analysis: 분석적 질문
-3. Compare (Multi-hop): 비교 및 다중 추론
-4. Aggregation: 집계 연산
-5. Reasoning: 복합 추론
-6. Insight: 통찰 도출
-
-답변 유형:
-- Exact Match: 단답형 (숫자, 예/아니오)
-- Descriptive: 서술형 (LLM Judge 평가)
-"""
-
-# =============================================================================
-# System Prompts
-# =============================================================================
-
-QA_GENERATOR_SYSTEM_PROMPT = """# Role Definition
-당신은 보험 도메인 전문가이자 고품질 QA 데이터셋 구축 전문가입니다.
-주어진 보험 테이블 데이터를 기반으로 다양한 난이도와 유형의 질문-답변 쌍을 생성해야 합니다.
-
-# Core Principles
-1. **정확성(Accuracy):** 모든 답변은 주어진 테이블 데이터에 근거해야 합니다. 테이블에 없는 정보를 추측하지 마십시오.
-2. **다양성(Diversity):** 단순 검색부터 복잡한 추론까지 다양한 난이도의 질문을 생성해야 합니다.
-3. **실용성(Practicality):** 실제 보험 고객이 물어볼 수 있는 현실적인 질문을 생성해야 합니다.
-4. **명확성(Clarity):** 질문과 답변 모두 명확하고 모호하지 않아야 합니다.
-
-# Difficulty Levels (난이도)
-- **IR (Level 1):** 특정 셀의 값을 직접 찾는 단순 검색
-- **Analysis (Level 2):** 단일 테이블 내에서의 분석적 질문
-- **Compare (Level 3):** 여러 행/열 또는 복수 테이블 간 비교
-- **Aggregation (Level 4):** 합계, 평균, 최대/최소 등의 집계 연산
-- **Reasoning (Level 5):** 여러 정보를 종합한 복합 추론
-- **Insight (Level 6):** 데이터로부터 통찰이나 시사점 도출
-
-# Answer Types (답변 유형)
-- **exact_match:** 숫자, 예/아니오, 특정 텍스트 등 정확히 일치해야 하는 답변
-- **descriptive:** 설명이 필요한 서술형 답변 (LLM-as-Judge로 평가)
-- **calculation:** 수치 계산 결과 (계산 과정 포함)
-- **comparison:** 비교 결과 및 근거"""
-
-# =============================================================================
-# QA Generation Prompts by Difficulty
-# =============================================================================
-
-IR_QA_PROMPT = """## Task: Information Retrieval (IR) Level QA 생성
-단일 테이블에서 특정 셀의 값을 직접 검색하는 간단한 QA를 생성하세요.
-
-### Input Tables
-{tables}
-
-### Requirements
-1. 특정 행과 열이 교차하는 지점의 값을 묻는 질문
-2. 단답형으로 대답 가능한 질문
-3. 테이블에서 바로 찾을 수 있는 정보만 질문
-
-### Output Format (JSON)
-```json
-{{
- "questions": [
- {{
- "id": "IR_001",
- "difficulty": "IR",
- "answer_type": "exact_match",
- "question": "질문 내용",
- "answer": "정확한 답변",
- "evidence": {{
- "table_id": "table_1",
- "row": "행 정보",
- "column": "열 정보"
- }},
- "tags": ["single_cell", "numeric"]
- }}
- ]
-}}
-```
-
-### Generate {num_questions} IR-level QA pairs."""
-
-ANALYSIS_QA_PROMPT = """## Task: Analysis Level QA 생성
-단일 테이블 내에서 데이터를 분석하는 질문을 생성하세요.
-
-### Input Tables
-{tables}
-
-### Requirements
-1. 특정 조건을 만족하는 행/열 찾기
-2. 최대값/최소값을 가진 항목 식별
-3. 특정 범위 내의 데이터 확인
-4. 단답형 또는 짧은 설명형 답변
-
-### Output Format (JSON)
-```json
-{{
- "questions": [
- {{
- "id": "ANALYSIS_001",
- "difficulty": "Analysis",
- "answer_type": "exact_match",
- "question": "질문 내용",
- "answer": "정확한 답변",
- "reasoning": "답을 도출하는 과정 설명",
- "evidence": {{
- "table_id": "table_1",
- "relevant_cells": ["셀 위치1", "셀 위치2"]
- }},
- "tags": ["conditional_search", "extrema"]
- }}
- ]
-}}
-```
-
-### Generate {num_questions} Analysis-level QA pairs."""
-
-COMPARE_QA_PROMPT = """## Task: Compare (Multi-hop) Level QA 생성
-여러 행, 열, 또는 복수 테이블 간 비교가 필요한 질문을 생성하세요.
-
-### Input Tables
-{tables}
-
-### Requirements
-1. 두 개 이상의 셀 값을 비교하는 질문
-2. 시계열 변화를 비교하는 질문
-3. 복수 테이블의 정보를 연결하는 질문
-4. 차이, 비율, 증감률 등을 묻는 질문
-
-### Output Format (JSON)
-```json
-{{
- "questions": [
- {{
- "id": "COMPARE_001",
- "difficulty": "Compare",
- "answer_type": "calculation",
- "question": "질문 내용",
- "answer": "정확한 답변",
- "calculation": "계산 과정",
- "reasoning": "비교 논리 설명",
- "evidence": {{
- "table_ids": ["table_1", "table_2"],
- "compared_cells": [
- {{"table": "table_1", "row": "행1", "column": "열1", "value": "값1"}},
- {{"table": "table_1", "row": "행2", "column": "열2", "value": "값2"}}
- ]
- }},
- "tags": ["multi_hop", "comparison", "calculation"]
- }}
- ]
-}}
-```
-
-### Generate {num_questions} Compare-level QA pairs."""
-
-AGGREGATION_QA_PROMPT = """## Task: Aggregation Level QA 생성
-합계, 평균, 누적값 등 집계 연산이 필요한 질문을 생성하세요.
-
-### Input Tables
-{tables}
-
-### Requirements
-1. 특정 열/행의 합계를 구하는 질문
-2. 평균값을 계산하는 질문
-3. 누적 증가율을 구하는 질문
-4. 조건부 집계 (특정 조건을 만족하는 항목들의 합계 등)
-
-### Python Code for Verification
-답변의 정확성 검증을 위해 Python 코드도 함께 생성하세요.
-
-### Output Format (JSON)
-```json
-{{
- "questions": [
- {{
- "id": "AGG_001",
- "difficulty": "Aggregation",
- "answer_type": "calculation",
- "question": "질문 내용",
- "answer": "정확한 수치 답변",
- "calculation": "단계별 계산 과정",
- "python_verification": "import pandas as pd\\n# 검증 코드",
- "evidence": {{
- "table_id": "table_1",
- "aggregated_cells": ["셀1", "셀2", "셀3"]
- }},
- "tags": ["aggregation", "sum", "average"]
- }}
- ]
-}}
-```
-
-### Generate {num_questions} Aggregation-level QA pairs."""
-
-REASONING_QA_PROMPT = """## Task: Reasoning Level QA 생성
-여러 정보를 종합하여 복합적인 추론이 필요한 질문을 생성하세요.
-
-### Input Tables
-{tables}
-
-### Requirements
-1. 조건부 로직을 적용한 추론 질문
-2. 가정(Assumption)을 포함한 시나리오 기반 질문
-3. 인과관계를 파악하는 질문
-4. 여러 단계의 논리적 추론이 필요한 질문
-
-### Chain-of-Thought Reasoning
-답변 도출 과정을 단계별로 명시하세요.
-
-### Output Format (JSON)
-```json
-{{
- "questions": [
- {{
- "id": "REASON_001",
- "difficulty": "Reasoning",
- "answer_type": "descriptive",
- "question": "질문 내용",
- "answer": "답변",
- "chain_of_thought": [
- "Step 1: ...",
- "Step 2: ...",
- "Step 3: ..."
- ],
- "assumptions": ["가정1", "가정2"],
- "evidence": {{
- "table_ids": ["table_1"],
- "relevant_data": ["관련 데이터 포인트"]
- }},
- "tags": ["multi_step_reasoning", "conditional_logic"]
- }}
- ]
-}}
-```
-
-### Generate {num_questions} Reasoning-level QA pairs."""
-
-INSIGHT_QA_PROMPT = """## Task: Insight Level QA 생성
-데이터로부터 통찰이나 시사점을 도출하는 고난도 질문을 생성하세요.
-
-### Input Tables
-{tables}
-
-### Requirements
-1. 데이터 추세(Trend)를 파악하는 질문
-2. 이상치(Anomaly)나 특이 패턴을 발견하는 질문
-3. 데이터 기반 예측이나 권고를 요청하는 질문
-4. 비즈니스적 함의를 도출하는 질문
-
-### Output Format (JSON)
-```json
-{{
- "questions": [
- {{
- "id": "INSIGHT_001",
- "difficulty": "Insight",
- "answer_type": "descriptive",
- "question": "질문 내용",
- "answer": "통찰 및 답변",
- "supporting_analysis": "분석 과정",
- "key_findings": ["발견1", "발견2"],
- "evidence": {{
- "table_ids": ["table_1", "table_2"],
- "data_points": ["근거 데이터"]
- }},
- "tags": ["trend_analysis", "insight", "recommendation"]
- }}
- ]
-}}
-```
-
-### Generate {num_questions} Insight-level QA pairs."""
-
-# =============================================================================
-# Follow-up Question Prompts (꼬리 질문)
-# =============================================================================
-
-FOLLOWUP_QA_PROMPT = """## Task: Follow-up Question (꼬리 질문) 생성
-주어진 초기 QA에 대해 연속적인 후속 질문을 생성하세요.
-
-### Original QA
-{original_qa}
-
-### Input Tables
-{tables}
-
-### Requirements
-1. 원래 질문의 맥락을 유지하면서 심화된 질문
-2. 원래 답변에서 파생되는 추가 질문
-3. 관련된 다른 데이터 포인트를 탐색하는 질문
-4. 2-3개의 연속적인 후속 질문 체인 생성
-
-### Output Format (JSON)
-```json
-{{
- "original_qa": {{
- "question": "원래 질문",
- "answer": "원래 답변"
- }},
- "followup_chain": [
- {{
- "id": "FOLLOWUP_001_1",
- "question": "후속 질문 1",
- "answer": "답변 1",
- "reasoning": "이전 답변과의 연결고리"
- }},
- {{
- "id": "FOLLOWUP_001_2",
- "question": "후속 질문 2 (질문1 기반)",
- "answer": "답변 2",
- "reasoning": "이전 답변과의 연결고리"
- }}
- ]
-}}
-```
-
-### Generate follow-up questions chain."""
-
-# =============================================================================
-# Multi-Table QA Prompts
-# =============================================================================
-
-MULTI_TABLE_QA_PROMPT = """## Task: Multi-Table QA 생성
-복수의 테이블을 참조해야 답변 가능한 질문을 생성하세요.
-
-### Input Tables
-{tables}
-
-### Requirements
-1. 반드시 2개 이상의 테이블 정보를 조합해야 답변 가능한 질문
-2. 테이블 간 연결 키(Key)를 활용한 질문
-3. 서로 다른 테이블의 수치를 비교/연산하는 질문
-4. 종합적인 분석이 필요한 질문
-
-### Output Format (JSON)
-```json
-{{
- "questions": [
- {{
- "id": "MULTI_001",
- "difficulty": "Compare",
- "answer_type": "calculation",
- "question": "질문 내용",
- "answer": "답변",
- "required_tables": ["table_1", "table_2"],
- "join_logic": "테이블 연결 방법 설명",
- "reasoning": "답변 도출 과정",
- "tags": ["multi_table", "join", "cross_reference"]
- }}
- ]
-}}
-```
-
-### Generate {num_questions} Multi-Table QA pairs."""
-
-# =============================================================================
-# Evol-Instruct Prompts (난이도 진화)
-# =============================================================================
-
-EVOL_INSTRUCT_PROMPT = """## Task: Evol-Instruct - 질문 난이도 진화
-주어진 기본 질문을 더 복잡하고 도전적인 질문으로 진화시키세요.
-
-### Original Question
-{original_question}
-
-### Evolution Strategies
-다음 전략 중 하나 이상을 적용하여 질문을 진화시키세요:
-
-1. **제약 조건 추가 (Adding Constraints):**
- - 특정 조건(나이, 기간, 금액 범위 등)을 추가
-
-2. **심층 추론 (Deepening Reasoning):**
- - 다단계 논리적 사고를 요구하도록 변환
-
-3. **구체화 (Concretizing):**
- - 추상적 질문을 구체적 시나리오로 대체
-
-4. **입력 복잡도 증가 (Complicating Input):**
- - 복수 테이블이나 추가 조건을 참조하도록 변환
-
-### Input Tables
-{tables}
-
-### Output Format (JSON)
-```json
-{{
- "original": {{
- "question": "원래 질문",
- "difficulty": "원래 난이도"
- }},
- "evolved": {{
- "question": "진화된 질문",
- "difficulty": "새로운 난이도",
- "evolution_strategy": "적용된 전략",
- "answer": "새로운 답변",
- "reasoning": "답변 도출 과정"
- }}
-}}
-```
-
-### Evolve the question."""
-
-# =============================================================================
-# Quality Evaluation Prompts (LLM-as-Judge)
-# =============================================================================
-
-QA_EVALUATION_PROMPT = """## Task: QA 품질 평가 (LLM-as-Judge)
-생성된 QA 쌍의 품질을 다면적으로 평가하세요.
-
-### QA to Evaluate
-{qa_pair}
-
-### Reference Tables
-{tables}
-
-### Evaluation Criteria (1-5점 척도)
-
-1. **정확성 (Correctness):**
- - 답변이 테이블 데이터에 정확히 근거하는가?
- - 수치 계산이 정확한가?
-
-2. **충실성 (Faithfulness):**
- - 테이블에 없는 정보를 날조(Hallucination)하지 않았는가?
- - 근거 데이터가 명확한가?
-
-3. **관련성 (Relevance):**
- - 질문이 보험 도메인에서 실용적인가?
- - 실제 고객이 물어볼 법한 질문인가?
-
-4. **난이도 적절성 (Difficulty Appropriateness):**
- - 표기된 난이도와 실제 난이도가 일치하는가?
-
-5. **명확성 (Clarity):**
- - 질문과 답변이 명확하고 모호하지 않은가?
-
-### Output Format (JSON)
-```json
-{{
- "evaluation": {{
- "correctness": {{"score": 5, "comment": "평가 코멘트"}},
- "faithfulness": {{"score": 5, "comment": "평가 코멘트"}},
- "relevance": {{"score": 5, "comment": "평가 코멘트"}},
- "difficulty_appropriateness": {{"score": 5, "comment": "평가 코멘트"}},
- "clarity": {{"score": 5, "comment": "평가 코멘트"}}
- }},
- "overall_score": 5.0,
- "pass": true,
- "improvement_suggestions": ["개선 제안1", "개선 제안2"]
-}}
-```
-
-### Evaluate the QA pair."""
-
-
-# =============================================================================
-# Helper Functions
-# =============================================================================
-
-def get_qa_prompt_by_difficulty(difficulty: str) -> str:
- """난이도에 따른 프롬프트 반환"""
- prompts = {
- "IR": IR_QA_PROMPT,
- "Analysis": ANALYSIS_QA_PROMPT,
- "Compare": COMPARE_QA_PROMPT,
- "Aggregation": AGGREGATION_QA_PROMPT,
- "Reasoning": REASONING_QA_PROMPT,
- "Insight": INSIGHT_QA_PROMPT,
- }
- return prompts.get(difficulty, IR_QA_PROMPT)
-
-
-def format_tables_for_prompt(tables: dict) -> str:
- """테이블 딕셔너리를 프롬프트용 문자열로 변환"""
- formatted = []
- for table_id, table_content in tables.items():
- formatted.append(f"### {table_id}\n```markdown\n{table_content}\n```\n")
- return "\n".join(formatted)
diff --git a/tests/choi/QA_example/qa_generation.ipynb b/tests/choi/QA_example/qa_generation.ipynb
deleted file mode 100644
index 34481fa..0000000
--- a/tests/choi/QA_example/qa_generation.ipynb
+++ /dev/null
@@ -1,1432 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "id": "8386b6ee",
- "metadata": {},
- "source": [
- "## 1. 환경 설정"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "8972c3e2",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "프로젝트 루트: /Users/jaehyeokchoi/Desktop/chois_toy/private/TableMagnifier\n",
- "현재 작업 디렉토리: /Users/jaehyeokchoi/Desktop/chois_toy/private/TableMagnifier/QA_example\n"
- ]
- }
- ],
- "source": [
- "import sys\n",
- "import json\n",
- "import asyncio\n",
- "from pathlib import Path\n",
- "from datetime import datetime\n",
- "\n",
- "# 프로젝트 루트 경로 설정\n",
- "project_root = Path.cwd().parent\n",
- "if str(project_root) not in sys.path:\n",
- " sys.path.insert(0, str(project_root))\n",
- "\n",
- "print(f\"프로젝트 루트: {project_root}\")\n",
- "print(f\"현재 작업 디렉토리: {Path.cwd()}\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "id": "ca7782da",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "✅ 모듈 임포트 완료 (리로드됨)\n"
- ]
- }
- ],
- "source": [
- "# QA Generator 모듈 임포트 (변경 시 리로드)\n",
- "import importlib\n",
- "import QA_example.qa_generator\n",
- "importlib.reload(QA_example.qa_generator)\n",
- "\n",
- "from QA_example.qa_generator import (\n",
- " InsuranceTableQAGenerator,\n",
- " QADifficulty,\n",
- " QAType,\n",
- " generate_qa_from_tables,\n",
- ")\n",
- "\n",
- "# Gemini API Pool 임포트\n",
- "from polling_gemini import get_gemini_pool\n",
- "\n",
- "print(\"✅ 모듈 임포트 완료 (리로드됨)\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "id": "68b1f92e",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "📊 API Pool 상태:\n",
- " 현재 키: key1\n",
- " 총 키 수: 3\n"
- ]
- }
- ],
- "source": [
- "# API Pool 상태 확인\n",
- "pool = get_gemini_pool()\n",
- "print(\"📊 API Pool 상태:\")\n",
- "print(f\" 현재 키: {pool.get_current_key_info()['name']}\")\n",
- "print(f\" 총 키 수: {pool.get_current_key_info()['total_keys']}\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "c38801d5",
- "metadata": {},
- "source": [
- "## 2. 샘플 테이블 데이터 준비\n",
- "\n",
- "보험 도메인의 다양한 테이블 예시를 준비합니다."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 13,
- "id": "504b0780",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "✅ 샘플 테이블 데이터 준비 완료\n",
- " - TABLE_1: 보험료 산출 기초율\n",
- " - TABLE_2: 해지환급금 예시\n",
- " - TABLE_3: 보장 내역\n",
- " - TABLE_4: 연령별 보험료\n"
- ]
- }
- ],
- "source": [
- "# 샘플 테이블 1: 보험료 산출 기초율 테이블 (실제 데이터 기반)\n",
- "TABLE_1_PREMIUM_CALCULATION = \"\"\"\n",
- "|구분|XX세|XX+1세|XX+2세|XX+3세|XX+4세|XX+5세|\n",
- "|---|---|---|---|---|---|---|\n",
- "|나이증가분(A)||1059|1357|1739|2229|2855|\n",
- "|보험료 산출 기초율(위험률 등) 증가분(B=전년도 기준보험료의 최대 25% 가정)||10846|13897|17806|22815|29232|\n",
- "|기준보험료(C=전년도 기준보험료+A+B)|42325|54321|69485|89030|114074|146161|\n",
- "\"\"\".strip()\n",
- "\n",
- "# 샘플 테이블 2: 해지환급금 예시표\n",
- "TABLE_2_SURRENDER_VALUE = \"\"\"\n",
- "|경과기간|납입보험료 누계|해지환급금|환급률|\n",
- "|---|---|---|---|\n",
- "|1년|600000|0|0%|\n",
- "|3년|1800000|540000|30%|\n",
- "|5년|3000000|1650000|55%|\n",
- "|10년|6000000|4800000|80%|\n",
- "|15년|9000000|8550000|95%|\n",
- "|20년(만기)|12000000|12000000|100%|\n",
- "\"\"\".strip()\n",
- "\n",
- "# 샘플 테이블 3: 보장 내역표\n",
- "TABLE_3_COVERAGE = \"\"\"\n",
- "|보장항목|보장내용|지급금액|지급조건|\n",
- "|---|---|---|---|\n",
- "|사망보험금|일반사망|50000000|피보험자 사망시|\n",
- "|사망보험금|재해사망|100000000|재해로 인한 사망시|\n",
- "|암진단금|일반암|30000000|암 최초 진단시|\n",
- "|암진단금|소액암|6000000|소액암 진단시|\n",
- "|암진단금|유사암|3000000|유사암 진단시|\n",
- "|입원비|일반입원|50000|1일당 (최대 180일)|\n",
- "|입원비|암입원|100000|1일당 (최대 180일)|\n",
- "|수술비|일반수술|500000|1회당|\n",
- "|수술비|암수술|2000000|1회당|\n",
- "\"\"\".strip()\n",
- "\n",
- "# 샘플 테이블 4: 연령별 보험료 예시\n",
- "TABLE_4_AGE_PREMIUM = \"\"\"\n",
- "|가입연령|성별|20년납_월보험료|전기납_월보험료|일시납_총보험료|\n",
- "|---|---|---|---|---|\n",
- "|30세|남|45000|38000|8500000|\n",
- "|30세|여|42000|35000|7800000|\n",
- "|40세|남|65000|52000|11500000|\n",
- "|40세|여|58000|47000|10200000|\n",
- "|50세|남|95000|75000|16000000|\n",
- "|50세|여|82000|65000|14000000|\n",
- "\"\"\".strip()\n",
- "\n",
- "print(\"✅ 샘플 테이블 데이터 준비 완료\")\n",
- "print(f\" - TABLE_1: 보험료 산출 기초율\")\n",
- "print(f\" - TABLE_2: 해지환급금 예시\")\n",
- "print(f\" - TABLE_3: 보장 내역\")\n",
- "print(f\" - TABLE_4: 연령별 보험료\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 14,
- "id": "c22033b5",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "============================================================\n",
- "📋 table_1_premium_calculation\n",
- "============================================================\n"
- ]
- },
- {
- "data": {
- "text/markdown": [
- "|구분|XX세|XX+1세|XX+2세|XX+3세|XX+4세|XX+5세|\n",
- "|---|---|---|---|---|---|---|\n",
- "|나이증가분(A)||1059|1357|1739|2229|2855|\n",
- "|보험료 산출 기초율(위험률 등) 증가분(B=전년도 기준보험료의 최대 25% 가정)||10846|13897|17806|22815|29232|\n",
- "|기준보험료(C=전년도 기준보험료+A+B)|42325|54321|69485|89030|114074|146161|"
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "============================================================\n",
- "📋 table_2_surrender_value\n",
- "============================================================\n"
- ]
- },
- {
- "data": {
- "text/markdown": [
- "|경과기간|납입보험료 누계|해지환급금|환급률|\n",
- "|---|---|---|---|\n",
- "|1년|600000|0|0%|\n",
- "|3년|1800000|540000|30%|\n",
- "|5년|3000000|1650000|55%|\n",
- "|10년|6000000|4800000|80%|\n",
- "|15년|9000000|8550000|95%|\n",
- "|20년(만기)|12000000|12000000|100%|"
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "============================================================\n",
- "📋 table_3_coverage\n",
- "============================================================\n"
- ]
- },
- {
- "data": {
- "text/markdown": [
- "|보장항목|보장내용|지급금액|지급조건|\n",
- "|---|---|---|---|\n",
- "|사망보험금|일반사망|50000000|피보험자 사망시|\n",
- "|사망보험금|재해사망|100000000|재해로 인한 사망시|\n",
- "|암진단금|일반암|30000000|암 최초 진단시|\n",
- "|암진단금|소액암|6000000|소액암 진단시|\n",
- "|암진단금|유사암|3000000|유사암 진단시|\n",
- "|입원비|일반입원|50000|1일당 (최대 180일)|\n",
- "|입원비|암입원|100000|1일당 (최대 180일)|\n",
- "|수술비|일반수술|500000|1회당|\n",
- "|수술비|암수술|2000000|1회당|"
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "============================================================\n",
- "📋 table_4_age_premium\n",
- "============================================================\n"
- ]
- },
- {
- "data": {
- "text/markdown": [
- "|가입연령|성별|20년납_월보험료|전기납_월보험료|일시납_총보험료|\n",
- "|---|---|---|---|---|\n",
- "|30세|남|45000|38000|8500000|\n",
- "|30세|여|42000|35000|7800000|\n",
- "|40세|남|65000|52000|11500000|\n",
- "|40세|여|58000|47000|10200000|\n",
- "|50세|남|95000|75000|16000000|\n",
- "|50세|여|82000|65000|14000000|"
- ],
- "text/plain": [
- ""
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": [
- "# 테이블 딕셔너리 구성\n",
- "tables = {\n",
- " \"table_1_premium_calculation\": TABLE_1_PREMIUM_CALCULATION,\n",
- " \"table_2_surrender_value\": TABLE_2_SURRENDER_VALUE,\n",
- " \"table_3_coverage\": TABLE_3_COVERAGE,\n",
- " \"table_4_age_premium\": TABLE_4_AGE_PREMIUM,\n",
- "}\n",
- "\n",
- "# 테이블 미리보기\n",
- "from IPython.display import display, Markdown\n",
- "\n",
- "for table_id, content in tables.items():\n",
- " print(f\"\\n{'='*60}\")\n",
- " print(f\"📋 {table_id}\")\n",
- " print('='*60)\n",
- " display(Markdown(content))"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "0480f78c",
- "metadata": {},
- "source": [
- "## 3. QA Generator 초기화"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 15,
- "id": "d4d5e0c6",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "✅ QA Generator 초기화 완료\n",
- " 사용 모델: gemini-2.0-flash\n"
- ]
- }
- ],
- "source": [
- "# QA Generator 인스턴스 생성\n",
- "qa_generator = InsuranceTableQAGenerator(\n",
- " model_name=\"gemini-2.0-flash\" # 또는 \"gemini-1.5-flash\"\n",
- ")\n",
- "\n",
- "print(\"✅ QA Generator 초기화 완료\")\n",
- "print(f\" 사용 모델: gemini-2.0-flash\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "f21cb567",
- "metadata": {},
- "source": [
- "## 4. 난이도별 QA 생성\n",
- "\n",
- "### 4.1 IR (Information Retrieval) - 단순 정보 검색"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 16,
- "id": "11267214",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "🔍 IR (Information Retrieval) QA 생성 중...\n",
- "\n",
- "✅ 3개의 IR QA 생성 완료\n",
- "\n",
- "📌 [IR_001] IR\n",
- " Q: XX세의 기준보험료는 얼마인가요?\n",
- " A: 42325\n",
- " Evidence: {'table_id': 'table_1_premium_calculation', 'row': '기준보험료(C=전년도 기준보험료+A+B)', 'column': 'XX세'}\n",
- "\n",
- "📌 [IR_002] IR\n",
- " Q: 경과기간이 1년일 때 해지환급금은 얼마인가요?\n",
- " A: 0\n",
- " Evidence: {'table_id': 'table_2_surrender_value', 'row': '1년', 'column': '해지환급금'}\n",
- "\n",
- "📌 [IR_003] IR\n",
- " Q: 30세 남성의 20년납 월보험료는 얼마인가요?\n",
- " A: 45000\n",
- " Evidence: {'table_id': 'table_4_age_premium', 'row': '30세 (남)', 'column': '20년납_월보험료'}\n",
- "\n",
- "✅ 3개의 IR QA 생성 완료\n",
- "\n",
- "📌 [IR_001] IR\n",
- " Q: XX세의 기준보험료는 얼마인가요?\n",
- " A: 42325\n",
- " Evidence: {'table_id': 'table_1_premium_calculation', 'row': '기준보험료(C=전년도 기준보험료+A+B)', 'column': 'XX세'}\n",
- "\n",
- "📌 [IR_002] IR\n",
- " Q: 경과기간이 1년일 때 해지환급금은 얼마인가요?\n",
- " A: 0\n",
- " Evidence: {'table_id': 'table_2_surrender_value', 'row': '1년', 'column': '해지환급금'}\n",
- "\n",
- "📌 [IR_003] IR\n",
- " Q: 30세 남성의 20년납 월보험료는 얼마인가요?\n",
- " A: 45000\n",
- " Evidence: {'table_id': 'table_4_age_premium', 'row': '30세 (남)', 'column': '20년납_월보험료'}\n"
- ]
- }
- ],
- "source": [
- "# IR 난이도 QA 생성 (단답형, 특정 셀 검색)\n",
- "print(\"🔍 IR (Information Retrieval) QA 생성 중...\")\n",
- "\n",
- "ir_qa_pairs = qa_generator.generate_qa_by_difficulty(\n",
- " tables=tables,\n",
- " difficulty=QADifficulty.IR,\n",
- " num_questions=3\n",
- ")\n",
- "\n",
- "print(f\"\\n✅ {len(ir_qa_pairs)}개의 IR QA 생성 완료\")\n",
- "for qa in ir_qa_pairs:\n",
- " print(f\"\\n📌 [{qa.id}] {qa.difficulty}\")\n",
- " print(f\" Q: {qa.question}\")\n",
- " print(f\" A: {qa.answer}\")\n",
- " if qa.evidence:\n",
- " print(f\" Evidence: {qa.evidence}\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "6c4f477c",
- "metadata": {},
- "source": [
- "### 4.2 Analysis - 분석적 질문"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 17,
- "id": "647c157f",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "📊 Analysis QA 생성 중...\n",
- "\n",
- "✅ 3개의 Analysis QA 생성 완료\n",
- "\n",
- "📌 [ANALYSIS_001] Analysis\n",
- " Q: 암진단금 보장항목 중에서 가장 높은 지급금액을 제공하는 보장내용은 무엇인가요?\n",
- " A: 일반암\n",
- " Reasoning: table_3_coverage에서 '보장항목'이 '암진단금'인 행들을 확인하고, 그 중 '지급금액'이 가장 높은 '보장내용'을 찾습니다. 일반암은 30,000,000원, 소액암은 6,000,000원, 유사암은 3,000,000원이므로 일반암이 가장 높습니다.\n",
- "\n",
- "📌 [ANALYSIS_002] Analysis\n",
- " Q: 해지환급률이 50% 이상이 되려면 최소 몇 년의 경과기간이 필요합니까?\n",
- " A: 5년\n",
- " Reasoning: table_2_surrender_value에서 '환급률'이 50% 이상인 행들을 찾고, 그 중 가장 작은 '경과기간'을 확인합니다. 3년 경과 시 환급률은 30%이고, 5년 경과 시 환급률은 55%이므로 최소 5년이 필요합니다.\n",
- "\n",
- "📌 [ANALYSIS_003] Analysis\n",
- " Q: 40세 가입자의 경우, 남성과 여성 중 누가 20년납_월보험료가 더 높은가요?\n",
- " A: 남성\n",
- " Reasoning: table_4_age_premium에서 '가입연령'이 40세인 행들을 찾고, 해당 행들의 '20년납_월보험료'를 비교합니다. 40세 남성의 20년납_월보험료는 65,000원이고, 40세 여성의 20년납_월보험료는 58,000원이므로 남성이 더 높습니다.\n",
- "\n",
- "✅ 3개의 Analysis QA 생성 완료\n",
- "\n",
- "📌 [ANALYSIS_001] Analysis\n",
- " Q: 암진단금 보장항목 중에서 가장 높은 지급금액을 제공하는 보장내용은 무엇인가요?\n",
- " A: 일반암\n",
- " Reasoning: table_3_coverage에서 '보장항목'이 '암진단금'인 행들을 확인하고, 그 중 '지급금액'이 가장 높은 '보장내용'을 찾습니다. 일반암은 30,000,000원, 소액암은 6,000,000원, 유사암은 3,000,000원이므로 일반암이 가장 높습니다.\n",
- "\n",
- "📌 [ANALYSIS_002] Analysis\n",
- " Q: 해지환급률이 50% 이상이 되려면 최소 몇 년의 경과기간이 필요합니까?\n",
- " A: 5년\n",
- " Reasoning: table_2_surrender_value에서 '환급률'이 50% 이상인 행들을 찾고, 그 중 가장 작은 '경과기간'을 확인합니다. 3년 경과 시 환급률은 30%이고, 5년 경과 시 환급률은 55%이므로 최소 5년이 필요합니다.\n",
- "\n",
- "📌 [ANALYSIS_003] Analysis\n",
- " Q: 40세 가입자의 경우, 남성과 여성 중 누가 20년납_월보험료가 더 높은가요?\n",
- " A: 남성\n",
- " Reasoning: table_4_age_premium에서 '가입연령'이 40세인 행들을 찾고, 해당 행들의 '20년납_월보험료'를 비교합니다. 40세 남성의 20년납_월보험료는 65,000원이고, 40세 여성의 20년납_월보험료는 58,000원이므로 남성이 더 높습니다.\n"
- ]
- }
- ],
- "source": [
- "# Analysis 난이도 QA 생성\n",
- "print(\"📊 Analysis QA 생성 중...\")\n",
- "\n",
- "analysis_qa_pairs = qa_generator.generate_qa_by_difficulty(\n",
- " tables=tables,\n",
- " difficulty=QADifficulty.ANALYSIS,\n",
- " num_questions=3\n",
- ")\n",
- "\n",
- "print(f\"\\n✅ {len(analysis_qa_pairs)}개의 Analysis QA 생성 완료\")\n",
- "for qa in analysis_qa_pairs:\n",
- " print(f\"\\n📌 [{qa.id}] {qa.difficulty}\")\n",
- " print(f\" Q: {qa.question}\")\n",
- " print(f\" A: {qa.answer}\")\n",
- " if qa.reasoning:\n",
- " print(f\" Reasoning: {qa.reasoning}\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "7c744604",
- "metadata": {},
- "source": [
- "### 4.3 Compare (Multi-hop) - 비교 및 다중 추론"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 18,
- "id": "597806d6",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "⚖️ Compare (Multi-hop) QA 생성 중...\n",
- "\n",
- "✅ 3개의 Compare QA 생성 완료\n",
- "\n",
- "📌 [COMPARE_001] Compare\n",
- " Q: table_1_premium_calculation에서 XX+1세의 경우, 보험료 산출 기초율 증가분(B)은 나이증가분(A)보다 얼마나 더 큰가요?\n",
- " A: 9,787원 더 큽니다.\n",
- " Reasoning: XX+1세의 보험료 산출 기초율 증가분(B) 값에서 나이증가분(A) 값을 차감하여 그 차이를 계산합니다.\n",
- "\n",
- "📌 [COMPARE_002] Compare\n",
- " Q: table_2_surrender_value에서 보험 가입 후 5년 경과 시점과 10년 경과 시점의 해지환급금은 얼마나 차이가 나나요?\n",
- " A: 3,150,000원 차이가 납니다.\n",
- " Reasoning: 10년 경과 시점의 해지환급금에서 5년 경과 시점의 해지환급금을 차감하여 차이를 계산합니다.\n",
- "\n",
- "📌 [COMPARE_003] Compare\n",
- " Q: table_4_age_premium에서 30세 남성이 20년납 월보험료로 가입했을 경우, 20년 만기 시점의 총 납입보험료와 table_2_surrender_value의 20년 경과 시점 해지환급금은 얼마나 차이가 나나요?\n",
- " A: 1,200,000원 차이가 납니다.\n",
- " Reasoning: table_4에서 30세 남성의 20년납 월보험료를 찾아 20년간의 총 납입보험료를 계산하고, table_2에서 20년 경과 시점의 해지환급금을 찾아 두 값의 차이를 계산합니다.\n",
- "\n",
- "✅ 3개의 Compare QA 생성 완료\n",
- "\n",
- "📌 [COMPARE_001] Compare\n",
- " Q: table_1_premium_calculation에서 XX+1세의 경우, 보험료 산출 기초율 증가분(B)은 나이증가분(A)보다 얼마나 더 큰가요?\n",
- " A: 9,787원 더 큽니다.\n",
- " Reasoning: XX+1세의 보험료 산출 기초율 증가분(B) 값에서 나이증가분(A) 값을 차감하여 그 차이를 계산합니다.\n",
- "\n",
- "📌 [COMPARE_002] Compare\n",
- " Q: table_2_surrender_value에서 보험 가입 후 5년 경과 시점과 10년 경과 시점의 해지환급금은 얼마나 차이가 나나요?\n",
- " A: 3,150,000원 차이가 납니다.\n",
- " Reasoning: 10년 경과 시점의 해지환급금에서 5년 경과 시점의 해지환급금을 차감하여 차이를 계산합니다.\n",
- "\n",
- "📌 [COMPARE_003] Compare\n",
- " Q: table_4_age_premium에서 30세 남성이 20년납 월보험료로 가입했을 경우, 20년 만기 시점의 총 납입보험료와 table_2_surrender_value의 20년 경과 시점 해지환급금은 얼마나 차이가 나나요?\n",
- " A: 1,200,000원 차이가 납니다.\n",
- " Reasoning: table_4에서 30세 남성의 20년납 월보험료를 찾아 20년간의 총 납입보험료를 계산하고, table_2에서 20년 경과 시점의 해지환급금을 찾아 두 값의 차이를 계산합니다.\n"
- ]
- }
- ],
- "source": [
- "# Compare 난이도 QA 생성 (Multi-hop 추론)\n",
- "print(\"⚖️ Compare (Multi-hop) QA 생성 중...\")\n",
- "\n",
- "compare_qa_pairs = qa_generator.generate_qa_by_difficulty(\n",
- " tables=tables,\n",
- " difficulty=QADifficulty.COMPARE,\n",
- " num_questions=3\n",
- ")\n",
- "\n",
- "print(f\"\\n✅ {len(compare_qa_pairs)}개의 Compare QA 생성 완료\")\n",
- "for qa in compare_qa_pairs:\n",
- " print(f\"\\n📌 [{qa.id}] {qa.difficulty}\")\n",
- " print(f\" Q: {qa.question}\")\n",
- " print(f\" A: {qa.answer}\")\n",
- " if qa.reasoning:\n",
- " print(f\" Reasoning: {qa.reasoning}\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "c91c5b2e",
- "metadata": {},
- "source": [
- "### 4.4 Aggregation - 집계 연산"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 19,
- "id": "c8a555ce",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "➕ Aggregation QA 생성 중...\n",
- "\n",
- "✅ 3개의 Aggregation QA 생성 완료\n",
- "\n",
- "📌 [AGG_001] Aggregation\n",
- " Q: table_1_premium_calculation에서 XX+1세부터 XX+5세까지 '나이증가분(A)'의 총합은 얼마인가요?\n",
- " A: 9239\n",
- " Python 검증 코드 포함: ✅\n",
- "\n",
- "📌 [AGG_002] Aggregation\n",
- " Q: table_2_surrender_value에서 경과기간 1년, 3년, 5년, 10년, 15년, 20년 시점의 '해지환급금'의 평균은 얼마인가요?\n",
- " A: 4590000\n",
- " Python 검증 코드 포함: ✅\n",
- "\n",
- "📌 [AGG_003] Aggregation\n",
- " Q: table_4_age_premium에서 30세 남성이 20년납으로 가입했을 경우, 20년 동안 총 납입해야 할 보험료는 얼마인가요?\n",
- " A: 10800000\n",
- " Python 검증 코드 포함: ✅\n",
- "\n",
- "✅ 3개의 Aggregation QA 생성 완료\n",
- "\n",
- "📌 [AGG_001] Aggregation\n",
- " Q: table_1_premium_calculation에서 XX+1세부터 XX+5세까지 '나이증가분(A)'의 총합은 얼마인가요?\n",
- " A: 9239\n",
- " Python 검증 코드 포함: ✅\n",
- "\n",
- "📌 [AGG_002] Aggregation\n",
- " Q: table_2_surrender_value에서 경과기간 1년, 3년, 5년, 10년, 15년, 20년 시점의 '해지환급금'의 평균은 얼마인가요?\n",
- " A: 4590000\n",
- " Python 검증 코드 포함: ✅\n",
- "\n",
- "📌 [AGG_003] Aggregation\n",
- " Q: table_4_age_premium에서 30세 남성이 20년납으로 가입했을 경우, 20년 동안 총 납입해야 할 보험료는 얼마인가요?\n",
- " A: 10800000\n",
- " Python 검증 코드 포함: ✅\n"
- ]
- }
- ],
- "source": [
- "# Aggregation 난이도 QA 생성 (수치 계산)\n",
- "print(\"➕ Aggregation QA 생성 중...\")\n",
- "\n",
- "agg_qa_pairs = qa_generator.generate_qa_by_difficulty(\n",
- " tables=tables,\n",
- " difficulty=QADifficulty.AGGREGATION,\n",
- " num_questions=3\n",
- ")\n",
- "\n",
- "print(f\"\\n✅ {len(agg_qa_pairs)}개의 Aggregation QA 생성 완료\")\n",
- "for qa in agg_qa_pairs:\n",
- " print(f\"\\n📌 [{qa.id}] {qa.difficulty}\")\n",
- " print(f\" Q: {qa.question}\")\n",
- " print(f\" A: {qa.answer}\")\n",
- " if qa.python_verification:\n",
- " print(f\" Python 검증 코드 포함: ✅\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "05f6c85e",
- "metadata": {},
- "source": [
- "### 4.5 Reasoning - 복합 추론"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 20,
- "id": "0a3ce609",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "🧠 Reasoning QA 생성 중...\n",
- "\n",
- "✅ 3개의 Reasoning QA 생성 완료\n",
- "\n",
- "📌 [REASON_001] Reasoning\n",
- " Q: 30세 남성이 20년납 월보험료로 가입했을 때, `table_1`의 '기준보험료' 증가율이 '월보험료'에 동일하게 적용된다고 가정하면, 가입 후 3년이 지난 시점(즉, 33세)의 월보험료는 얼마가 될까요?\n",
- " A: 약 94,658원\n",
- " Chain of Thought:\n",
- " Step 1: Step 1: `table_4`에서 30세 남성의 20년납 월보험료를 확인합니다: 45,000원.\n",
- " Step 2: Step 2: `table_1`에서 'XX세'를 30세로 가정하고, 'XX세' (30세)의 기준보험료(C)는 42,325원, 'XX+3세' (33세)의 기준보험료(C)는 89,030원임을 확인합니다.\n",
- " Step 3: Step 3: 30세 대비 33세의 기준보험료 증가율을 계산합니다: (89,030 / 42,325).\n",
- " Step 4: Step 4: 이 증가율을 30세 남성의 초기 월보험료에 적용하여 33세의 월보험료를 계산합니다: 45,000원 * (89,030 / 42,325) = 94,657.76...\n",
- " Step 5: Step 5: 계산된 값을 반올림하여 최종 월보험료를 도출합니다.\n",
- "\n",
- "📌 [REASON_002] Reasoning\n",
- " Q: 3년 동안 보험료를 납입한 계약자가 일반암 진단을 받고, 진단금을 수령한 직후 보험을 해지한다면, 이 계약자가 총 얼마의 금액을 받게 될까요? (단, 납입보험료는 해지환급금 계산에만 영향을 미치며, 진단금 수령 시점까지의 납입보험료는 해지환급금 누계에 포함된다고 가정합니다.)\n",
- " A: 30,540,000원\n",
- " Chain of Thought:\n",
- " Step 1: Step 1: `table_3`에서 '일반암' 진단금을 확인합니다: 30,000,000원.\n",
- " Step 2: Step 2: `table_2`에서 '경과기간' 3년 시점의 '해지환급금'을 확인합니다: 540,000원.\n",
- " Step 3: Step 3: 계약자가 받게 될 총 금액은 '일반암 진단금'과 '해지환급금'의 합계입니다.\n",
- " Step 4: Step 4: 총 수령액 = 30,000,000원 + 540,000원 = 30,540,000원.\n",
- "\n",
- "📌 [REASON_003] Reasoning\n",
- " Q: 40세 남성과 40세 여성이 각각 20년납으로 보험에 가입했다고 가정합니다. 두 사람 모두 가입 후 5년이 지난 시점에 일반암 진단을 받고, 10일간 암으로 입원했으며, 1회의 암수술을 받았을 경우, 다음 두 가지 질문에 답하세요.\n",
- "1. 두 사람이 5년간 납입한 총 보험료의 차이는 얼마입니까?\n",
- "2. 두 사람이 받게 되는 총 보장금액의 차이는 얼마입니까?\n",
- " A: 1. 5년간 납입 총 보험료 차이: 420,000원\n",
- "2. 총 보장금액 차이: 0원\n",
- " Chain of Thought:\n",
- " Step 1: Step 1: `table_4`에서 40세 남성과 40세 여성의 20년납 월보험료를 확인합니다.\n",
- " Step 2: - 40세 남성: 65,000원\n",
- " Step 3: - 40세 여성: 58,000원\n",
- " Step 4: Step 2: 각 성별로 5년간 납입할 총 보험료를 계산합니다 (월보험료 * 12개월 * 5년).\n",
- " Step 5: - 남성 총 납입 보험료: 65,000원 * 12 * 5 = 3,900,000원\n",
- " Step 6: - 여성 총 납입 보험료: 58,000원 * 12 * 5 = 3,480,000원\n",
- " Step 7: Step 3: 두 사람의 5년간 납입 총 보험료 차이를 계산합니다: 3,900,000원 - 3,480,000원 = 420,000원.\n",
- " Step 8: Step 4: `table_3`에서 일반암 진단금, 암입원비 (10일), 암수술비 (1회)를 확인합니다.\n",
- " Step 9: - 일반암 진단금: 30,000,000원\n",
- " Step 10: - 암입원비: 100,000원 (1일당) * 10일 = 1,000,000원\n",
- " Step 11: - 암수술비: 2,000,000원 (1회당)\n",
- " Step 12: Step 5: 각 사람이 받게 되는 총 보장금액을 계산합니다 (성별에 따른 보장금액 차이는 `table_3`에 명시되어 있지 않으므로 동일하다고 가정).\n",
- " Step 13: - 총 보장금액 = 30,000,000원 + 1,000,000원 + 2,000,000원 = 33,000,000원.\n",
- " Step 14: Step 6: 두 사람의 총 보장금액 차이를 계산합니다: 33,000,000원 - 33,000,000원 = 0원.\n",
- "\n",
- "✅ 3개의 Reasoning QA 생성 완료\n",
- "\n",
- "📌 [REASON_001] Reasoning\n",
- " Q: 30세 남성이 20년납 월보험료로 가입했을 때, `table_1`의 '기준보험료' 증가율이 '월보험료'에 동일하게 적용된다고 가정하면, 가입 후 3년이 지난 시점(즉, 33세)의 월보험료는 얼마가 될까요?\n",
- " A: 약 94,658원\n",
- " Chain of Thought:\n",
- " Step 1: Step 1: `table_4`에서 30세 남성의 20년납 월보험료를 확인합니다: 45,000원.\n",
- " Step 2: Step 2: `table_1`에서 'XX세'를 30세로 가정하고, 'XX세' (30세)의 기준보험료(C)는 42,325원, 'XX+3세' (33세)의 기준보험료(C)는 89,030원임을 확인합니다.\n",
- " Step 3: Step 3: 30세 대비 33세의 기준보험료 증가율을 계산합니다: (89,030 / 42,325).\n",
- " Step 4: Step 4: 이 증가율을 30세 남성의 초기 월보험료에 적용하여 33세의 월보험료를 계산합니다: 45,000원 * (89,030 / 42,325) = 94,657.76...\n",
- " Step 5: Step 5: 계산된 값을 반올림하여 최종 월보험료를 도출합니다.\n",
- "\n",
- "📌 [REASON_002] Reasoning\n",
- " Q: 3년 동안 보험료를 납입한 계약자가 일반암 진단을 받고, 진단금을 수령한 직후 보험을 해지한다면, 이 계약자가 총 얼마의 금액을 받게 될까요? (단, 납입보험료는 해지환급금 계산에만 영향을 미치며, 진단금 수령 시점까지의 납입보험료는 해지환급금 누계에 포함된다고 가정합니다.)\n",
- " A: 30,540,000원\n",
- " Chain of Thought:\n",
- " Step 1: Step 1: `table_3`에서 '일반암' 진단금을 확인합니다: 30,000,000원.\n",
- " Step 2: Step 2: `table_2`에서 '경과기간' 3년 시점의 '해지환급금'을 확인합니다: 540,000원.\n",
- " Step 3: Step 3: 계약자가 받게 될 총 금액은 '일반암 진단금'과 '해지환급금'의 합계입니다.\n",
- " Step 4: Step 4: 총 수령액 = 30,000,000원 + 540,000원 = 30,540,000원.\n",
- "\n",
- "📌 [REASON_003] Reasoning\n",
- " Q: 40세 남성과 40세 여성이 각각 20년납으로 보험에 가입했다고 가정합니다. 두 사람 모두 가입 후 5년이 지난 시점에 일반암 진단을 받고, 10일간 암으로 입원했으며, 1회의 암수술을 받았을 경우, 다음 두 가지 질문에 답하세요.\n",
- "1. 두 사람이 5년간 납입한 총 보험료의 차이는 얼마입니까?\n",
- "2. 두 사람이 받게 되는 총 보장금액의 차이는 얼마입니까?\n",
- " A: 1. 5년간 납입 총 보험료 차이: 420,000원\n",
- "2. 총 보장금액 차이: 0원\n",
- " Chain of Thought:\n",
- " Step 1: Step 1: `table_4`에서 40세 남성과 40세 여성의 20년납 월보험료를 확인합니다.\n",
- " Step 2: - 40세 남성: 65,000원\n",
- " Step 3: - 40세 여성: 58,000원\n",
- " Step 4: Step 2: 각 성별로 5년간 납입할 총 보험료를 계산합니다 (월보험료 * 12개월 * 5년).\n",
- " Step 5: - 남성 총 납입 보험료: 65,000원 * 12 * 5 = 3,900,000원\n",
- " Step 6: - 여성 총 납입 보험료: 58,000원 * 12 * 5 = 3,480,000원\n",
- " Step 7: Step 3: 두 사람의 5년간 납입 총 보험료 차이를 계산합니다: 3,900,000원 - 3,480,000원 = 420,000원.\n",
- " Step 8: Step 4: `table_3`에서 일반암 진단금, 암입원비 (10일), 암수술비 (1회)를 확인합니다.\n",
- " Step 9: - 일반암 진단금: 30,000,000원\n",
- " Step 10: - 암입원비: 100,000원 (1일당) * 10일 = 1,000,000원\n",
- " Step 11: - 암수술비: 2,000,000원 (1회당)\n",
- " Step 12: Step 5: 각 사람이 받게 되는 총 보장금액을 계산합니다 (성별에 따른 보장금액 차이는 `table_3`에 명시되어 있지 않으므로 동일하다고 가정).\n",
- " Step 13: - 총 보장금액 = 30,000,000원 + 1,000,000원 + 2,000,000원 = 33,000,000원.\n",
- " Step 14: Step 6: 두 사람의 총 보장금액 차이를 계산합니다: 33,000,000원 - 33,000,000원 = 0원.\n"
- ]
- }
- ],
- "source": [
- "# Reasoning 난이도 QA 생성 (Chain-of-Thought)\n",
- "print(\"🧠 Reasoning QA 생성 중...\")\n",
- "\n",
- "reasoning_qa_pairs = qa_generator.generate_qa_by_difficulty(\n",
- " tables=tables,\n",
- " difficulty=QADifficulty.REASONING,\n",
- " num_questions=3\n",
- ")\n",
- "\n",
- "print(f\"\\n✅ {len(reasoning_qa_pairs)}개의 Reasoning QA 생성 완료\")\n",
- "for qa in reasoning_qa_pairs:\n",
- " print(f\"\\n📌 [{qa.id}] {qa.difficulty}\")\n",
- " print(f\" Q: {qa.question}\")\n",
- " print(f\" A: {qa.answer}\")\n",
- " if qa.chain_of_thought:\n",
- " print(f\" Chain of Thought:\")\n",
- " for i, step in enumerate(qa.chain_of_thought, 1):\n",
- " print(f\" Step {i}: {step}\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "8c33297d",
- "metadata": {},
- "source": [
- "### 4.6 Insight - 통찰 도출"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 21,
- "id": "72b940c2",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "💡 Insight QA 생성 중...\n",
- "\n",
- "✅ 2개의 Insight QA 생성 완료\n",
- "\n",
- "📌 [INSIGHT_001] Insight\n",
- " Q: 이 보험 상품의 해지환급금 데이터를 분석했을 때, 조기 해지가 고객에게 미치는 재정적 영향은 무엇이며, 이는 상품 설계 철학에 대해 어떤 시사점을 제공합니까?\n",
- " A: 이 보험 상품을 조기에 해지할 경우, 고객은 상당한 재정적 손실을 입게 됩니다. 예를 들어, 1년 경과 후 해지 시 납입보험료 누계의 0%만 환급되며, 3년 후에도 30%만 돌려받습니다. 납입한 원금(환급률 100%)을 온전히 돌려받으려면 20년 만기까지 유지해야 합니다. 이는 이 상품이 장기적인 보장과 유지를 전제로 설계되었으며, 단기 해지에 대해 높은 ...\n",
- "\n",
- "📌 [INSIGHT_002] Insight\n",
- " Q: 보험료 산출 구성 요소와 연령 및 성별에 따른 월 보험료 데이터를 종합적으로 고려할 때, 이 보험 상품이 위험을 평가하고 보험료를 책정하는 방식에 대해 어떤 통찰을 얻을 수 있으며, 특히 연령이 증가함에 따라 위험 평가가 어떻게 변화하는 것으로 보입니까?\n",
- " A: 이 보험 상품은 연령이 증가함에 따라 위험 관련 요소를 보험료 산출에 매우 중요하게 반영하고 있습니다. `table_1`에서 '나이증가분(A)'보다 '보험료 산출 기초율(위험률 등) 증가분(B)'이 훨씬 더 큰 폭으로 보험료를 상승시키는 주요 요인임을 알 수 있습니다. 이는 연령이 높아질수록 질병 발생률이나 사고 위험 등 보험사가 인지하는 위험도가 급격히 ...\n",
- "\n",
- "✅ 2개의 Insight QA 생성 완료\n",
- "\n",
- "📌 [INSIGHT_001] Insight\n",
- " Q: 이 보험 상품의 해지환급금 데이터를 분석했을 때, 조기 해지가 고객에게 미치는 재정적 영향은 무엇이며, 이는 상품 설계 철학에 대해 어떤 시사점을 제공합니까?\n",
- " A: 이 보험 상품을 조기에 해지할 경우, 고객은 상당한 재정적 손실을 입게 됩니다. 예를 들어, 1년 경과 후 해지 시 납입보험료 누계의 0%만 환급되며, 3년 후에도 30%만 돌려받습니다. 납입한 원금(환급률 100%)을 온전히 돌려받으려면 20년 만기까지 유지해야 합니다. 이는 이 상품이 장기적인 보장과 유지를 전제로 설계되었으며, 단기 해지에 대해 높은 ...\n",
- "\n",
- "📌 [INSIGHT_002] Insight\n",
- " Q: 보험료 산출 구성 요소와 연령 및 성별에 따른 월 보험료 데이터를 종합적으로 고려할 때, 이 보험 상품이 위험을 평가하고 보험료를 책정하는 방식에 대해 어떤 통찰을 얻을 수 있으며, 특히 연령이 증가함에 따라 위험 평가가 어떻게 변화하는 것으로 보입니까?\n",
- " A: 이 보험 상품은 연령이 증가함에 따라 위험 관련 요소를 보험료 산출에 매우 중요하게 반영하고 있습니다. `table_1`에서 '나이증가분(A)'보다 '보험료 산출 기초율(위험률 등) 증가분(B)'이 훨씬 더 큰 폭으로 보험료를 상승시키는 주요 요인임을 알 수 있습니다. 이는 연령이 높아질수록 질병 발생률이나 사고 위험 등 보험사가 인지하는 위험도가 급격히 ...\n"
- ]
- }
- ],
- "source": [
- "# Insight 난이도 QA 생성 (서술형)\n",
- "print(\"💡 Insight QA 생성 중...\")\n",
- "\n",
- "insight_qa_pairs = qa_generator.generate_qa_by_difficulty(\n",
- " tables=tables,\n",
- " difficulty=QADifficulty.INSIGHT,\n",
- " num_questions=2\n",
- ")\n",
- "\n",
- "print(f\"\\n✅ {len(insight_qa_pairs)}개의 Insight QA 생성 완료\")\n",
- "for qa in insight_qa_pairs:\n",
- " print(f\"\\n📌 [{qa.id}] {qa.difficulty}\")\n",
- " print(f\" Q: {qa.question}\")\n",
- " print(f\" A: {qa.answer[:200]}...\" if len(qa.answer) > 200 else f\" A: {qa.answer}\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "15f40c4d",
- "metadata": {},
- "source": [
- "## 5. Multi-Table QA 생성\n",
- "\n",
- "복수의 테이블을 참조해야 답변 가능한 질문을 생성합니다."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 22,
- "id": "2dbbbad2",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "🔗 Multi-Table QA 생성 중...\n",
- "\n",
- "✅ 3개의 Multi-Table QA 생성 완료\n",
- "\n",
- "📌 [MULTI_001] Reasoning\n",
- " Q: table_2에서 10년 경과 시점의 납입보험료 누계가 6,000,000원일 때, 만약 이 보험이 20년납 상품이었다면 월 평균 보험료는 얼마였을까요? 그리고 이 월 평균 보험료는 table_4의 30세 남성 20년납 월보험료(45,000원)와 비교했을 때 얼마나 차이가 나나요?\n",
- " A: table_2의 10년 경과 시점 납입보험료 누계(6,000,000원)를 기준으로 20년납 상품의 월 평균 보험료를 계산하면 50,000원입니다. 이는 table_4의 30세 남성 20년납 월보험료(45,000원)보다 5,000원 더 높은 금액입니다.\n",
- "\n",
- "📌 [MULTI_002] Calculation\n",
- " Q: table_4에서 40세 여성이 전기납 월보험료 상품에 가입했다고 할 때, 이 보험료가 table_1의 'XX세' 기준보험료(C)에 해당한다고 가정합니다. 이 경우, 'XX+2세' 시점의 기준보험료는 얼마로 예상할 수 있을까요? (단, table_1의 나이증가분(A)와 보험료 산출 기초율 증가분(B)는 table_1의 해당 값을 따릅니다.)\n",
- " A: table_4의 40세 여성 전기납 월보험료 47,000원을 'XX세' 기준보험료로 가정하면, 'XX+1세' 시점의 기준보험료는 47,000 + 1,059 + 10,846 = 58,905원입니다. 이어서 'XX+2세' 시점의 기준보험료는 58,905 + 1,357 + 13,897 = 74,159원입니다.\n",
- "\n",
- "📌 [MULTI_003] Reasoning\n",
- " Q: 40세 남성이 20년납 월보험료 상품에 가입하여 5년 동안 보험료를 납입했을 경우, 총 납입한 보험료는 얼마인가요? 만약 이 시점에 일반암 진단을 받았다면, 총 납입 보험료 대비 암진단금은 몇 배에 해당하나요? 또한, 만약 이 보험의 해지환급금이 table_2의 '5년 경과' 시점의 납입보험료 누계(3,000,000원)에 해당하는 해지환급금과 동일하다고 가정할 때, 암진단금은 해지환급금보다 얼마나 더 많은 금액인가요?\n",
- " A: 40세 남성이 5년 동안 납입한 총 보험료는 3,900,000원입니다. 이 시점에 일반암 진단을 받았다면, 총 납입 보험료 대비 암진단금(30,000,000원)은 약 7.69배에 해당합니다. 또한, table_2의 5년 경과 시점 해지환급금(1,650,000원)과 비교했을 때, 암진단금은 해지환급금보다 28,350,000원 더 많은 금액입니다.\n",
- "\n",
- "✅ 3개의 Multi-Table QA 생성 완료\n",
- "\n",
- "📌 [MULTI_001] Reasoning\n",
- " Q: table_2에서 10년 경과 시점의 납입보험료 누계가 6,000,000원일 때, 만약 이 보험이 20년납 상품이었다면 월 평균 보험료는 얼마였을까요? 그리고 이 월 평균 보험료는 table_4의 30세 남성 20년납 월보험료(45,000원)와 비교했을 때 얼마나 차이가 나나요?\n",
- " A: table_2의 10년 경과 시점 납입보험료 누계(6,000,000원)를 기준으로 20년납 상품의 월 평균 보험료를 계산하면 50,000원입니다. 이는 table_4의 30세 남성 20년납 월보험료(45,000원)보다 5,000원 더 높은 금액입니다.\n",
- "\n",
- "📌 [MULTI_002] Calculation\n",
- " Q: table_4에서 40세 여성이 전기납 월보험료 상품에 가입했다고 할 때, 이 보험료가 table_1의 'XX세' 기준보험료(C)에 해당한다고 가정합니다. 이 경우, 'XX+2세' 시점의 기준보험료는 얼마로 예상할 수 있을까요? (단, table_1의 나이증가분(A)와 보험료 산출 기초율 증가분(B)는 table_1의 해당 값을 따릅니다.)\n",
- " A: table_4의 40세 여성 전기납 월보험료 47,000원을 'XX세' 기준보험료로 가정하면, 'XX+1세' 시점의 기준보험료는 47,000 + 1,059 + 10,846 = 58,905원입니다. 이어서 'XX+2세' 시점의 기준보험료는 58,905 + 1,357 + 13,897 = 74,159원입니다.\n",
- "\n",
- "📌 [MULTI_003] Reasoning\n",
- " Q: 40세 남성이 20년납 월보험료 상품에 가입하여 5년 동안 보험료를 납입했을 경우, 총 납입한 보험료는 얼마인가요? 만약 이 시점에 일반암 진단을 받았다면, 총 납입 보험료 대비 암진단금은 몇 배에 해당하나요? 또한, 만약 이 보험의 해지환급금이 table_2의 '5년 경과' 시점의 납입보험료 누계(3,000,000원)에 해당하는 해지환급금과 동일하다고 가정할 때, 암진단금은 해지환급금보다 얼마나 더 많은 금액인가요?\n",
- " A: 40세 남성이 5년 동안 납입한 총 보험료는 3,900,000원입니다. 이 시점에 일반암 진단을 받았다면, 총 납입 보험료 대비 암진단금(30,000,000원)은 약 7.69배에 해당합니다. 또한, table_2의 5년 경과 시점 해지환급금(1,650,000원)과 비교했을 때, 암진단금은 해지환급금보다 28,350,000원 더 많은 금액입니다.\n"
- ]
- }
- ],
- "source": [
- "# Multi-Table QA 생성\n",
- "print(\"🔗 Multi-Table QA 생성 중...\")\n",
- "\n",
- "multi_table_qa = qa_generator.generate_multi_table_qa(\n",
- " tables=tables,\n",
- " num_questions=3\n",
- ")\n",
- "\n",
- "print(f\"\\n✅ {len(multi_table_qa)}개의 Multi-Table QA 생성 완료\")\n",
- "for qa in multi_table_qa:\n",
- " print(f\"\\n📌 [{qa.id}] {qa.difficulty}\")\n",
- " print(f\" Q: {qa.question}\")\n",
- " print(f\" A: {qa.answer}\")\n",
- " if qa.evidence and 'required_tables' in str(qa.evidence):\n",
- " print(f\" 참조 테이블: {qa.evidence}\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "cc4df731",
- "metadata": {},
- "source": [
- "## 6. 꼬리 질문 (Follow-up) 생성\n",
- "\n",
- "특정 QA에 대해 연속적인 후속 질문 체인을 생성합니다."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 23,
- "id": "d2c2b8a1",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "🔄 Follow-up QA 생성 중...\n",
- "\n",
- "원본 QA:\n",
- " Q: XX세의 기준보험료는 얼마인가요?\n",
- " A: 42325\n",
- "\n",
- "✅ 3개의 Follow-up QA 생성 완료\n",
- "\n",
- " 🔹 Follow-up 1:\n",
- " Q: XX세에서 XX+1세로 나이가 증가할 때, 기준보험료는 얼마나 증가하나요?\n",
- " A: XX세의 기준보험료는 42325원이고, XX+1세의 기준보험료는 54321원이므로, 54321 - 42325 = 11996원 증가합니다.\n",
- "\n",
- " 🔹 Follow-up 2:\n",
- " Q: 이 11996원의 기준보험료 증가분은 주로 '나이증가분(A)'과 '보험료 산출 기초율(위험률 등) 증가분(B)' 중 어떤 요인에 의해 발생한 것인가요?\n",
- " A: XX+1세의 '나이증가분(A)'은 1059원이고, '보험료 산출 기초율(위험률 등) 증가분(B)'은 10846원입니다. 두 요인 중 '보험료 산출 기초율(위험률 등) 증가분(B)'이 훨씬 크므로, 주로 이 요인에 의해 기준보험료가 증가했습니다.\n",
- "\n",
- " 🔹 Follow-up 3:\n",
- " Q: '보험료 산출 기초율(위험률 등) 증가분(B)'이 '전년도 기준보험료의 최대 25% 가정'이라는 설명에 따르면, XX+1세의 B값(10846원)은 XX세의 기준보험료(42325원)의 25%를 초과하나요?\n",
- " A: XX세의 기준보험료 42325원의 25%는 42325 * 0.25 = 10581.25원입니다. XX+1세의 '보험료 산출 기초율 증가분(B)'은 10846원이므로, 10581.25원을 초과합니다.\n",
- "\n",
- "✅ 3개의 Follow-up QA 생성 완료\n",
- "\n",
- " 🔹 Follow-up 1:\n",
- " Q: XX세에서 XX+1세로 나이가 증가할 때, 기준보험료는 얼마나 증가하나요?\n",
- " A: XX세의 기준보험료는 42325원이고, XX+1세의 기준보험료는 54321원이므로, 54321 - 42325 = 11996원 증가합니다.\n",
- "\n",
- " 🔹 Follow-up 2:\n",
- " Q: 이 11996원의 기준보험료 증가분은 주로 '나이증가분(A)'과 '보험료 산출 기초율(위험률 등) 증가분(B)' 중 어떤 요인에 의해 발생한 것인가요?\n",
- " A: XX+1세의 '나이증가분(A)'은 1059원이고, '보험료 산출 기초율(위험률 등) 증가분(B)'은 10846원입니다. 두 요인 중 '보험료 산출 기초율(위험률 등) 증가분(B)'이 훨씬 크므로, 주로 이 요인에 의해 기준보험료가 증가했습니다.\n",
- "\n",
- " 🔹 Follow-up 3:\n",
- " Q: '보험료 산출 기초율(위험률 등) 증가분(B)'이 '전년도 기준보험료의 최대 25% 가정'이라는 설명에 따르면, XX+1세의 B값(10846원)은 XX세의 기준보험료(42325원)의 25%를 초과하나요?\n",
- " A: XX세의 기준보험료 42325원의 25%는 42325 * 0.25 = 10581.25원입니다. XX+1세의 '보험료 산출 기초율 증가분(B)'은 10846원이므로, 10581.25원을 초과합니다.\n"
- ]
- }
- ],
- "source": [
- "# 꼬리 질문 생성 (IR QA 기반)\n",
- "if ir_qa_pairs:\n",
- " print(\"🔄 Follow-up QA 생성 중...\")\n",
- " \n",
- " original_qa = ir_qa_pairs[0]\n",
- " print(f\"\\n원본 QA:\")\n",
- " print(f\" Q: {original_qa.question}\")\n",
- " print(f\" A: {original_qa.answer}\")\n",
- " \n",
- " followup_result = qa_generator.generate_followup_qa(\n",
- " tables=tables,\n",
- " original_qa=original_qa\n",
- " )\n",
- " \n",
- " if followup_result and 'followup_chain' in followup_result:\n",
- " print(f\"\\n✅ {len(followup_result['followup_chain'])}개의 Follow-up QA 생성 완료\")\n",
- " for i, followup in enumerate(followup_result['followup_chain'], 1):\n",
- " print(f\"\\n 🔹 Follow-up {i}:\")\n",
- " print(f\" Q: {followup.get('question', 'N/A')}\")\n",
- " print(f\" A: {followup.get('answer', 'N/A')}\")\n",
- " else:\n",
- " print(f\"\\n결과: {followup_result}\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "c1b07346",
- "metadata": {},
- "source": [
- "## 7. Evol-Instruct: 질문 난이도 진화\n",
- "\n",
- "기본 질문을 더 복잡한 질문으로 진화시킵니다."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 24,
- "id": "1ea8a3b0",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "🧬 Evol-Instruct 적용 중...\n",
- "\n",
- "원본 질문: 40세 남성의 20년납 월보험료는 얼마인가?\n",
- "\n",
- "✅ 진화 완료\n",
- " 진화 전략: 제약 조건 추가 (Adding Constraints), 심층 추론 (Deepening Reasoning), 입력 복잡도 증가 (Complicating Input)\n",
- " 진화된 질문: 40세 남성이 20년납으로 보험에 가입할 경우 월보험료는 65,000원이다. 만약 이 남성이 10년 뒤인 50세에 동일한 조건으로 가입한다면 월보험료는 얼마로 예상되는가? 그리고 table_1_premium_calculation 데이터를 참조하여 나이가 증가함에 따라 보험료가 상승하는 주요 원인 두 가지를 설명하시오.\n",
- " 새로운 난이도: Reasoning (Level 5)\n",
- " 답변: 50세에 동일한 조건으로 가입한다면 월보험료는 95,000원으로 예상됩니다. 보험료가 나이가 증가함에 따라 상승하는 주요 원인은 '나이증가분(A)'과 '보험료 산출 기초율(위험률 등) 증가분(B)'입니다. 이 두 가지 요소가 전년도 기준보험료에 더해져 새로운 기준보험료(C)를 형성하기 때문입니다.\n",
- "\n",
- "✅ 진화 완료\n",
- " 진화 전략: 제약 조건 추가 (Adding Constraints), 심층 추론 (Deepening Reasoning), 입력 복잡도 증가 (Complicating Input)\n",
- " 진화된 질문: 40세 남성이 20년납으로 보험에 가입할 경우 월보험료는 65,000원이다. 만약 이 남성이 10년 뒤인 50세에 동일한 조건으로 가입한다면 월보험료는 얼마로 예상되는가? 그리고 table_1_premium_calculation 데이터를 참조하여 나이가 증가함에 따라 보험료가 상승하는 주요 원인 두 가지를 설명하시오.\n",
- " 새로운 난이도: Reasoning (Level 5)\n",
- " 답변: 50세에 동일한 조건으로 가입한다면 월보험료는 95,000원으로 예상됩니다. 보험료가 나이가 증가함에 따라 상승하는 주요 원인은 '나이증가분(A)'과 '보험료 산출 기초율(위험률 등) 증가분(B)'입니다. 이 두 가지 요소가 전년도 기준보험료에 더해져 새로운 기준보험료(C)를 형성하기 때문입니다.\n"
- ]
- }
- ],
- "source": [
- "# Evol-Instruct 적용\n",
- "print(\"🧬 Evol-Instruct 적용 중...\")\n",
- "\n",
- "# 간단한 질문에서 시작\n",
- "simple_question = \"40세 남성의 20년납 월보험료는 얼마인가?\"\n",
- "print(f\"\\n원본 질문: {simple_question}\")\n",
- "\n",
- "evolved_result = qa_generator.evolve_question(\n",
- " tables=tables,\n",
- " original_question=simple_question\n",
- ")\n",
- "\n",
- "if evolved_result and 'evolved' in evolved_result:\n",
- " evolved = evolved_result['evolved']\n",
- " print(f\"\\n✅ 진화 완료\")\n",
- " print(f\" 진화 전략: {evolved.get('evolution_strategy', 'N/A')}\")\n",
- " print(f\" 진화된 질문: {evolved.get('question', 'N/A')}\")\n",
- " print(f\" 새로운 난이도: {evolved.get('difficulty', 'N/A')}\")\n",
- " print(f\" 답변: {evolved.get('answer', 'N/A')}\")\n",
- "else:\n",
- " print(f\"\\n결과: {evolved_result}\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "4ca79e89",
- "metadata": {},
- "source": [
- "## 8. LLM-as-Judge: 품질 평가"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 25,
- "id": "287c2e34",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "⚖️ QA 품질 평가 중...\n",
- "\n",
- "평가 대상 QA:\n",
- " Q: XX세의 기준보험료는 얼마인가요?\n",
- " A: 42325\n",
- "\n",
- "✅ 평가 완료\n",
- " 📊 Overall Score: 5.0/5.0\n",
- " ✓ Pass: 예\n",
- "\n",
- " 세부 점수:\n",
- " - 정확성: 5\n",
- " - 충실성: 5\n",
- " - 관련성: 5\n",
- " - 난이도 적절성: 5\n",
- " - 명확성: 5\n",
- "\n",
- "✅ 평가 완료\n",
- " 📊 Overall Score: 5.0/5.0\n",
- " ✓ Pass: 예\n",
- "\n",
- " 세부 점수:\n",
- " - 정확성: 5\n",
- " - 충실성: 5\n",
- " - 관련성: 5\n",
- " - 난이도 적절성: 5\n",
- " - 명확성: 5\n"
- ]
- }
- ],
- "source": [
- "# QA 품질 평가\n",
- "if ir_qa_pairs:\n",
- " print(\"⚖️ QA 품질 평가 중...\")\n",
- " \n",
- " qa_to_evaluate = ir_qa_pairs[0]\n",
- " print(f\"\\n평가 대상 QA:\")\n",
- " print(f\" Q: {qa_to_evaluate.question}\")\n",
- " print(f\" A: {qa_to_evaluate.answer}\")\n",
- " \n",
- " evaluation = qa_generator.evaluate_qa(\n",
- " tables=tables,\n",
- " qa_pair=qa_to_evaluate\n",
- " )\n",
- " \n",
- " if evaluation:\n",
- " print(f\"\\n✅ 평가 완료\")\n",
- " print(f\" 📊 Overall Score: {evaluation.overall_score}/5.0\")\n",
- " print(f\" ✓ Pass: {'예' if evaluation.passed else '아니오'}\")\n",
- " print(f\"\\n 세부 점수:\")\n",
- " print(f\" - 정확성: {evaluation.correctness.get('score', 'N/A')}\")\n",
- " print(f\" - 충실성: {evaluation.faithfulness.get('score', 'N/A')}\")\n",
- " print(f\" - 관련성: {evaluation.relevance.get('score', 'N/A')}\")\n",
- " print(f\" - 난이도 적절성: {evaluation.difficulty_appropriateness.get('score', 'N/A')}\")\n",
- " print(f\" - 명확성: {evaluation.clarity.get('score', 'N/A')}\")\n",
- " \n",
- " if evaluation.improvement_suggestions:\n",
- " print(f\"\\n 💡 개선 제안:\")\n",
- " for suggestion in evaluation.improvement_suggestions:\n",
- " print(f\" - {suggestion}\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "5dcbcf93",
- "metadata": {},
- "source": [
- "## 9. 종합 QA 데이터셋 생성\n",
- "\n",
- "모든 난이도의 QA를 한 번에 생성하고 데이터셋으로 저장합니다."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "342690ff",
- "metadata": {},
- "outputs": [],
- "source": [
- "# 종합 QA 데이터셋 생성\n",
- "print(\"📦 종합 QA 데이터셋 생성 중...\")\n",
- "print(\" (모든 난이도 + Follow-up + Evol-Instruct)\")\n",
- "print(\" ⏳ 약 2-3분 소요될 수 있습니다...\\n\")\n",
- "\n",
- "comprehensive_dataset = qa_generator.generate_comprehensive_qa_dataset(\n",
- " tables=tables,\n",
- " questions_per_difficulty=2,\n",
- " include_followup=True,\n",
- " include_evolution=True,\n",
- " evaluate_quality=False # 평가는 시간이 오래 걸려서 선택적으로\n",
- ")\n",
- "\n",
- "print(\"\\n\" + \"=\"*60)\n",
- "print(\"📊 데이터셋 생성 결과\")\n",
- "print(\"=\"*60)\n",
- "print(f\" 총 QA 쌍: {comprehensive_dataset['metadata'].get('total_qa_pairs', 0)}개\")\n",
- "print(f\" Follow-up 체인: {comprehensive_dataset['metadata'].get('total_followups', 0)}개\")\n",
- "print(f\" 진화된 질문: {comprehensive_dataset['metadata'].get('total_evolved', 0)}개\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "c24832a3",
- "metadata": {},
- "outputs": [],
- "source": [
- "# 생성된 QA 미리보기\n",
- "print(\"\\n📋 생성된 QA 샘플 (난이도별 1개씩):\")\n",
- "print(\"=\"*60)\n",
- "\n",
- "shown_difficulties = set()\n",
- "for qa in comprehensive_dataset['qa_pairs']:\n",
- " difficulty = qa.get('difficulty', 'Unknown')\n",
- " if difficulty not in shown_difficulties:\n",
- " shown_difficulties.add(difficulty)\n",
- " print(f\"\\n🔹 [{difficulty}]\")\n",
- " print(f\" Q: {qa.get('question', 'N/A')}\")\n",
- " answer = qa.get('answer', 'N/A')\n",
- " if len(str(answer)) > 150:\n",
- " print(f\" A: {str(answer)[:150]}...\")\n",
- " else:\n",
- " print(f\" A: {answer}\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "48fda52a",
- "metadata": {},
- "source": [
- "## 10. 데이터셋 저장"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "7a74e734",
- "metadata": {},
- "outputs": [],
- "source": [
- "# 출력 디렉토리 생성\n",
- "output_dir = Path.cwd() / \"output\"\n",
- "output_dir.mkdir(exist_ok=True)\n",
- "\n",
- "# 타임스탬프 생성\n",
- "timestamp = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n",
- "\n",
- "# JSON 파일로 저장\n",
- "output_file = output_dir / f\"insurance_qa_dataset_{timestamp}.json\"\n",
- "\n",
- "with open(output_file, 'w', encoding='utf-8') as f:\n",
- " json.dump(comprehensive_dataset, f, ensure_ascii=False, indent=2)\n",
- "\n",
- "print(f\"✅ 데이터셋 저장 완료: {output_file}\")\n",
- "print(f\" 파일 크기: {output_file.stat().st_size / 1024:.1f} KB\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "2669b33d",
- "metadata": {},
- "outputs": [],
- "source": [
- "# 간단한 통계 출력용 함수\n",
- "def print_dataset_statistics(dataset: dict):\n",
- " \"\"\"데이터셋 통계 출력\"\"\"\n",
- " print(\"\\n\" + \"=\"*60)\n",
- " print(\"📈 QA 데이터셋 통계\")\n",
- " print(\"=\"*60)\n",
- " \n",
- " # 난이도별 카운트\n",
- " difficulty_counts = {}\n",
- " answer_type_counts = {}\n",
- " \n",
- " for qa in dataset.get('qa_pairs', []):\n",
- " diff = qa.get('difficulty', 'Unknown')\n",
- " atype = qa.get('answer_type', 'Unknown')\n",
- " \n",
- " difficulty_counts[diff] = difficulty_counts.get(diff, 0) + 1\n",
- " answer_type_counts[atype] = answer_type_counts.get(atype, 0) + 1\n",
- " \n",
- " print(\"\\n📊 난이도별 분포:\")\n",
- " for diff, count in sorted(difficulty_counts.items()):\n",
- " bar = \"█\" * count\n",
- " print(f\" {diff:15} | {bar} ({count})\")\n",
- " \n",
- " print(\"\\n📊 답변 유형별 분포:\")\n",
- " for atype, count in sorted(answer_type_counts.items()):\n",
- " bar = \"█\" * count\n",
- " print(f\" {atype:15} | {bar} ({count})\")\n",
- " \n",
- " print(f\"\\n📊 총계:\")\n",
- " print(f\" 총 QA 쌍: {len(dataset.get('qa_pairs', []))}개\")\n",
- " print(f\" Follow-up 체인: {len(dataset.get('followup_chains', []))}개\")\n",
- " print(f\" 진화된 질문: {len(dataset.get('evolved_questions', []))}개\")\n",
- "\n",
- "# 통계 출력\n",
- "print_dataset_statistics(comprehensive_dataset)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "a8e41aa7",
- "metadata": {},
- "source": [
- "## 11. 비동기 대량 생성 (선택사항)\n",
- "\n",
- "더 빠른 생성을 위해 비동기 방식을 사용할 수 있습니다."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "05cf2fa2",
- "metadata": {},
- "outputs": [],
- "source": [
- "# 비동기 QA 생성 (선택사항)\n",
- "async def generate_async_dataset():\n",
- " \"\"\"비동기 방식으로 QA 데이터셋 생성\"\"\"\n",
- " print(\"🚀 비동기 QA 데이터셋 생성 중...\")\n",
- " \n",
- " dataset = await qa_generator.agenerate_comprehensive_qa_dataset(\n",
- " tables=tables,\n",
- " questions_per_difficulty=2\n",
- " )\n",
- " \n",
- " return dataset\n",
- "\n",
- "# Jupyter에서 비동기 실행\n",
- "# async_dataset = await generate_async_dataset()\n",
- "# print(f\"비동기 생성 완료: {len(async_dataset['qa_pairs'])}개 QA\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "3e43bab8",
- "metadata": {},
- "source": [
- "## 12. 커스텀 프롬프트로 특화 QA 생성\n",
- "\n",
- "특정 요구사항에 맞는 커스텀 QA를 생성합니다."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "4b0fbe57",
- "metadata": {},
- "outputs": [],
- "source": [
- "# 커스텀 프롬프트 예시: 수치 계산 중심 QA\n",
- "CUSTOM_CALCULATION_PROMPT = \"\"\"\n",
- "## Task: 수치 계산 중심 QA 생성\n",
- "보험 테이블에서 수치 계산이 필요한 질문을 생성하세요.\n",
- "\n",
- "### Input Tables\n",
- "{tables}\n",
- "\n",
- "### Requirements\n",
- "1. 반드시 수치 계산(사칙연산, 비율, 증감률 등)이 필요한 질문\n",
- "2. 답변은 정확한 숫자로 제공\n",
- "3. 계산 과정(Python 코드) 포함\n",
- "4. 검증 가능한 형태로 출력\n",
- "\n",
- "### Output Format (JSON)\n",
- "```json\n",
- "{{\n",
- " \"questions\": [\n",
- " {{\n",
- " \"id\": \"CALC_001\",\n",
- " \"difficulty\": \"Aggregation\",\n",
- " \"answer_type\": \"calculation\",\n",
- " \"question\": \"질문\",\n",
- " \"answer\": \"수치 답변\",\n",
- " \"calculation_steps\": [\"단계1\", \"단계2\"],\n",
- " \"python_code\": \"검증용 Python 코드\"\n",
- " }}\n",
- " ]\n",
- "}}\n",
- "```\n",
- "\n",
- "### Generate 3 calculation-focused QA pairs.\n",
- "\"\"\"\n",
- "\n",
- "# 커스텀 프롬프트로 생성\n",
- "from QA_example.prompts import format_tables_for_prompt\n",
- "\n",
- "formatted_tables = format_tables_for_prompt(tables)\n",
- "custom_prompt = CUSTOM_CALCULATION_PROMPT.format(tables=formatted_tables)\n",
- "\n",
- "print(\"🔢 수치 계산 중심 QA 생성 중...\")\n",
- "response = qa_generator.pool.generate_content(custom_prompt)\n",
- "\n",
- "# 결과 파싱\n",
- "result = qa_generator._parse_json_response(response)\n",
- "\n",
- "if 'questions' in result:\n",
- " print(f\"\\n✅ {len(result['questions'])}개의 계산 QA 생성 완료\")\n",
- " for qa in result['questions']:\n",
- " print(f\"\\n📌 [{qa.get('id', 'N/A')}]\")\n",
- " print(f\" Q: {qa.get('question', 'N/A')}\")\n",
- " print(f\" A: {qa.get('answer', 'N/A')}\")\n",
- " if 'python_code' in qa:\n",
- " print(f\" Python Code: 포함됨 ✅\")\n",
- "else:\n",
- " print(f\"결과: {result}\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "484134d3",
- "metadata": {},
- "source": [
- "## 13. 요약 및 결론\n",
- "\n",
- "### 생성된 QA 데이터셋의 특징\n",
- "\n",
- "| 특징 | 설명 | 커버되는 양상 |\n",
- "|------|------|-------------|\n",
- "| 난이도 다양성 | IR부터 Insight까지 6단계 | #2 |\n",
- "| Multi-Table | 복수 테이블 참조 필요 | #1 |\n",
- "| 답변 유형 | Exact Match, Descriptive, Calculation | #3 |\n",
- "| 수치 계산 | 집계, 비교, 증감률 계산 | #4, #6 |\n",
- "| 꼬리 질문 | Follow-up 체인 생성 | #5 |\n",
- "| 특정 셀 QA | 단일 셀 기반 Q-A | #7 |\n",
- "| Evol-Instruct | 질문 난이도 진화 | #2, #4 |\n",
- "| LLM Judge | 품질 평가 | #3 |"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": ".venv",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.12.11"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/tests/choi/QA_example/qa_generator.py b/tests/choi/QA_example/qa_generator.py
deleted file mode 100644
index b1ab1fe..0000000
--- a/tests/choi/QA_example/qa_generator.py
+++ /dev/null
@@ -1,556 +0,0 @@
-"""
-QA Generator for Insurance Table Data
-보험 테이블 기반 QA 데이터셋 생성기
-
-이 모듈은 Gemini API를 활용하여 보험 테이블 마크다운 데이터로부터
-다양한 난이도와 유형의 QA 데이터셋을 생성합니다.
-
-주요 기능:
-1. 난이도별 QA 생성 (IR, Analysis, Compare, Aggregation, Reasoning, Insight)
-2. Multi-table QA 생성
-3. 꼬리 질문 (Follow-up) 생성
-4. Evol-Instruct 기반 난이도 진화
-5. LLM-as-Judge 품질 평가
-"""
-
-import json
-import asyncio
-import logging
-from pathlib import Path
-from typing import Optional, Dict, Any, List, Union
-from dataclasses import dataclass, asdict
-from enum import Enum
-import sys
-from json_repair import repair_json
-
-# 프로젝트 루트 추가
-project_root = Path(__file__).parent.parent
-sys.path.insert(0, str(project_root))
-
-from polling_gemini import get_gemini_pool, GeminiAPIPool
-
-from .prompts import (
- QA_GENERATOR_SYSTEM_PROMPT,
- IR_QA_PROMPT,
- ANALYSIS_QA_PROMPT,
- COMPARE_QA_PROMPT,
- AGGREGATION_QA_PROMPT,
- REASONING_QA_PROMPT,
- INSIGHT_QA_PROMPT,
- FOLLOWUP_QA_PROMPT,
- MULTI_TABLE_QA_PROMPT,
- EVOL_INSTRUCT_PROMPT,
- QA_EVALUATION_PROMPT,
- get_qa_prompt_by_difficulty,
- format_tables_for_prompt,
-)
-
-# 로깅 설정
-logging.basicConfig(
- level=logging.INFO,
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
-)
-logger = logging.getLogger(__name__)
-
-
-class QADifficulty(Enum):
- """QA 난이도 레벨"""
- IR = "IR" # Level 1: 단순 정보 검색
- ANALYSIS = "Analysis" # Level 2: 분석적 질문
- COMPARE = "Compare" # Level 3: 비교/Multi-hop
- AGGREGATION = "Aggregation" # Level 4: 집계 연산
- REASONING = "Reasoning" # Level 5: 복합 추론
- INSIGHT = "Insight" # Level 6: 통찰 도출
-
-
-class QAType(Enum):
- """QA 답변 유형"""
- EXACT_MATCH = "exact_match" # 단답형 (정확히 일치)
- DESCRIPTIVE = "descriptive" # 서술형 (LLM Judge 평가)
- CALCULATION = "calculation" # 계산형 (수치 결과)
- COMPARISON = "comparison" # 비교형 (비교 결과 및 근거)
-
-
-@dataclass
-class QAPair:
- """QA 쌍 데이터 클래스"""
- id: str
- difficulty: str
- answer_type: str
- question: str
- answer: str
- reasoning: Optional[str] = None
- evidence: Optional[Dict[str, Any]] = None
- tags: Optional[List[str]] = None
- python_verification: Optional[str] = None
- chain_of_thought: Optional[List[str]] = None
- # 추가 필드들 (LLM이 생성할 수 있는 다양한 필드)
- calculation: Optional[str] = None
- calculation_steps: Optional[List[str]] = None
- assumptions: Optional[List[str]] = None
- supporting_analysis: Optional[str] = None
- key_findings: Optional[List[str]] = None
- required_tables: Optional[List[str]] = None
- join_logic: Optional[str] = None
- python_code: Optional[str] = None
- extra: Optional[Dict[str, Any]] = None # 기타 알 수 없는 필드용
-
- def to_dict(self) -> Dict[str, Any]:
- """딕셔너리로 변환"""
- return {k: v for k, v in asdict(self).items() if v is not None}
-
- @classmethod
- def from_dict(cls, data: Dict[str, Any]) -> 'QAPair':
- """딕셔너리에서 QAPair 생성 (알 수 없는 필드는 extra에 저장)"""
- # QAPair의 필드 목록
- known_fields = {
- 'id', 'difficulty', 'answer_type', 'question', 'answer',
- 'reasoning', 'evidence', 'tags', 'python_verification',
- 'chain_of_thought', 'calculation', 'calculation_steps',
- 'assumptions', 'supporting_analysis', 'key_findings',
- 'required_tables', 'join_logic', 'python_code', 'extra'
- }
-
- # 알려진 필드와 알 수 없는 필드 분리
- known_data = {}
- extra_data = {}
-
- for key, value in data.items():
- if key in known_fields:
- known_data[key] = value
- else:
- extra_data[key] = value
-
- # 필수 필드 기본값 설정
- known_data.setdefault('id', 'UNKNOWN')
- known_data.setdefault('difficulty', 'Unknown')
- known_data.setdefault('answer_type', 'unknown')
- known_data.setdefault('question', '')
- known_data.setdefault('answer', '')
-
- # extra 필드가 있으면 추가
- if extra_data:
- known_data['extra'] = extra_data
-
- return cls(**known_data)
-
-
-@dataclass
-class EvaluationResult:
- """QA 평가 결과 데이터 클래스"""
- correctness: Dict[str, Any]
- faithfulness: Dict[str, Any]
- relevance: Dict[str, Any]
- difficulty_appropriateness: Dict[str, Any]
- clarity: Dict[str, Any]
- overall_score: float
- passed: bool
- improvement_suggestions: List[str]
-
-
-class InsuranceTableQAGenerator:
- """
- 보험 테이블 기반 QA 데이터셋 생성기
-
- Gemini API Pool을 활용하여 자동 키 로테이션을 지원하며,
- 다양한 난이도와 유형의 QA를 생성합니다.
- """
-
- def __init__(
- self,
- config_path: Optional[str] = None,
- model_name: str = "gemini-2.0-flash",
- ):
- """
- Args:
- config_path: API 키 설정 파일 경로
- model_name: 사용할 Gemini 모델
- """
- self.pool = get_gemini_pool(config_path)
- self.model_name = model_name
- self.system_prompt = QA_GENERATOR_SYSTEM_PROMPT
-
- def _parse_json_response(self, response: str) -> Dict[str, Any]:
- """LLM 응답에서 JSON 추출 및 파싱 (agentjson 사용)"""
-
- try:
- result = repair_json(response, return_objects=True)
-
- if isinstance(result, dict):
- logger.debug(f"JSON 파싱 성공")
- return result
- elif isinstance(result, list):
- logger.warning(f"JSON 파싱 결과가 리스트입니다. 딕셔너리로 변환을 시도합니다.")
- # 질문 리스트라고 가정
- return {"questions": result}
- else:
- logger.warning(f"JSON 파싱 실패 (예상치 못한 타입): {type(result)}")
- return {"error": "parsing_failed", "raw_response": response}
-
- except Exception as e:
- logger.error(f"JSON 파싱 실패: {e}")
- logger.debug(f"원본 응답: {response}")
- return {"error": str(e), "raw_response": response}
-
- def _build_prompt(
- self,
- base_prompt: str,
- tables: Dict[str, str],
- **kwargs
- ) -> str:
- """프롬프트 구성"""
- formatted_tables = format_tables_for_prompt(tables)
-
- prompt = f"{self.system_prompt}\n\n{base_prompt}"
- prompt = prompt.format(tables=formatted_tables, **kwargs)
-
- return prompt
-
- def generate_qa_by_difficulty(
- self,
- tables: Dict[str, str],
- difficulty: QADifficulty,
- num_questions: int = 3,
- **kwargs
- ) -> List[QAPair]:
- """
- 특정 난이도의 QA 생성
-
- Args:
- tables: 테이블 딕셔너리 {table_id: markdown_content}
- difficulty: QA 난이도
- num_questions: 생성할 질문 수
-
- Returns:
- 생성된 QA 쌍 리스트
- """
- base_prompt = get_qa_prompt_by_difficulty(difficulty.value)
- prompt = self._build_prompt(
- base_prompt,
- tables,
- num_questions=num_questions
- )
-
- try:
- response = self.pool.generate_content(prompt)
- result = self._parse_json_response(response)
-
- if "questions" in result:
- return [QAPair.from_dict(q) for q in result["questions"]]
- else:
- logger.warning(f"예상치 못한 응답 형식: {result}")
- return []
-
- except Exception as e:
- logger.error(f"QA 생성 실패: {e}")
- return []
-
- async def agenerate_qa_by_difficulty(
- self,
- tables: Dict[str, str],
- difficulty: QADifficulty,
- num_questions: int = 3,
- **kwargs
- ) -> List[QAPair]:
- """난이도별 QA 생성 (비동기)"""
- base_prompt = get_qa_prompt_by_difficulty(difficulty.value)
- prompt = self._build_prompt(
- base_prompt,
- tables,
- num_questions=num_questions
- )
-
- try:
- response = await self.pool.agenerate_content(prompt)
- result = self._parse_json_response(response)
-
- if "questions" in result:
- return [QAPair.from_dict(q) for q in result["questions"]]
- else:
- return []
-
- except Exception as e:
- logger.error(f"비동기 QA 생성 실패: {e}")
- return []
-
- def generate_multi_table_qa(
- self,
- tables: Dict[str, str],
- num_questions: int = 3,
- ) -> List[QAPair]:
- """
- Multi-table QA 생성
-
- 복수의 테이블을 참조해야 답변 가능한 질문 생성
- """
- if len(tables) < 2:
- logger.warning("Multi-table QA는 최소 2개의 테이블이 필요합니다.")
- # 단일 테이블이라도 시도
-
- prompt = self._build_prompt(
- MULTI_TABLE_QA_PROMPT,
- tables,
- num_questions=num_questions
- )
-
- try:
- response = self.pool.generate_content(prompt)
- result = self._parse_json_response(response)
-
- if "questions" in result:
- return [QAPair.from_dict(q) for q in result["questions"]]
- return []
-
- except Exception as e:
- logger.error(f"Multi-table QA 생성 실패: {e}")
- return []
-
- def generate_followup_qa(
- self,
- tables: Dict[str, str],
- original_qa: QAPair,
- ) -> Dict[str, Any]:
- """
- 꼬리 질문 (Follow-up) 생성
-
- 원래 QA를 기반으로 연속적인 후속 질문 체인 생성
- """
- original_qa_str = json.dumps(original_qa.to_dict(), ensure_ascii=False, indent=2)
-
- prompt = self._build_prompt(
- FOLLOWUP_QA_PROMPT,
- tables,
- original_qa=original_qa_str
- )
-
- try:
- response = self.pool.generate_content(prompt)
- return self._parse_json_response(response)
-
- except Exception as e:
- logger.error(f"Follow-up QA 생성 실패: {e}")
- return {}
-
- def evolve_question(
- self,
- tables: Dict[str, str],
- original_question: str,
- ) -> Dict[str, Any]:
- """
- Evol-Instruct: 질문 난이도 진화
-
- 기본 질문을 더 복잡한 질문으로 진화
- """
- prompt = self._build_prompt(
- EVOL_INSTRUCT_PROMPT,
- tables,
- original_question=original_question
- )
-
- try:
- response = self.pool.generate_content(prompt)
- return self._parse_json_response(response)
-
- except Exception as e:
- logger.error(f"Evol-Instruct 실패: {e}")
- return {}
-
- def evaluate_qa(
- self,
- tables: Dict[str, str],
- qa_pair: QAPair,
- ) -> EvaluationResult:
- """
- LLM-as-Judge: QA 품질 평가
-
- 생성된 QA 쌍의 품질을 다면적으로 평가
- """
- qa_str = json.dumps(qa_pair.to_dict(), ensure_ascii=False, indent=2)
-
- prompt = self._build_prompt(
- QA_EVALUATION_PROMPT,
- tables,
- qa_pair=qa_str
- )
-
- try:
- response = self.pool.generate_content(prompt)
- result = self._parse_json_response(response)
-
- if "evaluation" in result:
- eval_data = result["evaluation"]
- return EvaluationResult(
- correctness=eval_data.get("correctness", {}),
- faithfulness=eval_data.get("faithfulness", {}),
- relevance=eval_data.get("relevance", {}),
- difficulty_appropriateness=eval_data.get("difficulty_appropriateness", {}),
- clarity=eval_data.get("clarity", {}),
- overall_score=result.get("overall_score", 0.0),
- passed=result.get("pass", False),
- improvement_suggestions=result.get("improvement_suggestions", [])
- )
- else:
- logger.warning(f"평가 결과 파싱 실패: {result}")
- return None
-
- except Exception as e:
- logger.error(f"QA 평가 실패: {e}")
- return None
-
- def generate_comprehensive_qa_dataset(
- self,
- tables: Dict[str, str],
- questions_per_difficulty: int = 2,
- include_followup: bool = True,
- include_evolution: bool = True,
- evaluate_quality: bool = False,
- ) -> Dict[str, Any]:
- """
- 종합적인 QA 데이터셋 생성
-
- 모든 난이도의 QA를 생성하고 선택적으로 꼬리질문, 진화, 평가를 수행
-
- Args:
- tables: 테이블 딕셔너리
- questions_per_difficulty: 난이도별 질문 수
- include_followup: 꼬리질문 포함 여부
- include_evolution: Evol-Instruct 포함 여부
- evaluate_quality: 품질 평가 수행 여부
-
- Returns:
- 종합 QA 데이터셋
- """
- dataset = {
- "metadata": {
- "tables_count": len(tables),
- "questions_per_difficulty": questions_per_difficulty,
- },
- "qa_pairs": [],
- "followup_chains": [],
- "evolved_questions": [],
- "evaluations": [],
- }
-
- # 1. 각 난이도별 QA 생성
- for difficulty in QADifficulty:
- logger.info(f"Generating {difficulty.value} level QA...")
- qa_pairs = self.generate_qa_by_difficulty(
- tables, difficulty, questions_per_difficulty
- )
-
- for qa in qa_pairs:
- qa_dict = qa.to_dict()
- dataset["qa_pairs"].append(qa_dict)
-
- # 2. 꼬리질문 생성 (선택적)
- if include_followup and difficulty in [QADifficulty.IR, QADifficulty.ANALYSIS]:
- followup = self.generate_followup_qa(tables, qa)
- if followup:
- dataset["followup_chains"].append(followup)
-
- # 3. 질문 진화 (선택적)
- if include_evolution and difficulty in [QADifficulty.IR, QADifficulty.ANALYSIS]:
- evolved = self.evolve_question(tables, qa.question)
- if evolved:
- dataset["evolved_questions"].append(evolved)
-
- # 4. 품질 평가 (선택적)
- if evaluate_quality:
- evaluation = self.evaluate_qa(tables, qa)
- if evaluation:
- dataset["evaluations"].append({
- "qa_id": qa.id,
- "evaluation": asdict(evaluation)
- })
-
- # 5. Multi-table QA (테이블이 2개 이상인 경우)
- if len(tables) >= 2:
- logger.info("Generating Multi-table QA...")
- multi_qa = self.generate_multi_table_qa(tables, questions_per_difficulty)
- for qa in multi_qa:
- dataset["qa_pairs"].append(qa.to_dict())
-
- # 메타데이터 업데이트
- dataset["metadata"]["total_qa_pairs"] = len(dataset["qa_pairs"])
- dataset["metadata"]["total_followups"] = len(dataset["followup_chains"])
- dataset["metadata"]["total_evolved"] = len(dataset["evolved_questions"])
-
- return dataset
-
- async def agenerate_comprehensive_qa_dataset(
- self,
- tables: Dict[str, str],
- questions_per_difficulty: int = 2,
- ) -> Dict[str, Any]:
- """종합 QA 데이터셋 생성 (비동기)"""
- dataset = {
- "metadata": {
- "tables_count": len(tables),
- "questions_per_difficulty": questions_per_difficulty,
- },
- "qa_pairs": [],
- }
-
- # 모든 난이도에 대해 병렬로 QA 생성
- tasks = [
- self.agenerate_qa_by_difficulty(tables, difficulty, questions_per_difficulty)
- for difficulty in QADifficulty
- ]
-
- results = await asyncio.gather(*tasks)
-
- for qa_list in results:
- for qa in qa_list:
- dataset["qa_pairs"].append(qa.to_dict())
-
- dataset["metadata"]["total_qa_pairs"] = len(dataset["qa_pairs"])
-
- return dataset
-
-
-# =============================================================================
-# Convenience Functions
-# =============================================================================
-
-def generate_qa_from_tables(
- tables: Dict[str, str],
- difficulty: Optional[QADifficulty] = None,
- num_questions: int = 3,
- config_path: Optional[str] = None,
-) -> List[Dict[str, Any]]:
- """
- 테이블에서 QA 생성 (간편 함수)
-
- Args:
- tables: 테이블 딕셔너리 {table_id: markdown_content}
- difficulty: 난이도 (None이면 모든 난이도)
- num_questions: 난이도별 질문 수
- config_path: API 설정 파일 경로
-
- Returns:
- 생성된 QA 리스트
- """
- generator = InsuranceTableQAGenerator(config_path=config_path)
-
- if difficulty:
- qa_pairs = generator.generate_qa_by_difficulty(tables, difficulty, num_questions)
- return [qa.to_dict() for qa in qa_pairs]
- else:
- dataset = generator.generate_comprehensive_qa_dataset(
- tables,
- questions_per_difficulty=num_questions,
- include_followup=False,
- include_evolution=False,
- evaluate_quality=False,
- )
- return dataset["qa_pairs"]
-
-
-async def agenerate_qa_from_tables(
- tables: Dict[str, str],
- num_questions: int = 3,
- config_path: Optional[str] = None,
-) -> Dict[str, Any]:
- """테이블에서 QA 생성 (비동기 간편 함수)"""
- generator = InsuranceTableQAGenerator(config_path=config_path)
- return await generator.agenerate_comprehensive_qa_dataset(tables, num_questions)
diff --git a/tests/choi/Table_example/README.md b/tests/choi/Table_example/README.md
deleted file mode 100644
index f0cc165..0000000
--- a/tests/choi/Table_example/README.md
+++ /dev/null
@@ -1,168 +0,0 @@
-# Table Example - 보험 테이블 추출기
-
-`polling_gemini` 패키지를 활용하여 보험 문서 이미지에서 테이블을 Markdown 형식으로 추출하는 예제입니다.
-
-## 주요 특징
-
-- **VLM + OCR 하이브리드 접근**: Gemini의 시각적 추론 능력과 OCR 텍스트를 결합
-- **보험 도메인 특화 프롬프트**: 계층적 헤더, 셀 병합, 복합 데이터 처리에 최적화
-- **자동 API 키 로테이션**: `polling_gemini` 패키지를 통한 API 키 관리
-- **동기/비동기 지원**: 대용량 처리를 위한 비동기 API 지원
-
-## 설치
-
-프로젝트 루트에서:
-
-```bash
-uv sync
-```
-
-## 사용법
-
-### 1. 기본 사용
-
-```python
-from Table_example import extract_table_from_image
-
-# 이미지에서 테이블 추출
-result = extract_table_from_image("insurance_table.png")
-print(result)
-```
-
-### 2. OCR 참조 텍스트와 함께 사용
-
-```python
-from Table_example import extract_table_from_image
-
-# OCR로 먼저 추출한 텍스트가 있는 경우
-ocr_text = """| 구분 | 보험기간 | 납입기간 |
-| 상해사망 | 80세 | 20년 |"""
-
-result = extract_table_from_image(
- "insurance_table.png",
- ocr_markdown=ocr_text # OCR 결과를 참조로 제공
-)
-```
-
-### 3. 비동기 처리
-
-```python
-import asyncio
-from Table_example import aextract_table_from_image
-
-async def process_multiple_images():
- images = ["table1.png", "table2.png", "table3.png"]
-
- # 동시에 여러 이미지 처리
- tasks = [aextract_table_from_image(img) for img in images]
- results = await asyncio.gather(*tasks)
-
- return results
-
-results = asyncio.run(process_multiple_images())
-```
-
-### 4. InsuranceTableExtractor 클래스 직접 사용
-
-```python
-from Table_example import InsuranceTableExtractor
-
-# 추출기 인스턴스 생성
-extractor = InsuranceTableExtractor(
- config_path="apis/gemini_keys.yaml", # 커스텀 설정 경로
- model_name="gemini-2.5-flash" # 모델 지정
-)
-
-# 테이블 추출
-result = extractor.extract("insurance_table.png")
-
-# API Pool 상태 확인
-status = extractor.get_pool_status()
-print(f"현재 API 키: {status['current_key']['name']}")
-```
-
-## 프롬프트 설계
-
-### System Prompt 핵심 원칙
-
-1. **구조적 완전성**: 병합된 셀을 비정규화하여 모든 행에 값 채우기
-2. **헤더 평탄화**: 다중 행 헤더를 언더스코어(_)로 연결하여 단일 행으로 변환
-3. **데이터 무결성**: 금액 포맷 정리, 퍼센트 유지, 부가 정보 제거
-4. **Hybrid Reference**: OCR 텍스트 참조로 오타 교정
-
-### User Prompt Chain-of-Table 단계
-
-1. **구조 분석**: 레이아웃, 헤더 행 수, 병합 셀 식별
-2. **헤더 처리**: 다중 행 헤더 → 단일 행 변환
-3. **데이터 추출**: 값 추출 및 병합 셀 반복 입력
-4. **포맷팅 검증**: 금액 정리, 컬럼 개수 확인
-
-## 테스트
-
-```bash
-cd TableMagnifier
-python -m Table_example.test_extraction
-```
-
-### 테스트 이미지 준비
-
-`Table_example/sample_images/` 폴더에 테스트할 보험 테이블 이미지를 추가하세요:
-- 지원 형식: PNG, JPG, JPEG, GIF, WebP, BMP
-- 권장: 해상도가 높은 테이블 이미지
-
-## 출력 예시
-
-입력 이미지:
-```
-┌─────────────┬────────────────────────────┐
-│ │ 해지환급금 │
-│ 구분 ├──────────────┬─────────────┤
-│ │ 금액 │ 환급률 │
-├─────────────┼──────────────┼─────────────┤
-│ 1년 │ 100,000원 │ 10% │
-│ 5년 │ 500,000원 │ 50% │
-│ 10년 │ 1,000,000원 │ 100% │
-└─────────────┴──────────────┴─────────────┘
-```
-
-출력 Markdown:
-```markdown
-| 구분 | 해지환급금_금액 | 해지환급금_환급률 |
-| :--- | :--- | :--- |
-| 1년 | 100000 | 10% |
-| 5년 | 500000 | 50% |
-| 10년 | 1000000 | 100% |
-```
-
-## 파일 구조
-
-```
-Table_example/
-├── __init__.py # 패키지 초기화
-├── prompts.py # 시스템/사용자 프롬프트 정의
-├── table_extractor.py # 테이블 추출기 클래스
-├── test_extraction.py # 테스트 코드
-├── sample_images/ # 테스트 이미지 폴더
-└── README.md # 이 문서
-```
-
-## API 키 설정
-
-`apis/gemini_keys.yaml` 파일에 Gemini API 키를 설정하세요:
-
-```yaml
-api_keys:
- - key: "YOUR_GEMINI_API_KEY"
- name: "key1"
- enabled: true
-
-settings:
- model: "gemini-2.5-flash"
- temperature: 0.1
- max_retries: 3
- retry_delay: 2
-```
-
-## 라이센스
-
-MIT License
diff --git a/tests/choi/Table_example/__init__.py b/tests/choi/Table_example/__init__.py
deleted file mode 100644
index 30e122d..0000000
--- a/tests/choi/Table_example/__init__.py
+++ /dev/null
@@ -1,20 +0,0 @@
-"""
-Table Extraction Example
-보험 도메인 특화 테이블 추출 예제
-polling_gemini 패키지를 사용하여 이미지에서 Markdown 테이블 추출
-"""
-
-from .table_extractor import (
- InsuranceTableExtractor,
- extract_table_from_image,
- aextract_table_from_image,
-)
-from .prompts import SYSTEM_PROMPT, USER_PROMPT_TEMPLATE
-
-__all__ = [
- 'InsuranceTableExtractor',
- 'extract_table_from_image',
- 'aextract_table_from_image',
- 'SYSTEM_PROMPT',
- 'USER_PROMPT_TEMPLATE',
-]
diff --git a/tests/choi/Table_example/example_batch.py b/tests/choi/Table_example/example_batch.py
deleted file mode 100644
index 2f348ff..0000000
--- a/tests/choi/Table_example/example_batch.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-비동기 배치 테이블 추출 예제
-여러 이미지를 동시에 처리하여 효율적으로 테이블을 추출합니다.
-"""
-
-import sys
-import asyncio
-import time
-from pathlib import Path
-from typing import List, Tuple, Optional
-
-# 프로젝트 루트를 Python 경로에 추가
-project_root = Path(__file__).parent.parent
-sys.path.insert(0, str(project_root))
-
-from Table_example import aextract_table_from_image, InsuranceTableExtractor
-
-
-async def process_single_image(
- image_path: Path,
- ocr_markdown: str = "N/A"
-) -> Tuple[Path, Optional[str], Optional[str]]:
- """
- 단일 이미지 처리 (비동기)
-
- Returns:
- (이미지 경로, 결과 또는 None, 에러 메시지 또는 None)
- """
- try:
- result = await aextract_table_from_image(
- image_path=image_path,
- ocr_markdown=ocr_markdown
- )
- return (image_path, result, None)
- except Exception as e:
- return (image_path, None, str(e))
-
-
-async def batch_extract_tables(
- image_paths: List[Path],
- max_concurrent: int = 3
-) -> List[Tuple[Path, Optional[str], Optional[str]]]:
- """
- 여러 이미지를 배치로 처리 (동시성 제한)
-
- Args:
- image_paths: 처리할 이미지 경로 리스트
- max_concurrent: 동시 처리 최대 개수
-
- Returns:
- (이미지 경로, 결과, 에러) 튜플 리스트
- """
- # 세마포어로 동시 실행 제한
- semaphore = asyncio.Semaphore(max_concurrent)
-
- async def process_with_semaphore(image_path: Path):
- async with semaphore:
- return await process_single_image(image_path)
-
- # 모든 이미지 동시 처리 (세마포어로 제한)
- tasks = [process_with_semaphore(path) for path in image_paths]
- results = await asyncio.gather(*tasks)
-
- return results
-
-
-def find_all_images(directory: Path) -> List[Path]:
- """디렉토리에서 모든 이미지 파일 찾기"""
- extensions = ["*.png", "*.jpg", "*.jpeg", "*.gif", "*.webp", "*.bmp"]
- images = []
- for ext in extensions:
- images.extend(directory.glob(ext))
- return sorted(images)
-
-
-async def main():
- """
- 배치 처리 예제
- sample_images 폴더의 모든 이미지를 처리합니다.
- """
- print("🏥 보험 테이블 배치 추출 시작")
- print("=" * 70)
-
- # ============================================
- # 📌 설정
- # ============================================
- sample_dir = Path(__file__).parent / "sample_images"
- output_dir = Path(__file__).parent / "output"
- max_concurrent = 3 # 동시 처리 최대 개수
-
- # 출력 디렉토리 생성
- output_dir.mkdir(exist_ok=True)
-
- # ============================================
- # 📌 이미지 파일 수집
- # ============================================
- image_paths = find_all_images(sample_dir)
-
- if not image_paths:
- print(f"❌ 이미지 파일이 없습니다: {sample_dir}")
- print("\n📝 sample_images 폴더에 테이블 이미지를 추가하세요.")
- return
-
- print(f"📁 처리할 이미지: {len(image_paths)}개")
- for i, path in enumerate(image_paths, 1):
- print(f" {i}. {path.name}")
- print(f"⚡ 동시 처리 수: {max_concurrent}")
- print("=" * 70)
-
- # ============================================
- # 🚀 배치 처리 실행
- # ============================================
- start_time = time.time()
-
- results = await batch_extract_tables(
- image_paths=image_paths,
- max_concurrent=max_concurrent
- )
-
- elapsed = time.time() - start_time
-
- # ============================================
- # 📊 결과 처리
- # ============================================
- success_count = 0
- failed_count = 0
-
- print("\n📊 처리 결과:")
- print("-" * 70)
-
- for image_path, result, error in results:
- if result:
- success_count += 1
- status = "✅ 성공"
-
- # 결과 파일 저장
- output_path = output_dir / f"{image_path.stem}_table.md"
- with open(output_path, "w", encoding="utf-8") as f:
- f.write(f"# {image_path.name}\n\n")
- f.write(result)
-
- print(f"\n{status}: {image_path.name}")
- print(f" 💾 저장: {output_path.name}")
- print(f" 📝 미리보기: {result[:100]}...")
- else:
- failed_count += 1
- status = "❌ 실패"
- print(f"\n{status}: {image_path.name}")
- print(f" ⚠️ 에러: {error}")
-
- # ============================================
- # 📈 최종 요약
- # ============================================
- print("\n" + "=" * 70)
- print("📈 처리 완료!")
- print(f" ⏱️ 총 소요 시간: {elapsed:.2f}초")
- print(f" ✅ 성공: {success_count}개")
- print(f" ❌ 실패: {failed_count}개")
- print(f" 📁 출력 폴더: {output_dir}")
-
- if success_count > 0:
- avg_time = elapsed / success_count
- print(f" ⚡ 평균 처리 시간: {avg_time:.2f}초/이미지")
-
-
-if __name__ == "__main__":
- asyncio.run(main())
diff --git a/tests/choi/Table_example/example_simple.py b/tests/choi/Table_example/example_simple.py
deleted file mode 100644
index c0bdbbc..0000000
--- a/tests/choi/Table_example/example_simple.py
+++ /dev/null
@@ -1,97 +0,0 @@
-"""
-간단한 테이블 추출 예제
-실제 이미지 파일 경로를 지정하여 테이블을 추출합니다.
-"""
-
-import sys
-from pathlib import Path
-
-# 프로젝트 루트를 Python 경로에 추가
-project_root = Path(__file__).parent.parent
-sys.path.insert(0, str(project_root))
-
-from Table_example import extract_table_from_image, InsuranceTableExtractor
-
-
-def main():
- """
- 사용 예제:
- 1. sample_images 폴더에 테이블 이미지를 추가하세요
- 2. 아래 IMAGE_PATH를 해당 이미지 경로로 수정하세요
- 3. 스크립트를 실행하세요
- """
-
- # ============================================
- # 📌 이미지 경로 설정
- # ============================================
- # 방법 1: sample_images 폴더의 이미지 사용
- sample_dir = Path(__file__).parent / "sample_images"
-
- # sample_images 폴더의 첫 번째 이미지 자동 선택
- image_files = list(sample_dir.glob("*.png")) + \
- list(sample_dir.glob("*.jpg")) + \
- list(sample_dir.glob("*.jpeg"))
-
- if not image_files:
- print("❌ sample_images 폴더에 이미지가 없습니다.")
- print(f" 경로: {sample_dir}")
- print("\n📝 테이블 이미지를 추가한 후 다시 실행하세요.")
- return
-
- IMAGE_PATH = image_files[0]
-
- # 방법 2: 직접 경로 지정 (주석 해제하여 사용)
- # IMAGE_PATH = "/path/to/your/table_image.png"
-
- # ============================================
- # 📌 OCR 참조 텍스트 (선택적)
- # ============================================
- # OCR로 먼저 추출한 텍스트가 있으면 여기에 입력
- # 이미지가 흐릿할 때 숫자 정확도 향상에 도움됩니다
- OCR_MARKDOWN = "N/A" # 없으면 "N/A"
-
- # 예시:
- # OCR_MARKDOWN = """
- # | 구분 | 보험료 |
- # | 상해 | 10000 |
- # | 질병 | 15000 |
- # """
-
- # ============================================
- # 🚀 테이블 추출 실행
- # ============================================
- print("🏥 보험 테이블 추출 시작")
- print("=" * 60)
- print(f"📁 이미지: {IMAGE_PATH}")
- print(f"📝 OCR 참조: {'있음' if OCR_MARKDOWN != 'N/A' else '없음'}")
- print("=" * 60)
-
- try:
- # 테이블 추출
- result = extract_table_from_image(
- image_path=IMAGE_PATH,
- ocr_markdown=OCR_MARKDOWN
- )
-
- print("\n✅ 추출 완료!")
- print("\n📊 결과 (Markdown Table):")
- print("-" * 60)
- print(result)
- print("-" * 60)
-
- # 결과를 파일로 저장
- output_path = Path(IMAGE_PATH).with_suffix(".md")
- with open(output_path, "w", encoding="utf-8") as f:
- f.write(result)
- print(f"\n💾 결과 저장됨: {output_path}")
-
- except FileNotFoundError as e:
- print(f"❌ 파일을 찾을 수 없습니다: {e}")
- except Exception as e:
- print(f"❌ 추출 실패: {e}")
- import traceback
- traceback.print_exc()
-
-
-if __name__ == "__main__":
- main()
diff --git a/tests/choi/Table_example/output/.gitkeep b/tests/choi/Table_example/output/.gitkeep
deleted file mode 100644
index bc83f8d..0000000
--- a/tests/choi/Table_example/output/.gitkeep
+++ /dev/null
@@ -1,3 +0,0 @@
-# Output
-
-이 폴더에 추출된 테이블 결과가 저장됩니다.
diff --git a/tests/choi/Table_example/prompts.py b/tests/choi/Table_example/prompts.py
deleted file mode 100644
index e928665..0000000
--- a/tests/choi/Table_example/prompts.py
+++ /dev/null
@@ -1,69 +0,0 @@
-
-# System Prompt - 보험 데이터 엔지니어 역할 정의
-SYSTEM_PROMPT = """# Role Definition
-당신은 20년 경력의 '수석 보험 데이터 엔지니어'이자 'OCR 후처리 전문가'입니다.
-당신의 임무는 제공된 [보험 문서 이미지]와 선택적으로 제공되는 [기초 OCR 텍스트]를 분석하여, 데이터베이스 적재가 가능한 완벽한 형태의 'Standardized Markdown Table'로 변환하는 것입니다.
-
-# Core Principles
-1. **구조적 완전성(Structural Integrity):** 시각적으로 병합(Merge)된 셀은 반드시 비정규화(Denormalization)하여 모든 행에 값을 채워야 합니다. 빈칸이나 " 상동" 등의 표현은 금지됩니다.
-2. **헤더 평탄화(Header Flattening):** 2행 이상의 계층적 헤더(Multi-row Headers)는 상위 헤더와 하위 헤더를 언더스코어(_)로 연결하여 단일 행(Single-row) 헤더로 변환합니다. (예: '보장내용' 하위에 '지급금액'이 있다면 -> '보장내용_지급금액')
-3. **데이터 무결성(Data Integrity):**
- - 금액의 천 단위 구분자(,)는 제거합니다. (예: 1,000,000 -> 1000000)
- - 퍼센트(%)는 기호를 포함한 문자열로 유지합니다. (예: 98.5%)
- - 괄호 안의 보조 정보(예: 전년 대비 증감액)는 무시하고 핵심 수치만 추출합니다.
-4. **Hybrid Reference:** [기초 OCR 텍스트]가 제공될 경우, 이미지 내 텍스트가 흐릿하거나 불분명할 때 해당 텍스트를 참조하여 오타를 교정하십시오. 단, 표의 구조(행/열 위치) 판단은 반드시 [원본 이미지]를 기준으로 합니다."""
-
-# User Prompt Template - 단계별 지시사항 포함
-USER_PROMPT_TEMPLATE = """# Task Description
-아래 제공된 입력을 바탕으로 보험 테이블 데이터를 추출하십시오.
-
-# Input Data
-1. **Target Image:** [첨부된 이미지]
-2. **Reference OCR Markdown (Optional):**
-\"\"\"
-{ocr_markdown}
-\"\"\"
-
-# Step-by-Step Instructions (Chain-of-Table)
-단계별로 생각하고 실행하십시오:
-
-**Step 1. 구조 분석 (Structure Analysis)**
-- 이미지를 보고 표의 전체적인 레이아웃을 파악하십시오.
-- 헤더가 몇 개의 행(Row)으로 구성되어 있는지 확인하십시오.
-- 세로로 병합된(Vertically Merged) '구분'이나 '기간' 컬럼이 있는지 식별하십시오.
-
-**Step 2. 헤더 처리 (Header Processing)**
-- 다중 행 헤더를 단일 행 키(Unique Key)로 변환하십시오.
-- 예:
- | 구분 | 해지환급금 |
- | | 금액 | 환급률 |
- -> | 구분 | 해지환급금_금액 | 해지환급금_환급률 |
-
-**Step 3. 데이터 추출 및 채우기 (Extraction & Filling)**
-- 각 행(Row)의 데이터를 추출하십시오.
-- **중요:** 병합된 셀은 해당 범위에 속하는 모든 행에 동일한 값을 반복 입력(Repeat Value)하십시오. 절대 빈 칸으로 두지 마십시오.
-- OCR 참고용 텍스트가 있다면, 숫자의 정확성을 검증하는 데 사용하십시오.
-
-**Step 4. 포맷팅 및 검증 (Formatting & Verification)**
-- 금액에서 '원', ',' 제거 / 정수형 변환.
-- 출력 전, 헤더의 컬럼 개수와 데이터 행의 컬럼 개수가 일치하는지 확인하십시오.
-
-# Output Format
-설명이나 사족 없이 오직 **Markdown Table** 만 출력하십시오.
-
-| 헤더1 | 헤더2_서브1 | 헤더2_서브2 | ... |
-| :--- | :--- | :--- | ... |
-| 값1 | 값2 | 값3 | ... |"""
-
-
-def get_user_prompt(ocr_markdown: str = "N/A") -> str:
- """
- OCR 마크다운 데이터를 포함한 사용자 프롬프트 생성
-
- Args:
- ocr_markdown: OCR로 추출된 마크다운 텍스트 (없으면 "N/A")
-
- Returns:
- 완성된 사용자 프롬프트 문자열
- """
- return USER_PROMPT_TEMPLATE.format(ocr_markdown=ocr_markdown)
diff --git a/tests/choi/Table_example/sample_images/.gitkeep b/tests/choi/Table_example/sample_images/.gitkeep
deleted file mode 100644
index eede5be..0000000
--- a/tests/choi/Table_example/sample_images/.gitkeep
+++ /dev/null
@@ -1,15 +0,0 @@
-# Sample Images
-
-이 폴더에 테스트할 보험 테이블 이미지를 추가하세요.
-
-## 지원 형식
-- PNG
-- JPG / JPEG
-- GIF
-- WebP
-- BMP
-
-## 권장 이미지
-- 해상도가 높은 테이블 이미지
-- 보험 약관, 보험료표, 해지환급금표 등
-- 계층적 헤더가 있는 복잡한 테이블
diff --git a/tests/choi/Table_example/sample_images/I_table_78.md b/tests/choi/Table_example/sample_images/I_table_78.md
deleted file mode 100644
index 727197b..0000000
--- a/tests/choi/Table_example/sample_images/I_table_78.md
+++ /dev/null
@@ -1,6 +0,0 @@
-|구분|XX세|XX+1세|XX+2세|XX+3세|XX+4세|XX+5세|
-|---|---|---|---|---|---|---|
-|나이증가분(A)||1,059|1,357|1,739|2,229|2,855|
-|보험료 산출 기초율
(위험률 등) 증가분
(B=전년도
기준보험료의 최대
25% 가정)||10,846|13,897|17,806|22,815|29,232|
-|기준보험료
(C=전년도
기준보험료+A+B)|42,325|54,321|69,485|89,030|114,074|146,161|
-
diff --git a/tests/choi/Table_example/sample_images/I_table_78.png b/tests/choi/Table_example/sample_images/I_table_78.png
deleted file mode 100644
index 3237899..0000000
Binary files a/tests/choi/Table_example/sample_images/I_table_78.png and /dev/null differ
diff --git a/tests/choi/Table_example/sample_images/qa_output/I_table_78_pair_0_qa.json b/tests/choi/Table_example/sample_images/qa_output/I_table_78_pair_0_qa.json
deleted file mode 100644
index f4d70a8..0000000
--- a/tests/choi/Table_example/sample_images/qa_output/I_table_78_pair_0_qa.json
+++ /dev/null
@@ -1,80 +0,0 @@
-{
- "name": "I_table_78_pair_0",
- "image_paths": [
- "tests/choi/Table_example/sample_images/I_table_78.png"
- ],
- "qa_results": [
- {
- "question": "XX+2세의 기준보험료(C)는 얼마입니까?",
- "answer": "69,485",
- "type": "lookup",
- "reasoning_annotation": "Directly retrieve the value from the '기준보험료 (C)' row and 'XX+2세' column.",
- "context": null
- },
- {
- "question": "기준보험료(C)가 70,000 미만인 연령대는 어디입니까?",
- "answer": "XX세, XX+1세, XX+2세",
- "type": "filter",
- "reasoning_annotation": "Filter the '기준보험료 (C)' row for values less than 70,000 and list the corresponding age categories.",
- "context": null
- },
- {
- "question": "XX+1세부터 XX+5세까지의 나이증가분(A)의 총합은 얼마입니까?",
- "answer": "9,239",
- "type": "aggregate",
- "reasoning_annotation": "Sum the values in the '나이증가분(A)' row for age categories XX+1세 (1,059), XX+2세 (1,357), XX+3세 (1,739), XX+4세 (2,229), and XX+5세 (2,855). (1,059 + 1,357 + 1,739 + 2,229 + 2,855 = 9,239).",
- "context": null
- },
- {
- "question": "XX+4세와 XX+5세 중 나이증가분(A)이 더 높은 연령대는 어디입니까?",
- "answer": "XX+5세",
- "type": "compare",
- "reasoning_annotation": "Compare the '나이증가분(A)' values for XX+4세 (2,229) and XX+5세 (2,855). XX+5세 has a higher value.",
- "context": null
- },
- {
- "question": "XX+5세의 기준보험료(C)와 XX세의 기준보험료(C)의 차이는 얼마입니까?",
- "answer": "103,836",
- "type": "arithmetic",
- "reasoning_annotation": "Subtract the '기준보험료 (C)' value for XX세 (42,325) from the '기준보험료 (C)' value for XX+5세 (146,161). (146,161 - 42,325 = 103,836).",
- "context": null
- },
- {
- "question": "XX세부터 XX+5세까지 기준보험료(C)의 전반적인 추세는 어떻습니까?",
- "answer": "연령이 증가함에 따라 기준보험료(C)가 지속적으로 증가하는 상승 추세를 보입니다.",
- "type": "temporal",
- "reasoning_annotation": "Observe the values in the '기준보험료 (C)' row across all age categories (42,325, 54,321, 69,485, 89,030, 114,074, 146,161). All values show a consistent increase.",
- "context": null
- },
- {
- "question": "나이증가분(A)이 1,739인 연령대의 기준보험료(C)는 얼마입니까?",
- "answer": "89,030",
- "type": "multi_hop",
- "reasoning_annotation": "First, find the age category where '나이증가분(A)' is 1,739, which is 'XX+3세'. Then, retrieve the '기준보험료 (C)' value for 'XX+3세'.",
- "context": null
- },
- {
- "question": "위험률 등 기초율 변화로 인한 추가 비용이 가장 높은 연령대는 어디입니까?",
- "answer": "XX+5세",
- "type": "implicit_reference",
- "reasoning_annotation": "The question implicitly refers to '보험료 산출 기초율 (위험률 등) 증가분 (B)'. Find the maximum value in this row, which is 29,232 for 'XX+5세'.",
- "context": null
- },
- {
- "question": "XX+4세 바로 다음 연령대의 기준보험료는 얼마입니까?",
- "answer": "146,161",
- "type": "ellipsis",
- "reasoning_annotation": "The question implicitly asks for the '기준보험료 (C)' of the age category immediately following 'XX+4세', which is 'XX+5세'. Retrieve the value from the '기준보험료 (C)' row and 'XX+5세' column.",
- "context": null
- },
- {
- "question": "정부의 보험료 안정화 방안에 따라, 보험료 인상률을 재조정해야 하는 연령대는 어디입니까?",
- "answer": "XX+4세, XX+5세",
- "type": "long_sequence",
- "reasoning_annotation": "According to the provided context, identify age categories where '보험료 산출 기초율 증가분(B)' exceeds 20,000. These are XX+4세 (22,815) and XX+5세 (29,232).",
- "context": "정부의 보험료 안정화 방안에 따라, '보험료 산출 기초율 증가분(B)'이 20,000을 초과하는 연령대에 대해서는 보험료 인상률을 재조정해야 한다."
- }
- ],
- "token_usage": 8086,
- "errors": []
-}
\ No newline at end of file
diff --git a/tests/choi/Table_example/sample_images/qa_output/_summary.json b/tests/choi/Table_example/sample_images/qa_output/_summary.json
deleted file mode 100644
index 1d6400d..0000000
--- a/tests/choi/Table_example/sample_images/qa_output/_summary.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "folder": "tests/choi/Table_example/sample_images",
- "total": 1,
- "success": 1,
- "failed": 0,
- "qa_only": true,
- "provider": "gemini_pool",
- "model": "gpt-4o-mini",
- "checkpointing_enabled": false,
- "checkpoint_dir": null,
- "results": [
- {
- "name": "I_table_78_pair_0",
- "status": "success",
- "qa_count": 10,
- "output_file": "tests/choi/Table_example/sample_images/qa_output/I_table_78_pair_0_qa.json",
- "errors": []
- }
- ]
-}
\ No newline at end of file
diff --git a/tests/choi/Table_example/table_extractor.py b/tests/choi/Table_example/table_extractor.py
deleted file mode 100644
index 4024079..0000000
--- a/tests/choi/Table_example/table_extractor.py
+++ /dev/null
@@ -1,295 +0,0 @@
-"""
-보험 테이블 추출기
-polling_gemini 패키지를 사용하여 이미지에서 테이블을 Markdown으로 변환
-"""
-
-import os
-import asyncio
-import base64
-import logging
-from pathlib import Path
-from typing import Optional, Dict, Any, Union
-import google.generativeai as genai
-from google.api_core import exceptions as google_exceptions
-
-from .prompts import SYSTEM_PROMPT, get_user_prompt
-
-# polling_gemini 패키지에서 API Pool 가져오기
-import sys
-project_root = Path(__file__).parent.parent
-sys.path.insert(0, str(project_root))
-
-from polling_gemini import get_gemini_pool, GeminiAPIPool
-
-# 로깅 설정
-logger = logging.getLogger(__name__)
-
-
-def load_image_as_base64(image_path: Union[str, Path]) -> str:
- """이미지 파일을 Base64로 인코딩"""
- image_path = Path(image_path)
- if not image_path.exists():
- raise FileNotFoundError(f"이미지 파일을 찾을 수 없습니다: {image_path}")
-
- with open(image_path, "rb") as f:
- return base64.b64encode(f.read()).decode("utf-8")
-
-
-def get_image_mime_type(image_path: Union[str, Path]) -> str:
- """이미지 파일의 MIME 타입 반환"""
- image_path = Path(image_path)
- suffix = image_path.suffix.lower()
-
- mime_types = {
- ".jpg": "image/jpeg",
- ".jpeg": "image/jpeg",
- ".png": "image/png",
- ".gif": "image/gif",
- ".webp": "image/webp",
- ".bmp": "image/bmp",
- }
-
- return mime_types.get(suffix, "image/jpeg")
-
-
-class InsuranceTableExtractor:
- """
- 보험 문서 이미지에서 테이블을 추출하는 클래스
-
- polling_gemini의 GeminiAPIPool을 활용하여 자동 API 키 로테이션을 지원합니다.
- """
-
- def __init__(
- self,
- config_path: Optional[str] = None,
- model_name: str = "gemini-2.5-flash",
- ):
- """
- Args:
- config_path: API 키 설정 파일 경로 (None이면 기본 경로 사용)
- model_name: 사용할 Gemini 모델 이름
- """
- self.pool = get_gemini_pool(config_path)
- self.model_name = model_name
- self.system_prompt = SYSTEM_PROMPT
-
- def _create_multimodal_content(
- self,
- image_path: Union[str, Path],
- ocr_markdown: str = "N/A"
- ) -> list:
- """
- 멀티모달 콘텐츠 생성 (이미지 + 텍스트)
-
- Args:
- image_path: 이미지 파일 경로
- ocr_markdown: 참조용 OCR 마크다운 텍스트
-
- Returns:
- Gemini API에 전달할 콘텐츠 리스트
- """
- # 이미지 로드
- image_data = load_image_as_base64(image_path)
- mime_type = get_image_mime_type(image_path)
-
- # 사용자 프롬프트 생성
- user_prompt = get_user_prompt(ocr_markdown)
-
- # 멀티모달 콘텐츠 구성
- content = [
- # 시스템 프롬프트를 포함한 전체 프롬프트
- f"{self.system_prompt}\n\n{user_prompt}",
- # 이미지 데이터
- {
- "mime_type": mime_type,
- "data": image_data
- }
- ]
-
- return content
-
- def extract(
- self,
- image_path: Union[str, Path],
- ocr_markdown: str = "N/A",
- **kwargs
- ) -> str:
- """
- 이미지에서 테이블을 추출하여 Markdown으로 반환 (동기)
-
- Args:
- image_path: 테이블이 포함된 이미지 파일 경로
- ocr_markdown: 참조용 OCR 마크다운 텍스트 (선택적)
- **kwargs: 추가 생성 파라미터
-
- Returns:
- 추출된 Markdown 테이블 문자열
- """
- content = self._create_multimodal_content(image_path, ocr_markdown)
-
- # API Pool의 현재 설정된 모델 사용
- # 멀티모달 요청을 위해 직접 genai 호출
- max_retries = self.pool.settings.get('max_retries', 3)
- retry_delay = self.pool.settings.get('retry_delay', 2)
-
- last_error = None
- attempts = 0
- max_attempts = len(self.pool.api_keys) * max_retries
-
- while attempts < max_attempts:
- current_key = self.pool.api_keys[self.pool.current_key_index]
-
- try:
- # 현재 키로 Gemini 설정
- genai.configure(api_key=current_key.key)
- model = genai.GenerativeModel(self.model_name)
-
- # 생성 설정
- generation_config = {
- 'temperature': self.pool.settings.get('temperature', 0.1),
- }
- generation_config.update(kwargs.get('generation_config', {}))
-
- # API 호출
- response = model.generate_content(
- content,
- generation_config=generation_config
- )
-
- # 성공 시 실패 카운트 리셋
- current_key.failed_count = 0
- current_key.last_error = None
-
- return response.text
-
- except google_exceptions.ResourceExhausted as e:
- logger.warning(f"API 키 '{current_key.name}' 할당량 초과. 다음 키로 전환합니다.")
- current_key.failed_count += 1
- current_key.last_error = str(e)
- last_error = e
-
- if not self.pool._rotate_key():
- break
-
- except Exception as e:
- logger.warning(f"API 호출 실패 (키: {current_key.name}): {e}")
- current_key.failed_count += 1
- current_key.last_error = str(e)
- last_error = e
-
- if self.pool._is_quota_error(e):
- if not self.pool._rotate_key():
- break
- else:
- import time
- time.sleep(retry_delay)
-
- attempts += 1
-
- error_msg = f"모든 API 키로 시도했으나 실패했습니다. 마지막 에러: {last_error}"
- logger.error(error_msg)
- raise Exception(error_msg)
-
- async def aextract(
- self,
- image_path: Union[str, Path],
- ocr_markdown: str = "N/A",
- **kwargs
- ) -> str:
- """
- 이미지에서 테이블을 추출하여 Markdown으로 반환 (비동기)
-
- Args:
- image_path: 테이블이 포함된 이미지 파일 경로
- ocr_markdown: 참조용 OCR 마크다운 텍스트 (선택적)
- **kwargs: 추가 생성 파라미터
-
- Returns:
- 추출된 Markdown 테이블 문자열
- """
- # 동기 메서드를 비동기로 래핑
- loop = asyncio.get_event_loop()
- return await loop.run_in_executor(
- None,
- lambda: self.extract(image_path, ocr_markdown, **kwargs)
- )
-
- def get_pool_status(self) -> Dict[str, Any]:
- """현재 API Pool 상태 반환"""
- return {
- 'current_key': self.pool.get_current_key_info(),
- 'all_keys': self.pool.get_all_keys_status()
- }
-
-
-# 편의 함수들
-
-def extract_table_from_image(
- image_path: Union[str, Path],
- ocr_markdown: str = "N/A",
- config_path: Optional[str] = None,
- **kwargs
-) -> str:
- """
- 이미지에서 보험 테이블을 추출하는 간편 함수 (동기)
-
- Args:
- image_path: 테이블이 포함된 이미지 파일 경로
- ocr_markdown: 참조용 OCR 마크다운 텍스트 (선택적)
- config_path: API 키 설정 파일 경로
- **kwargs: 추가 생성 파라미터
-
- Returns:
- 추출된 Markdown 테이블 문자열
-
- Example:
- ```python
- from Table_example import extract_table_from_image
-
- # 기본 사용
- result = extract_table_from_image("insurance_table.png")
- print(result)
-
- # OCR 참조 텍스트와 함께 사용
- result = extract_table_from_image(
- "insurance_table.png",
- ocr_markdown="| 구분 | 금액 |\\n| 보험료 | 10000 |"
- )
- ```
- """
- extractor = InsuranceTableExtractor(config_path=config_path)
- return extractor.extract(image_path, ocr_markdown, **kwargs)
-
-
-async def aextract_table_from_image(
- image_path: Union[str, Path],
- ocr_markdown: str = "N/A",
- config_path: Optional[str] = None,
- **kwargs
-) -> str:
- """
- 이미지에서 보험 테이블을 추출하는 간편 함수 (비동기)
-
- Args:
- image_path: 테이블이 포함된 이미지 파일 경로
- ocr_markdown: 참조용 OCR 마크다운 텍스트 (선택적)
- config_path: API 키 설정 파일 경로
- **kwargs: 추가 생성 파라미터
-
- Returns:
- 추출된 Markdown 테이블 문자열
-
- Example:
- ```python
- import asyncio
- from Table_example import aextract_table_from_image
-
- async def main():
- result = await aextract_table_from_image("insurance_table.png")
- print(result)
-
- asyncio.run(main())
- ```
- """
- extractor = InsuranceTableExtractor(config_path=config_path)
- return await extractor.aextract(image_path, ocr_markdown, **kwargs)
diff --git a/tests/choi/Table_example/test_extraction.ipynb b/tests/choi/Table_example/test_extraction.ipynb
deleted file mode 100644
index fc7a143..0000000
--- a/tests/choi/Table_example/test_extraction.ipynb
+++ /dev/null
@@ -1,610 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "markdown",
- "id": "03a4228b",
- "metadata": {},
- "source": [
- "## 1. 환경 설정"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "ac52abd7",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "프로젝트 루트: /Users/jaehyeokchoi/Desktop/chois_toy/private/TableMagnifier\n"
- ]
- }
- ],
- "source": [
- "import sys\n",
- "from pathlib import Path\n",
- "\n",
- "# 프로젝트 루트를 Python 경로에 추가\n",
- "project_root = Path.cwd().parent\n",
- "if str(project_root) not in sys.path:\n",
- " sys.path.insert(0, str(project_root))\n",
- "\n",
- "print(f\"프로젝트 루트: {project_root}\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "3f5862d6",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "✅ Table_example 패키지 로드 완료!\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "/Users/jaehyeokchoi/Desktop/chois_toy/private/TableMagnifier/.venv/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
- " from .autonotebook import tqdm as notebook_tqdm\n"
- ]
- }
- ],
- "source": [
- "# Table_example 패키지 임포트\n",
- "from Table_example import (\n",
- " InsuranceTableExtractor,\n",
- " extract_table_from_image,\n",
- " aextract_table_from_image,\n",
- " SYSTEM_PROMPT,\n",
- " USER_PROMPT_TEMPLATE,\n",
- ")\n",
- "from Table_example.prompts import get_user_prompt\n",
- "\n",
- "print(\"✅ Table_example 패키지 로드 완료!\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "7e2f995a",
- "metadata": {},
- "source": [
- "## 2. 프롬프트 확인\n",
- "\n",
- "보험 도메인 특화 프롬프트를 확인합니다."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "95f59ce1",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "📋 System Prompt:\n",
- "======================================================================\n",
- "# Role Definition\n",
- "당신은 20년 경력의 '수석 보험 데이터 엔지니어'이자 'OCR 후처리 전문가'입니다.\n",
- "당신의 임무는 제공된 [보험 문서 이미지]와 선택적으로 제공되는 [기초 OCR 텍스트]를 분석하여, 데이터베이스 적재가 가능한 완벽한 형태의 'Standardized Markdown Table'로 변환하는 것입니다.\n",
- "\n",
- "# Core Principles\n",
- "1. **구조적 완전성(Structural Integrity):** 시각적으로 병합(Merge)된 셀은 반드시 비정규화(Denormalization)하여 모든 행에 값을 채워야 합니다. 빈칸이나 \" 상동\" 등의 표현은 금지됩니다.\n",
- "2. **헤더 평탄화(Header Flattening):** 2행 이상의 계층적 헤더(Multi-row Headers)는 상위 헤더와 하위 헤더를 언더스코어(_)로 연결하여 단일 행(Single-row) 헤더로 변환합니다. (예: '보장내용' 하위에 '지급금액'이 있다면 -> '보장내용_지급금액')\n",
- "3. **데이터 무결성(Data Integrity):**\n",
- " - 금액의 천 단위 구분자(,)는 제거합니다. (예: 1,000,000 -> 1000000)\n",
- " - 퍼센트(%)는 기호를 포함한 문자열로 유지합니다. (예: 98.5%)\n",
- " - 괄호 안의 보조 정보(예: 전년 대비 증감액)는 무시하고 핵심 수치만 추출합니다.\n",
- "4. **Hybrid Reference:** [기초 OCR 텍스트]가 제공될 경우, 이미지 내 텍스트가 흐릿하거나 불분명할 때 해당 텍스트를 참조하여 오타를 교정하십시오. 단, 표의 구조(행/열 위치) 판단은 반드시 [원본 이미지]를 기준으로 합니다.\n",
- "======================================================================\n"
- ]
- }
- ],
- "source": [
- "# System Prompt 확인\n",
- "print(\"📋 System Prompt:\")\n",
- "print(\"=\" * 70)\n",
- "print(SYSTEM_PROMPT)\n",
- "print(\"=\" * 70)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "3bd4aaa6",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "📋 User Prompt Template:\n",
- "======================================================================\n",
- "# Task Description\n",
- "아래 제공된 입력을 바탕으로 보험 테이블 데이터를 추출하십시오.\n",
- "\n",
- "# Input Data\n",
- "1. **Target Image:** [첨부된 이미지]\n",
- "2. **Reference OCR Markdown (Optional):**\n",
- "\"\"\"\n",
- "{ocr_markdown}\n",
- "\"\"\"\n",
- "\n",
- "# Step-by-Step Instructions (Chain-of-Table)\n",
- "단계별로 생각하고 실행하십시오:\n",
- "\n",
- "**Step 1. 구조 분석 (Structure Analysis)**\n",
- "- 이미지를 보고 표의 전체적인 레이아웃을 파악하십시오.\n",
- "- 헤더가 몇 개의 행(Row)으로 구성되어 있는지 확인하십시오.\n",
- "- 세로로 병합된(Vertically Merged) '구분'이나 '기간' 컬럼이 있는지 식별하십시오.\n",
- "\n",
- "**Step 2. 헤더 처리 (Header Processing)**\n",
- "- 다중 행 헤더를 단일 행 키(Unique Key)로 변환하십시오.\n",
- "- 예:\n",
- " | 구분 | 해지환급금 |\n",
- " | | 금액 | 환급률 |\n",
- " -> | 구분 | 해지환급금_금액 | 해지환급금_환급률 |\n",
- "\n",
- "**Step 3. 데이터 추출 및 채우기 (Extraction & Filling)**\n",
- "- 각 행(Row)의 데이터를 추출하십시오.\n",
- "- **중요:** 병합된 셀은 해당 범위에 속하는 모든 행에 동일한 값을 반복 입력(Repeat Value)하십시오. 절대 빈 칸으로 두지 마십시오.\n",
- "- OCR 참고용 텍스트가 있다면, 숫자의 정확성을 검증하는 데 사용하십시오.\n",
- "\n",
- "**Step 4. 포맷팅 및 검증 (Formatting & Verification)**\n",
- "- 금액에서 '원', ',' 제거 / 정수형 변환.\n",
- "- 출력 전, 헤더의 컬럼 개수와 데이터 행의 컬럼 개수가 일치하는지 확인하십시오.\n",
- "\n",
- "# Output Format\n",
- "설명이나 사족 없이 오직 **Markdown Table** 만 출력하십시오.\n",
- "\n",
- "| 헤더1 | 헤더2_서브1 | 헤더2_서브2 | ... |\n",
- "| :--- | :--- | :--- | ... |\n",
- "| 값1 | 값2 | 값3 | ... |\n",
- "======================================================================\n"
- ]
- }
- ],
- "source": [
- "# User Prompt Template 확인\n",
- "print(\"📋 User Prompt Template:\")\n",
- "print(\"=\" * 70)\n",
- "print(USER_PROMPT_TEMPLATE)\n",
- "print(\"=\" * 70)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "efe2d4d4",
- "metadata": {},
- "source": [
- "## 3. 추출기 초기화\n",
- "\n",
- "API 키 설정 확인 및 추출기를 초기화합니다."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "id": "4d6f9bcb",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "✅ API 키 설정 파일 확인됨: /Users/jaehyeokchoi/Desktop/chois_toy/private/TableMagnifier/apis/gemini_keys.yaml\n"
- ]
- }
- ],
- "source": [
- "# API 키 설정 파일 확인\n",
- "config_path = project_root / \"apis\" / \"gemini_keys.yaml\"\n",
- "\n",
- "if not config_path.exists():\n",
- " print(f\"❌ API 키 설정 파일이 없습니다: {config_path}\")\n",
- " print(\"\\n다음 단계를 수행하세요:\")\n",
- " print(\"1. apis/gemini_keys-example.yaml을 apis/gemini_keys.yaml로 복사\")\n",
- " print(\"2. 실제 Gemini API 키를 입력\")\n",
- " print(\"3. Google AI Studio에서 무료 API 키 발급:\")\n",
- " print(\" https://makersuite.google.com/app/apikey\")\n",
- "else:\n",
- " print(f\"✅ API 키 설정 파일 확인됨: {config_path}\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "id": "08823fe6",
- "metadata": {},
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "2025-12-02 14:27:15,381 - polling_gemini.api_pool - INFO - 총 3개의 API 키를 로드했습니다.\n",
- "2025-12-02 14:27:15,382 - polling_gemini.api_pool - INFO - API 키 'key1' 사용 중 (모델: gemini-2.5-flash)\n",
- "2025-12-02 14:27:15,382 - polling_gemini.api_pool - INFO - API 키 'key1' 사용 중 (모델: gemini-2.5-flash)\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "✅ InsuranceTableExtractor 초기화 성공!\n",
- "\n",
- "현재 사용 중인 API 키: key1\n",
- "총 API 키 수: 3\n",
- "\n",
- "전체 API 키 상태:\n",
- " - key1: 활성화=True, 실패횟수=0\n",
- " - key2: 활성화=True, 실패횟수=0\n",
- " - key3: 활성화=True, 실패횟수=0\n"
- ]
- }
- ],
- "source": [
- "# InsuranceTableExtractor 초기화\n",
- "try:\n",
- " extractor = InsuranceTableExtractor()\n",
- " \n",
- " # API Pool 상태 확인\n",
- " status = extractor.get_pool_status()\n",
- " \n",
- " print(\"✅ InsuranceTableExtractor 초기화 성공!\")\n",
- " print(f\"\\n현재 사용 중인 API 키: {status['current_key']['name']}\")\n",
- " print(f\"총 API 키 수: {status['current_key']['total_keys']}\")\n",
- " \n",
- " print(\"\\n전체 API 키 상태:\")\n",
- " for key in status['all_keys']:\n",
- " print(f\" - {key['name']}: 활성화={key['enabled']}, 실패횟수={key['failed_count']}\")\n",
- " \n",
- "except FileNotFoundError as e:\n",
- " print(f\"❌ API 키 파일 오류: {e}\")\n",
- "except Exception as e:\n",
- " print(f\"❌ 초기화 실패: {e}\")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "41a30785",
- "metadata": {},
- "source": [
- "## 4. 샘플 이미지 확인\n",
- "\n",
- "테스트할 이미지 파일을 확인합니다."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "id": "dd007a21",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "📁 샘플 이미지 디렉토리: /Users/jaehyeokchoi/Desktop/chois_toy/private/TableMagnifier/Table_example/sample_images\n",
- "📷 발견된 이미지: 1개\n",
- " 1. I_table_78.png\n"
- ]
- }
- ],
- "source": [
- "# 샘플 이미지 디렉토리 확인\n",
- "sample_images_dir = Path.cwd() / \"sample_images\"\n",
- "\n",
- "if not sample_images_dir.exists():\n",
- " sample_images_dir.mkdir(parents=True, exist_ok=True)\n",
- " print(f\"📁 샘플 이미지 디렉토리 생성됨: {sample_images_dir}\")\n",
- "\n",
- "# 이미지 파일 검색\n",
- "image_extensions = [\"*.png\", \"*.jpg\", \"*.jpeg\", \"*.gif\", \"*.webp\", \"*.bmp\"]\n",
- "image_files = []\n",
- "for ext in image_extensions:\n",
- " image_files.extend(sample_images_dir.glob(ext))\n",
- "\n",
- "print(f\"\\n📁 샘플 이미지 디렉토리: {sample_images_dir}\")\n",
- "print(f\"📷 발견된 이미지: {len(image_files)}개\")\n",
- "\n",
- "if image_files:\n",
- " for i, img in enumerate(image_files, 1):\n",
- " print(f\" {i}. {img.name}\")\n",
- "else:\n",
- " print(\"\\n⚠️ 테스트할 이미지를 sample_images 폴더에 추가하세요!\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "id": "7f0f1733",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "📷 첫 번째 이미지 미리보기:\n"
- ]
- },
- {
- "data": {
- "image/png": "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DIiIiMCVm5iY6O28ZFB69+6N+Hg7FxmXFi1aZM2a1du5yLigJkF94u1cZFzKlSv3mlS2BmjVqtX/qRX3tWJ8gNehr9WrV68SEhJQ0lmzZtm4r5U63NeKhvta0XBfKxrua0XA3dgZn8Ln1SotLa179+7Vq1e/d+8ed2OnYbWiYbWiYbWiYbUiYLVifArfVquUlJTmzZujgE+ePEnnLwRdwWpFw2pFw2pFw2pFwGrF+BQ+rFYPHz6sW7du+/btU1NTxRJWKxpWKxpWKxpWKxpWKwJWK8an8FW1un37dsWKFfv06fPq1StpIasVDasVDasVDasVDasVAasV41P4pFpduXKlWLFio0ePdlrOakXDakXDakXDakXDakXAasX4FL6nVqdPn46NjZ0zZ458FasVDasVDasVDasVDasVAasV41P4mFolJSXlzp171apVimtZrWhYrWhYrWhYrWhYrQhYrRifwpfU6ocffsiVK9f27dvVNmC1omG1omG1omG1omG1ImC1YnwKn1Gr5cuXR0dHHzp0iNiG1YqG1YqG1YqG1YqG1YqA1YrxKXxDrWbOnBkbG3v27Fl6M1YrGlYrGlYrGlYrGlYrAlYrxqfwAbUaMWJE8eLFr1696nJLVisaVisaVisaVisaVisCVivGp8jUavXy5UtckJUqVbpz546W7VmtaFitaFitaFitaFitCFitGJ8i86rV8+fP27RpU79+/UePHmnchdWKhtWKhtWKhtWKhtWKgNWK8SkyqVo9fvy4YcOGLVu2hGBp34vViobViobViobViobVioDVivEpMqNa3b17t0qVKh999FFaWpquHVmtaFitaFitaFitaFitCFitGJ8i06nV9evXS5Ys+fnnnxvYl9WKhtWKhtWKhtWKhtWKgNWK+V9Onz6dkJDw4sULwymsW7du4cKFJmbJGJlLrX777be4uLipU6ca253ViobViobViobViobVioDVivlf6tevj3MAgmU4heLFiwcFBV25csXEXBkgE6nV4cOH8+TJs2zZMsMpsFrRsFrRsFrRsFrRsFoRZD61SkhI+Pbbb81K7fvvv0cIzErNLI4fP96xY8eHDx/KVyUnJ6NB1Zvg2bNn169fr7Z2165dOAGKFSv28uVLvSlLDBkyBIl069bNcAqmkFnUaseOHbly5UpMTHQnEVYrGlYrGlYrGlYrGlYr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QED58uXbt2+PEwPR+/LLL+FbEydOHDFiRM+ePRs1aiR96tikSRPFT0rTfVSt6tSpgyjJl7Na0bBa0bBa0bBa0bBaEXjuC8GnT59+8skn4qmME1CKH374QZ4UoVbNmzfX+8ikUKFCpjxLGzp0KFJDQfz8/DZs2KC2mXa1QtOYkJAQHBxss48jdf36dWQV/y9WrNjSpUufPXvmfp4J9u/fj2PNmjXLabmBvlbiw0m4td483Lt3b8KECRUqVKDH1IiIiGjZsiXdxc331AoSGR4ejstHvorViobViobViobViobVisBDaoWGoXr16liOK7lXr17z5s3bvHnz2rVrp06d2qBBA5GBuXPnYpXjB3H58uVTVKszZ85geZEiRbD7VxpAyhs3btQylrdLXr16Be/Jli3byZMnIyMjIViHDh1S3FJNrV6+fIm28MCBA19//TVcs2LFisInoFaTJ08W29y+ffu9994TYcmaNWuTJk3Gjx8P+zx37pzpprV161YcBZlxWm5ArRBn7JI9e3bDz9vu37+flJS0fPlyqN7EiRPHjRs3ZcoUcbYgPwidyxR8T61WrVqlViJWKxpWKxpWKxpWKxpWKwIPqZV40tOuXTvFgY6OHTsWHR2t9sRCrlYbNmxQfNDiARITE3Hovn37pttHy8ySJUuuXLkuXbok31JU61WqVGlop3379mLQc9EF2xEoGhxL3il+165drVq1cnrOBwOTfynmDmvWrLH984eZAgNqVadOHZFJmJCJOdSF76lVp06dZs+erbiK1YqG1YqG1YqG1YqG1YrAQ2pVsGDB3LlzP3/+XG2vlStX2uzjmzt22xIPtORqtXr1aixfvHixroyZQr169aCA586dE38uWrQIOcHll5KS4rSlqNYlAgICRPeg8ePHZ8uWrWTJkgjUiBEjdu/eTT/jefLkyapVq/r379+4ceOiRYvmzJlTOropiCLI37LpVSvx9Eu4YIUKFbQ8YbICH1MrhDEqKkpNnlitaFitaFitaFitaFitCCi1GjNmDJZv375dV4qINfZyevsWGhpKd8ER7/gGDBjguFCtr5W31AqWieO+//77jgs//PBD6TmWI6JaR+N31o7TFCUZhyFDhiCfcl3TpVY3btyIjY2FPuJ37NOnD3ZEsvQu+BGNjZvqSIcOHf7880/HZH1MrZKSkojKndWKhtWKhtWKhtWK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",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "image/png": {
- "width": 600
- }
- },
- "output_type": "display_data"
- }
- ],
- "source": [
- "# 이미지 미리보기 (IPython 사용)\n",
- "if image_files:\n",
- " from IPython.display import Image, display\n",
- " \n",
- " print(\"📷 첫 번째 이미지 미리보기:\")\n",
- " display(Image(filename=str(image_files[0]), width=600))"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "43bd0f11",
- "metadata": {},
- "source": [
- "## 5. 기본 테이블 추출\n",
- "\n",
- "이미지에서 테이블을 추출합니다."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "id": "101765ab",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "🎯 추출 대상 이미지: I_table_78.png\n"
- ]
- }
- ],
- "source": [
- "# 추출할 이미지 선택\n",
- "if image_files:\n",
- " # 첫 번째 이미지 사용\n",
- " target_image = image_files[0]\n",
- " print(f\"🎯 추출 대상 이미지: {target_image.name}\")\n",
- "else:\n",
- " print(\"❌ 이미지가 없습니다. sample_images 폴더에 이미지를 추가하세요.\")\n",
- " target_image = None"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "id": "8b4d4f8a",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "🚀 테이블 추출 시작: I_table_78.png\n",
- "======================================================================\n",
- "\n",
- "✅ 추출 완료!\n",
- "\n",
- "📊 결과 (Markdown Table):\n",
- "----------------------------------------------------------------------\n",
- "| 구분 | XX세 | XX+1세 | XX+2세 | XX+3세 | XX+4세 | XX+5세 |\n",
- "| :--- | :--- | :--- | :--- | :--- | :--- | :--- |\n",
- "| 나이증가분(A) | | 1059 | 1357 | 1739 | 2229 | 2855 |\n",
- "| 보험료 산출 기초율 (위험률 등) 증가분 (B=전년도 기준보험료의 최대 25% 가정) | | 10846 | 13897 | 17806 | 22815 | 29232 |\n",
- "| 기준보험료 (C=전년도 기준보험료+A+B) | 42325 | 54321 | 69485 | 89030 | 114074 | 146161 |\n",
- "----------------------------------------------------------------------\n",
- "CPU times: user 21.5 ms, sys: 14.8 ms, total: 36.3 ms\n",
- "Wall time: 14.7 s\n",
- "\n",
- "✅ 추출 완료!\n",
- "\n",
- "📊 결과 (Markdown Table):\n",
- "----------------------------------------------------------------------\n",
- "| 구분 | XX세 | XX+1세 | XX+2세 | XX+3세 | XX+4세 | XX+5세 |\n",
- "| :--- | :--- | :--- | :--- | :--- | :--- | :--- |\n",
- "| 나이증가분(A) | | 1059 | 1357 | 1739 | 2229 | 2855 |\n",
- "| 보험료 산출 기초율 (위험률 등) 증가분 (B=전년도 기준보험료의 최대 25% 가정) | | 10846 | 13897 | 17806 | 22815 | 29232 |\n",
- "| 기준보험료 (C=전년도 기준보험료+A+B) | 42325 | 54321 | 69485 | 89030 | 114074 | 146161 |\n",
- "----------------------------------------------------------------------\n",
- "CPU times: user 21.5 ms, sys: 14.8 ms, total: 36.3 ms\n",
- "Wall time: 14.7 s\n"
- ]
- }
- ],
- "source": [
- "%%time\n",
- "# 테이블 추출 실행\n",
- "if target_image:\n",
- " print(f\"🚀 테이블 추출 시작: {target_image.name}\")\n",
- " print(\"=\" * 70)\n",
- " \n",
- " try:\n",
- " result = extract_table_from_image(target_image)\n",
- " \n",
- " print(\"\\n✅ 추출 완료!\")\n",
- " print(\"\\n📊 결과 (Markdown Table):\")\n",
- " print(\"-\" * 70)\n",
- " print(result)\n",
- " print(\"-\" * 70)\n",
- " \n",
- " except Exception as e:\n",
- " print(f\"❌ 추출 실패: {e}\")\n",
- " import traceback\n",
- " traceback.print_exc()"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "bc284731",
- "metadata": {},
- "source": [
- "## 6. OCR 참조 텍스트와 함께 추출\n",
- "\n",
- "OCR로 먼저 추출한 텍스트를 참조로 제공하여 정확도를 높입니다."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "id": "361949ff",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "✅ OCR 참조 파일 로드됨: I_table_78.md\n",
- "\n",
- "📝 OCR 참조 텍스트:\n",
- "----------------------------------------------------------------------\n",
- "|구분|XX세|XX+1세|XX+2세|XX+3세|XX+4세|XX+5세|\n",
- "|---|---|---|---|---|---|---|\n",
- "|나이증가분(A)||1,059|1,357|1,739|2,229|2,855|\n",
- "|보험료 산출 기초율
(위험률 등) 증가분
(B=전년도
기준보험료의 최대
25% 가정)||10,846|13,897|17,806|22,815|29,232|\n",
- "|기준보험료
(C=전년도
기준보험료+A+B)|42,325|54,321|69,485|89,030|114,074|146,161|\n",
- "----------------------------------------------------------------------\n"
- ]
- }
- ],
- "source": [
- "# OCR 참조 텍스트 로드 (이미지와 같은 이름의 .md 파일에서)\n",
- "# 예: I_table_78.png → I_table_78.md\n",
- "\n",
- "if target_image:\n",
- " # 이미지와 같은 이름의 .md 파일 찾기\n",
- " ocr_md_path = target_image.with_suffix(\".md\")\n",
- " \n",
- " if ocr_md_path.exists():\n",
- " with open(ocr_md_path, \"r\", encoding=\"utf-8\") as f:\n",
- " sample_ocr_markdown = f.read().strip()\n",
- " print(f\"✅ OCR 참조 파일 로드됨: {ocr_md_path.name}\")\n",
- " print(\"\\n📝 OCR 참조 텍스트:\")\n",
- " print(\"-\" * 70)\n",
- " print(sample_ocr_markdown)\n",
- " print(\"-\" * 70)\n",
- " else:\n",
- " sample_ocr_markdown = None\n",
- " print(f\"⚠️ OCR 참조 파일이 없습니다: {ocr_md_path.name}\")\n",
- " print(\" 이미지와 같은 이름의 .md 파일을 sample_images 폴더에 추가하세요.\")\n",
- "else:\n",
- " sample_ocr_markdown = None\n",
- " print(\"❌ 대상 이미지가 없습니다.\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "id": "8495b93f",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "🚀 OCR 참조와 함께 테이블 추출: I_table_78.png\n",
- "======================================================================\n",
- "\n",
- "✅ 추출 완료!\n",
- "\n",
- "📊 결과 (OCR 참조 사용):\n",
- "----------------------------------------------------------------------\n",
- "|구분|XX세|XX+1세|XX+2세|XX+3세|XX+4세|XX+5세|\n",
- "|:---|:---|:---|:---|:---|:---|:---|:---|\n",
- "|나이증가분(A)||1059|1357|1739|2229|2855|\n",
- "|보험료 산출 기초율 (위험률 등) 증가분 (B=전년도 기준보험료의 최대 25% 가정)||10846|13897|17806|22815|29232|\n",
- "|기준보험료 (C=전년도 기준보험료+A+B)|42325|54321|69485|89030|114074|146161|\n",
- "----------------------------------------------------------------------\n",
- "CPU times: user 17.5 ms, sys: 17.2 ms, total: 34.7 ms\n",
- "Wall time: 20.8 s\n",
- "\n",
- "✅ 추출 완료!\n",
- "\n",
- "📊 결과 (OCR 참조 사용):\n",
- "----------------------------------------------------------------------\n",
- "|구분|XX세|XX+1세|XX+2세|XX+3세|XX+4세|XX+5세|\n",
- "|:---|:---|:---|:---|:---|:---|:---|:---|\n",
- "|나이증가분(A)||1059|1357|1739|2229|2855|\n",
- "|보험료 산출 기초율 (위험률 등) 증가분 (B=전년도 기준보험료의 최대 25% 가정)||10846|13897|17806|22815|29232|\n",
- "|기준보험료 (C=전년도 기준보험료+A+B)|42325|54321|69485|89030|114074|146161|\n",
- "----------------------------------------------------------------------\n",
- "CPU times: user 17.5 ms, sys: 17.2 ms, total: 34.7 ms\n",
- "Wall time: 20.8 s\n"
- ]
- }
- ],
- "source": [
- "%%time\n",
- "# OCR 참조와 함께 테이블 추출\n",
- "if target_image and sample_ocr_markdown:\n",
- " print(f\"🚀 OCR 참조와 함께 테이블 추출: {target_image.name}\")\n",
- " print(\"=\" * 70)\n",
- " \n",
- " try:\n",
- " result_with_ocr = extract_table_from_image(\n",
- " target_image,\n",
- " ocr_markdown=sample_ocr_markdown\n",
- " )\n",
- " \n",
- " print(\"\\n✅ 추출 완료!\")\n",
- " print(\"\\n📊 결과 (OCR 참조 사용):\")\n",
- " print(\"-\" * 70)\n",
- " print(result_with_ocr)\n",
- " print(\"-\" * 70)\n",
- " \n",
- " except Exception as e:\n",
- " print(f\"❌ 추출 실패: {e}\")\n",
- "elif target_image and not sample_ocr_markdown:\n",
- " print(\"⚠️ OCR 참조 파일이 없어서 이 섹션을 건너뜁니다.\")\n",
- " print(f\" {target_image.stem}.md 파일을 sample_images 폴더에 추가하세요.\")\n",
- "else:\n",
- " print(\"❌ 이미지가 없습니다.\")"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": ".venv",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.12.11"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/tests/choi/Table_example/test_extraction.py b/tests/choi/Table_example/test_extraction.py
deleted file mode 100644
index fb4e153..0000000
--- a/tests/choi/Table_example/test_extraction.py
+++ /dev/null
@@ -1,346 +0,0 @@
-"""
-보험 테이블 추출 테스트 코드
-Table_example 패키지를 사용하여 이미지에서 테이블을 추출하는 예제
-"""
-
-import sys
-import asyncio
-from pathlib import Path
-
-# 프로젝트 루트를 Python 경로에 추가
-project_root = Path(__file__).parent.parent
-sys.path.insert(0, str(project_root))
-
-from Table_example import (
- InsuranceTableExtractor,
- extract_table_from_image,
- aextract_table_from_image,
- SYSTEM_PROMPT,
- USER_PROMPT_TEMPLATE,
-)
-
-
-def test_prompt_display():
- """1. 프롬프트 내용 확인"""
- print("\n" + "="*70)
- print("테스트 1: 프롬프트 내용 확인")
- print("="*70)
-
- print("\n📋 System Prompt:")
- print("-"*50)
- print(SYSTEM_PROMPT[:500] + "...")
-
- print("\n📋 User Prompt Template (일부):")
- print("-"*50)
- print(USER_PROMPT_TEMPLATE[:500] + "...")
-
- print("\n✅ 프롬프트 로드 성공!")
- return True
-
-
-def test_extractor_initialization():
- """2. 추출기 초기화 테스트"""
- print("\n" + "="*70)
- print("테스트 2: InsuranceTableExtractor 초기화")
- print("="*70)
-
- try:
- extractor = InsuranceTableExtractor()
-
- status = extractor.get_pool_status()
- print(f"\n현재 사용 중인 키: {status['current_key']['name']}")
- print(f"총 API 키 수: {status['current_key']['total_keys']}")
-
- print("\n✅ 추출기 초기화 성공!")
- return True
-
- except FileNotFoundError as e:
- print(f"\n⚠️ API 키 파일이 없습니다: {e}")
- print("apis/gemini_keys.yaml 파일을 생성하세요.")
- return False
- except Exception as e:
- print(f"\n❌ 초기화 실패: {e}")
- return False
-
-
-def test_extract_from_sample_image():
- """3. 샘플 이미지에서 테이블 추출 테스트"""
- print("\n" + "="*70)
- print("테스트 3: 샘플 이미지에서 테이블 추출")
- print("="*70)
-
- # 샘플 이미지 경로 확인
- sample_images_dir = project_root / "Table_example" / "sample_images"
-
- if not sample_images_dir.exists():
- print(f"\n⚠️ 샘플 이미지 디렉토리가 없습니다: {sample_images_dir}")
- print("sample_images 폴더에 테스트 이미지를 추가하세요.")
- return None
-
- # 샘플 이미지 찾기
- image_files = list(sample_images_dir.glob("*.png")) + \
- list(sample_images_dir.glob("*.jpg")) + \
- list(sample_images_dir.glob("*.jpeg"))
-
- if not image_files:
- print(f"\n⚠️ 샘플 이미지가 없습니다: {sample_images_dir}")
- print("PNG, JPG, JPEG 형식의 이미지를 추가하세요.")
- return None
-
- # 첫 번째 이미지로 테스트
- image_path = image_files[0]
- print(f"\n테스트 이미지: {image_path.name}")
-
- try:
- # 테이블 추출
- result = extract_table_from_image(image_path)
-
- print("\n📊 추출 결과:")
- print("-"*50)
- print(result)
- print("-"*50)
-
- print("\n✅ 테이블 추출 성공!")
- return result
-
- except Exception as e:
- print(f"\n❌ 추출 실패: {e}")
- import traceback
- traceback.print_exc()
- return None
-
-
-def test_extract_with_ocr_reference():
- """4. OCR 참조 텍스트와 함께 추출 테스트"""
- print("\n" + "="*70)
- print("테스트 4: OCR 참조 텍스트와 함께 추출")
- print("="*70)
-
- sample_images_dir = project_root / "Table_example" / "sample_images"
-
- if not sample_images_dir.exists():
- print(f"\n⚠️ 샘플 이미지 디렉토리가 없습니다.")
- return None
-
- image_files = list(sample_images_dir.glob("*.png")) + \
- list(sample_images_dir.glob("*.jpg"))
-
- if not image_files:
- print(f"\n⚠️ 샘플 이미지가 없습니다.")
- return None
-
- image_path = image_files[0]
- print(f"\n테스트 이미지: {image_path.name}")
-
- # OCR 참조 텍스트 예시 (실제로는 OCR 결과를 사용)
- sample_ocr_markdown = """| 구분 | 보험기간 | 납입기간 | 가입금액 |
-| 상해사망 | 80세 | 20년 | 1억원 |
-| 질병사망 | 80세 | 20년 | 5천만원 |"""
-
- try:
- result = extract_table_from_image(
- image_path,
- ocr_markdown=sample_ocr_markdown
- )
-
- print("\n📊 추출 결과 (OCR 참조 사용):")
- print("-"*50)
- print(result)
- print("-"*50)
-
- print("\n✅ OCR 참조 추출 성공!")
- return result
-
- except Exception as e:
- print(f"\n❌ 추출 실패: {e}")
- import traceback
- traceback.print_exc()
- return None
-
-
-def test_async_extraction():
- """5. 비동기 테이블 추출 테스트"""
- print("\n" + "="*70)
- print("테스트 5: 비동기 테이블 추출")
- print("="*70)
-
- async def async_test():
- sample_images_dir = project_root / "Table_example" / "sample_images"
-
- if not sample_images_dir.exists():
- print(f"\n⚠️ 샘플 이미지 디렉토리가 없습니다.")
- return None
-
- image_files = list(sample_images_dir.glob("*.png")) + \
- list(sample_images_dir.glob("*.jpg"))
-
- if not image_files:
- print(f"\n⚠️ 샘플 이미지가 없습니다.")
- return None
-
- image_path = image_files[0]
- print(f"\n테스트 이미지: {image_path.name}")
-
- try:
- import time
- start_time = time.time()
-
- result = await aextract_table_from_image(image_path)
-
- elapsed = time.time() - start_time
-
- print(f"\n⏱️ 소요 시간: {elapsed:.2f}초")
- print("\n📊 추출 결과:")
- print("-"*50)
- print(result[:500] + "..." if len(result) > 500 else result)
- print("-"*50)
-
- print("\n✅ 비동기 추출 성공!")
- return result
-
- except Exception as e:
- print(f"\n❌ 추출 실패: {e}")
- import traceback
- traceback.print_exc()
- return None
-
- return asyncio.run(async_test())
-
-
-def test_multiple_images():
- """6. 여러 이미지 동시 처리 테스트"""
- print("\n" + "="*70)
- print("테스트 6: 여러 이미지 동시 처리 (비동기)")
- print("="*70)
-
- async def async_test():
- sample_images_dir = project_root / "Table_example" / "sample_images"
-
- if not sample_images_dir.exists():
- print(f"\n⚠️ 샘플 이미지 디렉토리가 없습니다.")
- return None
-
- image_files = list(sample_images_dir.glob("*.png")) + \
- list(sample_images_dir.glob("*.jpg")) + \
- list(sample_images_dir.glob("*.jpeg"))
-
- if len(image_files) < 2:
- print(f"\n⚠️ 2개 이상의 샘플 이미지가 필요합니다. 현재: {len(image_files)}개")
- return None
-
- # 최대 3개 이미지 처리
- images_to_process = image_files[:3]
-
- print(f"\n처리할 이미지 {len(images_to_process)}개:")
- for img in images_to_process:
- print(f" - {img.name}")
-
- try:
- import time
- start_time = time.time()
-
- # 동시에 여러 이미지 처리
- tasks = [aextract_table_from_image(img) for img in images_to_process]
- results = await asyncio.gather(*tasks, return_exceptions=True)
-
- elapsed = time.time() - start_time
-
- print(f"\n⏱️ 총 소요 시간: {elapsed:.2f}초")
-
- for i, (img, result) in enumerate(zip(images_to_process, results), 1):
- print(f"\n📊 이미지 {i} ({img.name}) 결과:")
- print("-"*40)
- if isinstance(result, Exception):
- print(f"❌ 에러: {result}")
- else:
- print(result[:300] + "..." if len(result) > 300 else result)
-
- success_count = sum(1 for r in results if not isinstance(r, Exception))
- print(f"\n✅ {len(images_to_process)}개 중 {success_count}개 성공!")
- return results
-
- except Exception as e:
- print(f"\n❌ 처리 실패: {e}")
- import traceback
- traceback.print_exc()
- return None
-
- return asyncio.run(async_test())
-
-
-def main():
- """모든 테스트 실행"""
- print("\n" + "🏥 " * 20)
- print("보험 테이블 추출 테스트 시작")
- print("🏥 " * 20)
-
- # API 키 설정 확인
- config_path = project_root / "apis" / "gemini_keys.yaml"
- if not config_path.exists():
- print(f"\n❌ 오류: API 키 설정 파일이 없습니다: {config_path}")
- print("\n다음 단계를 수행하세요:")
- print("1. apis/gemini_keys-example.yaml을 apis/gemini_keys.yaml로 복사")
- print("2. 실제 Gemini API 키를 입력")
- print("3. Google AI Studio에서 무료 API 키 발급:")
- print(" https://makersuite.google.com/app/apikey")
- return
-
- # 샘플 이미지 디렉토리 확인/생성
- sample_images_dir = project_root / "Table_example" / "sample_images"
- if not sample_images_dir.exists():
- sample_images_dir.mkdir(parents=True, exist_ok=True)
- print(f"\n📁 샘플 이미지 디렉토리를 생성했습니다: {sample_images_dir}")
- print("⚠️ 테스트할 보험 테이블 이미지를 이 폴더에 추가하세요.")
-
- # 테스트 실행
- tests = [
- ("프롬프트 확인", test_prompt_display),
- ("추출기 초기화", test_extractor_initialization),
- ("이미지 추출", test_extract_from_sample_image),
- ("OCR 참조 추출", test_extract_with_ocr_reference),
- ("비동기 추출", test_async_extraction),
- ("다중 이미지", test_multiple_images),
- ]
-
- results = []
- for name, test_func in tests:
- try:
- result = test_func()
- # None은 이미지가 없어서 스킵된 경우
- if result is None:
- results.append((name, "skipped"))
- else:
- results.append((name, "success"))
- except KeyboardInterrupt:
- print("\n\n⚠️ 사용자가 테스트를 중단했습니다.")
- break
- except Exception as e:
- print(f"\n❌ 예상치 못한 오류: {e}")
- results.append((name, "failed"))
-
- # 결과 요약
- print("\n" + "=" * 70)
- print("테스트 결과 요약")
- print("=" * 70)
-
- for name, status in results:
- if status == "success":
- icon = "✅"
- elif status == "skipped":
- icon = "⏭️ "
- else:
- icon = "❌"
- print(f"{icon} {name}: {status}")
-
- success_count = sum(1 for _, s in results if s == "success")
- skipped_count = sum(1 for _, s in results if s == "skipped")
- total_count = len(results)
-
- print(f"\n총 {total_count}개 테스트 중 {success_count}개 성공, {skipped_count}개 스킵")
-
- if skipped_count > 0:
- print("\n💡 팁: sample_images 폴더에 보험 테이블 이미지를 추가하면 더 많은 테스트가 실행됩니다.")
-
-
-if __name__ == "__main__":
- main()
diff --git a/tests/choi/upload_fin.txt b/tests/choi/upload_fin.txt
deleted file mode 100644
index da757cb..0000000
--- a/tests/choi/upload_fin.txt
+++ /dev/null
@@ -1 +0,0 @@
-I_origin_0/I_table_1.png
diff --git a/tests/test_flow.py b/tests/test_flow.py
deleted file mode 100644
index 417c125..0000000
--- a/tests/test_flow.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import pytest
-from unittest.mock import MagicMock
-from langchain_core.messages import AIMessage
-from generate_synthetic_table.flow import build_synthetic_table_graph, TableState
-
-@pytest.fixture
-def mock_llm():
- llm = MagicMock()
- llm.invoke.return_value = AIMessage(content="Mock response")
- return llm
-
-def test_graph_compilation(mock_llm):
- graph = build_synthetic_table_graph(mock_llm)
- assert graph is not None
-
-def test_image_to_html_node(mock_llm):
- # This is a bit harder to test without mocking the file system or _load_prompt
- # For now, we just check if the graph builds and runs with a mock
- pass
diff --git a/tests/test_html_to_image.py b/tests/test_html_to_image.py
deleted file mode 100644
index e90c721..0000000
--- a/tests/test_html_to_image.py
+++ /dev/null
@@ -1,41 +0,0 @@
-
-from pathlib import Path
-import pytest
-from generate_synthetic_table.html_to_image import capture_html_as_image
-
-def test_capture_html_as_image(tmp_path):
- html = """
-
-
-
-
-
- Test Table
-
-
- | Name |
- Age |
-
-
- | Alice |
- 30 |
-
-
- | Bob |
- 25 |
-
-
-
-
- """
-
- output_path = tmp_path / "test_table.png"
- capture_html_as_image(html, output_path)
-
- assert output_path.exists()
- assert output_path.stat().st_size > 0
- print(f"Image saved to {output_path}")
diff --git a/tests/test_utils.py b/tests/test_utils.py
deleted file mode 100644
index d78f755..0000000
--- a/tests/test_utils.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import pytest
-from generate_synthetic_table.validators import robust_json_parse, validate_html
-
-def test_robust_json_parse_valid():
- assert robust_json_parse('{"a": 1}') == {"a": 1}
-
-def test_robust_json_parse_markdown():
- text = """
- Here is the json:
- ```json
- {
- "key": "value"
- }
- ```
- """
- assert robust_json_parse(text) == {"key": "value"}
-
-def test_robust_json_parse_markdown_no_lang():
- text = """
- ```
- {"x": [1, 2]}
- ```
- """
- assert robust_json_parse(text) == {"x": [1, 2]}
-
-def test_robust_json_parse_dirty():
- text = "Sure! {\"a\": 1} is the answer."
- assert robust_json_parse(text) == {"a": 1}
-
-def test_validate_html_valid():
- html = ""
- assert validate_html(html) is True
-
-def test_validate_html_invalid_structure():
- html = "Not a table
"
- assert validate_html(html) is False
-
-def test_validate_html_empty():
- assert validate_html("") is False
diff --git a/tests/test_validation.py b/tests/test_validation.py
deleted file mode 100644
index 3b72a1b..0000000
--- a/tests/test_validation.py
+++ /dev/null
@@ -1,354 +0,0 @@
-"""3단계 검증 체인 테스트 스크립트 (standalone)"""
-
-import re
-import logging
-from typing import Optional, Any, List, Tuple
-from bs4 import BeautifulSoup
-
-# pandas/pandasql import
-try:
- import pandas as pd
- from pandasql import sqldf
- PANDAS_SQL_AVAILABLE = True
-except ImportError:
- PANDAS_SQL_AVAILABLE = False
- pd = None
- sqldf = None
-
-# REPL import
-try:
- from langchain_experimental.tools import PythonREPLTool
- REPL_AVAILABLE = True
-except ImportError:
- REPL_AVAILABLE = False
- PythonREPLTool = None
-
-logger = logging.getLogger(__name__)
-
-
-def parse_html_table_to_json(html: str) -> Optional[dict]:
- """HTML 테이블을 JSON으로 파싱"""
- if not html:
- return None
-
- try:
- soup = BeautifulSoup(html, "html.parser")
- table = soup.find("table")
- if not table:
- return None
-
- rows = table.find_all("tr")
- if not rows:
- return None
-
- max_cols = 0
- for row in rows:
- cols = sum(int(cell.get("colspan", 1)) for cell in row.find_all(["td", "th"]))
- max_cols = max(max_cols, cols)
-
- if max_cols == 0:
- return None
-
- grid = []
- for row_idx, row in enumerate(rows):
- while len(grid) <= row_idx:
- grid.append([None] * max_cols)
-
- col_idx = 0
- for cell in row.find_all(["td", "th"]):
- while col_idx < max_cols and grid[row_idx][col_idx] is not None:
- col_idx += 1
-
- if col_idx >= max_cols:
- break
-
- cell_text = cell.get_text(strip=True)
- colspan = int(cell.get("colspan", 1))
- rowspan = int(cell.get("rowspan", 1))
-
- for r in range(rowspan):
- for c in range(colspan):
- target_row = row_idx + r
- target_col = col_idx + c
- while len(grid) <= target_row:
- grid.append([None] * max_cols)
- if target_col < max_cols:
- grid[target_row][target_col] = cell_text
-
- col_idx += colspan
-
- raw_rows = [[cell if cell is not None else "" for cell in row] for row in grid]
- if not raw_rows:
- return None
-
- has_header = bool(rows[0].find_all("th"))
-
- if has_header and len(raw_rows) > 1:
- headers = raw_rows[0]
- data = raw_rows[1:]
- else:
- headers = [f"col_{i+1}" for i in range(len(raw_rows[0]))]
- data = raw_rows
-
- return {"headers": headers, "data": data, "raw_rows": raw_rows}
- except Exception as e:
- logger.error(f"HTML parsing failed: {e}")
- return None
-
-
-def html_table_to_dataframe(html: str) -> Optional[Any]:
- """HTML 테이블을 DataFrame으로 변환"""
- if not PANDAS_SQL_AVAILABLE:
- return None
-
- parsed = parse_html_table_to_json(html)
- if not parsed:
- return None
-
- try:
- headers = parsed["headers"]
- data = parsed["data"]
-
- clean_headers = []
- for i, h in enumerate(headers):
- clean = re.sub(r'[^\w가-힣]', '_', str(h).strip())
- clean = re.sub(r'_+', '_', clean).strip('_')
- if not clean or clean[0].isdigit():
- clean = f"col_{i}"
- clean_headers.append(clean)
-
- seen = {}
- final_headers = []
- for h in clean_headers:
- if h in seen:
- seen[h] += 1
- final_headers.append(f"{h}_{seen[h]}")
- else:
- seen[h] = 0
- final_headers.append(h)
-
- return pd.DataFrame(data, columns=final_headers)
- except Exception as e:
- logger.error(f"DataFrame conversion failed: {e}")
- return None
-
-
-def compare_tables_with_sql(original_html: str, synthetic_html: str) -> Tuple[bool, List[str]]:
- """pandasql로 두 테이블 비교"""
- if not PANDAS_SQL_AVAILABLE:
- return True, ["pandas/pandasql not available"]
-
- issues = []
-
- df_original = html_table_to_dataframe(original_html)
- df_synthetic = html_table_to_dataframe(synthetic_html)
-
- if df_original is None:
- return False, ["원본 테이블 변환 실패"]
- if df_synthetic is None:
- return False, ["합성 테이블 변환 실패"]
-
- orig_shape = df_original.shape
- synth_shape = df_synthetic.shape
-
- if orig_shape[1] != synth_shape[1]:
- issues.append(f"열 수 불일치: 원본={orig_shape[1]}, 합성={synth_shape[1]}")
-
- if orig_shape[0] != synth_shape[0]:
- issues.append(f"행 수 불일치: 원본={orig_shape[0]}, 합성={synth_shape[0]}")
-
- if orig_shape[1] != synth_shape[1]:
- return False, issues
-
- try:
- common_cols = [f"c{i}" for i in range(orig_shape[1])]
- df_original.columns = common_cols
- df_synthetic.columns = common_cols
-
- env = {"df_original": df_original, "df_synthetic": df_synthetic}
-
- numeric_cols = df_original.select_dtypes(include=['number']).columns.tolist()
-
- for col in numeric_cols:
- try:
- sum_query = f"""
- SELECT
- (SELECT COALESCE(SUM(CAST({col} AS REAL)), 0) FROM df_original) as orig_sum,
- (SELECT COALESCE(SUM(CAST({col} AS REAL)), 0) FROM df_synthetic) as synth_sum
- """
- sum_result = sqldf(sum_query, env)
- orig_sum = sum_result.iloc[0]['orig_sum']
- synth_sum = sum_result.iloc[0]['synth_sum']
-
- if abs(orig_sum - synth_sum) > 0.01:
- issues.append(f"열 '{col}' 합계 불일치: 원본={orig_sum:.2f}, 합성={synth_sum:.2f}")
- except:
- pass
-
- except Exception as e:
- issues.append(f"SQL 비교 오류: {e}")
-
- passed = len([i for i in issues if not i.startswith(" -")]) == 0
- return passed, issues
-
-
-def compare_tables_with_repl(original_html: str, synthetic_html: str) -> Tuple[bool, List[str]]:
- """REPL로 두 테이블 비교"""
- if not REPL_AVAILABLE or not PANDAS_SQL_AVAILABLE:
- return True, ["REPL 사용 불가"]
-
- df_original = html_table_to_dataframe(original_html)
- df_synthetic = html_table_to_dataframe(synthetic_html)
-
- if df_original is None or df_synthetic is None:
- return False, ["DataFrame 변환 실패"]
-
- issues = []
-
- try:
- # Shape 비교
- if df_original.shape != df_synthetic.shape:
- issues.append(f"Shape 불일치: 원본={df_original.shape}, 합성={df_synthetic.shape}")
-
- # 행 수 비교
- if len(df_original) != len(df_synthetic):
- issues.append(f"행 수 불일치: 원본={len(df_original)}, 합성={len(df_synthetic)}")
-
- # 숫자 컬럼 합계 비교
- for col in df_original.columns:
- if col in df_synthetic.columns:
- try:
- orig_sum = pd.to_numeric(df_original[col], errors='coerce').sum()
- synth_sum = pd.to_numeric(df_synthetic[col], errors='coerce').sum()
- if pd.notna(orig_sum) and pd.notna(synth_sum):
- if abs(orig_sum - synth_sum) > 0.01:
- issues.append(f"컬럼 '{col}' 합계 불일치: 원본={orig_sum:.2f}, 합성={synth_sum:.2f}")
- except:
- pass
-
- except Exception as e:
- issues.append(f"REPL 비교 오류: {e}")
-
- return len(issues) == 0, issues
-
-print("=" * 60)
-print("3단계 검증 체인 테스트")
-print("=" * 60)
-
-# 패키지 상태 확인
-print(f"\n📦 패키지 상태:")
-print(f" - pandas/pandasql: {'✅ 사용 가능' if PANDAS_SQL_AVAILABLE else '❌ 없음'}")
-print(f" - langchain REPL: {'✅ 사용 가능' if REPL_AVAILABLE else '❌ 없음'}")
-
-# 테스트용 HTML 테이블
-original_html = """
-
-
- | 이름 | 나이 | 점수 |
-
-
- | 김철수 | 25 | 85 |
- | 이영희 | 30 | 92 |
- | 박민수 | 28 | 78 |
-
-
-"""
-
-# 테스트 1: 동일한 테이블 비교 (PASS 예상)
-print("\n" + "=" * 60)
-print("테스트 1: 동일한 테이블 비교 (PASS 예상)")
-print("=" * 60)
-
-identical_synthetic = """
-
- | 이름 | 나이 | 점수 |
- | 김철수 | 25 | 85 |
- | 이영희 | 30 | 92 |
- | 박민수 | 28 | 78 |
-
-"""
-
-print("\n[1/3] pandasql 검증...")
-passed, issues = compare_tables_with_sql(original_html, identical_synthetic)
-print(f" 결과: {'✅ PASS' if passed else '❌ FAIL'}")
-if issues:
- print(f" 이슈: {issues}")
-
-print("\n[2/3] REPL 검증...")
-passed, issues = compare_tables_with_repl(original_html, identical_synthetic)
-print(f" 결과: {'✅ PASS' if passed else '❌ FAIL'}")
-if issues:
- print(f" 이슈: {issues}")
-
-# 테스트 2: 행 수가 다른 테이블 (FAIL 예상)
-print("\n" + "=" * 60)
-print("테스트 2: 행 수가 다른 테이블 (FAIL 예상)")
-print("=" * 60)
-
-different_rows = """
-
- | 이름 | 나이 | 점수 |
- | 김철수 | 25 | 85 |
- | 이영희 | 30 | 92 |
-
-"""
-
-print("\n[1/3] pandasql 검증...")
-passed, issues = compare_tables_with_sql(original_html, different_rows)
-print(f" 결과: {'✅ PASS' if passed else '❌ FAIL'}")
-if issues:
- for issue in issues[:5]:
- print(f" - {issue}")
-
-print("\n[2/3] REPL 검증...")
-passed, issues = compare_tables_with_repl(original_html, different_rows)
-print(f" 결과: {'✅ PASS' if passed else '❌ FAIL'}")
-if issues:
- for issue in issues[:5]:
- print(f" - {issue}")
-
-# 테스트 3: 숫자 값이 다른 테이블 (FAIL 예상)
-print("\n" + "=" * 60)
-print("테스트 3: 숫자 값이 다른 테이블 (FAIL 예상)")
-print("=" * 60)
-
-different_values = """
-
- | 이름 | 나이 | 점수 |
- | 김철수 | 25 | 90 |
- | 이영희 | 30 | 95 |
- | 박민수 | 28 | 80 |
-
-"""
-
-print("\n[1/3] pandasql 검증...")
-passed, issues = compare_tables_with_sql(original_html, different_values)
-print(f" 결과: {'✅ PASS' if passed else '❌ FAIL'}")
-if issues:
- for issue in issues[:5]:
- print(f" - {issue}")
-
-print("\n[2/3] REPL 검증...")
-passed, issues = compare_tables_with_repl(original_html, different_values)
-print(f" 결과: {'✅ PASS' if passed else '❌ FAIL'}")
-if issues:
- for issue in issues[:5]:
- print(f" - {issue}")
-
-# DataFrame 변환 테스트
-print("\n" + "=" * 60)
-print("DataFrame 변환 테스트")
-print("=" * 60)
-
-df = html_table_to_dataframe(original_html)
-if df is not None:
- print(f"\n변환된 DataFrame:")
- print(df)
- print(f"\nShape: {df.shape}")
- print(f"Columns: {list(df.columns)}")
-else:
- print("❌ DataFrame 변환 실패")
-
-print("\n" + "=" * 60)
-print("테스트 완료!")
-print("=" * 60)
diff --git a/uv.lock b/uv.lock
index 9e69bc9..6daa4bd 100644
--- a/uv.lock
+++ b/uv.lock
@@ -1,5 +1,5 @@
version = 1
-revision = 2
+revision = 3
requires-python = ">=3.12"
resolution-markers = [
"python_full_version >= '3.14'",
@@ -2425,6 +2425,25 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" },
]
+[[package]]
+name = "playwright"
+version = "1.57.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "greenlet" },
+ { name = "pyee" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ed/b6/e17543cea8290ae4dced10be21d5a43c360096aa2cce0aa7039e60c50df3/playwright-1.57.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:9351c1ac3dfd9b3820fe7fc4340d96c0d3736bb68097b9b7a69bd45d25e9370c", size = 41985039, upload-time = "2025-12-09T08:06:18.408Z" },
+ { url = "https://files.pythonhosted.org/packages/8b/04/ef95b67e1ff59c080b2effd1a9a96984d6953f667c91dfe9d77c838fc956/playwright-1.57.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a4a9d65027bce48eeba842408bcc1421502dfd7e41e28d207e94260fa93ca67e", size = 40775575, upload-time = "2025-12-09T08:06:22.105Z" },
+ { url = "https://files.pythonhosted.org/packages/60/bd/5563850322a663956c927eefcf1457d12917e8f118c214410e815f2147d1/playwright-1.57.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:99104771abc4eafee48f47dac2369e0015516dc1ce8c409807d2dd440828b9a4", size = 41985042, upload-time = "2025-12-09T08:06:25.357Z" },
+ { url = "https://files.pythonhosted.org/packages/56/61/3a803cb5ae0321715bfd5247ea871d25b32c8f372aeb70550a90c5f586df/playwright-1.57.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:284ed5a706b7c389a06caa431b2f0ba9ac4130113c3a779767dda758c2497bb1", size = 45975252, upload-time = "2025-12-09T08:06:29.186Z" },
+ { url = "https://files.pythonhosted.org/packages/83/d7/b72eb59dfbea0013a7f9731878df8c670f5f35318cedb010c8a30292c118/playwright-1.57.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a1bae6c0a07839cdeaddbc0756b3b2b85e476c07945f64ece08f1f956a86f1", size = 45706917, upload-time = "2025-12-09T08:06:32.549Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/09/3fc9ebd7c95ee54ba6a68d5c0bc23e449f7235f4603fc60534a364934c16/playwright-1.57.0-py3-none-win32.whl", hash = "sha256:1dd93b265688da46e91ecb0606d36f777f8eadcf7fbef12f6426b20bf0c9137c", size = 36553860, upload-time = "2025-12-09T08:06:35.864Z" },
+ { url = "https://files.pythonhosted.org/packages/58/d4/dcdfd2a33096aeda6ca0d15584800443dd2be64becca8f315634044b135b/playwright-1.57.0-py3-none-win_amd64.whl", hash = "sha256:6caefb08ed2c6f29d33b8088d05d09376946e49a73be19271c8cd5384b82b14c", size = 36553864, upload-time = "2025-12-09T08:06:38.915Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/60/fe31d7e6b8907789dcb0584f88be741ba388413e4fbce35f1eba4e3073de/playwright-1.57.0-py3-none-win_arm64.whl", hash = "sha256:5f065f5a133dbc15e6e7c71e7bc04f258195755b1c32a432b792e28338c8335e", size = 32837940, upload-time = "2025-12-09T08:06:42.268Z" },
+]
+
[[package]]
name = "prompt-toolkit"
version = "3.0.52"
@@ -2721,6 +2740,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" },
]
+[[package]]
+name = "pyee"
+version = "13.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/95/03/1fd98d5841cd7964a27d729ccf2199602fe05eb7a405c1462eb7277945ed/pyee-13.0.0.tar.gz", hash = "sha256:b391e3c5a434d1f5118a25615001dbc8f669cf410ab67d04c4d4e07c55481c37", size = 31250, upload-time = "2025-03-17T18:53:15.955Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9b/4d/b9add7c84060d4c1906abe9a7e5359f2a60f7a9a4f67268b2766673427d8/pyee-13.0.0-py3-none-any.whl", hash = "sha256:48195a3cddb3b1515ce0695ed76036b5ccc2ef3a9f963ff9f77aec0139845498", size = 15730, upload-time = "2025-03-17T18:53:14.532Z" },
+]
+
[[package]]
name = "pygments"
version = "2.19.2"
@@ -3374,6 +3405,7 @@ dependencies = [
{ name = "notion-client" },
{ name = "pandas" },
{ name = "pandasql" },
+ { name = "playwright" },
{ name = "pydantic" },
{ name = "pymongo" },
{ name = "pymupdf" },
@@ -3405,6 +3437,7 @@ requires-dist = [
{ name = "notion-client", specifier = ">=2.0.0" },
{ name = "pandas", specifier = ">=2.3.3" },
{ name = "pandasql", specifier = ">=0.7.3" },
+ { name = "playwright", specifier = ">=1.57.0" },
{ name = "pydantic", specifier = ">=2.12.4" },
{ name = "pymongo", specifier = ">=4.6.1" },
{ name = "pymupdf", specifier = ">=1.26.7" },