Add firefox start cmd, add cyberpunk theme
Browse files
app.py
CHANGED
|
@@ -35,34 +35,50 @@ model = QwenVLAPIModel(
|
|
| 35 |
|
| 36 |
|
| 37 |
custom_css = """
|
|
|
|
|
|
|
|
|
|
| 38 |
.sandbox-container {
|
| 39 |
position: relative;
|
| 40 |
width: 910px;
|
| 41 |
-
height:
|
| 42 |
overflow: hidden;
|
| 43 |
margin: auto;
|
| 44 |
}
|
| 45 |
|
| 46 |
-
.sandbox-
|
| 47 |
position: absolute;
|
| 48 |
top: 0;
|
| 49 |
left: 0;
|
| 50 |
width: 910px;
|
| 51 |
-
height:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
}
|
| 53 |
|
| 54 |
.sandbox-iframe, .bsod-image {
|
| 55 |
position: absolute;
|
| 56 |
-
top: 8%;
|
| 57 |
-
left: 7%;
|
| 58 |
width: <<WIDTH>>px;
|
| 59 |
height: <<HEIGHT>>px;
|
| 60 |
border: 4px solid #444444;
|
| 61 |
transform-origin: 0 0;
|
| 62 |
}
|
| 63 |
-
.sandbox-iframe {
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
/* Colored label for task textbox */
|
| 67 |
.primary-color-label label span {
|
| 68 |
font-weight: bold;
|
|
@@ -70,31 +86,29 @@ custom_css = """
|
|
| 70 |
}
|
| 71 |
|
| 72 |
/* Status indicator light */
|
| 73 |
-
.status-
|
|
|
|
| 74 |
position: absolute;
|
| 75 |
-
bottom:
|
| 76 |
-
left:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
width: 20px;
|
| 78 |
height: 20px;
|
| 79 |
border-radius: 50%;
|
| 80 |
-
border: 2px solid black;
|
| 81 |
-
z-index: 100;
|
| 82 |
}
|
| 83 |
|
| 84 |
.status-text {
|
| 85 |
-
position: absolute;
|
| 86 |
-
bottom: 3.8%;
|
| 87 |
-
left: 47%;
|
| 88 |
-
right:40%
|
| 89 |
font-size: 16px;
|
| 90 |
font-weight: bold;
|
| 91 |
-
color:
|
| 92 |
-
background-color: white;
|
| 93 |
padding: 0 10px;
|
| 94 |
-
border-radius: 3px;
|
| 95 |
-
border: 2px solid black;
|
| 96 |
text-shadow: none;
|
| 97 |
-
z-index: 100;
|
| 98 |
}
|
| 99 |
|
| 100 |
.status-interactive {
|
|
@@ -160,21 +174,19 @@ footer_html="""
|
|
| 160 |
</div>
|
| 161 |
"""
|
| 162 |
sandbox_html_template = """
|
| 163 |
-
<div class="sandbox-container">
|
| 164 |
-
<
|
| 165 |
-
|
| 166 |
-
|
|
|
|
| 167 |
<iframe id="sandbox-iframe"
|
| 168 |
src="{stream_url}"
|
| 169 |
class="sandbox-iframe"
|
| 170 |
style="display: block;"
|
| 171 |
allowfullscreen>
|
| 172 |
</iframe>
|
| 173 |
-
<img
|
| 174 |
-
|
| 175 |
-
class="bsod-image"
|
| 176 |
-
style="display: none;
|
| 177 |
-
/>
|
| 178 |
</div>
|
| 179 |
""".replace("<<WIDTH>>", str(WIDTH+15)).replace("<<HEIGHT>>", str(HEIGHT+10))
|
| 180 |
|
|
@@ -383,6 +395,8 @@ def get_or_create_sandbox(session_hash):
|
|
| 383 |
print(f"Creating new sandbox for session {session_hash}")
|
| 384 |
desktop = Sandbox(api_key=E2B_API_KEY, resolution=(WIDTH, HEIGHT), dpi=96, timeout=SANDBOX_TIMEOUT)
|
| 385 |
desktop.stream.start(require_auth=True)
|
|
|
|
|
|
|
| 386 |
|
| 387 |
# Store sandbox with metadata
|
| 388 |
SANDBOXES[session_hash] = desktop
|
|
@@ -393,7 +407,7 @@ def get_or_create_sandbox(session_hash):
|
|
| 393 |
|
| 394 |
return desktop
|
| 395 |
|
| 396 |
-
def update_html(interactive_mode, request: gr.Request):
|
| 397 |
session_hash = request.session_hash
|
| 398 |
desktop = get_or_create_sandbox(session_hash)
|
| 399 |
auth_key = desktop.stream.get_auth_key()
|
|
@@ -409,6 +423,7 @@ def update_html(interactive_mode, request: gr.Request):
|
|
| 409 |
creation_time = SANDBOX_METADATA[session_hash]['created_at'] if session_hash in SANDBOX_METADATA else time.time()
|
| 410 |
|
| 411 |
sandbox_html_content = sandbox_html_template.format(
|
|
|
|
| 412 |
stream_url=stream_url,
|
| 413 |
status_class=status_class,
|
| 414 |
status_text=status_text,
|
|
@@ -448,7 +463,8 @@ def initialize_session(interactive_mode, request: gr.Request):
|
|
| 448 |
with open(log_path, 'w') as f:
|
| 449 |
f.write(f"Ready to go...\n")
|
| 450 |
# Return HTML and session hash
|
| 451 |
-
return update_html(interactive_mode, request), session_hash
|
|
|
|
| 452 |
|
| 453 |
# Function to read log content that gets the path from session hash
|
| 454 |
def update_terminal_from_session(session_hash):
|
|
@@ -539,6 +555,7 @@ with gr.Blocks(css=custom_css, js=custom_js, fill_width=True) as demo:
|
|
| 539 |
with gr.Row():
|
| 540 |
sandbox_html = gr.HTML(
|
| 541 |
value=sandbox_html_template.format(
|
|
|
|
| 542 |
stream_url="",
|
| 543 |
status_class="status-interactive",
|
| 544 |
status_text="Interactive"
|
|
@@ -575,6 +592,7 @@ with gr.Blocks(css=custom_css, js=custom_js, fill_width=True) as demo:
|
|
| 575 |
)
|
| 576 |
|
| 577 |
update_btn = gr.Button("Let's go!", variant="primary")
|
|
|
|
| 578 |
cancel_btn = gr.Button("Interrupt running agent")
|
| 579 |
|
| 580 |
chatbot_display = gr.Chatbot(
|
|
@@ -612,31 +630,38 @@ with gr.Blocks(css=custom_css, js=custom_js, fill_width=True) as demo:
|
|
| 612 |
# Function to set view-only mode
|
| 613 |
def clear_and_set_view_only(task_input, request: gr.Request):
|
| 614 |
# First clear the results, then set view-only mode
|
| 615 |
-
return "", update_html(False, request), gr.update(visible=False)
|
| 616 |
|
| 617 |
def set_interactive(request: gr.Request):
|
| 618 |
-
return update_html(True, request)
|
| 619 |
|
|
|
|
| 620 |
|
| 621 |
# Chain the events
|
| 622 |
view_only_event = update_btn.click(
|
| 623 |
fn=clear_and_set_view_only,
|
| 624 |
-
inputs=[task_input],
|
| 625 |
outputs=[results_output, sandbox_html, results_container]
|
| 626 |
)
|
| 627 |
view_only_event.then(agent_ui.interact_with_agent, [task_input, stored_messages, session_state, session_hash_state], [chatbot_display]).then(
|
| 628 |
fn=set_interactive,
|
| 629 |
-
inputs=[],
|
| 630 |
outputs=sandbox_html
|
| 631 |
)
|
| 632 |
cancel_btn.click(fn=(lambda x: x), cancels=[view_only_event])
|
| 633 |
|
| 634 |
demo.load(
|
| 635 |
fn=initialize_session,
|
| 636 |
-
inputs=[
|
| 637 |
outputs=[sandbox_html, session_hash_state]
|
| 638 |
)
|
| 639 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 640 |
|
| 641 |
# Launch the app
|
| 642 |
if __name__ == "__main__":
|
|
|
|
| 35 |
|
| 36 |
|
| 37 |
custom_css = """
|
| 38 |
+
.app {
|
| 39 |
+
background-color:black
|
| 40 |
+
}
|
| 41 |
.sandbox-container {
|
| 42 |
position: relative;
|
| 43 |
width: 910px;
|
| 44 |
+
height: 800px;
|
| 45 |
overflow: hidden;
|
| 46 |
margin: auto;
|
| 47 |
}
|
| 48 |
|
| 49 |
+
.sandbox-frame {
|
| 50 |
position: absolute;
|
| 51 |
top: 0;
|
| 52 |
left: 0;
|
| 53 |
width: 910px;
|
| 54 |
+
height: 800px;
|
| 55 |
+
pointer-events:none;
|
| 56 |
+
}
|
| 57 |
+
.minimal .sandbox-frame {
|
| 58 |
+
display: none;
|
| 59 |
}
|
| 60 |
|
| 61 |
.sandbox-iframe, .bsod-image {
|
| 62 |
position: absolute;
|
|
|
|
|
|
|
| 63 |
width: <<WIDTH>>px;
|
| 64 |
height: <<HEIGHT>>px;
|
| 65 |
border: 4px solid #444444;
|
| 66 |
transform-origin: 0 0;
|
| 67 |
}
|
| 68 |
+
.minimal .sandbox-iframe, .bsod-image {
|
| 69 |
+
/* top: 73px; */
|
| 70 |
+
top: 99px;
|
| 71 |
+
/* left: 74px; */
|
| 72 |
+
left: 110px;
|
| 73 |
+
}
|
| 74 |
+
.cyberpunk .sandbox-iframe {
|
| 75 |
+
transform: scale(0.535);
|
| 76 |
+
/* transform: scale(0.59); */
|
| 77 |
}
|
| 78 |
+
.minimal .sandbox-iframe {
|
| 79 |
+
transform: scale(0.7);
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
/* Colored label for task textbox */
|
| 83 |
.primary-color-label label span {
|
| 84 |
font-weight: bold;
|
|
|
|
| 86 |
}
|
| 87 |
|
| 88 |
/* Status indicator light */
|
| 89 |
+
.status-bar {
|
| 90 |
+
display: flex;
|
| 91 |
position: absolute;
|
| 92 |
+
bottom: 86px;
|
| 93 |
+
left: 355px;
|
| 94 |
+
flex-direction: row;
|
| 95 |
+
align-items: center;
|
| 96 |
+
flex-align:center;
|
| 97 |
+
z-index: 100;
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
.status-indicator {
|
| 101 |
width: 20px;
|
| 102 |
height: 20px;
|
| 103 |
border-radius: 50%;
|
|
|
|
|
|
|
| 104 |
}
|
| 105 |
|
| 106 |
.status-text {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
font-size: 16px;
|
| 108 |
font-weight: bold;
|
| 109 |
+
color: #fed244;
|
|
|
|
| 110 |
padding: 0 10px;
|
|
|
|
|
|
|
| 111 |
text-shadow: none;
|
|
|
|
| 112 |
}
|
| 113 |
|
| 114 |
.status-interactive {
|
|
|
|
| 174 |
</div>
|
| 175 |
"""
|
| 176 |
sandbox_html_template = """
|
| 177 |
+
<div class="sandbox-container {theme}">
|
| 178 |
+
<div class="status-bar">
|
| 179 |
+
<div class="status-indicator {status_class}"></div>
|
| 180 |
+
<div class="status-text">{status_text}</div>
|
| 181 |
+
</div>
|
| 182 |
<iframe id="sandbox-iframe"
|
| 183 |
src="{stream_url}"
|
| 184 |
class="sandbox-iframe"
|
| 185 |
style="display: block;"
|
| 186 |
allowfullscreen>
|
| 187 |
</iframe>
|
| 188 |
+
<img src="https://huggingface.co/datasets/mfarre/servedfiles/resolve/main/blue_screen_of_death.gif" class="bsod-image" style="display: none;"/>
|
| 189 |
+
<img src="https://huggingface.co/datasets/m-ric/images/resolve/main/HUD_thom.png" class="sandbox-frame" />
|
|
|
|
|
|
|
|
|
|
| 190 |
</div>
|
| 191 |
""".replace("<<WIDTH>>", str(WIDTH+15)).replace("<<HEIGHT>>", str(HEIGHT+10))
|
| 192 |
|
|
|
|
| 395 |
print(f"Creating new sandbox for session {session_hash}")
|
| 396 |
desktop = Sandbox(api_key=E2B_API_KEY, resolution=(WIDTH, HEIGHT), dpi=96, timeout=SANDBOX_TIMEOUT)
|
| 397 |
desktop.stream.start(require_auth=True)
|
| 398 |
+
firefox_skipwelcome_cmd = """sudo mkdir -p /usr/lib/firefox-esr/distribution && echo '{"policies":{"OverrideFirstRunPage":"","OverridePostUpdatePage":"","DisableProfileImport":true,"DontCheckDefaultBrowser":true}}' | sudo tee /usr/lib/firefox-esr/distribution/policies.json > /dev/null"""
|
| 399 |
+
desktop.commands.run(firefox_skipwelcome_cmd)
|
| 400 |
|
| 401 |
# Store sandbox with metadata
|
| 402 |
SANDBOXES[session_hash] = desktop
|
|
|
|
| 407 |
|
| 408 |
return desktop
|
| 409 |
|
| 410 |
+
def update_html(interactive_mode: bool, theme_checkbox: bool, request: gr.Request):
|
| 411 |
session_hash = request.session_hash
|
| 412 |
desktop = get_or_create_sandbox(session_hash)
|
| 413 |
auth_key = desktop.stream.get_auth_key()
|
|
|
|
| 423 |
creation_time = SANDBOX_METADATA[session_hash]['created_at'] if session_hash in SANDBOX_METADATA else time.time()
|
| 424 |
|
| 425 |
sandbox_html_content = sandbox_html_template.format(
|
| 426 |
+
theme="cyberpunk" if theme_checkbox else "minimal",
|
| 427 |
stream_url=stream_url,
|
| 428 |
status_class=status_class,
|
| 429 |
status_text=status_text,
|
|
|
|
| 463 |
with open(log_path, 'w') as f:
|
| 464 |
f.write(f"Ready to go...\n")
|
| 465 |
# Return HTML and session hash
|
| 466 |
+
return update_html(interactive_mode, "cyberpunk", request), session_hash
|
| 467 |
+
|
| 468 |
|
| 469 |
# Function to read log content that gets the path from session hash
|
| 470 |
def update_terminal_from_session(session_hash):
|
|
|
|
| 555 |
with gr.Row():
|
| 556 |
sandbox_html = gr.HTML(
|
| 557 |
value=sandbox_html_template.format(
|
| 558 |
+
theme="cyberpunk",
|
| 559 |
stream_url="",
|
| 560 |
status_class="status-interactive",
|
| 561 |
status_text="Interactive"
|
|
|
|
| 592 |
)
|
| 593 |
|
| 594 |
update_btn = gr.Button("Let's go!", variant="primary")
|
| 595 |
+
theme_checkbox = gr.Checkbox(label="Cyberpunk Mode", value=True)
|
| 596 |
cancel_btn = gr.Button("Interrupt running agent")
|
| 597 |
|
| 598 |
chatbot_display = gr.Chatbot(
|
|
|
|
| 630 |
# Function to set view-only mode
|
| 631 |
def clear_and_set_view_only(task_input, request: gr.Request):
|
| 632 |
# First clear the results, then set view-only mode
|
| 633 |
+
return "", update_html(False, theme_checkbox, request), gr.update(visible=False)
|
| 634 |
|
| 635 |
def set_interactive(request: gr.Request):
|
| 636 |
+
return update_html(True, theme_checkbox, request)
|
| 637 |
|
| 638 |
+
is_interactive = gr.Checkbox(value=True, visible=False)
|
| 639 |
|
| 640 |
# Chain the events
|
| 641 |
view_only_event = update_btn.click(
|
| 642 |
fn=clear_and_set_view_only,
|
| 643 |
+
inputs=[task_input, theme_checkbox],
|
| 644 |
outputs=[results_output, sandbox_html, results_container]
|
| 645 |
)
|
| 646 |
view_only_event.then(agent_ui.interact_with_agent, [task_input, stored_messages, session_state, session_hash_state], [chatbot_display]).then(
|
| 647 |
fn=set_interactive,
|
| 648 |
+
inputs=[theme_checkbox],
|
| 649 |
outputs=sandbox_html
|
| 650 |
)
|
| 651 |
cancel_btn.click(fn=(lambda x: x), cancels=[view_only_event])
|
| 652 |
|
| 653 |
demo.load(
|
| 654 |
fn=initialize_session,
|
| 655 |
+
inputs=[is_interactive],
|
| 656 |
outputs=[sandbox_html, session_hash_state]
|
| 657 |
)
|
| 658 |
|
| 659 |
+
theme_checkbox.change(
|
| 660 |
+
fn=update_html,
|
| 661 |
+
inputs=[is_interactive, theme_checkbox],
|
| 662 |
+
outputs=[sandbox_html]
|
| 663 |
+
)
|
| 664 |
+
|
| 665 |
|
| 666 |
# Launch the app
|
| 667 |
if __name__ == "__main__":
|