DEVELOPMENT TOOL
NAA Tour API 테스트
실제 LLM을 호출합니다. API Key와 요청 본문은 브라우저에 저장하지 않습니다.
현재 API 설명·규율·명세
책임 경계, 생성·재생성 규칙, 요청·응답·오류 계약
POST /v1/tour/course
현재 구현 계약
NAA 현재 구현spaceContext의 공간 그래프와 scenes 선택 범위 안에서 Survey와 free_text를 반영한 XR 투어 정차 순서와 Action을 생성합니다. 응답은 XROO가 실행할 themeId와 Scene별 Action만 포함하며, 실제 이동 렌더링이나 좌표 기반 waypoint는 반환하지 않습니다.
책임 경계: 서버는 요청의
spaceContext.scenes[].links[].destSceneID를 방향성 이동 제약으로 사용하며, 이 Link로 연결된 Scene 순서만 허용합니다. XROO 클라이언트는 반환된 Scene 전환과 Action을 실행합니다. 별도 Transit Scene을 자동 삽입하지 않으며, 응답의 모든 Scene은 설명이 있는 실제 정차 지점입니다.처리 흐름
- 요청 크기·인증·JSON 필드와
spaceContext의 Scene·Theme·Link 참조를 검증합니다. scenes를 닫힌 선택 범위로 삼고, 요청 Scene 전체에서 공통으로 사용할 수 있는 Theme을 결정합니다.history를 후보에서 제외하고 초기 또는 현재 Scene 기준으로 도달 가능한 후보와 첫 Scene 정책을 계산합니다.- 필요한 Scene 좌표가 모두 유효하면 방향성 Link별 상대
coordinateCost를 계산해 LLM에 제공합니다. - LLM이 계획을 반환하면 Domain Validator가 검증합니다. Domain 검증에 실패한 경우에만 같은 후보 범위에서 한 번 Repair한 뒤 다시 검증합니다.
- LLM 연결·Structured Output 생성 실패는 즉시, Repair 후 Domain 검증 실패는 재검증 뒤
503 PLANNER_UNAVAILABLE로 응답합니다.
코스 생성 규율
- 초기 생성의 첫 Scene은 반드시
spaceContext.startingSceneID입니다. - Scene은
scenes안에서만 고르며 중복할 수 없습니다. 관련성이 낮으면maxScenes보다 적게 선택할 수 있습니다. - 연속 Scene은 이전 Scene의
links[].destSceneID에 있어야 합니다. 벽·보행 경로를 별도 추론하지 않습니다. - 좌표 비용은 비슷한 의미 경로 사이의 상대 tie-breaker일 뿐입니다. 미터·시간·최단 경로를 보장하지 않습니다.
- 모든 정차 Scene에는 공백이 아닌
DISPLAY_TEXT가 하나 이상 필요합니다. - 설명 근거는 Survey,
free_text, Scene 제목·설명·공간 유형·매칭 관심사입니다. 이미지 분석이나 제공되지 않은 채광·크기·수납·가구 정보는 추측하지 않습니다.
재생성 규율
current와history는 함께 보내고, 재생성에서는themeId도 필수입니다. 명시한 필드를null로 보내지 말고 불필요하면 생략합니다.history의 Scene은 후보에서 제외합니다. 중복 ID는 내부 방문 집합에서 하나로 합쳐집니다.- 현재 Scene이 미방문이면 응답의 첫 Scene은
current.sceneId입니다. - 현재 Scene이 이미 방문됐다면 첫 Scene은 현재 Scene의 직접 Link 중 남은 후보여야 합니다.
current.position을 생략하면 해당 Scene의 좌표를 사용합니다. 직접 보내려면x/y/z를 모두 보냅니다.- 서버는 코스·방문 상태를 저장하지 않습니다. 재생성 호출자는 전체 요청 정보와 최초
scenes, 고정themeId, 최신current·history를 매번 다시 보냅니다. - 테스트 페이지는 최초 성공 코스의 전체
scenes와 Theme을 잠가 미탐색 재생성 범위를 유지합니다.
요청 필드 명세
| 필드 | 필수 | 형식·제약 | 동작 |
|---|---|---|---|
identifier | 필수 | 문자열 1..256자 | 호출자가 제공하는 요청 식별값입니다. 서버 세션 상태에는 사용하지 않으며, 현재 접근 로그에는 원문 대신 해시만 기록합니다. |
language | 필수 | ko 또는 en | 생성 안내 문구의 언어입니다. |
scenes | 필수 | 중복 없는 정수 배열, 1..5000개 | LLM이 정차 지점을 고를 수 있는 닫힌 범위입니다. 모든 ID는 spaceContext.scenes에 있어야 하며, 초기 요청에는 startingSceneID가 포함돼야 합니다. |
survey | 필수 | family, childAges, people, spaces, lifestyle | 모든 하위 필드를 보냅니다. 지원하지 않는 문자열 코드를 먼저 제외한 뒤, 남은 지원 코드 기준으로 배열 중복을 금지하고 childAges 최대 8개, spaces 3개, lifestyle 2개를 적용합니다. |
spaceContext | 필수 | id, 정수 startingSceneID, themes 1..256개, scenes 1..5000개, 선택 markers 최대 10000개 | 현재 Phase의 인라인 공간정보입니다. Scene의 ID·제목·Theme Layer·방향성 Link와 선택 좌표를 검증·매핑합니다. 그 밖의 필드는 무시합니다. |
free_text | 선택 | 앞뒤 공백 제거 후 최대 1000자 | 사용자가 XR 투어에서 보고 싶은 관심사 원문입니다. 공백뿐이면 없는 값으로 처리합니다. |
themeId | 초기 선택 재생성 필수 | spaceContext.themes의 정수 ID | 요청 Scene 전체에 공통인 Theme이어야 합니다. 초기 요청에서 생략하면 기본 Theme 또는 Theme 순서로 선택합니다. |
options.maxScenes | 선택 | 정수 1..6, 기본값 6 | 응답 Scene 수의 상한입니다. 정확히 이 수를 채우라는 뜻은 아닙니다. |
current | 재생성 필수 | {sceneId, position?} | sceneId는 요청 scenes 안에 있어야 합니다. 위치는 선택이며 보낼 때 x/y/z를 모두 보냅니다. |
history | 재생성 필수 | 정수 배열, 최대 5000개 | 실제 방문 완료 Scene 목록입니다. 모든 ID는 요청 scenes와 공간정보에 있어야 하며 다음 후보에서 제외됩니다. |
Survey 지원 코드
family:single=1인 가구,couple=부부·커플,child=자녀가 있는 가족,parents=부모님과 함께 거주,etc=기타childAges:a=영유아,b=초등학생,c=중·고등학생,d=성인 자녀people:1=1명,2=2명,3=3명,4=4명,5=5명 이상spaces:living=거실,kitchen=주방·다이닝,bedroom=침실,kids=자녀방,bath=욕실,dress=드레스룸·파우더룸,pantry=팬트리·수납공간,utility=다용도실,balcony=발코니·테라스lifestyle:famtime=가족이 함께 보내는 공간,kidedu=자녀 학습과 생활,wfh=재택근무·홈오피스,guest=손님 방문과 모임,pet=반려동물과 생활,hobby=취미·운동 공간,chores=편리한 가사 동선,privacy=가족 구성원별 독립 공간,none=특별히 없음
알 수 없는 요청 필드는 현재 호환성을 위해 허용하지만 Planner나 성공 응답으로 전달하지 않습니다. 필드 형태의 기계 판독 기준은 OpenAPI JSON, 실제 초기 예시는 아래 “초기 샘플 불러오기”를 사용하세요.
응답 및 Action 명세
성공 응답은 추가 필드 없이 themeId와 1..6개의 scenes만 포함합니다. 각 Scene은 {sceneId, actions} 형태이며 Action은 실행 순서대로 적용합니다.
| Action | value | 의미·제약 |
|---|---|---|
DISPLAY_TEXT | 공백 아닌 문자열 | Scene 설명입니다. 모든 Scene에 하나 이상 필요합니다. |
AROUND_360 | 없음 | 360도 둘러보기입니다. 객체에는 type만 둡니다. |
STAY | 0 이상 정수 | 밀리초 단위 대기 시간입니다. |
OPEN_MARKER_CONTENTS | Marker 정수 ID | 계약에는 있으나 현재 Marker→Scene 명시 매핑이 확정되지 않아 생성 단계에서는 허용하지 않습니다. |
UPDATE_FOV | 30..120 | 절대 수직 FOV 값입니다. |
UPDATE_YAW | -45..45, 0 제외 | 상대 좌우 회전 각도입니다. |
UPDATE_PITCH | -30..30, 0 제외 | 상대 상하 회전 각도입니다. |
{
"themeId": 12608,
"scenes": [
{
"sceneId": 291441,
"actions": [
{"type": "DISPLAY_TEXT", "value": "거실을 살펴봅니다."},
{"type": "AROUND_360"}
]
}
]
}
오류·운영 계약
| HTTP | 대표 코드 | 발생 조건 |
|---|---|---|
| 400 | INVALID_INPUT | 필수 필드, 타입, 범위, Scene 참조, 초기·재생성 조합이 잘못된 경우 |
| 401 | UNAUTHORIZED | API Key 인증이 활성화됐고 X-API-Key가 없거나 일치하지 않는 경우 |
| 413 | PAYLOAD_TOO_LARGE | 요청 본문이 기본 10 MiB 또는 MAX_PAYLOAD_BYTES 설정을 초과한 경우 |
| 422 | NO_AVAILABLE_THEMENO_ELIGIBLE_SCENEINVALID_SPACE_GRAPH | 공통 Theme, 도달 가능한 후보, 공간 그래프 참조를 만족하지 못한 경우 |
| 500 | INTERNAL_ERROR | 인증 설정 누락 또는 처리되지 않은 서버 오류 |
| 503 | PLANNER_UNAVAILABLE | LLM 연결·Structured Output 생성이 실패한 경우 즉시, 또는 반환 계획의 Domain 검증이 1회 Repair 후에도 실패한 경우 |
{
"code": "INVALID_INPUT",
"message": "Request validation failed",
"requestId": "요청 추적 ID",
"details": [{"field": "scenes", "reason": "오류 원인"}]
}
인증·추적
API_KEY_REQUIRED=true일 때만X-API-Key가 필수입니다.- 요청의
X-Request-ID를 재사용하거나 서버가 생성하며, 응답 Header와 오류 본문에 돌려줍니다. - 애플리케이션 자체 Rate Limit과 Pagination은 현재 없습니다.
상태 확인·테스트 페이지
/health/live는 프로세스 생존,/health/ready는 설정 모델이 LLM 서버에 실제 제공되는지 확인합니다.- 이 테스트 페이지와 샘플 Route는
TEST_PAGE_ENABLED=true일 때만 열립니다. - API Key와 요청 JSON은 브라우저 저장소에 보관하지 않으며 새로고침하면 초기 샘플로 돌아갑니다.
투어 요청 설정
free_text · current · history현재 Scene이 방문 이력에 포함되면 다음 direct Link부터, 포함되지 않으면 현재 Scene부터 코스를 생성합니다. 상태는 브라우저 메모리에만 유지됩니다.
서베이 선택
request.survey선택값은 즉시 아래 요청 JSON의 survey에 반영됩니다. 지원되는 선택값은 모순되어 보여도 그대로 전송됩니다.
요청 JSON
POST /v1/tour/course선택한 JSON 객체는 spaceContext로, 포함된 Scene ID는 최상위 scenes로 입력됩니다.
응답
실행 전아직 응답이 없습니다.
미탐색 후보는 응답 후 계산됩니다.