File size: 3,192 Bytes
987ad7e
 
07b11b9
a50705a
 
 
 
 
8308d0a
a50705a
b27516c
8308d0a
b27516c
 
 
a50705a
b27516c
 
8e45882
 
8308d0a
a50705a
 
 
 
 
d7fe75d
6e43f58
 
 
d7fe75d
09eff80
afdc316
07b11b9
afdc316
a50705a
987ad7e
d7fe75d
a50705a
 
 
 
 
 
 
d7fe75d
 
 
 
 
3bb4a13
a50705a
67a91da
d7fe75d
 
67a91da
6e43f58
d7fe75d
646c22b
 
d7fe75d
67a91da
d7fe75d
a50705a
07b11b9
 
d7fe75d
a50705a
 
d7fe75d
 
a50705a
6e43f58
 
 
 
afdc316
d7fe75d
 
 
 
 
67a91da
 
d7fe75d
c553125
 
6e43f58
 
 
 
8308d0a
 
 
 
 
 
 
 
 
6e43f58
 
8308d0a
6e43f58
c553125
 
 
67a91da
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import gradio as gr

# Custom CSS: smaller arrow, pushed down, video enlarged
mycss = """
.arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 80px auto;
}
.arrow-tail {
  width: 150px;
  height: 20px;
  background-color: black;
}
.arrow-head {
  width: 0;
  height: 0;
  border-top: 30px solid transparent;
  border-bottom: 30px solid transparent;
  border-left: 60px solid black;
}
@media (prefers-color-scheme: dark) {
  .arrow-tail { background-color: white; }
  .arrow-head { border-left-color: white; }
}
/* ensure the video container has enough space */
#generated-video {
  min-height: 360px;
}
/* enlarge the video */
#generated-video video {
  width: 640px !important;
  height: auto !important;
}
"""

# Arrow HTML
myhtml = """
<div class="arrow">
  <div class="arrow-tail"></div>
  <div class="arrow-head"></div>
</div>
"""

def generate_media(echo_idx, ecg_idx):
    echo_path = f"resources/examples/ef{echo_idx}.png"
    ecg_path  = f"resources/examples/ecg{ecg_idx}.png"
    video_path = f"resources/examples/ef{echo_idx}.mp4"
    return echo_path, ecg_path, video_path

with gr.Blocks(css=mycss) as demo:
    gr.Markdown("""
    # ECHOPULSE: ECG-Controlled Echocardiogram Video Generation  
    Enter the example index for your ECHO image and ECG image below, then click **Generate Video** to load both images and play the corresponding video.
    """)

    # Two input fields for the example index
    echo_idx_input = gr.Textbox(label="Patient's Past ECHO Example Index (i)", placeholder="e.g. 0000")
    ecg_idx_input  = gr.Textbox(label="Patient's ECG Example Index (i)",  placeholder="e.g. 0000")

    with gr.Row():
        # Column 1: ECHO + ECG images
        with gr.Column():
            echo_image = gr.Image(interactive=False, label="ECHO Image")
            ecg_image  = gr.Image(interactive=False, label="ECG Image")
        # Column 2: arrow + button
        with gr.Column():
            gr.HTML(myhtml)
            gen_button = gr.Button("Generate Video")
        # Column 3: video output
        with gr.Column():
            video_out = gr.Video(interactive=False,
                                 autoplay=True,
                                 label="Generated Video",
                                 elem_id="generated-video")

    # Wire up the button to load images & video based on the indices
    gen_button.click(
        fn=generate_media,
        inputs=[echo_idx_input, ecg_idx_input],
        outputs=[echo_image, ecg_image, video_out]
    )

    # Delay display of the <video> element by 2s after it's loaded
    gr.HTML("""
<script>
const wrapper = document.getElementById('generated-video');
const observer = new MutationObserver(mutations => {
  mutations.forEach(mutation => {
    mutation.addedNodes.forEach(node => {
      if (node.tagName === 'VIDEO') {
        node.style.display = 'none';
        node.addEventListener('loadeddata', () => {
          setTimeout(() => {
            node.style.display = 'block';
            if (node.paused) node.play();
          }, 2000);
        });
      }
    });
  });
});
observer.observe(wrapper, { childList: true });
</script>
""")

demo.launch(share=False)