feat(gemini): 屋根伏図 지붕투영면 외곽선 추출 프롬프트 강화 + media_resolution HIGH
- BASE_PROMPT를 지붕 투영면(屋根伏図 footprint) 기준으로 재작성: 屋根伏図 우선(처마/케라바 포함), 立面図/配置図/求積図/断面図 배제, 도머/개구부 제외 - 寸法線 mm 1순위 축척 규칙, 910/1820mm 모듈 단서, L자/직각 형상 보존 규칙 추가 - generationConfig에 mediaResolution: MEDIA_RESOLUTION_HIGH 추가(미지원 SDK 시 무시), usageMetadata 로깅 - FLOOR_PLAN_SCHEMA 및 응답에 selectedDrawingType 추가 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3e37b7448c
commit
afda525be9
@ -26,37 +26,58 @@ const FLOOR_PLAN_SCHEMA = {
|
||||
scale: { type: SchemaType.NUMBER },
|
||||
confidence: { type: SchemaType.NUMBER },
|
||||
notes: { type: SchemaType.STRING },
|
||||
selectedDrawingType: { type: SchemaType.STRING },
|
||||
},
|
||||
required: ['outerline', 'unit'],
|
||||
}
|
||||
|
||||
const BASE_PROMPT = `당신은 건축 평면도(주택 도면)의 외곽선 추출 전문가입니다.
|
||||
첨부된 PDF에서 건물의 외곽(외벽선) 폴리곤 좌표를 추출하여 JSON 으로만 응답하세요.
|
||||
const BASE_PROMPT = `당신은 일본 주택 건축 도면에서 "지붕 투영면(屋根伏図 footprint)" 외곽선을 추출하는 전문가입니다.
|
||||
첨부된 PDF 에서 지붕을 위에서 내려다본 외곽(처마 끝선 포함) 폴리곤 좌표를 추출하여 JSON 으로만 응답하세요.
|
||||
|
||||
규칙:
|
||||
1. 모든 좌표는 밀리미터(mm) 단위의 실측 치수로 환산해야 합니다. 도면의 축척(scale)을 식별하여 적용하세요.
|
||||
[도면 종류 식별 — 매우 중요]
|
||||
- 추출 대상: 屋根伏図(지붕평면도)가 있으면 그 지붕 외곽선(처마/軒先·케라바/ケラバ 끝선 포함)을 사용합니다.
|
||||
- 屋根伏図 가 없으면 平面図(1층/1階 평면도)의 외벽 외주에 처마 출폭(軒の出)을 더한 지붕 투영 외곽을 추정합니다.
|
||||
- 절대 사용 금지: 立面図(입면도)·配置図(배치도)·求積図(면적도)·断面図(단면도). 이 도면들에서는 윤곽을 추출하지 마세요.
|
||||
- 도머(ドーマー)·천창·개구부(開口部) 등 지붕 위 돌출/구멍은 외곽선에 포함하지 마세요(외곽 윤곽이 아닙니다).
|
||||
- 평면도가 여러 층이면 1층(1F) 기준으로 지붕 투영을 판단합니다.
|
||||
|
||||
[축척·치수 결정 — 우선순위]
|
||||
1. 도면에 적힌 寸法線(치수선)의 실제 mm 숫자를 최우선 근거로 좌표를 환산합니다.
|
||||
2. 그 다음 縮尺 표기(예: 縮尺 1/100, S=1:100)를 사용합니다.
|
||||
3. 마지막으로 通り芯(grid axis) 간격으로 보정합니다.
|
||||
4. 치수선 숫자와 축척이 충돌하면 치수선 숫자를 신뢰하세요.
|
||||
5. 일본 주택은 尺貫法 모듈(1間=1820mm, 半間=910mm, 455mm, 303mm)에 정렬되는 경향이 있습니다 — 픽셀비례로 추정한 길이를 가장 가까운 모듈값과 대조해 검토하세요(강제 아님, 참고용).
|
||||
|
||||
[형상 규칙]
|
||||
1. 모든 좌표는 밀리미터(mm) 단위의 실측 치수로 환산합니다.
|
||||
2. 좌표계는 도면의 좌상단을 원점으로 하고, x 는 우측 양수, y 는 하단 양수로 합니다.
|
||||
3. 외곽선은 시계 반대 방향(CCW) 으로 정렬된 정점 배열로 반환합니다.
|
||||
4. 자기교차가 없는 단순 폴리곤이어야 하며, 정점은 3개 이상이어야 합니다.
|
||||
5. PDF 가 평면도가 아니거나 외곽을 추출할 수 없으면 outerline 을 빈 배열로 반환하고 notes 에 사유를 적습니다.
|
||||
6. 응답은 반드시 단일 JSON 객체만 포함하며, 다른 텍스트, 마크다운, 코드펜스를 포함하지 마세요.
|
||||
7. 좌표는 정수 또는 소수 첫째 자리까지 허용합니다.
|
||||
5. L자·凹凸(요철) 평면의 모든 꺾임을 정점으로 보존하고, 직각(直角)에 가까운 코너는 직각으로 간주합니다(비스듬히 근사 금지).
|
||||
6. 분리된 복수 동(棟)이 있으면 가장 큰 주 건물 하나만 반환하고, 별동은 notes 에 기재합니다.
|
||||
7. 지붕 투영을 추출할 수 없으면 outerline 을 빈 배열로 반환하고 notes 에 사유를 적습니다.
|
||||
|
||||
[출력]
|
||||
- 응답은 반드시 단일 JSON 객체만 포함하며, 다른 텍스트, 마크다운, 코드펜스를 포함하지 마세요.
|
||||
- 좌표는 정수 또는 소수 첫째 자리까지 허용합니다.
|
||||
- selectedDrawingType 에 사용한 도면 종류('roof_plan' | 'floor_plan_1f' | 'other')를 기재합니다.
|
||||
|
||||
스키마:
|
||||
{
|
||||
"outerline": [{"x": number, "y": number}, ...],
|
||||
"unit": "mm",
|
||||
"scale": number (선택, 도면 1mm 당 실제 mm),
|
||||
"scale": number (선택, 축척 분모. 1/100 이면 100),
|
||||
"confidence": number (0~1),
|
||||
"notes": string (선택)
|
||||
"notes": string (선택),
|
||||
"selectedDrawingType": string (선택)
|
||||
}`
|
||||
|
||||
const buildPrompt = ({ pageMode, facadePages, floorPages } = {}) => {
|
||||
if (pageMode === 'specify' && (facadePages || floorPages)) {
|
||||
const hints = []
|
||||
if (floorPages) hints.push(`평면도(平面図) 페이지: ${floorPages}`)
|
||||
if (floorPages) hints.push(`평면도(平面図)·지붕평면도(屋根伏図) 페이지: ${floorPages}`)
|
||||
if (facadePages) hints.push(`입면도(立面図) 페이지: ${facadePages}`)
|
||||
return `${BASE_PROMPT}\n\n페이지 힌트: ${hints.join(' / ')}. 외곽선은 위에서 지정한 평면도 페이지 기준으로 추출하세요.`
|
||||
return `${BASE_PROMPT}\n\n페이지 힌트: ${hints.join(' / ')}. 입면도 페이지는 외곽선 추출에 쓰지 말고 높이·층수 참고로만 사용하세요. 지붕 투영 외곽선은 지정된 평면도/지붕평면도 페이지 기준으로 추출하세요.`
|
||||
}
|
||||
return BASE_PROMPT
|
||||
}
|
||||
@ -157,6 +178,8 @@ export async function POST(req) {
|
||||
responseMimeType: 'application/json',
|
||||
responseSchema: FLOOR_PLAN_SCHEMA,
|
||||
temperature: 0.1,
|
||||
// Gemini 3 고fidelity 경로 — 얇은 외벽선/작은 寸法 텍스트 가독성 확보(미지원 시 무시됨). 적용 여부는 usageMetadata 토큰 증가로 검증.
|
||||
mediaResolution: 'MEDIA_RESOLUTION_HIGH',
|
||||
},
|
||||
})
|
||||
|
||||
@ -174,6 +197,7 @@ export async function POST(req) {
|
||||
|
||||
const raw = result.response.text()
|
||||
logger.debug('[gemini/floor-plan] raw response', raw)
|
||||
logger.debug('[gemini/floor-plan] usageMetadata', result.response.usageMetadata)
|
||||
|
||||
let parsed
|
||||
try {
|
||||
@ -193,6 +217,7 @@ export async function POST(req) {
|
||||
scale: parsed.scale ?? null,
|
||||
confidence: parsed.confidence ?? null,
|
||||
notes: parsed.notes ?? null,
|
||||
selectedDrawingType: parsed.selectedDrawingType ?? null,
|
||||
empty: validation.empty,
|
||||
})
|
||||
} catch (error) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user