Skip to content

Commit e32dcb3

Browse files
authored
docs(coco): update readme.md (#1046)
* docs(coco): update readme.md * refactor: improve error readability
1 parent 62d87b8 commit e32dcb3

File tree

2 files changed

+163
-34
lines changed

2 files changed

+163
-34
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
## Description
2+
This will serve as a guide on how to create a COCO file using the utility script for Google Drive and DropBox
3+
4+
## Google Drive
5+
You can find the utility script for Google Drive here: [generate_coco_from_drive.js](./generate_coco_from_drive.js)
6+
7+
### Prerequisites
8+
- You must have a Google account
9+
- Your image files should be stored in a public Google Drive folder
10+
- You have access to Google Apps Script via https://script.google.com
11+
12+
### Creation Steps
13+
- Create a Google Apps script project
14+
- Go to https://script.google.com
15+
- Click on "New Project"
16+
- Rename the project name to `your-project-name`
17+
- Paste the utility script
18+
- Replace the default code with the utility file's code
19+
- Replace placeholder values
20+
- Replace `your_coco_export.json` with your output filename
21+
- Replace `your_public_folder_id` with the ID of your Google Drive folder
22+
> The folder ID is the alphanumeric string that appears after "/folders/" in the URL.\
23+
> Eg: drive.google.com/drive/folders/**1prcCevijN5mubTllB2kr5ki1gjh_IO4u**?usp=sharing
24+
- Run the script
25+
- Save the project to Drive using the floppy disk 💾 icon
26+
- Press Run
27+
- Accept the authorization prompts the first time you run the script
28+
- View COCO JSON Output
29+
- Go to **View > Logs**
30+
- Copy the Google Drive URL where the coco file is generated
31+
- Download the json file
32+
33+
## DropBox
34+
You can find the utility script for DropBox here: [generate_coco_from_dropbox.py](./generate_coco_from_dropbox.py)
35+
36+
### Prerequisites
37+
- Create account: https://www.dropbox.com/register
38+
- Create new App: https://www.dropbox.com/developers/apps
39+
- Choose an API: Scoped access
40+
- Choose the type of access you need: Full Dropbox
41+
- Name your app: `your-app-name`
42+
- Update `Permission type`
43+
- Go to the app settings
44+
- Click **Scoped App**
45+
- Tick the following permissions
46+
- files.metadata.read
47+
- files.content.write
48+
- files.content.read
49+
- sharing.write
50+
- sharing.read
51+
- Submit
52+
- Generate new access token:
53+
- Go to the app settings
54+
- Click **Generated access token**
55+
- Install uv on your system: https://docs.astral.sh/uv/getting-started/installation/
56+
- Download the [generate_coco_from_dropbox.py](./generate_coco_from_dropbox.py) script
57+
- Create a DropBox folder and upload images
58+
59+
### Creation Steps
60+
- Copy the folder pathname in DropBox
61+
- Copy the generated access token from DropBox
62+
- Run the script
63+
```bash
64+
# Help
65+
uv run generate_coco_dropbox.py --help
66+
67+
# Sample
68+
uv run generate_coco_dropbox.py "DROPBOX_ACCESS_TOKEN" "FOLDER_PATHNAME_IN_DROPBOX" "DESTINATION_EXPORT_FILE_NAME_IN_DROPBOX"
69+
70+
# Example
71+
uv run generate_coco_dropbox.py sl.yourAccessTokenHere "/COCO TEST" "coco_export.json"
72+
```
73+
- Download the exported coco json from the link in terminal or your DropBox folder

manager-dashboard/user_scripts/generate_coco_from_dropbox.py

Lines changed: 90 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,94 @@
11
# /// script
2+
# requires-python = ">=3.13"
23
# dependencies = [
3-
# "requests<3",
4+
# "httpx~=0.28.1",
5+
# "colorama",
46
# ]
57
# ///
68
from pathlib import Path
7-
from argparse import ArgumentParser
8-
import requests
9+
from colorama import init, Fore
10+
11+
import argparse
12+
import textwrap
13+
import httpx
914
import json
1015
import re
1116

17+
# Initialize colorama
18+
init(autoreset=True)
19+
20+
21+
DROPBOX_PERMISSION_MESSAGE = f"""
22+
{Fore.YELLOW}
23+
----------------------------------------------------
24+
Make sure the dropbox App includes these permissions
25+
- files.metadata.read
26+
- files.content.write
27+
- files.content.read
28+
- sharing.write
29+
- sharing.read
30+
"""
31+
32+
33+
def dropbox_request_error_handler(res: httpx.Response):
34+
try:
35+
res.raise_for_status()
36+
except httpx.HTTPStatusError as http_err:
37+
print(f"{Fore.RED}HTTP error occurred while requesting {res.url}: {http_err}")
38+
print(f"{Fore.RED}Response content: {res.text}")
39+
raise
40+
except httpx.RequestError as req_err:
41+
print(
42+
f"{Fore.RED}An error occurred while making the request to {res.url}: {req_err}"
43+
)
44+
raise
45+
except Exception as err:
46+
print(f"{Fore.RED}An unexpected error occurred: {err}")
47+
raise
48+
finally:
49+
print(DROPBOX_PERMISSION_MESSAGE)
50+
51+
1252
def dropbox_request(endpoint: str, data: object, *, access_token: str):
1353
url = f"https://api.dropboxapi.com/2/{endpoint}"
1454
headers = {
1555
"Authorization": f"Bearer {access_token}",
1656
"Content-Type": "application/json",
1757
}
18-
res = requests.post(
58+
res = httpx.post(
1959
url,
2060
headers=headers,
2161
data=json.dumps(data),
2262
)
23-
res.raise_for_status()
63+
dropbox_request_error_handler(res)
2464
return res.json()
2565

26-
def dropbox_content_request(endpoint: str, path: str, data: object, *, access_token: str):
66+
67+
def dropbox_content_request(
68+
endpoint: str, path: str, data: object, *, access_token: str
69+
):
2770
url = f"https://content.dropboxapi.com/2/{endpoint}"
2871
headers = {
2972
"Authorization": f"Bearer {access_token}",
3073
"Content-Type": "application/octet-stream",
31-
"Dropbox-API-Arg": json.dumps({
32-
"path": path,
33-
"mode": "overwrite", # overwrite if exists
34-
"autorename": False,
35-
"mute": False
36-
})
74+
"Dropbox-API-Arg": json.dumps(
75+
{
76+
"path": path,
77+
"mode": "overwrite", # overwrite if exists
78+
"autorename": False,
79+
"mute": False,
80+
}
81+
),
3782
}
38-
res = requests.post(
83+
res = httpx.post(
3984
url,
4085
headers=headers,
4186
data=json.dumps(data).encode("utf-8"),
4287
)
43-
res.raise_for_status()
88+
dropbox_request_error_handler(res)
4489
return res.json()
4590

91+
4692
def list_all_files(folder_path: str, *, access_token: str):
4793
ALLOWED_EXTENSIONS = {".jpg", ".jpeg", ".png", ".webp"}
4894
files = []
@@ -65,11 +111,14 @@ def list_all_files(folder_path: str, *, access_token: str):
65111
files = sorted(files, key=lambda file: file["name"].lower())
66112
# Filter out only files (not folders) that are supported
67113
files = [
68-
file for file in files
69-
if file[".tag"] == "file" and Path(file["name"]).suffix.lower() in ALLOWED_EXTENSIONS
114+
file
115+
for file in files
116+
if file[".tag"] == "file"
117+
and Path(file["name"]).suffix.lower() in ALLOWED_EXTENSIONS
70118
]
71119
return files
72120

121+
73122
def share_file_and_get_links(files, *, access_token: str):
74123
total = len(files)
75124
images = []
@@ -88,34 +137,40 @@ def share_file_and_get_links(files, *, access_token: str):
88137
if res.get("links"):
89138
link = res["links"][0]["url"]
90139
else:
91-
data = {
92-
"path": path,
93-
"settings": {
94-
"requested_visibility": "public"
95-
}
96-
}
140+
data = {"path": path, "settings": {"requested_visibility": "public"}}
97141
res_create = dropbox_request(
98142
"sharing/create_shared_link_with_settings",
99143
data,
100144
access_token=access_token,
101145
)
102146
link = res_create["url"]
103147

104-
raw_url = re.sub(r'&dl=0\b', '', link) + '&raw=1'
148+
raw_url = re.sub(r"&dl=0\b", "", link) + "&raw=1"
105149

106-
images.append({
107-
"id": i + 1,
108-
"file_name": actual_path,
109-
"coco_url": raw_url,
110-
})
150+
images.append(
151+
{
152+
"id": i + 1,
153+
"file_name": actual_path,
154+
"coco_url": raw_url,
155+
}
156+
)
111157
return images
112158

113159

114160
def main():
115-
parser = ArgumentParser(description="Generate COCO file from images folder.")
161+
parser = argparse.ArgumentParser(
162+
description="Generate COCO file from images folder.",
163+
formatter_class=argparse.RawDescriptionHelpFormatter,
164+
epilog=textwrap.dedent(DROPBOX_PERMISSION_MESSAGE),
165+
)
116166
parser.add_argument("access_token", help="Access token for authentication")
117-
parser.add_argument("images_folder", help="Path to the images folder")
118-
parser.add_argument("export_file_name", help="Name of the export COCO file")
167+
parser.add_argument(
168+
"images_folder", help='Path to the images folder in dropbox. eg: "/COCO TEST"'
169+
)
170+
parser.add_argument(
171+
"export_file_name",
172+
help="Name of the export COCO file to be created in dropbox under provided images_folder",
173+
)
119174

120175
args = parser.parse_args()
121176

@@ -141,17 +196,18 @@ def main():
141196
dropbox_content_request(
142197
"files/upload",
143198
absolute_export_file_name,
144-
{ "images": public_images },
199+
{"images": public_images},
145200
access_token=access_token,
146201
)
147202

148203
# Get temporary link
149204
res = dropbox_request(
150205
"files/get_temporary_link",
151-
{ "path": absolute_export_file_name },
206+
{"path": absolute_export_file_name},
152207
access_token=access_token,
153208
)
154-
print(f"COCO file available at {res["link"]}")
209+
print(f"COCO file available at {res['link']}")
210+
155211

156212
if __name__ == "__main__":
157213
main()

0 commit comments

Comments
 (0)