tester343 commited on
Commit
3eaaa39
·
verified ·
1 Parent(s): 7bbdd4f

Update app_enhanced.py

Browse files
Files changed (1) hide show
  1. app_enhanced.py +68 -92
app_enhanced.py CHANGED
@@ -118,6 +118,7 @@ def generate_comic_gpu(video_path, user_dir, frames_dir, metadata_path, target_p
118
  raw_moments = [{'text': s.content, 'start': s.start.total_seconds(), 'end': s.end.total_seconds()} for s in valid_subs]
119
 
120
  if target_pages <= 0: target_pages = 1
 
121
  panels_per_page = 5
122
  total_panels_needed = target_pages * panels_per_page
123
 
@@ -176,11 +177,8 @@ def generate_comic_gpu(video_path, user_dir, frames_dir, metadata_path, target_p
176
  elif '!' in dialogue and dialogue.isupper(): b_type = 'reaction'
177
  elif '?' in dialogue: b_type = 'speech'
178
 
179
- # Use simpler positioning logic for the backend; user adjusts in frontend
180
- # Just putting default offsets
181
- bx, by = 50, 50
182
-
183
- b = bubble(dialog=dialogue, bubble_offset_x=bx, bubble_offset_y=by, type=b_type)
184
  bubbles_list.append(b)
185
 
186
  pages = []
@@ -329,44 +327,48 @@ INDEX_HTML = '''
329
  @keyframes ball { 0%{background-position:0 50%} 100%{background-position:100px 50%} }
330
 
331
  /* ========================================= */
332
- /* 🎨 NEW POLYGON TEMPLATE LAYOUT CSS */
333
  /* ========================================= */
334
-
335
  .comic-wrapper { max-width: 1050px; margin: 0 auto; }
336
  .page-wrapper { margin: 30px auto; display: flex; flex-direction: column; align-items: center; }
337
  .page-title { text-align: center; color: #333; margin-bottom: 10px; font-size: 18px; font-weight: bold; }
338
 
339
- /*
340
- The Comic Page Container
341
- Width: 1000px, Height: 710px
342
- Overflow must be VISIBLE so bubbles can pop out if needed,
343
- but we usually want them contained.
344
- Actually, to fix "missing bubbles", we must allow them to sit on top of everything.
345
- */
346
  .comic-page {
347
  background: white;
348
  width: 1000px;
349
  height: 710px;
350
  box-shadow: 0 4px 10px rgba(0,0,0,0.1);
351
  position: relative;
352
- /* Ensure bubbles (children of this) are not hidden by panel clipping */
353
  z-index: 1;
354
  }
355
 
356
- /*
357
- PANELS:
358
- Now defined with specific bounding boxes so images are not stretched/zoomed incorrectly.
359
- Each panel has overflow:hidden to clip the image, but the bubbles will be siblings, not children.
360
- */
 
 
 
 
 
 
 
361
  .panel {
362
  position: absolute;
363
  background: #eee;
364
  cursor: pointer;
365
  overflow: hidden;
366
- z-index: 0;
 
367
  }
368
- .panel.selected { filter: brightness(0.9) sepia(0.2); z-index: 0; outline: 3px solid #2196F3; }
369
 
 
 
 
370
  .panel img {
371
  width: 100%;
372
  height: 100%;
@@ -377,76 +379,72 @@ INDEX_HTML = '''
377
  .panel img.pannable { cursor: grab; }
378
  .panel img.panning { cursor: grabbing; }
379
 
 
 
 
 
 
380
  /* --- TIER 1 (Y: 0 - 350) --- */
381
 
382
  /* Panel 0 (Top Left)
383
- Starts at 0, ends at ~635.
384
- Polygon: (0,0) -> (635.2, 0) -> (588.2, 350) -> (0, 350)
385
- Box Width: ~636px. Box Height: 350px.
386
  */
387
  .panel-0 {
388
- top: 0; left: 0; width: 636px; height: 350px;
389
- clip-path: polygon(0% 0%, 100% 0%, 92.5% 100%, 0% 100%);
390
  }
391
 
392
  /* Panel 1 (Top Right)
393
- Starts at ~588 (to overlap/fit), ends at 1000.
394
- Polygon: (635.2 + gap) ... actually lets follow the user coords:
395
- Divider Top: 635.2, Bottom: 588.2.
396
- So Right Panel starts after the divider.
397
- Let's define Right Panel Box:
398
- Left: 588px (min X), Width: 412px (1000-588).
399
- Clip: (Top-Left of box is 588). Top-Left coord of polygon is 635.2. Relative X = 635.2 - 588 = 47.2.
400
- So polygon starts at X=47.2px relative to box.
401
  */
402
  .panel-1 {
403
- top: 0; left: 588px; width: 412px; height: 350px;
404
- clip-path: polygon(11.5% 0%, 100% 0%, 100% 100%, 0% 100%);
405
  }
406
 
407
- /* --- TIER 2 (Y: 360 - 710) Height 350 --- */
408
- /* Gutter is 10px, so T2 starts at 360px */
409
-
410
  /* Panel 2 (Bottom Left)
411
- Coords: (0,0) -> (293.2, 0) -> (326.2, 350) -> (0, 350)
412
- Box: Left 0, Width 327px.
 
 
413
  */
414
  .panel-2 {
415
- top: 360px; left: 0; width: 327px; height: 350px;
416
- clip-path: polygon(0% 0%, 89.6% 0%, 100% 100%, 0% 100%);
417
  }
418
 
419
  /* Panel 3 (Bottom Middle)
420
- Left Divider: Top 293.2, Bot 326.2.
421
- Right Divider: Top 617.2, Bot 666.2.
422
- Box Left: 293px. Width: 374px (667-293).
 
 
 
423
  */
424
  .panel-3 {
425
- top: 360px; left: 293px; width: 374px; height: 350px;
426
- clip-path: polygon(0% 0%, 86.6% 0%, 100% 100%, 8.8% 100%);
427
  }
428
 
429
  /* Panel 4 (Bottom Right)
430
- Right Divider: Top 617.2, Bot 666.2.
431
- Box Left: 617px. Width: 383px (1000-617).
 
432
  */
433
  .panel-4 {
434
- top: 360px; left: 617px; width: 383px; height: 350px;
435
- clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 12.8% 100%);
436
  }
437
 
438
- /* SPEECH BUBBLES */
439
- /* Positioned absolute relative to .comic-page now */
440
- .speech-bubble {
441
- position: absolute; display: flex; justify-content: center; align-items: center;
442
- width: 150px; height: 80px; min-width: 50px; min-height: 30px; box-sizing: border-box;
443
- z-index: 100; /* Above panels */
444
- cursor: move; font-family: 'Comic Neue', cursive; font-weight: bold;
445
- font-size: 13px; text-align: center;
446
- overflow: visible;
447
- line-height: 1.2;
448
- --tail-pos: 50%;
449
- }
450
 
451
  .bubble-text {
452
  padding: 0.5em;
@@ -465,10 +463,9 @@ INDEX_HTML = '''
465
  border-radius: inherit;
466
  }
467
 
468
- .speech-bubble.selected { outline: 2px dashed #4CAF50; z-index: 101; }
469
  .speech-bubble textarea { position: absolute; top:0; left:0; width:100%; height:100%; box-sizing:border-box; border:1px solid #4CAF50; background:rgba(255,255,255,0.95); text-align:center; padding:8px; z-index:102; resize:none; font: inherit; white-space: pre-wrap; }
470
 
471
- /* SPEECH BUBBLE CSS (Tails) */
472
  .speech-bubble.speech {
473
  --b: 3em; --h: 1.8em; --t: 0.6; --p: var(--tail-pos, 50%); --r: 1.2em;
474
  background: var(--bubble-fill-color, #4ECDC4);
@@ -736,14 +733,6 @@ INDEX_HTML = '''
736
 
737
  // UPDATED STATE RETRIEVAL
738
  // Bubbles are now children of comic-page, not panels.
739
- // Panels need to be associated with bubbles still for data consistency.
740
- // For simplicity, we will save bubbles as a list belonging to the page,
741
- // but the backend format expects bubbles inside panels.
742
- // We will attempt to reconstruct that structure roughly or just store them.
743
- // Actually, let's just store "page bubbles" separately in our new save format if needed,
744
- // OR we can map bubbles back to panels spatially.
745
- // SIMPLER APPROACH: Save the structure as it is visually (Page -> Panels, Page -> Bubbles).
746
-
747
  function getCurrentState() {
748
  const pages = [];
749
  document.querySelectorAll('.comic-page').forEach(p => {
@@ -805,10 +794,8 @@ INDEX_HTML = '''
805
  img.onmousedown = (e) => startPan(e, img);
806
  pDiv.appendChild(img);
807
 
808
- // Legacy support: if bubbles were inside panels
809
  (pan.bubbles || []).forEach(bData => {
810
- // Convert old relative coords (if any) to page relative?
811
- // Ideally data is standardized. We append to Page div, not pDiv.
812
  const b = createBubbleHTML(bData);
813
  div.appendChild(b);
814
  });
@@ -816,7 +803,7 @@ INDEX_HTML = '''
816
  div.appendChild(pDiv);
817
  });
818
 
819
- // 2. Render Page-Level Bubbles (New Structure)
820
  if(page.pageBubbles) {
821
  page.pageBubbles.forEach(bData => {
822
  div.appendChild(createBubbleHTML(bData));
@@ -869,8 +856,7 @@ INDEX_HTML = '''
869
  const panels = [];
870
  const pageBubbles = [];
871
 
872
- // Panel Geometry for Default Bubble Placement mapping
873
- // We have 5 panels. We know their rough centers.
874
  const panelCenters = [
875
  {x: 315, y: 175}, // 0
876
  {x: 790, y: 175}, // 1
@@ -886,21 +872,16 @@ INDEX_HTML = '''
886
  });
887
 
888
  if(p.bubbles && p.bubbles[j] && p.bubbles[j].dialog) {
889
- // Backend gives an offset relative to panel 0,0 usually.
890
- // But now panels have offsets.
891
- // Let's just place bubble near the center of the panel.
892
  const center = panelCenters[j % 5] || {x:500, y:350};
893
-
894
  pageBubbles.push({
895
  text: p.bubbles[j].dialog,
896
- left: (center.x - 75) + 'px', // Center - half bubble width
897
  top: (center.y - 40) + 'px',
898
  type: (p.bubbles[j].type || 'speech'),
899
  classes: `speech-bubble ${p.bubbles[j].type || 'speech'} tail-bottom`
900
  });
901
  }
902
  });
903
-
904
  return { panels: panels, pageBubbles: pageBubbles };
905
  });
906
  renderFromState(cleanData); saveDraft(true);
@@ -988,12 +969,7 @@ INDEX_HTML = '''
988
  }
989
 
990
  function addBubble() {
991
- // Add to the active page container
992
- // If no panel is selected, finding the active page is tricky.
993
- // We will default to the first page or the last clicked page context if we stored it.
994
- // For now, if a panel is selected, add to that panel's parent page.
995
  if(!selectedPanel) return alert("Select a panel to define which page to add to.");
996
-
997
  const pageDiv = selectedPanel.parentElement;
998
  const b = createBubbleHTML({ text: "Text", left: "50px", top: "50px", type: 'speech', classes: "speech-bubble speech tail-bottom" });
999
  pageDiv.appendChild(b); selectBubble(b); saveDraft(true);
 
118
  raw_moments = [{'text': s.content, 'start': s.start.total_seconds(), 'end': s.end.total_seconds()} for s in valid_subs]
119
 
120
  if target_pages <= 0: target_pages = 1
121
+ # 5 Panels for the specific template requested
122
  panels_per_page = 5
123
  total_panels_needed = target_pages * panels_per_page
124
 
 
177
  elif '!' in dialogue and dialogue.isupper(): b_type = 'reaction'
178
  elif '?' in dialogue: b_type = 'speech'
179
 
180
+ # Default placement; user will adjust in UI
181
+ b = bubble(dialog=dialogue, bubble_offset_x=50, bubble_offset_y=50, type=b_type)
 
 
 
182
  bubbles_list.append(b)
183
 
184
  pages = []
 
327
  @keyframes ball { 0%{background-position:0 50%} 100%{background-position:100px 50%} }
328
 
329
  /* ========================================= */
330
+ /* 🎨 POLYGON TEMPLATE LAYOUT CSS (FIXED) */
331
  /* ========================================= */
332
+
333
  .comic-wrapper { max-width: 1050px; margin: 0 auto; }
334
  .page-wrapper { margin: 30px auto; display: flex; flex-direction: column; align-items: center; }
335
  .page-title { text-align: center; color: #333; margin-bottom: 10px; font-size: 18px; font-weight: bold; }
336
 
 
 
 
 
 
 
 
337
  .comic-page {
338
  background: white;
339
  width: 1000px;
340
  height: 710px;
341
  box-shadow: 0 4px 10px rgba(0,0,0,0.1);
342
  position: relative;
343
+ /* Overflow visible so bubbles can pop out slightly if needed, but panels clip images */
344
  z-index: 1;
345
  }
346
 
347
+ /* BUBBLES are direct children of comic-page now, so they float above everything */
348
+ .speech-bubble {
349
+ position: absolute; display: flex; justify-content: center; align-items: center;
350
+ width: 150px; height: 80px; min-width: 50px; min-height: 30px; box-sizing: border-box;
351
+ z-index: 200; /* High z-index to stay above panels */
352
+ cursor: move; font-family: 'Comic Neue', cursive; font-weight: bold;
353
+ font-size: 13px; text-align: center;
354
+ overflow: visible;
355
+ line-height: 1.2;
356
+ --tail-pos: 50%;
357
+ }
358
+
359
  .panel {
360
  position: absolute;
361
  background: #eee;
362
  cursor: pointer;
363
  overflow: hidden;
364
+ z-index: 10;
365
+ border: none;
366
  }
367
+ .panel.selected { filter: brightness(0.9) sepia(0.2); outline: 3px solid #2196F3; z-index: 15; }
368
 
369
+ /* OBJECT FIT COVER FIX:
370
+ Images fill their defined bounding box, maintaining aspect ratio.
371
+ */
372
  .panel img {
373
  width: 100%;
374
  height: 100%;
 
379
  .panel img.pannable { cursor: grab; }
380
  .panel img.panning { cursor: grabbing; }
381
 
382
+ /*
383
+ CALCULATED COORDINATES WITH 10PX GUTTER
384
+ Total W: 1000, Row Height: 350. Gutter Y: 10px (350-360).
385
+ */
386
+
387
  /* --- TIER 1 (Y: 0 - 350) --- */
388
 
389
  /* Panel 0 (Top Left)
390
+ Line: (635.2, 0) to (588.2, 350).
391
+ Minus 5px for gutter.
392
+ TR: 630.2, BR: 583.2.
393
  */
394
  .panel-0 {
395
+ top: 0; left: 0; width: 631px; height: 350px;
396
+ clip-path: polygon(0% 0%, 630.2px 0%, 583.2px 100%, 0% 100%);
397
  }
398
 
399
  /* Panel 1 (Top Right)
400
+ Line: (635.2, 0) to (588.2, 350).
401
+ Plus 5px for gutter.
402
+ TL: 640.2, BL: 593.2.
403
+ Bounding Box: Starts at X=593. Width = 1000-593 = 407.
404
+ Poly Relative: TL(47.2, 0), BL(0.2, 350).
 
 
 
405
  */
406
  .panel-1 {
407
+ top: 0; left: 593px; width: 407px; height: 350px;
408
+ clip-path: polygon(47.2px 0%, 100% 0%, 100% 100%, 0.2px 100%);
409
  }
410
 
411
+ /* --- TIER 2 (Y: 360 - 710) --- */
412
+
 
413
  /* Panel 2 (Bottom Left)
414
+ Line Left: (293.2, 0) to (326.2, 350).
415
+ Minus 5px.
416
+ TR: 288.2, BR: 321.2.
417
+ Box Height: 350px. Top: 360px.
418
  */
419
  .panel-2 {
420
+ top: 360px; left: 0; width: 322px; height: 350px;
421
+ clip-path: polygon(0% 0%, 288.2px 0%, 321.2px 100%, 0% 100%);
422
  }
423
 
424
  /* Panel 3 (Bottom Middle)
425
+ Line Left (+5px): TL 298.2, BL 331.2.
426
+ Line Right (-5px): (617.2,0)->(666.2,350). TR 612.2, BR 661.2.
427
+ Box Start: 298px. Width: 662 - 298 = 364px.
428
+ Poly Relative:
429
+ TL: 0.2, BL: 33.2
430
+ TR: 314.2, BR: 363.2
431
  */
432
  .panel-3 {
433
+ top: 360px; left: 298px; width: 364px; height: 350px;
434
+ clip-path: polygon(0.2px 0%, 314.2px 0%, 363.2px 100%, 33.2px 100%);
435
  }
436
 
437
  /* Panel 4 (Bottom Right)
438
+ Line Right (+5px): TL 622.2, BL 671.2.
439
+ Box Start: 622px. Width: 378px.
440
+ Poly Relative: TL 0.2, BL 49.2.
441
  */
442
  .panel-4 {
443
+ top: 360px; left: 622px; width: 378px; height: 350px;
444
+ clip-path: polygon(0.2px 0%, 100% 0%, 100% 100%, 49.2px 100%);
445
  }
446
 
447
+ /* ... Bubbles CSS continued ... */
 
 
 
 
 
 
 
 
 
 
 
448
 
449
  .bubble-text {
450
  padding: 0.5em;
 
463
  border-radius: inherit;
464
  }
465
 
466
+ .speech-bubble.selected { outline: 2px dashed #4CAF50; z-index: 201; }
467
  .speech-bubble textarea { position: absolute; top:0; left:0; width:100%; height:100%; box-sizing:border-box; border:1px solid #4CAF50; background:rgba(255,255,255,0.95); text-align:center; padding:8px; z-index:102; resize:none; font: inherit; white-space: pre-wrap; }
468
 
 
469
  .speech-bubble.speech {
470
  --b: 3em; --h: 1.8em; --t: 0.6; --p: var(--tail-pos, 50%); --r: 1.2em;
471
  background: var(--bubble-fill-color, #4ECDC4);
 
733
 
734
  // UPDATED STATE RETRIEVAL
735
  // Bubbles are now children of comic-page, not panels.
 
 
 
 
 
 
 
 
736
  function getCurrentState() {
737
  const pages = [];
738
  document.querySelectorAll('.comic-page').forEach(p => {
 
794
  img.onmousedown = (e) => startPan(e, img);
795
  pDiv.appendChild(img);
796
 
797
+ // Legacy support for old saves
798
  (pan.bubbles || []).forEach(bData => {
 
 
799
  const b = createBubbleHTML(bData);
800
  div.appendChild(b);
801
  });
 
803
  div.appendChild(pDiv);
804
  });
805
 
806
+ // 2. Render Page-Level Bubbles
807
  if(page.pageBubbles) {
808
  page.pageBubbles.forEach(bData => {
809
  div.appendChild(createBubbleHTML(bData));
 
856
  const panels = [];
857
  const pageBubbles = [];
858
 
859
+ // Panel Geometry for Default Bubble Placement
 
860
  const panelCenters = [
861
  {x: 315, y: 175}, // 0
862
  {x: 790, y: 175}, // 1
 
872
  });
873
 
874
  if(p.bubbles && p.bubbles[j] && p.bubbles[j].dialog) {
 
 
 
875
  const center = panelCenters[j % 5] || {x:500, y:350};
 
876
  pageBubbles.push({
877
  text: p.bubbles[j].dialog,
878
+ left: (center.x - 75) + 'px',
879
  top: (center.y - 40) + 'px',
880
  type: (p.bubbles[j].type || 'speech'),
881
  classes: `speech-bubble ${p.bubbles[j].type || 'speech'} tail-bottom`
882
  });
883
  }
884
  });
 
885
  return { panels: panels, pageBubbles: pageBubbles };
886
  });
887
  renderFromState(cleanData); saveDraft(true);
 
969
  }
970
 
971
  function addBubble() {
 
 
 
 
972
  if(!selectedPanel) return alert("Select a panel to define which page to add to.");
 
973
  const pageDiv = selectedPanel.parentElement;
974
  const b = createBubbleHTML({ text: "Text", left: "50px", top: "50px", type: 'speech', classes: "speech-bubble speech tail-bottom" });
975
  pageDiv.appendChild(b); selectBubble(b); saveDraft(true);