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.
Files changed (139) hide show
  1. package/README.md +31 -17
  2. package/dist/app/classifier-config.d.ts +30 -0
  3. package/dist/app/classifier-config.js +46 -0
  4. package/dist/app/classifier-contracts.d.ts +32 -0
  5. package/dist/app/classifier-contracts.js +1 -0
  6. package/dist/app/classifier-runtime.d.ts +7 -0
  7. package/dist/app/classifier-runtime.js +71 -0
  8. package/dist/app/classifier-spatial.d.ts +31 -0
  9. package/dist/app/classifier-spatial.js +78 -0
  10. package/dist/app/cli-arguments.d.ts +2 -2
  11. package/dist/app/composed-classifier.d.ts +17 -0
  12. package/dist/app/composed-classifier.js +1 -0
  13. package/dist/app/create-classifier.d.ts +9 -33
  14. package/dist/app/create-classifier.js +53 -245
  15. package/dist/cli.js +1 -1
  16. package/dist/entities/classification.d.ts +83 -0
  17. package/dist/entities/classification.js +28 -0
  18. package/dist/entities/contracts.d.ts +6 -475
  19. package/dist/entities/contracts.js +6 -97
  20. package/dist/entities/decision.d.ts +211 -0
  21. package/dist/entities/decision.js +33 -0
  22. package/dist/entities/geometry.d.ts +37 -0
  23. package/dist/entities/geometry.js +26 -0
  24. package/dist/entities/image.d.ts +30 -0
  25. package/dist/entities/image.js +12 -0
  26. package/dist/entities/localization.d.ts +110 -0
  27. package/dist/entities/localization.js +13 -0
  28. package/dist/entities/object-proposals.d.ts +1 -1
  29. package/dist/entities/representation.d.ts +0 -183
  30. package/dist/entities/representation.js +1 -33
  31. package/dist/entities/segmentation-metadata.d.ts +70 -0
  32. package/dist/entities/segmentation-metadata.js +21 -1
  33. package/dist/entities/segmentation-verification.d.ts +1 -1
  34. package/dist/entities/segmentation.d.ts +5 -20
  35. package/dist/entities/validation.d.ts +2 -0
  36. package/dist/entities/validation.js +9 -0
  37. package/dist/entities/whole-object.d.ts +6 -21
  38. package/dist/features/choice-beam-layout.js +2 -7
  39. package/dist/features/proposals/presentation.d.ts +21 -0
  40. package/dist/features/proposals/presentation.js +122 -0
  41. package/dist/features/proposals/validation.d.ts +138 -0
  42. package/dist/features/proposals/validation.js +125 -0
  43. package/dist/features/segmentation/box-check.js +10 -23
  44. package/dist/features/segmentation/mask.js +2 -7
  45. package/dist/features/segmentation/region-result.d.ts +18 -0
  46. package/dist/features/segmentation/region-result.js +171 -0
  47. package/dist/features/segmentation/source-mask.d.ts +6 -0
  48. package/dist/features/segmentation/source-mask.js +32 -0
  49. package/dist/features/segmentation/validation.d.ts +9 -0
  50. package/dist/features/segmentation/validation.js +94 -0
  51. package/dist/infrastructure/decision-transport/errors.d.ts +8 -0
  52. package/dist/infrastructure/decision-transport/errors.js +34 -0
  53. package/dist/infrastructure/decision-transport/images.d.ts +1 -0
  54. package/dist/infrastructure/decision-transport/images.js +52 -0
  55. package/dist/infrastructure/{openrouter-common.d.ts → decision-transport/request.d.ts} +6 -15
  56. package/dist/infrastructure/decision-transport/request.js +162 -0
  57. package/dist/infrastructure/decision-transport/response.d.ts +1 -0
  58. package/dist/infrastructure/decision-transport/response.js +72 -0
  59. package/dist/infrastructure/decision-transport/route-identity.d.ts +11 -0
  60. package/dist/infrastructure/decision-transport/route-identity.js +23 -0
  61. package/dist/infrastructure/openrouter-vision.js +1 -1
  62. package/dist/infrastructure/openrouter.js +7 -19
  63. package/dist/infrastructure/raster.js +3 -8
  64. package/dist/infrastructure/segmentation/grabcut/index.d.ts +2 -2
  65. package/dist/infrastructure/segmentation/grabcut/index.js +3 -5
  66. package/dist/infrastructure/segmentation/grabcut/masks.d.ts +49 -0
  67. package/dist/infrastructure/segmentation/grabcut/masks.js +89 -0
  68. package/dist/infrastructure/segmentation/grabcut/model-asset.d.ts +4 -0
  69. package/dist/infrastructure/segmentation/grabcut/model-asset.js +4 -0
  70. package/dist/infrastructure/segmentation/grabcut/runtime.d.ts +70 -0
  71. package/dist/infrastructure/segmentation/grabcut/runtime.js +96 -0
  72. package/dist/infrastructure/segmentation/grabcut/worker-inference.d.ts +4 -43
  73. package/dist/infrastructure/segmentation/grabcut/worker-inference.js +4 -187
  74. package/dist/infrastructure/segmentation/mobile-sam/index.d.ts +3 -66
  75. package/dist/infrastructure/segmentation/mobile-sam/index.js +2 -478
  76. package/dist/infrastructure/segmentation/mobile-sam/input.d.ts +46 -0
  77. package/dist/infrastructure/segmentation/mobile-sam/input.js +83 -0
  78. package/dist/infrastructure/segmentation/mobile-sam/model-assets.d.ts +8 -0
  79. package/dist/infrastructure/segmentation/mobile-sam/model-assets.js +8 -0
  80. package/dist/infrastructure/segmentation/mobile-sam/object-proposals.d.ts +7 -0
  81. package/dist/infrastructure/segmentation/mobile-sam/object-proposals.js +124 -0
  82. package/dist/infrastructure/segmentation/mobile-sam/options.d.ts +43 -0
  83. package/dist/infrastructure/segmentation/mobile-sam/options.js +19 -0
  84. package/dist/infrastructure/segmentation/mobile-sam/proposal-masks.d.ts +26 -0
  85. package/dist/infrastructure/segmentation/mobile-sam/proposal-masks.js +71 -0
  86. package/dist/infrastructure/segmentation/mobile-sam/segmentation-masks.d.ts +112 -0
  87. package/dist/infrastructure/segmentation/mobile-sam/segmentation-masks.js +230 -0
  88. package/dist/infrastructure/segmentation/mobile-sam/segmenter.d.ts +22 -0
  89. package/dist/infrastructure/segmentation/mobile-sam/segmenter.js +268 -0
  90. package/dist/infrastructure/segmentation/mobile-sam/worker-expand.d.ts +7 -0
  91. package/dist/infrastructure/segmentation/mobile-sam/worker-expand.js +188 -0
  92. package/dist/infrastructure/segmentation/mobile-sam/worker-inference.d.ts +6 -149
  93. package/dist/infrastructure/segmentation/mobile-sam/worker-inference.js +6 -845
  94. package/dist/infrastructure/segmentation/mobile-sam/worker-models.d.ts +14 -0
  95. package/dist/infrastructure/segmentation/mobile-sam/worker-models.js +72 -0
  96. package/dist/infrastructure/segmentation/mobile-sam/worker-proposals.d.ts +7 -0
  97. package/dist/infrastructure/segmentation/mobile-sam/worker-proposals.js +159 -0
  98. package/dist/infrastructure/segmentation/mobile-sam/worker-segment.d.ts +4 -0
  99. package/dist/infrastructure/segmentation/mobile-sam/worker-segment.js +126 -0
  100. package/dist/infrastructure/segmentation/native-protocol.d.ts +59 -34
  101. package/dist/infrastructure/segmentation/native-protocol.js +26 -16
  102. package/dist/infrastructure/segmentation/proposal-presentation-input.d.ts +20 -0
  103. package/dist/infrastructure/segmentation/proposal-presentation-input.js +107 -0
  104. package/dist/infrastructure/segmentation/proposal-presentation-pixels.d.ts +8 -0
  105. package/dist/infrastructure/segmentation/proposal-presentation-pixels.js +93 -0
  106. package/dist/infrastructure/segmentation/proposal-presentation.js +10 -201
  107. package/dist/infrastructure/vision-chat/options.d.ts +62 -0
  108. package/dist/infrastructure/vision-chat/options.js +46 -0
  109. package/dist/infrastructure/vision-chat/request.d.ts +23 -0
  110. package/dist/infrastructure/vision-chat/request.js +109 -0
  111. package/dist/infrastructure/vision-chat/response.d.ts +3 -0
  112. package/dist/infrastructure/vision-chat/response.js +105 -0
  113. package/dist/infrastructure/vision-chat.d.ts +4 -61
  114. package/dist/infrastructure/vision-chat.js +8 -271
  115. package/dist/openai-compatible.js +1 -1
  116. package/dist/processes/extract-from-region.js +11 -216
  117. package/dist/processes/extract.d.ts +2 -8
  118. package/dist/processes/extract.js +12 -128
  119. package/dist/processes/proposal-location.js +5 -251
  120. package/docs/README.ru.md +50 -33
  121. package/docs/acceptance.md +6 -4
  122. package/docs/agents.ru.md +97 -0
  123. package/docs/api.md +4 -4
  124. package/docs/architecture.md +33 -7
  125. package/docs/architecture.ru.md +146 -0
  126. package/docs/benchmarks.md +3 -1
  127. package/docs/development.ru.md +141 -0
  128. package/docs/migrations/experimental-text-image-removal.ru.md +9 -0
  129. package/docs/provenance.json +288 -1
  130. package/docs/publishing.md +5 -3
  131. package/docs/refactoring-plan.ru.md +183 -0
  132. package/docs/v02-usage.md +8 -8
  133. package/docs/vision-results.md +1 -1
  134. package/package.json +5 -3
  135. package/dist/infrastructure/boundary-view.d.ts +0 -2
  136. package/dist/infrastructure/boundary-view.js +0 -263
  137. package/dist/infrastructure/openrouter-common.js +0 -317
  138. package/dist/infrastructure/text-representation.d.ts +0 -23
  139. 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
- }