Spaces:
Sleeping
Sleeping
move decorators to main function
Browse files
app.py
CHANGED
|
@@ -34,12 +34,8 @@ DIFFICULY = {"easy": 0.18, "medium": 0.1, "hard": 0.05}
|
|
| 34 |
DIFFICULY_LEVELS = list(DIFFICULY.keys())
|
| 35 |
|
| 36 |
|
| 37 |
-
@interactive(
|
| 38 |
-
seed=(45, [0, 100], "Puzzle seed"),
|
| 39 |
-
difficulty=(DIFFICULY_LEVELS[0], DIFFICULY_LEVELS, "Difficulty")
|
| 40 |
-
)
|
| 41 |
def generate_random_puzzle(
|
| 42 |
-
seed: int =
|
| 43 |
difficulty: str = DIFFICULY_LEVELS[0],
|
| 44 |
context: dict = {}
|
| 45 |
):
|
|
@@ -72,10 +68,6 @@ def create_puzzle(
|
|
| 72 |
return out, crop
|
| 73 |
|
| 74 |
|
| 75 |
-
@interactive(
|
| 76 |
-
flip=(False, "Flip Image"),
|
| 77 |
-
mirror=(False, "Mirror Image"),
|
| 78 |
-
)
|
| 79 |
def flip_mirror_piece(
|
| 80 |
piece: np.ndarray,
|
| 81 |
flip: bool = False,
|
|
@@ -87,10 +79,6 @@ def flip_mirror_piece(
|
|
| 87 |
return flip_image(piece.copy(), flip=flip, mirror=mirror)
|
| 88 |
|
| 89 |
|
| 90 |
-
@interactive(
|
| 91 |
-
pos_x=(0.5, [0.1, 0.9, 0.005], "Position X", ["left", "right"]),
|
| 92 |
-
pos_y=(0.5, [0.1, 0.9, 0.005], "Position Y", ["up", "down"]),
|
| 93 |
-
)
|
| 94 |
def place_puzzle(
|
| 95 |
puzzle: np.ndarray,
|
| 96 |
piece: np.ndarray,
|
|
@@ -111,11 +99,9 @@ TOLERANCES = {"low": 0.01, "medium": 0.02, "high": 0.05}
|
|
| 111 |
TOLERANCE_LEVELS = list(TOLERANCES.keys())
|
| 112 |
|
| 113 |
|
| 114 |
-
@interactive(
|
| 115 |
-
tolerance=(TOLERANCE_LEVELS[0], TOLERANCE_LEVELS, "Tolerance")
|
| 116 |
-
)
|
| 117 |
def check_puzzle(tolerance: str = "low", context: dict = {}) -> None:
|
| 118 |
-
"""Check if the user placed the puzzle piece correctly.
|
|
|
|
| 119 |
x_gt, y_gt = context["puzzle_pos"]
|
| 120 |
flip_gt, mirror_gt = context["puzzle_flip_mirror"]
|
| 121 |
x, y = context["user_pos"]
|
|
@@ -133,7 +119,8 @@ def display_feedback(
|
|
| 133 |
nok_ribbon: np.ndarray,
|
| 134 |
context: dict = {}
|
| 135 |
) -> np.ndarray:
|
| 136 |
-
|
|
|
|
| 137 |
ribbon = ok_ribbon if success else nok_ribbon
|
| 138 |
out = np.hstack([puzzle, ribbon[:puzzle.shape[0], ...]])
|
| 139 |
return out
|
|
@@ -152,19 +139,51 @@ def captcha_pipe(inp):
|
|
| 152 |
puzzle = display_feedback(puzzle, ok_ribbon, nok_ribbon)
|
| 153 |
return puzzle
|
| 154 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 155 |
|
| 156 |
if __name__ == "__main__":
|
| 157 |
import argparse
|
| 158 |
parser = argparse.ArgumentParser()
|
| 159 |
parser.add_argument("-b", "--backend", default="gradio",
|
| 160 |
-
choices=["gradio", "qt"], type=str)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 161 |
args = parser.parse_args()
|
| 162 |
-
markdown_description = "# Code to build this app on gradio \n"
|
|
|
|
|
|
|
| 163 |
markdown_description += "```python\n"+open(__file__, 'r').read()+"```"
|
| 164 |
img = Image.load_image("sample.jpg")
|
| 165 |
-
|
| 166 |
-
gui=args.backend,
|
| 167 |
-
cache=True,
|
| 168 |
-
markdown_description=markdown_description
|
| 169 |
-
)(captcha_pipe)
|
| 170 |
-
captcha_pipe_interactive(img)
|
|
|
|
| 34 |
DIFFICULY_LEVELS = list(DIFFICULY.keys())
|
| 35 |
|
| 36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
def generate_random_puzzle(
|
| 38 |
+
seed: int = 43,
|
| 39 |
difficulty: str = DIFFICULY_LEVELS[0],
|
| 40 |
context: dict = {}
|
| 41 |
):
|
|
|
|
| 68 |
return out, crop
|
| 69 |
|
| 70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
def flip_mirror_piece(
|
| 72 |
piece: np.ndarray,
|
| 73 |
flip: bool = False,
|
|
|
|
| 79 |
return flip_image(piece.copy(), flip=flip, mirror=mirror)
|
| 80 |
|
| 81 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
def place_puzzle(
|
| 83 |
puzzle: np.ndarray,
|
| 84 |
piece: np.ndarray,
|
|
|
|
| 99 |
TOLERANCE_LEVELS = list(TOLERANCES.keys())
|
| 100 |
|
| 101 |
|
|
|
|
|
|
|
|
|
|
| 102 |
def check_puzzle(tolerance: str = "low", context: dict = {}) -> None:
|
| 103 |
+
"""Check if the user placed the puzzle piece correctly.
|
| 104 |
+
Store the result in the context."""
|
| 105 |
x_gt, y_gt = context["puzzle_pos"]
|
| 106 |
flip_gt, mirror_gt = context["puzzle_flip_mirror"]
|
| 107 |
x, y = context["user_pos"]
|
|
|
|
| 119 |
nok_ribbon: np.ndarray,
|
| 120 |
context: dict = {}
|
| 121 |
) -> np.ndarray:
|
| 122 |
+
"""Display green/red ribbon on the right side of the puzzle."""
|
| 123 |
+
success = context.get("success", False)
|
| 124 |
ribbon = ok_ribbon if success else nok_ribbon
|
| 125 |
out = np.hstack([puzzle, ribbon[:puzzle.shape[0], ...]])
|
| 126 |
return out
|
|
|
|
| 139 |
puzzle = display_feedback(puzzle, ok_ribbon, nok_ribbon)
|
| 140 |
return puzzle
|
| 141 |
|
| 142 |
+
# add interactivity
|
| 143 |
+
# -----------------
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
def main(img: np.ndarray, backend="gradio", debug: bool = False):
|
| 147 |
+
# If debug mode, add interactive sliders to tune the puzzle generation
|
| 148 |
+
# and help the "game master" design a feasible puzzle.
|
| 149 |
+
if debug:
|
| 150 |
+
interactive(
|
| 151 |
+
tolerance=(TOLERANCE_LEVELS[0], TOLERANCE_LEVELS, "Tolerance")
|
| 152 |
+
)(check_puzzle)
|
| 153 |
+
interactive(
|
| 154 |
+
seed=(43, [0, 100], "Puzzle seed"),
|
| 155 |
+
difficulty=(DIFFICULY_LEVELS[0], DIFFICULY_LEVELS, "Difficulty")
|
| 156 |
+
)(generate_random_puzzle)
|
| 157 |
+
interactive(
|
| 158 |
+
pos_x=(0.5, [0.1, 0.9, 0.005], "Position X", ["left", "right"]),
|
| 159 |
+
pos_y=(0.5, [0.1, 0.9, 0.005], "Position Y", ["up", "down"]),
|
| 160 |
+
)(place_puzzle)
|
| 161 |
+
# left, right, up, down will only supported when using the Qt backend
|
| 162 |
+
interactive(
|
| 163 |
+
flip=(False, "Flip Image"),
|
| 164 |
+
mirror=(False, "Mirror Image"),
|
| 165 |
+
)(flip_mirror_piece)
|
| 166 |
+
captcha_pipe_interactive = interactive_pipeline(
|
| 167 |
+
gui=backend,
|
| 168 |
+
cache=True,
|
| 169 |
+
markdown_description=markdown_description
|
| 170 |
+
)(captcha_pipe)
|
| 171 |
+
captcha_pipe_interactive(img)
|
| 172 |
+
|
| 173 |
|
| 174 |
if __name__ == "__main__":
|
| 175 |
import argparse
|
| 176 |
parser = argparse.ArgumentParser()
|
| 177 |
parser.add_argument("-b", "--backend", default="gradio",
|
| 178 |
+
choices=["gradio", "qt", "mpl"], type=str)
|
| 179 |
+
parser.add_argument(
|
| 180 |
+
"-d", "--debug", action="store_true",
|
| 181 |
+
help="Debug mode (to tune difficulty and tolerance)"
|
| 182 |
+
)
|
| 183 |
args = parser.parse_args()
|
| 184 |
+
markdown_description = "# Code to build this app on gradio \n\n"
|
| 185 |
+
markdown_description += "In local, try using `python app.py --backend qt --debug` to get the best experience with keyboard support aswell \n\n"
|
| 186 |
+
markdown_description += "Please note that matplobi`--backend mpl` is also functional although it won't look as good\n\n"
|
| 187 |
markdown_description += "```python\n"+open(__file__, 'r').read()+"```"
|
| 188 |
img = Image.load_image("sample.jpg")
|
| 189 |
+
main(img, backend=args.backend, debug=args.debug)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|