Jimmyzheng-10 commited on
Commit
7d8b3d0
·
1 Parent(s): 410e3f4
Files changed (1) hide show
  1. app.py +2 -369
app.py CHANGED
@@ -349,380 +349,13 @@ with gr.Blocks(css="""
349
  font-weight: 600 !important;
350
  color: #374151 !important;
351
  }
352
-
353
- /* 截图工具区域样式 */
354
- .screenshot-tip {
355
- background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%) !important;
356
- border: 1px solid #bae6fd !important;
357
- border-radius: 8px !important;
358
- padding: 12px !important;
359
- margin-top: 8px !important;
360
- }
361
-
362
- .screenshot-tip div {
363
- line-height: 1.5 !important;
364
- }
365
-
366
- /* 截图按钮特殊样式 */
367
- .gr-button[data-testid="Take Screenshot"] {
368
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
369
- color: white !important;
370
- border: none !important;
371
- font-weight: 600 !important;
372
- transition: all 0.3s ease !important;
373
- }
374
-
375
- .gr-button[data-testid="Take Screenshot"]:hover {
376
- transform: translateY(-2px) !important;
377
- box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4) !important;
378
- }
379
-
380
- /* 全屏截图按钮样式 */
381
- .gr-button:has-text("Full Screen") {
382
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
383
- color: white !important;
384
- border: none !important;
385
- font-weight: 600 !important;
386
- transition: all 0.3s ease !important;
387
- }
388
-
389
- .gr-button:has-text("Full Screen"):hover {
390
- transform: translateY(-2px) !important;
391
- box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4) !important;
392
- }
393
-
394
- /* 区域截图按钮样式 */
395
- .gr-button:has-text("Select Area") {
396
- background: linear-gradient(135deg, #10b981 0%, #059669 100%) !important;
397
- color: white !important;
398
- border: none !important;
399
- font-weight: 600 !important;
400
- transition: all 0.3s ease !important;
401
- }
402
-
403
- .gr-button:has-text("Select Area"):hover {
404
- transform: translateY(-2px) !important;
405
- box-shadow: 0 8px 25px rgba(16, 185, 129, 0.4) !important;
406
- }
407
-
408
- /* 截图工具区域容器 */
409
- .screenshot-tools-container {
410
- background: #f8fafc !important;
411
- border: 1px solid #e2e8f0 !important;
412
- border-radius: 12px !important;
413
- padding: 16px !important;
414
- margin-bottom: 16px !important;
415
- }
416
  """) as demo:
417
  gr.Markdown("# ScreenCoder: Screenshot to Code")
418
  with gr.Row():
419
  with gr.Column(scale=1):
420
  gr.Markdown("## Step 1: Provide an Image")
421
-
422
- # 添加截图功能区域
423
- with gr.Row(elem_classes=["screenshot-tools-container"]):
424
- with gr.Column(scale=1):
425
- active_image = gr.Image(type="filepath", height=400)
426
- upload_button = gr.UploadButton("Click to Upload", file_types=["image"], variant="primary")
427
-
428
- with gr.Column(scale=1):
429
- gr.Markdown("**📸 Screenshot Tools**")
430
- with gr.Row():
431
- screenshot_btn = gr.Button("🎯 Full Screen", variant="secondary", size="sm")
432
- area_screenshot_btn = gr.Button("✂️ Select Area", variant="secondary", size="sm")
433
- gr.Markdown("""
434
- <div style="font-size: 12px; color: #666; margin-top: 8px;">
435
- 💡 Click "Full Screen" to capture entire screen.
436
- <br>Click "Select Area" to choose specific region.
437
- <br>Press ESC to cancel area selection.
438
- </div>
439
- """, elem_classes=["screenshot-tip"])
440
-
441
- # 添加截图功能的JavaScript
442
- gr.HTML("""
443
- <script>
444
- // 截图功能
445
- async function takeScreenshot() {
446
- try {
447
- // 检查浏览器是否支持截图API
448
- if (!navigator.mediaDevices || !navigator.mediaDevices.getDisplayMedia) {
449
- alert('Screenshot feature is not supported in this browser. Please use Chrome, Firefox, or Edge.');
450
- return;
451
- }
452
-
453
- // 请求屏幕共享权限
454
- const stream = await navigator.mediaDevices.getDisplayMedia({
455
- video: {
456
- mediaSource: 'screen',
457
- width: { ideal: 1920 },
458
- height: { ideal: 1080 }
459
- }
460
- });
461
-
462
- // 创建视频元素来捕获屏幕
463
- const video = document.createElement('video');
464
- video.srcObject = stream;
465
- video.onloadedmetadata = () => {
466
- video.play();
467
-
468
- // 创建canvas来绘制截图
469
- const canvas = document.createElement('canvas');
470
- const ctx = canvas.getContext('2d');
471
-
472
- // 设置canvas尺寸
473
- canvas.width = video.videoWidth;
474
- canvas.height = video.videoHeight;
475
-
476
- // 绘制视频帧到canvas
477
- ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
478
-
479
- // 停止视频流
480
- stream.getTracks().forEach(track => track.stop());
481
-
482
- // 将canvas转换为blob
483
- canvas.toBlob((blob) => {
484
- // 创建文件对象
485
- const file = new File([blob], 'screenshot.png', { type: 'image/png' });
486
-
487
- // 创建文件列表
488
- const dataTransfer = new DataTransfer();
489
- dataTransfer.items.add(file);
490
-
491
- // 找到图片上传组件并设置文件
492
- const imageInput = document.querySelector('input[type="file"]');
493
- if (imageInput) {
494
- imageInput.files = dataTransfer.files;
495
- // 触发change事件
496
- const event = new Event('change', { bubbles: true });
497
- imageInput.dispatchEvent(event);
498
- }
499
-
500
- // 显示成功消息
501
- showNotification('Screenshot captured successfully!', 'success');
502
- }, 'image/png');
503
- };
504
-
505
- } catch (error) {
506
- console.error('Screenshot error:', error);
507
- if (error.name === 'NotAllowedError') {
508
- alert('Screenshot permission denied. Please allow screen sharing when prompted.');
509
- } else {
510
- alert('Failed to take screenshot: ' + error.message);
511
- }
512
- }
513
- }
514
-
515
- // 区域截图功能
516
- async function takeAreaScreenshot() {
517
- try {
518
- // 检查浏览器是否支持截图API
519
- if (!navigator.mediaDevices || !navigator.mediaDevices.getDisplayMedia) {
520
- alert('Area screenshot feature is not supported in this browser.');
521
- return;
522
- }
523
-
524
- // 请求屏幕共享权限
525
- const stream = await navigator.mediaDevices.getDisplayMedia({
526
- video: {
527
- mediaSource: 'screen',
528
- width: { ideal: 1920 },
529
- height: { ideal: 1080 }
530
- }
531
- });
532
-
533
- // 创建视频元素
534
- const video = document.createElement('video');
535
- video.srcObject = stream;
536
- video.onloadedmetadata = () => {
537
- video.play();
538
-
539
- // 创建选择区域界面
540
- createSelectionOverlay(video, stream);
541
- };
542
-
543
- } catch (error) {
544
- console.error('Area screenshot error:', error);
545
- if (error.name === 'NotAllowedError') {
546
- alert('Screenshot permission denied. Please allow screen sharing when prompted.');
547
- } else {
548
- alert('Failed to take area screenshot: ' + error.message);
549
- }
550
- }
551
- }
552
-
553
- // 创建选择区域覆盖层
554
- function createSelectionOverlay(video, stream) {
555
- // 创建覆盖层
556
- const overlay = document.createElement('div');
557
- overlay.style.cssText = `
558
- position: fixed;
559
- top: 0;
560
- left: 0;
561
- width: 100vw;
562
- height: 100vh;
563
- background: rgba(0, 0, 0, 0.3);
564
- z-index: 9999;
565
- cursor: crosshair;
566
- `;
567
-
568
- // 创建选择框
569
- const selectionBox = document.createElement('div');
570
- selectionBox.style.cssText = `
571
- position: absolute;
572
- border: 2px dashed #3b82f6;
573
- background: rgba(59, 130, 246, 0.1);
574
- display: none;
575
- `;
576
-
577
- overlay.appendChild(selectionBox);
578
- document.body.appendChild(overlay);
579
-
580
- let isSelecting = false;
581
- let startX, startY;
582
-
583
- // 鼠标事件处理
584
- overlay.addEventListener('mousedown', (e) => {
585
- isSelecting = true;
586
- startX = e.clientX;
587
- startY = e.clientY;
588
- selectionBox.style.display = 'block';
589
- selectionBox.style.left = startX + 'px';
590
- selectionBox.style.top = startY + 'px';
591
- selectionBox.style.width = '0px';
592
- selectionBox.style.height = '0px';
593
- });
594
-
595
- overlay.addEventListener('mousemove', (e) => {
596
- if (!isSelecting) return;
597
-
598
- const currentX = e.clientX;
599
- const currentY = e.clientY;
600
-
601
- const left = Math.min(startX, currentX);
602
- const top = Math.min(startY, currentY);
603
- const width = Math.abs(currentX - startX);
604
- const height = Math.abs(currentY - startY);
605
-
606
- selectionBox.style.left = left + 'px';
607
- selectionBox.style.top = top + 'px';
608
- selectionBox.style.width = width + 'px';
609
- selectionBox.style.height = height + 'px';
610
- });
611
-
612
- overlay.addEventListener('mouseup', (e) => {
613
- if (!isSelecting) return;
614
- isSelecting = false;
615
-
616
- const rect = selectionBox.getBoundingClientRect();
617
- captureSelectedArea(video, rect, stream);
618
-
619
- // 清理
620
- document.body.removeChild(overlay);
621
- });
622
-
623
- // ESC键取消
624
- const handleKeyDown = (e) => {
625
- if (e.key === 'Escape') {
626
- document.body.removeChild(overlay);
627
- stream.getTracks().forEach(track => track.stop());
628
- document.removeEventListener('keydown', handleKeyDown);
629
- }
630
- };
631
- document.addEventListener('keydown', handleKeyDown);
632
- }
633
-
634
- // 捕获选定区域
635
- function captureSelectedArea(video, rect, stream) {
636
- const canvas = document.createElement('canvas');
637
- const ctx = canvas.getContext('2d');
638
-
639
- // 设置canvas尺寸为选择区域大小
640
- canvas.width = rect.width;
641
- canvas.height = rect.height;
642
-
643
- // 绘制选定区域
644
- ctx.drawImage(video, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);
645
-
646
- // 停止视频流
647
- stream.getTracks().forEach(track => track.stop());
648
-
649
- // 转换为blob并上传
650
- canvas.toBlob((blob) => {
651
- const file = new File([blob], 'area_screenshot.png', { type: 'image/png' });
652
- const dataTransfer = new DataTransfer();
653
- dataTransfer.items.add(file);
654
-
655
- const imageInput = document.querySelector('input[type="file"]');
656
- if (imageInput) {
657
- imageInput.files = dataTransfer.files;
658
- const event = new Event('change', { bubbles: true });
659
- imageInput.dispatchEvent(event);
660
- }
661
-
662
- showNotification('Area screenshot captured successfully!', 'success');
663
- }, 'image/png');
664
- }
665
-
666
- // 显示通知的函数
667
- function showNotification(message, type = 'info') {
668
- const notification = document.createElement('div');
669
- notification.style.cssText = `
670
- position: fixed;
671
- top: 20px;
672
- right: 20px;
673
- padding: 12px 20px;
674
- border-radius: 8px;
675
- color: white;
676
- font-weight: 500;
677
- z-index: 10000;
678
- animation: slideIn 0.3s ease-out;
679
- background: ${type === 'success' ? '#10b981' : '#3b82f6'};
680
- box-shadow: 0 4px 12px rgba(0,0,0,0.15);
681
- `;
682
- notification.textContent = message;
683
-
684
- // 添加动画样式
685
- const style = document.createElement('style');
686
- style.textContent = `
687
- @keyframes slideIn {
688
- from { transform: translateX(100%); opacity: 0; }
689
- to { transform: translateX(0); opacity: 1; }
690
- }
691
- `;
692
- document.head.appendChild(style);
693
-
694
- document.body.appendChild(notification);
695
-
696
- // 3秒后自动移除
697
- setTimeout(() => {
698
- notification.remove();
699
- }, 3000);
700
- }
701
-
702
- // 等待页面加载完成后绑定事件
703
- document.addEventListener('DOMContentLoaded', function() {
704
- // 查找截图按钮并绑定点击事件
705
- const observer = new MutationObserver(function(mutations) {
706
- mutations.forEach(function(mutation) {
707
- mutation.addedNodes.forEach(function(node) {
708
- if (node.nodeType === 1) { // 元素节点
709
- const buttons = node.querySelectorAll ? node.querySelectorAll('button') : [];
710
- buttons.forEach(function(button) {
711
- if (button.textContent.includes('Full Screen')) {
712
- button.addEventListener('click', takeScreenshot);
713
- } else if (button.textContent.includes('Select Area')) {
714
- button.addEventListener('click', takeAreaScreenshot);
715
- }
716
- });
717
- }
718
- });
719
- });
720
- });
721
-
722
- observer.observe(document.body, { childList: true, subtree: true });
723
- });
724
- </script>
725
- """)
726
 
727
  gr.Markdown("## Step 2: Write Prompts (Optional)")
728
  with gr.Accordion("Component-specific Prompts", open=False):
 
349
  font-weight: 600 !important;
350
  color: #374151 !important;
351
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  """) as demo:
353
  gr.Markdown("# ScreenCoder: Screenshot to Code")
354
  with gr.Row():
355
  with gr.Column(scale=1):
356
  gr.Markdown("## Step 1: Provide an Image")
357
+ active_image = gr.Image(type="filepath", height=400)
358
+ upload_button = gr.UploadButton("Click to Upload", file_types=["image"], variant="primary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
359
 
360
  gr.Markdown("## Step 2: Write Prompts (Optional)")
361
  with gr.Accordion("Component-specific Prompts", open=False):