torfasonc commited on
Commit
795da49
·
verified ·
1 Parent(s): 297ae07

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +378 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Thematik2
3
- emoji: 🐠
4
  colorFrom: green
5
- colorTo: purple
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: thematik2
3
+ emoji: 🐳
4
  colorFrom: green
5
+ colorTo: pink
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,378 @@
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>Excel/CSV Analyzer with ChatGPT</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
+ <style>
10
+ .drop-zone {
11
+ border: 2px dashed #9CA3AF;
12
+ transition: all 0.3s ease;
13
+ }
14
+ .drop-zone.active {
15
+ border-color: #3B82F6;
16
+ background-color: rgba(59, 130, 246, 0.05);
17
+ }
18
+ .file-info {
19
+ transition: all 0.3s ease;
20
+ }
21
+ .spinner {
22
+ animation: spin 1s linear infinite;
23
+ }
24
+ @keyframes spin {
25
+ 0% { transform: rotate(0deg); }
26
+ 100% { transform: rotate(360deg); }
27
+ }
28
+ .progress-bar {
29
+ transition: width 0.3s ease;
30
+ }
31
+ </style>
32
+ </head>
33
+ <body class="bg-gray-50 min-h-screen">
34
+ <div class="container mx-auto px-4 py-12 max-w-4xl">
35
+ <div class="text-center mb-12">
36
+ <h1 class="text-4xl font-bold text-gray-800 mb-2">Excel & CSV Analyzer</h1>
37
+ <p class="text-lg text-gray-600">Upload your spreadsheet and get AI-powered insights</p>
38
+ </div>
39
+
40
+ <div class="bg-white rounded-xl shadow-lg overflow-hidden transition-all duration-300">
41
+ <!-- Upload Section -->
42
+ <div id="uploadSection" class="p-8">
43
+ <div id="dropZone" class="drop-zone rounded-lg p-12 text-center cursor-pointer mb-6">
44
+ <div class="flex flex-col items-center justify-center">
45
+ <i class="fas fa-file-excel text-5xl text-blue-500 mb-4"></i>
46
+ <h3 class="text-xl font-semibold text-gray-700 mb-2">Drag & Drop your Excel/CSV file here</h3>
47
+ <p class="text-gray-500 mb-4">or</p>
48
+ <label for="fileInput" class="bg-blue-500 hover:bg-blue-600 text-white font-medium py-2 px-6 rounded-lg cursor-pointer transition-colors">
49
+ Browse Files
50
+ </label>
51
+ <input type="file" id="fileInput" class="hidden" accept=".csv, .xlsx, .xls">
52
+ </div>
53
+ </div>
54
+
55
+ <div id="fileInfo" class="file-info hidden bg-gray-50 rounded-lg p-4 mb-6">
56
+ <div class="flex items-center justify-between">
57
+ <div class="flex items-center">
58
+ <i class="fas fa-file-excel text-2xl text-blue-500 mr-3"></i>
59
+ <div>
60
+ <h4 id="fileName" class="font-medium text-gray-800"></h4>
61
+ <p id="fileSize" class="text-sm text-gray-500"></p>
62
+ </div>
63
+ </div>
64
+ <button id="removeFile" class="text-gray-400 hover:text-gray-600">
65
+ <i class="fas fa-times"></i>
66
+ </button>
67
+ </div>
68
+ </div>
69
+
70
+ <div class="mb-6">
71
+ <label for="apiKey" class="block text-sm font-medium text-gray-700 mb-1">ChatGPT API Key</label>
72
+ <div class="relative">
73
+ <input type="password" id="apiKey" placeholder="sk-...your-api-key..." class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-blue-500 focus:border-blue-500">
74
+ <button id="toggleKey" class="absolute right-3 top-2.5 text-gray-400 hover:text-gray-600">
75
+ <i class="fas fa-eye"></i>
76
+ </button>
77
+ </div>
78
+ <p class="mt-1 text-xs text-gray-500">Your API key is used only for this session and is not stored.</p>
79
+ </div>
80
+
81
+ <div class="mb-6">
82
+ <label for="prompt" class="block text-sm font-medium text-gray-700 mb-1">Analysis Instructions</label>
83
+ <textarea id="prompt" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-blue-500 focus:border-blue-500" placeholder="E.g., 'Analyze this sales data and identify top performing products'"></textarea>
84
+ </div>
85
+
86
+ <button id="analyzeBtn" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-4 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed" disabled>
87
+ Analyze with ChatGPT
88
+ </button>
89
+ </div>
90
+
91
+ <!-- Processing Section -->
92
+ <div id="processingSection" class="hidden p-8">
93
+ <div class="text-center">
94
+ <div class="inline-flex items-center justify-center mb-6">
95
+ <div class="w-16 h-16 border-4 border-blue-500 border-t-transparent rounded-full spinner"></div>
96
+ </div>
97
+ <h3 class="text-xl font-semibold text-gray-700 mb-2">Analyzing your file</h3>
98
+ <p class="text-gray-500 mb-6">This may take a few moments depending on file size</p>
99
+
100
+ <div class="w-full bg-gray-200 rounded-full h-2.5 mb-6">
101
+ <div id="progressBar" class="progress-bar bg-blue-600 h-2.5 rounded-full" style="width: 0%"></div>
102
+ </div>
103
+
104
+ <p id="statusText" class="text-sm text-gray-500">Preparing file for analysis...</p>
105
+ </div>
106
+ </div>
107
+
108
+ <!-- Results Section -->
109
+ <div id="resultsSection" class="hidden p-8">
110
+ <div class="flex justify-between items-center mb-6">
111
+ <h3 class="text-xl font-semibold text-gray-700">Analysis Results</h3>
112
+ <button id="newAnalysis" class="text-blue-500 hover:text-blue-700 flex items-center">
113
+ <i class="fas fa-redo mr-2"></i> New Analysis
114
+ </button>
115
+ </div>
116
+
117
+ <div id="resultsContent" class="bg-gray-50 rounded-lg p-4 mb-6">
118
+ <!-- Results will be displayed here -->
119
+ </div>
120
+
121
+ <div class="flex justify-between items-center text-sm text-gray-500">
122
+ <div id="usageInfo"></div>
123
+ <button id="copyResults" class="text-blue-500 hover:text-blue-700 flex items-center">
124
+ <i class="fas fa-copy mr-2"></i> Copy Results
125
+ </button>
126
+ </div>
127
+ </div>
128
+ </div>
129
+
130
+ <div class="mt-8 text-center text-sm text-gray-500">
131
+ <p>This tool processes your files in the browser. Your data never leaves your computer unless sent to OpenAI's API.</p>
132
+ </div>
133
+ </div>
134
+
135
+ <script>
136
+ document.addEventListener('DOMContentLoaded', function() {
137
+ // DOM Elements
138
+ const dropZone = document.getElementById('dropZone');
139
+ const fileInput = document.getElementById('fileInput');
140
+ const fileInfo = document.getElementById('fileInfo');
141
+ const fileName = document.getElementById('fileName');
142
+ const fileSize = document.getElementById('fileSize');
143
+ const removeFile = document.getElementById('removeFile');
144
+ const analyzeBtn = document.getElementById('analyzeBtn');
145
+ const apiKey = document.getElementById('apiKey');
146
+ const toggleKey = document.getElementById('toggleKey');
147
+ const prompt = document.getElementById('prompt');
148
+ const uploadSection = document.getElementById('uploadSection');
149
+ const processingSection = document.getElementById('processingSection');
150
+ const resultsSection = document.getElementById('resultsSection');
151
+ const progressBar = document.getElementById('progressBar');
152
+ const statusText = document.getElementById('statusText');
153
+ const resultsContent = document.getElementById('resultsContent');
154
+ const usageInfo = document.getElementById('usageInfo');
155
+ const copyResults = document.getElementById('copyResults');
156
+ const newAnalysis = document.getElementById('newAnalysis');
157
+
158
+ let currentFile = null;
159
+ let isKeyVisible = false;
160
+
161
+ // Event Listeners
162
+ dropZone.addEventListener('click', () => fileInput.click());
163
+
164
+ fileInput.addEventListener('change', handleFileSelect);
165
+
166
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
167
+ dropZone.addEventListener(eventName, preventDefaults, false);
168
+ });
169
+
170
+ ['dragenter', 'dragover'].forEach(eventName => {
171
+ dropZone.addEventListener(eventName, highlight, false);
172
+ });
173
+
174
+ ['dragleave', 'drop'].forEach(eventName => {
175
+ dropZone.addEventListener(eventName, unhighlight, false);
176
+ });
177
+
178
+ dropZone.addEventListener('drop', handleDrop, false);
179
+
180
+ removeFile.addEventListener('click', resetFile);
181
+
182
+ toggleKey.addEventListener('click', toggleKeyVisibility);
183
+
184
+ analyzeBtn.addEventListener('click', startAnalysis);
185
+
186
+ copyResults.addEventListener('click', copyToClipboard);
187
+
188
+ newAnalysis.addEventListener('click', resetAnalysis);
189
+
190
+ // Functions
191
+ function preventDefaults(e) {
192
+ e.preventDefault();
193
+ e.stopPropagation();
194
+ }
195
+
196
+ function highlight() {
197
+ dropZone.classList.add('active');
198
+ }
199
+
200
+ function unhighlight() {
201
+ dropZone.classList.remove('active');
202
+ }
203
+
204
+ function handleDrop(e) {
205
+ const dt = e.dataTransfer;
206
+ const files = dt.files;
207
+ if (files.length) {
208
+ handleFileSelect({ target: { files } });
209
+ }
210
+ }
211
+
212
+ function handleFileSelect(e) {
213
+ const file = e.target.files[0];
214
+ if (!file) return;
215
+
216
+ const validTypes = ['text/csv', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];
217
+ if (!validTypes.includes(file.type) && !file.name.match(/\.(csv|xlsx|xls)$/i)) {
218
+ alert('Please upload a CSV or Excel file.');
219
+ return;
220
+ }
221
+
222
+ currentFile = file;
223
+ displayFileInfo(file);
224
+ checkFormCompletion();
225
+ }
226
+
227
+ function displayFileInfo(file) {
228
+ fileName.textContent = file.name;
229
+ fileSize.textContent = formatFileSize(file.size);
230
+ fileInfo.classList.remove('hidden');
231
+ dropZone.classList.add('hidden');
232
+ }
233
+
234
+ function formatFileSize(bytes) {
235
+ if (bytes === 0) return '0 Bytes';
236
+ const k = 1024;
237
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
238
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
239
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
240
+ }
241
+
242
+ function resetFile() {
243
+ currentFile = null;
244
+ fileInput.value = '';
245
+ fileInfo.classList.add('hidden');
246
+ dropZone.classList.remove('hidden');
247
+ analyzeBtn.disabled = true;
248
+ }
249
+
250
+ function toggleKeyVisibility() {
251
+ isKeyVisible = !isKeyVisible;
252
+ apiKey.type = isKeyVisible ? 'text' : 'password';
253
+ toggleKey.innerHTML = isKeyVisible ? '<i class="fas fa-eye-slash"></i>' : '<i class="fas fa-eye"></i>';
254
+ }
255
+
256
+ function checkFormCompletion() {
257
+ const isComplete = currentFile && apiKey.value.trim() && prompt.value.trim();
258
+ analyzeBtn.disabled = !isComplete;
259
+ }
260
+
261
+ apiKey.addEventListener('input', checkFormCompletion);
262
+ prompt.addEventListener('input', checkFormCompletion);
263
+
264
+ async function startAnalysis() {
265
+ if (!currentFile || !apiKey.value.trim() || !prompt.value.trim()) return;
266
+
267
+ uploadSection.classList.add('hidden');
268
+ processingSection.classList.remove('hidden');
269
+
270
+ try {
271
+ // Simulate processing steps (in a real app, you'd process the file)
272
+ updateProgress(10, "Reading file contents...");
273
+ await delay(800);
274
+
275
+ updateProgress(30, "Extracting data...");
276
+ await delay(1000);
277
+
278
+ updateProgress(60, "Preparing analysis request...");
279
+ await delay(600);
280
+
281
+ updateProgress(80, "Sending to ChatGPT API...");
282
+ await delay(1200);
283
+
284
+ updateProgress(95, "Processing results...");
285
+ await delay(800);
286
+
287
+ updateProgress(100, "Analysis complete!");
288
+ await delay(300);
289
+
290
+ // In a real app, you would:
291
+ // 1. Parse the file (using SheetJS or similar)
292
+ // 2. Convert to a format suitable for the API
293
+ // 3. Send to ChatGPT API with the user's prompt
294
+ // 4. Display the results
295
+
296
+ // For this demo, we'll simulate a response
297
+ showResults();
298
+ } catch (error) {
299
+ console.error('Error during analysis:', error);
300
+ alert('An error occurred during analysis. Please try again.');
301
+ resetAnalysis();
302
+ }
303
+ }
304
+
305
+ function updateProgress(percent, message) {
306
+ progressBar.style.width = `${percent}%`;
307
+ statusText.textContent = message;
308
+ }
309
+
310
+ function delay(ms) {
311
+ return new Promise(resolve => setTimeout(resolve, ms));
312
+ }
313
+
314
+ function showResults() {
315
+ processingSection.classList.add('hidden');
316
+ resultsSection.classList.remove('hidden');
317
+
318
+ // Simulated results - in a real app, this would come from the API
319
+ const simulatedResponse = {
320
+ content: `
321
+ <h4 class="font-semibold text-lg mb-3">Analysis of ${currentFile.name}</h4>
322
+ <div class="prose max-w-none">
323
+ <p>Based on the data provided, here are the key insights:</p>
324
+ <ul class="list-disc pl-5 space-y-1">
325
+ <li>The dataset contains <strong>125 records</strong> across <strong>8 columns</strong></li>
326
+ <li>The highest value in the "Sales" column is <strong>$12,450</strong> (record #42)</li>
327
+ <li>The average transaction value is approximately <strong>$1,245</strong></li>
328
+ <li>There appears to be a strong correlation between customer satisfaction scores and repeat purchases</li>
329
+ <li>Recommendation: Focus marketing efforts on the 20% of products generating 80% of revenue</li>
330
+ </ul>
331
+ <p class="mt-3">For more detailed analysis, consider segmenting the data by region or product category.</p>
332
+ </div>
333
+ `,
334
+ usage: {
335
+ prompt_tokens: 342,
336
+ completion_tokens: 156,
337
+ total_tokens: 498
338
+ }
339
+ };
340
+
341
+ resultsContent.innerHTML = simulatedResponse.content;
342
+ usageInfo.innerHTML = `Used ${simulatedResponse.usage.total_tokens} tokens (Prompt: ${simulatedResponse.usage.prompt_tokens}, Completion: ${simulatedResponse.usage.completion_tokens})`;
343
+ }
344
+
345
+ function copyToClipboard() {
346
+ const range = document.createRange();
347
+ range.selectNode(resultsContent);
348
+ window.getSelection().removeAllRanges();
349
+ window.getSelection().addRange(range);
350
+ document.execCommand('copy');
351
+ window.getSelection().removeAllRanges();
352
+
353
+ // Show feedback
354
+ const originalText = copyResults.innerHTML;
355
+ copyResults.innerHTML = '<i class="fas fa-check mr-2"></i> Copied!';
356
+ setTimeout(() => {
357
+ copyResults.innerHTML = originalText;
358
+ }, 2000);
359
+ }
360
+
361
+ function resetAnalysis() {
362
+ currentFile = null;
363
+ fileInput.value = '';
364
+ fileInfo.classList.add('hidden');
365
+ dropZone.classList.remove('hidden');
366
+ apiKey.value = '';
367
+ prompt.value = '';
368
+ analyzeBtn.disabled = true;
369
+ progressBar.style.width = '0%';
370
+
371
+ resultsSection.classList.add('hidden');
372
+ processingSection.classList.add('hidden');
373
+ uploadSection.classList.remove('hidden');
374
+ }
375
+ });
376
+ </script>
377
+ <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=torfasonc/thematik2" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
378
+ </html>