fix(763-3): B04 분석 · 조합 짓기 = 보기만 · 다른 서피스 [확정] = 업로드와 같은 전처리 체인 · 체인 실패에도 미리 셈
- B04 [분석](조합 짓기) — 단계 시작 · 확정 해제 · 실패 단계 기록 걷음 · 1 단계 값(las_selection 포함) 그대로 · 미리 셈 없음 · 진행 글 = 확정 있으면 「확정 그대로」 - 분석 결과 DB 고쳐 쓰기가 확정 모델을 COMPLETE 로 내리던 것 — CONFIRMED 그대로(`_upsert_surface_model`) · 안 쓰는 `clear_confirmed_surface_models` 지움 - B04 [확정] — 같은 서피스(필터 · 표현 · 평활) = 등고선 간격만 · 다른 서피스 = `run_surface_change_chain`(새 파일): 초기값 스냅샷 버림 · B05~B09 지움(같은 지형 재업로드 길 keep_preprocess) · 단계 2 이후 처음 → 자동 설계 체인 - 자동 · 재확정 체인 미리 셈 = finally(실패 · 건너뜀 길에도) · B05 LAS 나중 올리기 끝 미리 셈 예약 - 추천 [적용](as_initial) = 선만 · 설계 지형 그대로(요구 605-2 · 브레인 승인) · 지형 칩은 사용자 답 기다림(지금대로) - 지킴 시험 test_763_3 — B05~B09 파이썬에서 확정 서피스 쓰는 부름은 지형 칩 · 라이다 적어 둠 둘만 - 시험 309_3 · 351_1 · 509_5 를 새 길에 맞춤(미리 셈 부르는 곳 둘 더 · finally · 추천 [적용] 지형 안 넘김) - 재확정 체인(`run_redesign_chain`) 부르는 곳 0 — 지움은 따로(시험 342_2 셋 함께) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,6 @@ from B04_PreProcess.B04_PreProcess_Engine_Extent import (
|
||||
from B04_PreProcess.B04_PreProcess_Engine_Ground import available_filters
|
||||
from B04_PreProcess.B04_PreProcess_Engine_PointPreview import ensure_point_preview, sample_points
|
||||
from B04_PreProcess.B04_PreProcess_Repository import (
|
||||
clear_confirmed_surface_models,
|
||||
get_input_file,
|
||||
list_project_point_cloud_inputs,
|
||||
list_project_point_cloud_paths,
|
||||
@@ -67,13 +66,11 @@ from common_util.common_util_auth import require_system_admin
|
||||
from common_util.common_util_http_cache import cached_file_response
|
||||
from common_util.common_util_storage import resolve_stored_project_path
|
||||
from common_util.common_util_surface_confirmation import (
|
||||
confirmed_surface_params,
|
||||
get_surface_confirmation_params,
|
||||
surface_confirmation_defaults,
|
||||
)
|
||||
from common_util.common_util_workflow_state import (
|
||||
fail_stage,
|
||||
start_stage,
|
||||
update_stage_progress,
|
||||
terrain_changes,
|
||||
update_contour_interval_param,
|
||||
)
|
||||
from config.config_db import get_db_pool
|
||||
|
||||
@@ -89,7 +86,10 @@ router.include_router(status_router)
|
||||
async def analyze_surface(
|
||||
project_id: UUID, request: SurfaceAnalyzeRequest
|
||||
) -> SurfaceAnalyzeResponse | JSONResponse:
|
||||
"""LAS 구조화·지면 필터·지표면 모델 생성을 실행하고 DB에 기록한다."""
|
||||
"""LAS 구조화·지면 필터·지표면 모델 생성을 실행하고 DB에 기록한다 — 보기만(763-3 · 요구 605).
|
||||
|
||||
확정 · 단계 상태 · 1 단계 값(`las_selection` 포함)을 안 바꿈 · 미리 셈도 없음. 서피스를 바꾸는
|
||||
길 = 다른 모델 [확정](전처리 체인 다시)."""
|
||||
try:
|
||||
source_filters = request.resolved_filters()
|
||||
methods = request.resolved_methods()
|
||||
@@ -97,19 +97,9 @@ async def analyze_surface(
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": str(exc)})
|
||||
|
||||
pool = get_db_pool()
|
||||
project_root: Path | None = None
|
||||
try:
|
||||
params = {
|
||||
"input_file_id": request.input_file_id,
|
||||
"source_filters": source_filters,
|
||||
"methods": methods,
|
||||
"force": request.force,
|
||||
}
|
||||
async with pool.acquire() as connection:
|
||||
async with connection.cursor() as cursor:
|
||||
await start_stage(cursor, str(project_id), 1, params)
|
||||
await clear_confirmed_surface_models(connection, project_id)
|
||||
await connection.commit()
|
||||
|
||||
stored_path = await get_project_storage_relative_path(connection, project_id)
|
||||
project_root = Path(resolve_stored_project_path(stored_path))
|
||||
input_file = await get_input_file(connection, project_id, request.input_file_id)
|
||||
@@ -151,19 +141,23 @@ async def analyze_surface(
|
||||
analysis_result=result,
|
||||
source_filters=source_filters,
|
||||
)
|
||||
async with connection.cursor() as cursor:
|
||||
await update_stage_progress(cursor, str(project_id), 1, 100)
|
||||
await connection.commit()
|
||||
confirmed = await confirmed_surface_params(connection, str(project_id))
|
||||
except Exception:
|
||||
await connection.rollback()
|
||||
raise
|
||||
|
||||
write_surface_progress(
|
||||
project_root,
|
||||
100,
|
||||
"awaiting_confirmation",
|
||||
"WF1 분석이 완료되었습니다. 사용할 모델을 확정하세요.",
|
||||
)
|
||||
if confirmed is not None:
|
||||
write_surface_progress(
|
||||
project_root, 100, "completed", "조합을 지었습니다 — 확정 그대로."
|
||||
)
|
||||
else:
|
||||
write_surface_progress(
|
||||
project_root,
|
||||
100,
|
||||
"awaiting_confirmation",
|
||||
"WF1 분석이 완료되었습니다. 사용할 모델을 확정하세요.",
|
||||
)
|
||||
|
||||
return SurfaceAnalyzeResponse(
|
||||
project_id=str(project_id),
|
||||
@@ -173,16 +167,14 @@ async def analyze_surface(
|
||||
)
|
||||
except LookupError as exc:
|
||||
return JSONResponse(status_code=404, content={"status": "error", "message": str(exc)})
|
||||
except (OSError, ValueError) as exc:
|
||||
async with pool.acquire() as connection, connection.cursor() as cursor:
|
||||
await fail_stage(cursor, str(project_id), 1, str(exc))
|
||||
await connection.commit()
|
||||
except (OSError, ValueError) as exc: # 보기만 — 단계 상태 그대로 · 진행 파일만 끝(763-3)
|
||||
if project_root is not None:
|
||||
write_surface_progress(project_root, 100, "failed", str(exc))
|
||||
return JSONResponse(status_code=400, content={"status": "error", "message": str(exc)})
|
||||
except Exception as exc:
|
||||
logger.exception("B04 지표면 분석 실패: project_id=%s", project_id)
|
||||
async with pool.acquire() as connection, connection.cursor() as cursor:
|
||||
await fail_stage(cursor, str(project_id), 1, str(exc))
|
||||
await connection.commit()
|
||||
if project_root is not None:
|
||||
write_surface_progress(project_root, 100, "failed", str(exc))
|
||||
return JSONResponse(
|
||||
status_code=500,
|
||||
content={"status": "error", "message": "지표면 분석 처리 중 오류가 발생했습니다."},
|
||||
@@ -214,7 +206,10 @@ async def confirm_surface(
|
||||
request: SurfaceConfirmRequest,
|
||||
_session: dict[str, Any] = Depends(require_system_admin),
|
||||
) -> SurfaceConfirmResponse | JSONResponse:
|
||||
"""사용자가 선택한 지표면 모델을 확정하고 WF1을 완료한다."""
|
||||
"""사용자가 선택한 지표면 모델을 확정하고 WF1을 완료한다.
|
||||
|
||||
같은 서피스(필터 · 표현 · 평활) 다시 [확정] = 등고선 간격만 · 체인 없음. 다른 서피스 = 업로드와
|
||||
같은 전처리 체인(B05~B09 초기화 → 자동 설계 · 추천 미리 셈 · 763-3 · 요구 605)."""
|
||||
pool = get_db_pool()
|
||||
try:
|
||||
async with pool.acquire() as connection:
|
||||
@@ -247,24 +242,32 @@ async def confirm_surface(
|
||||
),
|
||||
}
|
||||
)
|
||||
await confirm_surface_selection(
|
||||
connection,
|
||||
project_id,
|
||||
request.model_id,
|
||||
selection,
|
||||
)
|
||||
current = await confirmed_surface_params(connection, str(project_id))
|
||||
same = current is not None and not terrain_changes(current, selection)
|
||||
if same: # 같은 서피스 — 아무것도 안 다시 셈(등고선 간격만 · 763-3)
|
||||
await update_contour_interval_param(
|
||||
connection, str(project_id), float(selection["contour_interval_m"])
|
||||
)
|
||||
else:
|
||||
await confirm_surface_selection(
|
||||
connection,
|
||||
project_id,
|
||||
request.model_id,
|
||||
selection,
|
||||
)
|
||||
await connection.commit()
|
||||
except Exception:
|
||||
await connection.rollback()
|
||||
raise
|
||||
# 재확정 체인(2026-08-04 사용자 확정) — 새 지표면 기준으로 B05·B06을 백그라운드
|
||||
# 재계산·저장한다. 사용자 저장 입력(제어점·경사 옵션·측점별 설계)은 유지·이월된다.
|
||||
if same:
|
||||
return SurfaceConfirmResponse(project_id=str(project_id), model_id=request.model_id)
|
||||
# 서피스가 바뀜 — 업로드와 같은 전처리 체인 하나(B05~B09 초기화 · 763-3 · 요구 605).
|
||||
# 응답을 막지 않도록 백그라운드로 돌리고, 체인은 실패를 스스로 격리한다.
|
||||
from B03_FileInput.B03_FileInput_Service_Chain import run_redesign_chain
|
||||
from B03_FileInput.B03_FileInput_Service_SurfaceChange import run_surface_change_chain
|
||||
|
||||
redesign_task = asyncio.create_task(
|
||||
run_redesign_chain(project_id, request.model_id, dict(selection)),
|
||||
name=f"redesign-chain-{project_id}",
|
||||
run_surface_change_chain(project_id, request.model_id),
|
||||
name=f"surface-change-chain-{project_id}",
|
||||
)
|
||||
redesign_task.add_done_callback(
|
||||
lambda task: task.exception() # 체인 내부에서 이미 로깅 — 미회수 예외 경고만 방지
|
||||
|
||||
Reference in New Issue
Block a user