@willwade/aac-processors 0.0.25 → 0.0.27

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.
@@ -145,9 +145,10 @@ export declare class AACButton implements IAACButton {
145
145
  parameters?: {
146
146
  [key: string]: any;
147
147
  };
148
+ predictions?: string[];
148
149
  semantic_id?: string;
149
150
  clone_id?: string;
150
- constructor({ id, label, message, targetPageId, semanticAction, audioRecording, style, contentType, contentSubType, image, resolvedImageEntry, symbolLibrary, symbolPath, x, y, columnSpan, rowSpan, scanBlocks, scanBlock, visibility, directActivate, parameters, semantic_id, clone_id, type, action, }: {
151
+ constructor({ id, label, message, targetPageId, semanticAction, audioRecording, style, contentType, contentSubType, image, resolvedImageEntry, symbolLibrary, symbolPath, x, y, columnSpan, rowSpan, scanBlocks, scanBlock, visibility, directActivate, parameters, predictions, semantic_id, clone_id, type, action, }: {
151
152
  id: string;
152
153
  label?: string;
153
154
  message?: string;
@@ -177,6 +178,7 @@ export declare class AACButton implements IAACButton {
177
178
  parameters?: {
178
179
  [key: string]: any;
179
180
  };
181
+ predictions?: string[];
180
182
  semantic_id?: string;
181
183
  clone_id?: string;
182
184
  type?: 'SPEAK' | 'NAVIGATE' | 'ACTION';
@@ -57,7 +57,7 @@ var AACScanType;
57
57
  AACScanType["BLOCK_COLUMN_ROW"] = "block-column-row";
58
58
  })(AACScanType || (exports.AACScanType = AACScanType = {}));
59
59
  class AACButton {
60
- constructor({ id, label = '', message = '', targetPageId, semanticAction, audioRecording, style, contentType, contentSubType, image, resolvedImageEntry, symbolLibrary, symbolPath, x, y, columnSpan, rowSpan, scanBlocks, scanBlock, visibility, directActivate, parameters, semantic_id, clone_id,
60
+ constructor({ id, label = '', message = '', targetPageId, semanticAction, audioRecording, style, contentType, contentSubType, image, resolvedImageEntry, symbolLibrary, symbolPath, x, y, columnSpan, rowSpan, scanBlocks, scanBlock, visibility, directActivate, parameters, predictions, semantic_id, clone_id,
61
61
  // Legacy input support
62
62
  type, action, }) {
63
63
  this.id = id;
@@ -82,6 +82,7 @@ class AACButton {
82
82
  this.visibility = visibility;
83
83
  this.directActivate = directActivate;
84
84
  this.parameters = parameters;
85
+ this.predictions = predictions;
85
86
  this.semantic_id = semantic_id;
86
87
  this.clone_id = clone_id;
87
88
  // Legacy mapping: if no semanticAction provided, derive from legacy `action` first
@@ -1226,6 +1226,12 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1226
1226
  ...cellStyle,
1227
1227
  ...inlineStyle, // Inline styles override referenced styles
1228
1228
  },
1229
+ // Store predictions directly on button for easy access
1230
+ predictions: predictionWords?.length
1231
+ ? [...predictionWords]
1232
+ : gridPredictionWords.length > 0
1233
+ ? [...gridPredictionWords]
1234
+ : undefined,
1229
1235
  parameters: {
1230
1236
  pluginMetadata: pluginMetadata, // Store full plugin metadata for future use
1231
1237
  grid3Commands: detectedCommands, // Store detected command metadata
@@ -113,6 +113,7 @@ export interface AACButton {
113
113
  parameters?: {
114
114
  [key: string]: any;
115
115
  };
116
+ predictions?: string[];
116
117
  semantic_id?: string;
117
118
  clone_id?: string;
118
119
  }
@@ -39,6 +39,20 @@ export declare class MetricsCalculator {
39
39
  * Calculate what percentage of links to this board match semantic_id/clone_id
40
40
  */
41
41
  private calculateBoardLinkPercentages;
42
+ /**
43
+ * Calculate metrics for word forms (smart grammar predictions)
44
+ *
45
+ * Word forms are dynamically generated and not part of the tree structure.
46
+ * Their effort is calculated as:
47
+ * - Parent button's cumulative effort (to reach the button)
48
+ * - + Effort to select the word form from its position in predictions grid
49
+ *
50
+ * @param tree - The AAC tree
51
+ * @param buttons - Already calculated button metrics
52
+ * @param options - Metrics options
53
+ * @returns Array of word form button metrics
54
+ */
55
+ private calculateWordFormMetrics;
42
56
  /**
43
57
  * Calculate grid dimensions from the tree
44
58
  */
@@ -83,6 +83,11 @@ class MetricsCalculator {
83
83
  });
84
84
  // Update buttons using dynamic spelling effort if applicable
85
85
  const buttons = Array.from(knownButtons.values()).sort((a, b) => a.effort - b.effort);
86
+ // Calculate metrics for word forms (smart grammar predictions)
87
+ const wordFormMetrics = this.calculateWordFormMetrics(tree, buttons, options);
88
+ buttons.push(...wordFormMetrics);
89
+ // Re-sort after adding word forms
90
+ buttons.sort((a, b) => a.effort - b.effort);
86
91
  // Calculate grid dimensions
87
92
  const grid = this.calculateGridDimensions(tree);
88
93
  // Identify prediction metrics
@@ -560,6 +565,75 @@ class MetricsCalculator {
560
565
  boardPcts['all'] = totalLinks;
561
566
  return boardPcts;
562
567
  }
568
+ /**
569
+ * Calculate metrics for word forms (smart grammar predictions)
570
+ *
571
+ * Word forms are dynamically generated and not part of the tree structure.
572
+ * Their effort is calculated as:
573
+ * - Parent button's cumulative effort (to reach the button)
574
+ * - + Effort to select the word form from its position in predictions grid
575
+ *
576
+ * @param tree - The AAC tree
577
+ * @param buttons - Already calculated button metrics
578
+ * @param options - Metrics options
579
+ * @returns Array of word form button metrics
580
+ */
581
+ calculateWordFormMetrics(tree, buttons, _options = {}) {
582
+ const wordFormMetrics = [];
583
+ // Track which buttons already exist to avoid duplicates
584
+ const existingLabels = new Map();
585
+ buttons.forEach((btn) => existingLabels.set(btn.label.toLowerCase(), btn));
586
+ // Iterate through all pages to find buttons with predictions
587
+ Object.values(tree.pages).forEach((page) => {
588
+ page.grid.forEach((row) => {
589
+ row.forEach((btn) => {
590
+ if (!btn || !btn.predictions || btn.predictions.length === 0)
591
+ return;
592
+ // Find the parent button's metrics
593
+ const parentMetrics = buttons.find((b) => b.id === btn.id);
594
+ if (!parentMetrics)
595
+ return;
596
+ // Calculate effort for each word form
597
+ btn.predictions.forEach((wordForm, index) => {
598
+ const wordFormLower = wordForm.toLowerCase();
599
+ // Skip if this word form already exists as a regular button
600
+ if (existingLabels.has(wordFormLower)) {
601
+ return;
602
+ }
603
+ // Calculate effort based on position in predictions array
604
+ // Assume predictions are displayed in a grid layout (e.g., 2 columns)
605
+ const predictionsGridCols = 2; // Typical predictions layout
606
+ const predictionRowIndex = Math.floor(index / predictionsGridCols);
607
+ const predictionColIndex = index % predictionsGridCols;
608
+ // Calculate visual scan effort to reach this word form position
609
+ // Using similar logic to button scanning effort
610
+ const predictionPriorItems = predictionRowIndex * predictionsGridCols + predictionColIndex;
611
+ const predictionSelectionEffort = (0, effort_1.visualScanEffort)(predictionPriorItems);
612
+ // Word form effort = parent button's cumulative effort + selection effort
613
+ const wordFormEffort = parentMetrics.effort + predictionSelectionEffort;
614
+ // Mark as word form with a special ID pattern
615
+ const wordFormBtn = {
616
+ id: `${btn.id}_wordform_${index}`,
617
+ label: wordForm,
618
+ level: parentMetrics.level,
619
+ effort: wordFormEffort,
620
+ count: 1,
621
+ semantic_id: parentMetrics.semantic_id,
622
+ clone_id: parentMetrics.clone_id,
623
+ temporary_home_id: parentMetrics.temporary_home_id,
624
+ is_word_form: true, // Mark this as a word form metric
625
+ parent_button_id: btn.id, // Track parent button
626
+ parent_button_label: parentMetrics.label, // Track parent label
627
+ };
628
+ wordFormMetrics.push(wordFormBtn);
629
+ existingLabels.set(wordFormLower, wordFormBtn);
630
+ });
631
+ });
632
+ });
633
+ });
634
+ console.log(`📝 Calculated ${wordFormMetrics.length} word form metrics from predictions`);
635
+ return wordFormMetrics;
636
+ }
563
637
  /**
564
638
  * Calculate grid dimensions from the tree
565
639
  */
@@ -18,6 +18,9 @@ export interface ButtonMetrics {
18
18
  temporary_home_id?: string;
19
19
  comp_level?: number;
20
20
  comp_effort?: number;
21
+ is_word_form?: boolean;
22
+ parent_button_id?: string;
23
+ parent_button_label?: string;
21
24
  }
22
25
  /**
23
26
  * Board/page level analysis result
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@willwade/aac-processors",
3
- "version": "0.0.25",
3
+ "version": "0.0.27",
4
4
  "description": "A comprehensive TypeScript library for processing AAC (Augmentative and Alternative Communication) file formats with translation support",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",