nickdigger commited on
Commit
e7a342e
Β·
verified Β·
1 Parent(s): c3402f9

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +170 -174
app.py CHANGED
@@ -47,179 +47,6 @@ TITLE = """
47
  <p><em>Q&A added β€’ All fields editable β€’ Clear buttons β€’ Select text and type to replace</em></p>
48
  </div>
49
  <hr>
50
-
51
- <script>
52
- // Auto-replace selected text when typing
53
- document.addEventListener('DOMContentLoaded', function() {
54
- // Find all textareas and text inputs
55
- const textFields = document.querySelectorAll('textarea, input[type="text"]');
56
-
57
- textFields.forEach(field => {
58
- field.addEventListener('keydown', function(e) {
59
- // If there's selected text and user types a character
60
- if (this.selectionStart !== this.selectionEnd && e.key.length === 1) {
61
- // Let the default behavior replace the selected text
62
- return;
63
- }
64
- });
65
- });
66
-
67
- // Extension communication function
68
- window.getJoyCaptionData = function() {
69
- const data = {};
70
-
71
- try {
72
- // Get all textareas and inputs
73
- const allFields = document.querySelectorAll('textarea, input[type="text"]');
74
-
75
- allFields.forEach(field => {
76
- const value = field.value || '';
77
- const placeholder = field.placeholder || '';
78
-
79
- // Input fields
80
- if (placeholder.includes('keyword')) {
81
- data.keywords = value.trim();
82
- } else if (placeholder.includes('mention') || placeholder.includes('Make sure')) {
83
- data.custom_instructions = value.trim();
84
- } else if (placeholder.includes('question') || placeholder.includes('Ask a Question')) {
85
- data.question = value.trim();
86
- }
87
- // Output fields with substantial content
88
- else if (value.trim().length > 20) {
89
- if (placeholder.includes('engaging')) {
90
- data.caption_engaging = value.trim();
91
- } else if (placeholder.includes('casual') || placeholder.includes('friend')) {
92
- data.caption_casual_friend = value.trim();
93
- } else if (placeholder.includes('keywords caption')) {
94
- data.caption_keywords = value.trim();
95
- } else if (placeholder.includes('answer')) {
96
- data.answer = value.trim();
97
- }
98
- // Fallback: assign to first available caption slot
99
- else if (!data.caption_engaging && field.tagName === 'TEXTAREA') {
100
- data.caption_engaging = value.trim();
101
- } else if (!data.caption_casual_friend && field.tagName === 'TEXTAREA') {
102
- data.caption_casual_friend = value.trim();
103
- } else if (!data.caption_keywords && field.tagName === 'TEXTAREA') {
104
- data.caption_keywords = value.trim();
105
- } else if (!data.answer && field.tagName === 'TEXTAREA') {
106
- data.answer = value.trim();
107
- }
108
- }
109
- });
110
-
111
- // Get uploaded image
112
- const images = document.querySelectorAll('img[src*="blob:"], img[src*="data:"], img[src*="gradio"]');
113
- if (images.length > 0) {
114
- data.image_url = images[0].src;
115
- }
116
-
117
- console.log('JoyCaption data prepared for extension:', data);
118
- return data;
119
-
120
- } catch (error) {
121
- console.error('Error preparing JoyCaption data:', error);
122
- return {};
123
- }
124
- };
125
-
126
- // Listen for extension requests
127
- window.addEventListener('message', function(event) {
128
- if (event.data && event.data.action === 'getJoyCaptionData') {
129
- const data = window.getJoyCaptionData();
130
- event.source.postMessage({
131
- action: 'joyCaptionData',
132
- data: data,
133
- success: Object.keys(data).length > 0
134
- }, event.origin);
135
- }
136
- });
137
-
138
- // Export functionality
139
- window.downloadJoyCaptionData = function() {
140
- try {
141
- const rawData = window.getJoyCaptionData();
142
-
143
- if (Object.keys(rawData).length === 0) {
144
- alert('❌ No data found to export. Make sure you have generated captions first.');
145
- return;
146
- }
147
-
148
- // Package data for export
149
- const exportData = {
150
- timestamp: new Date().toISOString(),
151
- source: 'JoyCaption',
152
- data: rawData
153
- };
154
-
155
- // Create and download JSON file
156
- const jsonString = JSON.stringify(exportData, null, 2);
157
- const blob = new Blob([jsonString], { type: 'application/json' });
158
- const url = URL.createObjectURL(blob);
159
-
160
- const a = document.createElement('a');
161
- a.href = url;
162
- a.download = `joycaption_data_${new Date().toISOString().slice(0, 16).replace(/:/g, '-')}.json`;
163
- document.body.appendChild(a);
164
- a.click();
165
- document.body.removeChild(a);
166
- URL.revokeObjectURL(url);
167
-
168
- alert(`βœ… Downloaded JoyCaption data with ${Object.keys(rawData).length} fields!`);
169
- console.log('πŸ“₯ Downloaded data:', exportData);
170
-
171
- } catch (error) {
172
- console.error('❌ Export error:', error);
173
- alert('❌ Export failed: ' + error.message);
174
- }
175
- };
176
-
177
- // Create export button
178
- function createExportButton() {
179
- // Remove any existing button first
180
- const existingBtn = document.getElementById('joyCaption-export-btn');
181
- if (existingBtn) existingBtn.remove();
182
-
183
- // Create a floating export button
184
- const exportBtn = document.createElement('button');
185
- exportBtn.id = 'joyCaption-export-btn';
186
- exportBtn.innerHTML = 'πŸ“₯ Export JoyCaption Data';
187
- exportBtn.style.cssText = `
188
- position: fixed;
189
- top: 20px;
190
- right: 20px;
191
- z-index: 9999;
192
- background: linear-gradient(135deg, #ff6b35, #f7931e);
193
- color: white;
194
- border: none;
195
- padding: 12px 20px;
196
- border-radius: 25px;
197
- font-weight: 600;
198
- cursor: pointer;
199
- box-shadow: 0 4px 12px rgba(255, 107, 53, 0.3);
200
- transition: all 0.3s ease;
201
- `;
202
-
203
- exportBtn.addEventListener('mouseover', () => {
204
- exportBtn.style.transform = 'translateY(-2px)';
205
- exportBtn.style.boxShadow = '0 6px 16px rgba(255, 107, 53, 0.4)';
206
- });
207
-
208
- exportBtn.addEventListener('mouseout', () => {
209
- exportBtn.style.transform = 'translateY(0)';
210
- exportBtn.style.boxShadow = '0 4px 12px rgba(255, 107, 53, 0.3)';
211
- });
212
-
213
- exportBtn.addEventListener('click', window.downloadJoyCaptionData);
214
-
215
- document.body.appendChild(exportBtn);
216
- console.log('βœ… Export button created');
217
- }
218
-
219
- // Auto-create button when page loads
220
- setTimeout(createExportButton, 3000); // Wait for Gradio to load
221
- });
222
- </script>
223
  """
224
 
225
  print("πŸš€ Loading Sequential Three-Tone JoyCaption system... v2.1")
@@ -496,8 +323,177 @@ def answer_question(image, question):
496
 
497
  return result if result else "❌ No answer generated"
498
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
499
  # Gradio Interface
500
- with gr.Blocks(title="Sequential Three-Tone JoyCaption", theme=gr.themes.Soft()) as demo:
501
  gr.HTML(TITLE)
502
 
503
  with gr.Row():
 
47
  <p><em>Q&A added β€’ All fields editable β€’ Clear buttons β€’ Select text and type to replace</em></p>
48
  </div>
49
  <hr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  """
51
 
52
  print("πŸš€ Loading Sequential Three-Tone JoyCaption system... v2.1")
 
323
 
324
  return result if result else "❌ No answer generated"
325
 
326
+ # JavaScript for export functionality
327
+ EXPORT_JS = """
328
+ <script>
329
+ // JoyCaption Export System
330
+ (function() {
331
+ console.log('πŸš€ Initializing JoyCaption Export System...');
332
+
333
+ // Extract data from page fields
334
+ window.getJoyCaptionData = function() {
335
+ console.log('πŸ“Š Extracting JoyCaption data...');
336
+ const data = {};
337
+
338
+ // Get all textareas and inputs from the page
339
+ const allInputs = document.querySelectorAll('textarea, input[type="text"]');
340
+
341
+ allInputs.forEach((field, index) => {
342
+ const placeholder = (field.placeholder || '').toLowerCase();
343
+ const value = field.value ? field.value.trim() : '';
344
+
345
+ // Skip empty fields
346
+ if (!value) return;
347
+
348
+ // Map based on placeholder text and content length
349
+ if (placeholder.includes('engaging') || (value.length > 50 && placeholder.includes('generate engaging'))) {
350
+ data.caption_engaging = value;
351
+ } else if (placeholder.includes('casual') || placeholder.includes('friend') || (value.length > 50 && placeholder.includes('generate casual'))) {
352
+ data.caption_casual_friend = value;
353
+ } else if (placeholder.includes('keyword') && value.length > 50) {
354
+ data.caption_keywords = value;
355
+ } else if (placeholder.includes('keyword') && value.length <= 50) {
356
+ data.keywords = value;
357
+ } else if (placeholder.includes('custom') || placeholder.includes('make sure') || placeholder.includes('mention')) {
358
+ data.custom_instructions = value;
359
+ } else if (placeholder.includes('question')) {
360
+ data.question = value;
361
+ } else if (value.length > 50) {
362
+ // Long text likely a caption
363
+ if (!data.caption_engaging) data.caption_engaging = value;
364
+ else if (!data.caption_casual_friend) data.caption_casual_friend = value;
365
+ else if (!data.caption_keywords) data.caption_keywords = value;
366
+ }
367
+ });
368
+
369
+ // Add image URLs if present
370
+ const images = document.querySelectorAll('img');
371
+ const imageUrls = [];
372
+ images.forEach(img => {
373
+ if (img.src && !img.src.includes('data:') && !img.src.includes('blob:')) {
374
+ imageUrls.push(img.src);
375
+ }
376
+ });
377
+
378
+ if (imageUrls.length > 0) {
379
+ data.image_urls = imageUrls;
380
+ }
381
+
382
+ console.log('πŸ“¦ Extracted data:', data);
383
+ return data;
384
+ };
385
+
386
+ // Listen for extension requests
387
+ window.addEventListener('message', function(event) {
388
+ if (event.data && event.data.action === 'getJoyCaptionData') {
389
+ const data = window.getJoyCaptionData();
390
+ event.source.postMessage({
391
+ action: 'joyCaptionData',
392
+ data: data,
393
+ success: Object.keys(data).length > 0
394
+ }, event.origin);
395
+ }
396
+ });
397
+
398
+ // Export functionality
399
+ window.downloadJoyCaptionData = function() {
400
+ try {
401
+ const rawData = window.getJoyCaptionData();
402
+
403
+ if (Object.keys(rawData).length === 0) {
404
+ alert('❌ No data found to export. Make sure you have generated captions first.');
405
+ return;
406
+ }
407
+
408
+ // Package data for export
409
+ const exportData = {
410
+ timestamp: new Date().toISOString(),
411
+ source: 'JoyCaption',
412
+ data: rawData
413
+ };
414
+
415
+ // Create and download JSON file
416
+ const jsonString = JSON.stringify(exportData, null, 2);
417
+ const blob = new Blob([jsonString], { type: 'application/json' });
418
+ const url = URL.createObjectURL(blob);
419
+
420
+ const a = document.createElement('a');
421
+ a.href = url;
422
+ a.download = `joycaption_data_${new Date().toISOString().slice(0, 16).replace(/:/g, '-')}.json`;
423
+ document.body.appendChild(a);
424
+ a.click();
425
+ document.body.removeChild(a);
426
+ URL.revokeObjectURL(url);
427
+
428
+ alert(`βœ… Downloaded JoyCaption data with ${Object.keys(rawData).length} fields!`);
429
+ console.log('πŸ“₯ Downloaded data:', exportData);
430
+
431
+ } catch (error) {
432
+ console.error('❌ Export error:', error);
433
+ alert('❌ Export failed: ' + error.message);
434
+ }
435
+ };
436
+
437
+ // Create export button
438
+ function createExportButton() {
439
+ // Remove any existing button first
440
+ const existingBtn = document.getElementById('joyCaption-export-btn');
441
+ if (existingBtn) existingBtn.remove();
442
+
443
+ // Create a floating export button
444
+ const exportBtn = document.createElement('button');
445
+ exportBtn.id = 'joyCaption-export-btn';
446
+ exportBtn.innerHTML = 'πŸ“₯ Export JoyCaption Data';
447
+ exportBtn.style.cssText = `
448
+ position: fixed;
449
+ top: 20px;
450
+ right: 20px;
451
+ z-index: 9999;
452
+ background: linear-gradient(135deg, #ff6b35, #f7931e);
453
+ color: white;
454
+ border: none;
455
+ padding: 12px 20px;
456
+ border-radius: 25px;
457
+ font-weight: 600;
458
+ cursor: pointer;
459
+ box-shadow: 0 4px 12px rgba(255, 107, 53, 0.3);
460
+ transition: all 0.3s ease;
461
+ `;
462
+
463
+ exportBtn.addEventListener('mouseover', () => {
464
+ exportBtn.style.transform = 'translateY(-2px)';
465
+ exportBtn.style.boxShadow = '0 6px 16px rgba(255, 107, 53, 0.4)';
466
+ });
467
+
468
+ exportBtn.addEventListener('mouseout', () => {
469
+ exportBtn.style.transform = 'translateY(0)';
470
+ exportBtn.style.boxShadow = '0 4px 12px rgba(255, 107, 53, 0.3)';
471
+ });
472
+
473
+ exportBtn.addEventListener('click', window.downloadJoyCaptionData);
474
+
475
+ document.body.appendChild(exportBtn);
476
+ console.log('βœ… Export button created and attached to body');
477
+ }
478
+
479
+ // Multiple attempts to create button after Gradio loads
480
+ setTimeout(createExportButton, 1000);
481
+ setTimeout(createExportButton, 3000);
482
+ setTimeout(createExportButton, 5000);
483
+
484
+ // Also try when DOM changes (Gradio dynamic loading)
485
+ const observer = new MutationObserver(() => {
486
+ if (!document.getElementById('joyCaption-export-btn')) {
487
+ createExportButton();
488
+ }
489
+ });
490
+ observer.observe(document.body, { childList: true, subtree: true });
491
+ })();
492
+ </script>
493
+ """
494
+
495
  # Gradio Interface
496
+ with gr.Blocks(title="Sequential Three-Tone JoyCaption", theme=gr.themes.Soft(), head=EXPORT_JS) as demo:
497
  gr.HTML(TITLE)
498
 
499
  with gr.Row():