structverify 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. structverify/__init__.py +83 -0
  2. structverify/adaptation/__init__.py +0 -0
  3. structverify/adaptation/adapter_trainer.py +341 -0
  4. structverify/adaptation/feedback_store.py +31 -0
  5. structverify/adaptation/kosis_crawler.py +317 -0
  6. structverify/adaptation/sample_builder.py +149 -0
  7. structverify/adaptation/synthetic_generator.py +320 -0
  8. structverify/adaptation/update_embeddings.py +178 -0
  9. structverify/agent/__init__.py +21 -0
  10. structverify/agent/builder_agent.py +226 -0
  11. structverify/agent/conformance_agent.py +171 -0
  12. structverify/agent/dependency_planner.py +151 -0
  13. structverify/agent/indexing_agent.py +153 -0
  14. structverify/agent/indexing_planner.py +169 -0
  15. structverify/agent/integration_example.py +182 -0
  16. structverify/agent/loop.py +1165 -0
  17. structverify/agent/memory.py +207 -0
  18. structverify/agent/planner.py +817 -0
  19. structverify/agent/prompts/__init__.py +15 -0
  20. structverify/agent/prompts/planner_prompts.py +219 -0
  21. structverify/agent/prompts/reflect_prompts.py +387 -0
  22. structverify/agent/reflect.py +227 -0
  23. structverify/agent/runtime_agent.py +1272 -0
  24. structverify/agent/schemas.py +262 -0
  25. structverify/agent/source_profiler.py +229 -0
  26. structverify/agent/tools/__init__.py +64 -0
  27. structverify/agent/tools/base.py +222 -0
  28. structverify/agent/tools/calculate.py +244 -0
  29. structverify/agent/tools/catalog_search.py +859 -0
  30. structverify/agent/tools/deep_explore.py +293 -0
  31. structverify/agent/tools/explore_catalog.py +423 -0
  32. structverify/agent/tools/fetch_evidence.py +922 -0
  33. structverify/agent/tools/finish.py +423 -0
  34. structverify/agent/tools/meta_explore.py +267 -0
  35. structverify/agent/tools/query_rewriter.py +134 -0
  36. structverify/agent/tools/read_original.py +144 -0
  37. structverify/agent/tools/replan.py +365 -0
  38. structverify/agent/workspace.py +958 -0
  39. structverify/api.py +804 -0
  40. structverify/config/default.yaml +350 -0
  41. structverify/core/__init__.py +0 -0
  42. structverify/core/config_loader.py +30 -0
  43. structverify/core/pipeline.py +280 -0
  44. structverify/core/schemas.py +362 -0
  45. structverify/detection/__init__.py +26 -0
  46. structverify/detection/_config.py +163 -0
  47. structverify/detection/_llm.py +24 -0
  48. structverify/detection/candidate/__init__.py +1 -0
  49. structverify/detection/candidate/heuristic.py +60 -0
  50. structverify/detection/candidate/llm.py +51 -0
  51. structverify/detection/candidate_scorer.py +81 -0
  52. structverify/detection/claim_detector.py +164 -0
  53. structverify/detection/claims/__init__.py +1 -0
  54. structverify/detection/claims/worthiness.py +142 -0
  55. structverify/detection/domain/__init__.py +1 -0
  56. structverify/detection/domain/classify.py +84 -0
  57. structverify/detection/domain/preview.py +36 -0
  58. structverify/detection/domain/registry.py +99 -0
  59. structverify/detection/domain_classifier.py +75 -0
  60. structverify/detection/prompts/__init__.py +1 -0
  61. structverify/detection/prompts/candidate.py +38 -0
  62. structverify/detection/prompts/claim_worthiness.py +48 -0
  63. structverify/detection/prompts/domain.py +41 -0
  64. structverify/detection/prompts/schema.py +508 -0
  65. structverify/detection/prompts_loader.py +167 -0
  66. structverify/detection/schema/__init__.py +1 -0
  67. structverify/detection/schema/expand.py +83 -0
  68. structverify/detection/schema/induce.py +441 -0
  69. structverify/detection/schema/regenerate.py +162 -0
  70. structverify/detection/schema/temporal_hints.py +130 -0
  71. structverify/detection/schema/validate.py +193 -0
  72. structverify/detection/schema_inductor.py +112 -0
  73. structverify/detection/synthetic_generator.py +270 -0
  74. structverify/explanation/__init__.py +0 -0
  75. structverify/explanation/_config.py +18 -0
  76. structverify/explanation/_llm.py +25 -0
  77. structverify/explanation/explainer.py +183 -0
  78. structverify/explanation/fallback.py +29 -0
  79. structverify/explanation/formatters.py +75 -0
  80. structverify/explanation/prompts/__init__.py +1 -0
  81. structverify/explanation/prompts/match.py +27 -0
  82. structverify/explanation/prompts/mismatch.py +20 -0
  83. structverify/explanation/prompts/multihop.py +16 -0
  84. structverify/explanation/prompts/unverifiable.py +17 -0
  85. structverify/graph/__init__.py +0 -0
  86. structverify/graph/claim_graph.py +226 -0
  87. structverify/graph/document_graph.py +487 -0
  88. structverify/graph/graph_builder.py +238 -0
  89. structverify/graph/graph_multihop.py +335 -0
  90. structverify/graph/graph_store.py +281 -0
  91. structverify/graph/provenance.py +52 -0
  92. structverify/memory/__init__.py +44 -0
  93. structverify/memory/agent_memory.py +142 -0
  94. structverify/memory/embedder.py +69 -0
  95. structverify/memory/exemplar_store.py +241 -0
  96. structverify/memory/normalizer.py +91 -0
  97. structverify/memory/schema.py +119 -0
  98. structverify/memory/storage/__init__.py +29 -0
  99. structverify/memory/storage/jsonl_store.py +117 -0
  100. structverify/memory/working_memory.py +370 -0
  101. structverify/preprocessing/Dockerfile.scraper +27 -0
  102. structverify/preprocessing/__init__.py +0 -0
  103. structverify/preprocessing/extractor.py +574 -0
  104. structverify/preprocessing/pdf/__init__.py +16 -0
  105. structverify/preprocessing/pdf/fields.py +95 -0
  106. structverify/preprocessing/pdf/markdown.py +107 -0
  107. structverify/preprocessing/pdf/models.py +34 -0
  108. structverify/preprocessing/pdf/ocr.py +172 -0
  109. structverify/preprocessing/pdf/pipeline.py +74 -0
  110. structverify/preprocessing/pdf/reader.py +119 -0
  111. structverify/preprocessing/pdf/scoring.py +61 -0
  112. structverify/preprocessing/scraper_sandbox.py +561 -0
  113. structverify/preprocessing/segmenter.py +48 -0
  114. structverify/preprocessing/sir_builder.py +240 -0
  115. structverify/progress.py +591 -0
  116. structverify/retrieval/__init__.py +0 -0
  117. structverify/retrieval/base.py +208 -0
  118. structverify/retrieval/base_connector.py +85 -0
  119. structverify/retrieval/catalog_ranker.py +300 -0
  120. structverify/retrieval/catalog_search.py +583 -0
  121. structverify/retrieval/chunking.py +92 -0
  122. structverify/retrieval/custom_csv_source.py +386 -0
  123. structverify/retrieval/custom_db_source.py +396 -0
  124. structverify/retrieval/custom_docs_source.py +152 -0
  125. structverify/retrieval/dimension_resolver.py +281 -0
  126. structverify/retrieval/evidence_subgraph.py +63 -0
  127. structverify/retrieval/kosis_connector.py +1192 -0
  128. structverify/retrieval/kosis_relevance.py +142 -0
  129. structverify/retrieval/kosis_source.py +1541 -0
  130. structverify/retrieval/query_builder.py +72 -0
  131. structverify/retrieval/registry.py +133 -0
  132. structverify/retrieval/relevance_judge.py +141 -0
  133. structverify/retrieval/row_matcher.py +267 -0
  134. structverify/storage/__init__.py +0 -0
  135. structverify/storage/db_manager.py +157 -0
  136. structverify/storage/dwh_manager.py +92 -0
  137. structverify/storage/init_db.py +99 -0
  138. structverify/storage/raw_storage.py +29 -0
  139. structverify/training/__init__.py +26 -0
  140. structverify/training/curator.py +124 -0
  141. structverify/training/dataset.py +134 -0
  142. structverify/training/doctor.py +99 -0
  143. structverify/training/evalgate.py +96 -0
  144. structverify/training/generate.py +101 -0
  145. structverify/training/loop.py +116 -0
  146. structverify/training/recipe/train_mlx.py +99 -0
  147. structverify/training/recipe/train_qlora.py +104 -0
  148. structverify/training/tasks.py +79 -0
  149. structverify/utils/__init__.py +0 -0
  150. structverify/utils/embedding_client.py +248 -0
  151. structverify/utils/llm_client.py +809 -0
  152. structverify/utils/logger.py +81 -0
  153. structverify/verification/__init__.py +0 -0
  154. structverify/verification/_config.py +45 -0
  155. structverify/verification/adapters.py +405 -0
  156. structverify/verification/conformance.py +117 -0
  157. structverify/verification/decide_verdict.py +216 -0
  158. structverify/verification/decide_verdict_agent.py +454 -0
  159. structverify/verification/growth_diff.py +267 -0
  160. structverify/verification/row_match.py +345 -0
  161. structverify/verification/units.py +64 -0
  162. structverify/verification/verdict_thresholds.py +232 -0
  163. structverify/verification/verifier.py +84 -0
  164. structverify-0.3.0.dist-info/METADATA +903 -0
  165. structverify-0.3.0.dist-info/RECORD +168 -0
  166. structverify-0.3.0.dist-info/WHEEL +5 -0
  167. structverify-0.3.0.dist-info/licenses/LICENSE +21 -0
  168. structverify-0.3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,75 @@
1
+ """
2
+ detection/domain_classifier.py — 도메인 자동 분류 (Step 3)
3
+
4
+ 입력 텍스트의 도메인을 판별하고 적절한 Domain Pack을 선택한다.
5
+
6
+ [김예슬 - 2026-04-22]
7
+ - DOMAIN_CLASSIFY_PROMPT: few-shot 예시 3개 포함한 프롬프트로 교체
8
+ - classify_domain(): model_tier="light"(HCX-DASH-001)로 명시적 지정
9
+ - _build_text_preview(): 블록 타입 고려한 미리보기 텍스트 구성
10
+ - _load_domain_pack(): domain-packs/{domain}/prompts.yaml 로드 시도
11
+
12
+ [김예슬 - 2026-04-23 v1]
13
+ - SUPPORTED_DOMAINS 하드코딩 제거 → domain-packs/ 디렉토리 기반으로 변경
14
+
15
+ [김예슬 - 2026-04-23 v1]
16
+ - DomainRegistry 클래스 추가: 레지스트리 기반 도메인 관리
17
+ · 문제: LLM 자유 생성 시 같은 주제를 다른 이름으로 분류하는 파편화 발생
18
+ (예: real_estate / housing_market / property → 모두 같은 주제)
19
+ · 해결: 기존 등록 도메인 목록 + 설명을 LLM 프롬프트에 주입
20
+ → LLM이 기존 도메인 중 유사한 게 있으면 재사용, 없으면 신규 생성
21
+ · 신규 도메인 생성 시 레지스트리(registry.yaml)에 자동 저장
22
+ - classify_domain() 반환값: str → tuple[str, str] (domain, description)
23
+ · domain: 도메인 키 (영문 소문자)
24
+ · description: 도메인 한국어 설명 (레지스트리에서 조회 또는 신규 생성)
25
+ - DOMAIN_CLASSIFY_PROMPT: 기존 도메인 목록 동적 주입 방식으로 변경
26
+
27
+ [참고] ReAct (Yao et al., ICLR 2023)
28
+ Agent의 첫 단계로 도메인을 판별하여 이후 전략을 결정하는 패턴
29
+ """
30
+ from __future__ import annotations
31
+
32
+ from structverify.core.schemas import SIRDocument
33
+ from structverify.detection.domain.classify import _classify_domain_with_llm
34
+ from structverify.detection.domain.registry import (
35
+ CONFIDENCE_THRESHOLD,
36
+ DEFAULT_SEED_DOMAINS,
37
+ DOMAIN_NAME_PATTERN,
38
+ DomainRegistry,
39
+ )
40
+ from structverify.detection.prompts_loader import load_domain_pack
41
+ from structverify.utils.logger import get_logger
42
+
43
+ logger = get_logger(__name__)
44
+
45
+
46
+ # ── 메인 진입점 ──────────────────────────────────────────────────────────────
47
+ async def classify_domain(
48
+ sir_doc: SIRDocument,
49
+ config: dict | None = None,
50
+ ) -> tuple[str, str]:
51
+ """
52
+ SIR 문서의 도메인을 LLM으로 분류한다.
53
+
54
+ 반환값이 (domain, description) 튜플로 바뀐 이유:
55
+ - domain만 반환하면 나중에 설명을 다시 조회해야 함
56
+ - 한 번에 받아서 schema_inductor 등에서 도메인 힌트로 바로 활용 가능
57
+
58
+ 분류 로직:
59
+ 1) 레지스트리에서 기존 도메인 목록 + 설명 로드
60
+ 2) LLM 프롬프트에 목록 주입 → 기존 재사용 or 신규 생성
61
+ 3) 신규 도메인이면 레지스트리에 자동 저장
62
+ 4) confidence 낮으면 "general" fallback
63
+
64
+ Args:
65
+ sir_doc: 분류할 SIR 문서
66
+ config: 설정 dict
67
+
68
+ Returns:
69
+ (domain, description) 튜플
70
+ 예: ("agriculture", "농림수산식품 (농가, 경작면적, ...)")
71
+ """
72
+ domain, description = await _classify_domain_with_llm(sir_doc, config)
73
+ sir_doc.detected_domain = domain
74
+ load_domain_pack(domain, config)
75
+ return domain, description
@@ -0,0 +1 @@
1
+ """detection/prompts — Step 3~5 LLM 프롬프트·JSON schema 상수."""
@@ -0,0 +1,38 @@
1
+ """detection/prompts/candidate.py — Step 4 candidate scoring 프롬프트.
2
+
3
+ candidate_scorer.py에서 분리 (문자열 move-only, 동작 변경 없음).
4
+ """
5
+ from __future__ import annotations
6
+
7
+
8
+ # TODO [김예슬]: 프롬프트 튜닝 — domain-packs의 few-shot 예시 주입
9
+ # - 도메인별 positive/negative 예시 2~3개씩 추가
10
+ # - "공식 통계와 연결 가능" 기준을 예시로 명확히 제시
11
+ CANDIDATE_PROMPT = """당신은 수치 기반 팩트체크 시스템의 1차 후보 탐지기입니다.
12
+ 아래 문장이 "공식 통계나 구조화된 데이터로 검증할 만한 후보 문장"인지 판단하세요.
13
+
14
+ 판단 기준:
15
+ 1. 수치/비율/규모/시점/대상 중 일부가 드러나는가?
16
+ 2. 의견/감상/단순 이벤트 일정이 아니라 검증 가능한 사실 주장인가?
17
+ 3. 공식 통계 또는 공공 데이터와 연결될 가능성이 있는가?
18
+
19
+ 문장: "{sentence}"
20
+
21
+ 중요:
22
+ - candidate_label이 true이면 candidate_score는 반드시 0.5 이상이어야 합니다.
23
+ - candidate_label이 false이면 candidate_score는 반드시 0.5 미만이어야 합니다.
24
+ - JSON 앞뒤에 설명 문장을 절대 붙이지 마세요.
25
+
26
+ JSON으로만 답하세요:
27
+ {{
28
+ "candidate_score": 0.0,
29
+ "candidate_label": false,
30
+ "reason": "짧은 근거",
31
+ "signals": {{
32
+ "has_quantity": false,
33
+ "has_time_expr": false,
34
+ "has_population": false,
35
+ "has_comparison_expr": false
36
+ }}
37
+ }}
38
+ """
@@ -0,0 +1,48 @@
1
+ """detection/prompts/claim_worthiness.py — Step 4 check-worthiness 프롬프트.
2
+
3
+ claim_detector.py에서 분리 (문자열 move-only, 동작 변경 없음).
4
+
5
+ [박재윤 - 2026-05-14] CHECK_WORTHY_PROMPT 개선
6
+ [박재윤 - 2026-05-18] 검증 가능 기준 보강
7
+ """
8
+ from __future__ import annotations
9
+
10
+
11
+ # TODO [김예슬]: 프롬프트 튜닝
12
+ # - domain-packs/{domain}/prompts.yaml에서 도메인별 few-shot 예시 로드
13
+ # - positive 예시: 공식 통계로 검증 가능한 수치 주장 2~3개
14
+ # - negative 예시: 의견/감상/단순 이벤트 일정 2~3개
15
+ # - claim_type 분류 기준 명확화 (increase/decrease/scale/comparison/forecast)
16
+ CHECK_WORTHY_PROMPT = """팩트체크 전문가로서 아래 문장이 공식 통계로 검증 가능한 수치 기반 주장인지 판별하세요.
17
+
18
+ [검증 가능 기준]
19
+ 1. 정부/공공기관이 발표한 구체적 수치가 포함된 사실 주장
20
+ (변동률, 상승률, 하락률, 비율, 절대값, 증감폭 등 모두 포함)
21
+ 2. 단순 일정/발언 소개/감상이 아닌 사실 주장
22
+ 3. 수치가 *과거 또는 현재* 실측값 (예보/예상/전망/목표 아님)
23
+
24
+ [검증 불가 기준 — is_check_worthy=false]
25
+ - 예보/예상/전망/목표 수치: "예상 강수량 20mm", "목표 성장률 3%"
26
+ - 순위 표현만: "34년 만에 최대", "역대 최고"
27
+ - 단순 발언/의견: "전문가는 ~라고 말했다"
28
+ - 외국 기관 발표 수치 (KOSIS 검증 불가): "미국 연준이 금리를 0.25% 올렸다"
29
+
30
+ [검증 가능 예시]
31
+ ✓ "2024년 4월 출생아 수는 2만 171명이다" → true
32
+ ✓ "고용률이 전년 대비 1.2% 상승했다" → true
33
+ ✓ "서울 표준주택 공시가격 상승률은 6.8%다" → true
34
+ ✓ "동작구 공시가 상승률은 10.6%로 가장 높다" → true
35
+ ✓ "전국 표준단독주택 공시가격 상승률은 4.5%다" → true
36
+ ✗ "올해 강수량이 20mm로 예상된다" → false
37
+ ✗ "출생아 수가 34년 만에 최대를 기록했다" → false
38
+
39
+ 문장: "{sentence}"
40
+
41
+ 중요:
42
+ - is_check_worthy=true이면 score는 반드시 0.5 이상
43
+ - is_check_worthy=false이면 score는 반드시 0.5 미만
44
+ - JSON만 출력. 설명 금지.
45
+
46
+ JSON:
47
+ {{"is_check_worthy": false, "score": 0.0, "claim_type": null}}
48
+ """
@@ -0,0 +1,41 @@
1
+ """detection/prompts/domain.py — Step 3 도메인 분류 프롬프트.
2
+
3
+ domain_classifier.py에서 분리 (문자열 move-only, 동작 변경 없음).
4
+
5
+ [김예슬 - 2026-04-22] DOMAIN_CLASSIFY_PROMPT few-shot 예시
6
+ [김예슬 - 2026-04-23] 기존 도메인 목록 동적 주입 방식
7
+ """
8
+ from __future__ import annotations
9
+
10
+
11
+ DOMAIN_CLASSIFY_PROMPT = """당신은 한국 통계/뉴스 도메인 분류 전문가입니다.
12
+ 아래 문서를 읽고, 가장 적합한 도메인을 선택하거나 새로 생성하세요.
13
+
14
+ [현재 등록된 도메인 목록]
15
+ {domain_list}
16
+
17
+ [도메인 선택 규칙]
18
+ 1. 위 목록에서 문서 내용과 가장 잘 맞는 도메인이 있으면 그 도메인을 선택하세요.
19
+ 2. 목록에 적합한 도메인이 없을 때만 새 도메인을 만드세요.
20
+ - 영어 소문자와 언더스코어(_)만 사용 (예: real_estate, it_industry)
21
+ - 새 도메인 설명은 한국어로 간략히 작성
22
+ 3. 분류가 모호하거나 복합 도메인이면 "general"을 선택하세요.
23
+
24
+ [예시]
25
+ 문서: "통계청에 따르면 지난해 농가 인구는 216만 명으로 전년 대비 3.2% 감소했다."
26
+ → {{"domain": "agriculture", "description": "농림수산식품 (농가, 경작면적, 수확량, 축산, 어업)", "is_new": false, "confidence": 0.95, "reason": "농가 인구 통계"}}
27
+
28
+ 문서: "수도권 아파트 평균 매매가가 8억을 돌파하며 역대 최고치를 기록했다."
29
+ → {{"domain": "real_estate", "description": "부동산 (아파트, 매매가, 전세, 분양)", "is_new": true, "confidence": 0.93, "reason": "부동산 가격 통계로 기존 목록에 없음"}}
30
+
31
+ [분류할 문서]
32
+ {text_preview}
33
+
34
+ JSON으로만 답하세요:
35
+ {{
36
+ "domain": "도메인명",
37
+ "description": "도메인 한국어 설명",
38
+ "is_new": true 또는 false,
39
+ "confidence": 0.0~1.0,
40
+ "reason": "한 줄 근거"
41
+ }}"""