260710_0
This commit is contained in:
@@ -3,8 +3,10 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from uuid import UUID
|
||||
|
||||
import aiomysql
|
||||
from fastapi import APIRouter
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
@@ -30,6 +32,63 @@ logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/api/projects", tags=["B04 Surface Analysis"])
|
||||
|
||||
|
||||
async def save_surface_analysis_to_db(
|
||||
connection: aiomysql.Connection,
|
||||
*,
|
||||
project_id: UUID,
|
||||
input_file_id: int,
|
||||
analysis_result: dict[str, Any],
|
||||
source_filters: list[str],
|
||||
) -> list[int]:
|
||||
"""WF1 분석 결과를 DB에 저장한다.
|
||||
|
||||
이 함수는 트랜잭션을 시작하거나 종료하지 않는다. 호출자는 같은 커넥션에서
|
||||
begin/commit/rollback을 한 번만 수행해야 한다.
|
||||
"""
|
||||
input_file = await get_input_file(connection, project_id, input_file_id)
|
||||
processed = analysis_result["processed"]
|
||||
processed_cloud_id = await create_processed_point_cloud(
|
||||
connection,
|
||||
input_file_id=input_file_id,
|
||||
project_id=project_id,
|
||||
process_type="structured",
|
||||
processed_file_path=processed["processed_file_path"],
|
||||
converted_format=None,
|
||||
converted_file_path=processed["converted_file_path"],
|
||||
point_count=processed["point_count"],
|
||||
bounds=processed["bounds"],
|
||||
statistics=processed["statistics"],
|
||||
classification_summary=None,
|
||||
processing_params={"filters": source_filters},
|
||||
)
|
||||
surface_model_ids: list[int] = []
|
||||
for model in analysis_result["models"]:
|
||||
model_id = await create_surface_model(
|
||||
connection,
|
||||
project_id=project_id,
|
||||
model_type=model["model_type"],
|
||||
source_file_id=input_file_id,
|
||||
processed_cloud_id=processed_cloud_id,
|
||||
crs_epsg=input_file["crs_epsg"],
|
||||
resolution_m=model["resolution_m"],
|
||||
model_file_path=model["model_file_path"],
|
||||
generation_params=model["generation_params"],
|
||||
)
|
||||
surface_model_ids.append(model_id)
|
||||
for layer in model["layers"]:
|
||||
await create_terrain_layer(
|
||||
connection,
|
||||
surface_model_id=model_id,
|
||||
layer_name=layer["layer_name"],
|
||||
geometry_type=layer["geometry_type"],
|
||||
layer_file_path=layer["file_path"],
|
||||
file_format=layer["file_format"],
|
||||
file_size_mb=None,
|
||||
statistics=None,
|
||||
)
|
||||
return surface_model_ids
|
||||
|
||||
|
||||
@router.post("/{project_id}/surface/analyze", response_model=SurfaceAnalyzeResponse)
|
||||
async def analyze_surface(
|
||||
project_id: UUID, request: SurfaceAnalyzeRequest
|
||||
@@ -67,46 +126,13 @@ async def analyze_surface(
|
||||
# DB 기록 (트랜잭션)
|
||||
await connection.begin()
|
||||
try:
|
||||
processed = result["processed"]
|
||||
processed_cloud_id = await create_processed_point_cloud(
|
||||
surface_model_ids = await save_surface_analysis_to_db(
|
||||
connection,
|
||||
input_file_id=request.input_file_id,
|
||||
project_id=project_id,
|
||||
process_type="structured",
|
||||
processed_file_path=processed["processed_file_path"],
|
||||
converted_format=None,
|
||||
converted_file_path=processed["converted_file_path"],
|
||||
point_count=processed["point_count"],
|
||||
bounds=processed["bounds"],
|
||||
statistics=processed["statistics"],
|
||||
classification_summary=None,
|
||||
processing_params={"filters": source_filters},
|
||||
input_file_id=request.input_file_id,
|
||||
analysis_result=result,
|
||||
source_filters=source_filters,
|
||||
)
|
||||
surface_model_ids: list[int] = []
|
||||
for model in result["models"]:
|
||||
model_id = await create_surface_model(
|
||||
connection,
|
||||
project_id=project_id,
|
||||
model_type=model["model_type"],
|
||||
source_file_id=request.input_file_id,
|
||||
processed_cloud_id=processed_cloud_id,
|
||||
crs_epsg=input_file["crs_epsg"],
|
||||
resolution_m=model["resolution_m"],
|
||||
model_file_path=model["model_file_path"],
|
||||
generation_params=model["generation_params"],
|
||||
)
|
||||
surface_model_ids.append(model_id)
|
||||
for layer in model["layers"]:
|
||||
await create_terrain_layer(
|
||||
connection,
|
||||
surface_model_id=model_id,
|
||||
layer_name=layer["layer_name"],
|
||||
geometry_type=layer["geometry_type"],
|
||||
layer_file_path=layer["file_path"],
|
||||
file_format=layer["file_format"],
|
||||
file_size_mb=None,
|
||||
statistics=None,
|
||||
)
|
||||
await connection.commit()
|
||||
except Exception:
|
||||
await connection.rollback()
|
||||
@@ -147,3 +173,35 @@ async def get_surface_models(project_id: UUID) -> SurfaceModelListResponse | JSO
|
||||
status_code=500,
|
||||
content={"status": "error", "message": "모델 목록 조회 중 오류가 발생했습니다."},
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{project_id}/surface/status")
|
||||
async def get_wf1_analysis_status(project_id: UUID) -> dict:
|
||||
"""WF1 분석 상태를 조회한다."""
|
||||
pool = get_db_pool()
|
||||
try:
|
||||
async with pool.acquire() as connection:
|
||||
async with connection.cursor(aiomysql.DictCursor) as cursor:
|
||||
await cursor.execute(
|
||||
"""
|
||||
SELECT COUNT(*) as model_count
|
||||
FROM surface_models
|
||||
WHERE project_id = %s
|
||||
""",
|
||||
(str(project_id),),
|
||||
)
|
||||
row = await cursor.fetchone()
|
||||
model_count = int(row["model_count"]) if row else 0
|
||||
|
||||
status = "completed" if model_count > 0 else "in_progress"
|
||||
return {
|
||||
"project_id": str(project_id),
|
||||
"status": status,
|
||||
"model_count": model_count,
|
||||
}
|
||||
except Exception:
|
||||
logger.exception("WF1 분석 상태 조회 실패: project_id=%s", project_id)
|
||||
return JSONResponse(
|
||||
status_code=500,
|
||||
content={"status": "error", "message": "분석 상태 조회 중 오류가 발생했습니다."},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user