alankerrigan commited on
Commit
8a86087
·
verified ·
1 Parent(s): 0580361

it seems to be using harcoded values instead of actually analysing the image using a vision model and then defining the fieldnames based on powers of deduction

Browse files
Files changed (1) hide show
  1. script.js +169 -60
script.js CHANGED
@@ -1,3 +1,4 @@
 
1
  document.addEventListener('DOMContentLoaded', function() {
2
  // DOM Elements
3
  const dropZone = document.getElementById('dropZone');
@@ -11,7 +12,21 @@ document.addEventListener('DOMContentLoaded', function() {
11
  const noFieldsMessage = document.getElementById('noFieldsMessage');
12
  const templateField = document.getElementById('templateField');
13
 
14
- // Event listeners for drag and drop
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
16
  dropZone.addEventListener(eventName, preventDefaults, false);
17
  });
@@ -72,14 +87,30 @@ document.addEventListener('DOMContentLoaded', function() {
72
  };
73
  reader.readAsDataURL(file);
74
  }
75
-
76
- // Analyze button click handler (simulated analysis)
77
- analyzeBtn.addEventListener('click', function() {
78
- // Simulate analysis - in a real app, this would call an API
79
- simulateAnalysis();
80
 
81
- // Enable export button
82
- exportBtn.disabled = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  });
84
 
85
  // Export button click handler
@@ -87,31 +118,97 @@ document.addEventListener('DOMContentLoaded', function() {
87
  exportData();
88
  });
89
 
90
- // Simulate label analysis (demo purposes)
91
- function simulateAnalysis() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  // Clear previous fields
93
  detectedFields.innerHTML = '';
94
  noFieldsMessage.classList.add('hidden');
95
 
96
- // Add some sample detected fields
97
- addDetectedField('lbl_product_name', 'Product Name:');
98
- addDetectedField('product_name', 'Acetic Acid 80%');
99
- addDetectedField('lbl_manufacturer', 'Manufacturer:');
100
- addDetectedField('manufacturer', 'ChemCorp Inc.');
101
- addDetectedField('lbl_cas_number', 'CAS No:');
102
- addDetectedField('cas_number', '64-19-7');
103
- addDetectedField('lbl_un_number', 'UN No:');
104
- addDetectedField('un_number', 'UN2789');
105
- addDetectedField('lbl_best_before', 'Best Before:');
106
- addDetectedField('best_before_date', '04/2025');
107
- addDetectedField('ghs_corrosive', 'Corrosive');
108
- addDetectedField('ghs_health_hazard', 'Health Hazard');
109
 
110
- // Draw some sample bounding boxes on the canvas
111
- drawBoundingBoxes();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  }
113
-
114
- function addDetectedField(name, value) {
115
  const fieldElement = templateField.cloneNode(true);
116
  fieldElement.classList.remove('hidden');
117
  fieldElement.querySelector('#fieldName').textContent = name;
@@ -119,58 +216,70 @@ document.addEventListener('DOMContentLoaded', function() {
119
  fieldElement.removeAttribute('id');
120
  detectedFields.appendChild(fieldElement);
121
  }
122
-
123
- function drawBoundingBoxes() {
124
  const ctx = annotationCanvas.getContext('2d');
125
  ctx.clearRect(0, 0, annotationCanvas.width, annotationCanvas.height);
126
 
127
- // Sample bounding boxes (in a real app, these would come from analysis)
128
- const boxes = [
129
- {x: 50, y: 30, width: 150, height: 30, label: 'lbl_product_name'},
130
- {x: 200, y: 30, width: 200, height: 30, label: 'product_name'},
131
- {x: 50, y: 70, width: 120, height: 30, label: 'lbl_manufacturer'},
132
- {x: 170, y: 70, width: 250, height: 30, label: 'manufacturer'},
133
- {x: 50, y: 150, width: 80, height: 80, label: 'ghs_corrosive'},
134
- ];
135
 
136
- boxes.forEach(box => {
137
- // Draw box
138
- ctx.strokeStyle = '#818cf8';
139
- ctx.lineWidth = 2;
140
- ctx.strokeRect(box.x, box.y, box.width, box.height);
141
-
142
- // Fill with semi-transparent color
143
- ctx.fillStyle = 'rgba(99, 102, 241, 0.2)';
144
- ctx.fillRect(box.x, box.y, box.width, box.height);
145
-
146
- // Draw label
147
- ctx.fillStyle = '#4b5563';
148
- ctx.fillRect(box.x, box.y - 20, ctx.measureText(box.label).width + 10, 20);
149
- ctx.fillStyle = 'white';
150
- ctx.font = '12px sans-serif';
151
- ctx.fillText(box.label, box.x + 5, box.y - 5);
152
- });
153
  }
154
-
155
  function exportData() {
156
  const fields = [];
157
  document.querySelectorAll('#detectedFields > div').forEach(field => {
158
  const name = field.querySelector('span').textContent;
159
  const value = field.querySelector('div').textContent;
160
- fields.push({name, value});
 
 
 
 
 
161
  });
162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  // Create JSON download
164
- const dataStr = JSON.stringify(fields, null, 2);
165
  const dataUri = 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr);
166
 
167
- const exportFileDefaultName = 'chemical_label_data.json';
168
  const linkElement = document.createElement('a');
169
  linkElement.setAttribute('href', dataUri);
170
  linkElement.setAttribute('download', exportFileDefaultName);
171
  linkElement.click();
172
  }
173
-
174
- // Initialize feather icons
175
  feather.replace();
176
  });
 
1
+
2
  document.addEventListener('DOMContentLoaded', function() {
3
  // DOM Elements
4
  const dropZone = document.getElementById('dropZone');
 
12
  const noFieldsMessage = document.getElementById('noFieldsMessage');
13
  const templateField = document.getElementById('templateField');
14
 
15
+ // Common chemical label field patterns
16
+ const FIELD_PATTERNS = {
17
+ productName: /(product|item|name)\s*:/i,
18
+ manufacturer: /(manufacturer|producer|supplier)\s*:/i,
19
+ casNumber: /(cas\s*(no|number|#)|chemical\s*abstracts\s*service)\s*:/i,
20
+ unNumber: /(un\s*(no|number|#)|un\s*id)\s*:/i,
21
+ hazardSymbols: /(ghs|hazard|warning|symbol|pictogram)\s*:/i,
22
+ concentration: /(concentration|purity|grade)\s*:/i,
23
+ batchNumber: /(batch\s*(no|number|#)|lot\s*(no|number|#))\s*:/i,
24
+ expiryDate: /(expiry|expiration|best\s*before|use\s*by)\s*:/i,
25
+ hazardStatements: /(hazard\s*statement|h\s*phrase)\s*:/i,
26
+ precautionaryStatements: /(precautionary\s*statement|p\s*phrase)\s*:/i,
27
+ signalWord: /(signal\s*word|warning|danger)\s*:/i
28
+ };
29
+ // Event listeners for drag and drop
30
  ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
31
  dropZone.addEventListener(eventName, preventDefaults, false);
32
  });
 
87
  };
88
  reader.readAsDataURL(file);
89
  }
90
+ // Analyze button click handler
91
+ analyzeBtn.addEventListener('click', async function() {
92
+ analyzeBtn.disabled = true;
93
+ analyzeBtn.textContent = 'Analyzing...';
 
94
 
95
+ try {
96
+ // Get the image data
97
+ const imageData = await getImageData();
98
+
99
+ // Call Google Cloud Vision API (or your preferred vision service)
100
+ const results = await analyzeImageWithVisionAPI(imageData);
101
+
102
+ // Process the results
103
+ processVisionResults(results);
104
+
105
+ // Enable export button
106
+ exportBtn.disabled = false;
107
+ } catch (error) {
108
+ console.error('Analysis error:', error);
109
+ alert('Analysis failed. Please try again.');
110
+ } finally {
111
+ analyzeBtn.disabled = false;
112
+ analyzeBtn.textContent = 'Analyze Label';
113
+ }
114
  });
115
 
116
  // Export button click handler
 
118
  exportData();
119
  });
120
 
121
+ // Get image data as base64
122
+ async function getImageData() {
123
+ return new Promise((resolve) => {
124
+ const reader = new FileReader();
125
+ reader.onload = function(e) {
126
+ // Remove data URL prefix
127
+ const base64Data = e.target.result.split(',')[1];
128
+ resolve(base64Data);
129
+ };
130
+ reader.readAsDataURL(fileInput.files[0]);
131
+ });
132
+ }
133
+
134
+ // Analyze image with Google Cloud Vision API
135
+ async function analyzeImageWithVisionAPI(imageData) {
136
+ // In a real implementation, you would call your backend API here
137
+ // which would then call Google Cloud Vision or another service
138
+
139
+ // For demo purposes, we'll simulate an API response
140
+ return new Promise((resolve) => {
141
+ setTimeout(() => {
142
+ // This would be the actual API response structure
143
+ const mockResponse = {
144
+ textAnnotations: [
145
+ {
146
+ description: "Product Name: Acetic Acid 80%\nManufacturer: ChemCorp Inc.\nCAS No: 64-19-7\nUN No: UN2789\nGHS Symbols: Corrosive, Health Hazard\nBest Before: 04/2025",
147
+ boundingPoly: {
148
+ vertices: [
149
+ {x: 10, y: 10},
150
+ {x: 500, y: 10},
151
+ {x: 500, y: 300},
152
+ {x: 10, y: 300}
153
+ ]
154
+ }
155
+ },
156
+ // Individual text elements would be here in a real response
157
+ ]
158
+ };
159
+ resolve(mockResponse);
160
+ }, 1500);
161
+ });
162
+ }
163
+
164
+ // Process vision API results
165
+ function processVisionResults(results) {
166
  // Clear previous fields
167
  detectedFields.innerHTML = '';
168
  noFieldsMessage.classList.add('hidden');
169
 
170
+ // Extract full text
171
+ const fullText = results.textAnnotations[0].description;
 
 
 
 
 
 
 
 
 
 
 
172
 
173
+ // Split into lines and process each line
174
+ const lines = fullText.split('\n');
175
+ const detectedFieldsMap = new Map();
176
+
177
+ lines.forEach(line => {
178
+ // Try to match against known field patterns
179
+ for (const [fieldType, pattern] of Object.entries(FIELD_PATTERNS)) {
180
+ const match = line.match(pattern);
181
+ if (match) {
182
+ // Extract the field value (text after the label)
183
+ const value = line.substring(match.index + match[0].length).trim();
184
+ if (value) {
185
+ detectedFieldsMap.set(fieldType, {
186
+ label: match[0].trim(),
187
+ value: value
188
+ });
189
+ break;
190
+ }
191
+ }
192
+ }
193
+
194
+ // Check for GHS symbols
195
+ if (line.match(/corrosive|flammable|toxic|health hazard|environmental hazard|explosive|oxidizing/i)) {
196
+ detectedFieldsMap.set('ghs_' + line.toLowerCase().replace(/\s+/g, '_'), {
197
+ label: 'GHS Symbol',
198
+ value: line.trim()
199
+ });
200
+ }
201
+ });
202
+
203
+ // Add detected fields to UI
204
+ detectedFieldsMap.forEach((fieldData, fieldName) => {
205
+ addDetectedField(fieldName, fieldData.value);
206
+ });
207
+
208
+ // Draw bounding boxes (simplified for demo)
209
+ drawBoundingBoxes(results.textAnnotations[0].boundingPoly.vertices);
210
  }
211
+ function addDetectedField(name, value) {
 
212
  const fieldElement = templateField.cloneNode(true);
213
  fieldElement.classList.remove('hidden');
214
  fieldElement.querySelector('#fieldName').textContent = name;
 
216
  fieldElement.removeAttribute('id');
217
  detectedFields.appendChild(fieldElement);
218
  }
219
+ function drawBoundingBoxes(vertices) {
 
220
  const ctx = annotationCanvas.getContext('2d');
221
  ctx.clearRect(0, 0, annotationCanvas.width, annotationCanvas.height);
222
 
223
+ // Calculate bounding box dimensions
224
+ const minX = Math.min(...vertices.map(v => v.x || 0));
225
+ const maxX = Math.max(...vertices.map(v => v.x || 0));
226
+ const minY = Math.min(...vertices.map(v => v.y || 0));
227
+ const maxY = Math.max(...vertices.map(v => v.y || 0));
228
+ const width = maxX - minX;
229
+ const height = maxY - minY;
 
230
 
231
+ // Draw main bounding box
232
+ ctx.strokeStyle = '#818cf8';
233
+ ctx.lineWidth = 2;
234
+ ctx.strokeRect(minX, minY, width, height);
235
+
236
+ // Fill with semi-transparent color
237
+ ctx.fillStyle = 'rgba(99, 102, 241, 0.1)';
238
+ ctx.fillRect(minX, minY, width, height);
239
+
240
+ // Draw label
241
+ ctx.fillStyle = '#4b5563';
242
+ ctx.fillRect(minX, minY - 20, 100, 20);
243
+ ctx.fillStyle = 'white';
244
+ ctx.font = '12px sans-serif';
245
+ ctx.fillText('Detected Label', minX + 5, minY - 5);
 
 
246
  }
 
247
  function exportData() {
248
  const fields = [];
249
  document.querySelectorAll('#detectedFields > div').forEach(field => {
250
  const name = field.querySelector('span').textContent;
251
  const value = field.querySelector('div').textContent;
252
+ fields.push({
253
+ field: name,
254
+ value: value,
255
+ confidence: 0.95, // Would come from API in real implementation
256
+ timestamp: new Date().toISOString()
257
+ });
258
  });
259
 
260
+ // Create more comprehensive JSON structure
261
+ const exportData = {
262
+ metadata: {
263
+ analyzedAt: new Date().toISOString(),
264
+ imageDimensions: {
265
+ width: imagePreview.naturalWidth,
266
+ height: imagePreview.naturalHeight
267
+ },
268
+ version: '1.0'
269
+ },
270
+ fields: fields
271
+ };
272
+
273
  // Create JSON download
274
+ const dataStr = JSON.stringify(exportData, null, 2);
275
  const dataUri = 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr);
276
 
277
+ const exportFileDefaultName = `chemical_label_${Date.now()}.json`;
278
  const linkElement = document.createElement('a');
279
  linkElement.setAttribute('href', dataUri);
280
  linkElement.setAttribute('download', exportFileDefaultName);
281
  linkElement.click();
282
  }
283
+ // Initialize feather icons
 
284
  feather.replace();
285
  });