Fraser commited on
Commit
fe73d4f
·
1 Parent(s): 88005dc

stuck with asyncio issues

Browse files
Makefile CHANGED
@@ -5,3 +5,6 @@ proxy:
5
  uv sync
6
  uv pip install -e .
7
  playwright install
 
 
 
 
5
  uv sync
6
  uv pip install -e .
7
  playwright install
8
+
9
+ app:
10
+ streamlit run src/proxy_lite/app.py
pyproject.toml CHANGED
@@ -16,6 +16,7 @@ dependencies = [
16
  "tenacity>=9.0.0",
17
  "torch>=2.6.0",
18
  "torchvision>=0.21.0",
 
19
  ]
20
 
21
  [project.scripts]
 
16
  "tenacity>=9.0.0",
17
  "torch>=2.6.0",
18
  "torchvision>=0.21.0",
19
+ "streamlit>=1.40.2",
20
  ]
21
 
22
  [project.scripts]
src/proxy_lite/app.py ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import base64
3
+ from io import BytesIO
4
+
5
+ import streamlit as st
6
+ from PIL import Image
7
+
8
+ from proxy_lite import Runner, RunnerConfig
9
+
10
+
11
+ def get_user_config(config_expander):
12
+ config = {
13
+ "environment": {
14
+ "name": "webbrowser",
15
+ "annotate_image": True,
16
+ "screenshot_delay": 2.0,
17
+ "include_html": False,
18
+ "viewport_width": 1280,
19
+ "viewport_height": 1920,
20
+ "include_poi_text": True,
21
+ "homepage": "https://www.google.com",
22
+ "keep_original_image": False,
23
+ },
24
+ "solver": {
25
+ "name": "simple",
26
+ "agent": {
27
+ "name": "proxy_lite",
28
+ "client": {
29
+ "name": "convergence",
30
+ "model_id": "convergence-ai/subset-distill-tools-7b-15-02-2025",
31
+ "api_base": "http://slurm1-a3nodeset-4-1:8002/v1",
32
+ },
33
+ },
34
+ },
35
+ "local_view": False,
36
+ "verbose": True,
37
+ "task_timeout": 1800, # 30 minutes
38
+ "action_timeout": 300,
39
+ "environment_timeout": 30,
40
+ }
41
+
42
+ with config_expander:
43
+ st.subheader("Environment Settings")
44
+ col1, col2 = st.columns(2)
45
+
46
+ with col1:
47
+ config["environment"]["include_html"] = st.checkbox(
48
+ "Include HTML",
49
+ value=config["environment"]["include_html"],
50
+ help="Include HTML in observations",
51
+ )
52
+ config["environment"]["include_poi_text"] = st.checkbox(
53
+ "Include POI Text",
54
+ value=config["environment"]["include_poi_text"],
55
+ help="Include points of interest text in observations",
56
+ )
57
+ config["environment"]["homepage"] = st.text_input(
58
+ "Homepage",
59
+ value=config["environment"]["homepage"],
60
+ help="Homepage to start from",
61
+ )
62
+
63
+ with col2:
64
+ config["environment"]["screenshot_delay"] = st.slider(
65
+ "Screenshot Delay (seconds)",
66
+ min_value=0.5,
67
+ max_value=10.0,
68
+ value=config["environment"]["screenshot_delay"],
69
+ step=0.5,
70
+ help="Delay before taking screenshots",
71
+ )
72
+
73
+ st.subheader("Advanced Settings")
74
+ config["task_timeout"] = st.number_input(
75
+ "Task Timeout (seconds)",
76
+ min_value=60,
77
+ max_value=3600,
78
+ step=60,
79
+ value=config["task_timeout"],
80
+ help="Maximum time allowed for task completion",
81
+ )
82
+ config["action_timeout"] = st.number_input(
83
+ "Action Timeout (seconds)",
84
+ min_value=10,
85
+ max_value=300,
86
+ step=10,
87
+ value=config["action_timeout"],
88
+ help="Maximum time allowed for an action to complete",
89
+ )
90
+ config["environment_timeout"] = st.number_input(
91
+ "Environment Timeout (seconds)",
92
+ min_value=10,
93
+ max_value=300,
94
+ step=10,
95
+ value=config["environment_timeout"],
96
+ help="Maximum time allowed for environment to respond",
97
+ )
98
+
99
+ return config
100
+
101
+
102
+ async def run_task_async(
103
+ task: str,
104
+ status_placeholder,
105
+ action_placeholder,
106
+ environment_placeholder,
107
+ image_placeholder,
108
+ history_placeholder,
109
+ config: dict,
110
+ ):
111
+ try:
112
+ config = RunnerConfig.from_dict(config)
113
+ except Exception as e:
114
+ st.error(f"Error loading RunnerConfig: {e!s}")
115
+ return
116
+ print(config)
117
+ runner = Runner(config=config)
118
+
119
+ # Add the spinning animation using HTML
120
+ status_placeholder.markdown(
121
+ """
122
+ <style>
123
+ @keyframes spin {
124
+ 0% { content: "⚡"; }
125
+ 25% { content: "⚡."; }
126
+ 50% { content: "⚡.."; }
127
+ 75% { content: "⚡..."; }
128
+ }
129
+ .spinner::before {
130
+ content: "⚡";
131
+ animation: spin 2s linear infinite;
132
+ display: inline-block;
133
+ }
134
+ </style>
135
+ <div><b>Resolving your task </b><span class="spinner"></span></div>
136
+ """,
137
+ unsafe_allow_html=True,
138
+ )
139
+
140
+ all_steps = []
141
+ all_screenshots = []
142
+ all_soms = []
143
+
144
+ async for run in runner.run_generator(task):
145
+ # Update status with latest step
146
+ if run.actions:
147
+ latest_step = run.actions[-1].text
148
+ latest_step += "".join([
149
+ f'<tool_call>{{"name": {tool_call.function["name"]}, "arguments": {tool_call.function["arguments"]}}}</tool_call>' for tool_call in run.actions[-1].tool_calls
150
+ ])
151
+ action_placeholder.write(f"⚡ **Latest Step:** {latest_step}")
152
+ all_steps.append(latest_step)
153
+
154
+ # Update image if available
155
+ if run.observations and run.observations[-1].state.image:
156
+ environment_placeholder.write("🌐 **Environment:**")
157
+ image_bytes = base64.b64decode(run.observations[-1].state.image)
158
+ image = Image.open(BytesIO(image_bytes))
159
+ image_placeholder.image(image, use_container_width=True)
160
+ all_screenshots.append(image)
161
+ som = run.observations[-1].state.text
162
+ all_soms.append(som)
163
+
164
+ # Update history
165
+ with history_placeholder, st.expander("🕝 **History**"):
166
+ for idx, (action, img, som) in enumerate(zip(all_steps, all_screenshots, all_soms, strict=False)):
167
+ st.write(f"**Step {idx + 1}**")
168
+ st.image(img, use_container_width=True)
169
+ with st.expander("points of interest", expanded=False):
170
+ st.markdown(som)
171
+ st.write(f"**Action:** {action}")
172
+ action_placeholder.write(" ")
173
+ status_placeholder.write(f"✨ **Result:** {latest_step}")
174
+
175
+
176
+ def main():
177
+ st.title("⚡ Proxy-Lite")
178
+
179
+ def img_to_base64(image_path):
180
+ with open(image_path, "rb") as img_file:
181
+ return base64.b64encode(img_file.read()).decode("utf-8")
182
+
183
+ st.markdown("Powered by **Proxy-Lite**", unsafe_allow_html=True)
184
+
185
+ if "config_expanded" not in st.session_state:
186
+ st.session_state.config_expanded = False
187
+ if "settings_expanded" not in st.session_state:
188
+ st.session_state.settings_expanded = False
189
+
190
+ config_expander = st.expander("⚙️ Proxy-Lite Configuration", expanded=st.session_state.config_expanded)
191
+ config = get_user_config(config_expander)
192
+
193
+ with st.form(key="run_task_form"):
194
+ task = st.text_input(
195
+ "Submit a task",
196
+ key="task_input",
197
+ help="Enter a task to be completed",
198
+ )
199
+ submit_button = st.form_submit_button("Submit a task", type="primary", use_container_width=True)
200
+
201
+ if submit_button:
202
+ st.session_state.config_expanded = False
203
+ if task:
204
+ # Create placeholders for dynamic updates
205
+ status_placeholder = st.empty()
206
+ st.write(" ")
207
+ action_placeholder = st.empty()
208
+ environment_placeholder = st.empty()
209
+ image_placeholder = st.empty()
210
+ history_placeholder = st.empty()
211
+
212
+ # Run the async task
213
+ asyncio.run(
214
+ run_task_async(
215
+ task,
216
+ status_placeholder,
217
+ action_placeholder,
218
+ environment_placeholder,
219
+ image_placeholder,
220
+ history_placeholder,
221
+ config,
222
+ ),
223
+ )
224
+
225
+ st.success("Wish granted!", icon="✨")
226
+ else:
227
+ st.error("Please make a wish first!")
228
+
229
+
230
+ if __name__ == "__main__":
231
+ main()
src/proxy_lite/recorder.py CHANGED
@@ -80,7 +80,7 @@ class DataRecorder:
80
  self.local_folder = local_folder
81
 
82
  def initialise_run(self, task: str) -> Run:
83
- self.local_folder = Path(os.path.abspath(sys.path[0])) / "local_trajectories"
84
  os.makedirs(self.local_folder, exist_ok=True)
85
  return Run.initialise(task)
86
 
 
80
  self.local_folder = local_folder
81
 
82
  def initialise_run(self, task: str) -> Run:
83
+ self.local_folder = Path(os.path.abspath(".")) / "local_trajectories"
84
  os.makedirs(self.local_folder, exist_ok=True)
85
  return Run.initialise(task)
86
 
src/proxy_lite/runner.py CHANGED
@@ -55,7 +55,7 @@ class RunnerConfig(BaseModel):
55
  solver: SolverConfigTypes
56
 
57
  save_every_step: bool = True
58
- max_steps: int = 100
59
  action_timeout: float = 60.0
60
  environment_timeout: float = 30.0
61
  task_timeout: float = 1800.0
 
55
  solver: SolverConfigTypes
56
 
57
  save_every_step: bool = True
58
+ max_steps: int = 50
59
  action_timeout: float = 60.0
60
  environment_timeout: float = 30.0
61
  task_timeout: float = 1800.0