CoruNethron commited on
Commit
17ab7fa
·
verified ·
1 Parent(s): b3e05e8

This filter: `(element) => element.tokens.length>0` renders 0 objects matching filter for both classes. It's wrong as all the "tokens" arrays are not empty. - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +482 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Json Obj Filter
3
- emoji: 🚀
4
- colorFrom: purple
5
- colorTo: indigo
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: json-obj-filter
3
+ emoji: 🐳
4
+ colorFrom: green
5
+ colorTo: green
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,482 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>JSON Data Filter Analyzer</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <script>
10
+ tailwind.config = {
11
+ theme: {
12
+ extend: {
13
+ colors: {
14
+ primary: '#4F46E5',
15
+ secondary: '#818CF8',
16
+ dark: '#1E293B',
17
+ light: '#F1F5F9',
18
+ success: '#10B981',
19
+ warning: '#F59E0B',
20
+ danger: '#EF4444'
21
+ }
22
+ }
23
+ }
24
+ }
25
+ </script>
26
+ <style>
27
+ .drop-zone {
28
+ border: 2px dashed #cbd5e1;
29
+ transition: all 0.3s ease;
30
+ }
31
+ .drop-zone.active {
32
+ border-color: #4F46E5;
33
+ background-color: rgba(79, 70, 229, 0.05);
34
+ }
35
+ .code-block {
36
+ font-family: 'Courier New', monospace;
37
+ font-size: 0.9rem;
38
+ }
39
+ .result-card {
40
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
41
+ }
42
+ .result-card:hover {
43
+ transform: translateY(-5px);
44
+ box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
45
+ }
46
+ .filter-input {
47
+ transition: border-color 0.3s ease;
48
+ }
49
+ .filter-input:focus {
50
+ outline: none;
51
+ border-color: #4F46E5;
52
+ box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.2);
53
+ }
54
+ .syntax-highlight {
55
+ color: #4F46E5;
56
+ font-weight: 500;
57
+ }
58
+ </style>
59
+ </head>
60
+ <body class="bg-light min-h-screen">
61
+ <div class="max-w-6xl mx-auto px-4 py-8">
62
+ <!-- Header -->
63
+ <header class="text-center mb-12">
64
+ <h1 class="text-3xl md:text-4xl font-bold text-dark mb-2">JSON Data Filter Analyzer</h1>
65
+ <p class="text-gray-600 max-w-2xl mx-auto">Upload JSON files, apply custom filter functions, and analyze your data in real-time</p>
66
+ </header>
67
+
68
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
69
+ <!-- Left Column - File Upload & Instructions -->
70
+ <div class="space-y-8">
71
+ <!-- File Upload Section -->
72
+ <div class="bg-white rounded-xl shadow-md p-6">
73
+ <h2 class="text-xl font-semibold text-dark mb-4">Upload JSON File</h2>
74
+ <div id="dropZone" class="drop-zone rounded-lg p-8 text-center cursor-pointer mb-4">
75
+ <i class="fas fa-cloud-upload-alt text-4xl text-secondary mb-3"></i>
76
+ <p class="font-medium text-gray-700">Drag & drop your JSON file here</p>
77
+ <p class="text-gray-500 text-sm mt-1">or</p>
78
+ <label for="fileInput" class="mt-3 inline-block px-4 py-2 bg-primary text-white rounded-lg cursor-pointer hover:bg-secondary transition-colors">
79
+ <i class="fas fa-file-upload mr-2"></i>Browse Files
80
+ </label>
81
+ <input type="file" id="fileInput" class="hidden" accept=".json">
82
+ </div>
83
+ <div id="fileInfo" class="hidden bg-gray-50 rounded-lg p-3 text-sm">
84
+ <div class="flex items-center">
85
+ <i class="fas fa-file-code text-secondary text-xl mr-3"></i>
86
+ <div>
87
+ <p class="font-medium" id="fileName">example.json</p>
88
+ <p class="text-gray-500" id="fileSize">0 KB</p>
89
+ </div>
90
+ <button id="clearFile" class="ml-auto text-gray-500 hover:text-danger">
91
+ <i class="fas fa-times"></i>
92
+ </button>
93
+ </div>
94
+ </div>
95
+ </div>
96
+
97
+ <!-- Instructions Section -->
98
+ <div class="bg-white rounded-xl shadow-md p-6">
99
+ <h2 class="text-xl font-semibold text-dark mb-4">How to Use</h2>
100
+ <div class="space-y-4">
101
+ <div class="flex items-start">
102
+ <div class="bg-primary/10 text-primary rounded-full w-8 h-8 flex items-center justify-center mr-3 flex-shrink-0">
103
+ <span>1</span>
104
+ </div>
105
+ <div>
106
+ <h3 class="font-medium text-dark">Upload JSON File</h3>
107
+ <p class="text-gray-600 text-sm">Your JSON file should contain an array of objects with <span class="font-mono">hasText</span> (boolean) and <span class="font-mono">tokens</span> (array of objects with <span class="font-mono">id</span> and <span class="font-mono">piece</span>) properties.</p>
108
+ </div>
109
+ </div>
110
+
111
+ <div class="flex items-start">
112
+ <div class="bg-primary/10 text-primary rounded-full w-8 h-8 flex items-center justify-center mr-3 flex-shrink-0">
113
+ <span>2</span>
114
+ </div>
115
+ <div>
116
+ <h3 class="font-medium text-dark">Enter Filter Function</h3>
117
+ <p class="text-gray-600 text-sm">Write an arrow function to filter your data. Example:</p>
118
+ <div class="bg-gray-50 p-3 rounded-lg mt-2 text-sm code-block">
119
+ <span class="syntax-highlight">(element)</span> => <span class="syntax-highlight">element</span>.tokens.filter(<span class="syntax-highlight">(x)</span> => x.piece.length > 4).length > 5
120
+ </div>
121
+ </div>
122
+ </div>
123
+
124
+ <div class="flex items-start">
125
+ <div class="bg-primary/10 text-primary rounded-full w-8 h-8 flex items-center justify-center mr-3 flex-shrink-0">
126
+ <span>3</span>
127
+ </div>
128
+ <div>
129
+ <h3 class="font-medium text-dark">View Results</h3>
130
+ <p class="text-gray-600 text-sm">The app will automatically calculate and display counts for objects where <span class="font-mono">hasText</span> is true and false that pass your filter.</p>
131
+ </div>
132
+ </div>
133
+ </div>
134
+ </div>
135
+ </div>
136
+
137
+ <!-- Right Column - Filter & Results -->
138
+ <div class="space-y-8">
139
+ <!-- Filter Input Section -->
140
+ <div class="bg-white rounded-xl shadow-md p-6">
141
+ <h2 class="text-xl font-semibold text-dark mb-4">Filter Function</h2>
142
+ <div class="mb-4">
143
+ <label for="filterInput" class="block text-gray-700 mb-2">Enter your arrow function:</label>
144
+ <div class="relative">
145
+ <textarea
146
+ id="filterInput"
147
+ rows="4"
148
+ placeholder="(element) => element.tokens.filter((x) => x.piece.length > 4).length > 5"
149
+ class="filter-input w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-all"
150
+ ></textarea>
151
+ <div class="absolute top-3 right-3 text-gray-400">
152
+ <i class="fas fa-code"></i>
153
+ </div>
154
+ </div>
155
+ </div>
156
+ <div id="filterError" class="hidden bg-red-50 border-l-4 border-danger text-danger p-3 mb-4">
157
+ <i class="fas fa-exclamation-circle mr-2"></i>
158
+ <span id="errorMessage"></span>
159
+ </div>
160
+ <div class="flex items-center justify-between">
161
+ <button id="exampleBtn" class="text-secondary hover:text-primary flex items-center">
162
+ <i class="fas fa-lightbulb mr-2"></i>Load Example
163
+ </button>
164
+ <button id="validateBtn" class="px-4 py-2 bg-primary text-white rounded-lg hover:bg-secondary transition-colors">
165
+ <i class="fas fa-check-circle mr-2"></i>Validate Function
166
+ </button>
167
+ </div>
168
+ </div>
169
+
170
+ <!-- Results Section -->
171
+ <div class="bg-white rounded-xl shadow-md p-6">
172
+ <h2 class="text-xl font-semibold text-dark mb-4">Analysis Results</h2>
173
+ <div id="resultsContainer" class="grid grid-cols-1 md:grid-cols-2 gap-4">
174
+ <div class="result-card bg-gradient-to-br from-green-50 to-green-100 border border-green-200 rounded-xl p-5">
175
+ <div class="flex items-center mb-3">
176
+ <div class="bg-success/20 text-success rounded-full w-10 h-10 flex items-center justify-center mr-3">
177
+ <i class="fas fa-check"></i>
178
+ </div>
179
+ <h3 class="font-semibold text-dark">hasText = true</h3>
180
+ </div>
181
+ <div class="text-center">
182
+ <p class="text-4xl font-bold text-success" id="countTrue">0</p>
183
+ <p class="text-gray-600 mt-1">Objects matching filter</p>
184
+ </div>
185
+ </div>
186
+
187
+ <div class="result-card bg-gradient-to-br from-blue-50 to-blue-100 border border-blue-200 rounded-xl p-5">
188
+ <div class="flex items-center mb-3">
189
+ <div class="bg-secondary/20 text-secondary rounded-full w-10 h-10 flex items-center justify-center mr-3">
190
+ <i class="fas fa-times"></i>
191
+ </div>
192
+ <h3 class="font-semibold text-dark">hasText = false</h3>
193
+ </div>
194
+ <div class="text-center">
195
+ <p class="text-4xl font-bold text-secondary" id="countFalse">0</p>
196
+ <p class="text-gray-600 mt-1">Objects matching filter</p>
197
+ </div>
198
+ </div>
199
+
200
+ <div class="col-span-full mt-4">
201
+ <div class="bg-gray-50 rounded-lg p-4">
202
+ <div class="flex justify-between items-center mb-2">
203
+ <h3 class="font-medium text-dark">Summary</h3>
204
+ <span class="text-sm text-gray-500" id="totalObjects">Total objects: 0</span>
205
+ </div>
206
+ <div class="h-4 bg-gray-200 rounded-full overflow-hidden">
207
+ <div id="progressBar" class="h-full bg-primary rounded-full" style="width: 0%"></div>
208
+ </div>
209
+ <div class="flex justify-between mt-2 text-sm">
210
+ <div>
211
+ <span class="text-success font-medium" id="percentTrue">0%</span>
212
+ <span>hasText=true</span>
213
+ </div>
214
+ <div>
215
+ <span class="text-secondary font-medium" id="percentFalse">0%</span>
216
+ <span>hasText=false</span>
217
+ </div>
218
+ </div>
219
+ </div>
220
+ </div>
221
+ </div>
222
+
223
+ <div id="noResults" class="hidden text-center py-8">
224
+ <i class="fas fa-chart-pie text-4xl text-gray-300 mb-3"></i>
225
+ <p class="text-gray-500">Enter a filter function and upload a JSON file to see results</p>
226
+ </div>
227
+ </div>
228
+ </div>
229
+ </div>
230
+ </div>
231
+
232
+ <script>
233
+ // Global variables
234
+ let jsonData = [];
235
+ let filterFunction = null;
236
+
237
+ // DOM Elements
238
+ const dropZone = document.getElementById('dropZone');
239
+ const fileInput = document.getElementById('fileInput');
240
+ const fileInfo = document.getElementById('fileInfo');
241
+ const fileName = document.getElementById('fileName');
242
+ const fileSize = document.getElementById('fileSize');
243
+ const clearFile = document.getElementById('clearFile');
244
+ const filterInput = document.getElementById('filterInput');
245
+ const filterError = document.getElementById('filterError');
246
+ const errorMessage = document.getElementById('errorMessage');
247
+ const countTrue = document.getElementById('countTrue');
248
+ const countFalse = document.getElementById('countFalse');
249
+ const totalObjects = document.getElementById('totalObjects');
250
+ const percentTrue = document.getElementById('percentTrue');
251
+ const percentFalse = document.getElementById('percentFalse');
252
+ const progressBar = document.getElementById('progressBar');
253
+ const noResults = document.getElementById('noResults');
254
+ const validateBtn = document.getElementById('validateBtn');
255
+ const exampleBtn = document.getElementById('exampleBtn');
256
+
257
+ // Event Listeners
258
+ fileInput.addEventListener('change', handleFileUpload);
259
+ clearFile.addEventListener('click', clearUploadedFile);
260
+ filterInput.addEventListener('input', debounce(processFilter, 500));
261
+ validateBtn.addEventListener('click', validateFilter);
262
+ exampleBtn.addEventListener('click', loadExample);
263
+
264
+ // Drag and drop events
265
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
266
+ dropZone.addEventListener(eventName, preventDefaults, false);
267
+ });
268
+
269
+ function preventDefaults(e) {
270
+ e.preventDefault();
271
+ e.stopPropagation();
272
+ }
273
+
274
+ ['dragenter', 'dragover'].forEach(eventName => {
275
+ dropZone.addEventListener(eventName, highlight, false);
276
+ });
277
+
278
+ ['dragleave', 'drop'].forEach(eventName => {
279
+ dropZone.addEventListener(eventName, unhighlight, false);
280
+ });
281
+
282
+ function highlight() {
283
+ dropZone.classList.add('active');
284
+ }
285
+
286
+ function unhighlight() {
287
+ dropZone.classList.remove('active');
288
+ }
289
+
290
+ dropZone.addEventListener('drop', handleDrop, false);
291
+
292
+ function handleDrop(e) {
293
+ const dt = e.dataTransfer;
294
+ const file = dt.files[0];
295
+ if (file && file.type === 'application/json') {
296
+ fileInput.files = dt.files;
297
+ handleFileUpload();
298
+ }
299
+ }
300
+
301
+ // File handling
302
+ function handleFileUpload() {
303
+ const file = fileInput.files[0];
304
+ if (!file) return;
305
+
306
+ fileName.textContent = file.name;
307
+ fileSize.textContent = formatFileSize(file.size);
308
+ fileInfo.classList.remove('hidden');
309
+
310
+ const reader = new FileReader();
311
+ reader.onload = function(e) {
312
+ try {
313
+ jsonData = JSON.parse(e.target.result);
314
+ processFilter();
315
+ } catch (error) {
316
+ showError('Error parsing JSON: ' + error.message);
317
+ }
318
+ };
319
+ reader.readAsText(file);
320
+ }
321
+
322
+ function clearUploadedFile() {
323
+ fileInput.value = '';
324
+ fileInfo.classList.add('hidden');
325
+ jsonData = [];
326
+ resetResults();
327
+ }
328
+
329
+ // Filter processing
330
+ function validateFilter() {
331
+ const filterStr = filterInput.value.trim();
332
+ if (!filterStr) {
333
+ showError('Please enter a filter function');
334
+ return;
335
+ }
336
+
337
+ try {
338
+ // Attempt to create the function
339
+ const func = new Function('element', `return (${filterStr})(element);`);
340
+
341
+ // Test with a sample object
342
+ const testObj = {
343
+ hasText: true,
344
+ tokens: [
345
+ {id: 1, piece: 'test'},
346
+ {id: 2, piece: 'example'}
347
+ ]
348
+ };
349
+
350
+ // Run the test
351
+ const result = func(testObj);
352
+ if (typeof result !== 'boolean') {
353
+ showError('Filter function must return a boolean value');
354
+ return;
355
+ }
356
+
357
+ // If successful, clear error
358
+ filterError.classList.add('hidden');
359
+ processFilter();
360
+ } catch (error) {
361
+ showError('Invalid function: ' + error.message);
362
+ }
363
+ }
364
+
365
+ function processFilter() {
366
+ const filterStr = filterInput.value.trim();
367
+
368
+ // Reset results
369
+ resetResults();
370
+
371
+ // Check if we have data and a filter
372
+ if (!jsonData.length || !filterStr) {
373
+ return;
374
+ }
375
+
376
+ try {
377
+ // Create the filter function
378
+ filterFunction = new Function('element', `return (${filterStr})(element);`);
379
+
380
+ // Clear any previous errors
381
+ filterError.classList.add('hidden');
382
+
383
+ // Process data
384
+ let trueCount = 0;
385
+ let falseCount = 0;
386
+
387
+ jsonData.forEach(element => {
388
+ try {
389
+ const passes = filterFunction(element);
390
+ if (passes) {
391
+ if (element.hasText === true) {
392
+ trueCount++;
393
+ } else if (element.hasText === false) {
394
+ falseCount++;
395
+ }
396
+ }
397
+ } catch (e) {
398
+ // Skip elements that cause errors
399
+ }
400
+ });
401
+
402
+ // Update UI
403
+ updateResults(trueCount, falseCount);
404
+ } catch (error) {
405
+ showError('Error in filter: ' + error.message);
406
+ }
407
+ }
408
+
409
+ function updateResults(trueCount, falseCount) {
410
+ const total = trueCount + falseCount;
411
+
412
+ countTrue.textContent = trueCount;
413
+ countFalse.textContent = falseCount;
414
+ totalObjects.textContent = `Total objects: ${jsonData.length}`;
415
+
416
+ if (total > 0) {
417
+ const truePercent = Math.round((trueCount / total) * 100);
418
+ const falsePercent = Math.round((falseCount / total) * 100);
419
+
420
+ percentTrue.textContent = `${truePercent}%`;
421
+ percentFalse.textContent = `${falsePercent}%`;
422
+
423
+ progressBar.style.width = `${truePercent}%`;
424
+
425
+ noResults.classList.add('hidden');
426
+ } else {
427
+ noResults.classList.remove('hidden');
428
+ }
429
+ }
430
+
431
+ function resetResults() {
432
+ countTrue.textContent = '0';
433
+ countFalse.textContent = '0';
434
+ totalObjects.textContent = 'Total objects: 0';
435
+ percentTrue.textContent = '0%';
436
+ percentFalse.textContent = '0%';
437
+ progressBar.style.width = '0%';
438
+
439
+ if (!jsonData.length || !filterInput.value.trim()) {
440
+ noResults.classList.remove('hidden');
441
+ }
442
+ }
443
+
444
+ function showError(message) {
445
+ errorMessage.textContent = message;
446
+ filterError.classList.remove('hidden');
447
+ }
448
+
449
+ function loadExample() {
450
+ filterInput.value = '(element) => element.tokens.filter((x) => x.piece.length > 4).length > 2';
451
+ processFilter();
452
+ }
453
+
454
+ // Utility functions
455
+ function debounce(func, wait) {
456
+ let timeout;
457
+ return function executedFunction(...args) {
458
+ const later = () => {
459
+ clearTimeout(timeout);
460
+ func(...args);
461
+ };
462
+ clearTimeout(timeout);
463
+ timeout = setTimeout(later, wait);
464
+ };
465
+ }
466
+
467
+ function formatFileSize(bytes) {
468
+ if (bytes === 0) return '0 Bytes';
469
+ const k = 1024;
470
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
471
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
472
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
473
+ }
474
+
475
+ // Initialize with example if needed
476
+ window.addEventListener('DOMContentLoaded', () => {
477
+ // Uncomment to load example on startup
478
+ // loadExample();
479
+ });
480
+ </script>
481
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=CoruNethron/json-obj-filter" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
482
+ </html>