@things-factory/board-import 10.0.0-beta.108
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/config/config.development.js +44 -0
- package/config/config.production.js +18 -0
- package/dist-server/index.d.ts +7 -0
- package/dist-server/index.js +11 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/service/adapters/dxf-adapter.d.ts +8 -0
- package/dist-server/service/adapters/dxf-adapter.js +220 -0
- package/dist-server/service/adapters/dxf-adapter.js.map +1 -0
- 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 +185 -0
- package/dist-server/service/ai/types.js +378 -0
- package/dist-server/service/ai/types.js.map +1 -0
- package/dist-server/service/converters/generic-to.d.ts +31 -0
- package/dist-server/service/converters/generic-to.js +84 -0
- package/dist-server/service/converters/generic-to.js.map +1 -0
- package/dist-server/service/extraction/contracts.d.ts +112 -0
- package/dist-server/service/extraction/contracts.js +3 -0
- package/dist-server/service/extraction/contracts.js.map +1 -0
- package/dist-server/service/extraction/index.d.ts +17 -0
- package/dist-server/service/extraction/index.js +62 -0
- package/dist-server/service/extraction/index.js.map +1 -0
- package/dist-server/service/extraction/label-scale-calibrator.d.ts +5 -0
- package/dist-server/service/extraction/label-scale-calibrator.js +111 -0
- package/dist-server/service/extraction/label-scale-calibrator.js.map +1 -0
- package/dist-server/service/extraction/layout-refiner.d.ts +16 -0
- package/dist-server/service/extraction/layout-refiner.js +88 -0
- package/dist-server/service/extraction/layout-refiner.js.map +1 -0
- package/dist-server/service/extraction/pipeline.d.ts +11 -0
- package/dist-server/service/extraction/pipeline.js +124 -0
- package/dist-server/service/extraction/pipeline.js.map +1 -0
- package/dist-server/service/extraction/source-router.d.ts +17 -0
- package/dist-server/service/extraction/source-router.js +40 -0
- package/dist-server/service/extraction/source-router.js.map +1 -0
- package/dist-server/service/extraction/stubs.d.ts +18 -0
- package/dist-server/service/extraction/stubs.js +38 -0
- package/dist-server/service/extraction/stubs.js.map +1 -0
- package/dist-server/service/extraction/vector-geometry.d.ts +7 -0
- package/dist-server/service/extraction/vector-geometry.js +21 -0
- package/dist-server/service/extraction/vector-geometry.js.map +1 -0
- package/dist-server/service/extraction/vlm-recognizer.d.ts +18 -0
- package/dist-server/service/extraction/vlm-recognizer.js +78 -0
- package/dist-server/service/extraction/vlm-recognizer.js.map +1 -0
- 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 +39 -0
- package/dist-server/service/import-session/import-session-resolver.js +263 -0
- package/dist-server/service/import-session/import-session-resolver.js.map +1 -0
- package/dist-server/service/import-session/import-session.d.ts +28 -0
- package/dist-server/service/import-session/import-session.js +152 -0
- package/dist-server/service/import-session/import-session.js.map +1 -0
- package/dist-server/service/import-session/import-worker.d.ts +1 -0
- package/dist-server/service/import-session/import-worker.js +121 -0
- package/dist-server/service/import-session/import-worker.js.map +1 -0
- package/dist-server/service/import-session/index.d.ts +8 -0
- package/dist-server/service/import-session/index.js +19 -0
- package/dist-server/service/import-session/index.js.map +1 -0
- 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 +26 -0
- package/dist-server/service/index.js +60 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/service/pipeline/index.d.ts +66 -0
- package/dist-server/service/pipeline/index.js +127 -0
- package/dist-server/service/pipeline/index.js.map +1 -0
- package/dist-server/service/pipeline/stage2-mapping.d.ts +29 -0
- package/dist-server/service/pipeline/stage2-mapping.js +231 -0
- package/dist-server/service/pipeline/stage2-mapping.js.map +1 -0
- package/dist-server/service/pipeline/stage3-board.d.ts +52 -0
- package/dist-server/service/pipeline/stage3-board.js +108 -0
- package/dist-server/service/pipeline/stage3-board.js.map +1 -0
- package/dist-server/service/pipeline/stage4-binding.d.ts +9 -0
- package/dist-server/service/pipeline/stage4-binding.js +28 -0
- package/dist-server/service/pipeline/stage4-binding.js.map +1 -0
- package/dist-server/service/registry/index.d.ts +27 -0
- package/dist-server/service/registry/index.js +108 -0
- package/dist-server/service/registry/index.js.map +1 -0
- package/dist-server/service/types/index.d.ts +152 -0
- package/dist-server/service/types/index.js +3 -0
- package/dist-server/service/types/index.js.map +1 -0
- package/dist-server/service/types/registry.d.ts +175 -0
- package/dist-server/service/types/registry.js +3 -0
- package/dist-server/service/types/registry.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/package.json +35 -0
- package/probe/gcp-vision-probe.mjs +114 -0
- package/probe/opencv-geometry-probe.py +98 -0
- package/server/index.ts +7 -0
- package/server/service/adapters/dxf-adapter.ts +230 -0
- 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 +619 -0
- package/server/service/converters/generic-to.test.ts +105 -0
- package/server/service/converters/generic-to.ts +121 -0
- package/server/service/extraction/contracts.ts +142 -0
- package/server/service/extraction/extraction.test.ts +374 -0
- package/server/service/extraction/index.ts +51 -0
- package/server/service/extraction/label-scale-calibrator.ts +124 -0
- package/server/service/extraction/layout-refiner.ts +104 -0
- package/server/service/extraction/pipeline.ts +163 -0
- package/server/service/extraction/source-router.ts +45 -0
- package/server/service/extraction/stubs.ts +46 -0
- package/server/service/extraction/vector-geometry.ts +26 -0
- package/server/service/extraction/vlm-recognizer.ts +87 -0
- 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 +245 -0
- package/server/service/import-session/import-session.ts +141 -0
- package/server/service/import-session/import-worker.ts +132 -0
- package/server/service/import-session/index.ts +24 -0
- 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 +117 -0
- package/server/service/pipeline/index.ts +184 -0
- package/server/service/pipeline/stage2-mapping.test.ts +204 -0
- package/server/service/pipeline/stage2-mapping.ts +270 -0
- package/server/service/pipeline/stage3-board.test.ts +133 -0
- package/server/service/pipeline/stage3-board.ts +179 -0
- package/server/service/pipeline/stage4-binding.ts +31 -0
- package/server/service/registry/index.ts +127 -0
- package/server/service/types/index.ts +169 -0
- package/server/service/types/registry.ts +186 -0
- package/things-factory.config.js +1 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* convertPlaceholderTo / attachGlbToPlaceholder — 단위 테스트.
|
|
3
|
+
*
|
|
4
|
+
* 코어 placeholder type (placeholder) + 도메인 추상 (GenericTransport 등 호출자 명시)
|
|
5
|
+
* 모두 변환 가능한지 검증. 좌표/크기/source 보존, GLB attach morph 정책 회귀 방지.
|
|
6
|
+
*/
|
|
7
|
+
import {
|
|
8
|
+
convertPlaceholderTo,
|
|
9
|
+
isPlaceholderType,
|
|
10
|
+
CORE_PLACEHOLDER_TYPES
|
|
11
|
+
} from './generic-to'
|
|
12
|
+
import { GENERIC_OBJECT_TYPE } from '../pipeline/stage2-mapping'
|
|
13
|
+
|
|
14
|
+
// 호출자가 도메인 추상까지 인정하는 경우의 fixtures.
|
|
15
|
+
const EXTRA = ['GenericTransport', 'GenericFacility'] as const
|
|
16
|
+
|
|
17
|
+
// ── 계약 어설션 ─────────────────────────────────────────────────────
|
|
18
|
+
// things-scene 의 CORE_PLACEHOLDER_TYPES 와 mirror. client/server 경계로
|
|
19
|
+
// 직접 import 불가 — 이 테스트가 양쪽 값 일치를 보증.
|
|
20
|
+
describe('CORE_PLACEHOLDER_TYPES contract', () => {
|
|
21
|
+
test('GENERIC_OBJECT_TYPE 은 반드시 placeholder 고정', () => {
|
|
22
|
+
expect(GENERIC_OBJECT_TYPE).toBe('placeholder')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('CORE_PLACEHOLDER_TYPES 는 [placeholder] 고정 — things-scene 과 동기화', () => {
|
|
26
|
+
expect(Array.from(CORE_PLACEHOLDER_TYPES)).toEqual(['placeholder'])
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
describe('isPlaceholderType', () => {
|
|
31
|
+
test('코어 type 들은 인정', () => {
|
|
32
|
+
for (const t of CORE_PLACEHOLDER_TYPES) {
|
|
33
|
+
expect(isPlaceholderType(t)).toBe(true)
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test('extra list 의 도메인 추상도 인정', () => {
|
|
38
|
+
expect(isPlaceholderType('GenericTransport', EXTRA)).toBe(true)
|
|
39
|
+
expect(isPlaceholderType('GenericFacility', EXTRA)).toBe(true)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
test('미등록 type 은 거부', () => {
|
|
43
|
+
expect(isPlaceholderType('Stocker')).toBe(false)
|
|
44
|
+
expect(isPlaceholderType(undefined)).toBe(false)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('extra 미지정 시 도메인 추상 거부', () => {
|
|
48
|
+
expect(isPlaceholderType('GenericTransport')).toBe(false)
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe('convertPlaceholderTo', () => {
|
|
53
|
+
const base = {
|
|
54
|
+
type: 'placeholder',
|
|
55
|
+
id: 'src-1',
|
|
56
|
+
left: 100,
|
|
57
|
+
top: 200,
|
|
58
|
+
width: 80,
|
|
59
|
+
height: 60,
|
|
60
|
+
rotation: 0.5,
|
|
61
|
+
fillStyle: 'rgba(180,180,180,0.18)',
|
|
62
|
+
placeholderLabel: 'maybe stocker',
|
|
63
|
+
placeholderHint: 'STK_001'
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
test('placeholder 가 아닌 type 은 throw', () => {
|
|
67
|
+
expect(() =>
|
|
68
|
+
convertPlaceholderTo({ ...base, type: 'rect' } as any, 'Stocker')
|
|
69
|
+
).toThrow(/not a generic placeholder/)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
test('좌표/크기/회전/id 보존', () => {
|
|
73
|
+
const r = convertPlaceholderTo(base as any, 'Stocker') as any
|
|
74
|
+
expect(r.left).toBe(100)
|
|
75
|
+
expect(r.top).toBe(200)
|
|
76
|
+
expect(r.width).toBe(80)
|
|
77
|
+
expect(r.height).toBe(60)
|
|
78
|
+
expect(r.rotation).toBe(0.5)
|
|
79
|
+
expect(r.id).toBe('src-1')
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test('새 type 으로 변환 + category=unknown (rule 미등록)', () => {
|
|
83
|
+
const r = convertPlaceholderTo(base as any, 'Stocker') as any
|
|
84
|
+
expect(r.type).toBe('Stocker')
|
|
85
|
+
expect(r.category).toBe('unknown')
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
test('placeholder 시각 메타 (fillStyle / placeholderLabel) 는 제거', () => {
|
|
89
|
+
const r = convertPlaceholderTo(base as any, 'Stocker') as any
|
|
90
|
+
expect(r.fillStyle).toBeUndefined()
|
|
91
|
+
expect(r.placeholderLabel).toBeUndefined()
|
|
92
|
+
expect(r.placeholderHint).toBeUndefined()
|
|
93
|
+
expect(r.convertedFrom).toBeUndefined()
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
test('도메인 추상 (extraPlaceholderTypes 명시) 도 변환 가능', () => {
|
|
97
|
+
const transport = { ...base, type: 'GenericTransport', id: 'tx-1' }
|
|
98
|
+
const r = convertPlaceholderTo(transport as any, 'Forklift', {
|
|
99
|
+
extraPlaceholderTypes: ['GenericTransport']
|
|
100
|
+
}) as any
|
|
101
|
+
expect(r.type).toBe('Forklift')
|
|
102
|
+
expect(r.convertedFrom).toBeUndefined()
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic placeholder → 도메인 컴포넌트 변환.
|
|
3
|
+
*
|
|
4
|
+
* Import 시 매칭되지 않은 entity 는 `placeholder` 타입으로 보드에 배치된다.
|
|
5
|
+
* 사용자가 사후에 모델러 UI 에서 "Convert to ..." 액션으로 도메인 컴포넌트로 변환.
|
|
6
|
+
*
|
|
7
|
+
* 아키텍처 원칙:
|
|
8
|
+
* - `placeholder` — 도메인 비종속 임시 추상. 다른 type 으로 변환하는 기능만.
|
|
9
|
+
* GLB 지원 없음 (GltfComponent mixin 제거됨).
|
|
10
|
+
* - 도메인 generic 추상 (GenericTransport, GenericFacility 등) — 영구 도메인 추상.
|
|
11
|
+
* GLB 바디를 직접 채우는 방식으로 사용. 변환 대상 아님.
|
|
12
|
+
*
|
|
13
|
+
* 변환 시:
|
|
14
|
+
* - 좌표/크기/회전 보존
|
|
15
|
+
* - source (원본 entity attribs) 보존
|
|
16
|
+
* - 등록된 ImportRule.build 의 defaultState / idStrategy 적용
|
|
17
|
+
*/
|
|
18
|
+
import { find3DPreset, getImportRules } from '../registry/index'
|
|
19
|
+
import type { BoardComponent } from '../pipeline/stage3-board'
|
|
20
|
+
import type { ComponentCategory } from '../types/registry'
|
|
21
|
+
import { GENERIC_OBJECT_TYPE } from '../pipeline/stage2-mapping'
|
|
22
|
+
|
|
23
|
+
export interface ConvertOptions {
|
|
24
|
+
scopes?: string[]
|
|
25
|
+
/** 새 컴포넌트의 ID. 미지정 시 ImportRule 의 idStrategy 적용 또는 자동 생성. */
|
|
26
|
+
id?: string
|
|
27
|
+
/**
|
|
28
|
+
* 코어 placeholder type ('placeholder') 외에 인정할 도메인 추상 type list.
|
|
29
|
+
* 예: ['GenericTransport', 'GenericFacility'].
|
|
30
|
+
* 호출자가 자기 도메인 패키지의 추상까지 변환 대상으로 포함하도록 명시.
|
|
31
|
+
*/
|
|
32
|
+
extraPlaceholderTypes?: ReadonlyArray<string>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* things-scene 코어가 등록한 도메인 비종속 placeholder type.
|
|
37
|
+
*
|
|
38
|
+
* @sync things-scene/src/components/generic-placeholders.ts CORE_PLACEHOLDER_TYPES
|
|
39
|
+
* client/server 경계로 직접 import 불가 — 값을 바꾸면 양쪽 동시 수정 필수.
|
|
40
|
+
* 계약은 generic-to.test.ts 의 'CORE_PLACEHOLDER_TYPES contract' 어설션으로 보증.
|
|
41
|
+
*/
|
|
42
|
+
export const CORE_PLACEHOLDER_TYPES = [GENERIC_OBJECT_TYPE] as const
|
|
43
|
+
|
|
44
|
+
export function isPlaceholderType(
|
|
45
|
+
type: string | undefined,
|
|
46
|
+
extraTypes: ReadonlyArray<string> = []
|
|
47
|
+
): boolean {
|
|
48
|
+
if (!type) return false
|
|
49
|
+
if ((CORE_PLACEHOLDER_TYPES as readonly string[]).includes(type)) return true
|
|
50
|
+
return extraTypes.includes(type)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ── 일반화된 변환 helper ─────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 추상 placeholder 를 지정된 도메인 type 으로 변환. 호환되는 모든 generic-* 수용 (코어 + 도메인).
|
|
57
|
+
*
|
|
58
|
+
* 기존 좌표/크기/회전/source 보존. placeholder 시각 메타 (placeholderLabel/Hint, fillStyle 등) 는 제거.
|
|
59
|
+
*/
|
|
60
|
+
export function convertPlaceholderTo(
|
|
61
|
+
placeholder: BoardComponent,
|
|
62
|
+
toType: string,
|
|
63
|
+
options: ConvertOptions = {}
|
|
64
|
+
): BoardComponent {
|
|
65
|
+
const extra = options.extraPlaceholderTypes ?? []
|
|
66
|
+
if (!isPlaceholderType(placeholder.type, extra)) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`Source component is not a generic placeholder (type=${placeholder.type}). ` +
|
|
69
|
+
`Expected one of: ${[...CORE_PLACEHOLDER_TYPES, ...extra].join(', ')}`
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const rules = getImportRules(options.scopes)
|
|
74
|
+
const rule = rules.find(r => r.componentType === toType)
|
|
75
|
+
|
|
76
|
+
const category: ComponentCategory = rule?.category ?? 'unknown'
|
|
77
|
+
const newId = options.id ?? placeholder.id
|
|
78
|
+
|
|
79
|
+
const preset = find3DPreset(toType, category, options.scopes)
|
|
80
|
+
const threeD = {
|
|
81
|
+
geometry: preset.geometry,
|
|
82
|
+
...(preset.material && { material: preset.material }),
|
|
83
|
+
origin: preset.origin ?? 'bottom'
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// placeholder 시각/스타일 메타는 새 type 으로 옮길 때 의미 없음 — 제거.
|
|
87
|
+
const {
|
|
88
|
+
strokeStyle: _strokeStyle,
|
|
89
|
+
strokeDashArray: _strokeDashArray,
|
|
90
|
+
fillStyle: _fillStyle,
|
|
91
|
+
label: _label,
|
|
92
|
+
placeholderLabel: _placeholderLabel,
|
|
93
|
+
placeholderHint: _placeholderHint,
|
|
94
|
+
...preservedState
|
|
95
|
+
} = placeholder as any
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
...preservedState,
|
|
99
|
+
category,
|
|
100
|
+
type: toType,
|
|
101
|
+
id: newId,
|
|
102
|
+
threeD,
|
|
103
|
+
...(rule?.build.defaultState || {})
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ── Backward-compat alias — 기존 호출처 호환 ──────────────────────
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @deprecated Use `convertPlaceholderTo`. Placeholder 한정 — 새 코드는 일반화된 helper.
|
|
111
|
+
*/
|
|
112
|
+
export function convertGenericTo(
|
|
113
|
+
generic: BoardComponent,
|
|
114
|
+
toType: string,
|
|
115
|
+
options: ConvertOptions = {}
|
|
116
|
+
): BoardComponent {
|
|
117
|
+
if (generic.type !== GENERIC_OBJECT_TYPE) {
|
|
118
|
+
throw new Error(`Source component is not Placeholder (type=${generic.type})`)
|
|
119
|
+
}
|
|
120
|
+
return convertPlaceholderTo(generic, toType, options)
|
|
121
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 하이브리드 추출 contracts (Phase Board-AI §3.8) — 이미지/도면 → 레이아웃 추출을
|
|
3
|
+
* *역할분담* 으로 분해하기 위한 provider-중립 인터페이스.
|
|
4
|
+
*
|
|
5
|
+
* 위치/기하 ← GeometryExtractor (벡터 파싱 > CV > VLM폴백)
|
|
6
|
+
* 식별/라벨 ← LabelExtractor (OCR: GCP/Textract/Tesseract)
|
|
7
|
+
* 의미/타입 ← Recognizer (VLM — region 인식 전담, 좌표 아님)
|
|
8
|
+
* 스케일 ← ScaleCalibrator (치수/스케일바/알려진 크기)
|
|
9
|
+
* 정리 ← LayoutRefiner (정렬/스냅/등간격/겹침해소)
|
|
10
|
+
*
|
|
11
|
+
* 구현체는 스캐폴딩 단계에선 stub. 본격 테스트 단계에서 소스 적합 impl 을 채운다.
|
|
12
|
+
*/
|
|
13
|
+
import type { UniversalEntity, Vec2, BoundingBox, AdapterInput, ParseResult } from '../types/index'
|
|
14
|
+
|
|
15
|
+
/** 입력 소스 분류 — 추출 경로 선택 기준. */
|
|
16
|
+
export type SourceKind =
|
|
17
|
+
| 'vector' // DXF/IFC/SVG/PDF-vector — 정밀 기하 직접 파싱
|
|
18
|
+
| 'raster-topdown' // 평면도 비트맵 — CV + OCR + VLM 하이브리드
|
|
19
|
+
| 'photo' // 사진/3D 렌더 — VLM 러프 폴백
|
|
20
|
+
| 'unknown'
|
|
21
|
+
|
|
22
|
+
/** 검출된 저수준 기하 프리미티브 (픽셀/소스 좌표계). */
|
|
23
|
+
export interface GeometricPrimitive {
|
|
24
|
+
kind: 'line' | 'rect' | 'region' | 'point'
|
|
25
|
+
bbox: BoundingBox
|
|
26
|
+
/** line 일 때 양 끝점. */
|
|
27
|
+
segment?: { a: Vec2; b: Vec2 }
|
|
28
|
+
/** 검출 신뢰도 0..1 (있으면). */
|
|
29
|
+
score?: number
|
|
30
|
+
/**
|
|
31
|
+
* 이미 완전한 엔티티를 아는 추출기(벡터: DXF/IFC/SVG)가 원 엔티티를 그대로 실어 보낸다.
|
|
32
|
+
* 있으면 fuse 가 무손실로 사용(attribs/rotation/vertices 보존). CV 추출기는 비움 → fuse 가
|
|
33
|
+
* bbox 로 bare 엔티티 생성 후 Recognizer 가 의미 부여.
|
|
34
|
+
*/
|
|
35
|
+
entity?: UniversalEntity
|
|
36
|
+
/** 추출기별 원시 메타. */
|
|
37
|
+
meta?: Record<string, any>
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** OCR 라벨 — 텍스트 + 위치 (식별/앵커/스케일 단서). */
|
|
41
|
+
export interface Label {
|
|
42
|
+
text: string
|
|
43
|
+
bbox: BoundingBox
|
|
44
|
+
score?: number
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** 한 region(프리미티브/crop)에 대한 의미 인식 결과. */
|
|
48
|
+
export interface RecognitionResult {
|
|
49
|
+
/** 실제 보드 컴포넌트 type (카탈로그 그라운딩). 불명 시 undefined. */
|
|
50
|
+
componentType?: string
|
|
51
|
+
confidence: number
|
|
52
|
+
attribs?: Record<string, any>
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** 스케일 캘리브레이션 결과 — 픽셀 → board 단위 변환. */
|
|
56
|
+
export interface ScaleResult {
|
|
57
|
+
unitsPerPixel: number
|
|
58
|
+
origin: Vec2
|
|
59
|
+
units?: ParseResult['units']
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** 추출 컨텍스트 — 이미지 dims, 사용자 힌트, 카탈로그 등 (확장 여지). */
|
|
63
|
+
export interface ExtractionContext {
|
|
64
|
+
imageWidth?: number
|
|
65
|
+
imageHeight?: number
|
|
66
|
+
userPrompt?: string
|
|
67
|
+
/** 카탈로그 그라운딩용 컴포넌트 type 목록 (Recognizer 가 제약). */
|
|
68
|
+
catalog?: string[]
|
|
69
|
+
/**
|
|
70
|
+
* 명시 스케일 기준 — 알려진 픽셀 span = 알려진 실제 길이 (예: UI 2점 캘리브레이션,
|
|
71
|
+
* 스케일바). ScaleCalibrator 가 최우선 사용. unitsPerPixel = units / pixels.
|
|
72
|
+
*/
|
|
73
|
+
scaleReference?: { pixels: number; units: number; unit?: string }
|
|
74
|
+
[k: string]: any
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ── contracts ────────────────────────────────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
export interface GeometryExtractor {
|
|
80
|
+
readonly id: string
|
|
81
|
+
extract(input: AdapterInput, ctx?: ExtractionContext): Promise<GeometricPrimitive[]>
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface LabelExtractor {
|
|
85
|
+
readonly id: string
|
|
86
|
+
extract(input: AdapterInput, ctx?: ExtractionContext): Promise<Label[]>
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface Recognizer {
|
|
90
|
+
readonly id: string
|
|
91
|
+
/** region(프리미티브 + ctx)이 어떤 컴포넌트인지 — VLM 인식 전담(좌표 아님). */
|
|
92
|
+
recognize(region: GeometricPrimitive, ctx?: ExtractionContext): Promise<RecognitionResult>
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface ScaleCalibrator {
|
|
96
|
+
readonly id: string
|
|
97
|
+
calibrate(labels: Label[], primitives: GeometricPrimitive[], ctx?: ExtractionContext): Promise<ScaleResult>
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface LayoutRefiner {
|
|
101
|
+
readonly id: string
|
|
102
|
+
refine(entities: UniversalEntity[], ctx?: ExtractionContext): UniversalEntity[]
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** 한 시안(해석) — 공유 기하 위에 의미/그룹핑/전략만 달리한 결과. */
|
|
106
|
+
export interface VariantDraft {
|
|
107
|
+
/** URL 친화 short id (예: 'equipment-focus'). */
|
|
108
|
+
id: string
|
|
109
|
+
/** 사용자 표시 라벨 (예: '장비 중심'). */
|
|
110
|
+
label: string
|
|
111
|
+
description?: string
|
|
112
|
+
entities: UniversalEntity[]
|
|
113
|
+
subjectName?: string
|
|
114
|
+
subjectDescription?: string
|
|
115
|
+
importStrategy?: string
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 시안 전략 — *정확한 공유 기하+라벨* 을 받아 N개 해석 시안을 만든다.
|
|
120
|
+
* (UX: 사용자가 3안 중 선택하는 흐름 보존. 기하는 공유라 셋 다 레이아웃 정상, 해석만 다름.)
|
|
121
|
+
* 미지정 시 파이프라인이 단일 default 시안 1개를 만든다.
|
|
122
|
+
*/
|
|
123
|
+
export interface VariantStrategy {
|
|
124
|
+
readonly id: string
|
|
125
|
+
interpret(
|
|
126
|
+
primitives: GeometricPrimitive[],
|
|
127
|
+
labels: Label[],
|
|
128
|
+
set: ExtractorSet,
|
|
129
|
+
ctx?: ExtractionContext
|
|
130
|
+
): Promise<VariantDraft[]>
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** 한 소스경로의 추출기 묶음 (geometry 필수, 나머지는 경로별 선택). */
|
|
134
|
+
export interface ExtractorSet {
|
|
135
|
+
geometry: GeometryExtractor
|
|
136
|
+
labels?: LabelExtractor
|
|
137
|
+
recognizer?: Recognizer
|
|
138
|
+
scale?: ScaleCalibrator
|
|
139
|
+
refiner?: LayoutRefiner
|
|
140
|
+
/** 다중 시안 생성 전략 (3안 선택 UX). 미지정 시 단일 default 시안. */
|
|
141
|
+
variants?: VariantStrategy
|
|
142
|
+
}
|