Kyunnilee commited on
Commit
9a089a9
·
0 Parent(s):

first commit

Browse files
Files changed (4) hide show
  1. .gitattributes +36 -0
  2. README.md +13 -0
  3. app.py +139 -0
  4. requirements.txt +3 -0
.gitattributes ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.png filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Visual Puzzles Annotator
3
+ emoji: 🦀
4
+ colorFrom: indigo
5
+ colorTo: red
6
+ sdk: gradio
7
+ sdk_version: 5.34.0
8
+ app_file: app.py
9
+ pinned: false
10
+ short_description: visual-puzzles-annotator for visual-puzzles website
11
+ ---
12
+
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import json
4
+ from PIL import Image
5
+ import tempfile
6
+ from datasets import load_dataset
7
+
8
+ DATASET_NAME = "Kyunnilee/visual-puzzles"
9
+ SPLIT_NAME = "train"
10
+
11
+ IMAGE_FOLDER = "images"
12
+ os.makedirs(IMAGE_FOLDER, exist_ok=True)
13
+
14
+ # Load dataset
15
+ hf_dataset = load_dataset(DATASET_NAME, split=SPLIT_NAME)
16
+
17
+ image_paths = []
18
+ for i, example in enumerate(hf_dataset):
19
+ img = example["image"]
20
+ path = os.path.join(IMAGE_FOLDER, f"image_{i}.png")
21
+ img.save(path)
22
+ image_paths.append(f"image_{i}.png")
23
+
24
+ ANNOTATION_FILE = "annotations.json"
25
+
26
+ annotations = []
27
+ current_index = 0
28
+
29
+
30
+ # Helper functions
31
+ def load_annotations(file_obj):
32
+ global annotations, current_index
33
+ file_path = file_obj.name if hasattr(file_obj, "name") else file_obj
34
+ with open(file_path, "r") as f:
35
+ annotations = json.load(f)
36
+ done_images = {a["image"] for a in annotations}
37
+ remaining = [img for img in image_paths if img not in done_images]
38
+ current_index = 0 if not remaining else image_paths.index(remaining[0])
39
+ return update_interface()
40
+
41
+
42
+ def save_annotations():
43
+ with tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".json") as tmp:
44
+ json.dump(annotations, tmp, indent=2)
45
+ tmp_path = tmp.name
46
+ return tmp_path
47
+
48
+
49
+ def update_interface():
50
+ if current_index >= len(image_paths):
51
+ skipped_count = sum(1 for a in annotations if a["answer"] == "<SKIP>")
52
+ return None, "", f"All {len(image_paths)} images annotated. Skipped: {skipped_count}", 100
53
+ image_path = os.path.join(IMAGE_FOLDER, image_paths[current_index])
54
+ existing = next((a["answer"] for a in annotations if a["image"] == image_paths[current_index]), "")
55
+ skipped_count = sum(1 for a in annotations if a["answer"] == "<SKIP>")
56
+ return (
57
+ image_path,
58
+ existing if existing != "<SKIP>" else "",
59
+ f"{len(annotations)} / {len(image_paths)} completed. Skipped: {skipped_count}",
60
+ int((len(annotations) / len(image_paths)) * 100),
61
+ )
62
+
63
+
64
+ def submit_answer(answer):
65
+ global current_index
66
+ if current_index < len(image_paths):
67
+ img_name = image_paths[current_index]
68
+ existing = next((a for a in annotations if a["image"] == img_name), None)
69
+ if answer.strip():
70
+ if existing:
71
+ existing["answer"] = answer
72
+ else:
73
+ annotations.append({"image": img_name, "answer": answer})
74
+ else:
75
+ if not existing:
76
+ annotations.append({"image": img_name, "answer": "<SKIP>"})
77
+
78
+ # Find the next unannotated index
79
+ for i in range(current_index + 1, len(image_paths)):
80
+ next_img_name = image_paths[i]
81
+ if not any(a["image"] == next_img_name and a["answer"] not in ("", "<SKIP>") for a in annotations):
82
+ current_index = i
83
+ break
84
+ else:
85
+ # If no unannotated images are found, set current_index to the end
86
+ current_index = len(image_paths)
87
+
88
+ return update_interface()
89
+
90
+
91
+ def go_previous():
92
+ global current_index
93
+ if current_index > 0:
94
+ current_index -= 1
95
+ return update_interface()
96
+
97
+
98
+ def go_next():
99
+ global current_index
100
+ if current_index < len(image_paths) - 1:
101
+ current_index += 1
102
+ return update_interface()
103
+
104
+
105
+ # Gradio Interface
106
+ with gr.Blocks() as demo:
107
+ gr.Markdown("## Rebus Puzzle Annotator")
108
+
109
+ with gr.Row():
110
+ image_display = gr.Image(label="Rebus Image", type="filepath")
111
+ textbox = gr.Textbox(label="Your Answer", placeholder="Type the rebus answer here")
112
+
113
+ with gr.Row():
114
+ submit_btn = gr.Button("Submit Answer")
115
+ prev_btn = gr.Button("Previous")
116
+ next_btn = gr.Button("Next")
117
+
118
+ with gr.Row():
119
+ status = gr.Textbox(label="Progress")
120
+ progress_bar = gr.Slider(label="Progress", minimum=0, maximum=100, step=1, interactive=False)
121
+
122
+ with gr.Row():
123
+ download_btn = gr.Button("Export Annotations")
124
+ upload_btn = gr.File(label="Import Annotations", file_types=[".json"])
125
+ output_file = gr.File(label="Download JSON")
126
+
127
+ # Hook up events
128
+ submit_btn.click(submit_answer, textbox, [image_display, textbox, status, progress_bar])
129
+ textbox.submit(submit_answer, textbox, [image_display, textbox, status, progress_bar])
130
+ prev_btn.click(go_previous, None, [image_display, textbox, status, progress_bar])
131
+ next_btn.click(go_next, None, [image_display, textbox, status, progress_bar])
132
+ download_btn.click(save_annotations, None, output_file)
133
+ upload_btn.change(load_annotations, upload_btn, [image_display, textbox, status, progress_bar])
134
+
135
+ demo.load(update_interface, None, [image_display, textbox, status, progress_bar])
136
+
137
+
138
+ if __name__ == "__main__":
139
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio
2
+ datasets
3
+ pillow