콘텐츠로 이동

CSV에서 에셋 대량 가져오기

이 가이드에서는 CSV 파일에서 트윈에 RealityAsset을 대량으로 생성하는 방법을 보여줍니다. 각 행은 에셋 이름과 트윈 공간의 방향이 지정된 경계 상자를 정의합니다. 이 워크플로는 Client Credentials 플로우write:asset 스코프를 사용합니다.


  • Client Credentials로 구성된 OAuth 애플리케이션
  • 스코프: read:basic, read:hierarchy, write:asset
  • client_idclient_secret
  • 대상 트윈에 대한 콘텐츠 접근 및 편집 권한
  • 에셋을 생성할 트윈 ID

Prevu3D 외부에 이미 에셋 정의가 있는 경우 CSV 기반 가져오기를 사용하세요. 예:

  • 3D 좌표가 포함된 CMMS 또는 ERP 시스템에서 내보낸 장비 목록
  • 외부 도구의 측량 또는 태그 지정 결과
  • 에셋이 트윈 좌표에 배치된 다른 플랫폼에서의 마이그레이션

각 API 호출은 하나의 에셋을 생성합니다. 스크립트가 CSV 행을 반복하며 각 항목에 대해 POST /v1/twin/{twinId}/assets를 호출합니다.

스프레드시트에는 헤더 행이 포함되어야 합니다. 필수 열:

매핑 대상설명
Description에셋 nameRealityAsset의 표시 이름
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_Y
Pump A,6.27,-5.10,187.12,0.35,0.64,0.33
Valve 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에서 유형이 정의되는 방법은 에셋 유형을 참조하세요.

Client Credentials로 액세스 토큰을 획득합니다.

POST https://cloud-api.prevu3d.com/oauth/token
Authorization: Basic base64(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
GET https://cloud-api.prevu3d.com/oauth/api-info
Authorization: Bearer {access_token}
POST {api_url}/v1/twin/{twinId}/assets
Authorization: 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 base64
import csv
from 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는 콘텐츠 계층 구조에서 트윈 노드의 UUID입니다. 다음과 같이 할 수 있습니다.

  • 트윈이 열려 있을 때 RealityPlatform URL에서 복사
  • GET /v1/nodes/{organizationId}/browse로 계층 구조를 탐색하여 type: "Twin"인 노드를 찾기
  • 책임감 있게 일괄 처리하세요. API는 요청당 하나의 에셋을 생성합니다. 수백 개의 행에 대해서는 속도 제한에 도달하면 짧은 지연이나 백오프를 추가하세요.
  • 좌표를 먼저 검증하세요. 전체 파일을 실행하기 전에 단일 테스트 행을 가져오세요.
  • 다른 사용자가 보기 전에 에셋을 검토하려면 RealityTwin의 초안 모드를 사용하세요. API를 통해 생성된 에셋은 통합이 초안 워크플로를 대상으로 하지 않는 한 트윈에 즉시 나타납니다.
  • 메타데이터는 나중에 첨부하세요. 생성 후 PATCH /v1/twin/{twinId}/assets/{assetId}/metadata를 사용하여 속성 값을 추가하세요. API 참조의 에셋 엔드포인트를 참조하세요.