File size: 3,729 Bytes
88fe4e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
828ea87
88fe4e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import gradio as gr
from src.ui.styles import CSS
from src.config import CONFIG

def _status_html(msg: str) -> str:
    """Wrap a status message in the styled status-bar div."""
    return f'<div id="sightline-status" role="status" aria-live="polite">{msg}</div>'

def build_ui(assistant) -> gr.Blocks:
    auto_start_js = """

    function() {

        setInterval(function() {

            let clickTarget = function(btn) {

                let text = (btn.textContent || btn.innerText || '').toLowerCase().trim();

                if (text === 'click to access webcam' || text === 'record') {

                    btn.click();

                }

            };

            

            // Check Shadow DOMs

            document.querySelectorAll('*').forEach(function(el) {

                if (el.shadowRoot) {

                    el.shadowRoot.querySelectorAll('button').forEach(clickTarget);

                }

            });

            

            // Check regular DOM

            document.querySelectorAll('button').forEach(clickTarget);

        }, 1000); // Check every second indefinitely

    }

    """
    with gr.Blocks(title=f"{CONFIG.APP_NAME} v{CONFIG.APP_VERSION}", js=auto_start_js, css=CSS) as demo:
        gr.HTML('<div class="sr-only" aria-live="assertive" id="aria-live-region" role="status"></div>')
        
        status_bar = gr.HTML(_status_html("βœ… Ready β€” Press D to describe"))

        gr.Markdown(f"# πŸ‘οΈ {CONFIG.APP_NAME}")
        
        rt_state = gr.State(True)

        with gr.Row():
            with gr.Column(scale=1):
                # Controls at the top
                with gr.Row():
                    describe_btn = gr.Button("πŸ” Describe (D)", variant="primary", elem_id="btn-describe")
                    realtime_btn = gr.Button("⚫ Stop Realtime (R)", variant="secondary", elem_id="btn-realtime")
                
                with gr.Row():
                    task_radio = gr.Radio(
                        choices=["Quick Glance", "Detailed Scene", "Immersive Description", "Read Text"],
                        value="Detailed Scene",
                        label="Mode"
                    )
                    voice_dropdown = gr.Dropdown(
                        choices=["English (US) - Aria", "Hindi - Swara"],
                        value="English (US) - Aria",
                        label="Voice"
                    )
                
                webcam = gr.Image(label="πŸ“· Camera", type="numpy", sources=["webcam"], streaming=True)
                with gr.Accordion("Upload Image", open=False):
                    upload = gr.Image(label="πŸ“ Upload", type="numpy", sources=["upload"])

            with gr.Column(scale=1):
                caption_box = gr.Textbox(label="πŸ“ Description", lines=6, interactive=False)
                audio_player = gr.Audio(label="πŸ”Š Audio", type="filepath", autoplay=True)
                
                with gr.Row():
                    repeat_btn = gr.Button("πŸ” Repeat (P)", elem_id="btn-repeat")
                    stop_btn = gr.Button("⏹ Stop (Esc)", elem_id="btn-stop")

        components = {
            "webcam": webcam, "upload": upload, "task_radio": task_radio,
            "voice_dropdown": voice_dropdown, "describe_btn": describe_btn,
            "realtime_btn": realtime_btn, "caption_box": caption_box,
            "audio_player": audio_player, "status_bar": status_bar,
            "rt_state": rt_state, "repeat_btn": repeat_btn, "stop_btn": stop_btn
        }
        
        from src.ui.events import wire_events
        wire_events(demo, components, assistant)
        
        return demo