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.
- structverify/__init__.py +83 -0
- structverify/adaptation/__init__.py +0 -0
- structverify/adaptation/adapter_trainer.py +341 -0
- structverify/adaptation/feedback_store.py +31 -0
- structverify/adaptation/kosis_crawler.py +317 -0
- structverify/adaptation/sample_builder.py +149 -0
- structverify/adaptation/synthetic_generator.py +320 -0
- structverify/adaptation/update_embeddings.py +178 -0
- structverify/agent/__init__.py +21 -0
- structverify/agent/builder_agent.py +226 -0
- structverify/agent/conformance_agent.py +171 -0
- structverify/agent/dependency_planner.py +151 -0
- structverify/agent/indexing_agent.py +153 -0
- structverify/agent/indexing_planner.py +169 -0
- structverify/agent/integration_example.py +182 -0
- structverify/agent/loop.py +1165 -0
- structverify/agent/memory.py +207 -0
- structverify/agent/planner.py +817 -0
- structverify/agent/prompts/__init__.py +15 -0
- structverify/agent/prompts/planner_prompts.py +219 -0
- structverify/agent/prompts/reflect_prompts.py +387 -0
- structverify/agent/reflect.py +227 -0
- structverify/agent/runtime_agent.py +1272 -0
- structverify/agent/schemas.py +262 -0
- structverify/agent/source_profiler.py +229 -0
- structverify/agent/tools/__init__.py +64 -0
- structverify/agent/tools/base.py +222 -0
- structverify/agent/tools/calculate.py +244 -0
- structverify/agent/tools/catalog_search.py +859 -0
- structverify/agent/tools/deep_explore.py +293 -0
- structverify/agent/tools/explore_catalog.py +423 -0
- structverify/agent/tools/fetch_evidence.py +922 -0
- structverify/agent/tools/finish.py +423 -0
- structverify/agent/tools/meta_explore.py +267 -0
- structverify/agent/tools/query_rewriter.py +134 -0
- structverify/agent/tools/read_original.py +144 -0
- structverify/agent/tools/replan.py +365 -0
- structverify/agent/workspace.py +958 -0
- structverify/api.py +804 -0
- structverify/config/default.yaml +350 -0
- structverify/core/__init__.py +0 -0
- structverify/core/config_loader.py +30 -0
- structverify/core/pipeline.py +280 -0
- structverify/core/schemas.py +362 -0
- structverify/detection/__init__.py +26 -0
- structverify/detection/_config.py +163 -0
- structverify/detection/_llm.py +24 -0
- structverify/detection/candidate/__init__.py +1 -0
- structverify/detection/candidate/heuristic.py +60 -0
- structverify/detection/candidate/llm.py +51 -0
- structverify/detection/candidate_scorer.py +81 -0
- structverify/detection/claim_detector.py +164 -0
- structverify/detection/claims/__init__.py +1 -0
- structverify/detection/claims/worthiness.py +142 -0
- structverify/detection/domain/__init__.py +1 -0
- structverify/detection/domain/classify.py +84 -0
- structverify/detection/domain/preview.py +36 -0
- structverify/detection/domain/registry.py +99 -0
- structverify/detection/domain_classifier.py +75 -0
- structverify/detection/prompts/__init__.py +1 -0
- structverify/detection/prompts/candidate.py +38 -0
- structverify/detection/prompts/claim_worthiness.py +48 -0
- structverify/detection/prompts/domain.py +41 -0
- structverify/detection/prompts/schema.py +508 -0
- structverify/detection/prompts_loader.py +167 -0
- structverify/detection/schema/__init__.py +1 -0
- structverify/detection/schema/expand.py +83 -0
- structverify/detection/schema/induce.py +441 -0
- structverify/detection/schema/regenerate.py +162 -0
- structverify/detection/schema/temporal_hints.py +130 -0
- structverify/detection/schema/validate.py +193 -0
- structverify/detection/schema_inductor.py +112 -0
- structverify/detection/synthetic_generator.py +270 -0
- structverify/explanation/__init__.py +0 -0
- structverify/explanation/_config.py +18 -0
- structverify/explanation/_llm.py +25 -0
- structverify/explanation/explainer.py +183 -0
- structverify/explanation/fallback.py +29 -0
- structverify/explanation/formatters.py +75 -0
- structverify/explanation/prompts/__init__.py +1 -0
- structverify/explanation/prompts/match.py +27 -0
- structverify/explanation/prompts/mismatch.py +20 -0
- structverify/explanation/prompts/multihop.py +16 -0
- structverify/explanation/prompts/unverifiable.py +17 -0
- structverify/graph/__init__.py +0 -0
- structverify/graph/claim_graph.py +226 -0
- structverify/graph/document_graph.py +487 -0
- structverify/graph/graph_builder.py +238 -0
- structverify/graph/graph_multihop.py +335 -0
- structverify/graph/graph_store.py +281 -0
- structverify/graph/provenance.py +52 -0
- structverify/memory/__init__.py +44 -0
- structverify/memory/agent_memory.py +142 -0
- structverify/memory/embedder.py +69 -0
- structverify/memory/exemplar_store.py +241 -0
- structverify/memory/normalizer.py +91 -0
- structverify/memory/schema.py +119 -0
- structverify/memory/storage/__init__.py +29 -0
- structverify/memory/storage/jsonl_store.py +117 -0
- structverify/memory/working_memory.py +370 -0
- structverify/preprocessing/Dockerfile.scraper +27 -0
- structverify/preprocessing/__init__.py +0 -0
- structverify/preprocessing/extractor.py +574 -0
- structverify/preprocessing/pdf/__init__.py +16 -0
- structverify/preprocessing/pdf/fields.py +95 -0
- structverify/preprocessing/pdf/markdown.py +107 -0
- structverify/preprocessing/pdf/models.py +34 -0
- structverify/preprocessing/pdf/ocr.py +172 -0
- structverify/preprocessing/pdf/pipeline.py +74 -0
- structverify/preprocessing/pdf/reader.py +119 -0
- structverify/preprocessing/pdf/scoring.py +61 -0
- structverify/preprocessing/scraper_sandbox.py +561 -0
- structverify/preprocessing/segmenter.py +48 -0
- structverify/preprocessing/sir_builder.py +240 -0
- structverify/progress.py +591 -0
- structverify/retrieval/__init__.py +0 -0
- structverify/retrieval/base.py +208 -0
- structverify/retrieval/base_connector.py +85 -0
- structverify/retrieval/catalog_ranker.py +300 -0
- structverify/retrieval/catalog_search.py +583 -0
- structverify/retrieval/chunking.py +92 -0
- structverify/retrieval/custom_csv_source.py +386 -0
- structverify/retrieval/custom_db_source.py +396 -0
- structverify/retrieval/custom_docs_source.py +152 -0
- structverify/retrieval/dimension_resolver.py +281 -0
- structverify/retrieval/evidence_subgraph.py +63 -0
- structverify/retrieval/kosis_connector.py +1192 -0
- structverify/retrieval/kosis_relevance.py +142 -0
- structverify/retrieval/kosis_source.py +1541 -0
- structverify/retrieval/query_builder.py +72 -0
- structverify/retrieval/registry.py +133 -0
- structverify/retrieval/relevance_judge.py +141 -0
- structverify/retrieval/row_matcher.py +267 -0
- structverify/storage/__init__.py +0 -0
- structverify/storage/db_manager.py +157 -0
- structverify/storage/dwh_manager.py +92 -0
- structverify/storage/init_db.py +99 -0
- structverify/storage/raw_storage.py +29 -0
- structverify/training/__init__.py +26 -0
- structverify/training/curator.py +124 -0
- structverify/training/dataset.py +134 -0
- structverify/training/doctor.py +99 -0
- structverify/training/evalgate.py +96 -0
- structverify/training/generate.py +101 -0
- structverify/training/loop.py +116 -0
- structverify/training/recipe/train_mlx.py +99 -0
- structverify/training/recipe/train_qlora.py +104 -0
- structverify/training/tasks.py +79 -0
- structverify/utils/__init__.py +0 -0
- structverify/utils/embedding_client.py +248 -0
- structverify/utils/llm_client.py +809 -0
- structverify/utils/logger.py +81 -0
- structverify/verification/__init__.py +0 -0
- structverify/verification/_config.py +45 -0
- structverify/verification/adapters.py +405 -0
- structverify/verification/conformance.py +117 -0
- structverify/verification/decide_verdict.py +216 -0
- structverify/verification/decide_verdict_agent.py +454 -0
- structverify/verification/growth_diff.py +267 -0
- structverify/verification/row_match.py +345 -0
- structverify/verification/units.py +64 -0
- structverify/verification/verdict_thresholds.py +232 -0
- structverify/verification/verifier.py +84 -0
- structverify-0.3.0.dist-info/METADATA +903 -0
- structverify-0.3.0.dist-info/RECORD +168 -0
- structverify-0.3.0.dist-info/WHEEL +5 -0
- structverify-0.3.0.dist-info/licenses/LICENSE +21 -0
- structverify-0.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# StructVerify Lab v2.0 โ ๊ธฐ๋ณธ ์ค์
|
|
2
|
+
app:
|
|
3
|
+
name: "StructVerify Lab"
|
|
4
|
+
version: "0.2.0"
|
|
5
|
+
debug: true
|
|
6
|
+
|
|
7
|
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
8
|
+
# Phase A ์ถ๊ฐ ์น์
โ config/default.yaml ๋์ *์ถ๊ฐ*ํ์ธ์.
|
|
9
|
+
# ๊ธฐ์กด ์น์
(llm, embedding, kosis, ...) ์ *๊ทธ๋๋ก* ์ ์ง.
|
|
10
|
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
11
|
+
|
|
12
|
+
# === Agent (๋ฉํฐํด + memory + agentic ๊ฒ์ฆ) ===
|
|
13
|
+
# Phase A์์๋ *์๋ฆฌ๋ง* ์ถ๊ฐ. ์ค์ ํธ์ถ์ Phase D (loop) ํตํฉ ํ.
|
|
14
|
+
agent:
|
|
15
|
+
enabled: true # Phase A๋ false ์ ์ง. Phase D์์ true.
|
|
16
|
+
|
|
17
|
+
workspace:
|
|
18
|
+
backend: "local" # local | minio | s3 (์ง๊ธ์ local๋ง ๊ตฌํ)
|
|
19
|
+
local_path: "./agent_workspace" # workspace ๋๋ ํ ๋ฆฌ
|
|
20
|
+
persist_after_job: true # dev=true (๋๋ฒ๊น
), prod=false (์ ๋ฆฌ)
|
|
21
|
+
cleanup_after_days: 7 # persist=false ์ ๋ฉฐ์น ํ ์๋ ์ญ์
|
|
22
|
+
# [2026-05-21] workspace ๊ฒฉ๋ฆฌ ๋จ์:
|
|
23
|
+
# - "doc_hash" : ๋ณธ๋ฌธ ํ
์คํธ md5 hash ๊ธฐ์ค. *๊ฐ์ ๋ณธ๋ฌธ์ด๋ฉด ๊ฐ์ ๋๋ ํ ๋ฆฌ*๋ผ
|
|
24
|
+
# KOSIS fetch ์บ์(verified_facts/sibling_evidence/successful_stat_ids)๊ฐ
|
|
25
|
+
# API ํธ์ถ ์ฌ์ด์ ์ด์์์ด ๊ฐ์ ๊ธฐ์ฌ ์ฌ๊ฒ์ฆ์ด ๋น ๋ฆ. ๋จ์ : KOSIS
|
|
26
|
+
# ์ชฝ ๋ฐ์ดํฐ๊ฐ ๊ฐฑ์ ๋ผ๋ stale ์บ์ ์ฌ์ฉ ๊ฐ๋ฅ + ๋ค๋ฅธ ์ ์ ๊ฐ ๊ฐ์ ํ
์คํธ
|
|
27
|
+
# ๋ฃ์ผ๋ฉด ์บ์ ๊ณต์ (๋ฉํฐ-ํ
๋ํธ ๊ฒฉ๋ฆฌ ํ์ํ๋ฉด ๋ถ์ ํฉ).
|
|
28
|
+
# - "job_id" : API job_id (sv_platform์ด ๋ฐ๊ธํ UUID) ๊ธฐ์ค. *๋งค ์์ฒญ๋ง๋ค cold*
|
|
29
|
+
# start๋ผ ์ ํ์ฑโ ์๋โ. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋จ๋
์ฌ์ฉ(CLI ๋ฑ)์์ external_job_id
|
|
30
|
+
# ๋ฏธ์ ๊ณต ์ fresh UUID๋ก ํด๋ฐฑ.
|
|
31
|
+
scope: "job_id"
|
|
32
|
+
# ์ธ๋ถ์์ ์ฃผ์
ํ job_id (scope="job_id"์ผ ๋ ์ฌ์ฉ). sv_platform์ด ์๋ set.
|
|
33
|
+
# ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ง์ ์ฌ์ฉ ์ None ๋๋ฉด ํธ์ถ๋น fresh UUID ๋ฐ๊ธ.
|
|
34
|
+
external_job_id: null
|
|
35
|
+
|
|
36
|
+
memory:
|
|
37
|
+
backend: "file" # file | redis (์ง๊ธ์ file๋ง)
|
|
38
|
+
max_length_chars: 50000 # memory.md ์ฝ์ ๋ LLM์ ๋๊ธฐ๋ ์ํ
|
|
39
|
+
summarize_threshold: 30000 # ์ด ์ด์์ด๋ฉด LLM ์์ฝ (Phase D+)
|
|
40
|
+
|
|
41
|
+
loop:
|
|
42
|
+
mode: "reflect"
|
|
43
|
+
max_iterations: 10 # claim๋น reflect ์ต๋ ํ์
|
|
44
|
+
enable_reflection: true # false๋ฉด plan๋ง ๋ฐ๋ผ๊ฐ (๋ฉํฐํด X)
|
|
45
|
+
single_pass_fallback: true # agent ์คํจ/์์ฐ ์ด๊ณผ ์ v6.14 ๋จ์ผ ํจ์ค
|
|
46
|
+
early_stop_on_confidence: 0.9 # ์ด์์ด๋ฉด finish ๊ถ์ฅ
|
|
47
|
+
|
|
48
|
+
llm:
|
|
49
|
+
# llm.models ์์ *์ด๋ฆ*๋ง ์ฐธ์กฐ โ ๊ธฐ์กด ์ธํ๋ผ ์ฌ์ฌ์ฉ
|
|
50
|
+
plan_model: "structured" # โ HCX-007 (JSON ์ ํ)
|
|
51
|
+
reflect_model: "light" # โ HCX-DASH-002 (๋น์ฉ โ, ๋ฐ๋ณต ํธ์ถ)
|
|
52
|
+
explain_model: "heavy" # โ HCX-003
|
|
53
|
+
|
|
54
|
+
budget:
|
|
55
|
+
max_tokens_per_job: 100000
|
|
56
|
+
max_concurrent_claims: 3 # ๋์ ์ฒ๋ฆฌ claim ์
|
|
57
|
+
cost_alert_threshold_krw: 1000
|
|
58
|
+
|
|
59
|
+
cache:
|
|
60
|
+
enabled: true
|
|
61
|
+
ttl_hours: 24
|
|
62
|
+
backend: "memory" # memory | redis
|
|
63
|
+
|
|
64
|
+
# === Data sources (KOSIS๋ง โ multi-source ์ผ๋ฐํ) ===
|
|
65
|
+
# ๊ธฐ์กด kosis: ์น์
์ *๊ทธ๋๋ก ์ ์ง*. ์ฌ๊ธฐ์๋ *์ถ์ํ ๋ ์ด์ด*๋ง ์ถ๊ฐ.
|
|
66
|
+
data_sources:
|
|
67
|
+
enabled: ["kosis"] # ํ์ฌ: ["custom_db", "custom_csv"]
|
|
68
|
+
default_source: "kosis"
|
|
69
|
+
|
|
70
|
+
# KOSIS ๋ฐ์ดํฐ์์ค โ ๊ฒ์/ranking/๊ด๋ จ์ฑ ๊ฐ๋ ์ค์
|
|
71
|
+
# ์ฃผ์: ์ฌ๊ธฐ 'kosis' ์น์
์ KOSISDataSource ์์ฑ์์ ์ ๋ฌ๋จ (self._connector_config).
|
|
72
|
+
# ๊ธฐ์กด top-level 'kosis:' ์น์
(API URL, catalog ๋น๋ ๋ฑ)๊ณผ *๋ณ๋*.
|
|
73
|
+
kosis:
|
|
74
|
+
# [2026-05-26] catalog_ranker โ LLM batch ranking์ผ๋ก ํค์๋ ๊ฐ๋ + per-table
|
|
75
|
+
# relevance_judge๋ฅผ ํตํฉ ๋์ฒด. catalog_search + explore_catalog ๊ฒฐ๊ณผ๋ฅผ unionํด
|
|
76
|
+
# ๋ฉํ๋ฐ์ดํฐ(ํ ์ด๋ฆ, ๊ธฐ๊ด, category_path)์ ํจ๊ป LLM์ 1ํ ์ ๋ฌ โ ์๋ฏธ ์ ์ ์์.
|
|
77
|
+
catalog_ranker:
|
|
78
|
+
enabled: true # false๋ฉด ๊ธฐ์กด ํค์๋ ๊ฐ๋(Indicator Semantic Guard) ์ฌ์ฉ
|
|
79
|
+
score_threshold: 0.15 # ์ด ๋ฏธ๋ง์ reject (์์ ๋ง: ๊ฑฐ๋ถ๋ ํ๋ try_ids ๋ง์ง๋ง์ ์ถ๊ฐ)
|
|
80
|
+
pool_limit: 20 # ranker์ ๋ณด๋ผ ํ๋ณด ์ต๋ ๊ฐ์
|
|
81
|
+
max_try: 10 # ranker ์์๋ก try_ids ๋ง๋ค ๋ ์ํ
|
|
82
|
+
model_tier: "light" # HCX-DASH-002
|
|
83
|
+
|
|
84
|
+
# [2026-05-26] remove_relevance_judge โ true๋ฉด kosis_source์ per-table
|
|
85
|
+
# relevance_judge LLM ํธ์ถ์ skip. catalog_ranker๊ฐ ์ด๋ฏธ ์๋ฏธ ํ๋จํ๋ฏ๋ก
|
|
86
|
+
# ์ค๋ณต. ๋จ, 1์ฐจ ๋์
์์ ์์ ๋ง์ผ๋ก *false*(๋ ๋ค ์๋)๋ก ๋๊ณ , 18๋/1336๊ฐ
|
|
87
|
+
# ๋ ์ผ์ด์ค ๋ชจ๋ OK ํ์ธ๋๋ฉด true๋ก ์ ํ.
|
|
88
|
+
relevance_guard:
|
|
89
|
+
enabled: true # false๋ฉด per-table relevance_judge ์์ ๋นํ์ฑ
|
|
90
|
+
llm_fallback: true # P32: ๋ฃฐ ๊ฑฐ๋ถ ์ LLM ์๋ฏธ ํ๋จ 1ํ
|
|
91
|
+
model_tier: "light"
|
|
92
|
+
row_match_llm_fallback: true # P33c: _select_best_row ๋งค์นญ 0๊ฑด์ผ ๋ LLM rescue
|
|
93
|
+
row_match_model_tier: "light"
|
|
94
|
+
|
|
95
|
+
# custom_csv โ ํ์ฌ ์
๋ก๋ ํ์ผ
|
|
96
|
+
custom_csv:
|
|
97
|
+
enabled: false
|
|
98
|
+
base_path: "./uploads/custom"
|
|
99
|
+
catalog_json: "" # ํ ๋ชฉ๋ก JSON (ํ์)
|
|
100
|
+
embedding_cached: true
|
|
101
|
+
|
|
102
|
+
# custom_db โ ํ์ฌ ์์ฒด DB
|
|
103
|
+
custom_db:
|
|
104
|
+
enabled: false
|
|
105
|
+
dsn_env: "CUSTOM_DB_DSN" # .env์์ ๋ก๋
|
|
106
|
+
catalog_table: "stat_tables"
|
|
107
|
+
data_table_prefix: "data_"
|
|
108
|
+
|
|
109
|
+
# ์ธ๋ถ API plugin (ํ์ฅ ์๋ฆฌ)
|
|
110
|
+
external:
|
|
111
|
+
world_bank:
|
|
112
|
+
enabled: false
|
|
113
|
+
base_url: "https://api.worldbank.org/v2"
|
|
114
|
+
oecd:
|
|
115
|
+
enabled: false
|
|
116
|
+
|
|
117
|
+
# === Domain (๋๋ฉ์ธ/์ธ์ด ์ผ๋ฐํ) ===
|
|
118
|
+
# ํ๊ตญ์ด KOSIS ๋๋ฉ์ธ ์ธ โ ํ์ฌ๊ฐ *์์ฒด ๋ผ๋ฒจ/๋ถ๋ฅ์ฒด๊ณ* ์ฌ์ฉ ๊ฐ๋ฅ.
|
|
119
|
+
domain:
|
|
120
|
+
language: "ko" # ko | en | mixed
|
|
121
|
+
|
|
122
|
+
# ๋ถ๋ฅ ๋ผ๋ฒจ (ํ์ฌ ์ฝ๋์ ํ๋์ฝ๋ฉ๋ ๊ฒ โ config๋ก)
|
|
123
|
+
classifier_labels_path: "" # YAML ํ์ผ ๊ฒฝ๋ก, ๋น ๊ฐ์ด๋ฉด inline ์ฌ์ฉ
|
|
124
|
+
classifier_labels:
|
|
125
|
+
- id: "population"
|
|
126
|
+
desc: "์ธ๊ตฌ/๊ฐ๊ตฌ (์ถ์, ์ฌ๋ง, ํผ์ธ, ๊ณ ๋ นํ, ์ธ๊ตฌ๊ตฌ์กฐ)"
|
|
127
|
+
- id: "economy"
|
|
128
|
+
desc: "๊ฒฝ์ /์ฐ์
/๊ธ์ต"
|
|
129
|
+
- id: "labor"
|
|
130
|
+
desc: "๋
ธ๋/๊ณ ์ฉ"
|
|
131
|
+
- id: "health"
|
|
132
|
+
desc: "๋ณด๊ฑด/๋ณต์ง"
|
|
133
|
+
- id: "education"
|
|
134
|
+
desc: "๊ต์ก/๋ฌธํ"
|
|
135
|
+
# ํ์ฌ ์ถ๊ฐ ์:
|
|
136
|
+
# - id: "internal_sales"
|
|
137
|
+
# desc: "์ฌ๋ด ๋งค์ถ/ํ๋งค ์งํ"
|
|
138
|
+
|
|
139
|
+
schema_taxonomy_path: "" # parent_path ํธ๋ฆฌ YAML (์ ํ)
|
|
140
|
+
extra_schema_fields: [] # ClaimSchema ํ์ฅ ํ๋ ์ด๋ฆ๋ค
|
|
141
|
+
|
|
142
|
+
llm:
|
|
143
|
+
provider: "upstage" # hcx | openai | upstage [conformance ํ
์คํธ: HCX ํค ์์ด upstage]
|
|
144
|
+
# [v2 - ๊น์์ฌ] HCX ํค๊ฐ ์์ผ๋ฉด Upstage(Solar)๋ก ์ ํ โ OpenAI ํธํ์ด๋ผ base_url๋ง ๋ค๋ฆ.
|
|
145
|
+
# provider: "upstage"
|
|
146
|
+
# api_key_env: "UPSTAGE_API_KEY" # .env ์ UPSTAGE_API_KEY ์ธํ
|
|
147
|
+
# base_url: "https://api.upstage.ai/v1"
|
|
148
|
+
# models: { heavy: "solar-pro", light: "solar-mini", structured: "solar-pro" }
|
|
149
|
+
# (pip install openai ํ์. โป ์๋ฒ ๋ฉ/์นดํ๋ก๊ทธ๋ ์์ง HCX-EMB ๊ธฐ์ค โ ์๋ฒ ๋ฉ ์ ํ์ ๋ฐ์ฌ์ค ํํธ)
|
|
150
|
+
models:
|
|
151
|
+
heavy: "HCX-003" # ๋ณต์กํ ํ์คํฌ (check-worthiness, ์ค๋ช
์์ฑ) โ v1 API
|
|
152
|
+
light: "HCX-DASH-002" # ๋น ๋ฅธ ๋ถ๋ฅ (๋๋ฉ์ธ, candidate scoring) โ v3 API
|
|
153
|
+
structured: "HCX-007" # JSON ๊ตฌ์กฐํ ์ถ์ถ (schema_inductor ์ ์ฉ) โ v3 Structured Outputs
|
|
154
|
+
reasoning: "HCX-003" # ๋ณตํฉ ๊ทผ๊ฑฐ ์ข
ํฉ
|
|
155
|
+
temperature: 0.1
|
|
156
|
+
max_tokens: 4096 # [2026-05-21] 2048 โ 4096: reflect์ finish action์์ explanation์ด ๊ธธ์ด์ ธ JSON์ด ์๋ฆฌ๋ ์ผ์ด์ค ๋ฐฉ์ง. HCX-DASH-002 ํ๋ ๋ด.
|
|
157
|
+
api_key_env: "NCP_API_KEY" # .env์ ์ธํ
|
|
158
|
+
# [2026-05-21] ํ๋ก์ธ์ค ์ ์ญ HCX ํธ์ถ ์ฌ์ด ์ต์ ๊ฐ๊ฒฉ(ms). 0์ด๋ฉด ๋นํ์ฑ.
|
|
159
|
+
# 22:24 ๋ก๊ทธ ๋ถ์: 250ms(=4req/s)๋ก ๊น์๋ 21๊ฑด candidate ์ฒ๋ฆฌ ์ค ์ง์์ 429 ๋ฐ์.
|
|
160
|
+
# HCX ์ค์ sustained ํ๋๋ 1~2 req/s ์ถ์ โ 600ms๋ก ์ํฅ.
|
|
161
|
+
# ๊ถ์ฅ๊ฐ:
|
|
162
|
+
# - 250ms (4 req/s) : ๋๋ฌด ๊ณต๊ฒฉ์ , 429 ๋น๋ฐ
|
|
163
|
+
# - 500ms (2 req/s) : ๋ณดํต
|
|
164
|
+
# - 600ms (โ1.6 r/s) : ์์ ๊ธฐ๋ณธ๊ฐ
|
|
165
|
+
# - 1000ms (1 req/s) : ๋งค์ฐ ์์ , ๋๋ฆผ
|
|
166
|
+
min_call_interval_ms: 600 # ํธ์ถ ์ฌ์ด ์ต์ ๊ฐ๊ฒฉ(ms) โ rate limit
|
|
167
|
+
max_concurrency: 4 # โ
ํ ๋ฒ์ ๋ณด๋ผ ์ต๋ ๋์ LLM ์์ฒญ ์ (429 ๋ฐฉ์ง โ ๋ฎ์ถ์๋ก ์์ )
|
|
168
|
+
|
|
169
|
+
embedding:
|
|
170
|
+
provider: "upstage" # [conformance] HCX ํค ์์ด upstage (embedding-query/passage)
|
|
171
|
+
model: "HCX-EMB-V2" # provider!=hcx๋ฉด ๋ฌด์๋จ โ embedding-query ์๋
|
|
172
|
+
api_key_env: "UPSTAGE_API_KEY"
|
|
173
|
+
|
|
174
|
+
reranker:
|
|
175
|
+
provider: "hcx"
|
|
176
|
+
model: "HCX-RERANKER" # ๋ฆฌ๋ญ์ปค ๋ชจ๋ธ
|
|
177
|
+
api_key_env: "NCP_API_KEY"
|
|
178
|
+
|
|
179
|
+
kosis:
|
|
180
|
+
base_url: "https://kosis.kr/openapi"
|
|
181
|
+
api_key_env: "KOSIS_API_KEY"
|
|
182
|
+
pgvector_dsn_env: "PGVECTOR_DSN"
|
|
183
|
+
timeout: 30
|
|
184
|
+
catalog:
|
|
185
|
+
rebuild: false # true: ๊ฐ์ ์ฌ์์ง, false: DB์ ์์ผ๋ฉด skip
|
|
186
|
+
embed_batch_size: 100 # ์๋ฒ ๋ฉ ๋ฐฐ์น ํฌ๊ธฐ
|
|
187
|
+
min_rows: 1000 # ์ด ์ ์ด์์ด๋ฉด "์ด๋ฏธ ๊ตฌ์ถ๋จ"์ผ๋ก ํ๋จ
|
|
188
|
+
# [P20 2026-05-22] KOSIS API raw ์๋ต ์บ์ TTL (์๊ฐ).
|
|
189
|
+
# ๊ฐ์ (stat_id, prdSe, startPrdDe, endPrdDe) ์กฐํฉ ์ฌํธ์ถ ์ API ํธ์ถ ์์ด ์บ์ ์ฌ์ฉ.
|
|
190
|
+
# workspace ๋จ์ ํ์ผ ์บ์ (agent_workspace/job_<id>/kosis_cache/<key>.json).
|
|
191
|
+
# scope=doc_hash ๋ชจ๋๋ฉด ๊ฐ์ ๋ณธ๋ฌธ ์ฌ๊ฒ์ฆ ์ ๋ชจ๋ KOSIS API ํธ์ถ skip.
|
|
192
|
+
# - 0 : ์๊ตฌ ์บ์ (๋ง๋ฃ ์ ๋จ, ๊ฐ์ฅ ๋น ๋ฆ. KOSIS ๊ฐฑ์ ์ ์๋ cleanup ํ์)
|
|
193
|
+
# - 24 : 24์๊ฐ (๊ธฐ๋ณธ๊ฐ, KOSIS ์ผ์ผ ๊ฐฑ์ ๋์)
|
|
194
|
+
# - 168 : 1์ฃผ์ผ
|
|
195
|
+
cache_ttl_hours: 24
|
|
196
|
+
|
|
197
|
+
# [P32 2026-05-22] fetch_evidence์ *v6.17 ํ ๊ด๋ จ์ฑ ๊ฐ๋*์ LLM fallback ์ถ๊ฐ.
|
|
198
|
+
# ๋ฃฐ๋ฒ ์ด์ค _is_table_relevant()๊ฐ ํ ํฐ ๋งค์นญ์ผ๋ก ๊ฑฐ๋ถํ์ ๋, LLM์ด ํ ๋ฒ ๋
|
|
199
|
+
# *์๋ฏธ์ *์ผ๋ก ํ๋จํด false negative ํ๋ณต.
|
|
200
|
+
# ์: indicator="์ฒด์ธ ์ถฉ๊ฒฉํ ์์์ ์ฅ๋น ์" + table="์๊ตฐ๊ตฌ๋ณ ์ฃผ์ ์๋ฃ์ฅ๋น
|
|
201
|
+
# ํํฉ" โ ๋ฃฐ: "์ฅ๋น"(2๊ธ์, len<3 ๋ฃฐ์ ๋งํ) + "์์์ "(table์ ์์) โ ๊ฑฐ๋ถ.
|
|
202
|
+
# LLM: ํ๊ฐ "์๋ฃ์ฅ๋น"์ ์์ ๋ถ๋ฅ์ด๋ฏ๋ก row ๊ฒ์ํ๋ฉด ์ ๋ต ์ฐพ์ ๊ฐ๋ฅ์ฑ โ โ ํต๊ณผ.
|
|
203
|
+
# ๋ฃฐ *ํต๊ณผ* ์์ LLM ํธ์ถ ์ ํจ (์๋). ๋ฃฐ ๊ฑฐ๋ถ ์์๋ง LLM 1ํ (~1์ด).
|
|
204
|
+
relevance_guard:
|
|
205
|
+
llm_fallback: true # false๋ฉด ๋ฃฐ๋ฒ ์ด์ค๋ง (P32 ์ด์ ๋์)
|
|
206
|
+
model_tier: "light" # HCX-DASH-002. heavy/structured/reasoning ๊ฒฉ์ ๊ฐ๋ฅ.
|
|
207
|
+
# [P33c 2026-05-22] row ๋งค์นญ ๋จ๊ณ LLM fallback. _select_best_row๊ฐ indicator
|
|
208
|
+
# ๋ฃฐ ๋งค์นญ 0๊ฑด์ผ ๋ row์ unique ITM_NM/C_NM list๋ฅผ LLM์ ๋์ ธ ์๋ฏธ์ ๋งค์นญ
|
|
209
|
+
# ์๋ณ. KOSIS ํ row๊ฐ *๊ณ์ธต ๋ถ๋ฅ*๋ผ ์์ ์นดํ
๊ณ ๋ฆฌ ITM_NM๋ง ๋งค์นญ๋๊ณ ์ธ๋ถ
|
|
210
|
+
# row๋ฅผ ๋ชป ์ฐพ๋ ์ผ์ด์ค (์: "์ฒด์ธ ์ถฉ๊ฒฉํ ์์์ ์ฅ๋น" vs ITM_NM='์ง๋จ๋ฐฉ์ฌ์
|
|
211
|
+
# ยทํน์์๋ฃ์ฅ๋น')์์ ์ง์ง row ์๋ณ.
|
|
212
|
+
row_match_llm_fallback: true
|
|
213
|
+
row_match_model_tier: "light"
|
|
214
|
+
|
|
215
|
+
# [P34 2026-05-22] Dimension resolver โ KOSIS ํ์ N์ฐจ์ ์ฌ๋ผ์ด์ค ์ฝ๋ ๊ฒฐ์ .
|
|
216
|
+
# ๊ธฐ๋ณธ connector๋ cmmt_rows[0]์ ITM_ID/OBJ_ID(ํฉ๊ณ ์ฝ๋)๋ฅผ ๋ฐ์ *์ธ๋ถ row
|
|
217
|
+
# ๋๋ฝ*. ์ด๊ฑธ ๋ฉํ+LLM์ผ๋ก ๋์ ๊ฒฐ์ ํด์ ์ง์ง ์ ๋ต ์ฌ๋ผ์ด์ค๋ง ๋ฐ์.
|
|
218
|
+
# ํ๋ฆ: fetch ์ง์ โ getMeta(ITM/OBJL01~04) ๋ณ๋ ฌ โ LLM์ด claim ๋งค์นญ ์ฝ๋ ์ ํ
|
|
219
|
+
# โ fetch_params.dim_overrides์ ๋ฐ์ โ connector๊ฐ itmId/objL1~8 ์ฌ์ฉ.
|
|
220
|
+
# ๊ฐ์ stat_id๋ process-level cache๋ก 1ํ๋ง ํธ์ถ.
|
|
221
|
+
dimension_resolver:
|
|
222
|
+
enabled: true
|
|
223
|
+
model_tier: "light" # HCX-DASH-002
|
|
224
|
+
|
|
225
|
+
database:
|
|
226
|
+
# ๋ก์ปฌ ๊ฐ๋ฐ์ฉ DSN โ ์ค์ ๋น๋ฐ๋ฒํธ๋ ๋ฃ์ง ๋ง๊ณ ๊ฐ์ ํ๊ฒฝ์ ๋ง๊ฒ ์ค์ ํ์ธ์.
|
|
227
|
+
# (๊ท์ ์ค์ ๊ฒ์ฌ ๋ฑ ์ฝ์ด ๊ธฐ๋ฅ์ DB๊ฐ ํ์ ์์ต๋๋ค.)
|
|
228
|
+
url: "postgresql://localhost:5432/structverify"
|
|
229
|
+
|
|
230
|
+
graph:
|
|
231
|
+
provider: "neo4j" # "neo4j" | "memgraph"
|
|
232
|
+
uri: "bolt://localhost:7687"
|
|
233
|
+
user: "neo4j"
|
|
234
|
+
password_env: "NEO4J_PASSWORD"
|
|
235
|
+
|
|
236
|
+
storage:
|
|
237
|
+
provider: "minio"
|
|
238
|
+
endpoint: "http://localhost:9000"
|
|
239
|
+
bucket: "structverify-raw"
|
|
240
|
+
access_key_env: "MINIO_ACCESS_KEY"
|
|
241
|
+
secret_key_env: "MINIO_SECRET_KEY"
|
|
242
|
+
|
|
243
|
+
redis:
|
|
244
|
+
url: "redis://localhost:6379/0"
|
|
245
|
+
|
|
246
|
+
dwh:
|
|
247
|
+
provider: "snowflake" # "snowflake" | "bigquery" | "clickhouse"
|
|
248
|
+
snowflake:
|
|
249
|
+
account_env: "SNOWFLAKE_ACCOUNT"
|
|
250
|
+
user_env: "SNOWFLAKE_USER"
|
|
251
|
+
password_env: "SNOWFLAKE_PASSWORD"
|
|
252
|
+
warehouse: "STRUCTVERIFY_WH"
|
|
253
|
+
database: "STRUCTVERIFY_DB"
|
|
254
|
+
schema: "PUBLIC"
|
|
255
|
+
|
|
256
|
+
adaptation:
|
|
257
|
+
feedback_threshold: 10 # ํ์ต ํธ๋ฆฌ๊ฑฐ ์ต์ ํผ๋๋ฐฑ ์
|
|
258
|
+
eval_min_score: 0.85 # ๋ฐฐํฌ ๊ฒ์ดํธ ์ต์ ์ ์
|
|
259
|
+
mlflow_tracking_uri: "http://localhost:5000"
|
|
260
|
+
|
|
261
|
+
verification:
|
|
262
|
+
tolerance_percent: 1.0
|
|
263
|
+
min_confidence: 0.7
|
|
264
|
+
|
|
265
|
+
# [P21 2026-05-22] catalog_search ์๋ฏธ ์ ํ๋ ๋ณด๊ฐ โ LLM rerank
|
|
266
|
+
# [P25 2026-05-22] ์ผ์ ๋นํ์ฑ โ row_preview๊ฐ LLM์ด ์๋ชป๋ ํ(DT_HIRA48_1,
|
|
267
|
+
# DT_HIRA4Q ๊ฐ์ *์ธ๋ถ ๋ถ๋ฅ ํ*)๋ฅผ ์ ๋ต(DT_35003_A7 ๊ฐ์ *์๊ตฐ๊ตฌ๋ณ ์ผ๋ฐ ํ*)
|
|
268
|
+
# ๋ณด๋ค ์ฐ๋ํ๋ ๊ฒฝํฅ. ๊ฒ๋ค๊ฐ preview fetch๊ฐ KOSIS API์ 5 candidates ร 3 prdSe
|
|
269
|
+
# = 15๊ฐ ๋์ ํธ์ถ์ ๋ง๋ค์ด "Server disconnected" ์๋ฌ + 30~50์ด ์ง์ฐ ์ ๋ฐ.
|
|
270
|
+
# ์ฐ์ catalog ์๋ฒ ๋ฉ + prior_success score(P21A)๋ง ์ฌ์ฉ. rerank ์ ํ๋ ๊ฐ์ ์
|
|
271
|
+
# ๋ค์ ๋จ๊ณ(prompt ๊ฐํ + preview Y-only + LLM ๋ชจ๋ธ ๊ฒฉ์ ๋ฑ)์์ ์ฒ๋ฆฌ.
|
|
272
|
+
catalog_search:
|
|
273
|
+
# rerank_mode:
|
|
274
|
+
# - "none" : catalog ์๋ฒ ๋ฉ + prior score๋ง (ํ์ฌ ๊ธฐ๋ณธ)
|
|
275
|
+
# - "table_name" : top N ํ ์ด๋ฆ๋ง LLM์ ๋
ธ์ถํด์ best ์ ํ (์ ๋น์ฉ)
|
|
276
|
+
# - "row_preview" : top N ํ์ sample row 1๊ฐ fetch + LLM์ ๋
ธ์ถ (์ ํ๋โ ๋น์ฉโ)
|
|
277
|
+
# [2026-05-26 ํ๊ท] row_preview rerank๊ฐ LLM ์์ ์ถ์ถ ๋
ธ์ด์ฆ์ ๊ฒฐํฉํด ์ ๋ต ํ๋ฅผ
|
|
278
|
+
# ์คํ๋ ค *๋ค๋ฅธ ๋ฌด๊ด ํ*๋ก ์ฎ๊ธฐ๋ ์ผ์ด์ค ๋ฐ์. ์ด์ ์ ๋๋ ๋ฒ ์ด์ค(none)๋ก ๋๋๋ฆผ.
|
|
279
|
+
# ํ ์ ํ ์ ํ๋ ๊ฐ์ ์ ๋ณ๋ ์์
(indicator semantic guard ๋ฑ)์ผ๋ก ์ฒ๋ฆฌ.
|
|
280
|
+
rerank_mode: "none"
|
|
281
|
+
rerank_top_n: 5
|
|
282
|
+
rerank_min_score_gap: 0.15
|
|
283
|
+
|
|
284
|
+
# [P28 2026-05-22] Deep Exploration โ row ๋จ์ ๊ธฐ๋ฐ ์ธ์ฝ reasoning.
|
|
285
|
+
# pgvector catalog์ *ํ ์ด๋ฆ*๋ง ์๋ฒ ๋ฉ โ row-level keyword (์: "์ฒด์ธ ์ถฉ๊ฒฉํ
|
|
286
|
+
# ์์์ ", "์น๋ฃ ๊ฐ๋ฅ ์ฌ๋ง๋ฅ ")๋ cosine ๊ฒ์์์ ์ ์ ์กํ. P21B์ row_preview
|
|
287
|
+
# rerank๋ฅผ ๊ต์ฒดํ๋ ์ mechanism (P25์์ P21B๋ disable๋จ):
|
|
288
|
+
# - top 3 ํ๋ณด ร Y prdSe ร 5 row๋ง fetch (KOSIS ๋ถํ โ, P25 ํํผ)
|
|
289
|
+
# - prompt๊ฐ "best ๋จ์ ์ ํ"์ด ์๋๋ผ "row ๋จ์ ์ธ์ฝ reasoning"
|
|
290
|
+
# - LLM์ด "none"์ด๋ฉด ํธ์ถ์์ ์ ํธ โ reflect๊ฐ query refinement ๊ฒฐ์
|
|
291
|
+
# - P20 KOSIS cache hit์ด๋ฉด ๋น์ฉ 0
|
|
292
|
+
# ๋ฐ๋ ์กฐ๊ฑด (๋ ์ค ํ๋):
|
|
293
|
+
# - T1: top1 score < trigger_low_score OR (top1-top2) < trigger_score_gap
|
|
294
|
+
# - T2: catalog_search input์ force_explore=true (fetch ์คํจ ํ reflect๊ฐ ์ฌ์ฉ)
|
|
295
|
+
deep_explore:
|
|
296
|
+
enabled: true
|
|
297
|
+
top_n: 3 # sample row ๊ฐ์ ธ์ฌ ์์ ํ๋ณด ์
|
|
298
|
+
rows_per_table: 5 # ํ๋น LLM์ ๋ณด์ฌ์ค row ์
|
|
299
|
+
trigger_low_score: 0.6 # top1 < ์ด ๊ฐ์ด๋ฉด T1 ๋ฐ๋
|
|
300
|
+
trigger_score_gap: 0.1 # top1-top2 < ์ด ๊ฐ์ด๋ฉด T1 ๋ฐ๋
|
|
301
|
+
max_per_claim: 2 # claim๋น ์ต๋ ๋ฐ๋ ํ์ (loop ๋ฐฉ์ง)
|
|
302
|
+
# ์ฌ์ฉํ HCX ๋ชจ๋ธ tier โ llm.models์ ํค (heavy/light/structured/reasoning).
|
|
303
|
+
# row ํจํด ์๋ฏธ ๋น๊ต๊ฐ ์ฃผ์์
์ด๋ผ light(HCX-DASH-002) ์ถฉ๋ถ. ์ ํ๋ ๋
|
|
304
|
+
# ํ์ํ๋ฉด "heavy"(HCX-003) ๋๋ "structured"(HCX-007)๋ก ๊ฒฉ์ ๊ฐ๋ฅ.
|
|
305
|
+
model_tier: "light"
|
|
306
|
+
# [P30 2026-05-22] force_explore=true ์ ์ฌ์ฉํ ๋ฐฉ์.
|
|
307
|
+
# - "meta" (๊ธฐ๋ณธ, ๊ถ์ฅ) : KOSIS getMeta(ITM/OBJ) โ ํ๋น ~1์ด. ITM_NM list์
|
|
308
|
+
# indicator ํค์๋ ์ง์ ๋งค์นญ ํ์ธ ๊ฐ๋ฅ. Catalog ํ๋ณด
|
|
309
|
+
# ์์ ์ ๋ต์ด *์๋๋ฐ* cosine ์ ์๋ก ๋ฌปํ ์ผ์ด์ค์ ๊ฐํจ.
|
|
310
|
+
# - "row_preview" : ํ ์ ์ฒด row preview โ ํ๋น 22~26์ด. Catalog ํ ์ด๋ฆ
|
|
311
|
+
# ์ผ๋ก ๋ชจ๋ฅด์ง๋ง row ๋ถ๋ฅ ํจํด์ผ๋ก ์ธ์ฝํด์ผ ํ๋ ์ผ์ด์ค.
|
|
312
|
+
# input์ explore_mode๊ฐ ์์ผ๋ฉด ๊ทธ๊ฒ ์ฐ์ . ์์ผ๋ฉด ์ด default ์ฌ์ฉ.
|
|
313
|
+
explore_mode: "meta"
|
|
314
|
+
# meta ๋ชจ๋ ์ต์
โ OBJ(๋ถ๋ฅ ํญ๋ชฉ, ์ง์ญ/์ฐ๋ น ๋ฑ) ๋ฉํ๋ ๊ฐ์ ธ์ฌ์ง.
|
|
315
|
+
# true: ITM + OBJL01 ๋ ๋ค โ ์ ํ๋ โ ํธ์ถ ์ 2๋ฐฐ.
|
|
316
|
+
# false: ITM๋ง โ 1/2 ํธ์ถ.
|
|
317
|
+
include_obj: true
|
|
318
|
+
|
|
319
|
+
# [P30 2026-05-22] Query rewriter โ catalog_search ์ง์ ์ LLM์ด query ๋ณํ.
|
|
320
|
+
# input.query_rewrite=true์ผ ๋๋ง ๋ฐ๋ (reflect๊ฐ ๋ช
์ ํธ์ถ). row-level keyword
|
|
321
|
+
# (์: "์ฒด์ธ ์ถฉ๊ฒฉํ ์์์ ์ฅ๋น")๋ก๋ catalog ํ๋ณด์ ์ ๋ต ํ๊ฐ ์ง์
์กฐ์ฐจ ์ ๋๋
|
|
322
|
+
# ์ผ์ด์ค์ ์ฌ์ฉ. LLM์ด "์๊ตฐ๊ตฌ๋ณ ์๋ฃ์ฅ๋น" ๊ฐ์ *ํ ์ด๋ฆ ์นํ ์ดํ*๋ก ๋ณํ โ
|
|
323
|
+
# ๊ฐ ๋ณํ์ผ๋ก catalog ๊ฒ์ โ ํฉ์งํฉ ๋ฐํ.
|
|
324
|
+
query_rewriter:
|
|
325
|
+
enabled: true
|
|
326
|
+
n_variations: 3 # ๋ณํ query ๊ฐ์ (์๋ณธ ์ธ์ ์ถ๊ฐ๋ก ์์ฑํ ๊ฐ์)
|
|
327
|
+
model_tier: "light"
|
|
328
|
+
|
|
329
|
+
candidate_detection:
|
|
330
|
+
enabled: true
|
|
331
|
+
threshold: 0.65
|
|
332
|
+
use_surface_signals: true
|
|
333
|
+
teacher_llm_fallback: true
|
|
334
|
+
# [2026-05-21] LLM ๋์ ํธ์ถ ์ํ.
|
|
335
|
+
# candidate scoring(step 1) + check-worthiness(step 2) ๋ ๋จ๊ณ๊ฐ ๊ฐ๊ฐ ์ด ๊ฐ์
|
|
336
|
+
# Semaphore ์ํ์ผ๋ก ์ฌ์ฉ. HCX-003์ *์ด๋น ์์ฒญ ์* ์ ํ์ด ๋นก์ธ์ 5 ์ด์์ด๋ฉด
|
|
337
|
+
# 429 Too Many Requests ํญ์ฃผ(2026-05-21 21:42 ๋ก๊ทธ โ 5 concurrent โ ์ ๋ถ 429).
|
|
338
|
+
# 22:24 ์ฌํ
์คํธ: 4 concurrent + min_call_interval_ms=250๋ ์ง์ 429 ๋ฐ์.
|
|
339
|
+
# โ 2๋ก ํํฅ. min_call_interval_ms์ ํจ๊ป *์ค์ ์ฒ๋ฆฌ๋*์ ๊ฒฐ์ .
|
|
340
|
+
concurrency: 2
|
|
341
|
+
|
|
342
|
+
observability:
|
|
343
|
+
langfuse_enabled: false
|
|
344
|
+
log_level: "INFO"
|
|
345
|
+
|
|
346
|
+
preprocessing:
|
|
347
|
+
sandbox_backend: "docker" # "exec" | "docker" | "e2b"
|
|
348
|
+
use_llm_clean: true
|
|
349
|
+
|
|
350
|
+
enable_feedback: false # ํผ๋๋ฐฑ/ํ์ต ๋ฃจํ ๋นํ์ฑํ
|
|
File without changes
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import os
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
# ํจํค์ง์ ๋ฒ๋ค๋ ๊ธฐ๋ณธ ์ค์ โ pip ์ค์น ํ์๋ ํญ์ ์กด์ฌํ๋ค.
|
|
6
|
+
_PACKAGED_DEFAULT = Path(__file__).parent.parent / "config" / "default.yaml"
|
|
7
|
+
# ๊ฐ๋ฐ ์ฒดํฌ์์(backend/config/default.yaml) ์ค๋ฒ๋ผ์ด๋ โ ์์ผ๋ฉด ์ฐ์ .
|
|
8
|
+
_REPO_DEFAULT = Path(__file__).parent.parent.parent / "config" / "default.yaml"
|
|
9
|
+
_REPO_ENV = Path(__file__).parent.parent.parent / ".env"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def load_config(path: str | None = None) -> dict:
|
|
13
|
+
"""์ค์ ์ ๋ก๋ํ๋ค.
|
|
14
|
+
|
|
15
|
+
์ฐ์ ์์: ๋ช
์ ``path`` โ ๊ฐ๋ฐ ์ฒดํฌ์์(backend/config/default.yaml) โ
|
|
16
|
+
ํจํค์ง ๋ฒ๋ค(structverify/config/default.yaml). ์ด๋ ๊ฒ๋ ์์ผ๋ฉด ``{}``.
|
|
17
|
+
์ด ํด๋ฐฑ ๋๋ถ์ ``pip install`` ํ์๋(๋ฆฌํฌ ๋ฐ์์๋) ๊ธฐ๋ณธ ์ค์ ์ผ๋ก ๋์ํ๋ค.
|
|
18
|
+
"""
|
|
19
|
+
from dotenv import load_dotenv
|
|
20
|
+
# ๊ฐ๋ฐ ์ฒดํฌ์์์ด๋ฉด .env ์๋ ๋ก๋ โ ์์ผ๋ฉด ์กฐ์ฉํ ๋ฌด์๋๋ค.
|
|
21
|
+
if _REPO_ENV.exists():
|
|
22
|
+
load_dotenv(_REPO_ENV)
|
|
23
|
+
|
|
24
|
+
import yaml
|
|
25
|
+
if path is None:
|
|
26
|
+
path = str(_REPO_DEFAULT if _REPO_DEFAULT.exists() else _PACKAGED_DEFAULT)
|
|
27
|
+
if not os.path.exists(path):
|
|
28
|
+
return {}
|
|
29
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
30
|
+
return yaml.safe_load(f) or {}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"""
|
|
2
|
+
# ์์ ์: ๋ฐ์ฌ์ค
|
|
3
|
+
# ์์ ๋ ์ง: 2026-04-29
|
|
4
|
+
# ์์ ๋ด์ฉ: DBManager ์ด๊ธฐํ ๋ฐ save_claims, save_results ์ฐ๋ ๊ตฌํ
|
|
5
|
+
|
|
6
|
+
# [DONE] DBManager ์ด๊ธฐํ ์ฐ๋
|
|
7
|
+
# [DONE] save_claims ํ์ดํ๋ผ์ธ ์ฐ๊ฒฐ
|
|
8
|
+
# [DONE] save_results ํ์ดํ๋ผ์ธ ์ฐ๊ฒฐ
|
|
9
|
+
# [DONE] ๊ธฐ์ฌ ํ
์คํธ ํด์๋ก doc_id ๊ณ ์ (์ฌ์คํ ์ ์ค๋ณต ๋ฐฉ์ง)
|
|
10
|
+
# [DONE] save_claims source_type ํ๋ผ๋ฏธํฐ ์ถ๊ฐ
|
|
11
|
+
# [TODO] RawStorage ์ด๊ธฐํ (MinIO/S3 ์
๋ก๋)
|
|
12
|
+
# [TODO] DWHManager ์ด๊ธฐํ (Snowflake)
|
|
13
|
+
# [TODO] GraphStore ์ด๊ธฐํ (Neo4j)
|
|
14
|
+
# [TODO] save_document ๊ตฌํ (db_manager.py)
|
|
15
|
+
# [๊น์์ฌ - 2026-04-30 / v3]
|
|
16
|
+
# - config ๊ธฐ๋ณธ๊ฐ load_config() ์ ์ฉ
|
|
17
|
+
# - feedback/ํ์ต: enable_feedback=false ์ด๋ฉด Step 11~12 skip
|
|
18
|
+
# - runtime_agent์ kosis llm config ์ ๋ฌ (LLM Agent catalog ๊ฒ์์ฉ)
|
|
19
|
+
|
|
20
|
+
core/pipeline.py โ v2.1 ๊ฒ์ฆ ํ์ดํ๋ผ์ธ (13๋จ๊ณ)
|
|
21
|
+
|
|
22
|
+
โ ์
๋ ฅ โ โก ์ ์ฒ๋ฆฌ+SIR Tree โ โข ๋๋ฉ์ธ ํ๋ณ
|
|
23
|
+
โ โฃ Sentence Candidate Detection + Claim Detection
|
|
24
|
+
โ โค Schema Induction โ โฅ Graph Construction
|
|
25
|
+
โ โฆ Retrieval+Evidence Subgraph โ โง Verification
|
|
26
|
+
โ โจ Explanation+Provenance โ โฉ Human Review
|
|
27
|
+
โ โช Feedback Logging โ โซ Adaptation Trigger โ โฌ Report
|
|
28
|
+
|
|
29
|
+
[๊น์์ฌ]
|
|
30
|
+
- ๊ธฐ์กด Step 4์ "์์น ํฌํจ ๋ฌธ์ฅ ํํฐ๋ง + Claim Detection" ๊ตฌ์กฐ๋ฅผ
|
|
31
|
+
"๋ฌธ์ฅ ๋จ์ candidate scoring + Claim Detection" ๊ตฌ์กฐ๋ก ํ์ฅ
|
|
32
|
+
- has_numeric regex๋ ๋ณด์กฐ surface signal๋ก๋ง ์ฌ์ฉ
|
|
33
|
+
- ์ค์ ๊ฒ์ฆ ํ๋ณด ์ฌ๋ถ๋ candidate_score / candidate_label ๊ธฐ์ค์ผ๋ก ํ๋จ
|
|
34
|
+
- ์ ์ฒด ํ์ดํ๋ผ์ธ ํ๋ฆ ๋ฐ Agent ๊ฐ ์ฐ๊ฒฐ ๊ด๋ฆฌ
|
|
35
|
+
|
|
36
|
+
[์ฐธ๊ณ ] ReAct (Yao et al., ICLR 2023) โ https://github.com/ysymyth/ReAct
|
|
37
|
+
ThoughtโActionโObservation ์ํ ๊ธฐ๋ฐ ์ค์ผ์คํธ๋ ์ด์
ํจํด
|
|
38
|
+
"""
|
|
39
|
+
from __future__ import annotations
|
|
40
|
+
|
|
41
|
+
from structverify.core.schemas import (
|
|
42
|
+
SourceType,
|
|
43
|
+
SIRDocument,
|
|
44
|
+
VerificationReport,
|
|
45
|
+
)
|
|
46
|
+
from structverify.core.config_loader import load_config
|
|
47
|
+
from structverify.preprocessing.extractor import extract_text
|
|
48
|
+
from structverify.preprocessing.sir_builder import build_sir
|
|
49
|
+
from structverify.agent.runtime_agent import RuntimeAgent
|
|
50
|
+
from structverify.storage.db_manager import DBManager
|
|
51
|
+
from structverify.utils.logger import get_logger
|
|
52
|
+
|
|
53
|
+
logger = get_logger(__name__)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class VerificationPipeline:
|
|
57
|
+
"""
|
|
58
|
+
13๋จ๊ณ ๊ฒ์ฆ ํ์ดํ๋ผ์ธ ์ค์ผ์คํธ๋ ์ดํฐ.
|
|
59
|
+
|
|
60
|
+
์ฌ์ฉ๋ฒ:
|
|
61
|
+
pipeline = VerificationPipeline()
|
|
62
|
+
report = await pipeline.run("https://news.example.com/article", "url")
|
|
63
|
+
|
|
64
|
+
Step 4 ๋ณ๊ฒฝ์ฌํญ:
|
|
65
|
+
๊ธฐ์กด:
|
|
66
|
+
has_numeric=True ๋ฌธ์ฅ ์ ๋ณ โ LLM check-worthiness
|
|
67
|
+
๋ณ๊ฒฝ:
|
|
68
|
+
sentence candidate scoring โ ์์ ํ๋ณด์ ๋ํด LLM check-worthiness
|
|
69
|
+
|
|
70
|
+
์ฆ, Claim Detection ์๋จ์ "Sentence Candidate Detection"์ด ์ถ๊ฐ๋์๋ค.
|
|
71
|
+
"""
|
|
72
|
+
def __init__(self, config: dict | None = None):
|
|
73
|
+
# [v3 ๊น์์ฌ] config ์์ผ๋ฉด default.yaml ์๋ ๋ก๋
|
|
74
|
+
self.config = config if config is not None else load_config()
|
|
75
|
+
|
|
76
|
+
# runtime_agent์ kosis + llm ์ค์ ํฉ์ณ์ ์ ๋ฌ
|
|
77
|
+
# โ KOSISConnector๊ฐ LLM Agent(catalog ๊ฒ์)์ llm ์ค์ ํ์
|
|
78
|
+
agent_config = {
|
|
79
|
+
**self.config,
|
|
80
|
+
"kosis": {
|
|
81
|
+
**self.config.get("kosis", {}),
|
|
82
|
+
"llm": self.config.get("llm", {}),
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
self.runtime_agent = RuntimeAgent(config=agent_config)
|
|
86
|
+
|
|
87
|
+
# [v1] - ๋ฐ์ฌ์ค: DBManager ์ด๊ธฐํ ์ฐ๋
|
|
88
|
+
self.db_manager = DBManager(config=self.config.get("database", {}))
|
|
89
|
+
|
|
90
|
+
# [v3 ๊น์์ฌ] ํผ๋๋ฐฑ/ํ์ต ํ์ฑํ ์ฌ๋ถ (false๋ฉด Step 11~12 skip)
|
|
91
|
+
self.enable_feedback = bool(self.config.get("enable_feedback", False))
|
|
92
|
+
|
|
93
|
+
# TODO [๊น์์ฌ]: BuilderAgent ์ด๊ธฐํ (๋น๋๊ธฐ ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ต ๋ฃจํ)
|
|
94
|
+
# self.builder_agent = BuilderAgent(config=self.config)
|
|
95
|
+
|
|
96
|
+
# TODO [๋ฐ์ฌ์ค]: RawStorage ์ด๊ธฐํ (MinIO/S3 ์
๋ก๋)
|
|
97
|
+
# self.raw_storage = RawStorage(config=self.config.get("storage", {}))
|
|
98
|
+
|
|
99
|
+
# TODO [๋ฐ์ฌ์ค]: DWHManager ์ด๊ธฐํ (Snowflake)
|
|
100
|
+
# self.dwh_manager = DWHManager(config=self.config.get("dwh", {}))
|
|
101
|
+
|
|
102
|
+
# TODO [๋ฐ์ฌ์ค]: GraphStore ์ด๊ธฐํ (Neo4j)
|
|
103
|
+
# self.graph_store = GraphStore(config=self.config.get("graph", {}))
|
|
104
|
+
|
|
105
|
+
async def run(
|
|
106
|
+
self,
|
|
107
|
+
source: str,
|
|
108
|
+
source_type: str = "text",
|
|
109
|
+
source_text: str | None = None,
|
|
110
|
+
) -> VerificationReport:
|
|
111
|
+
"""
|
|
112
|
+
source ์
๋ ฅ์ ๋ฐ์ ์ ์ฒด ๊ฒ์ฆ ํ์ดํ๋ผ์ธ์ ์ํํ๋ค.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
source: ์๋ณธ ์
๋ ฅ (ํ
์คํธ/URL/PDF ๊ฒฝ๋ก ๋ฑ)
|
|
116
|
+
source_type: "text" | "url" | "pdf" | "docx"
|
|
117
|
+
source_text: *์ต์
* โ ์ด๋ฏธ ์ถ์ถ๋ ๋ณธ๋ฌธ ํ
์คํธ๊ฐ ์์ผ๋ฉด ์ ๋ฌ.
|
|
118
|
+
URL/PDF ์
๋ ฅ์์ sv_platform์ด ๋ฏธ๋ฆฌ ์ถ์ถํด Job.source_data์
|
|
119
|
+
์ ์ฅํ ๋ค ๊ทธ ํ
์คํธ๋ฅผ ๊ทธ๋๋ก ๋๊ฒจ์ฃผ๋ฉด *์ค๋ณต ์ถ์ถ ์์ด* ํ์ดํ๋ผ์ธ
|
|
120
|
+
์งํ. (์ค์๊ฐ partial ์๋ต ๋งค์นญ์๋ ์ฌ์ฉ๋จ.)
|
|
121
|
+
None์ด๋ฉด source์์ extract_text() ์ง์ ํธ์ถ.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
VerificationReport: ์ ์ฒด ๊ฒ์ฆ ๊ฒฐ๊ณผ ๋ณด๊ณ ์
|
|
125
|
+
"""
|
|
126
|
+
src = SourceType(source_type)
|
|
127
|
+
logger.info(f"ํ์ดํ๋ผ์ธ ์์: {src.value}")
|
|
128
|
+
import structverify.progress as _progress
|
|
129
|
+
_enabled = list((self.config.get("data_sources", {}) or {}).get("enabled", []) or [])
|
|
130
|
+
_progress.emit("start", source=", ".join(_enabled) or src.value)
|
|
131
|
+
|
|
132
|
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
133
|
+
# Step 1~2: ์
๋ ฅ โ ์ ์ฒ๋ฆฌ โ SIR Tree
|
|
134
|
+
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
135
|
+
# TODO [์ด์๋ฏผ]: extractor.py โ URL/PDF/DOCX ์ค์ ์ถ์ถ ๋ก์ง ๊ตฌํ
|
|
136
|
+
# - URL: trafilatura.extract() ํธ์ถ
|
|
137
|
+
# - PDF: PyMuPDF(fitz) ํ์ด์ง๋ณ ํ
์คํธ ์ถ์ถ
|
|
138
|
+
# - DOCX: python-docx ๋จ๋ฝ ์ถ์ถ
|
|
139
|
+
if source_text is not None and source_text.strip():
|
|
140
|
+
# sv_platform์ด ์ฌ์ ์ถ์ถํด ๋๊ธด ๊ฒฝ์ฐ โ ์ค๋ณต ํธ์ถ ํํผ
|
|
141
|
+
raw_text = source_text
|
|
142
|
+
logger.info(f"ํ์ดํ๋ผ์ธ: ์ฌ์ ์ถ์ถ ๋ณธ๋ฌธ ์ฌ์ฉ ({len(raw_text)}์)")
|
|
143
|
+
else:
|
|
144
|
+
raw_text = await extract_text(source, src)
|
|
145
|
+
|
|
146
|
+
# TODO [์ด์๋ฏผ]: sir_builder.py โ SIR Tree ๋ณํ ๊ฒ์ฆ
|
|
147
|
+
# - block ๋ถํ + ๋ฌธ์ฅ ๋ถ๋ฆฌ + ์ ๋ offset ๋ณด์ ํ์ธ
|
|
148
|
+
# - entity_refs, event_refs ์ถ์ถ (ํ์ฌ regex placeholder โ NER ๊ต์ฒด ์์ )
|
|
149
|
+
sir_doc = build_sir(
|
|
150
|
+
raw_text,
|
|
151
|
+
src,
|
|
152
|
+
source_uri=source if src == SourceType.URL else None,
|
|
153
|
+
)
|
|
154
|
+
# [v2] - ๋ฐ์ฌ์ค: ๊ธฐ์ฌ ํ
์คํธ ํด์๋ก doc_id ๊ณ ์ (์ฌ์คํ ์ ์ค๋ณต ๋ฐฉ์ง)
|
|
155
|
+
import hashlib
|
|
156
|
+
from uuid import UUID
|
|
157
|
+
text_hash = hashlib.md5(raw_text.encode()).hexdigest()
|
|
158
|
+
sir_doc.doc_id = UUID(text_hash)
|
|
159
|
+
# [2026-05-21] URL/PDF ์
๋ ฅ์ ์ถ์ถ๋ ๋ณธ๋ฌธ์ SIRDocument์ ๋ณด์กด.
|
|
160
|
+
# sv_platform์ด Job.source_data๋ก ๋ณต์ฌํด ํ๋ก ํธ "์๋ฌธ" ํจ๋ ๋ ๋์ ์ฌ์ฉ.
|
|
161
|
+
sir_doc.raw_text = raw_text
|
|
162
|
+
logger.info(f"SIR Tree: {len(sir_doc.blocks)} blocks")
|
|
163
|
+
|
|
164
|
+
# TODO [๋ฐ์ฌ์ค]: Step 1.5 โ ์๋ณธ ํ
์คํธ โ Raw Storage(S3/MinIO) ์ ์ฅ
|
|
165
|
+
# await self.raw_storage.upload(source, raw_text, metadata={"source_type": src.value})
|
|
166
|
+
|
|
167
|
+
# TODO [๋ฐ์ฌ์ค]: Step 2.5 โ SIR Document โ PostgreSQL ์ ์ฅ
|
|
168
|
+
# await self.db_manager.save_document(sir_doc)
|
|
169
|
+
|
|
170
|
+
# Step 3~9: Runtime Agent ์คํ
|
|
171
|
+
claims, results, nodes, edges = await self.runtime_agent.process(sir_doc)
|
|
172
|
+
|
|
173
|
+
# [v1] - ๋ฐ์ฌ์ค: Claims/Results โ PostgreSQL ์ ์ฅ (ํ๋ซํผ ์ ์ฉ).
|
|
174
|
+
# ์คํ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฒฝ๋ก์๋ postgres๊ฐ ์์ผ๋ฏ๋ก ์ ์ฅ ์คํจ๊ฐ
|
|
175
|
+
# ๊ฒ์ฆ ์์ฒด๋ฅผ ์ฃฝ์ด์ง ์๊ฒ ๊ฐ์ผ๋ค (psycopg2 ๋ฏธ์ค์น/์ฐ๊ฒฐ๋ถ๊ฐ โ ๊ฒฝ๊ณ ํ ์งํ).
|
|
176
|
+
try:
|
|
177
|
+
if claims:
|
|
178
|
+
await self.db_manager.save_claims(claims, domain=sir_doc.detected_domain, source_type=src.value)
|
|
179
|
+
logger.info(f"Claims ์ ์ฅ ์๋ฃ: {len(claims)}๊ฑด")
|
|
180
|
+
if results:
|
|
181
|
+
await self.db_manager.save_results(results, claims)
|
|
182
|
+
logger.info(f"Results ์ ์ฅ ์๋ฃ: {len(results)}๊ฑด")
|
|
183
|
+
except ImportError as e:
|
|
184
|
+
logger.debug(f"๊ฒฐ๊ณผ ์ ์ฅ ์คํต (DB ๋๋ผ์ด๋ฒ ์์ โ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ชจ๋): {e}")
|
|
185
|
+
except Exception as e: # noqa: BLE001 โ ์ ์ฅ ์คํจ๊ฐ ๊ฒ์ฆ ๊ฒฐ๊ณผ๋ฅผ ๋ฌดํจํํ์ง ์์
|
|
186
|
+
logger.warning(f"๊ฒฐ๊ณผ ์ ์ฅ ์คํจ (๊ฒ์ฆ ๊ฒฐ๊ณผ๋ ์ ํจ): {e}")
|
|
187
|
+
|
|
188
|
+
# TODO [๋ฐ์ฌ์ค]: Nodes/Edges โ Neo4j ์ ์ฅ
|
|
189
|
+
# await self.graph_store.merge_nodes(nodes)
|
|
190
|
+
# await self.graph_store.merge_edges(edges)
|
|
191
|
+
|
|
192
|
+
# Step 10~13: ํผ๋๋ฐฑ/ํ์ต ๋ฃจํ (enable_feedback=true ์ผ ๋๋ง ํ์ฑํ)
|
|
193
|
+
# [v3 ๊น์์ฌ] enable_feedback=false (๊ธฐ๋ณธ๊ฐ) โ skip
|
|
194
|
+
# ํ์ฑํ: config.yaml์์ enable_feedback: true
|
|
195
|
+
if self.enable_feedback:
|
|
196
|
+
pass
|
|
197
|
+
# TODO [๊น์์ฌ]: Step 10 โ Human Review ์ธํฐํ์ด์ค ์ฐ๋
|
|
198
|
+
# TODO [๊น์์ฌ]: Step 11 โ Feedback Logging
|
|
199
|
+
# TODO [๊น์์ฌ]: Step 12 โ Adaptation Trigger
|
|
200
|
+
# TODO [๊น์์ฌ]: Step 13 โ Report ๋ ๋๋ง
|
|
201
|
+
else:
|
|
202
|
+
logger.debug("Step 10~13 skip (enable_feedback=false)")
|
|
203
|
+
|
|
204
|
+
# TODO [๋ฐ์ฌ์ค]: DWH ์ ์ฌ (๊ฒ์ฆ ๋ก๊ทธ, ๋ชจ๋ธ ์ฑ๋ฅ, LLM ๋น์ฉ)
|
|
205
|
+
# await self.dwh_manager.load_verification_logs([...])
|
|
206
|
+
|
|
207
|
+
report = VerificationReport(
|
|
208
|
+
document=sir_doc,
|
|
209
|
+
claims=claims,
|
|
210
|
+
results=results,
|
|
211
|
+
graph_nodes=nodes,
|
|
212
|
+
graph_edges=edges,
|
|
213
|
+
domain_pack_used=sir_doc.detected_domain,
|
|
214
|
+
)
|
|
215
|
+
logger.info(f"ํ์ดํ๋ผ์ธ ์๋ฃ: {len(results)} results")
|
|
216
|
+
_progress.emit("done", count=len(results))
|
|
217
|
+
return report
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
async def verify_text(text: str, config: dict | None = None) -> VerificationReport:
|
|
221
|
+
"""
|
|
222
|
+
์ต์์ API โ ํ
์คํธ ์
๋ ฅ โ ๊ฒ์ฆ ๋ณด๊ณ ์
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
text: ๊ฒ์ฆํ ์๋ฌธ ํ
์คํธ
|
|
226
|
+
config: ์ ํ์ ์ค์ dict
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
VerificationReport
|
|
230
|
+
"""
|
|
231
|
+
return await VerificationPipeline(config).run(text, "text")
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
# [v2 - ๊น์์ฌ] ๋ฌธ์ ์
๋ ฅ(URL/PDF/DOCX/TEXT) ๊ณต๊ฐ ์ง์
์
|
|
235
|
+
async def verify_document(
|
|
236
|
+
source: str,
|
|
237
|
+
source_type: str = "url",
|
|
238
|
+
config: dict | None = None,
|
|
239
|
+
source_text: str | None = None,
|
|
240
|
+
) -> VerificationReport:
|
|
241
|
+
"""
|
|
242
|
+
์ต์์ API โ ๋ฌธ์ ์
๋ ฅ(URL/PDF/DOCX/TEXT) โ ๊ฒ์ฆ ๋ณด๊ณ ์.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
source: URL ยท ํ์ผ ๊ฒฝ๋ก ยท ๋๋ ๋ณธ๋ฌธ ํ
์คํธ
|
|
246
|
+
source_type: "url" | "pdf" | "docx" | "text"
|
|
247
|
+
config: ์ ํ์ ์ค์ dict
|
|
248
|
+
source_text: ์ด๋ฏธ ์ถ์ถ๋ ๋ณธ๋ฌธ์ด ์์ผ๋ฉด ์ ๋ฌ(์ค๋ณต ์ถ์ถ ๋ฐฉ์ง)
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
VerificationReport
|
|
252
|
+
"""
|
|
253
|
+
return await VerificationPipeline(config).run(source, source_type, source_text)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
# [v2 - ๊น์์ฌ] ๊ฐ์ฒดํ ์ง์
์ โ ๊ฐ์ config๋ก ์ฌ๋ฌ ๋ฒ ๊ฒ์ฆํ ๋ (ํจ์ํ์ ์ผํ์ฑ).
|
|
257
|
+
class VerificationEngine:
|
|
258
|
+
"""config๋ฅผ ํ ๋ฒ ์ฃผ์
ํด ๋๊ณ ์ฌ๋ฌ ๋ฌธ์๋ฅผ ๊ฒ์ฆํ๋ ๊ฐ์ฒดํ ์ง์
์ .
|
|
259
|
+
|
|
260
|
+
- ํจ์ํ(`verify_text`/`verify_document`): ๋งค๋ฒ config๋ฅผ ๋ฐ๋ *์ผํ์ฑ* ํธ์ถ์ ํธํจ.
|
|
261
|
+
- ๊ฐ์ฒดํ(`VerificationEngine`): ์์ง์ ๋ง๋ค์ด ๋๊ณ ์ฌ์ฌ์ฉ.
|
|
262
|
+
|
|
263
|
+
engine = VerificationEngine(config)
|
|
264
|
+
r1 = await engine.verify_text("๋ฌธ์ฅ1")
|
|
265
|
+
r2 = await engine.verify_document(url, source_type="url")
|
|
266
|
+
"""
|
|
267
|
+
|
|
268
|
+
def __init__(self, config: dict | None = None):
|
|
269
|
+
self._pipeline = VerificationPipeline(config)
|
|
270
|
+
|
|
271
|
+
async def verify_text(self, text: str) -> VerificationReport:
|
|
272
|
+
return await self._pipeline.run(text, "text")
|
|
273
|
+
|
|
274
|
+
async def verify_document(
|
|
275
|
+
self,
|
|
276
|
+
source: str,
|
|
277
|
+
source_type: str = "url",
|
|
278
|
+
source_text: str | None = None,
|
|
279
|
+
) -> VerificationReport:
|
|
280
|
+
return await self._pipeline.run(source, source_type, source_text)
|