lybic-guiagents 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of lybic-guiagents might be problematic. Click here for more details.

Files changed (85) hide show
  1. desktop_env/__init__.py +1 -0
  2. desktop_env/actions.py +203 -0
  3. desktop_env/controllers/__init__.py +0 -0
  4. desktop_env/controllers/python.py +471 -0
  5. desktop_env/controllers/setup.py +882 -0
  6. desktop_env/desktop_env.py +509 -0
  7. desktop_env/evaluators/__init__.py +5 -0
  8. desktop_env/evaluators/getters/__init__.py +41 -0
  9. desktop_env/evaluators/getters/calc.py +15 -0
  10. desktop_env/evaluators/getters/chrome.py +1774 -0
  11. desktop_env/evaluators/getters/file.py +154 -0
  12. desktop_env/evaluators/getters/general.py +42 -0
  13. desktop_env/evaluators/getters/gimp.py +38 -0
  14. desktop_env/evaluators/getters/impress.py +126 -0
  15. desktop_env/evaluators/getters/info.py +24 -0
  16. desktop_env/evaluators/getters/misc.py +406 -0
  17. desktop_env/evaluators/getters/replay.py +20 -0
  18. desktop_env/evaluators/getters/vlc.py +86 -0
  19. desktop_env/evaluators/getters/vscode.py +35 -0
  20. desktop_env/evaluators/metrics/__init__.py +160 -0
  21. desktop_env/evaluators/metrics/basic_os.py +68 -0
  22. desktop_env/evaluators/metrics/chrome.py +493 -0
  23. desktop_env/evaluators/metrics/docs.py +1011 -0
  24. desktop_env/evaluators/metrics/general.py +665 -0
  25. desktop_env/evaluators/metrics/gimp.py +637 -0
  26. desktop_env/evaluators/metrics/libreoffice.py +28 -0
  27. desktop_env/evaluators/metrics/others.py +92 -0
  28. desktop_env/evaluators/metrics/pdf.py +31 -0
  29. desktop_env/evaluators/metrics/slides.py +957 -0
  30. desktop_env/evaluators/metrics/table.py +585 -0
  31. desktop_env/evaluators/metrics/thunderbird.py +176 -0
  32. desktop_env/evaluators/metrics/utils.py +719 -0
  33. desktop_env/evaluators/metrics/vlc.py +524 -0
  34. desktop_env/evaluators/metrics/vscode.py +283 -0
  35. desktop_env/providers/__init__.py +35 -0
  36. desktop_env/providers/aws/__init__.py +0 -0
  37. desktop_env/providers/aws/manager.py +278 -0
  38. desktop_env/providers/aws/provider.py +186 -0
  39. desktop_env/providers/aws/provider_with_proxy.py +315 -0
  40. desktop_env/providers/aws/proxy_pool.py +193 -0
  41. desktop_env/providers/azure/__init__.py +0 -0
  42. desktop_env/providers/azure/manager.py +87 -0
  43. desktop_env/providers/azure/provider.py +207 -0
  44. desktop_env/providers/base.py +97 -0
  45. desktop_env/providers/gcp/__init__.py +0 -0
  46. desktop_env/providers/gcp/manager.py +0 -0
  47. desktop_env/providers/gcp/provider.py +0 -0
  48. desktop_env/providers/virtualbox/__init__.py +0 -0
  49. desktop_env/providers/virtualbox/manager.py +463 -0
  50. desktop_env/providers/virtualbox/provider.py +124 -0
  51. desktop_env/providers/vmware/__init__.py +0 -0
  52. desktop_env/providers/vmware/manager.py +455 -0
  53. desktop_env/providers/vmware/provider.py +105 -0
  54. gui_agents/__init__.py +0 -0
  55. gui_agents/agents/Action.py +209 -0
  56. gui_agents/agents/__init__.py +0 -0
  57. gui_agents/agents/agent_s.py +832 -0
  58. gui_agents/agents/global_state.py +610 -0
  59. gui_agents/agents/grounding.py +651 -0
  60. gui_agents/agents/hardware_interface.py +129 -0
  61. gui_agents/agents/manager.py +568 -0
  62. gui_agents/agents/translator.py +132 -0
  63. gui_agents/agents/worker.py +355 -0
  64. gui_agents/cli_app.py +560 -0
  65. gui_agents/core/__init__.py +0 -0
  66. gui_agents/core/engine.py +1496 -0
  67. gui_agents/core/knowledge.py +449 -0
  68. gui_agents/core/mllm.py +555 -0
  69. gui_agents/tools/__init__.py +0 -0
  70. gui_agents/tools/tools.py +727 -0
  71. gui_agents/unit_test/__init__.py +0 -0
  72. gui_agents/unit_test/run_tests.py +65 -0
  73. gui_agents/unit_test/test_manager.py +330 -0
  74. gui_agents/unit_test/test_worker.py +269 -0
  75. gui_agents/utils/__init__.py +0 -0
  76. gui_agents/utils/analyze_display.py +301 -0
  77. gui_agents/utils/common_utils.py +263 -0
  78. gui_agents/utils/display_viewer.py +281 -0
  79. gui_agents/utils/embedding_manager.py +53 -0
  80. gui_agents/utils/image_axis_utils.py +27 -0
  81. lybic_guiagents-0.1.0.dist-info/METADATA +416 -0
  82. lybic_guiagents-0.1.0.dist-info/RECORD +85 -0
  83. lybic_guiagents-0.1.0.dist-info/WHEEL +5 -0
  84. lybic_guiagents-0.1.0.dist-info/licenses/LICENSE +201 -0
  85. lybic_guiagents-0.1.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,406 @@
1
+ import logging
2
+ from typing import TypeVar, Dict
3
+ from datetime import datetime, timedelta
4
+ import pytz
5
+ import requests
6
+
7
+ logger = logging.getLogger("desktopenv.getters.misc")
8
+
9
+ R = TypeVar("Rule")
10
+
11
+ day_of_week_mapping = {
12
+ 0: 'Mon',
13
+ 1: 'Tue',
14
+ 2: 'Wed',
15
+ 3: 'Thu',
16
+ 4: 'Fri',
17
+ 5: 'Sat',
18
+ 6: 'Sun'
19
+ }
20
+
21
+ month_mapping = {
22
+ 1: 'Jan',
23
+ 2: 'Feb',
24
+ 3: 'Mar',
25
+ 4: 'Apr',
26
+ 5: 'May',
27
+ 6: 'Jun',
28
+ 7: 'Jul',
29
+ 8: 'Aug',
30
+ 9: 'Sep',
31
+ 10: 'Oct',
32
+ 11: 'Nov',
33
+ 12: 'Dec'
34
+ }
35
+
36
+ Month_Mapping_Full = {
37
+ 1: "January",
38
+ 2: "February",
39
+ 3: "March",
40
+ 4: "April",
41
+ 5: "May",
42
+ 6: "June",
43
+ 7: "July",
44
+ 8: "August",
45
+ 9: "September",
46
+ 10: "October",
47
+ 11: "November",
48
+ 12: "December"
49
+ }
50
+
51
+ month_mapping_full = {
52
+ 1: 'january',
53
+ 2: 'february',
54
+ 3:'march',
55
+ 4: 'april',
56
+ 5:'may',
57
+ 6: 'june',
58
+ 7: 'july',
59
+ 8: 'august',
60
+ 9:'september',
61
+ 10: 'october',
62
+ 11: 'november',
63
+ 12: 'december'
64
+ }
65
+
66
+ relativeTime_to_IntDay = {
67
+ "tomorrow": 1,
68
+ "5th next month": "special",
69
+ "10th next month": "special",
70
+ "11th next month": "special",
71
+ "this month": "special",
72
+ "this Saturday": "special",
73
+ "this Sunday": "special",
74
+ "next Monday": "special",
75
+ "next Friday": "special",
76
+ "next Saturday": "special",
77
+ "next Sunday": "special",
78
+ "next week Friday": "special",
79
+ "next week Saturday": "special",
80
+ "next week Sunday": "special",
81
+ "first monday four months later": "special",
82
+ "first monday eight months later": "special",
83
+ "next Monday split": "special",
84
+ "next Friday split": "special"
85
+ }
86
+
87
+ def get_rule(env, config: Dict[str, R]) -> R:
88
+ """
89
+ Returns the rule as-is.
90
+ """
91
+ return config["rules"]
92
+
93
+ def get_rule_relativeTime(env, config: Dict[str, R]) -> R:
94
+ """
95
+ According to the rule definded in funciton "apply_rules_to_timeFormat", convert the relative time to absolute time.
96
+ config:
97
+ 'relativeTime': {
98
+ "from": must exist; indicates the relativeTime.
99
+ "to": optional; indicates the relativeTime.
100
+ }
101
+ If relativeTime only has key "from", then the key of time in "expected" dict must be "time".
102
+ If relativeTime has key "to", then the key of time in "expected" dict must be "from" and "to".
103
+
104
+ Optional 'timezone': timezone string like 'Europe/Zurich', 'America/New_York', etc.
105
+ If not specified, will try to get timezone from IP geolocation.
106
+ """
107
+ logger.info(f"[DEBUG] get_rule_relativeTime called with config: {config}")
108
+
109
+ relativeRules = config["rules"]
110
+ relativeTime = relativeRules["relativeTime"] # int, "+" means future, "-" means past
111
+
112
+ logger.info(f"[DEBUG] relativeTime: {relativeTime}")
113
+
114
+ # Get timezone configuration
115
+ timezone_str = get_timezone_from_config(config)
116
+ try:
117
+ timezone = pytz.timezone(timezone_str)
118
+ logger.info(f"Successfully loaded timezone: {timezone_str}")
119
+ except pytz.exceptions.UnknownTimeZoneError:
120
+ logger.error(f"Unknown timezone: {timezone_str}, falling back to UTC")
121
+ timezone = pytz.UTC
122
+
123
+ # Get current time in the specified timezone
124
+ now = datetime.now(timezone)
125
+ logger.info(f"Current time in {timezone_str}: {now.strftime('%Y-%m-%d %H:%M:%S %Z')}")
126
+
127
+ # calculate the relative time
128
+ if "to" not in relativeTime.keys():
129
+ start_relative_time = relativeTime["from"]
130
+ logger.info(f"Processing single time: '{start_relative_time}'")
131
+
132
+ if relativeTime_to_IntDay[start_relative_time] != "special":
133
+ # relativeTime can be represented by actual int days
134
+ start_relative_time_IntDat = relativeTime_to_IntDay[start_relative_time]
135
+ timediff = timedelta(days=start_relative_time_IntDat)
136
+ absoluteDay = now + timediff
137
+ logger.info(f"Simple calculation: {start_relative_time} = {start_relative_time_IntDat} days → {absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
138
+ else:
139
+ # special case, you can add more special cases here
140
+ if start_relative_time == "5th next month":
141
+ next_year = now.year + 1 if now.month == 12 else now.year
142
+ next_month = now.month + 1 if now.month < 12 else 1
143
+ next_day = 5
144
+ absoluteDay = timezone.localize(datetime(next_year, next_month, next_day))
145
+ logger.info(f"5th next month: {absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
146
+ elif start_relative_time == "10th next month":
147
+ next_year = now.year + 1 if now.month == 12 else now.year
148
+ next_month = now.month + 1 if now.month < 12 else 1
149
+ next_day = 10
150
+ absoluteDay = timezone.localize(datetime(next_year, next_month, next_day))
151
+ logger.info(f"10th next month: {absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
152
+ elif start_relative_time == "this month":
153
+ absoluteDay = now
154
+ logger.info(f"This month: {absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
155
+ elif start_relative_time == "next Monday":
156
+ days_until_monday = (6-now.weekday()) + 1
157
+ absoluteDay = now + timedelta(days=days_until_monday)
158
+ logger.info(f"Next Monday: current weekday={now.weekday()}, days to add={days_until_monday} → {absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
159
+ elif start_relative_time == "first monday four months later":
160
+ next_year = now.year + 1 if now.month >=9 else now.year
161
+ next_month = (now.month + 4)%12
162
+ # get the first monday of the next_month
163
+ temp_date = timezone.localize(datetime(next_year, next_month, 1))
164
+ days_to_monday = ((6-temp_date.weekday())+1)%7
165
+ absoluteDay = temp_date + timedelta(days=days_to_monday)
166
+ logger.info(f"First Monday 4 months later: {next_year}-{next_month:02d} → {absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
167
+ elif start_relative_time == "first monday eight months later":
168
+ next_year = now.year + 1 if now.month >= 5 else now.year
169
+ next_month = (now.month + 8)%12
170
+ # get the first monday of the next_month
171
+ temp_date = timezone.localize(datetime(next_year, next_month, 1))
172
+ days_to_monday = ((6-temp_date.weekday())+1)%7
173
+ absoluteDay = temp_date + timedelta(days=days_to_monday)
174
+ logger.info(f"First Monday 8 months later: {next_year}-{next_month:02d} → {absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
175
+ regular_time = apply_rules_to_timeFormat(relativeRules["expected"]["time"], absoluteDay)
176
+ logger.info(f"Final formatted time: {regular_time}")
177
+ config["rules"]["expected"]["time"] = regular_time
178
+
179
+ else:
180
+ from_time = relativeTime["from"]
181
+ to_time = relativeTime["to"]
182
+ logger.info(f"Processing time range: from '{from_time}' to '{to_time}'")
183
+
184
+ # deal with from_time first
185
+ if relativeTime_to_IntDay[from_time] != "special":
186
+ from_time_IntDat = relativeTime_to_IntDay[from_time]
187
+ from_timediff = timedelta(days=from_time_IntDat)
188
+ from_absoluteDay = now + from_timediff
189
+ logger.info(f"From time calculation: {from_time} = {from_time_IntDat} days → {from_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
190
+ else:
191
+ if from_time == "this Saturday":
192
+ days_until_saturday = (5-now.weekday())
193
+ from_absoluteDay = now + timedelta(days=days_until_saturday)
194
+ logger.info(f"This Saturday: current weekday={now.weekday()}, days to add={days_until_saturday} → {from_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
195
+ elif from_time == "10th next month":
196
+ next_year = now.year + 1 if now.month == 12 else now.year
197
+ next_month = now.month + 1 if now.month < 12 else 1
198
+ next_day = 10
199
+ from_absoluteDay = timezone.localize(datetime(next_year, next_month, next_day))
200
+ logger.info(f"10th next month (from): {from_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
201
+ elif from_time == "next Monday" or from_time == "next Monday split":
202
+ days_until_monday = (6-now.weekday()) + 1
203
+ from_absoluteDay = now + timedelta(days=days_until_monday)
204
+ logger.info(f"Next Monday (from): current weekday={now.weekday()}, days to add={days_until_monday} → {from_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
205
+ elif from_time == "next Friday":
206
+ # Next weekend Friday calculation
207
+ if now.weekday() < 4: # Monday to Thursday - use this weekend
208
+ days_until_friday = 4 - now.weekday()
209
+ elif now.weekday() == 4: # Today is Friday - use next weekend
210
+ days_until_friday = 7
211
+ else: # Saturday to Sunday - use next weekend
212
+ days_until_friday = (7 - now.weekday()) + 4 # Days to next Monday + 4 to get to Friday
213
+ from_absoluteDay = now + timedelta(days=days_until_friday)
214
+ logger.info(f"Next Friday (from): current weekday={now.weekday()}, days to add={days_until_friday} → {from_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
215
+ elif from_time == "next Saturday":
216
+ # Next weekend Saturday calculation
217
+ if now.weekday() < 5: # Monday to Friday - use this weekend
218
+ days_until_saturday = 5 - now.weekday()
219
+ elif now.weekday() == 5: # Today is Saturday - use next weekend
220
+ days_until_saturday = 7
221
+ else: # Sunday - use next weekend
222
+ days_until_saturday = 6 # 6 days to next Saturday
223
+ from_absoluteDay = now + timedelta(days=days_until_saturday)
224
+ logger.info(f"Next Saturday (from): current weekday={now.weekday()}, days to add={days_until_saturday} → {from_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
225
+ elif from_time == "next week Friday":
226
+ # Next week Friday - simple: go to next Monday, then +4 days
227
+ days_to_next_monday = 7 - now.weekday()
228
+ days_until_friday = days_to_next_monday + 4 # Monday + 4 = Friday
229
+ from_absoluteDay = now + timedelta(days=days_until_friday)
230
+ logger.info(f"Next week Friday (from): current weekday={now.weekday()}, days to add={days_until_friday} → {from_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
231
+ elif from_time == "next week Saturday":
232
+ # Next week Saturday - simple: go to next Monday, then +5 days
233
+ days_to_next_monday = 7 - now.weekday()
234
+ days_until_saturday = days_to_next_monday + 5 # Monday + 5 = Saturday
235
+ from_absoluteDay = now + timedelta(days=days_until_saturday)
236
+ logger.info(f"Next week Saturday (from): current weekday={now.weekday()}, days to add={days_until_saturday} → {from_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
237
+ elif from_time == "next week Sunday":
238
+ # Next week Sunday - simple: go to next Monday, then +6 days
239
+ days_to_next_monday = 7 - now.weekday()
240
+ days_until_sunday = days_to_next_monday + 6 # Monday + 6 = Sunday
241
+ from_absoluteDay = now + timedelta(days=days_until_sunday)
242
+ logger.info(f"Next week Sunday (from): current weekday={now.weekday()}, days to add={days_until_sunday} → {from_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
243
+ else:
244
+ pass # more rules here
245
+ if from_time == "next Monday split":
246
+ puday = apply_rules_to_timeFormat(relativeRules["expected"]["puDay"], from_absoluteDay)
247
+ config["rules"]["expected"]["puDay"] = puday
248
+ pumonth = apply_rules_to_timeFormat(relativeRules["expected"]["puMonth"], from_absoluteDay)
249
+ config["rules"]["expected"]["puMonth"] = pumonth
250
+ puyear = apply_rules_to_timeFormat(relativeRules["expected"]["puYear"], from_absoluteDay)
251
+ config["rules"]["expected"]["puYear"] = puyear
252
+ logger.info(f"Monday split formatting: puDay={puday}, puMonth={pumonth}, puYear={puyear}")
253
+ else:
254
+ regular_from_time = apply_rules_to_timeFormat(relativeRules["expected"]["from"], from_absoluteDay)
255
+ config["rules"]["expected"]["from"] = regular_from_time
256
+ logger.info(f"From time formatted: {regular_from_time}")
257
+
258
+ # deal with to_time
259
+ if relativeTime_to_IntDay[to_time] != "special":
260
+ to_time_IntDat = relativeTime_to_IntDay[to_time]
261
+ to_timediff = timedelta(days=to_time_IntDat)
262
+ to_absoluteDay = now + to_timediff
263
+ logger.info(f"To time calculation: {to_time} = {to_time_IntDat} days → {to_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
264
+ else:
265
+ if to_time == "this Sunday":
266
+ days_until_sunday = (6-now.weekday())
267
+ to_absoluteDay = now + timedelta(days=days_until_sunday)
268
+ logger.info(f"This Sunday: current weekday={now.weekday()}, days to add={days_until_sunday} → {to_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
269
+ elif to_time == "11th next month":
270
+ next_year = now.year + 1 if now.month == 12 else now.year
271
+ next_month = now.month + 1 if now.month < 12 else 1
272
+ next_day = 11
273
+ to_absoluteDay = timezone.localize(datetime(next_year, next_month, next_day))
274
+ logger.info(f"11th next month (to): {to_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
275
+ elif to_time == "next Friday" or to_time == "next Friday split":
276
+ # Check if from_time is any variant of "next Monday"
277
+ if from_time in ["next Monday", "next Monday split"]:
278
+ # Calculate Friday of the same week as the Monday
279
+ # from_absoluteDay is already calculated as next Monday
280
+ # Friday is 4 days after Monday (Monday=0, Friday=4)
281
+ to_absoluteDay = from_absoluteDay + timedelta(days=4)
282
+ logger.info(f"Next Friday (same week as Monday): from Monday {from_absoluteDay.strftime('%Y-%m-%d')} + 4 days → {to_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
283
+ else:
284
+ # Standalone "next Friday" calculation
285
+ if now.weekday() < 4: # Monday to Thursday
286
+ days_to_friday = 4 - now.weekday()
287
+ else: # Friday to Sunday
288
+ days_to_friday = (6 - now.weekday()) + 5
289
+ to_absoluteDay = now + timedelta(days=days_to_friday)
290
+ logger.info(f"Next Friday (standalone): current weekday={now.weekday()}, days to add={days_to_friday} → {to_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
291
+ elif to_time == "next Sunday":
292
+ # Next weekend Sunday calculation - should be the same weekend as the from_time
293
+ if from_time in ["next Friday", "next Saturday"]:
294
+ # Calculate Sunday of the same weekend as from_time
295
+ # from_absoluteDay is already calculated, get the Sunday of that week
296
+ days_to_add_for_sunday = 6 - from_absoluteDay.weekday() # Days from Friday/Saturday to Sunday
297
+ to_absoluteDay = from_absoluteDay + timedelta(days=days_to_add_for_sunday)
298
+ logger.info(f"Next Sunday (to, same weekend as {from_time}): from {from_absoluteDay.strftime('%Y-%m-%d %A')} + {days_to_add_for_sunday} days → {to_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
299
+ else:
300
+ # Standalone next Sunday calculation
301
+ if now.weekday() < 6: # Monday to Saturday - use this weekend
302
+ days_until_sunday = 6 - now.weekday()
303
+ else: # Sunday - use next weekend
304
+ days_until_sunday = 7
305
+ to_absoluteDay = now + timedelta(days=days_until_sunday)
306
+ logger.info(f"Next Sunday (to, standalone): current weekday={now.weekday()}, days to add={days_until_sunday} → {to_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
307
+ elif to_time == "next week Sunday":
308
+ # Next week Sunday calculation - should be the same week as from_time if from_time is also "next week"
309
+ if from_time in ["next week Friday", "next week Saturday"]:
310
+ # Calculate Sunday of the same week as from_time
311
+ # from_absoluteDay is already calculated, get the Sunday of that week
312
+ days_to_add_for_sunday = 6 - from_absoluteDay.weekday() # Days from Friday/Saturday to Sunday
313
+ to_absoluteDay = from_absoluteDay + timedelta(days=days_to_add_for_sunday)
314
+ logger.info(f"Next week Sunday (to, same week as {from_time}): from {from_absoluteDay.strftime('%Y-%m-%d %A')} + {days_to_add_for_sunday} days → {to_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
315
+ else:
316
+ # Standalone next week Sunday calculation - simple: go to next Monday, then +6 days
317
+ days_to_next_monday = 7 - now.weekday()
318
+ days_until_sunday = days_to_next_monday + 6 # Monday + 6 = Sunday
319
+ to_absoluteDay = now + timedelta(days=days_until_sunday)
320
+ logger.info(f"Next week Sunday (to, standalone): current weekday={now.weekday()}, days to add={days_until_sunday} → {to_absoluteDay.strftime('%Y-%m-%d %H:%M:%S %Z')}")
321
+ else:
322
+ pass # more rules here
323
+ if to_time == "next Friday split":
324
+ to_day = apply_rules_to_timeFormat(relativeRules["expected"]["doDay"], to_absoluteDay)
325
+ config["rules"]["expected"]["doDay"] = to_day
326
+ to_month = apply_rules_to_timeFormat(relativeRules["expected"]["doMonth"], to_absoluteDay)
327
+ config["rules"]["expected"]["doMonth"] = to_month
328
+ to_year = apply_rules_to_timeFormat(relativeRules["expected"]["doYear"], to_absoluteDay)
329
+ config["rules"]["expected"]["doYear"] = to_year
330
+ logger.info(f"Friday split formatting: doDay={to_day}, doMonth={to_month}, doYear={to_year}")
331
+ else:
332
+ regular_to_time = apply_rules_to_timeFormat(relativeRules["expected"]["to"], to_absoluteDay)
333
+ config["rules"]["expected"]["to"] = regular_to_time
334
+ logger.info(f"To time formatted: {regular_to_time}")
335
+
336
+ logger.info(f"[DEBUG] Final config rules: {config['rules']}")
337
+ print(config["rules"])
338
+ return config["rules"]
339
+
340
+
341
+ def apply_rules_to_timeFormat(timeFormat: str, absoluteDay: datetime):
342
+ timeFormat = timeFormat.replace("{DoW}", day_of_week_mapping[absoluteDay.weekday()], 1)
343
+ timeFormat = timeFormat.replace("{Month}", month_mapping[absoluteDay.month], 1)
344
+ timeFormat = timeFormat.replace("{DayD}", str(absoluteDay.day), 1)
345
+ timeFormat = timeFormat.replace("{Year}", str(absoluteDay.year), 1)
346
+ timeFormat = timeFormat.replace("{Month0D}", "0"+str(absoluteDay.month) if absoluteDay.month < 10 else str(absoluteDay.month), 1)
347
+ timeFormat = timeFormat.replace("{month}", month_mapping_full[absoluteDay.month], 1)
348
+ timeFormat = timeFormat.replace("{MonthFull}", Month_Mapping_Full[absoluteDay.month], 1)
349
+ timeFormat = timeFormat.replace("{Day0D}", "0"+str(absoluteDay.day) if absoluteDay.day < 10 else str(absoluteDay.day), 1)
350
+ timeFormat = timeFormat.replace("{MonthD}", str(absoluteDay.month), 1)
351
+ # you can add other replace rules here
352
+
353
+ return timeFormat
354
+
355
+
356
+ def get_accessibility_tree(env, *args) -> str:
357
+ accessibility_tree: str = env.controller.get_accessibility_tree()
358
+ logger.debug("AT@eval: %s", accessibility_tree)
359
+ return accessibility_tree
360
+
361
+ def get_time_diff_range(env, config) -> str:
362
+ try:
363
+ return config["diff_range_in_minutes"]
364
+ except:
365
+ logger.error("diff_range_in_minutes not found in config.")
366
+ return None
367
+
368
+ def get_timezone_from_ip() -> str:
369
+ """
370
+ Get timezone from IP address using IP geolocation API
371
+ Returns timezone string like 'Europe/Zurich' or 'UTC' as fallback
372
+ """
373
+ try:
374
+ # Try ipapi.co first
375
+ response = requests.get('https://ipapi.co/json/', timeout=5)
376
+ if response.status_code == 200:
377
+ data = response.json()
378
+ timezone = data.get('timezone')
379
+ if timezone:
380
+ logger.info(f"Timezone from IP: {timezone}")
381
+ return timezone
382
+ except Exception as e:
383
+ logger.warning(f"Failed to get timezone from IP: {e}")
384
+
385
+ # Fallback to UTC
386
+ logger.info("Using UTC as fallback timezone")
387
+ return 'UTC'
388
+
389
+ def get_timezone_from_config(config: Dict, default_timezone: str = None) -> str:
390
+ """
391
+ Get timezone from config, with fallback options
392
+ Priority: config timezone > default_timezone > IP-based timezone > UTC
393
+ """
394
+ # Check if timezone is specified in config
395
+ if "timezone" in config.get("rules", {}):
396
+ timezone = config["rules"]["timezone"]
397
+ logger.info(f"Using timezone from config: {timezone}")
398
+ return timezone
399
+
400
+ # Use provided default
401
+ if default_timezone:
402
+ logger.info(f"Using provided default timezone: {default_timezone}")
403
+ return default_timezone
404
+
405
+ # Get from IP
406
+ return get_timezone_from_ip()
@@ -0,0 +1,20 @@
1
+ from typing import List, Dict, Any
2
+
3
+
4
+ def get_replay(env, trajectory: List[Dict[str, Any]]) -> None:
5
+ # fixme: need to be combined with the accessibility tree to activate the selection of the target window
6
+ def parse(action):
7
+ if action["type"] == "hotkey":
8
+ keys = "', '".join(action["param"])
9
+ return f"pyautogui.hotkey('{keys}')"
10
+
11
+ if action["type"] == "typewrite":
12
+ text = action["param"]
13
+ return f"pyautogui.typewrite('{text}')"
14
+
15
+ if action["type"] == "press":
16
+ key = action["param"]
17
+ return f"pyautogui.press('{key}')"
18
+
19
+ for action in trajectory:
20
+ env.controller.execute_python_command(parse(action))
@@ -0,0 +1,86 @@
1
+ import logging
2
+ import os
3
+ from typing import Dict
4
+ from collections import Counter
5
+ from .general import get_vm_command_line
6
+ import requests
7
+
8
+ logger = logging.getLogger("desktopenv.getters.vlc")
9
+
10
+
11
+ def get_vlc_playing_info(env, config: Dict[str, str]):
12
+ """
13
+ Gets the current playing information from VLC's HTTP interface.
14
+ """
15
+
16
+ host = env.vm_ip
17
+ port = env.vlc_port
18
+ password = 'password'
19
+
20
+ _path = os.path.join(env.cache_dir, config["dest"])
21
+ url = f'http://{host}:{port}/requests/status.xml'
22
+ response = requests.get(url, auth=('', password))
23
+ if response.status_code == 200:
24
+ content = response.content
25
+ else:
26
+ logger.error("Failed to get vlc status. Status code: %d", response.status_code)
27
+ return None
28
+
29
+ with open(_path, "wb") as f:
30
+ f.write(content)
31
+
32
+ return _path
33
+
34
+
35
+ def get_vlc_config(env, config: Dict[str, str]):
36
+ """
37
+ Reads the VLC configuration file to check setting.
38
+ """
39
+
40
+ os_type = env.vm_platform
41
+
42
+ # fixme: depends on how we config and install the vlc in virtual machine, need to be aligned and double-checked
43
+ if os_type == "Linux":
44
+ config_path = \
45
+ env.controller.execute_python_command("import os; print(os.path.expanduser('~/.config/vlc/vlcrc'))")[
46
+ 'output'].strip()
47
+ elif os_type == "Darwin":
48
+ config_path = env.controller.execute_python_command(
49
+ "import os; print(os.path.expanduser('~/Library/Preferences/org.videolan.vlc/vlcrc'))")['output'].strip()
50
+ elif os_type == "Windows":
51
+ config_path = env.controller.execute_python_command(
52
+ "import os; print(os.path.expanduser('~\\AppData\\Roaming\\vlc\\vlcrc'))")['output'].strip()
53
+ else:
54
+ raise Exception("Unsupported operating system", os_type)
55
+
56
+ _path = os.path.join(env.cache_dir, config["dest"])
57
+ content = env.controller.get_file(config_path)
58
+ with open(_path, "wb") as f:
59
+ f.write(content)
60
+
61
+ return _path
62
+
63
+
64
+ def get_default_video_player(env, config: dict):
65
+ """ Gets the default application for a category or file extension.
66
+ """
67
+
68
+ os_type = env.vm_platform
69
+
70
+ if os_type == "Linux":
71
+ extensions = ['3gp', '3gp', '3gpp', '3gpp', '3gpp2', '3gpp2', 'avi', 'avi', 'divx', 'divx', 'dv', 'dv', 'fli', 'fli', 'flv', 'flv', 'mp2t', 'mp2t', 'mp4', 'mp4', 'mp4v-es', 'mp4v-es', 'mpeg', 'mpeg', 'mpeg-system', 'mpeg-system', 'msvideo', 'msvideo', 'ogg', 'ogg', 'quicktime', 'quicktime', 'vnd.divx', 'vnd.divx', 'vnd.mpegurl', 'vnd.mpegurl', 'vnd.rn-realvideo', 'vnd.rn-realvideo', 'webm', 'webm', 'x-anim', 'x-anim', 'x-avi', 'x-avi', 'x-flc', 'x-flc', 'x-fli', 'x-fli', 'x-flv', 'x-flv', 'x-m4v', 'x-m4v', 'x-matroska', 'x-matroska', 'x-mpeg', 'x-mpeg', 'x-mpeg-system', 'x-mpeg-system', 'x-mpeg2', 'x-mpeg2', 'x-ms-asf', 'x-ms-asf', 'x-ms-asf-plugin', 'x-ms-asf-plugin', 'x-ms-asx', 'x-ms-asx', 'x-ms-wm', 'x-ms-wm', 'x-ms-wmv', 'x-ms-wmv', 'x-ms-wmx', 'x-ms-wmx', 'x-ms-wvx', 'x-ms-wvx', 'x-msvideo', 'x-msvideo', 'x-nsv', 'x-nsv', 'x-ogm', 'x-ogm', 'x-ogm+ogg', 'x-theora', 'x-theora', 'x-theora+ogg', 'x-theora+ogg']
72
+ apps = []
73
+ for ext in extensions:
74
+ app = get_vm_command_line(env, {"command": ["xdg-mime", "query", "default", f"video/{ext}"]})
75
+ if app:
76
+ apps.append(app)
77
+ if len(apps) == 0:
78
+ return 'unknown'
79
+ else:
80
+ return Counter(apps).most_common(1)[0][0]
81
+ elif os_type == "Darwin":
82
+ raise Exception("Unsupported operating system", os_type)
83
+ elif os_type == "Windows":
84
+ raise Exception("Unsupported operating system", os_type)
85
+ else:
86
+ raise Exception("Unsupported operating system", os_type)
@@ -0,0 +1,35 @@
1
+ import logging
2
+ from typing import Any, Dict
3
+ import time
4
+ from .file import get_vm_file
5
+ from .replay import get_replay
6
+
7
+ logger = logging.getLogger("desktopenv.getters.vscode")
8
+
9
+
10
+ def get_vscode_config(env, config: Dict[str, Any]) -> str:
11
+ os_type = env.vm_platform
12
+ vscode_extension_command = config["vscode_extension_command"]
13
+
14
+ # fixme: depends on how we config and install the vscode in virtual machine, need to be aligned and double-checked
15
+
16
+ if os_type == "MacOS":
17
+ trajectory = [
18
+ {"type": "hotkey", "param": ["command", "shift", "p"]},
19
+ {"type": "typewrite", "param": vscode_extension_command},
20
+ {"type": "press", "param": "enter"}
21
+ ]
22
+ else:
23
+ trajectory = [
24
+ {"type": "hotkey", "param": ["ctrl", "shift", "p"]},
25
+ {"type": "typewrite", "param": vscode_extension_command},
26
+ {"type": "press", "param": "enter"}
27
+ ]
28
+
29
+ get_replay(env, trajectory)
30
+ time.sleep(1.0)
31
+
32
+ return get_vm_file(env, {
33
+ "path": config["path"],
34
+ "dest": config["dest"]
35
+ })