lvwerra HF Staff commited on
Commit
29ccb45
·
1 Parent(s): 13ad481
Files changed (5) hide show
  1. app.py +22 -259
  2. custom.css +103 -0
  3. custom.js +115 -0
  4. footer.html +12 -0
  5. sandbox.html +17 -0
app.py CHANGED
@@ -17,6 +17,9 @@ from smolagents.gradio_ui import GradioUI, stream_to_gradio
17
  from e2bqwen import QwenVLAPIModel, E2BVisionAgent
18
 
19
  E2B_API_KEY = os.getenv("E2B_API_KEY")
 
 
 
20
  SANDBOXES = {}
21
  SANDBOX_METADATA = {}
22
  SANDBOX_TIMEOUT = 600
@@ -26,269 +29,29 @@ TMP_DIR = './tmp/'
26
  if not os.path.exists(TMP_DIR):
27
  os.makedirs(TMP_DIR)
28
 
29
- hf_token = os.getenv("HUGGINGFACE_API_KEY")
30
- login(token=hf_token)
 
 
 
 
31
  model = QwenVLAPIModel(
32
- hf_base_url="https://s41ydkv0iyjeokyj.us-east-1.aws.endpoints.huggingface.cloud",
33
- hf_token = hf_token,
34
  )
35
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
- custom_css = """
38
- .sandbox-container {
39
- position: relative;
40
- width: 910px;
41
- overflow: hidden;
42
- margin: auto;
43
- }
44
- .sandbox-container {
45
- height: 800px;
46
- }
47
- .sandbox-frame {
48
- display: none;
49
- position: absolute;
50
- top: 0;
51
- left: 0;
52
- width: 910px;
53
- height: 800px;
54
- pointer-events:none;
55
- }
56
-
57
- .sandbox-iframe, .bsod-image {
58
- position: absolute;
59
- width: <<WIDTH>>px;
60
- height: <<HEIGHT>>px;
61
- border: 4px solid #444444;
62
- transform-origin: 0 0;
63
- }
64
-
65
- /* Colored label for task textbox */
66
- .primary-color-label label span {
67
- font-weight: bold;
68
- color: var(--color-accent);
69
- }
70
-
71
- /* Status indicator light */
72
- .status-bar {
73
- display: flex;
74
- flex-direction: row;
75
- align-items: center;
76
- flex-align:center;
77
- z-index: 100;
78
- }
79
-
80
- .status-indicator {
81
- width: 15px;
82
- height: 15px;
83
- border-radius: 50%;
84
- }
85
-
86
- .status-text {
87
- font-size: 16px;
88
- font-weight: bold;
89
- padding: 0 10px;
90
- text-shadow: none;
91
- }
92
-
93
- .status-interactive {
94
- background-color: #2ecc71;
95
- animation: blink 2s infinite;
96
- }
97
-
98
- .status-view-only {
99
- background-color: #e74c3c;
100
- }
101
-
102
- .status-error {
103
- background-color: #e74c3c;
104
- animation: blink-error 1s infinite;
105
- }
106
-
107
- @keyframes blink-error {
108
- 0% { background-color: rgba(231, 76, 60, 1); }
109
- 50% { background-color: rgba(231, 76, 60, 0.4); }
110
- 100% { background-color: rgba(231, 76, 60, 1); }
111
- }
112
-
113
- @keyframes blink {
114
- 0% { background-color: rgba(46, 204, 113, 1); } /* Green at full opacity */
115
- 50% { background-color: rgba(46, 204, 113, 0.4); } /* Green at 40% opacity */
116
- 100% { background-color: rgba(46, 204, 113, 1); } /* Green at full opacity */
117
- }
118
-
119
- .logo-container {
120
- display: flex;
121
- flex-direction: column;
122
- justify-content: space-between;
123
- align-items: center;
124
- width: 100%;
125
- box-sizing: border-box;
126
- }
127
-
128
- .logo-item {
129
- flex: 1;
130
- display: flex;
131
- justify-content: center;
132
- align-items: center;
133
- padding: 0 15px;
134
- }
135
-
136
- .logo-item img {
137
- height: 60px;
138
- object-fit: contain;
139
- }
140
- """.replace("<<WIDTH>>", str(WIDTH+15)).replace("<<HEIGHT>>", str(HEIGHT+10))
141
-
142
- footer_html="""
143
- <h3 style="text-align: center; margin-top:100px;"><i>Powered by:</i></h2>
144
- <div class="logo-container">
145
- <a class="logo-item" href="https://github.com/huggingface/smolagents">
146
- <img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/smolagents/smolagents.png" alt="Smolagents logo">
147
- </a>
148
- <a class="logo-item" href="https://huggingface.co/Qwen/Qwen2.5-VL-32B-Instruct">
149
- <img src="https://upload.wikimedia.org/wikipedia/en/8/85/Logo_of_Qwen.png" alt="Qwen logo", style="height:48px;margin-top=10px;">
150
- </a>
151
- <a class="logo-item" href="https://github.com/e2b-dev/desktop">
152
- <img src="https://image.pitchbook.com/XcarTFiUTDTVBfBep3JKHtiTAob1714067332850_200x200" alt="e2b logo", style="height:80px;">
153
- </a>
154
- </div>
155
- """
156
- sandbox_html_template = """
157
- <style>
158
- @import url('https://fonts.googleapis.com/css2?family=Oxanium:[email protected]&display=swap');
159
- </style>
160
- <div class="sandbox-container">
161
- <div class="status-bar">
162
- <div class="status-indicator {status_class}"></div>
163
- <div class="status-text">{status_text}</div>
164
- </div>
165
- <iframe id="sandbox-iframe"
166
- src="{stream_url}"
167
- class="sandbox-iframe"
168
- style="display: block;"
169
- allowfullscreen>
170
- </iframe>
171
- <img src="https://huggingface.co/datasets/mfarre/servedfiles/resolve/main/blue_screen_of_death.gif" class="bsod-image" style="display: none;"/>
172
- <img src="https://huggingface.co/datasets/m-ric/images/resolve/main/HUD_thom.png" class="sandbox-frame" />
173
- </div>
174
- """.replace("<<WIDTH>>", str(WIDTH+15)).replace("<<HEIGHT>>", str(HEIGHT+10))
175
-
176
- custom_js = """function() {
177
- document.body.classList.add('dark');
178
-
179
- // Function to check if sandbox is timing out
180
- const checkSandboxTimeout = function() {
181
- const timeElement = document.getElementById('sandbox-creation-time');
182
-
183
- if (timeElement) {
184
- const creationTime = parseFloat(timeElement.getAttribute('data-time'));
185
- const timeoutValue = parseFloat(timeElement.getAttribute('data-timeout'));
186
- const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
187
-
188
- const elapsedTime = currentTime - creationTime;
189
- console.log("Sandbox running for: " + elapsedTime + " seconds of " + timeoutValue + " seconds");
190
-
191
- // If we've exceeded the timeout, show BSOD
192
- if (elapsedTime >= timeoutValue) {
193
- console.log("Sandbox timeout! Showing BSOD");
194
- showBSOD('Error');
195
- // Don't set another timeout, we're done checking
196
- return;
197
- }
198
- }
199
-
200
- // Continue checking every 5 seconds
201
- setTimeout(checkSandboxTimeout, 5000);
202
- };
203
-
204
- const showBSOD = function(statusText = 'Error') {
205
- console.log("Showing BSOD with status: " + statusText);
206
- const iframe = document.getElementById('sandbox-iframe');
207
- const bsod = document.getElementById('bsod-image');
208
-
209
- if (iframe && bsod) {
210
- iframe.style.display = 'none';
211
- bsod.style.display = 'block';
212
-
213
- // Update status indicator
214
- const statusIndicator = document.querySelector('.status-indicator');
215
- const statusTextElem = document.querySelector('.status-text');
216
-
217
- if (statusIndicator) {
218
- statusIndicator.className = 'status-indicator status-error';
219
- }
220
-
221
- if (statusTextElem) {
222
- statusTextElem.innerText = statusText;
223
- }
224
- }
225
- };
226
-
227
- const resetBSOD = function() {
228
- console.log("Resetting BSOD display");
229
- const iframe = document.getElementById('sandbox-iframe');
230
- const bsod = document.getElementById('bsod-image');
231
-
232
- if (iframe && bsod) {
233
- if (bsod.style.display === 'block') {
234
- // BSOD is currently showing, reset it
235
- iframe.style.display = 'block';
236
- bsod.style.display = 'none';
237
- console.log("BSOD reset complete");
238
- return true; // Indicates reset was performed
239
- }
240
- }
241
- return false; // No reset needed
242
- };
243
-
244
- // Function to monitor for error messages
245
- const monitorForErrors = function() {
246
- console.log("Error monitor started");
247
- const resultsInterval = setInterval(function() {
248
- const resultsElements = document.querySelectorAll('textarea, .output-text');
249
- for (let elem of resultsElements) {
250
- const content = elem.value || elem.innerText || '';
251
- if (content.includes('Error running agent')) {
252
- console.log("Error detected!");
253
- showBSOD('Error');
254
- clearInterval(resultsInterval);
255
- break;
256
- }
257
- }
258
- }, 1000);
259
- };
260
-
261
-
262
- // Start monitoring for timeouts immediately
263
- checkSandboxTimeout();
264
-
265
- // Start monitoring for errors
266
- setTimeout(monitorForErrors, 3000);
267
-
268
- // Also monitor for errors after button clicks
269
- document.addEventListener('click', function(e) {
270
- if (e.target.tagName === 'BUTTON') {
271
- if (e.target.innerText === "Let's go!") {
272
- resetBSOD();
273
- }
274
- setTimeout(monitorForErrors, 3000);
275
- }
276
- });
277
-
278
- // Set up an interval to click the refresh button every 5 seconds
279
- setInterval(function() {
280
- const btn = document.getElementById('refresh-log-btn');
281
- if (btn) btn.click();
282
- }, 5000);
283
-
284
- // Force dark mode
285
- const params = new URLSearchParams(window.location.search);
286
- if (!params.has('__theme')) {
287
- params.set('__theme', 'dark');
288
- window.location.search = params.toString();
289
- }
290
- }
291
- """
292
 
293
  def write_to_console_log(log_file_path, message):
294
  """
 
17
  from e2bqwen import QwenVLAPIModel, E2BVisionAgent
18
 
19
  E2B_API_KEY = os.getenv("E2B_API_KEY")
20
+ HF_TOKEN = os.getenv("HUGGINGFACE_API_KEY")
21
+ HF_ENDPOINT_URL = os.getenv("HUGGINGFACE_ENPOINT_URL")
22
+
23
  SANDBOXES = {}
24
  SANDBOX_METADATA = {}
25
  SANDBOX_TIMEOUT = 600
 
29
  if not os.path.exists(TMP_DIR):
30
  os.makedirs(TMP_DIR)
31
 
32
+ CSS_PATH = "./custom.css"
33
+ SANDBOX_TEMPLATE = "./sandbox.html"
34
+ FOOTER_PATH = "./footer.html"
35
+ JS_PATH = "./custom.js"
36
+
37
+ login(token=HF_TOKEN)
38
  model = QwenVLAPIModel(
39
+ hf_base_url=HF_ENDPOINT_URL,
40
+ hf_token = HF_TOKEN,
41
  )
42
 
43
+ with open(CSS_PATH, "r") as f:
44
+ custom_css = f.read().replace("<<WIDTH>>", str(WIDTH+15)).replace("<<HEIGHT>>", str(HEIGHT+10))
45
+
46
+ with open(FOOTER_PATH, "r") as f:
47
+ footer_html = f.read()
48
+
49
+ with open(SANDBOX_TEMPLATE, "r") as f:
50
+ sandbox_html_template = f.read().replace("<<WIDTH>>", str(WIDTH+15)).replace("<<HEIGHT>>", str(HEIGHT+10))
51
+
52
+ with open(JS_PATH, "r") as f:
53
+ custom_js = f.read()
54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  def write_to_console_log(log_file_path, message):
57
  """
custom.css ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ .sandbox-container {
3
+ position: relative;
4
+ width: 910px;
5
+ overflow: hidden;
6
+ margin: auto;
7
+ }
8
+ .sandbox-container {
9
+ height: 800px;
10
+ }
11
+ .sandbox-frame {
12
+ display: none;
13
+ position: absolute;
14
+ top: 0;
15
+ left: 0;
16
+ width: 910px;
17
+ height: 800px;
18
+ pointer-events:none;
19
+ }
20
+
21
+ .sandbox-iframe, .bsod-image {
22
+ position: absolute;
23
+ width: <<WIDTH>>px;
24
+ height: <<HEIGHT>>px;
25
+ border: 4px solid #444444;
26
+ transform-origin: 0 0;
27
+ }
28
+
29
+ /* Colored label for task textbox */
30
+ .primary-color-label label span {
31
+ font-weight: bold;
32
+ color: var(--color-accent);
33
+ }
34
+
35
+ /* Status indicator light */
36
+ .status-bar {
37
+ display: flex;
38
+ flex-direction: row;
39
+ align-items: center;
40
+ flex-align:center;
41
+ z-index: 100;
42
+ }
43
+
44
+ .status-indicator {
45
+ width: 15px;
46
+ height: 15px;
47
+ border-radius: 50%;
48
+ }
49
+
50
+ .status-text {
51
+ font-size: 16px;
52
+ font-weight: bold;
53
+ padding: 0 10px;
54
+ text-shadow: none;
55
+ }
56
+
57
+ .status-interactive {
58
+ background-color: #2ecc71;
59
+ animation: blink 2s infinite;
60
+ }
61
+
62
+ .status-view-only {
63
+ background-color: #e74c3c;
64
+ }
65
+
66
+ .status-error {
67
+ background-color: #e74c3c;
68
+ animation: blink-error 1s infinite;
69
+ }
70
+
71
+ @keyframes blink-error {
72
+ 0% { background-color: rgba(231, 76, 60, 1); }
73
+ 50% { background-color: rgba(231, 76, 60, 0.4); }
74
+ 100% { background-color: rgba(231, 76, 60, 1); }
75
+ }
76
+
77
+ @keyframes blink {
78
+ 0% { background-color: rgba(46, 204, 113, 1); } /* Green at full opacity */
79
+ 50% { background-color: rgba(46, 204, 113, 0.4); } /* Green at 40% opacity */
80
+ 100% { background-color: rgba(46, 204, 113, 1); } /* Green at full opacity */
81
+ }
82
+
83
+ .logo-container {
84
+ display: flex;
85
+ flex-direction: column;
86
+ justify-content: space-between;
87
+ align-items: center;
88
+ width: 100%;
89
+ box-sizing: border-box;
90
+ }
91
+
92
+ .logo-item {
93
+ flex: 1;
94
+ display: flex;
95
+ justify-content: center;
96
+ align-items: center;
97
+ padding: 0 15px;
98
+ }
99
+
100
+ .logo-item img {
101
+ height: 60px;
102
+ object-fit: contain;
103
+ }
custom.js ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function() {
2
+ document.body.classList.add('dark');
3
+
4
+ // Function to check if sandbox is timing out
5
+ const checkSandboxTimeout = function() {
6
+ const timeElement = document.getElementById('sandbox-creation-time');
7
+
8
+ if (timeElement) {
9
+ const creationTime = parseFloat(timeElement.getAttribute('data-time'));
10
+ const timeoutValue = parseFloat(timeElement.getAttribute('data-timeout'));
11
+ const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
12
+
13
+ const elapsedTime = currentTime - creationTime;
14
+ console.log("Sandbox running for: " + elapsedTime + " seconds of " + timeoutValue + " seconds");
15
+
16
+ // If we've exceeded the timeout, show BSOD
17
+ if (elapsedTime >= timeoutValue) {
18
+ console.log("Sandbox timeout! Showing BSOD");
19
+ showBSOD('Error');
20
+ // Don't set another timeout, we're done checking
21
+ return;
22
+ }
23
+ }
24
+
25
+ // Continue checking every 5 seconds
26
+ setTimeout(checkSandboxTimeout, 5000);
27
+ };
28
+
29
+ const showBSOD = function(statusText = 'Error') {
30
+ console.log("Showing BSOD with status: " + statusText);
31
+ const iframe = document.getElementById('sandbox-iframe');
32
+ const bsod = document.getElementById('bsod-image');
33
+
34
+ if (iframe && bsod) {
35
+ iframe.style.display = 'none';
36
+ bsod.style.display = 'block';
37
+
38
+ // Update status indicator
39
+ const statusIndicator = document.querySelector('.status-indicator');
40
+ const statusTextElem = document.querySelector('.status-text');
41
+
42
+ if (statusIndicator) {
43
+ statusIndicator.className = 'status-indicator status-error';
44
+ }
45
+
46
+ if (statusTextElem) {
47
+ statusTextElem.innerText = statusText;
48
+ }
49
+ }
50
+ };
51
+
52
+ const resetBSOD = function() {
53
+ console.log("Resetting BSOD display");
54
+ const iframe = document.getElementById('sandbox-iframe');
55
+ const bsod = document.getElementById('bsod-image');
56
+
57
+ if (iframe && bsod) {
58
+ if (bsod.style.display === 'block') {
59
+ // BSOD is currently showing, reset it
60
+ iframe.style.display = 'block';
61
+ bsod.style.display = 'none';
62
+ console.log("BSOD reset complete");
63
+ return true; // Indicates reset was performed
64
+ }
65
+ }
66
+ return false; // No reset needed
67
+ };
68
+
69
+ // Function to monitor for error messages
70
+ const monitorForErrors = function() {
71
+ console.log("Error monitor started");
72
+ const resultsInterval = setInterval(function() {
73
+ const resultsElements = document.querySelectorAll('textarea, .output-text');
74
+ for (let elem of resultsElements) {
75
+ const content = elem.value || elem.innerText || '';
76
+ if (content.includes('Error running agent')) {
77
+ console.log("Error detected!");
78
+ showBSOD('Error');
79
+ clearInterval(resultsInterval);
80
+ break;
81
+ }
82
+ }
83
+ }, 1000);
84
+ };
85
+
86
+
87
+ // Start monitoring for timeouts immediately
88
+ checkSandboxTimeout();
89
+
90
+ // Start monitoring for errors
91
+ setTimeout(monitorForErrors, 3000);
92
+
93
+ // Also monitor for errors after button clicks
94
+ document.addEventListener('click', function(e) {
95
+ if (e.target.tagName === 'BUTTON') {
96
+ if (e.target.innerText === "Let's go!") {
97
+ resetBSOD();
98
+ }
99
+ setTimeout(monitorForErrors, 3000);
100
+ }
101
+ });
102
+
103
+ // Set up an interval to click the refresh button every 5 seconds
104
+ setInterval(function() {
105
+ const btn = document.getElementById('refresh-log-btn');
106
+ if (btn) btn.click();
107
+ }, 5000);
108
+
109
+ // Force dark mode
110
+ const params = new URLSearchParams(window.location.search);
111
+ if (!params.has('__theme')) {
112
+ params.set('__theme', 'dark');
113
+ window.location.search = params.toString();
114
+ }
115
+ }
footer.html ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <h3 style="text-align: center; margin-top:100px;"><i>Powered by:</i></h2>
2
+ <div class="logo-container">
3
+ <a class="logo-item" href="https://github.com/huggingface/smolagents">
4
+ <img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/smolagents/smolagents.png" alt="Smolagents logo">
5
+ </a>
6
+ <a class="logo-item" href="https://huggingface.co/Qwen/Qwen2.5-VL-32B-Instruct">
7
+ <img src="https://upload.wikimedia.org/wikipedia/en/8/85/Logo_of_Qwen.png" alt="Qwen logo", style="height:48px;margin-top=10px;">
8
+ </a>
9
+ <a class="logo-item" href="https://github.com/e2b-dev/desktop">
10
+ <img src="https://image.pitchbook.com/XcarTFiUTDTVBfBep3JKHtiTAob1714067332850_200x200" alt="e2b logo", style="height:80px;">
11
+ </a>
12
+ </div>
sandbox.html ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <style>
2
+ @import url('https://fonts.googleapis.com/css2?family=Oxanium:[email protected]&display=swap');
3
+ </style>
4
+ <div class="sandbox-container">
5
+ <div class="status-bar">
6
+ <div class="status-indicator {status_class}"></div>
7
+ <div class="status-text">{status_text}</div>
8
+ </div>
9
+ <iframe id="sandbox-iframe"
10
+ src="{stream_url}"
11
+ class="sandbox-iframe"
12
+ style="display: block;"
13
+ allowfullscreen>
14
+ </iframe>
15
+ <img src="https://huggingface.co/datasets/mfarre/servedfiles/resolve/main/blue_screen_of_death.gif" class="bsod-image" style="display: none;"/>
16
+ <img src="https://huggingface.co/datasets/m-ric/images/resolve/main/HUD_thom.png" class="sandbox-frame" />
17
+ </div>