lvwerra HF Staff commited on
Commit
33826e4
·
1 Parent(s): 7e08911

ui overhaul

Browse files
Files changed (3) hide show
  1. README.md +1 -1
  2. app.py +17 -35
  3. jupyter_handler.py +76 -10
README.md CHANGED
@@ -8,7 +8,7 @@ sdk_version: 5.30.0
8
  app_file: app.py
9
  pinned: false
10
  thumbnail: >-
11
- https://huggingface.co/spaces/lvwerra/jupyter-agent/resolve/main/jupyter-agent.png
12
  ---
13
 
14
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
8
  app_file: app.py
9
  pinned: false
10
  thumbnail: >-
11
+ https://huggingface.co/spaces/lvwerra/jupyter-agent-2/resolve/main/jupyter-agent-2.png
12
  ---
13
 
14
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py CHANGED
@@ -29,6 +29,8 @@ DEFAULT_MAX_TOKENS = 512
29
  SANDBOXES = {}
30
  SANDBOX_TIMEOUT = 300
31
  TMP_DIR = './tmp/'
 
 
32
  if not os.path.exists(TMP_DIR):
33
  os.makedirs(TMP_DIR)
34
 
@@ -44,7 +46,7 @@ The following files are available (if any):
44
  """
45
 
46
  def execute_jupyter_agent(
47
- sytem_prompt, user_input, max_new_tokens, model, files, message_history, request: gr.Request
48
  ):
49
  if request.session_hash not in SANDBOXES:
50
  SANDBOXES[request.session_hash] = Sandbox(api_key=E2B_API_KEY, timeout=SANDBOX_TIMEOUT)
@@ -68,6 +70,7 @@ def execute_jupyter_agent(
68
  sbx.files.write(filpath.name, file)
69
  filenames.append(filpath.name)
70
 
 
71
  # Initialize message_history if it doesn't exist
72
  if len(message_history) == 0:
73
  if files is None:
@@ -86,7 +89,7 @@ def execute_jupyter_agent(
86
  #print("history:", message_history)
87
 
88
  for notebook_html, notebook_data, messages in run_interactive_notebook(
89
- client, model, message_history, sbx, max_new_tokens=max_new_tokens
90
  ):
91
  message_history = messages
92
 
@@ -126,47 +129,26 @@ with gr.Blocks() as demo:
126
 
127
  user_input = gr.Textbox(
128
  #value="Write code to multiply three numbers: 10048, 32, 19", lines=3, label="User input"
129
- value="Solve the Lotka-Volterra equation and plot the results. Do it step by step and explain what you are doing and in the end make a super nice and clean plot.", lines=3, label="User input"
130
  )
131
-
132
- with gr.Row():
133
- generate_btn = gr.Button("Let's go!")
134
- clear_btn = gr.Button("Clear")
135
 
136
- file = gr.File(TMP_DIR+"jupyter-agent.ipynb", label="Download Jupyter Notebook")
 
 
137
 
138
- with gr.Accordion("Upload files", open=False):
139
  files = gr.File(label="Upload files to use", file_count="multiple")
 
140
 
141
- with gr.Accordion("Advanced Settings", open=False):
142
- system_input = gr.Textbox(
143
- label="System Prompt",
144
- value=DEFAULT_SYSTEM_PROMPT,
145
- elem_classes="input-box",
146
- lines=8,
147
- )
148
- with gr.Row():
149
- max_tokens = gr.Number(
150
- label="Max New Tokens",
151
- value=DEFAULT_MAX_TOKENS,
152
- minimum=128,
153
- maximum=2048,
154
- step=8,
155
- interactive=True,
156
- )
157
-
158
- model = gr.Dropdown(
159
- value="Qwen/Qwen3-Coder-480B-A35B-Instruct:cerebras",
160
- choices=[
161
- "Qwen/Qwen3-Coder-30B-A3B-Instruct",
162
- "Qwen/Qwen3-Coder-480B-A35B-Instruct:cerebras",
163
- ],
164
- label="Models"
165
- )
166
 
167
  generate_btn.click(
168
  fn=execute_jupyter_agent,
169
- inputs=[system_input, user_input, max_tokens, model, files, msg_state],
170
  outputs=[html_output, msg_state, file],
171
  )
172
 
 
29
  SANDBOXES = {}
30
  SANDBOX_TIMEOUT = 300
31
  TMP_DIR = './tmp/'
32
+ model="Qwen/Qwen3-Coder-480B-A35B-Instruct:cerebras"
33
+
34
  if not os.path.exists(TMP_DIR):
35
  os.makedirs(TMP_DIR)
36
 
 
46
  """
47
 
48
  def execute_jupyter_agent(
49
+ user_input, files, message_history, request: gr.Request
50
  ):
51
  if request.session_hash not in SANDBOXES:
52
  SANDBOXES[request.session_hash] = Sandbox(api_key=E2B_API_KEY, timeout=SANDBOX_TIMEOUT)
 
70
  sbx.files.write(filpath.name, file)
71
  filenames.append(filpath.name)
72
 
73
+ sytem_prompt = DEFAULT_SYSTEM_PROMPT
74
  # Initialize message_history if it doesn't exist
75
  if len(message_history) == 0:
76
  if files is None:
 
89
  #print("history:", message_history)
90
 
91
  for notebook_html, notebook_data, messages in run_interactive_notebook(
92
+ client, model, message_history, sbx,
93
  ):
94
  message_history = messages
95
 
 
129
 
130
  user_input = gr.Textbox(
131
  #value="Write code to multiply three numbers: 10048, 32, 19", lines=3, label="User input"
132
+ value="Solve the Lotka-Volterra equation and plot the results. Do it step by step and explain what you are doing and in the end make a super nice and clean plot.", label="Agent task"
133
  )
 
 
 
 
134
 
135
+ with gr.Row():
136
+ generate_btn = gr.Button("Run!")
137
+ clear_btn = gr.Button("Clear Notebook")
138
 
139
+ with gr.Accordion("Upload files ⬆ | Download notebook⬇", open=False):
140
  files = gr.File(label="Upload files to use", file_count="multiple")
141
+ file = gr.File(TMP_DIR+"jupyter-agent.ipynb", label="Download Jupyter Notebook")
142
 
143
+ powered_html = gr.HTML("""\
144
+ <p align="center">
145
+ <img style="height:100px;"src="https://huggingface.co/spaces/lvwerra/jupyter-agent-2/resolve/main/powered-by.png" alt="Powered by" />
146
+ </p>""")
147
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
  generate_btn.click(
150
  fn=execute_jupyter_agent,
151
+ inputs=[user_input, files, msg_state],
152
  outputs=[html_output, msg_state, file],
153
  )
154
 
jupyter_handler.py CHANGED
@@ -9,11 +9,12 @@ import datetime
9
 
10
  system_template = """\
11
  <details>
12
- <summary style="display: flex; align-items: center; cursor: pointer;">
13
- <span style="background-color: #374151; color: white; padding: 0px 4px; border-radius: 3px; font-weight: 500; display: inline-block;">System:</span>
14
- <span class="arrow" style="margin-left: 8px; font-size: 12px;">▶</span>
 
15
  </summary>
16
- <div style="margin-top: 8px; padding: 8px; background-color: #f9fafb; border-radius: 4px; border-left: 3px solid #374151;">
17
  {}
18
  </div>
19
  </details>
@@ -36,11 +37,18 @@ details > summary::-webkit-details-marker {{
36
  """
37
 
38
  user_template = """\
39
- <span style="background-color: #166534; color: white; padding: 0px 4px; border-radius: 3px; font-weight: 500; display: inline-block; margin-bottom: 0px;">User:</span> {}"""
40
-
 
 
 
41
 
42
  assistant_thinking_template = """\
43
- <span style="background-color: #1d5b8e; color: white; padding: 0px 4px; border-radius: 3px; font-weight: 500; display: inline-block; margin-bottom: 0px;">Assistant:</span> {}"""
 
 
 
 
44
 
45
  assistant_final_answer_template = """<div class="alert alert-block alert-warning">
46
  <b>Assistant:</b> Final answer: {}
@@ -48,11 +56,11 @@ assistant_final_answer_template = """<div class="alert alert-block alert-warning
48
  """
49
 
50
  header_message = """<p align="center">
51
- <img src="https://huggingface.co/spaces/lvwerra/jupyter-agent/resolve/main/jupyter-agent.png" alt="Jupyter Agent Logo" />
52
  </p>
53
 
54
 
55
- <p style="text-align:center;">Let a LLM agent write and execute code inside a notebook!</p>"""
56
 
57
  bad_html_bad = """input[type="file"] {
58
  display: block;
@@ -195,6 +203,33 @@ TIMEOUT_HTML = """
195
  </style>
196
  """
197
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
  # just make the code font a bit smaller
199
  custom_css = """
200
  <style type="text/css">
@@ -569,4 +604,35 @@ class JupyterNotebook:
569
  # make code font a bit smaller with custom css
570
  if "<head>" in notebook_body:
571
  notebook_body = notebook_body.replace("</head>", f"{custom_css}</head>")
572
- return notebook_body
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  system_template = """\
11
  <details>
12
+ <summary style="display: flex; align-items: center; cursor: pointer; margin-bottom: 12px;">
13
+ <h3 style="color: #374151; margin: 0; margin-right: 8px; font-size: 14px; font-weight: 600;">System</h3>
14
+ <span class="arrow" style="margin-right: 12px; font-size: 12px;">▶</span>
15
+ <div style="flex: 1; height: 2px; background-color: #374151;"></div>
16
  </summary>
17
+ <div style="margin-top: 8px; padding: 8px; background-color: #f9fafb; border-radius: 4px; border-left: 3px solid #374151; margin-bottom: 16px;">
18
  {}
19
  </div>
20
  </details>
 
37
  """
38
 
39
  user_template = """\
40
+ <div style="display: flex; align-items: center; margin-bottom: 12px;">
41
+ <h3 style="color: #166534; margin: 0; margin-right: 12px; font-size: 14px; font-weight: 600;">User</h3>
42
+ <div style="flex: 1; height: 2px; background-color: #166534;"></div>
43
+ </div>
44
+ <div style="margin-bottom: 16px;">{}</div>"""
45
 
46
  assistant_thinking_template = """\
47
+ <div style="display: flex; align-items: center; margin-bottom: 12px;">
48
+ <h3 style="color: #1d5b8e; margin: 0; margin-right: 12px; font-size: 14px; font-weight: 600;">Assistant</h3>
49
+ <div style="flex: 1; height: 2px; background-color: #1d5b8e;"></div>
50
+ </div>
51
+ <div style="margin-bottom: 16px;">{}</div>"""
52
 
53
  assistant_final_answer_template = """<div class="alert alert-block alert-warning">
54
  <b>Assistant:</b> Final answer: {}
 
56
  """
57
 
58
  header_message = """<p align="center">
59
+ <img style="height:120px;"src="https://huggingface.co/spaces/lvwerra/jupyter-agent-2/resolve/main/jupyter-agent-2.png" alt="Jupyter Agent Logo" />
60
  </p>
61
 
62
 
63
+ <p style="text-align:center;">Running Qwen3-Coder-480B-A35B-Instruct in a Jupyter notebook powered by E2B, Cerebras and Hugging Face Inference Providers.</p>"""
64
 
65
  bad_html_bad = """input[type="file"] {
66
  display: block;
 
203
  </style>
204
  """
205
 
206
+ TIMEOUT_HTML = """
207
+ <div style="display: flex; align-items: center; gap: 8px; padding: 6px 10px; background-color: #fafafa; border-radius: 4px; border-left: 2px solid #d1d5db; margin-bottom: 8px; font-size: 12px;">
208
+ <div style="width: 12px; height: 12px; background-color: #d1d5db; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; font-size: 8px;">
209
+
210
+ </div>
211
+ <div style="flex: 1;">
212
+ <div style="margin-bottom: 2px; font-size: 11px; color: #6b7280; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-weight: 400;">
213
+ Sandbox timeout: {total_seconds}s
214
+ </div>
215
+ <div style="width: 100%; height: 6px; background-color: #e5e7eb; border-radius: 3px; overflow: hidden;">
216
+ <div id="progress-bar-{unique_id}" style="height: 100%; background-color: #6b7280; border-radius: 3px; width: {current_progress}%; animation: progress-fill-{unique_id} {remaining_seconds}s linear forwards;"></div>
217
+ </div>
218
+ <div style="display: flex; justify-content: space-between; margin-top: 2px; font-size: 10px; color: #9ca3af; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
219
+ <span>Started: {start_time}</span>
220
+ <span>Expires: {end_time}</span>
221
+ </div>
222
+ </div>
223
+ </div>
224
+
225
+ <style>
226
+ @keyframes progress-fill-{unique_id} {{
227
+ from {{ width: {current_progress}%; }}
228
+ to {{ width: 100%; }}
229
+ }}
230
+ </style>
231
+ """
232
+
233
  # just make the code font a bit smaller
234
  custom_css = """
235
  <style type="text/css">
 
604
  # make code font a bit smaller with custom css
605
  if "<head>" in notebook_body:
606
  notebook_body = notebook_body.replace("</head>", f"{custom_css}</head>")
607
+ return notebook_body
608
+
609
+ def main():
610
+ """Create a mock notebook to test styling"""
611
+ # Create mock messages
612
+ mock_messages = [
613
+ {"role": "system", "content": "You are a helpful AI assistant that can write and execute Python code."},
614
+ {"role": "user", "content": "Can you help me create a simple plot of a sine wave?"},
615
+ {"role": "assistant", "content": "I'll help you create a sine wave plot using matplotlib. Let me write the code for that."},
616
+ {"role": "assistant", "tool_calls": [{"id": "call_1", "function": {"name": "add_and_execute_jupyter_code_cell", "arguments": '{"code": "import numpy as np\\nimport matplotlib.pyplot as plt\\n\\n# Create x values\\nx = np.linspace(0, 4*np.pi, 100)\\ny = np.sin(x)\\n\\n# Create the plot\\nplt.figure(figsize=(10, 6))\\nplt.plot(x, y, \'b-\', linewidth=2)\\nplt.title(\'Sine Wave\')\\nplt.xlabel(\'x\')\\nplt.ylabel(\'sin(x)\')\\nplt.grid(True)\\nplt.show()"}'}}]},
617
+ {"role": "tool", "tool_call_id": "call_1", "raw_execution": [{"output_type": "stream", "name": "stdout", "text": "Plot created successfully!"}]}
618
+ ]
619
+
620
+ # Create notebook
621
+ notebook = JupyterNotebook(mock_messages)
622
+
623
+ # Add a timeout countdown (simulating a sandbox that started 2 minutes ago with 5 minute timeout)
624
+ start_time = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(minutes=2)
625
+ end_time = start_time + datetime.timedelta(minutes=5)
626
+ notebook.add_sandbox_countdown(start_time, end_time)
627
+
628
+ # Render and save
629
+ html_output = notebook.render()
630
+
631
+ with open("mock_notebook.html", "w", encoding="utf-8") as f:
632
+ f.write(html_output)
633
+
634
+ print("Mock notebook saved as 'mock_notebook.html'")
635
+ print("Open it in your browser to see the styling changes.")
636
+
637
+ if __name__ == "__main__":
638
+ main()