stereoid commited on
Commit
af46737
·
verified ·
1 Parent(s): 1da285f

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +40 -0
  2. approach/ovod/APE/.asset/ape.png +3 -0
  3. approach/ovod/APE/.asset/demo.png +3 -0
  4. approach/ovod/APE/.asset/example_1.png +3 -0
  5. approach/ovod/APE/.asset/framework.png +3 -0
  6. approach/ovod/APE/.asset/head.png +3 -0
  7. approach/ovod/APE/.asset/radar.png +3 -0
  8. approach/ovod/APE/ape/modeling/text/eva01_clip/bpe_simple_vocab_16e6.txt.gz +3 -0
  9. approach/ovod/APE/ape/modeling/text/eva02_clip/bpe_simple_vocab_16e6.txt.gz +3 -0
  10. approach/ovod/APE/ape_d_model_final.pth +3 -0
  11. approach/ovod/APE/demo/examples/MatrixRevolutionForZion.jpg +3 -0
  12. approach/ovod/APE/demo/examples/SolvayConference1927.jpg +3 -0
  13. approach/ovod/APE/demo/examples/Terminator3.jpg +3 -0
  14. approach/ovod/APE/demo/examples/Totoro01.png +3 -0
  15. approach/ovod/APE/demo/examples/Transformers.webp +3 -0
  16. approach/ovod/GroundingDINO/.asset/COCO.png +3 -0
  17. approach/ovod/GroundingDINO/.asset/GD_GLIGEN.png +3 -0
  18. approach/ovod/GroundingDINO/.asset/GD_SD.png +3 -0
  19. approach/ovod/GroundingDINO/.asset/ODinW.png +3 -0
  20. approach/ovod/GroundingDINO/.asset/arch.png +3 -0
  21. approach/ovod/GroundingDINO/.asset/cat_dog.jpeg +3 -0
  22. approach/ovod/GroundingDINO/.asset/cats.png +3 -0
  23. approach/ovod/GroundingDINO/.asset/grounding_dino_logo.png +3 -0
  24. approach/ovod/GroundingDINO/.asset/hero_figure.png +3 -0
  25. approach/ovod/GroundingDINO/.asset/model_explan1.PNG +3 -0
  26. approach/ovod/GroundingDINO/.asset/model_explan2.PNG +3 -0
  27. approach/ovod/d-cube/.assets/teaser.png +3 -0
  28. approach/ovod/mm-ovod/datasets/metadata/lvis_gpt3_text-davinci-002_features_author.npy +3 -0
  29. approach/ovod/mm-ovod/datasets/metadata/lvis_image_exemplar_features_agg_K-005_author.npy +3 -0
  30. approach/ovod/mm-ovod/datasets/metadata/lvis_image_exemplar_features_avg_K-005_author.npy +3 -0
  31. approach/ovod/mm-ovod/datasets/metadata/lvis_multi-modal_agg_K-005_author.npy +3 -0
  32. approach/ovod/mm-ovod/datasets/metadata/lvis_multi-modal_avg_K-005_author.npy +3 -0
  33. approach/ovod/mm-ovod/datasets/metadata/lvis_v1_clip_a+cname.npy +3 -0
  34. approach/ovod/mm-ovod/docs/teaser.jpg +3 -0
  35. approach/vlm/LLaVA/images/demo_cli.gif +3 -0
  36. approach/vlm/LLaVA/images/llava_example_cmp.png +3 -0
  37. approach/vlm/LLaVA/images/llava_logo.png +3 -0
  38. approach/vlm/LLaVA/images/llava_v1_5_radar.jpg +3 -0
  39. baselines/Aria-UI/AndroidWorld/README.md +57 -0
  40. baselines/Aria-UI/AndroidWorld/agents/aria_ui_utils.py +150 -0
  41. baselines/Aria-UI/AndroidWorld/agents/m3a_aria_ui.py +668 -0
  42. baselines/Aria-UI/AndroidWorld/env/json_action.py +180 -0
  43. baselines/Aria-UI/AndroidWorld/run_aria_ui.py +245 -0
  44. baselines/Aria-UI/assets/aria_ui_framework_v4.pdf +3 -0
  45. baselines/Aria-UI/assets/aria_ui_logo.png +0 -0
  46. baselines/Aria-UI/assets/logo_long.png +3 -0
  47. baselines/Aria-UI/assets/overall.png +3 -0
  48. baselines/Aria-UI/assets/performance_spider.pdf +0 -0
  49. baselines/Aria-UI/assets/seo.png +0 -0
  50. baselines/Aria-UI/examples/aria.png +3 -0
.gitattributes CHANGED
@@ -1 +1,41 @@
1
  approach/ovod/APE/ape_d_model_final.pth filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  approach/ovod/APE/ape_d_model_final.pth filter=lfs diff=lfs merge=lfs -text
2
+ approach/vlm/LLaVA/images/llava_example_cmp.png filter=lfs diff=lfs merge=lfs -text
3
+ approach/vlm/LLaVA/images/llava_logo.png filter=lfs diff=lfs merge=lfs -text
4
+ approach/ovod/APE/.asset/ape.png filter=lfs diff=lfs merge=lfs -text
5
+ approach/ovod/APE/.asset/radar.png filter=lfs diff=lfs merge=lfs -text
6
+ approach/ovod/APE/.asset/demo.png filter=lfs diff=lfs merge=lfs -text
7
+ approach/ovod/APE/.asset/head.png filter=lfs diff=lfs merge=lfs -text
8
+ approach/ovod/APE/.asset/example_1.png filter=lfs diff=lfs merge=lfs -text
9
+ approach/ovod/APE/.asset/framework.png filter=lfs diff=lfs merge=lfs -text
10
+ approach/ovod/APE/demo/examples/SolvayConference1927.jpg filter=lfs diff=lfs merge=lfs -text
11
+ approach/ovod/APE/demo/examples/Terminator3.jpg filter=lfs diff=lfs merge=lfs -text
12
+ approach/ovod/APE/demo/examples/Totoro01.png filter=lfs diff=lfs merge=lfs -text
13
+ approach/ovod/APE/demo/examples/MatrixRevolutionForZion.jpg filter=lfs diff=lfs merge=lfs -text
14
+ approach/ovod/APE/demo/examples/Transformers.webp filter=lfs diff=lfs merge=lfs -text
15
+ approach/ovod/APE/ape/modeling/text/eva02_clip/bpe_simple_vocab_16e6.txt.gz filter=lfs diff=lfs merge=lfs -text
16
+ approach/ovod/APE/ape/modeling/text/eva01_clip/bpe_simple_vocab_16e6.txt.gz filter=lfs diff=lfs merge=lfs -text
17
+ approach/vlm/LLaVA/images/llava_v1_5_radar.jpg filter=lfs diff=lfs merge=lfs -text
18
+ approach/vlm/LLaVA/images/demo_cli.gif filter=lfs diff=lfs merge=lfs -text
19
+ approach/ovod/mm-ovod/docs/teaser.jpg filter=lfs diff=lfs merge=lfs -text
20
+ approach/ovod/mm-ovod/datasets/metadata/lvis_multi-modal_avg_K-005_author.npy filter=lfs diff=lfs merge=lfs -text
21
+ approach/ovod/mm-ovod/datasets/metadata/lvis_image_exemplar_features_agg_K-005_author.npy filter=lfs diff=lfs merge=lfs -text
22
+ approach/ovod/mm-ovod/datasets/metadata/lvis_gpt3_text-davinci-002_features_author.npy filter=lfs diff=lfs merge=lfs -text
23
+ approach/ovod/mm-ovod/datasets/metadata/lvis_multi-modal_agg_K-005_author.npy filter=lfs diff=lfs merge=lfs -text
24
+ approach/ovod/mm-ovod/datasets/metadata/lvis_image_exemplar_features_avg_K-005_author.npy filter=lfs diff=lfs merge=lfs -text
25
+ approach/ovod/mm-ovod/datasets/metadata/lvis_v1_clip_a+cname.npy filter=lfs diff=lfs merge=lfs -text
26
+ approach/ovod/d-cube/.assets/teaser.png filter=lfs diff=lfs merge=lfs -text
27
+ approach/ovod/GroundingDINO/.asset/model_explan1.PNG filter=lfs diff=lfs merge=lfs -text
28
+ approach/ovod/GroundingDINO/.asset/hero_figure.png filter=lfs diff=lfs merge=lfs -text
29
+ approach/ovod/GroundingDINO/.asset/model_explan2.PNG filter=lfs diff=lfs merge=lfs -text
30
+ approach/ovod/GroundingDINO/.asset/grounding_dino_logo.png filter=lfs diff=lfs merge=lfs -text
31
+ approach/ovod/GroundingDINO/.asset/cats.png filter=lfs diff=lfs merge=lfs -text
32
+ approach/ovod/GroundingDINO/.asset/cat_dog.jpeg filter=lfs diff=lfs merge=lfs -text
33
+ approach/ovod/GroundingDINO/.asset/arch.png filter=lfs diff=lfs merge=lfs -text
34
+ approach/ovod/GroundingDINO/.asset/COCO.png filter=lfs diff=lfs merge=lfs -text
35
+ approach/ovod/GroundingDINO/.asset/GD_SD.png filter=lfs diff=lfs merge=lfs -text
36
+ approach/ovod/GroundingDINO/.asset/ODinW.png filter=lfs diff=lfs merge=lfs -text
37
+ approach/ovod/GroundingDINO/.asset/GD_GLIGEN.png filter=lfs diff=lfs merge=lfs -text
38
+ baselines/Aria-UI/examples/aria.png filter=lfs diff=lfs merge=lfs -text
39
+ baselines/Aria-UI/assets/overall.png filter=lfs diff=lfs merge=lfs -text
40
+ baselines/Aria-UI/assets/logo_long.png filter=lfs diff=lfs merge=lfs -text
41
+ baselines/Aria-UI/assets/aria_ui_framework_v4.pdf filter=lfs diff=lfs merge=lfs -text
approach/ovod/APE/.asset/ape.png ADDED

Git LFS Details

  • SHA256: b90fd5bb35bbf1c17ec33c32055fc218b6334e92a3a1038ae0fad315a98821d9
  • Pointer size: 131 Bytes
  • Size of remote file: 565 kB
approach/ovod/APE/.asset/demo.png ADDED

Git LFS Details

  • SHA256: 959657a6bb3914001250322b1ec9f77f9d98b5e234c18ce592c97a0530829f82
  • Pointer size: 132 Bytes
  • Size of remote file: 3.57 MB
approach/ovod/APE/.asset/example_1.png ADDED

Git LFS Details

  • SHA256: 06a6d45bd6bea5d08b11e538a5c7ae3775a1555cffc293d24231ec7b87e6d5e1
  • Pointer size: 132 Bytes
  • Size of remote file: 9.84 MB
approach/ovod/APE/.asset/framework.png ADDED

Git LFS Details

  • SHA256: 4435e99466cb7eebf57d03008c1f960aadd4f5039a882a9f4c669b1169d1efb0
  • Pointer size: 132 Bytes
  • Size of remote file: 1.4 MB
approach/ovod/APE/.asset/head.png ADDED

Git LFS Details

  • SHA256: 37404816913a6e314a3bc9fa5d8632be871ecf655a94d74a9560608f7e662860
  • Pointer size: 132 Bytes
  • Size of remote file: 5.1 MB
approach/ovod/APE/.asset/radar.png ADDED

Git LFS Details

  • SHA256: e538cf7a46b6625a1c2519b55fbd0d6b4acdb911ca9877794f75416258babdc0
  • Pointer size: 131 Bytes
  • Size of remote file: 425 kB
approach/ovod/APE/ape/modeling/text/eva01_clip/bpe_simple_vocab_16e6.txt.gz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:924691ac288e54409236115652ad4aa250f48203de50a9e4722a6ecd48d6804a
3
+ size 1356917
approach/ovod/APE/ape/modeling/text/eva02_clip/bpe_simple_vocab_16e6.txt.gz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:924691ac288e54409236115652ad4aa250f48203de50a9e4722a6ecd48d6804a
3
+ size 1356917
approach/ovod/APE/ape_d_model_final.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3548f41a3238148180e08fd4b16c71f4abc3ac3caf9c8434444462d1bdb7f965
3
+ size 5956547279
approach/ovod/APE/demo/examples/MatrixRevolutionForZion.jpg ADDED

Git LFS Details

  • SHA256: 66ae46c66721ca81bbc667eff5163e558aea496108cdbed018ab78a0b38251d0
  • Pointer size: 131 Bytes
  • Size of remote file: 110 kB
approach/ovod/APE/demo/examples/SolvayConference1927.jpg ADDED

Git LFS Details

  • SHA256: 043516fa47c14d20817ae26cfb1b0b7d82aa487ef7b6afdd573cd01a286a4618
  • Pointer size: 131 Bytes
  • Size of remote file: 238 kB
approach/ovod/APE/demo/examples/Terminator3.jpg ADDED

Git LFS Details

  • SHA256: f1a236355c4f0377d27292eb91879d21cc4e1b411878cd43e3b0393734677341
  • Pointer size: 132 Bytes
  • Size of remote file: 2.94 MB
approach/ovod/APE/demo/examples/Totoro01.png ADDED

Git LFS Details

  • SHA256: bdb52d3bcea59e5232c1329e7a861a59ca77b690bbe85dcf6fb0ad63fa84a624
  • Pointer size: 131 Bytes
  • Size of remote file: 273 kB
approach/ovod/APE/demo/examples/Transformers.webp ADDED

Git LFS Details

  • SHA256: b5fdfe662c60c0decdf8c96bdf20fb4ef002656de4faa5aa883ff08787ccff22
  • Pointer size: 131 Bytes
  • Size of remote file: 148 kB
approach/ovod/GroundingDINO/.asset/COCO.png ADDED

Git LFS Details

  • SHA256: 3050ba4775563ef0bb2592181f3c94af4ea42b515052825ed034e3b167ff5a1d
  • Pointer size: 131 Bytes
  • Size of remote file: 262 kB
approach/ovod/GroundingDINO/.asset/GD_GLIGEN.png ADDED

Git LFS Details

  • SHA256: 6e36d497ace68412ecd6c064fff6d7481a685963ffc2ec047a8892411fb0ab8e
  • Pointer size: 132 Bytes
  • Size of remote file: 1.23 MB
approach/ovod/GroundingDINO/.asset/GD_SD.png ADDED

Git LFS Details

  • SHA256: 92c8a690a2de028d42c9b876c73dca53b7736134eb77cce5b3cbda9d1c4b62de
  • Pointer size: 132 Bytes
  • Size of remote file: 1.16 MB
approach/ovod/GroundingDINO/.asset/ODinW.png ADDED

Git LFS Details

  • SHA256: ffadf3704e8c709541d40ff212944679f5637d9cbf83b8652dfa21b09a0d406e
  • Pointer size: 131 Bytes
  • Size of remote file: 293 kB
approach/ovod/GroundingDINO/.asset/arch.png ADDED

Git LFS Details

  • SHA256: 909a01c89273d8f956fcb010c869d3b48672a6c1a1d3552fd5619cadbe130bfd
  • Pointer size: 131 Bytes
  • Size of remote file: 568 kB
approach/ovod/GroundingDINO/.asset/cat_dog.jpeg ADDED

Git LFS Details

  • SHA256: f056b63ab86ac8c83471316351e0df5fcc33ce21160f0e041a12d8a80c4eea8f
  • Pointer size: 131 Bytes
  • Size of remote file: 123 kB
approach/ovod/GroundingDINO/.asset/cats.png ADDED

Git LFS Details

  • SHA256: 3c8de99f9a7f6cfb75e4fd07f457bb24092bbd6fd0dbd847ba4ed5bc77b40807
  • Pointer size: 131 Bytes
  • Size of remote file: 382 kB
approach/ovod/GroundingDINO/.asset/grounding_dino_logo.png ADDED

Git LFS Details

  • SHA256: 6e422e9e1115ea4ce2c5afc7e25196cc18efba6ef3d5a857a30d7dbbc727f554
  • Pointer size: 131 Bytes
  • Size of remote file: 363 kB
approach/ovod/GroundingDINO/.asset/hero_figure.png ADDED

Git LFS Details

  • SHA256: 24b18b31e9f150bae0ae01b09608d7bf7fc34f42c8e17d85eda55ea4a55b1e91
  • Pointer size: 132 Bytes
  • Size of remote file: 2.98 MB
approach/ovod/GroundingDINO/.asset/model_explan1.PNG ADDED

Git LFS Details

  • SHA256: bb7bd185928d9b2032760a666c8826fbd371556c3ec4d6d6731c40feebc8ab0e
  • Pointer size: 131 Bytes
  • Size of remote file: 484 kB
approach/ovod/GroundingDINO/.asset/model_explan2.PNG ADDED

Git LFS Details

  • SHA256: 02321231f93683e5035d6b7f55aa240e34598b0efcc4be01a3f47616ac5c3c92
  • Pointer size: 131 Bytes
  • Size of remote file: 467 kB
approach/ovod/d-cube/.assets/teaser.png ADDED

Git LFS Details

  • SHA256: 6bf288b09dfb4a5a7fad3b94153ba4f3d829cd1b9444984137609e833eefbf6f
  • Pointer size: 131 Bytes
  • Size of remote file: 766 kB
approach/ovod/mm-ovod/datasets/metadata/lvis_gpt3_text-davinci-002_features_author.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:48e39732dde55b2462222003714b2026b916cc982af2e4de43da64fa3e3a494f
3
+ size 1232000
approach/ovod/mm-ovod/datasets/metadata/lvis_image_exemplar_features_agg_K-005_author.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b4b83998ed03452204d17cf2f679d222b2338c973cf486784e88c9dcf8216a17
3
+ size 1232000
approach/ovod/mm-ovod/datasets/metadata/lvis_image_exemplar_features_avg_K-005_author.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:62a27438c4cb576080df9247ccabb2d6c6cd149244c3ebd054cfa88e169763f8
3
+ size 2463872
approach/ovod/mm-ovod/datasets/metadata/lvis_multi-modal_agg_K-005_author.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9dba2b82fd6f19930708c3feb1c0b0930c7c8f76ab00653105a96e9358afc5ae
3
+ size 1232000
approach/ovod/mm-ovod/datasets/metadata/lvis_multi-modal_avg_K-005_author.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:99ddedc9437a3a2173eb5a059c1e5b1e9e665778c744ee8dfa6f9d379011f6a9
3
+ size 2463872
approach/ovod/mm-ovod/datasets/metadata/lvis_v1_clip_a+cname.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:16059f1fe5f7d857273d16a1b7c6d6141a88d133e99a107be5065f42311da0f8
3
+ size 1232000
approach/ovod/mm-ovod/docs/teaser.jpg ADDED

Git LFS Details

  • SHA256: 26f472c39adb37018d76757faa2329e179f65b0836df9d7f51c83872b7652e69
  • Pointer size: 131 Bytes
  • Size of remote file: 633 kB
approach/vlm/LLaVA/images/demo_cli.gif ADDED

Git LFS Details

  • SHA256: 09227563f4fe04f077587eeb7b7c33ace2fbb8830e6cc9cfce03a25a57c43bfe
  • Pointer size: 133 Bytes
  • Size of remote file: 10 MB
approach/vlm/LLaVA/images/llava_example_cmp.png ADDED

Git LFS Details

  • SHA256: 722b358a3ea285deedda3c9d278390f8f5cbb0b5e924465248f458c4d7aa1c51
  • Pointer size: 131 Bytes
  • Size of remote file: 324 kB
approach/vlm/LLaVA/images/llava_logo.png ADDED

Git LFS Details

  • SHA256: 49324ed27269d31bd05f94fec215555ada39e4e75e6d6b69aa3896ed90bce759
  • Pointer size: 131 Bytes
  • Size of remote file: 268 kB
approach/vlm/LLaVA/images/llava_v1_5_radar.jpg ADDED

Git LFS Details

  • SHA256: 0ac28945d24b22a53ca8ba71ac81bf5edae298ac8dfeb8f5d3ceca4f05fd924f
  • Pointer size: 131 Bytes
  • Size of remote file: 324 kB
baselines/Aria-UI/AndroidWorld/README.md ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🚀 Welcome to the M3A Agent Powered by Aria-UI for AndroidWorld!
2
+
3
+ We’re thrilled to release the **M3A Agent powered by Aria-UI**! 🎉 This integration enhances task success rates and brings seamless grounding instruction understanding to **AndroidWorld**. Follow the steps below to get started. 🚀
4
+
5
+ ## 🛠️ How to Use M3A Agent with AndroidWorld
6
+
7
+ ### 1️⃣ Clone AndroidWorld and Set Up the Environment
8
+
9
+ First, clone the latest version of **AndroidWorld** and install the required dependencies:
10
+
11
+ ```bash
12
+ git clone https://github.com/google-research/android_world.git
13
+ cd android_world
14
+ ```
15
+ For more details, check out the official [AndroidWorld GitHub repository](https://github.com/google-research/android_world?tab=readme-ov-file).
16
+
17
+ ### 2️⃣ Merge M3A Agent Files with AndroidWorld
18
+
19
+ We’ve organized our files to match AndroidWorld’s directory structure. To integrate:
20
+
21
+ - Merge the provided `agents/` and `env/` directories with the respective directories in AndroidWorld.
22
+ - Place `run_aria_ui.py` in the root directory of AndroidWorld.
23
+
24
+ After merging, your directory structure should look like this:
25
+ ```
26
+ AndroidWorld/
27
+ ├── agents/
28
+ │ └── aria_ui_utils.py
29
+ │ └── m3a_aria_ui.py
30
+ ├── env/
31
+ │ └── json_action.py
32
+ ├── run_aria_ui.py
33
+ ...
34
+ ```
35
+
36
+ ### 3️⃣ Deploy Aria-UI API 🌐
37
+ Under AndroidWorld/agents/aria_ui_utils.py, you’ll find how we connect to Aria-UI using an API. Follow these steps to set it up:
38
+ - Deploy Aria-UI with vLLM to serve an OpenAI-style API.
39
+ Reference the [vLLM OpenAI-Compatible Server](https://docs.vllm.ai/en/latest/serving/openai_compatible_server.html).
40
+ - Update the API key and base URL in `aria_ui_utils.py` to match your deployment. Replace the placeholders with your values:
41
+ ```python
42
+ ariaui_api_key = "ariaui_api_key"
43
+ ariaui_api_base = "ariaui_api_base"
44
+ ```
45
+
46
+ **Note**: You may also set up a simple API server with the vLLM inference script and [FastAPI](https://github.com/fastapi/fastapi).
47
+ ### 4️⃣ Run the M3A Agent 🎉
48
+ Once everything is set up, run the agent with the following command:
49
+ ```python
50
+ python run_aria_ui.py
51
+ ```
52
+ Sit back and watch **Aria-UI** in action! 🚀
53
+
54
+ ### 💡 Additional Notes
55
+ For troubleshooting or further customization, explore `aria_ui_utils.py` and `m3a_aria_ui.py` to understand how Aria-UI is integrated.
56
+
57
+ Enjoy using the M3A Agent powered by **Aria-UI**! 🎉
baselines/Aria-UI/AndroidWorld/agents/aria_ui_utils.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2024 The Aria-UI Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import base64
16
+ from io import BytesIO
17
+ import requests
18
+ from PIL import Image
19
+ from openai import OpenAI
20
+ import numpy as np
21
+ import cv2
22
+ from android_world.agents.m3a_utils import _logical_to_physical
23
+
24
+ """
25
+ Deploy Aria-UI with vLLM, then get the api_key and api_base from the deployment for directly API call.
26
+ """
27
+ ariaui_api_key = "ariaui_api_key"
28
+ ariaui_api_base = "ariaui_api_base"
29
+
30
+ client = OpenAI(
31
+ api_key=ariaui_api_key,
32
+ base_url=ariaui_api_base,
33
+ )
34
+
35
+ models = client.models.list()
36
+ model = models.data[0].id
37
+
38
+ def encode_image_to_base64(image_path):
39
+ pil_image = Image.open(image_path).convert('RGB')
40
+ buffered = BytesIO()
41
+ pil_image.save(buffered, format="JPEG")
42
+ base64_str = base64.b64encode(buffered.getvalue()).decode('utf-8')
43
+ return base64_str
44
+
45
+ def encode_numpy_image_to_base64(image: np.ndarray) -> str:
46
+ """Converts a numpy array image to base64 string.
47
+
48
+ Args:
49
+ image: Numpy array representing an image (height, width, channels)
50
+
51
+ Returns:
52
+ Base64 encoded string of the image
53
+ """
54
+ # Convert numpy array to bytes
55
+ success, buffer = cv2.imencode('.jpg', image)
56
+ if not success:
57
+ raise ValueError("Failed to encode image to jpg format")
58
+
59
+ # Convert bytes to base64 string
60
+ image_bytes = buffer.tobytes()
61
+ base64_string = base64.b64encode(image_bytes).decode('utf-8')
62
+
63
+ return base64_string
64
+
65
+ def request_aria_ui(image: np.ndarray, prompt: str) -> str:
66
+ image_base64 = encode_numpy_image_to_base64(image)
67
+ chat_completion_from_url = client.chat.completions.create(
68
+ messages=[{
69
+ "role":
70
+ "user",
71
+ "content": [
72
+ {
73
+ "type": "text",
74
+ "text": prompt
75
+ },
76
+ {
77
+ "type": "image_url",
78
+ "image_url": {
79
+ "url": f"data:image/jpeg;base64,{image_base64}"
80
+ },
81
+ },
82
+ ],
83
+ }],
84
+ model=model,
85
+ max_tokens=512,
86
+ stop=["<|im_end|>"],
87
+ extra_body= {
88
+ "split_image": True,
89
+ "image_max_size": 980
90
+ }
91
+ )
92
+
93
+ result = chat_completion_from_url.choices[0].message.content
94
+ print(f"Chat completion output:{result}")
95
+ return result
96
+
97
+
98
+ def add_ui_element_mark_coords(
99
+ screenshot: np.ndarray,
100
+ coords: tuple[int, int], # Normalized coordinates in [0, 1000]
101
+ logical_screen_size: tuple[int, int],
102
+ physical_frame_boundary: tuple[int, int, int, int],
103
+ orientation: int,
104
+ ):
105
+ """Add a red circle marker at the specified normalized coordinates.
106
+
107
+ Args:
108
+ screenshot: The screenshot as a numpy ndarray.
109
+ coords: Normalized coordinates (x, y) in range [0, 1000].
110
+ logical_screen_size: The logical screen size.
111
+ physical_frame_boundary: The physical coordinates in portrait orientation
112
+ for the upper left and lower right corner for the frame.
113
+ orientation: The current screen orientation.
114
+ """
115
+ # Convert normalized coordinates to logical coordinates
116
+ logical_point = (
117
+ coords[0] * logical_screen_size[0] // 1000,
118
+ coords[1] * logical_screen_size[1] // 1000
119
+ )
120
+
121
+ # Convert to physical coordinates
122
+ physical_point = _logical_to_physical(
123
+ logical_point,
124
+ logical_screen_size,
125
+ physical_frame_boundary,
126
+ orientation,
127
+ )
128
+
129
+ # Draw a large red circle
130
+ radius = 30 # Adjust size as needed
131
+ cv2.circle(
132
+ screenshot,
133
+ physical_point,
134
+ radius,
135
+ color=(0, 0, 255), # BGR format - Red
136
+ thickness=3
137
+ )
138
+
139
+ def convert_coords_to_physical(coords: tuple[int, int], logical_screen_size: tuple[int, int], physical_frame_boundary: tuple[int, int, int, int], orientation: int) -> tuple[int, int]:
140
+ logical_point = (
141
+ coords[0] * logical_screen_size[0] // 1000,
142
+ coords[1] * logical_screen_size[1] // 1000
143
+ )
144
+ physical_point = _logical_to_physical(
145
+ logical_point,
146
+ logical_screen_size,
147
+ physical_frame_boundary,
148
+ orientation,
149
+ )
150
+ return physical_point
baselines/Aria-UI/AndroidWorld/agents/m3a_aria_ui.py ADDED
@@ -0,0 +1,668 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2024 The Aria-UI Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # Copyright 2024 The android_world Authors.
16
+ #
17
+ # Licensed under the Apache License, Version 2.0 (the "License");
18
+ # you may not use this file except in compliance with the License.
19
+ # You may obtain a copy of the License at
20
+ #
21
+ # http://www.apache.org/licenses/LICENSE-2.0
22
+ #
23
+ # Unless required by applicable law or agreed to in writing, software
24
+ # distributed under the License is distributed on an "AS IS" BASIS,
25
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26
+ # See the License for the specific language governing permissions and
27
+ # limitations under the License.
28
+
29
+ """A Multimodal Autonomous Agent for Android (Aria-UI under M3A)."""
30
+
31
+ import time
32
+ from android_world.agents import agent_utils
33
+ from android_world.agents import base_agent
34
+ from android_world.agents import infer
35
+ from android_world.agents import m3a_utils
36
+ from android_world.env import interface
37
+ from android_world.env import json_action
38
+ from android_world.env import representation_utils
39
+ from android_world.agents import aria_ui_utils
40
+ import ast
41
+ from tenacity import retry, stop_after_attempt, wait_fixed, retry_if_exception_type
42
+
43
+
44
+ PROMPT_PREFIX = """
45
+ You are an agent who can operate an Android phone on behalf of a user. Based on the user's goal/request, you may:
46
+
47
+ - Answer back if the request/goal is a question (or a chat message), like user asks "What is my schedule for today?".
48
+ - Complete some tasks described in the requests/goals by performing actions (step by step) on the phone.
49
+
50
+ When given a user request, you will try to complete it step by step. At each step, you will be given the current screenshot and a history of what you have done (in text). Based on these pieces of information and the goal, you must choose to perform one of the actions in the following list (action description followed by the JSON format) by outputting the action in the correct JSON format:
51
+
52
+ - If you think the task has been completed, finish the task by using the status action with complete as goal_status:
53
+ {{
54
+ "action_type": "status",
55
+ "goal_status": "complete"
56
+ }}
57
+
58
+ - If you think the task is not feasible (including cases like you don't have enough information or cannot perform some necessary actions), finish by using the `status` action with infeasible as goal_status:
59
+ {{
60
+ "action_type": "status",
61
+ "goal_status": "infeasible"
62
+ }}
63
+
64
+ - Answer user's question:
65
+ {{
66
+ "action_type": "answer",
67
+ "text": "answer_text"
68
+ }}
69
+
70
+ - Click/tap on an element on the screen. Please describe the element you want to click using natural language:
71
+ {{
72
+ "action_type": "click",
73
+ "instruction": the step-wise instruction in short,
74
+ "target": target_element_description
75
+ }}
76
+
77
+ - Long press on an element on the screen, similar to the click action above, use the semantic description to indicate the element:
78
+ {{
79
+ "action_type": "long_press",
80
+ "instruction": the step-wise instruction in short,
81
+ "target": target_element_description
82
+ }}
83
+
84
+ - Type text into a text field (this action contains clicking the text field, typing in the text, and pressing Enter, so no need to click on the target field to start). Use the semantic description to indicate the target text field:
85
+ {{
86
+ "action_type": "input_text",
87
+ "text": text_input,
88
+ "instruction": the step-wise instruction in short,
89
+ "target": target_element_description
90
+ }}
91
+
92
+ - Press the Enter key:
93
+ {{
94
+ "action_type": "keyboard_enter"
95
+ }}
96
+
97
+ - Navigate to the home screen:
98
+ {{
99
+ "action_type": "navigate_home"
100
+ }}
101
+
102
+ - Navigate back:
103
+ {{
104
+ "action_type": "navigate_back"
105
+ }}
106
+
107
+ - Scroll the screen or a scrollable UI element in one of the four directions, use the same semantic description as above if you want to scroll a specific UI element, leave it empty when scrolling the whole screen:
108
+ {{
109
+ "action_type": "scroll",
110
+ "direction": "up/down/left/right",
111
+ "instruction": the step-wise instruction in short,
112
+ "element": optional_target_element_description
113
+ }}
114
+
115
+ - Open an app (nothing will happen if the app is not installed):
116
+ {{
117
+ "action_type": "open_app",
118
+ "app_name": name
119
+ }}
120
+
121
+ - Wait for the screen to update:
122
+ {{
123
+ "action_type": "wait"
124
+ }}
125
+ """
126
+
127
+ GUIDANCE = """
128
+ Here are some useful guidelines you need to follow:
129
+
130
+ General:
131
+ - Usually there will be multiple ways to complete a task, pick the easiest one. Also when something does not work as expected (due to various reasons), sometimes a simple retry can solve the problem, but if it doesn’t (you can see that from the history), SWITCH to other solutions.
132
+ - Sometimes you may need to navigate the phone to gather information needed to complete the task, for example if user asks "what is my schedule tomorrow", then you may want to open the calendar app (using the ‘open_app‘ action), look up information there, answer user’s question (using the ‘answer‘ action) and finish (using the ‘status‘ action with complete as goal_status).
133
+ - For requests that are questions (or chat messages), remember to use the ‘answer‘ action to reply to user explicitly before finish! Merely displaying the answer on the screen is NOT sufficient (unless the goal is something like "show me ...").
134
+ - If the desired state is already achieved (e.g., enabling Wi-Fi when it’s already on), you can just complete the task.
135
+
136
+ Action Related:
137
+ - Use the ‘open_app‘ action whenever you want to open an app (nothing will happen if the app is not installed), do not use the app drawer to open an app unless all other ways have failed.
138
+ - Use the ‘input_text‘ action whenever you want to type something (including passwords) instead of clicking characters on the keyboard one by one. Sometimes there is some default text in the text field you want to type in, remember to delete them before typing.
139
+ - For ‘click‘, ‘long_press‘ and ‘input_text‘, the target_element.description parameter you choose must be based on a VISIBLE element in the screenshot.
140
+ - Consider exploring the screen by using the ‘scroll‘ action with different directions to reveal additional content.
141
+ - The direction parameter for the ‘scroll‘ action can be confusing sometimes as it’s opposite to swipe, for example, to view content at the bottom, the ‘scroll‘ direction should be set to "down". It has been observed that you have difficulties in choosing the correct direction, so if one does not work, try the opposite as well.
142
+
143
+ Text Related Operations:
144
+ - Normally to select certain text on the screen: (i) Enter text selection mode by long pressing the area where the text is, then some of the words near the long press point will be selected (highlighted with two pointers indicating the range) and usually a text selection bar will also appear with options like "copy", "paste", "select all", etc. (ii) Select the exact text you need. Usually the text selected from the previous step is NOT the one you want, you need to adjust the range by dragging the two pointers. If you want to select all text in the text field, simply click the "select all" button in the bar.
145
+ - At this point, you don’t have the ability to drag something around the screen, so in general you can not select arbitrary text.
146
+ - To delete some text: the most traditional way is to place the cursor at the right place and use the backspace button in the keyboard to delete the characters one by one (can long press the backspace to accelerate if there are many to delete). Another approach is to first select the text you want to delete, then click the backspace button in the keyboard.
147
+ - To copy some text: first select the exact text you want to copy, which usually also brings up the text selection bar, then click the `copy` button in bar.
148
+ - To paste text into a text box, first long press the text box, then usually the text selection bar will appear with a `paste` button in it.
149
+ - When typing into a text field, sometimes an auto-complete dropdown list will appear. This usually indicating this is a enum field and you should try to select the best match by clicking the corresponding one in the list.
150
+ """
151
+
152
+
153
+ ACTION_SELECTION_PROMPT_TEMPLATE = (
154
+ PROMPT_PREFIX + "\nThe current user goal/request is: {goal}\n\n"
155
+ "Here is a history of what you have done so far:\n{history}\n\n"
156
+ "The current screenshot is also given to you.\n"
157
+ + GUIDANCE
158
+ + "{additional_guidelines}"
159
+ + "\nNow output an action from the above list in the correct JSON format,"
160
+ " following the reason why you do that. Your answer should look like:\n"
161
+ 'Reason: ...\nAction: {{"action_type":...}}\n\n'
162
+ "Your Answer:\n"
163
+ )
164
+
165
+
166
+ SUMMARY_PROMPT_TEMPLATE = (
167
+ PROMPT_PREFIX + "\nThe (overall) user goal/request is: {goal}\n"
168
+ "Now I want you to summerize the latest step.\n"
169
+ "You will be given the screenshot before you performed the action (which"
170
+ ' has a text label "before" on the bottom right), the action you chose'
171
+ " (together with the reason) and the screenshot after the action was"
172
+ ' performed (which has a text label "after" on the bottom right).\n'
173
+ "Also here is the list of detailed information for some UI elements"
174
+ " in the before screenshot:\n{before_elements}\n"
175
+ "Here is the list for the after screenshot:\n{after_elements}\n"
176
+ "This is the action you picked: {action}\n"
177
+ "Based on the reason: {reason}\n\n"
178
+ "By comparing the two screenshots (plus the UI element lists) and the"
179
+ " action performed, give a brief summary of this step. This summary"
180
+ " will be added to action history and used in future action selection,"
181
+ " so try to include essential information you think that will be most"
182
+ " useful for future action selections like what you"
183
+ " intended to do, why, if it worked as expected, if not"
184
+ " what might be the reason (be critical, the action/reason might be"
185
+ " wrong), what should/should not be done next and so on. Some more"
186
+ " rules/tips you should follow:\n"
187
+ "- Keep it short (better less than 50 words) and in a single line\n"
188
+ "- Some actions (like `answer`, `wait`) don't involve screen change,"
189
+ " you can just assume they work as expected.\n"
190
+ "- Given this summary will be added into action history, it can be used as"
191
+ " memory to include information that needs to be remembered, or shared"
192
+ " between different apps.\n\n"
193
+ "Summary of this step: "
194
+ )
195
+
196
+
197
+ ARIA_UI_PROMPT_TEMPLATE = """The agent is performing the ultimate task: {ultimate_task}.
198
+ History of the agent's steps:\n{history_list}.
199
+ <image>Step {step_idx}. Given a GUI image, what are the relative (0-1000) pixel point coordinates for the element corresponding to the following instruction or description: {instruction}"""
200
+
201
+ ARIA_UI_PROMPT_TEMPLATE_MINIWOB = """<image>Given a GUI image, what are the relative (0-1000) pixel point coordinates for the element corresponding to the following instruction or description: {instruction}"""
202
+
203
+
204
+ def _generate_ui_element_description(
205
+ ui_element: representation_utils.UIElement, index: int
206
+ ) -> str:
207
+ """Generate a description for a given UI element with important information.
208
+
209
+ Args:
210
+ ui_element: UI elements for the current screen.
211
+ index: The numeric index for the UI element.
212
+
213
+ Returns:
214
+ The description for the UI element.
215
+ """
216
+ element_description = f'UI element {index}: {{"index": {index}, '
217
+ if ui_element.text:
218
+ element_description += f'"text": "{ui_element.text}", '
219
+ if ui_element.content_description:
220
+ element_description += (
221
+ f'"content_description": "{ui_element.content_description}", '
222
+ )
223
+ if ui_element.hint_text:
224
+ element_description += f'"hint_text": "{ui_element.hint_text}", '
225
+ if ui_element.tooltip:
226
+ element_description += f'"tooltip": "{ui_element.tooltip}", '
227
+ element_description += (
228
+ f'"is_clickable": {"True" if ui_element.is_clickable else "False"}, '
229
+ )
230
+ element_description += (
231
+ '"is_long_clickable":'
232
+ f' {"True" if ui_element.is_long_clickable else "False"}, '
233
+ )
234
+ element_description += (
235
+ f'"is_editable": {"True" if ui_element.is_editable else "False"}, '
236
+ )
237
+ if ui_element.is_scrollable:
238
+ element_description += '"is_scrollable": True, '
239
+ if ui_element.is_focusable:
240
+ element_description += '"is_focusable": True, '
241
+ element_description += (
242
+ f'"is_selected": {"True" if ui_element.is_selected else "False"}, '
243
+ )
244
+ element_description += (
245
+ f'"is_checked": {"True" if ui_element.is_checked else "False"}, '
246
+ )
247
+ return element_description[:-2] + "}"
248
+
249
+
250
+ def _generate_ui_elements_description_list(
251
+ ui_elements: list[representation_utils.UIElement],
252
+ screen_width_height_px: tuple[int, int],
253
+ ) -> str:
254
+ """Generate concise information for a list of UIElement.
255
+
256
+ Args:
257
+ ui_elements: UI elements for the current screen.
258
+ screen_width_height_px: The height and width of the screen in pixels.
259
+
260
+ Returns:
261
+ Concise information for each UIElement.
262
+ """
263
+ tree_info = ""
264
+ for index, ui_element in enumerate(ui_elements):
265
+ if m3a_utils.validate_ui_element(ui_element, screen_width_height_px):
266
+ tree_info += _generate_ui_element_description(ui_element, index) + "\n"
267
+ return tree_info
268
+
269
+
270
+ def _pvision_action_selection_prompt(
271
+ goal: str,
272
+ history: list[str],
273
+ additional_guidelines: list[str] | None = None,
274
+ ) -> str:
275
+ """Generate the prompt for the action selection.
276
+
277
+ Args:
278
+ goal: The current goal.
279
+ history: Summaries for previous steps.
280
+ ui_elements: A list of descriptions for the UI elements.
281
+ additional_guidelines: Task specific guidelines.
282
+
283
+ Returns:
284
+ The text prompt for action selection that will be sent to gpt4v.
285
+ """
286
+ if history:
287
+ history = "\n".join(history)
288
+ else:
289
+ history = "You just started, no action has been performed yet."
290
+
291
+ extra_guidelines = ""
292
+ if additional_guidelines:
293
+ extra_guidelines = "For The Current Task:\n"
294
+ for guideline in additional_guidelines:
295
+ extra_guidelines += f"- {guideline}\n"
296
+
297
+ return ACTION_SELECTION_PROMPT_TEMPLATE.format(
298
+ goal=goal,
299
+ history=history,
300
+ additional_guidelines=extra_guidelines,
301
+ )
302
+
303
+
304
+ def _summarize_prompt(
305
+ action: str,
306
+ reason: str,
307
+ goal: str,
308
+ before_elements: str,
309
+ after_elements: str,
310
+ ) -> str:
311
+ """Generate the prompt for the summarization step.
312
+
313
+ Args:
314
+ action: Action picked.
315
+ reason: The reason to pick the action.
316
+ goal: The overall goal.
317
+ before_elements: Information for UI elements on the before screenshot.
318
+ after_elements: Information for UI elements on the after screenshot.
319
+
320
+ Returns:
321
+ The text prompt for summarization that will be sent to gpt4v.
322
+ """
323
+ return SUMMARY_PROMPT_TEMPLATE.format(
324
+ goal=goal,
325
+ before_elements=before_elements,
326
+ after_elements=after_elements,
327
+ action=action,
328
+ reason=reason,
329
+ )
330
+
331
+
332
+ def _extract_coords_from_response(response: str) -> tuple[int, int]:
333
+ """Extract coordinate tuple from LLM response string.
334
+
335
+ Args:
336
+ response: String containing coordinates like "(892,925)" or "[892, 925]"
337
+
338
+ Returns:
339
+ Tuple of (x,y) coordinates as integers
340
+
341
+ Raises:
342
+ ValueError: If exactly 2 numbers are not found in the response
343
+ """
344
+ # Clean up the response string
345
+ resp = response.replace("```", "").strip()
346
+
347
+ # Extract numbers using regex
348
+ import re
349
+
350
+ numbers = re.findall(r"\d+", resp)
351
+ if len(numbers) != 2:
352
+ raise ValueError(
353
+ f"Expected exactly 2 coordinates, found {len(numbers)} numbers in response: {response}"
354
+ )
355
+
356
+ return (int(numbers[0]), int(numbers[1]))
357
+
358
+
359
+ @retry(
360
+ stop=stop_after_attempt(3),
361
+ wait=wait_fixed(5),
362
+ retry=retry_if_exception_type(ValueError),
363
+ reraise=True,
364
+ )
365
+ def call_grounding_llm(screenshot, goal, history, elem_description, elem_instruction):
366
+ history_list = "\n".join(
367
+ [f"\t{j+1}. " + step_info["summary"] for j, step_info in enumerate(history)]
368
+ )
369
+ """
370
+ AndroidWorld
371
+ """
372
+ prompt = ARIA_UI_PROMPT_TEMPLATE.format(
373
+ ultimate_task=goal,
374
+ history_list=history_list,
375
+ step_idx=len(history) + 1,
376
+ instruction=f"description: {elem_description}; instruction: {elem_instruction}",
377
+ )
378
+ """
379
+ MiniWob++
380
+ """
381
+ # prompt = ARIA_UI_PROMPT_TEMPLATE_MINIWOB.format(
382
+ # instruction=f"{elem_description}",
383
+ # )
384
+
385
+ response = aria_ui_utils.request_aria_ui(screenshot, prompt)
386
+
387
+ coords = _extract_coords_from_response(response)
388
+ return coords
389
+
390
+
391
+ class M3A(base_agent.EnvironmentInteractingAgent):
392
+ """M3A which stands for Multimodal Autonomous Agent for Android."""
393
+
394
+ def __init__(
395
+ self,
396
+ env: interface.AsyncEnv,
397
+ llm: infer.MultimodalLlmWrapper,
398
+ name: str = "M3A",
399
+ wait_after_action_seconds: float = 2.0,
400
+ ):
401
+ """Initializes a M3A Agent.
402
+
403
+ Args:
404
+ env: The environment.
405
+ llm: The multimodal LLM wrapper.
406
+ name: The agent name.
407
+ wait_after_action_seconds: Seconds to wait for the screen to stablize
408
+ after executing an action
409
+ """
410
+ super().__init__(env, name)
411
+ self.llm = llm
412
+ self.history = []
413
+ self.additional_guidelines = None
414
+ self.wait_after_action_seconds = wait_after_action_seconds
415
+
416
+ def set_task_guidelines(self, task_guidelines: list[str]) -> None:
417
+ self.additional_guidelines = task_guidelines
418
+
419
+ def reset(self, go_home_on_reset: bool = False):
420
+ super().reset(go_home_on_reset)
421
+ # Hide the coordinates on screen which might affect the vision model.
422
+ self.env.hide_automation_ui()
423
+ self.history = []
424
+
425
+ def step(self, goal: str) -> base_agent.AgentInteractionResult:
426
+ step_data = {
427
+ "raw_screenshot": None,
428
+ "before_screenshot_with_som": None,
429
+ "before_ui_elements": [],
430
+ "after_screenshot_with_som": None,
431
+ "action_prompt": None,
432
+ "action_output": None,
433
+ "action_output_json": None,
434
+ "action_reason": None,
435
+ "action_raw_response": None,
436
+ "summary_prompt": None,
437
+ "summary": None,
438
+ "summary_raw_response": None,
439
+ }
440
+ print("----------step " + str(len(self.history) + 1))
441
+
442
+ state = self.get_post_transition_state()
443
+ logical_screen_size = self.env.logical_screen_size
444
+ orientation = self.env.orientation
445
+ physical_frame_boundary = self.env.physical_frame_boundary
446
+
447
+ before_ui_elements = state.ui_elements
448
+ step_data["before_ui_elements"] = before_ui_elements
449
+ before_ui_elements_list = _generate_ui_elements_description_list(
450
+ before_ui_elements, logical_screen_size
451
+ )
452
+ step_data["raw_screenshot"] = state.pixels.copy()
453
+ before_screenshot = state.pixels.copy()
454
+ for index, ui_element in enumerate(before_ui_elements):
455
+ if m3a_utils.validate_ui_element(ui_element, logical_screen_size):
456
+ m3a_utils.add_ui_element_mark(
457
+ before_screenshot,
458
+ ui_element,
459
+ index,
460
+ logical_screen_size,
461
+ physical_frame_boundary,
462
+ orientation,
463
+ )
464
+ step_data["before_screenshot_with_som"] = before_screenshot.copy()
465
+
466
+ action_prompt = _pvision_action_selection_prompt(
467
+ goal,
468
+ [
469
+ "Step " + str(i + 1) + "- " + step_info["summary"]
470
+ for i, step_info in enumerate(self.history)
471
+ ],
472
+ self.additional_guidelines,
473
+ )
474
+ step_data["action_prompt"] = action_prompt
475
+ action_output, is_safe, raw_response = self.llm.predict_mm(
476
+ action_prompt,
477
+ [
478
+ step_data["raw_screenshot"],
479
+ ],
480
+ )
481
+
482
+ if is_safe == False: # pylint: disable=singleton-comparison
483
+ # is_safe could be None
484
+ action_output = f"""Reason: {m3a_utils.TRIGGER_SAFETY_CLASSIFIER}
485
+ Action: {{"action_type": "status", "goal_status": "infeasible"}}"""
486
+
487
+ if not raw_response:
488
+ raise RuntimeError("Error calling LLM in action selection phase.")
489
+ step_data["action_output"] = action_output
490
+ step_data["action_raw_response"] = raw_response
491
+
492
+ reason, action = m3a_utils.parse_reason_action_output(action_output)
493
+
494
+ # If the output is not in the right format, add it to step summary which
495
+ # will be passed to next step and return.
496
+ if (not reason) or (not action):
497
+ print("Action prompt output is not in the correct format.")
498
+ step_data["summary"] = (
499
+ "Output for action selection is not in the correct format, so no"
500
+ " action is performed."
501
+ )
502
+ self.history.append(step_data)
503
+
504
+ return base_agent.AgentInteractionResult(
505
+ False,
506
+ step_data,
507
+ )
508
+
509
+ print("Action: " + action)
510
+ print("Reason: " + reason)
511
+ step_data["action_reason"] = reason
512
+
513
+ try:
514
+ action_json = agent_utils.extract_json(action)
515
+ converted_action = json_action.JSONAction(
516
+ **action_json,
517
+ )
518
+ step_data["action_output_json"] = converted_action
519
+ except Exception as e: # pylint: disable=broad-exception-caught
520
+ print("Failed to convert the output to a valid action.")
521
+ print(str(e))
522
+ step_data["summary"] = (
523
+ "Can not parse the output to a valid action. Please make sure to pick"
524
+ " the action from the list with required parameters (if any) in the"
525
+ " correct JSON format!"
526
+ )
527
+ self.history.append(step_data)
528
+
529
+ return base_agent.AgentInteractionResult(
530
+ False,
531
+ step_data,
532
+ )
533
+
534
+ action_index = converted_action.index
535
+ elem_description = converted_action.target
536
+ elem_instruction = converted_action.instruction
537
+
538
+ num_ui_elements = len(before_ui_elements)
539
+ if (
540
+ converted_action.action_type
541
+ in ["click", "long_press", "input_text", "scroll"]
542
+ and elem_description is not None
543
+ ):
544
+ aria_ui_coords = call_grounding_llm(
545
+ step_data["raw_screenshot"],
546
+ goal,
547
+ self.history,
548
+ elem_description,
549
+ elem_instruction,
550
+ )
551
+ physical_coords = aria_ui_utils.convert_coords_to_physical(
552
+ aria_ui_coords,
553
+ logical_screen_size,
554
+ physical_frame_boundary,
555
+ orientation,
556
+ )
557
+
558
+ converted_action.x = physical_coords[0]
559
+ converted_action.y = physical_coords[1]
560
+
561
+ # Add mark to the target element.
562
+ aria_ui_utils.add_ui_element_mark_coords(
563
+ step_data["raw_screenshot"],
564
+ aria_ui_coords,
565
+ logical_screen_size,
566
+ physical_frame_boundary,
567
+ orientation,
568
+ )
569
+
570
+ if converted_action.action_type == "status":
571
+ if converted_action.goal_status == "infeasible":
572
+ print("Agent stopped since it thinks mission impossible.")
573
+ step_data["summary"] = "Agent thinks the request has been completed."
574
+ self.history.append(step_data)
575
+ return base_agent.AgentInteractionResult(
576
+ True,
577
+ step_data,
578
+ )
579
+
580
+ if converted_action.action_type == "answer":
581
+ print("Agent answered with: " + converted_action.text)
582
+
583
+ try:
584
+ self.env.execute_action(converted_action)
585
+ except Exception as e: # pylint: disable=broad-exception-caught
586
+ print("Failed to execute action.")
587
+ print(str(e))
588
+ step_data["summary"] = (
589
+ "Can not execute the action, make sure to select the action with"
590
+ " the required parameters (if any) in the correct JSON format!"
591
+ )
592
+ return base_agent.AgentInteractionResult(
593
+ False,
594
+ step_data,
595
+ )
596
+
597
+ time.sleep(self.wait_after_action_seconds)
598
+
599
+ state = self.env.get_state(wait_to_stabilize=False)
600
+ logical_screen_size = self.env.logical_screen_size
601
+ orientation = self.env.orientation
602
+ physical_frame_boundary = self.env.physical_frame_boundary
603
+ after_ui_elements = state.ui_elements
604
+ after_ui_elements_list = _generate_ui_elements_description_list(
605
+ after_ui_elements, logical_screen_size
606
+ )
607
+ after_screenshot = state.pixels.copy()
608
+ for index, ui_element in enumerate(after_ui_elements):
609
+ if m3a_utils.validate_ui_element(ui_element, logical_screen_size):
610
+ m3a_utils.add_ui_element_mark(
611
+ after_screenshot,
612
+ ui_element,
613
+ index,
614
+ logical_screen_size,
615
+ physical_frame_boundary,
616
+ orientation,
617
+ )
618
+
619
+ m3a_utils.add_screenshot_label(
620
+ step_data["before_screenshot_with_som"], "before"
621
+ )
622
+ m3a_utils.add_screenshot_label(after_screenshot, "after")
623
+ step_data["after_screenshot_with_som"] = after_screenshot.copy()
624
+
625
+ summary_prompt = _summarize_prompt(
626
+ action,
627
+ reason,
628
+ goal,
629
+ before_ui_elements_list,
630
+ after_ui_elements_list,
631
+ )
632
+ summary, is_safe, raw_response = self.llm.predict_mm(
633
+ summary_prompt,
634
+ [
635
+ before_screenshot,
636
+ after_screenshot,
637
+ ],
638
+ )
639
+
640
+ if is_safe == False: # pylint: disable=singleton-comparison
641
+ # is_safe could be None
642
+ summary = """Summary triggered LLM safety classifier."""
643
+
644
+ if not raw_response:
645
+ print(
646
+ "Error calling LLM in summarization phase. This should not happen: "
647
+ f"{summary}"
648
+ )
649
+ step_data["summary"] = (
650
+ "Some error occurred calling LLM during summarization phase: %s"
651
+ % summary
652
+ )
653
+ self.history.append(step_data)
654
+ return base_agent.AgentInteractionResult(
655
+ False,
656
+ step_data,
657
+ )
658
+
659
+ step_data["summary_prompt"] = summary_prompt
660
+ step_data["summary"] = f"Action selected: {action}. {summary}"
661
+ print("Summary: " + summary)
662
+ step_data["summary_raw_response"] = raw_response
663
+
664
+ self.history.append(step_data)
665
+ return base_agent.AgentInteractionResult(
666
+ False,
667
+ step_data,
668
+ )
baselines/Aria-UI/AndroidWorld/env/json_action.py ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2024 The android_world Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Represents an action for Android interaction, parsed from a JSON format."""
16
+
17
+ import dataclasses
18
+ import json
19
+ from typing import Optional
20
+
21
+
22
+ _JSON_SEPARATORS = (',', ':')
23
+
24
+ ANSWER = 'answer'
25
+ CLICK = 'click'
26
+ DOUBLE_TAP = 'double_tap'
27
+ INPUT_TEXT = 'input_text'
28
+ KEYBOARD_ENTER = 'keyboard_enter'
29
+ LONG_PRESS = 'long_press'
30
+ NAVIGATE_BACK = 'navigate_back'
31
+ NAVIGATE_HOME = 'navigate_home'
32
+ OPEN_APP = 'open_app'
33
+ SCROLL = 'scroll'
34
+ STATUS = 'status'
35
+ SWIPE = 'swipe'
36
+ UNKNOWN = 'unknown'
37
+ WAIT = 'wait'
38
+
39
+ _ACTION_TYPES = (
40
+ CLICK,
41
+ DOUBLE_TAP,
42
+ SCROLL,
43
+ SWIPE,
44
+ INPUT_TEXT,
45
+ NAVIGATE_HOME,
46
+ NAVIGATE_BACK,
47
+ KEYBOARD_ENTER,
48
+ OPEN_APP,
49
+ STATUS,
50
+ WAIT,
51
+ LONG_PRESS,
52
+ ANSWER,
53
+ UNKNOWN,
54
+ )
55
+
56
+ _SCROLL_DIRECTIONS = ('left', 'right', 'down', 'up')
57
+
58
+ # Keys of JSON action.
59
+ ACTION_TYPE = 'action_type'
60
+ INDEX = 'index'
61
+ X = 'x'
62
+ Y = 'y'
63
+ TEXT = 'text'
64
+ DIRECTION = 'direction'
65
+ APP_NAME = 'app_name'
66
+ GOAL_STATUS = 'goal_status'
67
+
68
+
69
+ @dataclasses.dataclass()
70
+ class JSONAction:
71
+ """Represents a parsed JSON action.
72
+
73
+ # Example
74
+ result_json = {'action_type': 'click', 'x': %d, 'y': %d}
75
+ action = JSONAction(**result_json)
76
+
77
+ Attributes:
78
+ action_type: The action type.
79
+ index: The index to click, if action is a click. Either an index or a <x, y>
80
+ should be provided. See x, y attributes below.
81
+ x: The x position to click, if the action is a click.
82
+ y: The y position to click, if the action is a click.
83
+ text: The text to type, if action is type.
84
+ direction: The direction to scroll, if action is scroll.
85
+ goal_status: If the status is a 'status' type, indicates the status of the
86
+ goal.
87
+ app_name: The app name to launch, if the action type is 'open_app'.
88
+ keycode: Keycode actions are necessary for an agent to interact with complex
89
+ UI elements (like large textareas) that can't be accessed or controlled by
90
+ simply taping, ensuring precise control over navigation and selection in
91
+ the interface.
92
+ """
93
+
94
+ action_type: Optional[str] = None
95
+ index: Optional[str | int] = None
96
+ x: Optional[int] = None
97
+ y: Optional[int] = None
98
+ text: Optional[str] = None
99
+ direction: Optional[str] = None
100
+ goal_status: Optional[str] = None
101
+ app_name: Optional[str] = None
102
+ keycode: Optional[str] = None
103
+
104
+ # for aria-UI
105
+ target: Optional[str] = None
106
+ instruction: Optional[str] = None
107
+ coords: Optional[tuple[int, int]] = None
108
+
109
+ def __post_init__(self):
110
+ if self.action_type not in _ACTION_TYPES:
111
+ raise ValueError(f'Invalid action type: {self.action_type}')
112
+ if self.index is not None:
113
+ self.index = int(self.index)
114
+ if self.x is not None or self.y is not None:
115
+ raise ValueError('Either an index or a <x, y> should be provided.')
116
+ if self.direction and self.direction not in _SCROLL_DIRECTIONS:
117
+ raise ValueError(f'Invalid scroll direction: {self.direction}')
118
+ if self.text is not None and not isinstance(self.text, str):
119
+ self.text = str(self.text)
120
+ if self.keycode is not None and not self.keycode.startswith('KEYCODE_'):
121
+ raise ValueError(f'Invalid keycode: {self.keycode}')
122
+
123
+ def __repr__(self) -> str:
124
+ properties = []
125
+ for key, value in self.__dict__.items():
126
+ if value is not None:
127
+ if isinstance(value, float):
128
+ value = f'{value:.3f}'
129
+ properties.append(f'{key}={value!r}')
130
+ return f"JSONAction({', '.join(properties)})"
131
+
132
+ def __eq__(self, other):
133
+ if isinstance(other, JSONAction):
134
+ return _compare_actions(self, other)
135
+ return False
136
+
137
+ def __ne__(self, other):
138
+ return not self.__eq__(other)
139
+
140
+ def json_str(self) -> str:
141
+ non_null = {}
142
+ for key, value in self.__dict__.items():
143
+ if value is not None:
144
+ non_null[key] = value
145
+ return json.dumps(non_null, separators=_JSON_SEPARATORS)
146
+
147
+
148
+ def _compare_actions(a: JSONAction, b: JSONAction) -> bool:
149
+ """Compares two JSONActions.
150
+
151
+ Args:
152
+ a: The first action.
153
+ b: The second action.
154
+
155
+ Returns:
156
+ If the actions are equal.
157
+ """
158
+ # Ignore cases.
159
+ if a.app_name is not None and b.app_name is not None:
160
+ app_name_match = a.app_name.lower() == b.app_name.lower()
161
+ else:
162
+ app_name_match = a.app_name == b.app_name
163
+
164
+ if a.text is not None and b.text is not None:
165
+ text_match = a.text.lower() == b.text.lower()
166
+ else:
167
+ text_match = a.text == b.text
168
+
169
+ # Compare the non-metadata fields.
170
+ return (
171
+ app_name_match
172
+ and text_match
173
+ and a.action_type == b.action_type
174
+ and a.index == b.index
175
+ and a.x == b.x
176
+ and a.y == b.y
177
+ and a.keycode == b.keycode
178
+ and a.direction == b.direction
179
+ and a.goal_status == b.goal_status
180
+ )
baselines/Aria-UI/AndroidWorld/run_aria_ui.py ADDED
@@ -0,0 +1,245 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2024 The Aria-UI Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # Copyright 2024 The android_world Authors.
16
+ #
17
+ # Licensed under the Apache License, Version 2.0 (the "License");
18
+ # you may not use this file except in compliance with the License.
19
+ # You may obtain a copy of the License at
20
+ #
21
+ # http://www.apache.org/licenses/LICENSE-2.0
22
+ #
23
+ # Unless required by applicable law or agreed to in writing, software
24
+ # distributed under the License is distributed on an "AS IS" BASIS,
25
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26
+ # See the License for the specific language governing permissions and
27
+ # limitations under the License.
28
+
29
+ """Run eval suite.
30
+
31
+ The run.py module is used to run a suite of tasks, with configurable task
32
+ combinations, environment setups, and agent configurations. You can run specific
33
+ tasks or all tasks in the suite and customize various settings using the
34
+ command-line flags.
35
+ """
36
+
37
+ from collections.abc import Sequence
38
+ import os
39
+
40
+ from absl import app
41
+ from absl import flags
42
+ from absl import logging
43
+ from android_world import checkpointer as checkpointer_lib
44
+ from android_world import registry
45
+ from android_world import suite_utils
46
+ from android_world.agents import base_agent
47
+ from android_world.agents import human_agent
48
+ from android_world.agents import infer
49
+ from android_world.agents import m3a
50
+ from android_world.agents import random_agent
51
+ from android_world.agents import seeact
52
+ from android_world.agents import t3a
53
+ from android_world.env import env_launcher
54
+ from android_world.env import interface
55
+
56
+ from android_world.agents import m3a_aria_ui
57
+
58
+ logging.set_verbosity(logging.WARNING)
59
+
60
+ os.environ["GRPC_VERBOSITY"] = "ERROR" # Only show errors
61
+ os.environ["GRPC_TRACE"] = "none" # Disable tracing
62
+
63
+
64
+ def _find_adb_directory() -> str:
65
+ """Returns the directory where adb is located."""
66
+ potential_paths = [
67
+ os.path.expanduser("~/Library/Android/sdk/platform-tools/adb"),
68
+ os.path.expanduser("~/Android/Sdk/platform-tools/adb"),
69
+ ]
70
+ for path in potential_paths:
71
+ if os.path.isfile(path):
72
+ return path
73
+ raise EnvironmentError(
74
+ "adb not found in the common Android SDK paths. Please install Android"
75
+ " SDK and ensure adb is in one of the expected directories. If it's"
76
+ " already installed, point to the installed location."
77
+ )
78
+
79
+
80
+ _ADB_PATH = flags.DEFINE_string(
81
+ "adb_path",
82
+ _find_adb_directory(),
83
+ "Path to adb. Set if not installed through SDK.",
84
+ )
85
+ _EMULATOR_SETUP = flags.DEFINE_boolean(
86
+ "perform_emulator_setup",
87
+ False,
88
+ "Whether to perform emulator setup. This must be done once and only once"
89
+ " before running Android World. After an emulator is setup, this flag"
90
+ " should always be False.",
91
+ )
92
+ _DEVICE_CONSOLE_PORT = flags.DEFINE_integer(
93
+ "console_port",
94
+ 5554,
95
+ "The console port of the running Android device. This can usually be"
96
+ " retrieved by looking at the output of `adb devices`. In general, the"
97
+ " first connected device is port 5554, the second is 5556, and"
98
+ " so on.",
99
+ )
100
+
101
+ _SUITE_FAMILY = flags.DEFINE_enum(
102
+ "suite_family",
103
+ registry.TaskRegistry.ANDROID_WORLD_FAMILY,
104
+ [
105
+ # Families from the paper.
106
+ registry.TaskRegistry.ANDROID_WORLD_FAMILY,
107
+ registry.TaskRegistry.MINIWOB_FAMILY_SUBSET,
108
+ # Other families for more testing.
109
+ registry.TaskRegistry.MINIWOB_FAMILY,
110
+ registry.TaskRegistry.ANDROID_FAMILY,
111
+ registry.TaskRegistry.INFORMATION_RETRIEVAL_FAMILY,
112
+ ],
113
+ "Suite family to run. See registry.py for more information.",
114
+ )
115
+ _TASK_RANDOM_SEED = flags.DEFINE_integer(
116
+ "task_random_seed", 30, "Random seed for task randomness."
117
+ )
118
+
119
+ _TASKS = flags.DEFINE_list(
120
+ "tasks",
121
+ None,
122
+ "List of specific tasks to run in the given suite family. If None, run all"
123
+ " tasks in the suite family.",
124
+ )
125
+ _N_TASK_COMBINATIONS = flags.DEFINE_integer(
126
+ "n_task_combinations",
127
+ 1,
128
+ "Number of task instances to run for each task template.",
129
+ )
130
+
131
+ _CHECKPOINT_DIR = flags.DEFINE_string(
132
+ "checkpoint_dir",
133
+ "",
134
+ "The directory to save checkpoints and resume evaluation from. If the"
135
+ " directory contains existing checkpoint files, evaluation will resume from"
136
+ " the latest checkpoint. If the directory is empty or does not exist, a new"
137
+ " directory will be created.",
138
+ )
139
+ _OUTPUT_PATH = flags.DEFINE_string(
140
+ "output_path",
141
+ os.path.expanduser("~/android_world/runs"),
142
+ "The path to save results to if not resuming from a checkpoint is not" " provided.",
143
+ )
144
+
145
+ # Agent specific.
146
+ _AGENT_NAME = flags.DEFINE_string("agent_name", "m3a_aria_ui", help="Agent name.")
147
+
148
+ _FIXED_TASK_SEED = flags.DEFINE_boolean(
149
+ "fixed_task_seed",
150
+ False,
151
+ "Whether to use the same task seed when running multiple task combinations"
152
+ " (n_task_combinations > 1).",
153
+ )
154
+
155
+
156
+ # MiniWoB is very lightweight and new screens/View Hierarchy load quickly.
157
+ _MINIWOB_TRANSITION_PAUSE = 0.2
158
+
159
+ # Additional guidelines for the MiniWob tasks.
160
+ _MINIWOB_ADDITIONAL_GUIDELINES = [
161
+ (
162
+ "This task is running in a mock app, you must stay in this app and"
163
+ " DO NOT use the `navigate_home` action."
164
+ ),
165
+ ]
166
+
167
+
168
+ def _get_agent(
169
+ env: interface.AsyncEnv,
170
+ family: str | None = None,
171
+ ) -> base_agent.EnvironmentInteractingAgent:
172
+ """Gets agent."""
173
+ print("Initializing agent...")
174
+ agent = None
175
+
176
+ agent = m3a_aria_ui.M3A(env, infer.Gpt4Wrapper("gpt-4o"))
177
+
178
+ if (
179
+ agent.name in ["M3A", "T3A", "SeeAct"]
180
+ and family
181
+ and family.startswith("miniwob")
182
+ and hasattr(agent, "set_task_guidelines")
183
+ ):
184
+ agent.set_task_guidelines(_MINIWOB_ADDITIONAL_GUIDELINES)
185
+ agent.name = _AGENT_NAME.value
186
+
187
+ return agent
188
+
189
+
190
+ def _main() -> None:
191
+ """Runs eval suite and gets rewards back."""
192
+ env = env_launcher.load_and_setup_env(
193
+ console_port=_DEVICE_CONSOLE_PORT.value,
194
+ emulator_setup=_EMULATOR_SETUP.value,
195
+ adb_path=_ADB_PATH.value,
196
+ )
197
+
198
+ n_task_combinations = _N_TASK_COMBINATIONS.value
199
+ task_registry = registry.TaskRegistry()
200
+ suite = suite_utils.create_suite(
201
+ task_registry.get_registry(family=_SUITE_FAMILY.value),
202
+ n_task_combinations=n_task_combinations,
203
+ seed=_TASK_RANDOM_SEED.value,
204
+ tasks=_TASKS.value,
205
+ use_identical_params=_FIXED_TASK_SEED.value,
206
+ )
207
+ suite.suite_family = _SUITE_FAMILY.value
208
+
209
+ agent = _get_agent(env, _SUITE_FAMILY.value)
210
+
211
+ if _SUITE_FAMILY.value.startswith("miniwob"):
212
+ # MiniWoB pages change quickly, don't need to wait for screen to stabilize.
213
+ agent.transition_pause = _MINIWOB_TRANSITION_PAUSE
214
+ else:
215
+ agent.transition_pause = None
216
+
217
+ if _CHECKPOINT_DIR.value:
218
+ checkpoint_dir = _CHECKPOINT_DIR.value
219
+ else:
220
+ checkpoint_dir = checkpointer_lib.create_run_directory(_OUTPUT_PATH.value)
221
+
222
+ print(
223
+ f"Starting eval with agent {_AGENT_NAME.value} and writing to"
224
+ f" {checkpoint_dir}"
225
+ )
226
+ suite_utils.run(
227
+ suite,
228
+ agent,
229
+ checkpointer=checkpointer_lib.IncrementalCheckpointer(checkpoint_dir),
230
+ demo_mode=False,
231
+ )
232
+ print(
233
+ f"Finished running agent {_AGENT_NAME.value} on {_SUITE_FAMILY.value}"
234
+ f" family. Wrote to {checkpoint_dir}."
235
+ )
236
+ env.close()
237
+
238
+
239
+ def main(argv: Sequence[str]) -> None:
240
+ del argv
241
+ _main()
242
+
243
+
244
+ if __name__ == "__main__":
245
+ app.run(main)
baselines/Aria-UI/assets/aria_ui_framework_v4.pdf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4f5ee32f13abf04b44357801582680ebd8c371e80b4cebf5b8961d842c963e40
3
+ size 2277714
baselines/Aria-UI/assets/aria_ui_logo.png ADDED
baselines/Aria-UI/assets/logo_long.png ADDED

Git LFS Details

  • SHA256: 46ebb35ffbc575ba0c8db8a757503ba9ac3c01e16b29b6e18abeb3c26d198b49
  • Pointer size: 131 Bytes
  • Size of remote file: 128 kB
baselines/Aria-UI/assets/overall.png ADDED

Git LFS Details

  • SHA256: 67abc9f966be4bff0ce2fb07bc3f60a1758e6d601c62ddd7876a88061a5eacfc
  • Pointer size: 131 Bytes
  • Size of remote file: 780 kB
baselines/Aria-UI/assets/performance_spider.pdf ADDED
Binary file (21.5 kB). View file
 
baselines/Aria-UI/assets/seo.png ADDED
baselines/Aria-UI/examples/aria.png ADDED

Git LFS Details

  • SHA256: 62e27f944de12df59c4eaa8060832a19fe54ea3fccad0196e78dbcd10858700a
  • Pointer size: 132 Bytes
  • Size of remote file: 2.75 MB