Merge pull request #21 from sdsc-ordes/feat-multi-animal-reporting
Browse files- .gitignore +2 -0
- app/.env.dist +1 -0
- app/assets/config/config_checkbox_behavior.json +1 -1
- app/assets/config/config_checkbox_physical.json +1 -1
- app/assets/config/{config_dropdown_conditions.json β config_dropdown_circumstances.json} +59 -24
- app/assets/images/empty_image.jpg +0 -0
- app/behavior/__init__.py +0 -0
- app/{behavior_checkbox.py β behavior/behavior_checkbox.py} +11 -4
- app/behavior/class_behavior.py +66 -0
- app/circumstances/__init__.py +0 -0
- app/{circumstances.py β circumstances/circumstances.py} +24 -14
- app/{circumstances_dropdowns.py β circumstances/circumstances_dropdowns.py} +40 -9
- app/circumstances/class_circumstance.py +205 -0
- app/classes.py +46 -0
- app/dead.py +32 -7
- app/display.py +120 -0
- app/follow_up/class_follow_up.py +50 -0
- app/follow_up/followup_events.py +46 -0
- app/followup_events.py +0 -17
- app/geolocalisation/__init__.py +0 -0
- app/geolocalisation/class_geolocalisation.py +16 -0
- app/{maps.py β geolocalisation/maps.py} +24 -1
- app/gradio_test/test_selectdata_event.py +16 -0
- app/gradio_test/tests_delete_gallery.py +25 -0
- app/main.py +311 -138
- app/main_test.py +0 -68
- app/physical/__init__.py +0 -0
- app/physical/class_physical.py +79 -0
- app/{physical_boxes_define.py β physical/physical_boxes_define.py} +0 -0
- app/{physical_boxes_map.py β physical/physical_boxes_map.py} +7 -2
- app/{physical_checkbox.py β physical/physical_checkbox.py} +17 -4
- app/{physical_select_animal.py β physical/physical_select_animal.py} +11 -5
- app/styling/__init__.py +0 -0
- app/{style.py β styling/style.py} +20 -2
- app/styling/theme.py +104 -0
- app/theme.py +0 -18
- app/utils/__init__.py +0 -0
- app/{utils_checkbox.py β utils/utils_checkbox.py} +0 -0
- app/{utils_config.py β utils/utils_config.py} +7 -2
- app/{utils_visible.py β utils/utils_visible.py} +0 -0
- app/validation_submission/__init__.py +0 -0
- app/validation_submission/add_json.py +15 -0
- app/validation_submission/create_json.py +20 -0
- app/validation_submission/get_json.py +16 -0
- app/validation_submission/processing.py +55 -0
- app/validation_submission/submission.py +17 -0
- app/validation_submission/validation.py +173 -0
- app/wounded.py +20 -9
- requirements.txt +3 -1
.gitignore
CHANGED
@@ -7,6 +7,8 @@ __pycache__/
|
|
7 |
|
8 |
#Data
|
9 |
test/data/**
|
|
|
|
|
10 |
|
11 |
# C extensions
|
12 |
*.so
|
|
|
7 |
|
8 |
#Data
|
9 |
test/data/**
|
10 |
+
data/**
|
11 |
+
app/assets/tmp_json/**
|
12 |
|
13 |
# C extensions
|
14 |
*.so
|
app/.env.dist
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
PATH_ASSETS="YOUR_PATH_HERE"
|
app/assets/config/config_checkbox_behavior.json
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
{
|
2 |
-
"Abnormal
|
3 |
{
|
4 |
"Description": "Problems breathing, breathing sounds"
|
5 |
},
|
|
|
1 |
{
|
2 |
+
"Abnormal breathing":
|
3 |
{
|
4 |
"Description": "Problems breathing, breathing sounds"
|
5 |
},
|
app/assets/config/config_checkbox_physical.json
CHANGED
@@ -11,7 +11,7 @@
|
|
11 |
"Description": "Obvious bone fracture"},
|
12 |
"Injury": {
|
13 |
"Description": "Visible skin injury"},
|
14 |
-
"
|
15 |
"Description": "Maggots, fleas, lice, louseflies"},
|
16 |
"Swelling": {
|
17 |
"Description": "Marked swelling without injury"},
|
|
|
11 |
"Description": "Obvious bone fracture"},
|
12 |
"Injury": {
|
13 |
"Description": "Visible skin injury"},
|
14 |
+
"Parasite": {
|
15 |
"Description": "Maggots, fleas, lice, louseflies"},
|
16 |
"Swelling": {
|
17 |
"Description": "Marked swelling without injury"},
|
app/assets/config/{config_dropdown_conditions.json β config_dropdown_circumstances.json}
RENAMED
@@ -3,40 +3,52 @@
|
|
3 |
{
|
4 |
"road vehicle":
|
5 |
{
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
},
|
11 |
"train":
|
12 |
{
|
13 |
-
"Open": "
|
14 |
},
|
15 |
"aircraft": {},
|
16 |
"boat": {},
|
17 |
-
"other": {},
|
18 |
"unknown": {}
|
19 |
},
|
20 |
"Destruction / Deliberatly removed" :
|
21 |
{
|
22 |
"hunting":
|
23 |
{
|
24 |
-
"Options":
|
|
|
|
|
|
|
25 |
},
|
26 |
"trap":
|
27 |
{
|
28 |
-
"Options":
|
|
|
|
|
|
|
|
|
29 |
},
|
30 |
"poisoning": {},
|
31 |
"removal or direct capture":
|
32 |
{
|
33 |
-
"Options": ["gassing", "raptor captured at nest",
|
|
|
|
|
|
|
34 |
},
|
35 |
"fishing":
|
36 |
{
|
37 |
-
"Options": ["drowned/tangled", "beached with capture indications",
|
|
|
|
|
38 |
},
|
39 |
-
"other": {},
|
40 |
"unknown": {}
|
41 |
},
|
42 |
"Indirect destruction":
|
@@ -44,59 +56,82 @@
|
|
44 |
"pylone and electric grid":
|
45 |
{
|
46 |
|
47 |
-
"Options":
|
|
|
|
|
48 |
"Extra":
|
49 |
{
|
50 |
-
"Cause": ["collision", "electrocution"
|
51 |
}
|
52 |
},
|
53 |
"windfarm": {},
|
54 |
"other collision":
|
55 |
{
|
56 |
-
"Options":
|
|
|
|
|
57 |
},
|
58 |
"fall":
|
59 |
{
|
60 |
-
"Options":
|
|
|
|
|
61 |
},
|
62 |
"development work":
|
63 |
{
|
64 |
-
"Options":
|
|
|
|
|
65 |
},
|
66 |
"pollution / contamination":
|
67 |
{
|
68 |
-
"Options":
|
|
|
|
|
69 |
},
|
70 |
"agricultural net protection": {},
|
71 |
"vegetal / forest work":
|
72 |
{
|
73 |
-
"Options":
|
|
|
|
|
|
|
|
|
74 |
},
|
75 |
-
"other": {},
|
76 |
"unknown": {}
|
77 |
},
|
78 |
"Natural cause":
|
79 |
{
|
80 |
"predation":
|
81 |
{
|
82 |
-
"Options":
|
|
|
|
|
|
|
83 |
},
|
84 |
"weather":
|
85 |
{
|
86 |
-
"Options":
|
|
|
|
|
87 |
},
|
88 |
"natural disaster":
|
89 |
{
|
90 |
-
"Options":
|
|
|
|
|
91 |
},
|
92 |
"nest fall": {},
|
93 |
"stranding due to exhaustion": {},
|
94 |
"disease/parasite": {},
|
95 |
"accidental drowing":
|
96 |
{
|
97 |
-
"Options":
|
|
|
|
|
98 |
},
|
99 |
-
"other": {},
|
100 |
"unknown": {}
|
101 |
},
|
102 |
"Unknown": {}
|
|
|
3 |
{
|
4 |
"road vehicle":
|
5 |
{
|
6 |
+
"Options": {
|
7 |
+
"road_type" : ["highway", "main road", "secondary road", "local road/path/trail", "parking lot", "other road", "unknown road"]
|
8 |
+
},
|
9 |
+
"Open": "Infrastructure_number"
|
10 |
},
|
11 |
"train":
|
12 |
{
|
13 |
+
"Open": "Infrastructure_number"
|
14 |
},
|
15 |
"aircraft": {},
|
16 |
"boat": {},
|
17 |
+
"other transport collision": {},
|
18 |
"unknown": {}
|
19 |
},
|
20 |
"Destruction / Deliberatly removed" :
|
21 |
{
|
22 |
"hunting":
|
23 |
{
|
24 |
+
"Options": {
|
25 |
+
"method" : ["shooting", "bow", "falconry",
|
26 |
+
"hounds hunting", "digging up", "other hunting", "unknow hunting"]
|
27 |
+
}
|
28 |
},
|
29 |
"trap":
|
30 |
{
|
31 |
+
"Options": {
|
32 |
+
"method": ["killing trap", "pole trap",
|
33 |
+
"trap cage", "corvids nasse", "net", "cage trap",
|
34 |
+
"fall-trap", "glue trap", "insect trap", "other trap", "unknown trap"]
|
35 |
+
}
|
36 |
},
|
37 |
"poisoning": {},
|
38 |
"removal or direct capture":
|
39 |
{
|
40 |
+
"Options": {"method": ["gassing", "raptor captured at nest",
|
41 |
+
"brood destruction", "traffic/trade", "capture accident",
|
42 |
+
"scientific sample", "other removal", "unknown removal"]
|
43 |
+
}
|
44 |
},
|
45 |
"fishing":
|
46 |
{
|
47 |
+
"Options": {"method" : ["drowned/tangled", "beached with capture indications",
|
48 |
+
"other fishing", "unknown fishing"]
|
49 |
+
}
|
50 |
},
|
51 |
+
"other destruction": {},
|
52 |
"unknown": {}
|
53 |
},
|
54 |
"Indirect destruction":
|
|
|
56 |
"pylone and electric grid":
|
57 |
{
|
58 |
|
59 |
+
"Options": {
|
60 |
+
"infrastructure" : ["electric line", "pole/pylon", "other structure", "unknown structure"]
|
61 |
+
},
|
62 |
"Extra":
|
63 |
{
|
64 |
+
"Cause": ["collision", "electrocution"]
|
65 |
}
|
66 |
},
|
67 |
"windfarm": {},
|
68 |
"other collision":
|
69 |
{
|
70 |
+
"Options": {
|
71 |
+
"object": ["window", "building", "lighthouse", "cable", "wire fence/barbed wire", "other crash", "unknown crash"]
|
72 |
+
}
|
73 |
},
|
74 |
"fall":
|
75 |
{
|
76 |
+
"Options": {
|
77 |
+
"location": ["chimney", "empty pole", "hole/well", "other fall", "unknown fall"]
|
78 |
+
}
|
79 |
},
|
80 |
"development work":
|
81 |
{
|
82 |
+
"Options": {
|
83 |
+
"work_type" : ["transport infrastructure", "building", "other work", "unknown work"]
|
84 |
+
}
|
85 |
},
|
86 |
"pollution / contamination":
|
87 |
{
|
88 |
+
"Options": {
|
89 |
+
"pollution_type" : ["oil pollution", "chemical pollution", "heavy metals",
|
90 |
+
"light", "noise", "plastic ingestion", "other pollution", "unknown pollution"]
|
91 |
},
|
92 |
"agricultural net protection": {},
|
93 |
"vegetal / forest work":
|
94 |
{
|
95 |
+
"Options": {
|
96 |
+
"work_type" : ["clearing/mowing/plowing", "tree felling/pruning",
|
97 |
+
"other forest work", "unknown forest work"]
|
98 |
+
}
|
99 |
+
}
|
100 |
},
|
101 |
+
"other indirect destruction": {},
|
102 |
"unknown": {}
|
103 |
},
|
104 |
"Natural cause":
|
105 |
{
|
106 |
"predation":
|
107 |
{
|
108 |
+
"Options": {
|
109 |
+
"predator" : ["cat", "dog", "rooster/hen", "other domestic animal", "wild birds",
|
110 |
+
"wild mammal", "other predator", "unknown predator"]
|
111 |
+
}
|
112 |
},
|
113 |
"weather":
|
114 |
{
|
115 |
+
"Options": {
|
116 |
+
"condition" : ["cold wave", "drought", "hail", "lightening", "storm", "other weather", "unknown weather"]
|
117 |
+
}
|
118 |
},
|
119 |
"natural disaster":
|
120 |
{
|
121 |
+
"Options": {
|
122 |
+
"disaster" : ["fire", "avalanche", "rock fall", "mudslide", "volcanic eruption/ashes", "other natural disaster", "unknown natural disaster"]
|
123 |
+
}
|
124 |
},
|
125 |
"nest fall": {},
|
126 |
"stranding due to exhaustion": {},
|
127 |
"disease/parasite": {},
|
128 |
"accidental drowing":
|
129 |
{
|
130 |
+
"Options": {
|
131 |
+
"drowning_location" : ["drinking trough", "pool", "storm pool", "irrigation pool", "natural pool", "flood", "other location", "unknown location"]
|
132 |
+
}
|
133 |
},
|
134 |
+
"other natural cause": {},
|
135 |
"unknown": {}
|
136 |
},
|
137 |
"Unknown": {}
|
app/assets/images/empty_image.jpg
ADDED
![]() |
app/behavior/__init__.py
ADDED
File without changes
|
app/{behavior_checkbox.py β behavior/behavior_checkbox.py}
RENAMED
@@ -1,9 +1,15 @@
|
|
1 |
-
|
2 |
-
from
|
3 |
-
from
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
def retrieve_behavior_options_description():
|
6 |
-
dropdown_config = get_custom_config_dropdowns("
|
7 |
options = list(dropdown_config.keys())
|
8 |
options = [option.title() for option in options]
|
9 |
descriptions =[]
|
@@ -20,4 +26,5 @@ def create_behavior_checkbox(section: str, visible):
|
|
20 |
def show_behavior(choice, section: str):
|
21 |
visible = set_visible(choice)
|
22 |
checkbox, text = create_behavior_checkbox(section, visible)
|
|
|
23 |
return checkbox, text
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from utils.utils_config import get_custom_config_dropdowns
|
3 |
+
from utils.utils_checkbox import create_checkbox
|
4 |
+
from utils.utils_visible import set_visible
|
5 |
+
from validation_submission.add_json import add_data_tmp
|
6 |
+
|
7 |
+
def on_select_behavior(behavior_checkbox):
|
8 |
+
behavior_checkbox = [behavior.lower() for behavior in behavior_checkbox]
|
9 |
+
add_data_tmp("wounded_dead", "behaviors_type", behavior_checkbox)
|
10 |
|
11 |
def retrieve_behavior_options_description():
|
12 |
+
dropdown_config = get_custom_config_dropdowns("config_checkbox_behavior.json")
|
13 |
options = list(dropdown_config.keys())
|
14 |
options = [option.title() for option in options]
|
15 |
descriptions =[]
|
|
|
26 |
def show_behavior(choice, section: str):
|
27 |
visible = set_visible(choice)
|
28 |
checkbox, text = create_behavior_checkbox(section, visible)
|
29 |
+
add_data_tmp("wounded_dead", "behaviors_radio", choice)
|
30 |
return checkbox, text
|
app/behavior/class_behavior.py
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel, Field
|
2 |
+
from typing import Literal, List, Union, Optional
|
3 |
+
|
4 |
+
class Behavior(BaseModel):
|
5 |
+
type: str
|
6 |
+
description: Optional[str] = None # Making the description field optional
|
7 |
+
|
8 |
+
# --- Specific Behavior classes ---
|
9 |
+
class AbnormalBreathing(Behavior):
|
10 |
+
type: Literal['abnormal breathing']
|
11 |
+
description: Optional[Literal["Problems breathing, breathing sounds"]] = None
|
12 |
+
|
13 |
+
class CrashFalling(Behavior):
|
14 |
+
type: Literal['crash, falling from the sky']
|
15 |
+
description: Optional[Literal["Suddenly falling from the sky"]] = None
|
16 |
+
|
17 |
+
class Diarrhea(Behavior):
|
18 |
+
type: Literal['diarrhea']
|
19 |
+
description: Optional[Literal["Observed diarrhea"]] = None
|
20 |
+
|
21 |
+
class Lameness(Behavior):
|
22 |
+
type: Literal['lameness']
|
23 |
+
description: Optional[Literal["Apparent limping or not able to walk properly"]] = None
|
24 |
+
|
25 |
+
class Neurological(Behavior):
|
26 |
+
type: Literal['neurological']
|
27 |
+
description: Optional[Literal["Circling, incoordination, tremors, convulsions, fast eye movements"]] = None
|
28 |
+
|
29 |
+
class OtherAbnormalBehavior(Behavior):
|
30 |
+
type: Literal['other abnormal behavior']
|
31 |
+
description: Optional[Literal["Other than weakness, other than neurologic"]] = None
|
32 |
+
|
33 |
+
class UnableToFly(Behavior):
|
34 |
+
type: Literal['unable to fly']
|
35 |
+
description: Optional[Literal["Animal alert and tries to fly but can not take off"]] = None
|
36 |
+
|
37 |
+
class Vomiting(Behavior):
|
38 |
+
type: Literal['vomiting']
|
39 |
+
description: Optional[Literal["Throwing up undigested food, regurgitating"]] = None
|
40 |
+
|
41 |
+
class Weakness(Behavior):
|
42 |
+
type: Literal['weakness']
|
43 |
+
description: Optional[Literal["Non responsive, does not fly away when approached, lethargy"]] = None
|
44 |
+
|
45 |
+
class NoChanges(Behavior):
|
46 |
+
type: Literal['no changes']
|
47 |
+
description: Optional[Literal["Animal is acting normally"]] = None
|
48 |
+
|
49 |
+
# Union of all possible behaviors
|
50 |
+
BehaviorType = Union[
|
51 |
+
AbnormalBreathing,
|
52 |
+
CrashFalling,
|
53 |
+
Diarrhea,
|
54 |
+
Lameness,
|
55 |
+
Neurological,
|
56 |
+
OtherAbnormalBehavior,
|
57 |
+
UnableToFly,
|
58 |
+
Vomiting,
|
59 |
+
Weakness,
|
60 |
+
NoChanges
|
61 |
+
]
|
62 |
+
|
63 |
+
# Main class that logs multiple behaviors
|
64 |
+
class Behaviors(BaseModel):
|
65 |
+
behaviors_radio: str # e.g., "Yes"
|
66 |
+
behaviors_type: Optional[List[BehaviorType]] = None
|
app/circumstances/__init__.py
ADDED
File without changes
|
app/{circumstances.py β circumstances/circumstances.py}
RENAMED
@@ -1,49 +1,59 @@
|
|
1 |
import gradio as gr
|
2 |
import os
|
3 |
-
from
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
-
PATH = os.getcwd()
|
6 |
CAUSE_COL_WIDTH = "50px"
|
7 |
|
8 |
-
|
|
|
9 |
visible = set_visible(choice)
|
10 |
-
|
|
|
|
|
|
|
11 |
return button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2
|
12 |
|
13 |
-
def
|
14 |
-
button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause =
|
15 |
-
dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2 =
|
16 |
return button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2
|
17 |
|
18 |
-
|
19 |
-
def create_causes_buttons(visible):
|
20 |
with gr.Row() as image_row:
|
21 |
with gr.Column(scale=1, min_width=CAUSE_COL_WIDTH):
|
22 |
button_collision = gr.Button("Collision with a means of transport",
|
23 |
visible=visible,
|
24 |
-
icon=
|
25 |
elem_id="buttons-conditions")
|
26 |
|
27 |
with gr.Column(scale=1, min_width=CAUSE_COL_WIDTH):
|
28 |
button_deliberate_destruction = gr.Button("Destruction / Deliberatly removed",
|
29 |
-
icon=
|
30 |
visible=visible,
|
31 |
elem_id="buttons-conditions")
|
32 |
|
33 |
with gr.Column(scale=1, min_width=CAUSE_COL_WIDTH):
|
34 |
button_indirect_destruction = gr.Button("Indirect destruction",
|
35 |
-
icon=
|
36 |
visible=visible,
|
37 |
elem_id="buttons-conditions")
|
38 |
|
39 |
with gr.Column(scale=1, min_width=CAUSE_COL_WIDTH):
|
40 |
button_natural_cause = gr.Button("Natural cause",
|
41 |
-
icon=
|
42 |
visible=visible,
|
43 |
elem_id="buttons-conditions")
|
44 |
return button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause
|
45 |
|
46 |
-
def
|
47 |
with gr.Row() as dropdown_row:
|
48 |
dropdown = gr.Dropdown(choices=[],
|
49 |
label="Choices will appear here...",
|
|
|
1 |
import gradio as gr
|
2 |
import os
|
3 |
+
from dotenv import load_dotenv
|
4 |
+
|
5 |
+
from utils.utils_visible import set_visible
|
6 |
+
from validation_submission.add_json import add_data_tmp
|
7 |
+
|
8 |
+
load_dotenv()
|
9 |
+
PATH = os.getcwd() + "/"
|
10 |
+
PATH_ASSETS = os.getenv('PATH_ASSETS')
|
11 |
+
LOGO_PATH = PATH + PATH_ASSETS + "logos"
|
12 |
|
|
|
13 |
CAUSE_COL_WIDTH = "50px"
|
14 |
|
15 |
+
|
16 |
+
def show_circumstances(choice):
|
17 |
visible = set_visible(choice)
|
18 |
+
add_data_tmp("wounded_dead",
|
19 |
+
"circumstance_radio",
|
20 |
+
choice)
|
21 |
+
button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2 = create_circumstances(visible)
|
22 |
return button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2
|
23 |
|
24 |
+
def create_circumstances(visible):
|
25 |
+
button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause = create_circumstances_buttons(visible)
|
26 |
+
dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2 = create_circumstances_dropdown(visible)
|
27 |
return button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2
|
28 |
|
29 |
+
def create_circumstances_buttons(visible):
|
|
|
30 |
with gr.Row() as image_row:
|
31 |
with gr.Column(scale=1, min_width=CAUSE_COL_WIDTH):
|
32 |
button_collision = gr.Button("Collision with a means of transport",
|
33 |
visible=visible,
|
34 |
+
icon=LOGO_PATH + '/van.png',
|
35 |
elem_id="buttons-conditions")
|
36 |
|
37 |
with gr.Column(scale=1, min_width=CAUSE_COL_WIDTH):
|
38 |
button_deliberate_destruction = gr.Button("Destruction / Deliberatly removed",
|
39 |
+
icon=LOGO_PATH + '/destruction.png',
|
40 |
visible=visible,
|
41 |
elem_id="buttons-conditions")
|
42 |
|
43 |
with gr.Column(scale=1, min_width=CAUSE_COL_WIDTH):
|
44 |
button_indirect_destruction = gr.Button("Indirect destruction",
|
45 |
+
icon=LOGO_PATH + '/indirect.png',
|
46 |
visible=visible,
|
47 |
elem_id="buttons-conditions")
|
48 |
|
49 |
with gr.Column(scale=1, min_width=CAUSE_COL_WIDTH):
|
50 |
button_natural_cause = gr.Button("Natural cause",
|
51 |
+
icon=LOGO_PATH + '/natural.png',
|
52 |
visible=visible,
|
53 |
elem_id="buttons-conditions")
|
54 |
return button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause
|
55 |
|
56 |
+
def create_circumstances_dropdown(visible):
|
57 |
with gr.Row() as dropdown_row:
|
58 |
dropdown = gr.Dropdown(choices=[],
|
59 |
label="Choices will appear here...",
|
app/{circumstances_dropdowns.py β circumstances/circumstances_dropdowns.py}
RENAMED
@@ -1,6 +1,6 @@
|
|
1 |
import gradio as gr
|
2 |
-
from utils_config import get_custom_config_dropdowns
|
3 |
-
|
4 |
|
5 |
#--------------------------------------------------------- LEVEL 1 DROPDOWNS
|
6 |
def retrieve_config_options(label, dropdown_config):
|
@@ -15,7 +15,7 @@ def reinitialise_level2():
|
|
15 |
return dropdown_level2, openfield_level2, dropdown_extra_level2
|
16 |
|
17 |
def create_dropdown_level1(label):
|
18 |
-
dropdown_config = get_custom_config_dropdowns("
|
19 |
options = retrieve_config_options(label, dropdown_config)
|
20 |
dropdown = gr.Dropdown(choices=options, label=label, interactive=True, visible=True)
|
21 |
dropdown_level2, openfield_level2, dropdown_extra_level2 = reinitialise_level2()
|
@@ -23,34 +23,41 @@ def create_dropdown_level1(label):
|
|
23 |
|
24 |
def dropdown_collision():
|
25 |
label = "Collision with a means of transport"
|
|
|
26 |
return create_dropdown_level1(label)
|
27 |
|
28 |
def dropdown_deliberate_destruction():
|
29 |
label = "Destruction / Deliberatly removed"
|
|
|
30 |
return create_dropdown_level1(label)
|
31 |
|
32 |
def dropdown_indirect_destruction():
|
33 |
label = "Indirect destruction"
|
|
|
34 |
return create_dropdown_level1(label)
|
35 |
|
36 |
def dropdown_natural_cause():
|
37 |
label = "Natural cause"
|
|
|
38 |
return create_dropdown_level1(label)
|
39 |
|
40 |
|
41 |
#--------------------------------------------------------- LEVEL 2 DROPDOWNS
|
42 |
def get_options(value):
|
43 |
value = value.lower()
|
|
|
44 |
options_dropdown= None
|
45 |
open_field = None
|
46 |
extras = None
|
47 |
extras_label = None
|
48 |
-
dropdown_config = get_custom_config_dropdowns("
|
49 |
for _, sub_dict in dropdown_config.items():
|
50 |
nested_dict = sub_dict.get(value)
|
51 |
if nested_dict is not None:
|
52 |
if "Options" in nested_dict.keys():
|
53 |
-
|
|
|
|
|
54 |
options_dropdown = [option.title() for option in options_dropdown]
|
55 |
if "Open" in nested_dict.keys():
|
56 |
open_field = nested_dict["Open"]
|
@@ -60,10 +67,18 @@ def get_options(value):
|
|
60 |
extras_label = key
|
61 |
extras = val
|
62 |
extras = [extra.title() for extra in extras]
|
63 |
-
return options_dropdown, open_field, extras, extras_label
|
64 |
-
|
|
|
65 |
def on_select(evt: gr.SelectData): # SelectData is a subclass of EventData
|
66 |
-
options_dropdown, open_field, extras, extras_label = get_options(evt.value)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
if options_dropdown is not None:
|
68 |
dropdown_level2 = gr.Dropdown(choices=options_dropdown, label=evt.value, interactive=True, visible=True)
|
69 |
else:
|
@@ -78,4 +93,20 @@ def on_select(evt: gr.SelectData): # SelectData is a subclass of EventData
|
|
78 |
dropdown_extra_level2 = gr.Dropdown(choices=extras, label=extras_label, interactive=True, visible=True)
|
79 |
else:
|
80 |
dropdown_extra_level2 = gr.Dropdown(choices=[], visible=False)
|
81 |
-
return dropdown_level2, openfield_level2, dropdown_extra_level2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
+
from utils.utils_config import get_custom_config_dropdowns
|
3 |
+
from validation_submission.add_json import add_data_tmp
|
4 |
|
5 |
#--------------------------------------------------------- LEVEL 1 DROPDOWNS
|
6 |
def retrieve_config_options(label, dropdown_config):
|
|
|
15 |
return dropdown_level2, openfield_level2, dropdown_extra_level2
|
16 |
|
17 |
def create_dropdown_level1(label):
|
18 |
+
dropdown_config = get_custom_config_dropdowns("config_dropdown_circumstances.json")
|
19 |
options = retrieve_config_options(label, dropdown_config)
|
20 |
dropdown = gr.Dropdown(choices=options, label=label, interactive=True, visible=True)
|
21 |
dropdown_level2, openfield_level2, dropdown_extra_level2 = reinitialise_level2()
|
|
|
23 |
|
24 |
def dropdown_collision():
|
25 |
label = "Collision with a means of transport"
|
26 |
+
add_data_tmp("wounded_dead", "circumstance", label.lower())
|
27 |
return create_dropdown_level1(label)
|
28 |
|
29 |
def dropdown_deliberate_destruction():
|
30 |
label = "Destruction / Deliberatly removed"
|
31 |
+
add_data_tmp("wounded_dead", "circumstance", label.lower())
|
32 |
return create_dropdown_level1(label)
|
33 |
|
34 |
def dropdown_indirect_destruction():
|
35 |
label = "Indirect destruction"
|
36 |
+
add_data_tmp("wounded_dead", "circumstance", label.lower())
|
37 |
return create_dropdown_level1(label)
|
38 |
|
39 |
def dropdown_natural_cause():
|
40 |
label = "Natural cause"
|
41 |
+
add_data_tmp("wounded_dead", "circumstance", label.lower())
|
42 |
return create_dropdown_level1(label)
|
43 |
|
44 |
|
45 |
#--------------------------------------------------------- LEVEL 2 DROPDOWNS
|
46 |
def get_options(value):
|
47 |
value = value.lower()
|
48 |
+
options_label = None
|
49 |
options_dropdown= None
|
50 |
open_field = None
|
51 |
extras = None
|
52 |
extras_label = None
|
53 |
+
dropdown_config = get_custom_config_dropdowns("config_dropdown_circumstances.json")
|
54 |
for _, sub_dict in dropdown_config.items():
|
55 |
nested_dict = sub_dict.get(value)
|
56 |
if nested_dict is not None:
|
57 |
if "Options" in nested_dict.keys():
|
58 |
+
options_dict = nested_dict["Options"]
|
59 |
+
options_label = list(options_dict.keys())[0]
|
60 |
+
options_dropdown = list(options_dict.values())[0]
|
61 |
options_dropdown = [option.title() for option in options_dropdown]
|
62 |
if "Open" in nested_dict.keys():
|
63 |
open_field = nested_dict["Open"]
|
|
|
67 |
extras_label = key
|
68 |
extras = val
|
69 |
extras = [extra.title() for extra in extras]
|
70 |
+
return options_label, options_dropdown, open_field, extras, extras_label
|
71 |
+
|
72 |
+
|
73 |
def on_select(evt: gr.SelectData): # SelectData is a subclass of EventData
|
74 |
+
options_label, options_dropdown, open_field, extras, extras_label = get_options(evt.value)
|
75 |
+
add_data_tmp("wounded_dead",
|
76 |
+
"circumstance_type",
|
77 |
+
{"type": (evt.value).lower(),
|
78 |
+
"option_dropdown_label" : options_label.lower() if options_label is not None else 'NA',
|
79 |
+
"open_field_label" : open_field.lower() if open_field is not None else 'NA',
|
80 |
+
"extra_label": extras_label.lower() if extras_label is not None else 'NA'
|
81 |
+
})
|
82 |
if options_dropdown is not None:
|
83 |
dropdown_level2 = gr.Dropdown(choices=options_dropdown, label=evt.value, interactive=True, visible=True)
|
84 |
else:
|
|
|
93 |
dropdown_extra_level2 = gr.Dropdown(choices=extras, label=extras_label, interactive=True, visible=True)
|
94 |
else:
|
95 |
dropdown_extra_level2 = gr.Dropdown(choices=[], visible=False)
|
96 |
+
return dropdown_level2, openfield_level2, dropdown_extra_level2
|
97 |
+
|
98 |
+
def on_select_dropdown_level2(evt: gr.SelectData):
|
99 |
+
add_data_tmp("wounded_dead",
|
100 |
+
"circumstance_option_dropdown",
|
101 |
+
evt.value.lower())
|
102 |
+
|
103 |
+
def on_select_dropdown_extra_level2(evt: gr.SelectData):
|
104 |
+
add_data_tmp("wounded_dead",
|
105 |
+
"circumstance_extra",
|
106 |
+
evt.value.lower())
|
107 |
+
|
108 |
+
def on_change_openfield_level2(openfield_level2_dead):
|
109 |
+
print("Saving open field")
|
110 |
+
add_data_tmp("wounded_dead",
|
111 |
+
"circumstance_open_field",
|
112 |
+
str(openfield_level2_dead).lower())
|
app/circumstances/class_circumstance.py
ADDED
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel, Field
|
2 |
+
from typing import Literal, List, Union, Optional
|
3 |
+
|
4 |
+
# Base class for CircumstanceType with a discriminator field 'type'
|
5 |
+
class CircumstanceTypeBase(BaseModel):
|
6 |
+
type: str
|
7 |
+
|
8 |
+
# Collision with means of transport
|
9 |
+
class RoadVehicleCollision(CircumstanceTypeBase):
|
10 |
+
type: Literal['road_vehicle']
|
11 |
+
infrastructure_number: Optional[str] = None
|
12 |
+
road_type: Literal['highway', 'main road',
|
13 |
+
'secondary road', 'local road/path/trail',
|
14 |
+
'parking lot']
|
15 |
+
|
16 |
+
class TrainCollision(CircumstanceTypeBase):
|
17 |
+
type: Literal['train']
|
18 |
+
infrastructure_number: str
|
19 |
+
|
20 |
+
class AircraftCollision(CircumstanceTypeBase):
|
21 |
+
type: Literal['aircraft']
|
22 |
+
|
23 |
+
class BoatCollision(CircumstanceTypeBase):
|
24 |
+
type: Literal['boat']
|
25 |
+
|
26 |
+
class OtherTransportCollision(CircumstanceTypeBase):
|
27 |
+
type: Literal['other transport collision']
|
28 |
+
|
29 |
+
class UnknownTransportCollision(CircumstanceTypeBase):
|
30 |
+
type: Literal['unknown transport collision']
|
31 |
+
|
32 |
+
# Destruction / Deliberately removed
|
33 |
+
class HuntingDestruction(CircumstanceTypeBase):
|
34 |
+
type: Literal['hunting']
|
35 |
+
method: Literal['shooting', 'bow', 'falconry',
|
36 |
+
'hounds hunting', 'digging up',
|
37 |
+
"other hunting", "unknow hunting"]
|
38 |
+
|
39 |
+
class TrapDestruction(CircumstanceTypeBase):
|
40 |
+
type: Literal['trap']
|
41 |
+
method: Literal['killing trap', 'pole trap', 'trap cage', 'corvids nasse',
|
42 |
+
'net', 'cage trap', 'fall-trap', 'glue trap', 'insect trap',
|
43 |
+
"other trap", "unknown trap"]
|
44 |
+
|
45 |
+
class PoisoningDestruction(CircumstanceTypeBase):
|
46 |
+
type: Literal['poisoning']
|
47 |
+
|
48 |
+
class RemovalDestruction(CircumstanceTypeBase):
|
49 |
+
type: Literal['removal or direct capture']
|
50 |
+
method: Literal['gassing', 'raptor captured at nest', 'brood destruction',
|
51 |
+
'traffic/trade', 'capture accident', 'scientific sample',
|
52 |
+
"other removal", "unknown removal"]
|
53 |
+
|
54 |
+
class FishingDestruction(CircumstanceTypeBase):
|
55 |
+
type: Literal['fishing']
|
56 |
+
method: Literal['drowned/tangled', 'beached with capture indications', "other fishing", "unknown fishing"]
|
57 |
+
|
58 |
+
class OtherDestruction(CircumstanceTypeBase):
|
59 |
+
type: Literal['other destruction']
|
60 |
+
|
61 |
+
class UnknownDestruction(CircumstanceTypeBase):
|
62 |
+
type: Literal['unknown destruction']
|
63 |
+
|
64 |
+
# Indirect destruction
|
65 |
+
class PylonElectricGridDestruction(CircumstanceTypeBase):
|
66 |
+
type: Literal['pylone and electric grid']
|
67 |
+
infrastructure: Literal['electric line', 'pole/pylon', "other structure", "unknown structure"]
|
68 |
+
cause: Literal['collision', 'electrocution']
|
69 |
+
|
70 |
+
class WindfarmDestruction(CircumstanceTypeBase):
|
71 |
+
type: Literal['windfarm']
|
72 |
+
|
73 |
+
class OtherCollisionDestruction(CircumstanceTypeBase):
|
74 |
+
type: Literal['other collision']
|
75 |
+
object: Literal['window', 'building', 'lighthouse',
|
76 |
+
'cable', 'wire fence/barbed wire', 'other crash', 'unknown crash']
|
77 |
+
|
78 |
+
class FallDestruction(CircumstanceTypeBase):
|
79 |
+
type: Literal['fall']
|
80 |
+
location: Literal['chimney', 'empty pole', 'hole/well', 'other fall', 'unknown fall']
|
81 |
+
|
82 |
+
class DevelopmentWorkDestruction(CircumstanceTypeBase):
|
83 |
+
type: Literal['development work']
|
84 |
+
work_type: Literal['transport infrastructure', 'building', 'other work', 'unknown work']
|
85 |
+
|
86 |
+
class PollutionContaminationDestruction(CircumstanceTypeBase):
|
87 |
+
type: Literal['pollution / contamination']
|
88 |
+
pollution_type: Literal['oil pollution', 'chemical pollution', 'heavy metals',
|
89 |
+
'light', 'noise',
|
90 |
+
'plastic ingestion', 'other pollution', 'unknown pollution']
|
91 |
+
|
92 |
+
class AgriculturalNetProtectionDestruction(CircumstanceTypeBase):
|
93 |
+
type: Literal['agricultural net protection']
|
94 |
+
|
95 |
+
class VegetalForestWorkDestruction(CircumstanceTypeBase):
|
96 |
+
type: Literal['vegetal / forest work']
|
97 |
+
work_type: Literal['clearing/mowing/plowing', 'tree felling/pruning',
|
98 |
+
'other forest work', 'unknown forest work']
|
99 |
+
|
100 |
+
class OtherIndirectDestruction(CircumstanceTypeBase):
|
101 |
+
type: Literal['other indirect desctruction']
|
102 |
+
|
103 |
+
class UnknownIndirectDestruction(CircumstanceTypeBase):
|
104 |
+
type: Literal['unknown indirect desctruction']
|
105 |
+
|
106 |
+
# Natural cause
|
107 |
+
class Predation(CircumstanceTypeBase):
|
108 |
+
type: Literal['predation']
|
109 |
+
predator: Literal['cat', 'dog', 'rooster/hen',
|
110 |
+
'other domestic animal', 'wild birds',
|
111 |
+
'wild mammal', 'other predator', 'unknown predator']
|
112 |
+
|
113 |
+
class Weather(CircumstanceTypeBase):
|
114 |
+
type: Literal['weather']
|
115 |
+
condition: Literal['cold wave', 'drought', 'hail',
|
116 |
+
'lightening', 'storm',
|
117 |
+
'other weather', 'unknown weather']
|
118 |
+
|
119 |
+
class NaturalDisaster(CircumstanceTypeBase):
|
120 |
+
type: Literal['natural disaster']
|
121 |
+
disaster: Literal['fire', 'avalanche', 'rock fall',
|
122 |
+
'mudslide', 'volcanic eruption/ashes',
|
123 |
+
'other natural disaster', 'unknown natural disaster']
|
124 |
+
|
125 |
+
class NestFall(CircumstanceTypeBase):
|
126 |
+
type: Literal['nest fall']
|
127 |
+
|
128 |
+
class StrandingExhaustion(CircumstanceTypeBase):
|
129 |
+
type: Literal['stranding due to exhaustion']
|
130 |
+
|
131 |
+
class DiseaseParasite(CircumstanceTypeBase):
|
132 |
+
type: Literal['disease/parasite']
|
133 |
+
|
134 |
+
class AccidentalDrowning(CircumstanceTypeBase):
|
135 |
+
type: Literal['accidental drowning']
|
136 |
+
drowning_location: Literal['drinking trough', 'pool',
|
137 |
+
'storm pool', 'irrigation pool',
|
138 |
+
'natural pool', 'flood',
|
139 |
+
'other location', 'unknown location']
|
140 |
+
|
141 |
+
class OtherNaturalCause(CircumstanceTypeBase):
|
142 |
+
type: Literal['other natural cause']
|
143 |
+
|
144 |
+
class UnknownNaturalCause(CircumstanceTypeBase):
|
145 |
+
type: Literal['unknown natural cause']
|
146 |
+
|
147 |
+
# Unknown cause
|
148 |
+
class UnknownCircumstance(CircumstanceTypeBase):
|
149 |
+
type: Literal['unknown']
|
150 |
+
|
151 |
+
# Union of all possible CircumstanceTypes with 'type' as the discriminator
|
152 |
+
CircumstanceType = Union[
|
153 |
+
RoadVehicleCollision,
|
154 |
+
TrainCollision,
|
155 |
+
AircraftCollision,
|
156 |
+
BoatCollision,
|
157 |
+
OtherTransportCollision,
|
158 |
+
UnknownTransportCollision,
|
159 |
+
HuntingDestruction,
|
160 |
+
TrapDestruction,
|
161 |
+
PoisoningDestruction,
|
162 |
+
RemovalDestruction,
|
163 |
+
FishingDestruction,
|
164 |
+
OtherDestruction,
|
165 |
+
UnknownDestruction,
|
166 |
+
PylonElectricGridDestruction,
|
167 |
+
WindfarmDestruction,
|
168 |
+
OtherCollisionDestruction,
|
169 |
+
FallDestruction,
|
170 |
+
DevelopmentWorkDestruction,
|
171 |
+
PollutionContaminationDestruction,
|
172 |
+
AgriculturalNetProtectionDestruction,
|
173 |
+
VegetalForestWorkDestruction,
|
174 |
+
OtherIndirectDestruction,
|
175 |
+
UnknownIndirectDestruction,
|
176 |
+
Predation,
|
177 |
+
Weather,
|
178 |
+
NaturalDisaster,
|
179 |
+
NestFall,
|
180 |
+
StrandingExhaustion,
|
181 |
+
DiseaseParasite,
|
182 |
+
AccidentalDrowning,
|
183 |
+
OtherNaturalCause,
|
184 |
+
UnknownNaturalCause,
|
185 |
+
UnknownCircumstance
|
186 |
+
]
|
187 |
+
|
188 |
+
# Main Circumstance class
|
189 |
+
class Circumstances(BaseModel):
|
190 |
+
circumstance_radio: str # e.g., "Yes"
|
191 |
+
circumstance: Optional[str] = None # e.g., "COLLISION"
|
192 |
+
circumstance_type: Optional[CircumstanceType] = Field(None, discriminator='type')
|
193 |
+
|
194 |
+
|
195 |
+
# Example usage
|
196 |
+
# json_data = {
|
197 |
+
# "circumstance": "COLLISION",
|
198 |
+
# "circumstance_radio": "Yes",
|
199 |
+
# "circumstance_type": {
|
200 |
+
# "type": "Train",
|
201 |
+
# "infrastructure_number": "56"
|
202 |
+
# }
|
203 |
+
# }
|
204 |
+
# circumstance_instance = Circumstance(**json_data)
|
205 |
+
# circumstance_schema = Circumstance.schema_json(indent=2)
|
app/classes.py
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel, Field
|
2 |
+
from typing import Optional
|
3 |
+
import numpy as np
|
4 |
+
from PIL import Image
|
5 |
+
import io
|
6 |
+
import base64
|
7 |
+
import uuid
|
8 |
+
|
9 |
+
from behavior.class_behavior import Behaviors
|
10 |
+
from circumstances.class_circumstance import Circumstances
|
11 |
+
from physical.class_physical import PhysicalAnomalies
|
12 |
+
from follow_up.class_follow_up import FollowUpEvents
|
13 |
+
from geolocalisation.class_geolocalisation import Geolocalisation
|
14 |
+
|
15 |
+
class Wounded(BaseModel):
|
16 |
+
circumstances: Circumstances
|
17 |
+
behaviors: Behaviors
|
18 |
+
physical_anomalies: PhysicalAnomalies
|
19 |
+
follow_up_events: FollowUpEvents
|
20 |
+
|
21 |
+
class Dead(BaseModel):
|
22 |
+
circumstances: Circumstances
|
23 |
+
physical_anomalies: PhysicalAnomalies
|
24 |
+
follow_up_events: FollowUpEvents
|
25 |
+
|
26 |
+
class ImageBase64(BaseModel):
|
27 |
+
image: str
|
28 |
+
@classmethod
|
29 |
+
def to_base64(cls, pixel_data: list):
|
30 |
+
img_array = np.array(pixel_data, dtype=np.uint8)
|
31 |
+
img = Image.fromarray(img_array)
|
32 |
+
# Save the image to a bytes buffer
|
33 |
+
buffer = io.BytesIO()
|
34 |
+
img.save(buffer, format="PNG")
|
35 |
+
buffer.seek(0)
|
36 |
+
base64_str = base64.b64encode(buffer.read()).decode('utf-8')
|
37 |
+
return cls(image=base64_str)
|
38 |
+
|
39 |
+
class Report(BaseModel):
|
40 |
+
identifier: str
|
41 |
+
image: ImageBase64
|
42 |
+
geolocalisation: Geolocalisation
|
43 |
+
wounded_state: str
|
44 |
+
wounded: Optional[Wounded] = None
|
45 |
+
dead_state: str
|
46 |
+
dead: Optional[Dead] = None
|
app/dead.py
CHANGED
@@ -1,15 +1,40 @@
|
|
1 |
import gradio as gr
|
2 |
-
from circumstances import
|
3 |
-
from
|
4 |
-
|
|
|
|
|
5 |
|
6 |
def show_section_dead(visible):
|
|
|
|
|
|
|
|
|
7 |
with gr.Column(visible=visible, elem_id="dead") as section_dead:
|
8 |
gr.Markdown("# Dead Animal")
|
9 |
-
gr.Markdown("## Please describe the cause of death", label="description")
|
10 |
|
11 |
-
|
|
|
|
|
12 |
|
13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
|
15 |
-
return section_dead,
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
+
from circumstances.circumstances import create_circumstances
|
3 |
+
from physical.physical_select_animal import create_bird_anatomy
|
4 |
+
from physical.physical_checkbox import process_body_parts
|
5 |
+
from follow_up.followup_events import create_followup_dropdowns, create_followup_open
|
6 |
+
from validation_submission.add_json import add_data_to_individual
|
7 |
|
8 |
def show_section_dead(visible):
|
9 |
+
if visible==True:
|
10 |
+
add_data_to_individual("wounded_state", "No")
|
11 |
+
add_data_to_individual("dead_state", "Yes")
|
12 |
+
|
13 |
with gr.Column(visible=visible, elem_id="dead") as section_dead:
|
14 |
gr.Markdown("# Dead Animal")
|
|
|
15 |
|
16 |
+
gr.Markdown("## Do you know what conditions caused this?", label="description")
|
17 |
+
radio_cause = gr.Radio(["Yes", "No"], value=None, show_label=False, interactive=True)
|
18 |
+
button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2 = create_circumstances(visible=False)
|
19 |
|
20 |
+
gr.Markdown("## Are there physical changes on the bird?" , label="description")
|
21 |
+
radio_physical = gr.Radio(["Yes", "No"], value=None, show_label=False, interactive=True)
|
22 |
+
with gr.Row():
|
23 |
+
physical_boxes = create_bird_anatomy(False, "dead")
|
24 |
+
with gr.Column():
|
25 |
+
checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs = process_body_parts("dead", "None")
|
26 |
+
|
27 |
+
gr.Markdown("## Follow-Up Events", label="Title")
|
28 |
+
gr.Markdown("Please tell us what you did with the animal.", label="description")
|
29 |
+
with gr.Row():
|
30 |
+
fe_collection_dropdown, fe_recepient_dropdown, fe_radio_dropdown, fe_answer_dropdown = create_followup_dropdowns(visible, "dead")
|
31 |
+
with gr.Row():
|
32 |
+
fe_name_recipient, fe_collection_ref = create_followup_open(visible, "dead")
|
33 |
+
|
34 |
|
35 |
+
return section_dead, radio_cause, radio_physical,\
|
36 |
+
button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, \
|
37 |
+
dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2, \
|
38 |
+
physical_boxes, \
|
39 |
+
checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs, \
|
40 |
+
fe_collection_dropdown, fe_recepient_dropdown, fe_radio_dropdown, fe_answer_dropdown, fe_name_recipient, fe_collection_ref
|
app/display.py
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import pandas as pd
|
3 |
+
from gradio_modal import Modal
|
4 |
+
from PIL import Image
|
5 |
+
from io import BytesIO
|
6 |
+
import base64
|
7 |
+
|
8 |
+
from validation_submission.submission import validate_save_individual
|
9 |
+
from validation_submission.get_json import get_json_all_individuals
|
10 |
+
|
11 |
+
HEADERS = ["Identifier", "Location", "Wounded", "Dead"]
|
12 |
+
|
13 |
+
|
14 |
+
def save_display_individual(gallery, df, error_box):
|
15 |
+
individual, error_box = validate_save_individual(error_box)
|
16 |
+
if individual:
|
17 |
+
all_animals = get_json_all_individuals()
|
18 |
+
gallery_animals = process_animals_for_gallery(all_animals)
|
19 |
+
gallery = make_gallery(gallery_animals)
|
20 |
+
df_animals = process_animals_for_df(all_animals)
|
21 |
+
df = make_df(df_animals)
|
22 |
+
return gallery, df, error_box
|
23 |
+
|
24 |
+
# ----------------------------------
|
25 |
+
# GALLERY
|
26 |
+
|
27 |
+
def convert_image(image_base64_str):
|
28 |
+
im = Image.open(BytesIO(base64.b64decode(image_base64_str)))
|
29 |
+
return im
|
30 |
+
|
31 |
+
def set_gallery_size(len_animals):
|
32 |
+
if len_animals < 10:
|
33 |
+
num_cols=5
|
34 |
+
num_rows=2
|
35 |
+
else:
|
36 |
+
num_cols = len_animals/2
|
37 |
+
num_rows = len_animals/(num_cols)
|
38 |
+
return num_cols, num_rows
|
39 |
+
|
40 |
+
def process_animals_for_gallery(all_animals):
|
41 |
+
gallery_animals = []
|
42 |
+
for _, animal in all_animals.items():
|
43 |
+
image = convert_image(animal["image"]["image"])
|
44 |
+
caption = animal["identifier"]
|
45 |
+
animal = (image, caption)
|
46 |
+
gallery_animals.append(animal)
|
47 |
+
return gallery_animals
|
48 |
+
|
49 |
+
def make_gallery(gallery_animals):
|
50 |
+
num_cols, num_rows = set_gallery_size(len(gallery_animals))
|
51 |
+
gallery = gr.Gallery(
|
52 |
+
label="Gallery of Records", elem_id="gallery",
|
53 |
+
columns=[num_cols], rows=[num_rows],
|
54 |
+
value=gallery_animals,
|
55 |
+
object_fit="contain", height="auto", interactive=False)
|
56 |
+
return gallery
|
57 |
+
|
58 |
+
def keep_only_values(dict_to_filter):
|
59 |
+
info_text = ""
|
60 |
+
values_to_ignore = ["Yes", "No", "NA"]
|
61 |
+
if dict_to_filter:
|
62 |
+
for key, val in dict_to_filter.items():
|
63 |
+
if type(val) is dict:
|
64 |
+
subset_text = keep_only_values(val)
|
65 |
+
info_text += f"{subset_text}"
|
66 |
+
elif type(val) is list:
|
67 |
+
for item in val:
|
68 |
+
if type(item) is dict:
|
69 |
+
subset_text = keep_only_values(item)
|
70 |
+
info_text += f"{subset_text}"
|
71 |
+
elif (val is not None) and (type(val) is not bool) and (val not in values_to_ignore):
|
72 |
+
info_text += f" {key} : {val} |"
|
73 |
+
else:
|
74 |
+
print("Ignoring value: ", val)
|
75 |
+
print("Associated key: ", key)
|
76 |
+
else:
|
77 |
+
info_text = "NaN"
|
78 |
+
return info_text
|
79 |
+
|
80 |
+
# ----------------------------------
|
81 |
+
# DATAFRAME
|
82 |
+
|
83 |
+
def process_animals_for_df(all_animals):
|
84 |
+
df_animals = {}
|
85 |
+
identifiers =[]
|
86 |
+
geo =[]
|
87 |
+
wounded =[]
|
88 |
+
dead =[]
|
89 |
+
for _, animal in all_animals.items():
|
90 |
+
identifier_value = animal["identifier"]
|
91 |
+
identifiers.append(identifier_value)
|
92 |
+
geo_dict = animal["geolocalisation"]
|
93 |
+
geo_values = keep_only_values(geo_dict)
|
94 |
+
geo.append(geo_values)
|
95 |
+
wounded_dict = animal["wounded"]
|
96 |
+
wounded_values = keep_only_values(wounded_dict)
|
97 |
+
wounded.append(wounded_values)
|
98 |
+
dead_dict = animal["dead"]
|
99 |
+
dead_values = keep_only_values(dead_dict)
|
100 |
+
dead.append(dead_values)
|
101 |
+
df_animals["Identifier"] = identifiers
|
102 |
+
df_animals["Location"] = geo
|
103 |
+
df_animals["Wounded"] = wounded
|
104 |
+
df_animals["Dead"] = dead
|
105 |
+
return df_animals
|
106 |
+
|
107 |
+
|
108 |
+
def make_df(df_animals):
|
109 |
+
df = pd.DataFrame.from_dict(df_animals)
|
110 |
+
styled_df = df.style.set_properties(**{
|
111 |
+
'min-width': '25px',
|
112 |
+
'max-width': '50px', # Adjust width as needed
|
113 |
+
'white-space': 'normal', # Allows text to wrap to the next line
|
114 |
+
'word-wrap': 'break-word' # Breaks long words to fit within the width
|
115 |
+
})
|
116 |
+
df_gradio = gr.DataFrame(visible=True,
|
117 |
+
value=styled_df,
|
118 |
+
headers=HEADERS, interactive=False)
|
119 |
+
return df_gradio
|
120 |
+
|
app/follow_up/class_follow_up.py
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel, Field
|
2 |
+
from typing import Literal, Union, Optional, List
|
3 |
+
|
4 |
+
# --- Event follow-up classes ---
|
5 |
+
|
6 |
+
class AnimalCollectedEvent(BaseModel):
|
7 |
+
type: Literal['animal collected']
|
8 |
+
collected: Literal['yes', 'no']
|
9 |
+
|
10 |
+
class RecipientEvent(BaseModel):
|
11 |
+
type: Literal['recipient']
|
12 |
+
recipient: Literal['veterinary', 'care center',
|
13 |
+
'local museum', 'national museum',
|
14 |
+
'other']
|
15 |
+
|
16 |
+
class RadiographyEvent(BaseModel):
|
17 |
+
type: Literal['radiography']
|
18 |
+
radiography: Literal['yes', 'no', 'unknown']
|
19 |
+
|
20 |
+
class GivenAnswerEvent(BaseModel):
|
21 |
+
type: Literal['given answer']
|
22 |
+
answer: Literal[
|
23 |
+
'nothing',
|
24 |
+
'complaint against x',
|
25 |
+
'complaint',
|
26 |
+
'police call',
|
27 |
+
'discussion with the speaker',
|
28 |
+
'press release',
|
29 |
+
'unknown'
|
30 |
+
]
|
31 |
+
|
32 |
+
class NameOfRecipientEvent(BaseModel):
|
33 |
+
type: Literal['recipient name']
|
34 |
+
name: str
|
35 |
+
|
36 |
+
class CollectionReferenceEvent(BaseModel):
|
37 |
+
type: Literal['collection reference']
|
38 |
+
reference: str
|
39 |
+
|
40 |
+
FollowUpEventType = Union[
|
41 |
+
AnimalCollectedEvent,
|
42 |
+
RecipientEvent,
|
43 |
+
RadiographyEvent,
|
44 |
+
GivenAnswerEvent,
|
45 |
+
NameOfRecipientEvent,
|
46 |
+
CollectionReferenceEvent
|
47 |
+
]
|
48 |
+
|
49 |
+
class FollowUpEvents(BaseModel):
|
50 |
+
follow_up_events: Optional[List[FollowUpEventType]] = None
|
app/follow_up/followup_events.py
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from utils.utils_config import get_custom_config_dropdowns
|
3 |
+
from validation_submission.add_json import add_data_tmp
|
4 |
+
|
5 |
+
def create_followup_dropdowns(visible, elem_id):
|
6 |
+
followup_config = get_custom_config_dropdowns("config_followup.json")
|
7 |
+
followup_config = followup_config["Event follow-up"]
|
8 |
+
fe_collection_dropdown = create_fe_collection_dropdown(followup_config, visible, elem_id)
|
9 |
+
fe_recipient_dropdown = create_fe_recipient_dropdown(followup_config, visible, elem_id)
|
10 |
+
fe_radio_dropdown = create_fe_radio_dropdown(followup_config, visible, elem_id)
|
11 |
+
fe_answer_dropdown = create_fe_answer_dropdown(followup_config, visible, elem_id)
|
12 |
+
return fe_collection_dropdown, fe_recipient_dropdown, fe_radio_dropdown, fe_answer_dropdown
|
13 |
+
|
14 |
+
def create_followup_open(visible, elem_id):
|
15 |
+
fe_name_recipient = gr.Textbox(label="Name of recipient / museum", visible=visible,
|
16 |
+
elem_id=elem_id, interactive=True)
|
17 |
+
fe_collection_ref = gr.Textbox(label="Collection reference", visible=visible,
|
18 |
+
elem_id=elem_id, interactive=True)
|
19 |
+
return fe_name_recipient, fe_collection_ref
|
20 |
+
|
21 |
+
|
22 |
+
def create_fe_collection_dropdown(followup_config, visible, elem_id):
|
23 |
+
fe_collection_dropdown = gr.Dropdown(choices=followup_config["Animal collected"]["Options"], label="Animal collected",
|
24 |
+
visible=visible, elem_id=elem_id, interactive=True)
|
25 |
+
return fe_collection_dropdown
|
26 |
+
|
27 |
+
def create_fe_recipient_dropdown(followup_config, visible, elem_id):
|
28 |
+
fe_recipient_dropdown = gr.Dropdown(choices=followup_config["Recipient"]["Options"], label="Recipient",
|
29 |
+
visible=visible, elem_id=elem_id, interactive=True)
|
30 |
+
return fe_recipient_dropdown
|
31 |
+
|
32 |
+
def create_fe_radio_dropdown(followup_config, visible, elem_id):
|
33 |
+
fe_radio_dropdown = gr.Dropdown(choices=followup_config["Radiography"]["Options"], label="Radiography",
|
34 |
+
visible=visible, elem_id=elem_id, interactive=True)
|
35 |
+
return fe_radio_dropdown
|
36 |
+
|
37 |
+
def create_fe_answer_dropdown(followup_config, visible, elem_id):
|
38 |
+
fe_answer_dropdown = gr.Dropdown(choices=followup_config["Given answer"]["Options"], label="Given answer",
|
39 |
+
visible=visible, elem_id=elem_id, interactive=True)
|
40 |
+
return fe_answer_dropdown
|
41 |
+
|
42 |
+
def save_fe(value, key):
|
43 |
+
add_data_tmp("wounded_dead", "followup " + key.lower(), value.lower())
|
44 |
+
|
45 |
+
|
46 |
+
|
app/followup_events.py
DELETED
@@ -1,17 +0,0 @@
|
|
1 |
-
import gradio as gr
|
2 |
-
from utils_config import get_custom_config_dropdowns
|
3 |
-
|
4 |
-
def create_followup_section():
|
5 |
-
followup_config = get_custom_config_dropdowns("/assets/config/config_followup.json")
|
6 |
-
followup_config = followup_config["Event follow-up"]
|
7 |
-
gr.Markdown("Please tell us what you did with the animal.", label="description")
|
8 |
-
with gr.Row():
|
9 |
-
for key, val in followup_config.items():
|
10 |
-
followup_label = key
|
11 |
-
if "Options" in val.keys():
|
12 |
-
gr.Dropdown(choices=val["Options"], label=followup_label, visible=True, elem_id="followup")
|
13 |
-
with gr.Row():
|
14 |
-
for key, val in followup_config.items():
|
15 |
-
followup_label = key
|
16 |
-
if "Open" in val.keys():
|
17 |
-
gr.Textbox(label=followup_label, visible=True, elem_id="followup")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/geolocalisation/__init__.py
ADDED
File without changes
|
app/geolocalisation/class_geolocalisation.py
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel, Field
|
2 |
+
from typing import Literal, List, Union
|
3 |
+
|
4 |
+
class Longitude(BaseModel):
|
5 |
+
type: Literal['longitude']
|
6 |
+
value: float
|
7 |
+
|
8 |
+
class Latitude(BaseModel):
|
9 |
+
type: Literal['latitude']
|
10 |
+
value: float
|
11 |
+
|
12 |
+
class Geolocalisation(BaseModel):
|
13 |
+
longitude: Longitude
|
14 |
+
latitude: Latitude
|
15 |
+
name: str
|
16 |
+
|
app/{maps.py β geolocalisation/maps.py}
RENAMED
@@ -1,6 +1,24 @@
|
|
1 |
from geopy.geocoders import Nominatim
|
2 |
import gradio as gr
|
3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
def get_location(address):
|
5 |
try:
|
6 |
# calling the Nominatim tool
|
@@ -12,6 +30,11 @@ def get_location(address):
|
|
12 |
# latitude and longitude
|
13 |
lat = getLoc.latitude
|
14 |
lon = getLoc.longitude
|
|
|
|
|
|
|
|
|
|
|
15 |
#display location processing
|
16 |
value = "Latitude = " + str(lat) + "\n" + "Longitude = " + str(lon)
|
17 |
identified_location= gr.Textbox(visible=True, interactive=False,
|
|
|
1 |
from geopy.geocoders import Nominatim
|
2 |
import gradio as gr
|
3 |
+
from validation_submission.add_json import add_data_to_individual
|
4 |
+
from geolocalisation.class_geolocalisation import Geolocalisation
|
5 |
+
|
6 |
+
|
7 |
+
def create_geolocalisation_object(lat, long, name):
|
8 |
+
try:
|
9 |
+
geolocalisation = Geolocalisation(
|
10 |
+
longitude={"type": "longitude", "value": long},
|
11 |
+
latitude={"type": "latitude", "value": lat},
|
12 |
+
name=name
|
13 |
+
)
|
14 |
+
except:
|
15 |
+
print("Pydantic Error for Geolocalisation")
|
16 |
+
return geolocalisation
|
17 |
+
|
18 |
+
def save_geolocalisation_to_json(geolocalisation):
|
19 |
+
geo_dict = geolocalisation.dict()
|
20 |
+
add_data_to_individual("geolocalisation", geo_dict)
|
21 |
+
|
22 |
def get_location(address):
|
23 |
try:
|
24 |
# calling the Nominatim tool
|
|
|
30 |
# latitude and longitude
|
31 |
lat = getLoc.latitude
|
32 |
lon = getLoc.longitude
|
33 |
+
|
34 |
+
# Save values
|
35 |
+
geolocalisation = create_geolocalisation_object(lat, lon, address)
|
36 |
+
save_geolocalisation_to_json(geolocalisation)
|
37 |
+
|
38 |
#display location processing
|
39 |
value = "Latitude = " + str(lat) + "\n" + "Longitude = " + str(lon)
|
40 |
identified_location= gr.Textbox(visible=True, interactive=False,
|
app/gradio_test/test_selectdata_event.py
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
with gr.Blocks() as demo:
|
4 |
+
table = gr.Dataframe([[1, 2, 3], [4, 5, 6]])
|
5 |
+
#gallery = gr.Gallery([("cat.jpg", "Cat"), ("dog.jpg", "Dog")])
|
6 |
+
textbox = gr.Textbox("Hello World!")
|
7 |
+
statement = gr.Textbox()
|
8 |
+
|
9 |
+
def on_select(evt: gr.SelectData):
|
10 |
+
return gr.Textbox(f"You selected {evt.value} at {evt.index} from {evt.target}")
|
11 |
+
|
12 |
+
table.select(on_select, inputs=[table], outputs=[statement])
|
13 |
+
#gallery.select(on_select, gallery, statement)
|
14 |
+
textbox.select(on_select, inputs=[textbox], outputs=[statement])
|
15 |
+
|
16 |
+
demo.launch(server_name="0.0.0.0", server_port=3131)
|
app/gradio_test/tests_delete_gallery.py
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
# Example initial image list
|
4 |
+
images = [
|
5 |
+
"https://via.placeholder.com/150/0000FF",
|
6 |
+
"https://via.placeholder.com/150/FF0000",
|
7 |
+
"https://via.placeholder.com/150/00FF00"
|
8 |
+
]
|
9 |
+
|
10 |
+
# Function to remove a selected image from the gallery
|
11 |
+
def delete_image(selected_image, image_list):
|
12 |
+
if selected_image in image_list:
|
13 |
+
image_list.remove(selected_image) # Remove the selected image
|
14 |
+
return image_list # Return the updated image list
|
15 |
+
|
16 |
+
# Gradio app
|
17 |
+
with gr.Blocks() as demo:
|
18 |
+
gallery = gr.Gallery(value=images, label="Gallery") # Gallery of images
|
19 |
+
selected_image = gr.Dropdown(choices=images, label="Select Image to Delete") # Dropdown for selection
|
20 |
+
delete_button = gr.Button("Delete Selected Image") # Button to delete
|
21 |
+
|
22 |
+
# When button is clicked, delete the selected image and update gallery
|
23 |
+
delete_button.click(fn=delete_image, inputs=[selected_image, gallery], outputs=gallery)
|
24 |
+
|
25 |
+
demo.launch(server_name="0.0.0.0", server_port=3232)
|
app/main.py
CHANGED
@@ -1,164 +1,337 @@
|
|
1 |
import gradio as gr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
from functools import partial
|
3 |
from dead import show_section_dead
|
4 |
from wounded import show_section_wounded
|
5 |
-
from circumstances import
|
6 |
-
from circumstances_dropdowns import *
|
7 |
-
from physical_select_animal import show_physical, find_bounding_box
|
8 |
-
from
|
9 |
-
from
|
10 |
-
from
|
11 |
-
from
|
12 |
-
|
13 |
-
|
|
|
|
|
|
|
14 |
# ---------------------------------------------------------
|
15 |
# Intro Text
|
16 |
with gr.Row():
|
17 |
with gr.Column(scale=1):
|
18 |
title = gr.Markdown("# Welcome to Digiwild", label="Title")
|
19 |
description = gr.Markdown("Please record your wildlife observations here !", label="description")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
# Location
|
29 |
-
#with gr.Row():
|
30 |
-
with gr.Column(scale=1):
|
31 |
-
location = gr.Textbox(visible=True, interactive=True, label="Location of Sighting")
|
32 |
-
#display location processing
|
33 |
-
identified_location= gr.Textbox(visible=False, interactive=False,
|
34 |
-
label="Identified GPS Location")
|
35 |
-
with gr.Row():
|
36 |
-
#to clear it
|
37 |
-
clear_location = gr.ClearButton(components=[location], visible=True, interactive=True, scale=1
|
38 |
-
)
|
39 |
-
clear_location.click()
|
40 |
-
#to submit it
|
41 |
-
submit_location = gr.Button("Get GPS Coordinates", visible=True, interactive=True, scale=3)
|
42 |
-
submit_location.click(get_location, inputs=[location], outputs=[identified_location])
|
43 |
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
with gr.Column(scale=1):
|
50 |
-
butt_wounded = gr.Button("Wounded", elem_id="wounded")
|
51 |
-
with gr.Column(scale=1):
|
52 |
-
butt_dead = gr.Button("Dead", elem_id="dead")
|
53 |
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded,
|
99 |
dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded,
|
100 |
behavior_checkbox, behavior_text,
|
101 |
-
physical_boxes_wounded,
|
102 |
-
|
|
|
|
|
103 |
])
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
# Dropdowns Dead
|
110 |
-
button_collision_dead.click(dropdown_collision,
|
111 |
-
outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead])
|
112 |
-
button_deliberate_destruction_dead.click(dropdown_deliberate_destruction, outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead])
|
113 |
-
button_indirect_destruction_dead.click(dropdown_indirect_destruction, outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead])
|
114 |
-
button_natural_cause_dead.click(dropdown_natural_cause, outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead])
|
115 |
|
116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
button_collision_wounded.click(dropdown_collision,
|
128 |
-
outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded])
|
129 |
-
button_deliberate_destruction_wounded.click(dropdown_deliberate_destruction, outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded])
|
130 |
-
button_indirect_destruction_wounded.click(dropdown_indirect_destruction, outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded])
|
131 |
-
button_natural_cause_wounded.click(dropdown_natural_cause, outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded])
|
132 |
-
|
133 |
-
dropdown_wounded.select(on_select, None, [dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded])
|
134 |
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
|
153 |
# ---------------------------------------------------------
|
154 |
-
#
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
scale=1)
|
160 |
-
output_message = gr.Markdown("Thank you, you are a champion of biodiversity conservation !")
|
161 |
|
162 |
-
|
163 |
|
164 |
-
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
+
from gradio_modal import Modal
|
3 |
+
|
4 |
+
from validation_submission.create_json import create_json_all_individuals, create_json_one_individual, create_tmp, reset_json
|
5 |
+
from validation_submission.add_json import add_data_to_individual
|
6 |
+
from validation_submission.validation import reset_error_box
|
7 |
+
from display import save_display_individual
|
8 |
+
from geolocalisation.maps import get_location
|
9 |
from functools import partial
|
10 |
from dead import show_section_dead
|
11 |
from wounded import show_section_wounded
|
12 |
+
from circumstances.circumstances import show_circumstances
|
13 |
+
from circumstances.circumstances_dropdowns import *
|
14 |
+
from physical.physical_select_animal import show_physical, find_bounding_box
|
15 |
+
from physical.physical_checkbox import on_select_body_part, hide_physical
|
16 |
+
from behavior.behavior_checkbox import show_behavior, on_select_behavior
|
17 |
+
from follow_up.followup_events import save_fe
|
18 |
+
from styling.style import *
|
19 |
+
from styling.theme import css
|
20 |
+
|
21 |
+
# with gr.Blocks(theme=theme, css=css) as demo:
|
22 |
+
with gr.Blocks(css=css) as demo:
|
23 |
+
create_json_all_individuals()
|
24 |
# ---------------------------------------------------------
|
25 |
# Intro Text
|
26 |
with gr.Row():
|
27 |
with gr.Column(scale=1):
|
28 |
title = gr.Markdown("# Welcome to Digiwild", label="Title")
|
29 |
description = gr.Markdown("Please record your wildlife observations here !", label="description")
|
30 |
+
with gr.Row():
|
31 |
+
show_modal = gr.Button("Add an Animal", scale=3)
|
32 |
+
submit_button = gr.Button("Submit All Animals", scale=1)
|
33 |
+
df = gr.Dataframe(headers=["Identifier", "Location", "Wounded", "Dead"], visible=False, interactive=False)
|
34 |
+
gallery = gr.Gallery(
|
35 |
+
label="Gallery of Records", elem_id="gallery",
|
36 |
+
columns=[1], rows=[1],
|
37 |
+
object_fit="contain", height="auto", interactive=False)
|
38 |
|
39 |
+
with Modal(visible=False) as modal:
|
40 |
+
# ---------------------------------------------------------
|
41 |
+
# Intro Text
|
42 |
+
with gr.Row():
|
43 |
+
with gr.Column(scale=1):
|
44 |
+
title = gr.Markdown("# Animal Report", label="Title")
|
45 |
+
description = gr.Markdown("Please record your observation here.", label="description")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
|
47 |
+
# ---------------------------------------------------------
|
48 |
+
# Camera
|
49 |
+
with gr.Row():
|
50 |
+
def save_image(camera):
|
51 |
+
add_data_to_individual("image", camera.tolist())
|
|
|
|
|
|
|
|
|
52 |
|
53 |
+
camera = gr.Image(elem_id="image")
|
54 |
+
camera.input(save_image, inputs=[camera])
|
55 |
+
# ---------------------------------------------------------
|
56 |
+
# Location
|
57 |
+
#with gr.Row():
|
58 |
+
with gr.Column(scale=1):
|
59 |
+
location = gr.Textbox(visible=True, interactive=True, label="Location of Sighting")
|
60 |
+
#display location processing
|
61 |
+
identified_location= gr.Textbox(visible=False, interactive=False,
|
62 |
+
label="Identified GPS Location")
|
63 |
+
with gr.Row():
|
64 |
+
#to submit it
|
65 |
+
submit_location = gr.Button("Get GPS Coordinates",
|
66 |
+
visible=True, interactive=True, scale=3)
|
67 |
+
submit_location.click(get_location, inputs=[location], outputs=[identified_location])
|
68 |
+
#to clear it
|
69 |
+
clear_location = gr.ClearButton(components=[location, identified_location],
|
70 |
+
visible=True, interactive=True, scale=1
|
71 |
+
)
|
72 |
+
clear_location.click()
|
73 |
+
|
74 |
+
# ---------------------------------------------------------
|
75 |
+
# ---------------------------------------------------------
|
76 |
+
# Dead and Wounded Buttons
|
77 |
+
gr.Markdown("## The State of the Animal", label="Title")
|
78 |
+
gr.Markdown("Please tell us if the animal was wounded or dead.", label="description")
|
79 |
+
with gr.Row() as block_form:
|
80 |
+
with gr.Column(scale=1):
|
81 |
+
butt_wounded = gr.Button("Wounded", elem_id="wounded")
|
82 |
+
with gr.Column(scale=1):
|
83 |
+
butt_dead = gr.Button("Dead", elem_id="dead")
|
84 |
|
85 |
+
# ---------------------------------------------------------
|
86 |
+
# Initiate sections
|
87 |
+
section_dead, radio_circumstance_dead, radio_physical_dead,\
|
88 |
+
button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead, \
|
89 |
+
dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, \
|
90 |
+
physical_boxes_dead, \
|
91 |
+
checkbox_beak_dead, text_beak_dead, checkbox_body_dead, text_body_dead, checkbox_feathers_dead, text_feathers_dead, checkbox_head_dead, text_head_dead, checkbox_legs_dead, text_legs_dead, \
|
92 |
+
fe_collection_dropdown_dead, fe_recepient_dropdown_dead, fe_radio_dropdown_dead, fe_answer_dropdown_dead, \
|
93 |
+
fe_name_recipient_dead, fe_collection_ref_dead \
|
94 |
+
= show_section_dead(False)
|
95 |
+
section_wounded, radio_circumstance_wounded, radio_behavior_wounded, radio_physical_wounded, \
|
96 |
+
button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded, \
|
97 |
+
dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, \
|
98 |
+
behavior_checkbox, behavior_text, \
|
99 |
+
physical_boxes_wounded, \
|
100 |
+
checkbox_beak_wounded, text_beak_wounded, checkbox_body_wounded, text_body_wounded, checkbox_feathers_wounded, text_feathers_wounded, checkbox_head_wounded, text_head_wounded, checkbox_legs_wounded, text_legs_wounded, \
|
101 |
+
fe_collection_dropdown_wounded, fe_recepient_dropdown_wounded, fe_radio_dropdown_wounded, fe_answer_dropdown_wounded, \
|
102 |
+
fe_name_recipient_wounded, fe_collection_ref_wounded \
|
103 |
+
= show_section_wounded(False)
|
104 |
+
|
105 |
+
# ---------------------------------------------------------
|
106 |
+
# ---------------------------------------------------------
|
107 |
+
# ---------------------------------------------------------
|
108 |
+
# Dead Button Logic
|
109 |
+
partial_show_section_dead = partial(show_section_dead, True)
|
110 |
+
partial_hide_section_wounded = partial(show_section_wounded, False)
|
111 |
+
butt_dead.click(partial_show_section_dead,
|
112 |
+
inputs=None,
|
113 |
+
outputs=[section_dead,
|
114 |
+
radio_circumstance_dead, radio_physical_dead,
|
115 |
+
button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead,
|
116 |
+
dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, \
|
117 |
+
physical_boxes_dead, \
|
118 |
+
checkbox_beak_dead, text_beak_dead, checkbox_body_dead, text_body_dead, checkbox_feathers_dead, text_feathers_dead, checkbox_head_dead, text_head_dead, checkbox_legs_dead, text_legs_dead, \
|
119 |
+
fe_collection_dropdown_dead, fe_recepient_dropdown_dead, fe_radio_dropdown_dead, fe_answer_dropdown_dead, \
|
120 |
+
fe_name_recipient_dead, fe_collection_ref_dead \
|
121 |
+
])
|
122 |
+
butt_dead.click(partial_hide_section_wounded,
|
123 |
+
inputs=None,
|
124 |
+
outputs=[section_wounded,
|
125 |
+
radio_circumstance_wounded, radio_behavior_wounded, radio_physical_wounded,
|
126 |
button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded,
|
127 |
dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded,
|
128 |
behavior_checkbox, behavior_text,
|
129 |
+
physical_boxes_wounded, \
|
130 |
+
checkbox_beak_wounded, text_beak_wounded, checkbox_body_wounded, text_body_wounded, checkbox_feathers_wounded, text_feathers_wounded, checkbox_head_wounded, text_head_wounded, checkbox_legs_wounded, text_legs_wounded, \
|
131 |
+
fe_collection_dropdown_wounded, fe_recepient_dropdown_wounded, fe_radio_dropdown_wounded, fe_answer_dropdown_wounded, \
|
132 |
+
fe_name_recipient_wounded, fe_collection_ref_wounded \
|
133 |
])
|
134 |
+
|
135 |
+
# ---------------------------------------------------------
|
136 |
+
# Wounded Button Logic
|
137 |
+
partial_show_section_wounded = partial(show_section_wounded, True)
|
138 |
+
partial_hide_section_dead = partial(show_section_dead, False)
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
|
140 |
+
butt_wounded.click(partial_show_section_wounded,
|
141 |
+
inputs=None,
|
142 |
+
outputs=[section_wounded,
|
143 |
+
radio_circumstance_wounded, radio_behavior_wounded, radio_physical_wounded,
|
144 |
+
button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded,
|
145 |
+
dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded,
|
146 |
+
behavior_checkbox, behavior_text,
|
147 |
+
physical_boxes_wounded, \
|
148 |
+
checkbox_beak_wounded, text_beak_wounded, checkbox_body_wounded, text_body_wounded, checkbox_feathers_wounded, text_feathers_wounded, checkbox_head_wounded, text_head_wounded, checkbox_legs_wounded, text_legs_wounded, \
|
149 |
+
fe_collection_dropdown_wounded, fe_recepient_dropdown_wounded, fe_radio_dropdown_wounded, fe_answer_dropdown_wounded, \
|
150 |
+
fe_name_recipient_wounded, fe_collection_ref_wounded \
|
151 |
+
])
|
152 |
+
butt_wounded.click(partial_hide_section_dead, inputs=None, outputs=[section_dead,
|
153 |
+
radio_circumstance_dead, radio_physical_dead,
|
154 |
+
button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead,
|
155 |
+
dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, \
|
156 |
+
physical_boxes_dead, \
|
157 |
+
checkbox_beak_dead, text_beak_dead, checkbox_body_dead, text_body_dead, checkbox_feathers_dead, text_feathers_dead, checkbox_head_dead, text_head_dead, checkbox_legs_dead, text_legs_dead, \
|
158 |
+
fe_collection_dropdown_dead, fe_recepient_dropdown_dead, fe_radio_dropdown_dead, fe_answer_dropdown_dead, \
|
159 |
+
fe_name_recipient_dead, fe_collection_ref_dead \
|
160 |
+
])
|
161 |
+
# ---------------------------------------------------------
|
162 |
+
# ---------------------------------------------------------
|
163 |
+
# ---------------------------------------------------------
|
164 |
+
# ---------------------------------------------------------
|
165 |
+
# DEAD
|
166 |
+
# ---------------------------------------------------------
|
167 |
+
# Radio Circumstance Dead
|
168 |
+
radio_circumstance_dead.change(fn=show_circumstances,
|
169 |
+
inputs=[radio_circumstance_dead],
|
170 |
+
outputs=[button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead,
|
171 |
+
dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead]
|
172 |
+
)
|
173 |
+
|
174 |
+
# Dropdowns Dead
|
175 |
+
button_collision_dead.click(dropdown_collision,
|
176 |
+
outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead])
|
177 |
+
button_deliberate_destruction_dead.click(dropdown_deliberate_destruction, outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead])
|
178 |
+
button_indirect_destruction_dead.click(dropdown_indirect_destruction, outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead])
|
179 |
+
button_natural_cause_dead.click(dropdown_natural_cause, outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead])
|
180 |
|
181 |
+
dropdown_dead.select(on_select, None, [dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead])
|
182 |
+
dropdown_level2_dead.select(on_select_dropdown_level2)
|
183 |
+
openfield_level2_dead.change(on_change_openfield_level2, inputs=[openfield_level2_dead])
|
184 |
+
dropdown_extra_level2_dead.select(on_select_dropdown_extra_level2)
|
185 |
+
# ---------------------------------------------------------
|
186 |
+
# Radio Physical Dead
|
187 |
+
radio_physical_dead.change(fn=show_physical,
|
188 |
+
inputs=[radio_physical_dead, gr.Text("dead", visible=False)],
|
189 |
+
outputs=[physical_boxes_dead])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
|
191 |
+
# Checkbox Physical Dead
|
192 |
+
physical_boxes_dead.select(find_bounding_box,
|
193 |
+
inputs=[physical_boxes_dead, gr.Textbox(value="dead", visible=False)],
|
194 |
+
outputs=[checkbox_beak_dead, text_beak_dead,
|
195 |
+
checkbox_body_dead, text_body_dead,
|
196 |
+
checkbox_feathers_dead, text_feathers_dead,
|
197 |
+
checkbox_head_dead, text_head_dead,
|
198 |
+
checkbox_legs_dead, text_legs_dead
|
199 |
+
])
|
200 |
+
checkbox_beak_dead.select(on_select_body_part, inputs=[checkbox_beak_dead, gr.Text("beak", visible=False)])
|
201 |
+
checkbox_body_dead.select(on_select_body_part, inputs=[checkbox_body_dead, gr.Text("body", visible=False)])
|
202 |
+
checkbox_feathers_dead.select(on_select_body_part, inputs=[checkbox_feathers_dead, gr.Text("feathers", visible=False)])
|
203 |
+
checkbox_head_dead.select(on_select_body_part, inputs=[checkbox_head_dead, gr.Text("head", visible=False)])
|
204 |
+
checkbox_legs_dead.select(on_select_body_part, inputs=[checkbox_legs_dead, gr.Text("legs", visible=False)])
|
205 |
+
# ---------------------------------------------------------
|
206 |
+
# ---------------------------------------------------------
|
207 |
+
# ---------------------------------------------------------
|
208 |
+
# ---------------------------------------------------------
|
209 |
+
# WOUNDED
|
210 |
+
# ---------------------------------------------------------
|
211 |
+
# Radio Circumstance Wounded
|
212 |
+
radio_circumstance_wounded.change(fn=show_circumstances,
|
213 |
+
inputs=[radio_circumstance_wounded],
|
214 |
+
outputs=[button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded,
|
215 |
+
dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded]
|
216 |
+
)
|
217 |
+
|
218 |
+
# Dropdowns Circumstance Wounded
|
219 |
+
button_collision_wounded.click(dropdown_collision,
|
220 |
+
outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded])
|
221 |
+
button_deliberate_destruction_wounded.click(dropdown_deliberate_destruction, outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded])
|
222 |
+
button_indirect_destruction_wounded.click(dropdown_indirect_destruction, outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded])
|
223 |
+
button_natural_cause_wounded.click(dropdown_natural_cause, outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded])
|
224 |
+
|
225 |
+
dropdown_wounded.select(on_select, None, [dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded])
|
226 |
+
dropdown_level2_wounded.select(on_select_dropdown_level2)
|
227 |
+
openfield_level2_wounded.change(on_change_openfield_level2, inputs=[openfield_level2_wounded])
|
228 |
+
dropdown_extra_level2_wounded.select(on_select_dropdown_extra_level2)
|
229 |
+
# ---------------------------------------------------------
|
230 |
+
# Radio Behavior Wounded
|
231 |
+
radio_behavior_wounded.change(fn=show_behavior,
|
232 |
+
inputs=[radio_behavior_wounded, gr.Text("wounded", visible=False)],
|
233 |
+
outputs=[behavior_checkbox, behavior_text])
|
234 |
+
behavior_checkbox.select(on_select_behavior,
|
235 |
+
inputs=[behavior_checkbox])
|
236 |
+
# ---------------------------------------------------------
|
237 |
+
# Radio Physical Wounded
|
238 |
+
radio_physical_wounded.change(fn=show_physical,
|
239 |
+
inputs=[radio_physical_wounded, gr.Text("wounded", visible=False)],
|
240 |
+
outputs=[physical_boxes_wounded])
|
241 |
|
242 |
+
# Checkbox Physical Wounded
|
243 |
+
physical_boxes_wounded.select(find_bounding_box,
|
244 |
+
inputs=[physical_boxes_wounded, gr.Textbox(value="wounded", visible=False)],
|
245 |
+
outputs=[checkbox_beak_wounded, text_beak_wounded,
|
246 |
+
checkbox_body_wounded, text_body_wounded,
|
247 |
+
checkbox_feathers_wounded, text_feathers_wounded,
|
248 |
+
checkbox_head_wounded, text_head_wounded,
|
249 |
+
checkbox_legs_wounded, text_legs_wounded
|
250 |
+
])
|
251 |
+
checkbox_beak_wounded.select(on_select_body_part, inputs=[checkbox_beak_wounded, gr.Text("beak", visible=False)])
|
252 |
+
checkbox_body_wounded.select(on_select_body_part, inputs=[checkbox_body_wounded, gr.Text("body", visible=False)])
|
253 |
+
checkbox_feathers_wounded.select(on_select_body_part, inputs=[checkbox_feathers_wounded, gr.Text("feathers", visible=False)])
|
254 |
+
checkbox_head_wounded.select(on_select_body_part, inputs=[checkbox_head_wounded, gr.Text("head", visible=False)])
|
255 |
+
checkbox_legs_wounded.select(on_select_body_part, inputs=[checkbox_legs_wounded, gr.Text("legs", visible=False)])
|
256 |
+
|
257 |
+
# ---------------------------------------------------------
|
258 |
+
# Follow Up Events Wounded
|
259 |
+
fe_collection_dropdown_wounded.select(save_fe, inputs=[fe_collection_dropdown_wounded, gr.Textbox("animal collected", visible=False)])
|
260 |
+
fe_recepient_dropdown_wounded.select(save_fe, inputs=[fe_recepient_dropdown_wounded, gr.Textbox("recipient", visible=False)])
|
261 |
+
fe_radio_dropdown_wounded.select(save_fe, inputs=[fe_radio_dropdown_wounded, gr.Textbox("radiography", visible=False)])
|
262 |
+
fe_answer_dropdown_wounded.select(save_fe, inputs=[fe_answer_dropdown_wounded, gr.Textbox("given answer", visible=False)])
|
263 |
+
fe_name_recipient_wounded.input(save_fe, inputs=[fe_name_recipient_wounded, gr.Textbox("recipient name", visible=False)])
|
264 |
+
fe_collection_ref_wounded.input(save_fe, inputs=[fe_collection_ref_wounded, gr.Textbox("collection reference", visible=False)])
|
265 |
+
|
266 |
+
# ---------------------------------------------------------
|
267 |
+
# Follow Up Events Dead
|
268 |
+
fe_collection_dropdown_dead.select(save_fe, inputs=[fe_collection_dropdown_dead, gr.Textbox("animal collected", visible=False)])
|
269 |
+
fe_recepient_dropdown_dead.select(save_fe, inputs=[fe_recepient_dropdown_dead, gr.Textbox("recipient", visible=False)])
|
270 |
+
fe_radio_dropdown_dead.select(save_fe, inputs=[fe_radio_dropdown_dead, gr.Textbox("radiography", visible=False)])
|
271 |
+
fe_answer_dropdown_dead.select(save_fe, inputs=[fe_answer_dropdown_dead, gr.Textbox("given answer", visible=False)])
|
272 |
+
fe_name_recipient_dead.input(save_fe, inputs=[fe_name_recipient_dead, gr.Textbox("recipient name", visible=False)])
|
273 |
+
fe_collection_ref_dead.input(save_fe, inputs=[fe_collection_ref_dead, gr.Textbox("collection reference", visible=False)])
|
274 |
+
|
275 |
+
# ---------------------------------------------------------
|
276 |
+
# Error Box
|
277 |
+
error_box = gr.Text(value=None, visible=False)
|
278 |
+
|
279 |
+
# ---------------------------------------------------------
|
280 |
+
# Add One Individual's Data to the Dataframe
|
281 |
+
# And Allow clearing of all previous output
|
282 |
+
with gr.Row():
|
283 |
+
button_df = gr.Button("Submit Animal Report", scale = 3)
|
284 |
+
button_clear = gr.ClearButton(scale = 1,
|
285 |
+
components=[
|
286 |
+
camera,
|
287 |
+
location, identified_location,
|
288 |
+
#dead reset
|
289 |
+
radio_circumstance_dead, radio_physical_dead,
|
290 |
+
button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead,
|
291 |
+
dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead,
|
292 |
+
physical_boxes_dead,
|
293 |
+
checkbox_beak_dead, text_beak_dead, checkbox_body_dead, text_body_dead, checkbox_feathers_dead, text_feathers_dead, checkbox_head_dead, text_head_dead, checkbox_legs_dead, text_legs_dead,
|
294 |
+
fe_collection_dropdown_dead, fe_recepient_dropdown_dead, fe_radio_dropdown_dead, fe_answer_dropdown_dead,
|
295 |
+
fe_name_recipient_dead, fe_collection_ref_dead,
|
296 |
+
#wounded reset
|
297 |
+
radio_circumstance_wounded, radio_behavior_wounded, radio_physical_wounded,
|
298 |
+
button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded,
|
299 |
+
dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded,
|
300 |
+
behavior_checkbox, behavior_text,
|
301 |
+
physical_boxes_wounded,
|
302 |
+
checkbox_beak_wounded, text_beak_wounded, checkbox_body_wounded, text_body_wounded, checkbox_feathers_wounded, text_feathers_wounded, checkbox_head_wounded, text_head_wounded, checkbox_legs_wounded, text_legs_wounded,
|
303 |
+
fe_collection_dropdown_wounded, fe_recepient_dropdown_wounded, fe_radio_dropdown_wounded, fe_answer_dropdown_wounded,
|
304 |
+
fe_name_recipient_wounded, fe_collection_ref_wounded,
|
305 |
+
error_box
|
306 |
+
])
|
307 |
+
button_close = gr.Button("Back to Display", scale = 1)
|
308 |
+
|
309 |
+
|
310 |
+
# ---------------------------------------------------------
|
311 |
+
# Button Click Logic
|
312 |
+
button_clear.click()
|
313 |
+
button_clear.click(hide_physical,
|
314 |
+
outputs=[checkbox_beak_wounded, text_beak_wounded, checkbox_body_wounded, text_body_wounded, checkbox_feathers_wounded, text_feathers_wounded, checkbox_head_wounded, text_head_wounded, checkbox_legs_wounded, text_legs_wounded])
|
315 |
+
button_clear.click(hide_physical,
|
316 |
+
outputs=[checkbox_beak_dead, text_beak_dead, checkbox_body_dead, text_body_dead, checkbox_feathers_dead, text_feathers_dead, checkbox_head_dead, text_head_dead, checkbox_legs_dead, text_legs_dead])
|
317 |
+
|
318 |
+
button_clear.click(reset_error_box, inputs=[error_box], outputs=[error_box])
|
319 |
+
button_clear.click(reset_json)
|
320 |
+
|
321 |
+
button_df.click(save_display_individual,
|
322 |
+
inputs=[gallery, df, error_box],
|
323 |
+
outputs=[gallery, df, error_box]
|
324 |
+
)
|
325 |
+
button_close.click(lambda: Modal(visible=False), None, modal)
|
326 |
|
327 |
# ---------------------------------------------------------
|
328 |
+
# Event Functions of the landing page buttons
|
329 |
+
show_modal.click(lambda: Modal(visible=True), None, modal)
|
330 |
+
show_modal.click(create_json_one_individual)
|
331 |
+
show_modal.click(create_tmp)
|
332 |
+
#submit_button.click(save_and_rest_df, inputs=[df], outputs=[df])
|
|
|
|
|
333 |
|
|
|
334 |
|
335 |
+
|
336 |
+
if __name__ == "__main__":
|
337 |
+
demo.launch(server_name="0.0.0.0", server_port=3333)
|
app/main_test.py
DELETED
@@ -1,68 +0,0 @@
|
|
1 |
-
import gradio as gr
|
2 |
-
|
3 |
-
# Function that processes the Textbox input and generates new CheckboxGroups
|
4 |
-
def generate_checkbox_groups(textbox_input):
|
5 |
-
try:
|
6 |
-
num_groups = int(textbox_input)
|
7 |
-
except ValueError:
|
8 |
-
return "Please enter a valid number."
|
9 |
-
|
10 |
-
# Dynamically create a list of CheckboxGroups
|
11 |
-
checkbox_groups = []
|
12 |
-
for i in range(num_groups):
|
13 |
-
checkbox_groups.append(gr.CheckboxGroup(
|
14 |
-
choices=["Option 1", "Option 2", "Option 3"],
|
15 |
-
label=f"Checkbox Group {i + 1}",
|
16 |
-
interactive=True
|
17 |
-
))
|
18 |
-
|
19 |
-
return checkbox_groups
|
20 |
-
|
21 |
-
# Function to process the selections of the dynamically created CheckboxGroups
|
22 |
-
def process_selections(*checkbox_values):
|
23 |
-
results = []
|
24 |
-
for i, selections in enumerate(checkbox_values):
|
25 |
-
selected_options = ', '.join(selections) if selections else 'None'
|
26 |
-
results.append(f"Selected options for group {i + 1}: {selected_options}")
|
27 |
-
|
28 |
-
return "\n".join(results)
|
29 |
-
|
30 |
-
with gr.Blocks() as demo:
|
31 |
-
# Textbox for user input to specify the number of CheckboxGroups
|
32 |
-
textbox = gr.Textbox(label="Enter the number of Checkbox Groups to create")
|
33 |
-
|
34 |
-
# Button to trigger the generation of CheckboxGroups
|
35 |
-
generate_button = gr.Button("Generate Checkbox Groups")
|
36 |
-
|
37 |
-
# A placeholder for the dynamically generated CheckboxGroups
|
38 |
-
dynamic_checkbox_groups = gr.Column()
|
39 |
-
|
40 |
-
# Output Textbox to display the results
|
41 |
-
output = gr.Textbox(label="Output")
|
42 |
-
|
43 |
-
# Generate CheckboxGroups based on Textbox input
|
44 |
-
def update_dynamic_groups(textbox_value):
|
45 |
-
groups = generate_checkbox_groups(textbox_value)
|
46 |
-
dynamic_checkbox_groups.children = groups
|
47 |
-
return dynamic_checkbox_groups
|
48 |
-
|
49 |
-
generate_button.click(
|
50 |
-
fn=update_dynamic_groups,
|
51 |
-
inputs=textbox,
|
52 |
-
outputs=dynamic_checkbox_groups
|
53 |
-
)
|
54 |
-
|
55 |
-
# Button to process selections from the dynamically generated CheckboxGroups
|
56 |
-
process_button = gr.Button("Submit Selections")
|
57 |
-
|
58 |
-
# Process the selections when the second button is clicked
|
59 |
-
def process_dynamic_groups(*checkbox_groups):
|
60 |
-
return process_selections(*checkbox_groups)
|
61 |
-
|
62 |
-
process_button.click(
|
63 |
-
fn=process_dynamic_groups,
|
64 |
-
inputs=dynamic_checkbox_groups.children, # Unpack the dynamically generated groups
|
65 |
-
outputs=output
|
66 |
-
)
|
67 |
-
|
68 |
-
demo.launch(server_name="0.0.0.0")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/physical/__init__.py
ADDED
File without changes
|
app/physical/class_physical.py
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel, Field
|
2 |
+
from typing import Literal, List, Union, Optional
|
3 |
+
|
4 |
+
# Define common anomalies as a Literal type
|
5 |
+
CommonAnomalies = Literal[
|
6 |
+
'blackened/burnt skin',
|
7 |
+
'blood',
|
8 |
+
'foreign body',
|
9 |
+
'fracture',
|
10 |
+
'injury',
|
11 |
+
'parasite',
|
12 |
+
'swelling',
|
13 |
+
'warty or tumor-like growth, crusts'
|
14 |
+
]
|
15 |
+
|
16 |
+
# --- Beak-related Anomalies ---
|
17 |
+
class BeakAnomaly(BaseModel):
|
18 |
+
type: Literal['beak']
|
19 |
+
anomaly_type: List[Literal[
|
20 |
+
'adhesion',
|
21 |
+
'deformation',
|
22 |
+
CommonAnomalies
|
23 |
+
]]
|
24 |
+
|
25 |
+
# --- Body-related Anomalies ---
|
26 |
+
class BodyAnomaly(BaseModel):
|
27 |
+
type: Literal['body']
|
28 |
+
anomaly_type: List[Literal[
|
29 |
+
'emaciation',
|
30 |
+
'fluffed up',
|
31 |
+
'stained feathers',
|
32 |
+
CommonAnomalies
|
33 |
+
]]
|
34 |
+
|
35 |
+
# --- Legs-related Anomalies ---
|
36 |
+
class LegAnomaly(BaseModel):
|
37 |
+
type: Literal['legs']
|
38 |
+
anomaly_type: List[Literal[
|
39 |
+
'missing limb',
|
40 |
+
'deformation',
|
41 |
+
CommonAnomalies
|
42 |
+
]]
|
43 |
+
|
44 |
+
# --- Feathers/Wings/Tail-related Anomalies ---
|
45 |
+
class FeathersWingsTailAnomaly(BaseModel):
|
46 |
+
type: Literal['feathers/wings/tail']
|
47 |
+
anomaly_type: List[Literal[
|
48 |
+
'fluffed up',
|
49 |
+
'feather abnormalities',
|
50 |
+
'stained feathers',
|
51 |
+
'abnormal wing posture',
|
52 |
+
'missing limb',
|
53 |
+
CommonAnomalies
|
54 |
+
]]
|
55 |
+
|
56 |
+
# --- Head-related Anomalies (including eyes) ---
|
57 |
+
class HeadAnomaly(BaseModel):
|
58 |
+
type: Literal['head incl. eyes']
|
59 |
+
anomaly_type: List[Literal[
|
60 |
+
'ear changes',
|
61 |
+
'eye changes',
|
62 |
+
'tilted head',
|
63 |
+
CommonAnomalies
|
64 |
+
]]
|
65 |
+
|
66 |
+
|
67 |
+
# Union of all possible anomaly types for specific body parts
|
68 |
+
AnomalyType = Union[
|
69 |
+
BeakAnomaly,
|
70 |
+
BodyAnomaly,
|
71 |
+
LegAnomaly,
|
72 |
+
FeathersWingsTailAnomaly,
|
73 |
+
HeadAnomaly
|
74 |
+
]
|
75 |
+
|
76 |
+
# Main PhysicalAnomaly class that logs anomalies across different body parts
|
77 |
+
class PhysicalAnomalies(BaseModel):
|
78 |
+
physical_radio: str
|
79 |
+
physical_anomalies_type: Optional[List[AnomalyType]] = None
|
app/{physical_boxes_define.py β physical/physical_boxes_define.py}
RENAMED
File without changes
|
app/{physical_boxes_map.py β physical/physical_boxes_map.py}
RENAMED
@@ -2,6 +2,11 @@ from PIL import Image, ImageDraw, ImageFont
|
|
2 |
|
3 |
from physical_boxes_define import gdf
|
4 |
|
|
|
|
|
|
|
|
|
|
|
5 |
# Function to draw the bounding boxes on the image
|
6 |
def draw_bounding_boxes(image_path, gdf):
|
7 |
image = Image.open(image_path+'bird.png').convert("RGB")
|
@@ -10,7 +15,7 @@ def draw_bounding_boxes(image_path, gdf):
|
|
10 |
|
11 |
# Optional: Load a font (requires a TTF file)
|
12 |
# try:
|
13 |
-
font = ImageFont.truetype("
|
14 |
20)
|
15 |
# except IOError:
|
16 |
# print("default")
|
@@ -25,4 +30,4 @@ def draw_bounding_boxes(image_path, gdf):
|
|
25 |
image.save(image_path+'bird_boxed.png', "PNG")
|
26 |
|
27 |
if __name__ == "__main__":
|
28 |
-
draw_bounding_boxes('
|
|
|
2 |
|
3 |
from physical_boxes_define import gdf
|
4 |
|
5 |
+
from dotenv import load_dotenv
|
6 |
+
import os
|
7 |
+
load_dotenv()
|
8 |
+
PATH_ASSETS = os.getenv('PATH_ASSETS')
|
9 |
+
|
10 |
# Function to draw the bounding boxes on the image
|
11 |
def draw_bounding_boxes(image_path, gdf):
|
12 |
image = Image.open(image_path+'bird.png').convert("RGB")
|
|
|
15 |
|
16 |
# Optional: Load a font (requires a TTF file)
|
17 |
# try:
|
18 |
+
font = ImageFont.truetype(PATH_ASSETS + "fonts/LiberationSans-Regular.ttf",
|
19 |
20)
|
20 |
# except IOError:
|
21 |
# print("default")
|
|
|
30 |
image.save(image_path+'bird_boxed.png', "PNG")
|
31 |
|
32 |
if __name__ == "__main__":
|
33 |
+
draw_bounding_boxes(PATH_ASSETS + 'images/', gdf)
|
app/{physical_checkbox.py β physical/physical_checkbox.py}
RENAMED
@@ -1,9 +1,10 @@
|
|
1 |
import gradio as gr
|
2 |
-
from utils_config import get_custom_config_dropdowns
|
3 |
-
from utils_checkbox import create_checkbox
|
|
|
4 |
#---------------------------------------------------------
|
5 |
def get_body_parts():
|
6 |
-
dropdown_config = get_custom_config_dropdowns("
|
7 |
return list(dropdown_config.keys())
|
8 |
|
9 |
def retrieve_config_options(label, dropdown_config):
|
@@ -12,7 +13,7 @@ def retrieve_config_options(label, dropdown_config):
|
|
12 |
return options
|
13 |
|
14 |
def get_options_description(value):
|
15 |
-
dropdown_config = get_custom_config_dropdowns("
|
16 |
# get options
|
17 |
options_common = retrieve_config_options("Common", dropdown_config)
|
18 |
options_for_value = retrieve_config_options(value, dropdown_config)
|
@@ -68,4 +69,16 @@ def process_body_parts(section, matched_box):
|
|
68 |
checkbox_legs, text_legs = create_checkbox_legs(section, label_checkbox, visibles[4])
|
69 |
return checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs
|
70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
|
|
|
1 |
import gradio as gr
|
2 |
+
from utils.utils_config import get_custom_config_dropdowns
|
3 |
+
from utils.utils_checkbox import create_checkbox
|
4 |
+
from validation_submission.add_json import add_data_tmp
|
5 |
#---------------------------------------------------------
|
6 |
def get_body_parts():
|
7 |
+
dropdown_config = get_custom_config_dropdowns("config_checkbox_physical.json")
|
8 |
return list(dropdown_config.keys())
|
9 |
|
10 |
def retrieve_config_options(label, dropdown_config):
|
|
|
13 |
return options
|
14 |
|
15 |
def get_options_description(value):
|
16 |
+
dropdown_config = get_custom_config_dropdowns("config_checkbox_physical.json")
|
17 |
# get options
|
18 |
options_common = retrieve_config_options("Common", dropdown_config)
|
19 |
options_for_value = retrieve_config_options(value, dropdown_config)
|
|
|
69 |
checkbox_legs, text_legs = create_checkbox_legs(section, label_checkbox, visibles[4])
|
70 |
return checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs
|
71 |
|
72 |
+
#---------------------------------------------------------
|
73 |
+
|
74 |
+
def on_select_body_part(body_part_checkbox, body_part):
|
75 |
+
add_data_tmp("wounded_dead", "physical_type_"+body_part.lower(), body_part.lower())
|
76 |
+
body_part_checkbox = [body_part_check.lower() for body_part_check in body_part_checkbox]
|
77 |
+
add_data_tmp("wounded_dead", "physical_anomaly_"+body_part.lower(), body_part_checkbox)
|
78 |
+
|
79 |
+
#---------------------------------------------------------
|
80 |
+
|
81 |
+
def hide_physical():
|
82 |
+
checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs = process_body_parts("wounded", "None")
|
83 |
+
return checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs
|
84 |
|
app/{physical_select_animal.py β physical/physical_select_animal.py}
RENAMED
@@ -1,11 +1,15 @@
|
|
1 |
import gradio as gr
|
2 |
-
|
|
|
3 |
from typing import List
|
4 |
from shapely.geometry import Point
|
5 |
-
from physical_checkbox import *
|
6 |
-
from physical_boxes_define import gdf
|
7 |
-
from utils_visible import set_visible
|
8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
# Function to find the matching bounding box for a given point and return the image with boxes
|
11 |
def find_bounding_box(evt: gr.SelectData, img, section: str):
|
@@ -25,7 +29,8 @@ def find_bounding_box(evt: gr.SelectData, img, section: str):
|
|
25 |
# Gradio app
|
26 |
def create_bird_anatomy(visible, section: str):
|
27 |
# Draw bounding boxes on the image
|
28 |
-
|
|
|
29 |
show_label=False,
|
30 |
height="600px",
|
31 |
elem_id=section,
|
@@ -35,6 +40,7 @@ def create_bird_anatomy(visible, section: str):
|
|
35 |
def show_physical(choice, section: str):
|
36 |
visible = set_visible(choice)
|
37 |
physical_boxes = create_bird_anatomy(visible, section)
|
|
|
38 |
return physical_boxes
|
39 |
|
40 |
|
|
|
1 |
import gradio as gr
|
2 |
+
from dotenv import load_dotenv
|
3 |
+
import os
|
4 |
from typing import List
|
5 |
from shapely.geometry import Point
|
|
|
|
|
|
|
6 |
|
7 |
+
from physical.physical_checkbox import *
|
8 |
+
from physical.physical_boxes_define import gdf
|
9 |
+
from utils.utils_visible import set_visible
|
10 |
+
|
11 |
+
load_dotenv()
|
12 |
+
PATH_ASSETS = os.getenv('PATH_ASSETS')
|
13 |
|
14 |
# Function to find the matching bounding box for a given point and return the image with boxes
|
15 |
def find_bounding_box(evt: gr.SelectData, img, section: str):
|
|
|
29 |
# Gradio app
|
30 |
def create_bird_anatomy(visible, section: str):
|
31 |
# Draw bounding boxes on the image
|
32 |
+
print
|
33 |
+
img_with_boxes = gr.Image(value=PATH_ASSETS+'images/bird_boxed.png',
|
34 |
show_label=False,
|
35 |
height="600px",
|
36 |
elem_id=section,
|
|
|
40 |
def show_physical(choice, section: str):
|
41 |
visible = set_visible(choice)
|
42 |
physical_boxes = create_bird_anatomy(visible, section)
|
43 |
+
add_data_tmp("wounded_dead", "physical_radio", choice)
|
44 |
return physical_boxes
|
45 |
|
46 |
|
app/styling/__init__.py
ADDED
File without changes
|
app/{style.py β styling/style.py}
RENAMED
@@ -3,7 +3,7 @@ import gradio as gr
|
|
3 |
gr.HTML('''
|
4 |
<style>
|
5 |
.custom-button {
|
6 |
-
background-color: #
|
7 |
border: none;
|
8 |
color: white;
|
9 |
padding: 15px 32px;
|
@@ -16,4 +16,22 @@ gr.HTML('''
|
|
16 |
border-radius: 8px;
|
17 |
}
|
18 |
</style>
|
19 |
-
''')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
gr.HTML('''
|
4 |
<style>
|
5 |
.custom-button {
|
6 |
+
background-color: #3B4C54;
|
7 |
border: none;
|
8 |
color: white;
|
9 |
padding: 15px 32px;
|
|
|
16 |
border-radius: 8px;
|
17 |
}
|
18 |
</style>
|
19 |
+
''')
|
20 |
+
|
21 |
+
# gr.HTML('''
|
22 |
+
# <style>
|
23 |
+
# .custom-button {
|
24 |
+
# background-color: #4CAF50; /* Green */
|
25 |
+
# border: none;
|
26 |
+
# color: white;
|
27 |
+
# padding: 15px 32px;
|
28 |
+
# text-align: center;
|
29 |
+
# text-decoration: none;
|
30 |
+
# display: inline-block;
|
31 |
+
# font-size: 16px;
|
32 |
+
# margin: 4px 2px;
|
33 |
+
# cursor: pointer;
|
34 |
+
# border-radius: 8px;
|
35 |
+
# }
|
36 |
+
# </style>
|
37 |
+
# ''')
|
app/styling/theme.py
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
css = """
|
4 |
+
.gradio-container {background: url(https://openclipart.org/image/2000px/279687)}
|
5 |
+
|
6 |
+
/* Main background */
|
7 |
+
body {
|
8 |
+
background-color: #3B4C54;
|
9 |
+
color: #ffffff; /* Set default text color for contrast */
|
10 |
+
}
|
11 |
+
|
12 |
+
/* Secondary color for headers and panels */
|
13 |
+
.gradio-container .card,
|
14 |
+
.gradio-container h1,
|
15 |
+
.gradio-container h2,
|
16 |
+
.gradio-container h3,
|
17 |
+
.gradio-container h4 {
|
18 |
+
background-color: #3F543B;
|
19 |
+
color: #ffffff; /* Ensuring text is readable */
|
20 |
+
}
|
21 |
+
|
22 |
+
|
23 |
+
|
24 |
+
|
25 |
+
/* Background color for the wounded section */
|
26 |
+
#wounded {
|
27 |
+
background-color: #503B54;
|
28 |
+
color: #ffffff; /* Ensures text is readable */
|
29 |
+
}
|
30 |
+
|
31 |
+
/* Olive green color for headers within the wounded section */
|
32 |
+
#wounded h1,
|
33 |
+
#wounded h2,
|
34 |
+
#wounded h3,
|
35 |
+
#wounded h4,
|
36 |
+
#wounded h5,
|
37 |
+
#wounded h6 {
|
38 |
+
color: #ffffff; /* Olive green color for header text */
|
39 |
+
background-color: #503B54; /* No background color for headers */
|
40 |
+
}
|
41 |
+
|
42 |
+
/* Styling dropdowns within the wounded section */
|
43 |
+
#wounded select {
|
44 |
+
background-color: #3F543B; /* Olive green background */
|
45 |
+
color: #ffffff; /* Ensures text is readable */
|
46 |
+
border: 1px solid #3B4C54; /* Optional border for consistency */
|
47 |
+
}
|
48 |
+
|
49 |
+
/* Styling checkboxes within the wounded section */
|
50 |
+
#wounded input[type="checkbox"] {
|
51 |
+
accent-color: #3F543B; /* Olive green color for the checkbox */
|
52 |
+
}
|
53 |
+
|
54 |
+
/* Additional checkbox label styling if needed */
|
55 |
+
#wounded label {
|
56 |
+
color: #ffffff; /* Ensures labels are readable */
|
57 |
+
}
|
58 |
+
|
59 |
+
|
60 |
+
|
61 |
+
|
62 |
+
|
63 |
+
/* Background color for the dead section */
|
64 |
+
#dead {
|
65 |
+
background-color: #54433B;
|
66 |
+
color: #ffffff; /* Ensures text is readable */
|
67 |
+
}
|
68 |
+
|
69 |
+
/* Brown color for headers within the dead section */
|
70 |
+
#dead h1,
|
71 |
+
#dead h2,
|
72 |
+
#dead h3,
|
73 |
+
#dead h4,
|
74 |
+
#dead h5,
|
75 |
+
#dead h6 {
|
76 |
+
color: #ffffff; /* Olive green color for header text */
|
77 |
+
background-color: #54433B; /* No background color for headers */
|
78 |
+
}
|
79 |
+
|
80 |
+
|
81 |
+
#bird-boxes {background-color: #3B4C54}
|
82 |
+
#submit {background-color: #abb2bf}
|
83 |
+
#error {background-color: #e82323}
|
84 |
+
#valid {background-color: #07e63f}
|
85 |
+
"""
|
86 |
+
|
87 |
+
# OLD THEME:
|
88 |
+
|
89 |
+
# css = """
|
90 |
+
# .gradio-container {background: url(https://openclipart.org/image/2000px/279687)}
|
91 |
+
# #image {background-color: #73b9ae}
|
92 |
+
# #dead {background-color: #333333}
|
93 |
+
# #wounded {background-color: #5e0724}
|
94 |
+
# #bird-boxes {background-color: #f2f3f3}
|
95 |
+
# #buttons-conditions {background-color: #b3b3b3}
|
96 |
+
# #dropdown-conditions {background-color: #b3b3b3}
|
97 |
+
# #followup {background-color: #38241c}
|
98 |
+
# #submit {background-color: #abb2bf}
|
99 |
+
# #error {background-color: #e82323}
|
100 |
+
# #valid {background-color: #07e63f}
|
101 |
+
# """
|
102 |
+
|
103 |
+
# theme = gr.themes.Soft(primary_hue="teal", secondary_hue="teal", neutral_hue="emerald",
|
104 |
+
# font=[gr.themes.GoogleFont("Inconsolata"), "Arial", "sans-serif"])
|
app/theme.py
DELETED
@@ -1,18 +0,0 @@
|
|
1 |
-
import gradio as gr
|
2 |
-
|
3 |
-
css = """
|
4 |
-
.gradio-container {background: url(https://openclipart.org/image/2000px/279687)}
|
5 |
-
#image {background-color: #73b9ae}
|
6 |
-
#dead {background-color: #333333}
|
7 |
-
#wounded {background-color: #5e0724}
|
8 |
-
#bird-boxes {background-color: #f2f3f3}
|
9 |
-
#buttons-conditions {background-color: #b3b3b3}
|
10 |
-
#dropdown-conditions {background-color: #b3b3b3}
|
11 |
-
#followup {background-color: #38241c}
|
12 |
-
#submit {background-color: #abb2bf}
|
13 |
-
"""
|
14 |
-
|
15 |
-
#followup 2nd option: #13422f
|
16 |
-
|
17 |
-
theme = gr.themes.Soft(primary_hue="teal", secondary_hue="teal", neutral_hue="emerald",
|
18 |
-
font=[gr.themes.GoogleFont("Inconsolata"), "Arial", "sans-serif"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/utils/__init__.py
ADDED
File without changes
|
app/{utils_checkbox.py β utils/utils_checkbox.py}
RENAMED
File without changes
|
app/{utils_config.py β utils/utils_config.py}
RENAMED
@@ -1,5 +1,11 @@
|
|
1 |
import json
|
2 |
import os
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
def load_config(file_path):
|
5 |
with open(file_path) as f:
|
@@ -7,8 +13,7 @@ def load_config(file_path):
|
|
7 |
return config
|
8 |
|
9 |
def get_custom_config_dropdowns(config_path):
|
10 |
-
|
11 |
-
dropdown_config_path = path + config_path
|
12 |
dropdown_config = load_config(dropdown_config_path)
|
13 |
return dropdown_config
|
14 |
|
|
|
1 |
import json
|
2 |
import os
|
3 |
+
from dotenv import load_dotenv
|
4 |
+
import os
|
5 |
+
load_dotenv()
|
6 |
+
PATH = os.getcwd() + "/"
|
7 |
+
PATH_ASSETS = os.getenv('PATH_ASSETS')
|
8 |
+
PATH_CONFIG = PATH + PATH_ASSETS + "config/"
|
9 |
|
10 |
def load_config(file_path):
|
11 |
with open(file_path) as f:
|
|
|
13 |
return config
|
14 |
|
15 |
def get_custom_config_dropdowns(config_path):
|
16 |
+
dropdown_config_path = PATH_CONFIG + config_path
|
|
|
17 |
dropdown_config = load_config(dropdown_config_path)
|
18 |
return dropdown_config
|
19 |
|
app/{utils_visible.py β utils/utils_visible.py}
RENAMED
File without changes
|
app/validation_submission/__init__.py
ADDED
File without changes
|
app/validation_submission/add_json.py
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from validation_submission.create_json import create_json_one_individual, create_tmp
|
2 |
+
import json
|
3 |
+
|
4 |
+
def add_data_to_individual(key, value):
|
5 |
+
with open("data/one_individual.json", 'r') as openfile:
|
6 |
+
one_individual = json.load(openfile)
|
7 |
+
one_individual[key] = value
|
8 |
+
create_json_one_individual(one_individual)
|
9 |
+
|
10 |
+
def add_data_tmp(tmp_name, key, value):
|
11 |
+
with open(f"app/assets/tmp_json/tmp_{tmp_name}.json", 'r') as openfile:
|
12 |
+
tmp = json.load(openfile)
|
13 |
+
tmp[key] = value
|
14 |
+
create_tmp(tmp_name, tmp)
|
15 |
+
|
app/validation_submission/create_json.py
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
|
3 |
+
def create_json_one_individual(one_individual={}):
|
4 |
+
one_individual = json.dumps(one_individual)
|
5 |
+
with open("data/one_individual.json", "w") as outfile:
|
6 |
+
outfile.write(one_individual)
|
7 |
+
|
8 |
+
def create_json_all_individuals(all_individuals={}):
|
9 |
+
all_individuals = json.dumps(all_individuals)
|
10 |
+
with open("data/all_individuals.json", "w") as outfile:
|
11 |
+
outfile.write(all_individuals)
|
12 |
+
|
13 |
+
def create_tmp(tmp_name="wounded_dead", tmp={}):
|
14 |
+
tmp = json.dumps(tmp)
|
15 |
+
with open(f"app/assets/tmp_json/tmp_{tmp_name}.json", "w") as outfile:
|
16 |
+
outfile.write(tmp)
|
17 |
+
|
18 |
+
def reset_json():
|
19 |
+
create_json_one_individual()
|
20 |
+
create_tmp()
|
app/validation_submission/get_json.py
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
|
3 |
+
def get_json_one_individual():
|
4 |
+
with open("data/one_individual.json", 'r') as openfile:
|
5 |
+
one_individual = json.load(openfile)
|
6 |
+
return one_individual
|
7 |
+
|
8 |
+
def get_json_all_individuals():
|
9 |
+
with open("data/all_individuals.json", "r") as openfile:
|
10 |
+
all_individuals = json.load(openfile)
|
11 |
+
return all_individuals
|
12 |
+
|
13 |
+
def get_json_tmp(tmp_name):
|
14 |
+
with open(f"app/assets/tmp_json/tmp_{tmp_name}.json", "r") as openfile:
|
15 |
+
tmp_json = json.load(openfile)
|
16 |
+
return tmp_json
|
app/validation_submission/processing.py
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#### PROCESS FUNCTIONS
|
2 |
+
|
3 |
+
def process_circumstance(data):
|
4 |
+
fields_to_check = ["option_dropdown", "open_field", "extra"]
|
5 |
+
if data["circumstance_radio"] == "Yes":
|
6 |
+
for field in fields_to_check:
|
7 |
+
if data["circumstance_type"][field+"_label"] == "NA":
|
8 |
+
data["circumstance_type"].pop(field+"_label")
|
9 |
+
else :
|
10 |
+
val = data[f"circumstance_{field}"]
|
11 |
+
key = data["circumstance_type"][field+"_label"]
|
12 |
+
data["circumstance_type"][key] = val
|
13 |
+
data["circumstance_type"].pop(field+"_label")
|
14 |
+
return data
|
15 |
+
|
16 |
+
def process_behaviors(data):
|
17 |
+
behaviors =[]
|
18 |
+
if data["behaviors_radio"] == "Yes":
|
19 |
+
for type in data["behaviors_type"]:
|
20 |
+
new_behavior = {}
|
21 |
+
new_behavior["type"] = type
|
22 |
+
behaviors.append(new_behavior)
|
23 |
+
data["behaviors_type"] = behaviors
|
24 |
+
return data
|
25 |
+
|
26 |
+
def process_physical(data):
|
27 |
+
body_parts= ["beak", "body", "legs", "feathers/wings/tail", "head incl. eyes"]
|
28 |
+
anomalies=[]
|
29 |
+
reformatted = {}
|
30 |
+
reformatted["physical_radio"] = data["physical_radio"]
|
31 |
+
if data["physical_radio"] == "Yes":
|
32 |
+
for body_part in body_parts:
|
33 |
+
anomaly = {}
|
34 |
+
for key, val in data.items():
|
35 |
+
if "type_"+ body_part in key:
|
36 |
+
anomaly["type"] = body_part
|
37 |
+
elif "anomaly_"+ body_part in key:
|
38 |
+
anomaly["anomaly_type"] = val
|
39 |
+
if anomaly:
|
40 |
+
anomalies.append(anomaly)
|
41 |
+
reformatted["physical_anomalies_type"] = anomalies
|
42 |
+
return reformatted
|
43 |
+
|
44 |
+
def process_followup(data):
|
45 |
+
followup_events = []
|
46 |
+
for key, val in data.items():
|
47 |
+
followup_event={}
|
48 |
+
type = key.split("followup")[-1]
|
49 |
+
option = type.split(" ")[-1]
|
50 |
+
followup_event["type"] = type.strip()
|
51 |
+
followup_event[option.strip()] = val
|
52 |
+
followup_events.append(followup_event)
|
53 |
+
reformatted ={}
|
54 |
+
reformatted["follow_up_events"] = followup_events
|
55 |
+
return reformatted
|
app/validation_submission/submission.py
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
from validation_submission.get_json import get_json_all_individuals
|
3 |
+
from validation_submission.validation import validate_individual
|
4 |
+
|
5 |
+
def validate_save_individual(error_box):
|
6 |
+
individual, error_box = validate_individual(error_box)
|
7 |
+
if individual:
|
8 |
+
save_to_all_individuals(individual.model_dump())
|
9 |
+
return individual, error_box
|
10 |
+
|
11 |
+
def save_to_all_individuals(one_individual):
|
12 |
+
all_individuals = get_json_all_individuals()
|
13 |
+
all_individuals[str(len(all_individuals))] = one_individual
|
14 |
+
all_individuals_for_json = json.dumps(all_individuals)
|
15 |
+
with open("data/all_individuals.json", "w") as outfile:
|
16 |
+
outfile.write(all_individuals_for_json)
|
17 |
+
return all_individuals
|
app/validation_submission/validation.py
ADDED
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import uuid
|
2 |
+
from pydantic import ValidationError
|
3 |
+
import gradio as gr
|
4 |
+
|
5 |
+
from validation_submission.get_json import get_json_tmp, get_json_one_individual
|
6 |
+
from circumstances.class_circumstance import Circumstances
|
7 |
+
from behavior.class_behavior import Behaviors
|
8 |
+
from physical.class_physical import PhysicalAnomalies
|
9 |
+
from follow_up.class_follow_up import FollowUpEvents
|
10 |
+
from classes import Report, Wounded, Dead, ImageBase64
|
11 |
+
from validation_submission.processing import process_circumstance, process_behaviors, process_physical, process_followup
|
12 |
+
|
13 |
+
def get_fields(data_dict, keyword):
|
14 |
+
extract = {}
|
15 |
+
for key, val in data_dict.items():
|
16 |
+
if keyword in key:
|
17 |
+
extract[key] = val
|
18 |
+
return extract
|
19 |
+
|
20 |
+
def validate_individual(error_box):
|
21 |
+
error_box = reset_error_box(error_box)
|
22 |
+
data = get_json_one_individual()
|
23 |
+
data["identifier"] = str(uuid.uuid4())
|
24 |
+
if "image" in data.keys():
|
25 |
+
img = ImageBase64.to_base64(data["image"])
|
26 |
+
else:
|
27 |
+
img = None
|
28 |
+
if "geolocalisation" in data.keys():
|
29 |
+
geolocalisation = data["geolocalisation"]
|
30 |
+
else:
|
31 |
+
geolocalisation = None
|
32 |
+
|
33 |
+
error_behavior = None
|
34 |
+
error_circumstance = None
|
35 |
+
error_followup = None
|
36 |
+
error_physical = None
|
37 |
+
error_individual = None
|
38 |
+
if "wounded_state" not in data or "dead_state" not in data:
|
39 |
+
data["wounded_state"] = "No"
|
40 |
+
data["dead_state"] = "No"
|
41 |
+
if (data["wounded_state"] == "Yes") or (data["dead_state"] == "Yes"):
|
42 |
+
data_wounded_dead = get_json_tmp("wounded_dead")
|
43 |
+
circumstance, error_circumstance = validate_circumstance(data_wounded_dead)
|
44 |
+
physical, error_physical = validate_physical(data_wounded_dead)
|
45 |
+
followup, error_followup = validate_follow_up(data_wounded_dead)
|
46 |
+
|
47 |
+
if data["wounded_state"]=="Yes":
|
48 |
+
print(physical)
|
49 |
+
behavior, error_behavior = validate_behavior(data_wounded_dead)
|
50 |
+
try :
|
51 |
+
individual = Report(identifier = data["identifier"],
|
52 |
+
image = img,
|
53 |
+
geolocalisation = geolocalisation,
|
54 |
+
wounded_state = data["wounded_state"],
|
55 |
+
wounded = Wounded(circumstances = circumstance,
|
56 |
+
behaviors = behavior,
|
57 |
+
physical_anomalies = physical,
|
58 |
+
follow_up_events = followup),
|
59 |
+
dead_state = data["dead_state"])
|
60 |
+
except ValidationError as e:
|
61 |
+
print(e)
|
62 |
+
error_individual = e
|
63 |
+
|
64 |
+
elif data["dead_state"]=="Yes":
|
65 |
+
try:
|
66 |
+
individual = Report(identifier = data["identifier"],
|
67 |
+
image = img,
|
68 |
+
geolocalisation = geolocalisation,
|
69 |
+
wounded_state = data["wounded_state"],
|
70 |
+
dead_state = data["dead_state"],
|
71 |
+
dead = Dead(circumstances = circumstance,
|
72 |
+
physical_anomalies = physical,
|
73 |
+
follow_up_events = followup)
|
74 |
+
)
|
75 |
+
except ValidationError as e:
|
76 |
+
print(e)
|
77 |
+
error_individual = e
|
78 |
+
else:
|
79 |
+
try:
|
80 |
+
individual = Report(identifier = data["identifier"],
|
81 |
+
image = img,
|
82 |
+
geolocalisation = geolocalisation,
|
83 |
+
wounded_state = data["wounded_state"],
|
84 |
+
dead_state = data["dead_state"])
|
85 |
+
except ValidationError as e:
|
86 |
+
print(e)
|
87 |
+
error_individual = e
|
88 |
+
if error_behavior or error_circumstance or error_followup or error_physical or error_individual:
|
89 |
+
error_box = show_error(error_box, error_behavior, error_circumstance, error_followup, error_physical, error_individual)
|
90 |
+
individual = None
|
91 |
+
else:
|
92 |
+
error_box= gr.Text(label="ALL VALID.", value="Record Registered. You can return to the Display.", visible=True, elem_id="valid")
|
93 |
+
return individual, error_box
|
94 |
+
|
95 |
+
def show_error(error_box, error_behavior, error_circumstance, error_followup, error_physical, error_individual):
|
96 |
+
error_text = ""
|
97 |
+
if error_circumstance:
|
98 |
+
error_text += f"Error in circumstance: {error_circumstance}\n"
|
99 |
+
if error_behavior:
|
100 |
+
error_text += f"Error in behavior: {error_behavior}\n"
|
101 |
+
if error_physical:
|
102 |
+
error_text += f"Error in physical: {error_physical}\n"
|
103 |
+
if error_followup:
|
104 |
+
error_text += f"Error in follow-up: {error_followup}\n"
|
105 |
+
if error_individual:
|
106 |
+
error_text += f"Error in individual: {error_individual}\n"
|
107 |
+
error_text += "PLEASE CORRECT THESE ERRORS BEFORE SUBMITTING."
|
108 |
+
error_box= gr.Text(label="ERROR DETECTED !", value=error_text, visible=True, elem_id="error")
|
109 |
+
return error_box
|
110 |
+
|
111 |
+
def reset_error_box(error_box):
|
112 |
+
error_box = gr.Text(value=None, visible=False)
|
113 |
+
return error_box
|
114 |
+
|
115 |
+
#### VALIDATION FUNCTIONS
|
116 |
+
def validate_circumstance(data):
|
117 |
+
circumstance_raw = get_fields(data, "circumstance")
|
118 |
+
circumstance_formatted = process_circumstance(circumstance_raw)
|
119 |
+
try:
|
120 |
+
Circumstances.model_validate(circumstance_formatted)
|
121 |
+
circumstances = Circumstances(**circumstance_formatted)
|
122 |
+
error = None
|
123 |
+
except ValidationError as e:
|
124 |
+
error = e
|
125 |
+
print(e)
|
126 |
+
circumstances = None
|
127 |
+
return circumstances, error
|
128 |
+
|
129 |
+
|
130 |
+
def validate_behavior(data):
|
131 |
+
behaviors_raw = get_fields(data, "behaviors")
|
132 |
+
behaviors_formatted = process_behaviors(behaviors_raw)
|
133 |
+
try:
|
134 |
+
Behaviors.model_validate(behaviors_formatted)
|
135 |
+
behavior = Behaviors(**behaviors_formatted)
|
136 |
+
error = None
|
137 |
+
except ValidationError as e:
|
138 |
+
print(e)
|
139 |
+
print("Validation failed for the behaviors.")
|
140 |
+
behavior = None
|
141 |
+
error = e
|
142 |
+
return behavior, error
|
143 |
+
|
144 |
+
|
145 |
+
def validate_physical(data):
|
146 |
+
physical_raw = get_fields(data, "physical")
|
147 |
+
physical_formatted = process_physical(physical_raw)
|
148 |
+
try:
|
149 |
+
PhysicalAnomalies.model_validate(physical_formatted)
|
150 |
+
physical = PhysicalAnomalies(**physical_formatted)
|
151 |
+
error = None
|
152 |
+
except ValidationError as e:
|
153 |
+
print(e)
|
154 |
+
print("Validation failed for the physical anomalies.")
|
155 |
+
physical = None
|
156 |
+
error = e
|
157 |
+
return physical, error
|
158 |
+
|
159 |
+
def validate_follow_up(data):
|
160 |
+
followup_raw = get_fields(data, "followup")
|
161 |
+
followup_formatted = process_followup(followup_raw)
|
162 |
+
try:
|
163 |
+
FollowUpEvents.model_validate(followup_formatted)
|
164 |
+
followup = FollowUpEvents(**followup_formatted)
|
165 |
+
error = None
|
166 |
+
except ValidationError as e:
|
167 |
+
print(e)
|
168 |
+
print("Validation failed for the follow-up events.")
|
169 |
+
followup = None
|
170 |
+
return followup, error
|
171 |
+
|
172 |
+
|
173 |
+
|
app/wounded.py
CHANGED
@@ -1,17 +1,22 @@
|
|
1 |
import gradio as gr
|
2 |
-
from circumstances import
|
3 |
-
from physical_select_animal import create_bird_anatomy
|
4 |
-
from physical_checkbox import process_body_parts
|
5 |
-
from behavior_checkbox import create_behavior_checkbox
|
6 |
-
from followup_events import
|
|
|
7 |
|
8 |
def show_section_wounded(visible):
|
|
|
|
|
|
|
|
|
9 |
with gr.Column(visible=visible, elem_id="wounded") as wounded_section:
|
10 |
gr.Markdown("# Wounded Animal")
|
11 |
|
12 |
gr.Markdown("## Do you know what conditions caused this?", label="description")
|
13 |
radio_cause = gr.Radio(["Yes", "No"], value=None, show_label=False, interactive=True)
|
14 |
-
button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2 =
|
15 |
|
16 |
gr.Markdown("## Is the bird displaying behavioural changes?" , label="description")
|
17 |
radio_behaviour = gr.Radio(["Yes", "No"], value=None, show_label=False, interactive=True)
|
@@ -25,9 +30,14 @@ def show_section_wounded(visible):
|
|
25 |
with gr.Column():
|
26 |
checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs = process_body_parts("wounded", "None")
|
27 |
|
28 |
-
|
29 |
gr.Markdown("## Follow-Up Events", label="Title")
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
31 |
|
32 |
# Change variables and names
|
33 |
return wounded_section, radio_cause, radio_behaviour, radio_physical, \
|
@@ -35,4 +45,5 @@ def show_section_wounded(visible):
|
|
35 |
dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2, \
|
36 |
behavior_checkbox, behavior_text, \
|
37 |
physical_boxes, \
|
38 |
-
checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs
|
|
|
|
1 |
import gradio as gr
|
2 |
+
from circumstances.circumstances import create_circumstances
|
3 |
+
from physical.physical_select_animal import create_bird_anatomy
|
4 |
+
from physical.physical_checkbox import process_body_parts
|
5 |
+
from behavior.behavior_checkbox import create_behavior_checkbox
|
6 |
+
from follow_up.followup_events import create_followup_dropdowns, create_followup_open
|
7 |
+
from validation_submission.add_json import add_data_to_individual
|
8 |
|
9 |
def show_section_wounded(visible):
|
10 |
+
if visible==True:
|
11 |
+
add_data_to_individual("wounded_state", "Yes")
|
12 |
+
add_data_to_individual("dead_state", "No")
|
13 |
+
|
14 |
with gr.Column(visible=visible, elem_id="wounded") as wounded_section:
|
15 |
gr.Markdown("# Wounded Animal")
|
16 |
|
17 |
gr.Markdown("## Do you know what conditions caused this?", label="description")
|
18 |
radio_cause = gr.Radio(["Yes", "No"], value=None, show_label=False, interactive=True)
|
19 |
+
button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2 = create_circumstances(visible=False)
|
20 |
|
21 |
gr.Markdown("## Is the bird displaying behavioural changes?" , label="description")
|
22 |
radio_behaviour = gr.Radio(["Yes", "No"], value=None, show_label=False, interactive=True)
|
|
|
30 |
with gr.Column():
|
31 |
checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs = process_body_parts("wounded", "None")
|
32 |
|
33 |
+
|
34 |
gr.Markdown("## Follow-Up Events", label="Title")
|
35 |
+
gr.Markdown("Please tell us what you did with the animal.", label="description")
|
36 |
+
with gr.Row():
|
37 |
+
fe_collection_dropdown, fe_recepient_dropdown, fe_radio_dropdown, fe_answer_dropdown = create_followup_dropdowns(visible, "wounded")
|
38 |
+
with gr.Row():
|
39 |
+
fe_name_recipient, fe_collection_ref = create_followup_open(visible, "wounded")
|
40 |
+
|
41 |
|
42 |
# Change variables and names
|
43 |
return wounded_section, radio_cause, radio_behaviour, radio_physical, \
|
|
|
45 |
dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2, \
|
46 |
behavior_checkbox, behavior_text, \
|
47 |
physical_boxes, \
|
48 |
+
checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs, \
|
49 |
+
fe_collection_dropdown, fe_recepient_dropdown, fe_radio_dropdown, fe_answer_dropdown, fe_name_recipient, fe_collection_ref
|
requirements.txt
CHANGED
@@ -1,4 +1,6 @@
|
|
1 |
gradio
|
|
|
2 |
geopy
|
3 |
geopandas
|
4 |
-
pillow
|
|
|
|
1 |
gradio
|
2 |
+
gradio_modal
|
3 |
geopy
|
4 |
geopandas
|
5 |
+
pillow
|
6 |
+
dotenv
|