perf(전처리): 343-1 같은 지형 파일 다시 올림 = 전처리 결과 살림 · 다시 돌 때 점군 안 풂 · 도엽 병합 · 국가 GIS · 타일 기억 열쇠
- B03 재올림 — 지형 파일이 source_identity.json 과 같으면 B04 폴더 · 지표면 DB 행 남기고 단계 표시만 되돌림 - 확인 창 「처음부터 다시」 따로 고름(fresh_start) · 409 응답에 preprocess_kept - B04 다시 돎 — 점 수 · 평균 Z 를 structured_stats.json 에 · xyz 는 쓸 때만 풂 - 도엽 병합 열쇠 = 도엽 번호 목록 · 국가 GIS 열쇠 = 범위 · 좌표계 - 지도 타일 메모리 기억 열쇠에 mtime · 크기 - 시험 test_343_1_preprocess_keep 13건 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014utrjfoW831Vc5wJUd13kL
This commit is contained in:
@@ -29,7 +29,7 @@ from B03_FileInput.B03_FileInput_Schema import (
|
||||
)
|
||||
from common_util.common_util_initial_snapshot import clear_designing, discard_initial_snapshot
|
||||
from common_util.common_util_json import atomic_write_json
|
||||
from common_util.common_util_project_reset import purge_project_outputs
|
||||
from common_util.common_util_project_reset import PREPROCESS_STAGE_DIR, purge_project_outputs
|
||||
from common_util.common_util_storage import resolve_stored_project_path
|
||||
from common_util.common_util_workflow_state import (
|
||||
complete_stage,
|
||||
@@ -61,8 +61,10 @@ class OutputsWouldBeDiscarded(Exception):
|
||||
로 다시 들어온다. 자동 절차는 이 예외를 만들지 않는다 — 부를 때 확인을 켜 준다.
|
||||
"""
|
||||
|
||||
def __init__(self, targets: list[str]) -> None:
|
||||
def __init__(self, targets: list[str], preprocess_kept: bool = False) -> None:
|
||||
self.targets = targets
|
||||
# 지형 파일이 그대로라 전처리 결과를 살리는지 — 화면이 「처음부터 다시」를 따로 묻는다.
|
||||
self.preprocess_kept = preprocess_kept
|
||||
super().__init__("설계 산출물이 있어 확인이 필요합니다.")
|
||||
|
||||
|
||||
@@ -78,14 +80,17 @@ def _confirm_replace_response(exc: "OutputsWouldBeDiscarded") -> JSONResponse:
|
||||
"아래가 지워지고 **되돌릴 수 없습니다**: " + " · ".join(exc.targets)
|
||||
),
|
||||
"targets": exc.targets,
|
||||
"preprocess_kept": exc.preprocess_kept,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def describe_existing_outputs(project_root: Path) -> list[str]:
|
||||
def describe_existing_outputs(project_root: Path, keep_preprocess: bool = False) -> list[str]:
|
||||
"""새 자료를 받으면 **지워질 것**의 이름을 사람 말로 늘어놓는다. 없으면 빈 목록."""
|
||||
targets: list[str] = []
|
||||
for stage, label in _OUTPUT_STAGE_LABELS:
|
||||
if keep_preprocess and stage == PREPROCESS_STAGE_DIR:
|
||||
continue
|
||||
stage_root = project_root / stage
|
||||
if not stage_root.is_dir():
|
||||
continue
|
||||
@@ -201,16 +206,37 @@ async def _already_uploaded(
|
||||
)
|
||||
|
||||
|
||||
def preprocess_input_unchanged(project_root: Path, terrain_paths: list[Path]) -> bool:
|
||||
"""지형 파일이 마지막 전처리 때와 같은지 — `processed/source_identity.json` 과 대조.
|
||||
|
||||
같은 지문(크기 + 앞·가운데·끝) 파일은 전송을 건너뛰어 파일이 그대로 남는다 —
|
||||
이름·크기·수정시각이 전처리가 적어 둔 값과 같으면 같은 입력이다.
|
||||
"""
|
||||
if not terrain_paths:
|
||||
return False
|
||||
from B04_PreProcess.B04_PreProcess_Engine import _source_identity
|
||||
|
||||
identity_path = project_root / PREPROCESS_STAGE_DIR / "processed" / "source_identity.json"
|
||||
try:
|
||||
stored = json.loads(identity_path.read_text(encoding="utf-8"))
|
||||
return stored == _source_identity(terrain_paths)
|
||||
except (OSError, ValueError):
|
||||
return False
|
||||
|
||||
|
||||
async def _complete_file_input_if_ready(
|
||||
connection: aiomysql.Connection,
|
||||
project_id: UUID,
|
||||
las_free: bool = False,
|
||||
confirm_replace: bool = True,
|
||||
fresh_start: bool = False,
|
||||
) -> int:
|
||||
"""새 자료로 갈아 끼운다. `confirm_replace=False` 면 지울 것이 있을 때 멈추고 묻는다.
|
||||
|
||||
기본이 `True` 인 까닭 — 자동 절차(체인·스크립트)는 물음에 걸리면 안 된다.
|
||||
사람이 올리는 갈래(라우터)만 `False` 로 불러 확인을 받는다(2026-09-08 사용자 지시).
|
||||
지형 파일이 그대로면 전처리 결과는 살리고 단계 표시만 되돌린다 —
|
||||
`fresh_start=True`(확인 창의 「처음부터 다시」)면 전처리까지 지운다.
|
||||
"""
|
||||
file_types, point_cloud_input_id, route_csv_input_id = await get_project_input_readiness(
|
||||
connection, project_id
|
||||
@@ -234,14 +260,15 @@ async def _complete_file_input_if_ready(
|
||||
gap_message = merge_gap_error(terrain_paths)
|
||||
if gap_message:
|
||||
raise ValueError(gap_message)
|
||||
keep_preprocess = not fresh_start and preprocess_input_unchanged(project_root, terrain_paths)
|
||||
# ⚠ 여기서부터는 되돌릴 수 없다 — 아래 셋이 파일까지 지운다. 지울 것이 있으면 먼저 묻는다.
|
||||
if not confirm_replace:
|
||||
targets = describe_existing_outputs(project_root)
|
||||
targets = describe_existing_outputs(project_root, keep_preprocess)
|
||||
if targets:
|
||||
raise OutputsWouldBeDiscarded(targets)
|
||||
raise OutputsWouldBeDiscarded(targets, keep_preprocess)
|
||||
clear_designing(project_root)
|
||||
discard_initial_snapshot(project_root)
|
||||
await purge_project_outputs(connection, str(project_id), project_root)
|
||||
await purge_project_outputs(connection, str(project_id), project_root, keep_preprocess)
|
||||
async with connection.cursor(aiomysql.DictCursor) as cursor:
|
||||
await reset_stages_after_input_change(cursor, str(project_id))
|
||||
await complete_stage(cursor, str(project_id), 0)
|
||||
|
||||
Reference in New Issue
Block a user