CSV에서 에셋 대량 가져오기
이 가이드에서는 CSV 파일에서 트윈에 RealityAsset을 대량으로 생성하는 방법을 보여줍니다. 각 행은 에셋 이름과 트윈 공간의 방향이 지정된 경계 상자를 정의합니다. 이 워크플로는 Client Credentials 플로우와 write:asset 스코프를 사용합니다.
사전 요구 사항
섹션 제목: “사전 요구 사항”- Client Credentials로 구성된 OAuth 애플리케이션
- 스코프:
read:basic,read:hierarchy,write:asset client_id와client_secret- 대상 트윈에 대한 콘텐츠 접근 및 편집 권한
- 에셋을 생성할 트윈 ID
이 패턴을 사용해야 하는 경우
섹션 제목: “이 패턴을 사용해야 하는 경우”Prevu3D 외부에 이미 에셋 정의가 있는 경우 CSV 기반 가져오기를 사용하세요. 예:
- 3D 좌표가 포함된 CMMS 또는 ERP 시스템에서 내보낸 장비 목록
- 외부 도구의 측량 또는 태그 지정 결과
- 에셋이 트윈 좌표에 배치된 다른 플랫폼에서의 마이그레이션
각 API 호출은 하나의 에셋을 생성합니다. 스크립트가 CSV 행을 반복하며 각 항목에 대해 POST /v1/twin/{twinId}/assets를 호출합니다.
CSV 형식
섹션 제목: “CSV 형식”스프레드시트에는 헤더 행이 포함되어야 합니다. 필수 열:
| 열 | 매핑 대상 | 설명 |
|---|---|---|
Description | 에셋 name | RealityAsset의 표시 이름 |
Manual_X | 상자 중심 x | 트윈 공간에서 상자 중심의 X 좌표 |
Manual_Y | 상자 중심 y | 트윈 공간에서 상자 중심의 Y 좌표 |
Manual_Z | 상자 중심 z | 트윈 공간에서 상자 중심의 Z 좌표 |
Manual_Box_X | 상자 크기 x | 경계 상자의 너비 |
Manual_Box_Y | 상자 크기 y | 경계 상자의 깊이 |
Manual_Box_Z | 상자 크기 z | 경계 상자의 높이 |
예:
Description,Manual_X,Manual_Z,Manual_Y,Manual_Box_X,Manual_Box_Z,Manual_Box_YPump A,6.27,-5.10,187.12,0.35,0.64,0.33Valve B,8.84,-3.14,189.41,2.99,1.11,4.69좌표는 트윈과 동일한 좌표계여야 합니다. RealityTwin에서 에셋을 수동으로 배치한 경우 트윈 공간의 값을 내보내거나 기록하세요. 회전은 기본적으로 항등값입니다. 방향이 지정된 볼륨이 필요한 경우 API는 각 상자에서 선택적 rotation 쿼터니언을 허용합니다.
엔드투엔드 플로우
섹션 제목: “엔드투엔드 플로우”flowchart LR A["1. Authenticate"] --> B["2. Read CSV rows"] B --> C["3. Build workingStructure"] C --> D["4. POST asset per row"] D --> E["5. Review results"]
| 단계 | 엔드포인트 | 얻는 것 |
|---|---|---|
| 인증 | POST /oauth/token | 액세스 토큰 |
| API URL 확인 | GET /oauth/api-info | 지역별 apiUrl |
| 에셋 생성 | POST /v1/twin/{twinId}/assets | 행마다 새 에셋 ID |
에셋 페이로드 형태
섹션 제목: “에셋 페이로드 형태”각 행은 단일 방향 상자를 포함하는 workingStructure가 있는 하나의 에셋이 됩니다.
{ "name": "Pump A", "workingStructure": { "boxes": [ { "center": { "x": 6.27, "y": 187.12, "z": -5.10 }, "size": { "x": 0.35, "y": 0.33, "z": 0.64 }, "rotation": { "x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0 } } ] }}생성 시 에셋 유형을 지정하려면 조직에 구성된 유형의 UUID와 함께 assetTypeId를 추가하세요. RealityPlatform에서 유형이 정의되는 방법은 에셋 유형을 참조하세요.
1단계 — 인증
섹션 제목: “1단계 — 인증”Client Credentials로 액세스 토큰을 획득합니다.
POST https://cloud-api.prevu3d.com/oauth/tokenAuthorization: Basic base64(client_id:client_secret)Content-Type: application/x-www-form-urlencoded
grant_type=client_credentialsGET https://cloud-api.prevu3d.com/oauth/api-infoAuthorization: Bearer {access_token}2단계 — CSV에서 에셋 생성
섹션 제목: “2단계 — CSV에서 에셋 생성”POST {api_url}/v1/twin/{twinId}/assetsAuthorization: Bearer {access_token}Content-Type: application/json
{ "name": "Pump A", "workingStructure": { "boxes": [ { "center": { "x": 6.27, "y": 187.12, "z": -5.10 }, "size": { "x": 0.35, "y": 0.33, "z": 0.64 }, "rotation": { "x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0 } } ] }}성공적인 응답은 id를 포함한 생성된 에셋을 반환합니다. 각 CSV 행에 대해 반복하세요.
전체 예제
섹션 제목: “전체 예제”import base64import csvfrom pathlib import Path
import requests
CLIENT_ID = "your-client-id"CLIENT_SECRET = "your-client-secret"CLOUD_API_BASE = "https://cloud-api.prevu3d.com"TWIN_ID = "your-twin-id"CSV_FILE = Path("assets.csv")
credentials = base64.b64encode(f"{CLIENT_ID}:{CLIENT_SECRET}".encode()).decode()token_response = requests.post( f"{CLOUD_API_BASE}/oauth/token", data={"grant_type": "client_credentials"}, headers={"Authorization": f"Basic {credentials}"},)token_response.raise_for_status()access_token = token_response.json()["access_token"]headers = {"Authorization": f"Bearer {access_token}"}
api_info = requests.get(f"{CLOUD_API_BASE}/oauth/api-info", headers=headers).json()api_url = api_info["apiUrl"].rstrip("/")
def api_post(path: str, body: dict) -> dict: response = requests.post(f"{api_url}{path}", json=body, headers=headers) response.raise_for_status() return response.json()
def oriented_box(cx: float, cy: float, cz: float, sx: float, sy: float, sz: float) -> dict: return { "center": {"x": cx, "y": cy, "z": cz}, "size": {"x": sx, "y": sy, "z": sz}, "rotation": {"x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0}, }
with CSV_FILE.open(newline="", encoding="utf-8") as handle: rows = list(csv.DictReader(handle))
created = []errors = []
for row in rows: name = row["Description"].strip() body = { "name": name, "workingStructure": { "boxes": [ oriented_box( cx=float(row["Manual_X"]), cy=float(row["Manual_Y"]), cz=float(row["Manual_Z"]), sx=float(row["Manual_Box_X"]), sy=float(row["Manual_Box_Y"]), sz=float(row["Manual_Box_Z"]), ) ] }, }
try: asset = api_post(f"/v1/twin/{TWIN_ID}/assets", body) print(f"[OK] {name} -> {asset['id']}") created.append(asset) except requests.HTTPError as error: print(f"[ERR] {name} -> {error.response.status_code} {error.response.text}") errors.append(name)
print(f"\nCreated: {len(created)} / Errors: {len(errors)}")트윈 ID 찾기
섹션 제목: “트윈 ID 찾기”트윈 ID는 콘텐츠 계층 구조에서 트윈 노드의 UUID입니다. 다음과 같이 할 수 있습니다.
- 트윈이 열려 있을 때 RealityPlatform URL에서 복사
GET /v1/nodes/{organizationId}/browse로 계층 구조를 탐색하여type: "Twin"인 노드를 찾기
대규모 가져오기를 위한 팁
섹션 제목: “대규모 가져오기를 위한 팁”- 책임감 있게 일괄 처리하세요. API는 요청당 하나의 에셋을 생성합니다. 수백 개의 행에 대해서는 속도 제한에 도달하면 짧은 지연이나 백오프를 추가하세요.
- 좌표를 먼저 검증하세요. 전체 파일을 실행하기 전에 단일 테스트 행을 가져오세요.
- 다른 사용자가 보기 전에 에셋을 검토하려면 RealityTwin의 초안 모드를 사용하세요. API를 통해 생성된 에셋은 통합이 초안 워크플로를 대상으로 하지 않는 한 트윈에 즉시 나타납니다.
- 메타데이터는 나중에 첨부하세요. 생성 후
PATCH /v1/twin/{twinId}/assets/{assetId}/metadata를 사용하여 속성 값을 추가하세요. API 참조의 에셋 엔드포인트를 참조하세요.
다음 단계
섹션 제목: “다음 단계”- Client Credentials 플로우 가이드에서 인증을 설정하세요.
- 트윈 워크스페이스에서 에셋이 작동하는 방식을 알아보세요: RealityAsset 작업.
- API 참조에서 에셋 엔드포인트를 살펴보세요.