zorya-classifier 0.2.1 → 0.2.3
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/README.md +31 -17
- package/dist/app/classifier-config.d.ts +30 -0
- package/dist/app/classifier-config.js +46 -0
- package/dist/app/classifier-contracts.d.ts +32 -0
- package/dist/app/classifier-contracts.js +1 -0
- package/dist/app/classifier-runtime.d.ts +7 -0
- package/dist/app/classifier-runtime.js +71 -0
- package/dist/app/classifier-spatial.d.ts +31 -0
- package/dist/app/classifier-spatial.js +78 -0
- package/dist/app/cli-arguments.d.ts +2 -2
- package/dist/app/composed-classifier.d.ts +17 -0
- package/dist/app/composed-classifier.js +1 -0
- package/dist/app/create-classifier.d.ts +9 -33
- package/dist/app/create-classifier.js +53 -245
- package/dist/cli.js +1 -1
- package/dist/entities/classification.d.ts +83 -0
- package/dist/entities/classification.js +28 -0
- package/dist/entities/contracts.d.ts +6 -475
- package/dist/entities/contracts.js +6 -97
- package/dist/entities/decision.d.ts +211 -0
- package/dist/entities/decision.js +33 -0
- package/dist/entities/geometry.d.ts +37 -0
- package/dist/entities/geometry.js +26 -0
- package/dist/entities/image.d.ts +30 -0
- package/dist/entities/image.js +12 -0
- package/dist/entities/localization.d.ts +110 -0
- package/dist/entities/localization.js +13 -0
- package/dist/entities/object-proposals.d.ts +1 -1
- package/dist/entities/representation.d.ts +0 -183
- package/dist/entities/representation.js +1 -33
- package/dist/entities/segmentation-metadata.d.ts +70 -0
- package/dist/entities/segmentation-metadata.js +21 -1
- package/dist/entities/segmentation-verification.d.ts +1 -1
- package/dist/entities/segmentation.d.ts +5 -20
- package/dist/entities/validation.d.ts +2 -0
- package/dist/entities/validation.js +9 -0
- package/dist/entities/whole-object.d.ts +6 -21
- package/dist/features/choice-beam-layout.js +2 -7
- package/dist/features/proposals/presentation.d.ts +21 -0
- package/dist/features/proposals/presentation.js +122 -0
- package/dist/features/proposals/validation.d.ts +138 -0
- package/dist/features/proposals/validation.js +125 -0
- package/dist/features/segmentation/box-check.js +10 -23
- package/dist/features/segmentation/mask.js +2 -7
- package/dist/features/segmentation/region-result.d.ts +18 -0
- package/dist/features/segmentation/region-result.js +171 -0
- package/dist/features/segmentation/source-mask.d.ts +6 -0
- package/dist/features/segmentation/source-mask.js +32 -0
- package/dist/features/segmentation/validation.d.ts +9 -0
- package/dist/features/segmentation/validation.js +94 -0
- package/dist/infrastructure/decision-transport/errors.d.ts +8 -0
- package/dist/infrastructure/decision-transport/errors.js +34 -0
- package/dist/infrastructure/decision-transport/images.d.ts +1 -0
- package/dist/infrastructure/decision-transport/images.js +52 -0
- package/dist/infrastructure/{openrouter-common.d.ts → decision-transport/request.d.ts} +6 -15
- package/dist/infrastructure/decision-transport/request.js +162 -0
- package/dist/infrastructure/decision-transport/response.d.ts +1 -0
- package/dist/infrastructure/decision-transport/response.js +72 -0
- package/dist/infrastructure/decision-transport/route-identity.d.ts +11 -0
- package/dist/infrastructure/decision-transport/route-identity.js +23 -0
- package/dist/infrastructure/openrouter-vision.js +1 -1
- package/dist/infrastructure/openrouter.js +7 -19
- package/dist/infrastructure/raster.js +3 -8
- package/dist/infrastructure/segmentation/grabcut/index.d.ts +2 -2
- package/dist/infrastructure/segmentation/grabcut/index.js +3 -5
- package/dist/infrastructure/segmentation/grabcut/masks.d.ts +49 -0
- package/dist/infrastructure/segmentation/grabcut/masks.js +89 -0
- package/dist/infrastructure/segmentation/grabcut/model-asset.d.ts +4 -0
- package/dist/infrastructure/segmentation/grabcut/model-asset.js +4 -0
- package/dist/infrastructure/segmentation/grabcut/runtime.d.ts +70 -0
- package/dist/infrastructure/segmentation/grabcut/runtime.js +96 -0
- package/dist/infrastructure/segmentation/grabcut/worker-inference.d.ts +4 -43
- package/dist/infrastructure/segmentation/grabcut/worker-inference.js +4 -187
- package/dist/infrastructure/segmentation/mobile-sam/index.d.ts +3 -66
- package/dist/infrastructure/segmentation/mobile-sam/index.js +2 -478
- package/dist/infrastructure/segmentation/mobile-sam/input.d.ts +46 -0
- package/dist/infrastructure/segmentation/mobile-sam/input.js +83 -0
- package/dist/infrastructure/segmentation/mobile-sam/model-assets.d.ts +8 -0
- package/dist/infrastructure/segmentation/mobile-sam/model-assets.js +8 -0
- package/dist/infrastructure/segmentation/mobile-sam/object-proposals.d.ts +7 -0
- package/dist/infrastructure/segmentation/mobile-sam/object-proposals.js +124 -0
- package/dist/infrastructure/segmentation/mobile-sam/options.d.ts +43 -0
- package/dist/infrastructure/segmentation/mobile-sam/options.js +19 -0
- package/dist/infrastructure/segmentation/mobile-sam/proposal-masks.d.ts +26 -0
- package/dist/infrastructure/segmentation/mobile-sam/proposal-masks.js +71 -0
- package/dist/infrastructure/segmentation/mobile-sam/segmentation-masks.d.ts +112 -0
- package/dist/infrastructure/segmentation/mobile-sam/segmentation-masks.js +230 -0
- package/dist/infrastructure/segmentation/mobile-sam/segmenter.d.ts +22 -0
- package/dist/infrastructure/segmentation/mobile-sam/segmenter.js +268 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-expand.d.ts +7 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-expand.js +188 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-inference.d.ts +6 -149
- package/dist/infrastructure/segmentation/mobile-sam/worker-inference.js +6 -845
- package/dist/infrastructure/segmentation/mobile-sam/worker-models.d.ts +14 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-models.js +72 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-proposals.d.ts +7 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-proposals.js +159 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-segment.d.ts +4 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-segment.js +126 -0
- package/dist/infrastructure/segmentation/native-protocol.d.ts +59 -34
- package/dist/infrastructure/segmentation/native-protocol.js +26 -16
- package/dist/infrastructure/segmentation/proposal-presentation-input.d.ts +20 -0
- package/dist/infrastructure/segmentation/proposal-presentation-input.js +107 -0
- package/dist/infrastructure/segmentation/proposal-presentation-pixels.d.ts +8 -0
- package/dist/infrastructure/segmentation/proposal-presentation-pixels.js +93 -0
- package/dist/infrastructure/segmentation/proposal-presentation.js +10 -201
- package/dist/infrastructure/vision-chat/options.d.ts +62 -0
- package/dist/infrastructure/vision-chat/options.js +46 -0
- package/dist/infrastructure/vision-chat/request.d.ts +23 -0
- package/dist/infrastructure/vision-chat/request.js +109 -0
- package/dist/infrastructure/vision-chat/response.d.ts +3 -0
- package/dist/infrastructure/vision-chat/response.js +105 -0
- package/dist/infrastructure/vision-chat.d.ts +4 -61
- package/dist/infrastructure/vision-chat.js +8 -271
- package/dist/openai-compatible.js +1 -1
- package/dist/processes/extract-from-region.js +11 -216
- package/dist/processes/extract.d.ts +2 -8
- package/dist/processes/extract.js +12 -128
- package/dist/processes/proposal-location.js +5 -251
- package/docs/README.ru.md +50 -33
- package/docs/acceptance.md +6 -4
- package/docs/agents.ru.md +97 -0
- package/docs/api.md +4 -4
- package/docs/architecture.md +33 -7
- package/docs/architecture.ru.md +146 -0
- package/docs/benchmarks.md +3 -1
- package/docs/development.ru.md +141 -0
- package/docs/migrations/experimental-text-image-removal.ru.md +9 -0
- package/docs/provenance.json +288 -1
- package/docs/publishing.md +5 -3
- package/docs/refactoring-plan.ru.md +183 -0
- package/docs/v02-usage.md +8 -8
- package/docs/vision-results.md +1 -1
- package/package.json +5 -3
- package/dist/infrastructure/boundary-view.d.ts +0 -2
- package/dist/infrastructure/boundary-view.js +0 -263
- package/dist/infrastructure/openrouter-common.js +0 -317
- package/dist/infrastructure/text-representation.d.ts +0 -23
- package/dist/infrastructure/text-representation.js +0 -226
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { PixelRect } from '../entities/contracts.js';
|
|
2
|
-
import type { ImageRepresentationPort, RepresentationView } from '../entities/representation.js';
|
|
3
|
-
export interface TextPixelView {
|
|
4
|
-
id: string;
|
|
5
|
-
role: RepresentationView['role'];
|
|
6
|
-
sourceRegion: PixelRect;
|
|
7
|
-
width: number;
|
|
8
|
-
height: number;
|
|
9
|
-
/** Clean, resized, row-major RGBA8. Grid labels remain separately available as metadata. */
|
|
10
|
-
data: Uint8Array;
|
|
11
|
-
grid?: RepresentationView['grid'];
|
|
12
|
-
}
|
|
13
|
-
export interface TextRepresentationEncoder {
|
|
14
|
-
readonly profile: string;
|
|
15
|
-
/** Hard UTF-8 upper bound for one encoded view at these dimensions. */
|
|
16
|
-
maxEncodedBytes(width: number, height: number): number;
|
|
17
|
-
encode(view: TextPixelView, signal: AbortSignal): Promise<string>;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Build request-wide text representations from clean canonical pixels. The injected encoder
|
|
21
|
-
* is intentionally internal so research codecs do not become public package exports.
|
|
22
|
-
*/
|
|
23
|
-
export declare function createTextRepresentation(encoder: TextRepresentationEncoder): ImageRepresentationPort;
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
import sharp from 'sharp';
|
|
2
|
-
import { limits } from '../entities/contracts.js';
|
|
3
|
-
import { ClassifierError, assertActive } from '../entities/errors.js';
|
|
4
|
-
import { representationLimits } from '../entities/representation.js';
|
|
5
|
-
import { readCanonicalPixels } from './raster.js';
|
|
6
|
-
function isContained(outer, inner) {
|
|
7
|
-
return (inner.left >= outer.left &&
|
|
8
|
-
inner.top >= outer.top &&
|
|
9
|
-
inner.left + inner.width <= outer.left + outer.width &&
|
|
10
|
-
inner.top + inner.height <= outer.top + outer.height);
|
|
11
|
-
}
|
|
12
|
-
function key(region) {
|
|
13
|
-
return `${region.left},${region.top},${region.width},${region.height}`;
|
|
14
|
-
}
|
|
15
|
-
function dimensions(region, maxSide) {
|
|
16
|
-
const scale = Math.min(1, maxSide / Math.max(region.width, region.height));
|
|
17
|
-
return {
|
|
18
|
-
width: Math.max(1, Math.round(region.width * scale)),
|
|
19
|
-
height: Math.max(1, Math.round(region.height * scale)),
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
function assertGridGeometry(view, width, height) {
|
|
23
|
-
if (!view.grid)
|
|
24
|
-
return;
|
|
25
|
-
const map = (rect) => ({
|
|
26
|
-
left: Math.round(((rect.left - view.sourceRegion.left) * width) / view.sourceRegion.width),
|
|
27
|
-
top: Math.round(((rect.top - view.sourceRegion.top) * height) / view.sourceRegion.height),
|
|
28
|
-
width: Math.round((rect.width * width) / view.sourceRegion.width),
|
|
29
|
-
height: Math.round((rect.height * height) / view.sourceRegion.height),
|
|
30
|
-
});
|
|
31
|
-
const mapped = view.grid.cells.map((cell) => map(cell.region));
|
|
32
|
-
if (view.grid.cells.some((cell) => !isContained(view.sourceRegion, cell.region)))
|
|
33
|
-
throw new ClassifierError('INVALID_INPUT', 'Grid geometry lies outside its source region');
|
|
34
|
-
if (mapped.some((rect) => rect.width < 1 || rect.height < 1))
|
|
35
|
-
throw new ClassifierError('RESOURCE_LIMIT', 'Distinct grid geometry is indistinguishable at the allocated resolution', { component: 'representation' });
|
|
36
|
-
const sourceKeys = new Set(view.grid.cells.map((cell) => key(cell.region)));
|
|
37
|
-
const mappedKeys = new Set(mapped.map((rect) => key(rect)));
|
|
38
|
-
if (sourceKeys.size !== mappedKeys.size)
|
|
39
|
-
throw new ClassifierError('RESOURCE_LIMIT', 'Distinct grid geometry collapses at the allocated resolution', {
|
|
40
|
-
component: 'representation',
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
async function cleanPixels(source, sourcePixels, view, width, height, signal) {
|
|
44
|
-
const region = view.sourceRegion;
|
|
45
|
-
if (!isContained({ left: 0, top: 0, width: source.width, height: source.height }, region))
|
|
46
|
-
throw new ClassifierError('INVALID_INPUT', 'Representation view lies outside the oriented source');
|
|
47
|
-
const raw = Buffer.from(sourcePixels.buffer, sourcePixels.byteOffset, sourcePixels.byteLength);
|
|
48
|
-
const pipeline = sharp(raw, {
|
|
49
|
-
raw: { width: source.width, height: source.height, channels: 4 },
|
|
50
|
-
limitInputPixels: limits.imagePixels,
|
|
51
|
-
})
|
|
52
|
-
.extract(region)
|
|
53
|
-
.resize(width, height, { kernel: 'nearest' })
|
|
54
|
-
.raw();
|
|
55
|
-
try {
|
|
56
|
-
const result = await pipeline.toBuffer({ resolveWithObject: true });
|
|
57
|
-
assertActive(signal);
|
|
58
|
-
if (result.info.channels !== 4 || result.data.byteLength !== width * height * 4)
|
|
59
|
-
throw new ClassifierError('INVALID_RESPONSE', 'Sharp returned an invalid canonical pixel view');
|
|
60
|
-
return {
|
|
61
|
-
id: view.id,
|
|
62
|
-
role: view.role,
|
|
63
|
-
sourceRegion: region,
|
|
64
|
-
width,
|
|
65
|
-
height,
|
|
66
|
-
data: result.data,
|
|
67
|
-
...(view.grid ? { grid: view.grid } : {}),
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
finally {
|
|
71
|
-
pipeline.destroy();
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
function aliasesFor(view) {
|
|
75
|
-
return {
|
|
76
|
-
id: view.id,
|
|
77
|
-
role: view.role,
|
|
78
|
-
sourceRegion: view.sourceRegion,
|
|
79
|
-
...(view.grid ? { grid: view.grid } : {}),
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
function gridMetadata(grid) {
|
|
83
|
-
if (!grid)
|
|
84
|
-
return undefined;
|
|
85
|
-
return {
|
|
86
|
-
cells: grid.cells.map((cell) => ({
|
|
87
|
-
id: cell.id,
|
|
88
|
-
column: cell.column,
|
|
89
|
-
row: cell.row,
|
|
90
|
-
region: cell.region,
|
|
91
|
-
label: grid.labels.get(cell.id) ?? null,
|
|
92
|
-
})),
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
function makePlan(groups, maxSide, encoder) {
|
|
96
|
-
const plan = [];
|
|
97
|
-
let totalBytes = 0;
|
|
98
|
-
for (const group of groups) {
|
|
99
|
-
const size = dimensions(group.sourceRegion, maxSide);
|
|
100
|
-
const metadataText = JSON.stringify({
|
|
101
|
-
representationView: {
|
|
102
|
-
id: group.aliases[0]?.id ?? group.primary.id,
|
|
103
|
-
aliases: group.aliases.map((alias) => ({
|
|
104
|
-
id: alias.id,
|
|
105
|
-
role: alias.role,
|
|
106
|
-
sourceRegion: alias.sourceRegion,
|
|
107
|
-
})),
|
|
108
|
-
sourceRegion: group.sourceRegion,
|
|
109
|
-
dimensions: size,
|
|
110
|
-
scaleX: size.width / group.sourceRegion.width,
|
|
111
|
-
scaleY: size.height / group.sourceRegion.height,
|
|
112
|
-
grid: group.aliases.flatMap((alias) => {
|
|
113
|
-
const value = gridMetadata(alias.grid);
|
|
114
|
-
return value === undefined ? [] : [{ viewId: alias.id, cells: value.cells }];
|
|
115
|
-
}),
|
|
116
|
-
},
|
|
117
|
-
});
|
|
118
|
-
const bound = encoder.maxEncodedBytes(size.width, size.height);
|
|
119
|
-
const metadataBytes = Buffer.byteLength(metadataText, 'utf8');
|
|
120
|
-
if (!Number.isSafeInteger(bound) ||
|
|
121
|
-
bound < 0 ||
|
|
122
|
-
bound > representationLimits.partCharacters ||
|
|
123
|
-
metadataText.length > representationLimits.partCharacters)
|
|
124
|
-
return undefined;
|
|
125
|
-
totalBytes += metadataBytes + bound;
|
|
126
|
-
plan.push({ group, ...size, metadataText, maxEncodedBytes: bound });
|
|
127
|
-
}
|
|
128
|
-
return totalBytes <= representationLimits.totalBytes ? plan : undefined;
|
|
129
|
-
}
|
|
130
|
-
function buildGroups(views) {
|
|
131
|
-
const groups = new Map();
|
|
132
|
-
for (const view of views) {
|
|
133
|
-
const regionKey = key(view.sourceRegion);
|
|
134
|
-
const prior = groups.get(regionKey);
|
|
135
|
-
if (!prior) {
|
|
136
|
-
groups.set(regionKey, {
|
|
137
|
-
sourceRegion: view.sourceRegion,
|
|
138
|
-
primary: view,
|
|
139
|
-
aliases: [aliasesFor(view)],
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
prior.aliases.push(aliasesFor(view));
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return [...groups.values()];
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Build request-wide text representations from clean canonical pixels. The injected encoder
|
|
150
|
-
* is intentionally internal so research codecs do not become public package exports.
|
|
151
|
-
*/
|
|
152
|
-
export function createTextRepresentation(encoder) {
|
|
153
|
-
return {
|
|
154
|
-
async prepare(input) {
|
|
155
|
-
assertActive(input.signal);
|
|
156
|
-
if (input.views.length > representationLimits.maxViews)
|
|
157
|
-
throw new ClassifierError('RESOURCE_LIMIT', 'A representation request may contain at most nine views', {
|
|
158
|
-
component: 'representation',
|
|
159
|
-
});
|
|
160
|
-
const groups = buildGroups(input.views);
|
|
161
|
-
for (const group of groups) {
|
|
162
|
-
if (!isContained({ left: 0, top: 0, width: input.source.width, height: input.source.height }, group.sourceRegion))
|
|
163
|
-
throw new ClassifierError('INVALID_INPUT', 'Representation view lies outside the oriented source');
|
|
164
|
-
}
|
|
165
|
-
let plan;
|
|
166
|
-
for (let side = representationLimits.maxSide; side >= 1 && plan === undefined; side -= 1)
|
|
167
|
-
plan = makePlan(groups, side, encoder);
|
|
168
|
-
if (!plan)
|
|
169
|
-
throw new ClassifierError('RESOURCE_LIMIT', 'No bounded text representation allocation fits the request', {
|
|
170
|
-
component: 'representation',
|
|
171
|
-
});
|
|
172
|
-
for (const item of plan)
|
|
173
|
-
for (const alias of item.group.aliases)
|
|
174
|
-
if (alias.grid)
|
|
175
|
-
assertGridGeometry({ ...item.group.primary, sourceRegion: item.group.sourceRegion, grid: alias.grid }, item.width, item.height);
|
|
176
|
-
const decoded = await readCanonicalPixels(input.source, input.signal);
|
|
177
|
-
const pixelViews = [];
|
|
178
|
-
for (const item of plan)
|
|
179
|
-
pixelViews.push(await cleanPixels(input.source, decoded.data, item.group.primary, item.width, item.height, input.signal));
|
|
180
|
-
const state = [];
|
|
181
|
-
const metadata = { profile: encoder.profile, bytes: 0, views: [] };
|
|
182
|
-
for (let index = 0; index < pixelViews.length; index += 1) {
|
|
183
|
-
const view = pixelViews[index];
|
|
184
|
-
const allocation = plan[index];
|
|
185
|
-
if (!view || !allocation)
|
|
186
|
-
throw new ClassifierError('INVALID_RESPONSE', 'Text representation allocation was incomplete');
|
|
187
|
-
assertActive(input.signal);
|
|
188
|
-
state.push(allocation.metadataText);
|
|
189
|
-
metadata.bytes += Buffer.byteLength(allocation.metadataText, 'utf8');
|
|
190
|
-
let text;
|
|
191
|
-
try {
|
|
192
|
-
text = await encoder.encode(view, input.signal);
|
|
193
|
-
}
|
|
194
|
-
catch (error) {
|
|
195
|
-
if (error instanceof ClassifierError && error.code === 'RESOURCE_LIMIT')
|
|
196
|
-
throw new ClassifierError(error.code, error.message, {
|
|
197
|
-
...error.details,
|
|
198
|
-
component: 'representation',
|
|
199
|
-
});
|
|
200
|
-
throw error;
|
|
201
|
-
}
|
|
202
|
-
const bytes = Buffer.byteLength(text, 'utf8');
|
|
203
|
-
if (text.length > representationLimits.partCharacters || bytes > allocation.maxEncodedBytes)
|
|
204
|
-
throw new ClassifierError('RESOURCE_LIMIT', 'Encoder output exceeds its declared per-view bound', {
|
|
205
|
-
component: 'representation',
|
|
206
|
-
});
|
|
207
|
-
if (metadata.bytes + bytes > representationLimits.totalBytes)
|
|
208
|
-
throw new ClassifierError('RESOURCE_LIMIT', 'Encoded request exceeds the aggregate UTF-8 byte limit', {
|
|
209
|
-
component: 'representation',
|
|
210
|
-
});
|
|
211
|
-
metadata.bytes += bytes;
|
|
212
|
-
state.push(text);
|
|
213
|
-
metadata.views.push({
|
|
214
|
-
id: view.id,
|
|
215
|
-
sourceRegion: view.sourceRegion,
|
|
216
|
-
width: view.width,
|
|
217
|
-
height: view.height,
|
|
218
|
-
scaleX: view.width / view.sourceRegion.width,
|
|
219
|
-
scaleY: view.height / view.sourceRegion.height,
|
|
220
|
-
content: { left: 0, top: 0, width: view.width, height: view.height },
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
return { state, metadata };
|
|
224
|
-
},
|
|
225
|
-
};
|
|
226
|
-
}
|