@things-factory/board-import 10.0.0-beta.71 → 10.0.0-beta.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-server/index.d.ts +1 -1
- package/dist-server/index.js +1 -1
- package/dist-server/index.js.map +1 -1
- package/dist-server/service/adapters/dxf-adapter.d.ts +1 -1
- package/dist-server/service/adapters/dxf-adapter.js +18 -4
- package/dist-server/service/adapters/dxf-adapter.js.map +1 -1
- package/dist-server/service/adapters/image-adapter.d.ts +32 -0
- package/dist-server/service/adapters/image-adapter.js +420 -0
- package/dist-server/service/adapters/image-adapter.js.map +1 -0
- package/dist-server/service/ai/types.d.ts +96 -4
- package/dist-server/service/ai/types.js +221 -12
- package/dist-server/service/ai/types.js.map +1 -1
- package/dist-server/service/converters/generic-to.d.ts +37 -8
- package/dist-server/service/converters/generic-to.js +60 -44
- package/dist-server/service/converters/generic-to.js.map +1 -1
- package/dist-server/service/import-session/import-actions.d.ts +79 -0
- package/dist-server/service/import-session/import-actions.js +98 -0
- package/dist-server/service/import-session/import-actions.js.map +1 -0
- package/dist-server/service/import-session/import-session-resolver.d.ts +22 -1
- package/dist-server/service/import-session/import-session-resolver.js +166 -38
- package/dist-server/service/import-session/import-session-resolver.js.map +1 -1
- package/dist-server/service/import-session/import-worker.js +55 -13
- package/dist-server/service/import-session/import-worker.js.map +1 -1
- package/dist-server/service/import-session/index.d.ts +5 -3
- package/dist-server/service/import-session/index.js +16 -9
- package/dist-server/service/import-session/index.js.map +1 -1
- package/dist-server/service/import-session/materialize-from-session.d.ts +66 -0
- package/dist-server/service/import-session/materialize-from-session.js +104 -0
- package/dist-server/service/import-session/materialize-from-session.js.map +1 -0
- package/dist-server/service/import-session/suggest-board-name.d.ts +80 -0
- package/dist-server/service/import-session/suggest-board-name.js +195 -0
- package/dist-server/service/import-session/suggest-board-name.js.map +1 -0
- package/dist-server/service/import-tools.d.ts +10 -0
- package/dist-server/service/import-tools.js +227 -0
- package/dist-server/service/import-tools.js.map +1 -0
- package/dist-server/service/index.d.ts +22 -19
- package/dist-server/service/index.js +47 -36
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/pipeline/index.d.ts +42 -9
- package/dist-server/service/pipeline/index.js +92 -23
- package/dist-server/service/pipeline/index.js.map +1 -1
- package/dist-server/service/pipeline/stage2-mapping.d.ts +20 -5
- package/dist-server/service/pipeline/stage2-mapping.js +84 -26
- package/dist-server/service/pipeline/stage2-mapping.js.map +1 -1
- package/dist-server/service/pipeline/stage3-board.d.ts +2 -2
- package/dist-server/service/pipeline/stage3-board.js +65 -10
- package/dist-server/service/pipeline/stage3-board.js.map +1 -1
- package/dist-server/service/pipeline/stage4-binding.d.ts +1 -1
- package/dist-server/service/pipeline/stage4-binding.js +2 -2
- package/dist-server/service/pipeline/stage4-binding.js.map +1 -1
- package/dist-server/service/registry/index.d.ts +1 -1
- package/dist-server/service/registry/index.js.map +1 -1
- package/dist-server/service/types/index.d.ts +35 -0
- package/dist-server/service/types/index.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -6
- package/server/index.ts +1 -1
- package/server/service/adapters/dxf-adapter.ts +17 -4
- package/server/service/adapters/image-adapter.test.ts +545 -0
- package/server/service/adapters/image-adapter.ts +464 -0
- package/server/service/ai/types.ts +354 -19
- package/server/service/converters/generic-to.test.ts +145 -0
- package/server/service/converters/generic-to.ts +114 -45
- package/server/service/import-session/import-actions.test.ts +185 -0
- package/server/service/import-session/import-actions.ts +164 -0
- package/server/service/import-session/import-session-resolver.ts +171 -39
- package/server/service/import-session/import-worker.ts +56 -12
- package/server/service/import-session/index.ts +19 -3
- package/server/service/import-session/materialize-from-session.test.ts +274 -0
- package/server/service/import-session/materialize-from-session.ts +158 -0
- package/server/service/import-session/suggest-board-name.test.ts +271 -0
- package/server/service/import-session/suggest-board-name.ts +279 -0
- package/server/service/import-tools.test.ts +137 -0
- package/server/service/import-tools.ts +255 -0
- package/server/service/index.ts +36 -18
- package/server/service/pipeline/index.ts +118 -23
- package/server/service/pipeline/stage2-mapping.test.ts +204 -0
- package/server/service/pipeline/stage2-mapping.ts +102 -27
- package/server/service/pipeline/stage3-board.test.ts +133 -0
- package/server/service/pipeline/stage3-board.ts +76 -11
- package/server/service/pipeline/stage4-binding.ts +2 -2
- package/server/service/registry/index.ts +1 -1
- package/server/service/types/index.ts +36 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage 3 — assembleBoard 의 컴포넌트 root 외곽 spill 방지 회귀 테스트.
|
|
3
|
+
*
|
|
4
|
+
* 검증 포인트:
|
|
5
|
+
* - bbox 가 컴포넌트 position+size 보다 작아도 board 가 그것 cover
|
|
6
|
+
* - normalizeOrigin + flipY 조합에서 컴포넌트 음수 좌표 회피 (root 위쪽 spill 방지)
|
|
7
|
+
* - padding 으로 컴포넌트가 root 가장자리에 붙지 않음
|
|
8
|
+
* - 빈 board 는 1000x1000 fallback
|
|
9
|
+
*/
|
|
10
|
+
import { assembleBoard } from './stage3-board'
|
|
11
|
+
import type { ComponentDraft } from '../types/registry'
|
|
12
|
+
import type { BoundingBox, UniversalEntity } from '../types/index'
|
|
13
|
+
|
|
14
|
+
function entity(uid: string, x: number, y: number, w: number, h: number): UniversalEntity {
|
|
15
|
+
return {
|
|
16
|
+
uid,
|
|
17
|
+
kind: 'shape',
|
|
18
|
+
position: { x, y },
|
|
19
|
+
size: { width: w, height: h },
|
|
20
|
+
bbox: { min: { x, y }, max: { x: x + w, y: y + h } },
|
|
21
|
+
attribs: {}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function draft(src: UniversalEntity): ComponentDraft {
|
|
26
|
+
return {
|
|
27
|
+
category: 'unknown',
|
|
28
|
+
type: 'placeholder',
|
|
29
|
+
id: src.uid,
|
|
30
|
+
state: {},
|
|
31
|
+
source: src
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe('assembleBoard — board 크기 산정', () => {
|
|
36
|
+
test('컴포넌트 모두 root 안 — left/top 모두 0 이상, right/bottom 모두 board 크기 이하', () => {
|
|
37
|
+
const drafts = [draft(entity('a', 0, 0, 100, 80)), draft(entity('b', 200, 100, 60, 60))]
|
|
38
|
+
const bbox: BoundingBox = { min: { x: 0, y: 0 }, max: { x: 260, y: 160 } }
|
|
39
|
+
const board = assembleBoard(drafts, bbox, { normalizeOrigin: true, flipY: false, scale: 1 })
|
|
40
|
+
|
|
41
|
+
for (const c of board.components ?? []) {
|
|
42
|
+
expect(c.left).toBeGreaterThanOrEqual(0)
|
|
43
|
+
expect(c.top).toBeGreaterThanOrEqual(0)
|
|
44
|
+
expect(c.left + c.width).toBeLessThanOrEqual(board.width!)
|
|
45
|
+
expect(c.top + c.height).toBeLessThanOrEqual(board.height!)
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test('bbox 가 컴포넌트 size 보다 작아도 board 가 컴포넌트 fully cover', () => {
|
|
50
|
+
// 의도적으로 bbox 를 entity 보다 작게 — VLM 이 lossy bbox 줬을 때 시뮬레이션
|
|
51
|
+
const drafts = [draft(entity('a', 0, 0, 500, 400))]
|
|
52
|
+
const tightBbox: BoundingBox = { min: { x: 0, y: 0 }, max: { x: 100, y: 100 } }
|
|
53
|
+
const board = assembleBoard(drafts, tightBbox, {
|
|
54
|
+
normalizeOrigin: true,
|
|
55
|
+
flipY: false,
|
|
56
|
+
scale: 1
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const c = board.components![0]
|
|
60
|
+
expect(c.left + c.width).toBeLessThanOrEqual(board.width!)
|
|
61
|
+
expect(c.top + c.height).toBeLessThanOrEqual(board.height!)
|
|
62
|
+
// board 는 컴포넌트 (500x400) + padding 2개 = 580 / 480 이상이어야 함
|
|
63
|
+
expect(board.width!).toBeGreaterThanOrEqual(500)
|
|
64
|
+
expect(board.height!).toBeGreaterThanOrEqual(400)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test('flipY=true 일 때 모든 컴포넌트 top 이 0 이상 (root 위쪽 spill 방지)', () => {
|
|
68
|
+
const drafts = [
|
|
69
|
+
draft(entity('a', 0, 0, 100, 100)),
|
|
70
|
+
draft(entity('b', 50, 50, 100, 100)),
|
|
71
|
+
draft(entity('c', 100, 200, 100, 100))
|
|
72
|
+
]
|
|
73
|
+
const bbox: BoundingBox = { min: { x: 0, y: 0 }, max: { x: 200, y: 300 } }
|
|
74
|
+
const board = assembleBoard(drafts, bbox, { normalizeOrigin: true, flipY: true, scale: 1 })
|
|
75
|
+
|
|
76
|
+
for (const c of board.components ?? []) {
|
|
77
|
+
expect(c.top).toBeGreaterThanOrEqual(0)
|
|
78
|
+
expect(c.top + c.height).toBeLessThanOrEqual(board.height!)
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test('빈 drafts → board 1000x1000 fallback', () => {
|
|
83
|
+
const bbox: BoundingBox = { min: { x: 0, y: 0 }, max: { x: 0, y: 0 } }
|
|
84
|
+
const board = assembleBoard([], bbox, { normalizeOrigin: true, flipY: true, scale: 1 })
|
|
85
|
+
// 0 + padding 80 < 1000 fallback
|
|
86
|
+
expect(board.width).toBe(1000)
|
|
87
|
+
expect(board.height).toBe(1000)
|
|
88
|
+
expect(board.components).toEqual([])
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
test('padding 적용 — 컴포넌트 가장자리에 정확히 맞닿지 않고 약간의 여백', () => {
|
|
92
|
+
const drafts = [draft(entity('a', 0, 0, 100, 80))]
|
|
93
|
+
const bbox: BoundingBox = { min: { x: 0, y: 0 }, max: { x: 100, y: 80 } }
|
|
94
|
+
const board = assembleBoard(drafts, bbox, { normalizeOrigin: true, flipY: false, scale: 1 })
|
|
95
|
+
|
|
96
|
+
const c = board.components![0]
|
|
97
|
+
// 가장자리에 정확히 0 이 아니라 padding 만큼 안쪽
|
|
98
|
+
expect(c.left).toBeGreaterThan(0)
|
|
99
|
+
expect(c.top).toBeGreaterThan(0)
|
|
100
|
+
// 우측/하단도 padding 만큼 여유
|
|
101
|
+
expect(c.left + c.width).toBeLessThan(board.width!)
|
|
102
|
+
expect(c.top + c.height).toBeLessThan(board.height!)
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
test('normalizeOrigin=true 일 때 음수 entity 좌표도 root 안으로 끌어올림', () => {
|
|
106
|
+
// entity 가 음수 좌표 (e.g. CAD 의 임의 원점) — bbox 가 정확하면 normalizeOrigin 으로
|
|
107
|
+
// 0 이상으로 올려야 함.
|
|
108
|
+
const drafts = [draft(entity('a', -100, -50, 100, 100))]
|
|
109
|
+
const bbox: BoundingBox = { min: { x: -100, y: -50 }, max: { x: 0, y: 50 } }
|
|
110
|
+
const board = assembleBoard(drafts, bbox, { normalizeOrigin: true, flipY: false, scale: 1 })
|
|
111
|
+
|
|
112
|
+
const c = board.components![0]
|
|
113
|
+
expect(c.left).toBeGreaterThanOrEqual(0)
|
|
114
|
+
expect(c.top).toBeGreaterThanOrEqual(0)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
test('scale 적용 — 모든 좌표/크기가 비율대로', () => {
|
|
118
|
+
const drafts = [draft(entity('a', 10, 20, 100, 80))]
|
|
119
|
+
const bbox: BoundingBox = { min: { x: 0, y: 0 }, max: { x: 200, y: 200 } }
|
|
120
|
+
const board = assembleBoard(drafts, bbox, {
|
|
121
|
+
normalizeOrigin: true,
|
|
122
|
+
flipY: false,
|
|
123
|
+
scale: 0.5
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
const c = board.components![0]
|
|
127
|
+
// scale=0.5 적용
|
|
128
|
+
expect(c.width).toBe(50)
|
|
129
|
+
expect(c.height).toBe(40)
|
|
130
|
+
// padding 은 scale 무관 (40 unit)
|
|
131
|
+
expect(c.left).toBe(10 * 0.5 + 40)
|
|
132
|
+
})
|
|
133
|
+
})
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Stage 3 — ComponentDraft → Board Model JSON.
|
|
3
3
|
* 좌표/단위 변환 + 3D Preset 적용.
|
|
4
4
|
*/
|
|
5
|
-
import { find3DPreset } from '../registry/index
|
|
6
|
-
import type { BoundingBox } from '../types/index
|
|
7
|
-
import type { ComponentCategory, ComponentDraft } from '../types/registry
|
|
5
|
+
import { find3DPreset } from '../registry/index'
|
|
6
|
+
import type { BoundingBox } from '../types/index'
|
|
7
|
+
import type { ComponentCategory, ComponentDraft } from '../types/registry'
|
|
8
8
|
|
|
9
9
|
export interface BoardModel {
|
|
10
10
|
width?: number
|
|
@@ -58,6 +58,18 @@ export interface AssembleOptions {
|
|
|
58
58
|
importMeta?: BoardModel['importMeta']
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* 보드 외곽 padding (양쪽). 컴포넌트가 root 가장자리에 정확히 맞닿지 않도록 살짝 여백.
|
|
63
|
+
* 너무 크면 빈 공간 낭비, 너무 작으면 시각적으로 갑갑함 → 40 unit.
|
|
64
|
+
*/
|
|
65
|
+
const BOARD_PADDING = 40
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 빈 보드 / 너무 작은 컨텐츠일 때 fallback 크기.
|
|
69
|
+
* 최소 1000x1000 — things-scene 의 RootContainer 기본 크기에 맞춤.
|
|
70
|
+
*/
|
|
71
|
+
const MIN_BOARD_SIZE = 1000
|
|
72
|
+
|
|
61
73
|
export function assembleBoard(
|
|
62
74
|
drafts: ComponentDraft[],
|
|
63
75
|
bbox: BoundingBox,
|
|
@@ -67,16 +79,69 @@ export function assembleBoard(
|
|
|
67
79
|
const offsetX = options.normalizeOrigin ? -bbox.min.x : 0
|
|
68
80
|
const offsetY = options.normalizeOrigin ? -bbox.min.y : 0
|
|
69
81
|
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
// 1단계: bbox 기반 가설 board 크기. 그러나 entity bbox 와 position+size 가 어긋나는 경우
|
|
83
|
+
// 컴포넌트가 root 외곽으로 spill 할 수 있어 2단계에서 컴포넌트 실제 edge 로 보정한다.
|
|
84
|
+
let boardWidth = (bbox.max.x - bbox.min.x) * scale
|
|
85
|
+
let boardHeight = (bbox.max.y - bbox.min.y) * scale
|
|
72
86
|
|
|
73
|
-
|
|
87
|
+
// 1.5단계: 컴포넌트 layout 1차 (flipY 미적용 — boardHeight 확정 전이라 미루기).
|
|
88
|
+
type Layout = {
|
|
89
|
+
d: ComponentDraft
|
|
90
|
+
src: ComponentDraft['source']
|
|
91
|
+
left: number
|
|
92
|
+
rawTop: number
|
|
93
|
+
width: number
|
|
94
|
+
height: number
|
|
95
|
+
}
|
|
96
|
+
const layouts: Layout[] = drafts.map(d => {
|
|
74
97
|
const src = d.source
|
|
75
98
|
const left = src ? (src.position.x + offsetX) * scale : 0
|
|
76
99
|
const rawTop = src ? (src.position.y + offsetY) * scale : 0
|
|
77
|
-
const top = options.flipY ? boardHeight - rawTop - (src?.size?.height ?? 0) * scale : rawTop
|
|
78
100
|
const width = (src?.size?.width ?? 1) * scale
|
|
79
101
|
const height = (src?.size?.height ?? 1) * scale
|
|
102
|
+
return { d, src, left, rawTop, width, height }
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
// 2단계: 컴포넌트 실제 edge 로 board 크기 보정. bbox 보다 컴포넌트 right/bottom 이
|
|
106
|
+
// 크면 그것 기준. 모든 컴포넌트 left/top 도 음수 안 되도록 0 이상 보장 (있으면 offset 보정).
|
|
107
|
+
let computedRight = 0
|
|
108
|
+
let computedBottom = 0
|
|
109
|
+
let computedMinLeft = 0
|
|
110
|
+
let computedMinTop = 0
|
|
111
|
+
for (const l of layouts) {
|
|
112
|
+
if (l.left < computedMinLeft) computedMinLeft = l.left
|
|
113
|
+
if (l.rawTop < computedMinTop) computedMinTop = l.rawTop
|
|
114
|
+
if (l.left + l.width > computedRight) computedRight = l.left + l.width
|
|
115
|
+
if (l.rawTop + l.height > computedBottom) computedBottom = l.rawTop + l.height
|
|
116
|
+
}
|
|
117
|
+
// 음수 left/top 이 있으면 추가 offset 으로 0 으로 끌어올림.
|
|
118
|
+
const extraOffsetX = computedMinLeft < 0 ? -computedMinLeft : 0
|
|
119
|
+
const extraOffsetY = computedMinTop < 0 ? -computedMinTop : 0
|
|
120
|
+
if (extraOffsetX || extraOffsetY) {
|
|
121
|
+
for (const l of layouts) {
|
|
122
|
+
l.left += extraOffsetX
|
|
123
|
+
l.rawTop += extraOffsetY
|
|
124
|
+
}
|
|
125
|
+
computedRight += extraOffsetX
|
|
126
|
+
computedBottom += extraOffsetY
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// 최종 board 크기 — bbox 와 컴포넌트 실제 max edge 중 큰 값 + padding.
|
|
130
|
+
// 컴포넌트 없으면 padding 의미 없고, fallback 으로 MIN_BOARD_SIZE.
|
|
131
|
+
boardWidth = Math.max(boardWidth, computedRight)
|
|
132
|
+
boardHeight = Math.max(boardHeight, computedBottom)
|
|
133
|
+
if (layouts.length > 0) {
|
|
134
|
+
boardWidth += BOARD_PADDING * 2
|
|
135
|
+
boardHeight += BOARD_PADDING * 2
|
|
136
|
+
}
|
|
137
|
+
boardWidth = Math.max(boardWidth, MIN_BOARD_SIZE)
|
|
138
|
+
boardHeight = Math.max(boardHeight, MIN_BOARD_SIZE)
|
|
139
|
+
|
|
140
|
+
// 3단계: padding 만큼 모든 컴포넌트 안쪽으로 평행이동 + flipY 적용.
|
|
141
|
+
const components: BoardComponent[] = layouts.map(({ d, src, left, rawTop, width, height }) => {
|
|
142
|
+
const finalLeft = left + BOARD_PADDING
|
|
143
|
+
const finalRawTop = rawTop + BOARD_PADDING
|
|
144
|
+
const finalTop = options.flipY ? boardHeight - finalRawTop - height : finalRawTop
|
|
80
145
|
const rotation = src?.rotation
|
|
81
146
|
|
|
82
147
|
const preset = find3DPreset(d.type, d.category, options.scopes)
|
|
@@ -86,8 +151,8 @@ export function assembleBoard(
|
|
|
86
151
|
category: d.category,
|
|
87
152
|
type: d.type,
|
|
88
153
|
id: d.id,
|
|
89
|
-
left,
|
|
90
|
-
top,
|
|
154
|
+
left: finalLeft,
|
|
155
|
+
top: finalTop,
|
|
91
156
|
width,
|
|
92
157
|
height,
|
|
93
158
|
...(rotation !== undefined && { rotation: options.flipY ? -rotation : rotation }),
|
|
@@ -97,8 +162,8 @@ export function assembleBoard(
|
|
|
97
162
|
})
|
|
98
163
|
|
|
99
164
|
return {
|
|
100
|
-
width: boardWidth
|
|
101
|
-
height: boardHeight
|
|
165
|
+
width: boardWidth,
|
|
166
|
+
height: boardHeight,
|
|
102
167
|
fillStyle: options.backgroundColor ?? '#ffffff',
|
|
103
168
|
components,
|
|
104
169
|
importMeta: options.importMeta
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Stage 4 — 보드 모델에 데이터 바인딩 자동 설정.
|
|
3
3
|
* 컴포넌트 type 에 등록된 SubscriptionRule 을 찾아 subscriptionTag 등 부여.
|
|
4
4
|
*/
|
|
5
|
-
import { findSubscriptionRule } from '../registry/index
|
|
6
|
-
import type { BoardComponent, BoardModel } from './stage3-board
|
|
5
|
+
import { findSubscriptionRule } from '../registry/index'
|
|
6
|
+
import type { BoardComponent, BoardModel } from './stage3-board'
|
|
7
7
|
|
|
8
8
|
export interface BindingOptions {
|
|
9
9
|
scopes?: string[]
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* 백엔드 단일 프로세스 안에서 in-memory 로 유지된다. 모듈 부트스트랩 시 등록.
|
|
6
6
|
*/
|
|
7
|
-
import type { ComponentCategory, ImportRule, SubscriptionRule, ThreeDPreset } from '../types/registry
|
|
7
|
+
import type { ComponentCategory, ImportRule, SubscriptionRule, ThreeDPreset } from '../types/registry'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* 코어가 제공하는 카테고리별 기본 3D Preset.
|
|
@@ -63,6 +63,12 @@ export interface EntityAttribs {
|
|
|
63
63
|
text?: string
|
|
64
64
|
/** 도면 모양 종류 (rect/circle/polyline 등) */
|
|
65
65
|
shape?: 'rect' | 'circle' | 'polyline' | 'polygon'
|
|
66
|
+
/**
|
|
67
|
+
* 카테고리 힌트 — AI 분류기 / 매처가 구체 type 까지는 못 정해도 카테고리만 줄 때 사용.
|
|
68
|
+
* Stage2 매핑이 ImportRule 매치에 실패하면 이 값을 보고 카테고리별 generic-* placeholder
|
|
69
|
+
* 로 폴백한다 (`MappingOptions.categoryFallback`).
|
|
70
|
+
*/
|
|
71
|
+
categoryHint?: import('./registry').ComponentCategory
|
|
66
72
|
/** 임의 추가 속성 */
|
|
67
73
|
[k: string]: any
|
|
68
74
|
}
|
|
@@ -75,6 +81,10 @@ export interface EntityRelation {
|
|
|
75
81
|
|
|
76
82
|
/**
|
|
77
83
|
* Adapter 결과 — 정규화된 entity 목록 + 메타데이터.
|
|
84
|
+
*
|
|
85
|
+
* 단일 변형이 default. AI/VLM 어댑터는 추가로 `variants` (다중 시안) 를 줄 수 있음 —
|
|
86
|
+
* 같은 도면을 다르게 해석한 후보들. 사용자가 review 단계에서 선택. variants[0] 와
|
|
87
|
+
* 최상위 entities 는 동일 (default 시안).
|
|
78
88
|
*/
|
|
79
89
|
export interface ParseResult {
|
|
80
90
|
entities: UniversalEntity[]
|
|
@@ -82,6 +92,32 @@ export interface ParseResult {
|
|
|
82
92
|
bbox: BoundingBox
|
|
83
93
|
/** 도면 단위 (mm/m/inch 등). 명시되지 않으면 'unknown' */
|
|
84
94
|
units?: 'mm' | 'cm' | 'm' | 'inch' | 'unknown'
|
|
95
|
+
/**
|
|
96
|
+
* 다중 시안 (AI 가 같은 도면을 다른 관점으로 해석). 미지정 시 단일 변형 (default 만).
|
|
97
|
+
* 각 시안은 자기 entities + 자기 subjectName/Description + 자기 importStrategy.
|
|
98
|
+
*/
|
|
99
|
+
variants?: ParseVariant[]
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* AI 가 제공하는 다중 해석 시안 — 같은 도면, 다른 관점/분류 전략.
|
|
104
|
+
* 예: "장비 중심" / "운송 중심" / "영역 중심" — 또는 "보수적" / "균형" / "공격적".
|
|
105
|
+
*/
|
|
106
|
+
export interface ParseVariant {
|
|
107
|
+
/** URL 친화적 short id — materialize 시 사용. */
|
|
108
|
+
id: string
|
|
109
|
+
/** 사용자에게 보여줄 한글 라벨. 예: "장비 중심", "운송 중심". */
|
|
110
|
+
label: string
|
|
111
|
+
/** 짧은 한 줄 설명 (선택) — 이 시안이 뭘 강조하는가. */
|
|
112
|
+
description?: string
|
|
113
|
+
entities: UniversalEntity[]
|
|
114
|
+
bbox?: BoundingBox
|
|
115
|
+
/** 도면 정체성 — 짧은 제목 (보드 name 추천 기반). */
|
|
116
|
+
subjectName?: string
|
|
117
|
+
/** 도면 정체성 — 1-2 문장 설명 (보드 description 추천 기반). */
|
|
118
|
+
subjectDescription?: string
|
|
119
|
+
/** AI 의 의도 narrative — 왜 이 시안을 이렇게 해석했나. review 카드 표시. */
|
|
120
|
+
importStrategy?: string
|
|
85
121
|
}
|
|
86
122
|
|
|
87
123
|
export interface AdapterMetadata {
|