vancauwe commited on
Commit
b77c9e9
Β·
unverified Β·
2 Parent(s): 667ff60 8564432

Merge pull request #21 from sdsc-ordes/feat-multi-animal-reporting

Browse files
Files changed (49) hide show
  1. .gitignore +2 -0
  2. app/.env.dist +1 -0
  3. app/assets/config/config_checkbox_behavior.json +1 -1
  4. app/assets/config/config_checkbox_physical.json +1 -1
  5. app/assets/config/{config_dropdown_conditions.json β†’ config_dropdown_circumstances.json} +59 -24
  6. app/assets/images/empty_image.jpg +0 -0
  7. app/behavior/__init__.py +0 -0
  8. app/{behavior_checkbox.py β†’ behavior/behavior_checkbox.py} +11 -4
  9. app/behavior/class_behavior.py +66 -0
  10. app/circumstances/__init__.py +0 -0
  11. app/{circumstances.py β†’ circumstances/circumstances.py} +24 -14
  12. app/{circumstances_dropdowns.py β†’ circumstances/circumstances_dropdowns.py} +40 -9
  13. app/circumstances/class_circumstance.py +205 -0
  14. app/classes.py +46 -0
  15. app/dead.py +32 -7
  16. app/display.py +120 -0
  17. app/follow_up/class_follow_up.py +50 -0
  18. app/follow_up/followup_events.py +46 -0
  19. app/followup_events.py +0 -17
  20. app/geolocalisation/__init__.py +0 -0
  21. app/geolocalisation/class_geolocalisation.py +16 -0
  22. app/{maps.py β†’ geolocalisation/maps.py} +24 -1
  23. app/gradio_test/test_selectdata_event.py +16 -0
  24. app/gradio_test/tests_delete_gallery.py +25 -0
  25. app/main.py +311 -138
  26. app/main_test.py +0 -68
  27. app/physical/__init__.py +0 -0
  28. app/physical/class_physical.py +79 -0
  29. app/{physical_boxes_define.py β†’ physical/physical_boxes_define.py} +0 -0
  30. app/{physical_boxes_map.py β†’ physical/physical_boxes_map.py} +7 -2
  31. app/{physical_checkbox.py β†’ physical/physical_checkbox.py} +17 -4
  32. app/{physical_select_animal.py β†’ physical/physical_select_animal.py} +11 -5
  33. app/styling/__init__.py +0 -0
  34. app/{style.py β†’ styling/style.py} +20 -2
  35. app/styling/theme.py +104 -0
  36. app/theme.py +0 -18
  37. app/utils/__init__.py +0 -0
  38. app/{utils_checkbox.py β†’ utils/utils_checkbox.py} +0 -0
  39. app/{utils_config.py β†’ utils/utils_config.py} +7 -2
  40. app/{utils_visible.py β†’ utils/utils_visible.py} +0 -0
  41. app/validation_submission/__init__.py +0 -0
  42. app/validation_submission/add_json.py +15 -0
  43. app/validation_submission/create_json.py +20 -0
  44. app/validation_submission/get_json.py +16 -0
  45. app/validation_submission/processing.py +55 -0
  46. app/validation_submission/submission.py +17 -0
  47. app/validation_submission/validation.py +173 -0
  48. app/wounded.py +20 -9
  49. 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 breating":
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
- "Parasites": {
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
- "Options": ["highway", "main road", "secondary road", "local road/path/trail", "parking lot", "other", "unknown"],
8
- "Open": "Infrastructure number"
9
-
10
  },
11
  "train":
12
  {
13
- "Open": "Infrastructure number"
14
  },
15
  "aircraft": {},
16
  "boat": {},
17
- "other": {},
18
  "unknown": {}
19
  },
20
  "Destruction / Deliberatly removed" :
21
  {
22
  "hunting":
23
  {
24
- "Options": ["shooting", "bow", "falconry", "hounds hunting", "digging up", "other", "unknown"]
 
 
 
25
  },
26
  "trap":
27
  {
28
- "Options": ["killing trap", "pole trap", "trap cage", "corvids nasse", "net", "cage trap", "fall-trap", "glue trap", "insect trap", "other", "unknown"]
 
 
 
 
29
  },
30
  "poisoning": {},
31
  "removal or direct capture":
32
  {
33
- "Options": ["gassing", "raptor captured at nest", "brood destruction", "traffic/trade", "capture accident", "scientific sample", "other", "unknown"]
 
 
 
34
  },
35
  "fishing":
36
  {
37
- "Options": ["drowned/tangled", "beached with capture indications", "other", "unknown"]
 
 
38
  },
39
- "other": {},
40
  "unknown": {}
41
  },
42
  "Indirect destruction":
@@ -44,59 +56,82 @@
44
  "pylone and electric grid":
45
  {
46
 
47
- "Options": ["electric line", "pole/pylon", "other", "unknown"],
 
 
48
  "Extra":
49
  {
50
- "Cause": ["collision", "electrocution", "unknown"]
51
  }
52
  },
53
  "windfarm": {},
54
  "other collision":
55
  {
56
- "Options": ["window", "building", "lighthouse", "cable", "wire fence/barbed wire", "other crash", "unknown"]
 
 
57
  },
58
  "fall":
59
  {
60
- "Options": ["chimney", "empty pole", "hole/well", "other", "unknown"]
 
 
61
  },
62
  "development work":
63
  {
64
- "Options": ["transport infrastructure", "building", "other", "unknown"]
 
 
65
  },
66
  "pollution / contamination":
67
  {
68
- "Options": ["oil pollution", "chemical pollution", "heavy metals", "light", "noise", "plastic ingestion", "other", "unknown"]
 
 
69
  },
70
  "agricultural net protection": {},
71
  "vegetal / forest work":
72
  {
73
- "Options": ["clearing/mowing/plowing", "tree felling/pruning", "other", "unknown"]
 
 
 
 
74
  },
75
- "other": {},
76
  "unknown": {}
77
  },
78
  "Natural cause":
79
  {
80
  "predation":
81
  {
82
- "Options": ["cat", "dog", "rooster/hen", "other domestic animal", "wild birds", "wild mammal", "other", "unknown"]
 
 
 
83
  },
84
  "weather":
85
  {
86
- "Options": ["cold wave", "drought", "hail", "lightening", "storm", "other", "unknown"]
 
 
87
  },
88
  "natural disaster":
89
  {
90
- "Options": ["fire", "avalanche", "rock fall", "mudslide", "volcanic eruption/ashes", "other", "unknown"]
 
 
91
  },
92
  "nest fall": {},
93
  "stranding due to exhaustion": {},
94
  "disease/parasite": {},
95
  "accidental drowing":
96
  {
97
- "Options": ["drinking trough", "pool", "storm pool", "irrigation pool", "natural pool", "flood", "other container", "unknown"]
 
 
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
- from utils_config import get_custom_config_dropdowns
2
- from utils_checkbox import create_checkbox
3
- from utils_visible import set_visible
 
 
 
 
 
 
4
 
5
  def retrieve_behavior_options_description():
6
- dropdown_config = get_custom_config_dropdowns("/assets/config/config_checkbox_behavior.json")
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 utils_visible import set_visible
 
 
 
 
 
 
 
 
4
 
5
- PATH = os.getcwd()
6
  CAUSE_COL_WIDTH = "50px"
7
 
8
- def show_causes(choice):
 
9
  visible = set_visible(choice)
10
- button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2 = create_causes(visible)
 
 
 
11
  return button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2
12
 
13
- def create_causes(visible):
14
- button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause = create_causes_buttons(visible)
15
- dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2 = create_causes_dropdown(visible)
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=PATH + '/assets/logos/van.png',
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=PATH + '/assets/logos/destruction.png',
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=PATH + '/assets/logos/indirect.png',
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=PATH + '/assets/logos/natural.png',
42
  visible=visible,
43
  elem_id="buttons-conditions")
44
  return button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause
45
 
46
- def create_causes_dropdown(visible):
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("/assets/config/config_dropdown_conditions.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,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("/assets/config/config_dropdown_conditions.json")
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
- options_dropdown = nested_dict["Options"]
 
 
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 create_causes
3
- from followup_events import create_followup_section
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
- button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2 = create_causes(visible)
 
 
12
 
13
- create_followup_section()
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
- return section_dead, button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2
 
 
 
 
 
 
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 show_causes
6
- from circumstances_dropdowns import *
7
- from physical_select_animal import show_physical, find_bounding_box
8
- from behavior_checkbox import show_behavior
9
- from maps import get_location
10
- from style import *
11
- from theme import theme, css
12
-
13
- with gr.Blocks(theme=theme, css=css) as demo:
 
 
 
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
- # Camera
23
- with gr.Row():
24
- #with gr.Column(scale=1):
25
- camera = gr.Image(elem_id="image")
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
- # Dead and Wounded Buttons
46
- gr.Markdown("## The State of the Animal", label="Title")
47
- gr.Markdown("Please tell us if the animal was wounded or dead.", label="description")
48
- with gr.Row() as block_form:
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
- # Initiate sections
56
- section_dead, \
57
- button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead, \
58
- dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead \
59
- = show_section_dead(False)
60
- section_wounded, radio_cause_wounded, radio_behavior_wounded, radio_physical_wounded, \
61
- button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded, \
62
- dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, \
63
- behavior_checkbox, behavior_text, \
64
- physical_boxes_wounded, \
65
- checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs \
66
- = show_section_wounded(False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
- # ---------------------------------------------------------
69
- # Dead Button Logic
70
- partial_show_section_dead = partial(show_section_dead, True)
71
- partial_hide_section_wounded = partial(show_section_wounded, False)
72
- butt_dead.click(partial_show_section_dead,
73
- inputs=None,
74
- outputs=[section_dead,
75
- button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead,
76
- dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead
77
- ])
78
- butt_dead.click(partial_hide_section_wounded,
79
- inputs=None,
80
- outputs=[section_wounded,
81
- radio_cause_wounded, radio_behavior_wounded, radio_physical_wounded,
82
- button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded,
83
- dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded,
84
- behavior_checkbox, behavior_text,
85
- physical_boxes_wounded,
86
- checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs
87
-
88
- ])
89
- # ---------------------------------------------------------
90
- # Wounded Button Logic
91
- partial_show_section_wounded = partial(show_section_wounded, True)
92
- partial_hide_section_dead = partial(show_section_dead, False)
93
-
94
- butt_wounded.click(partial_show_section_wounded,
95
- inputs=None,
96
- outputs=[section_wounded,
97
- radio_cause_wounded, radio_behavior_wounded, radio_physical_wounded,
 
 
 
 
 
 
 
 
 
 
 
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
- checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs
 
 
103
  ])
104
- butt_wounded.click(partial_hide_section_dead, inputs=None, outputs=[section_dead,
105
- button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead,
106
- dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead
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
- dropdown_dead.select(on_select, None, [dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
- # ---------------------------------------------------------
119
- # Radio Cause Wounded
120
- radio_cause_wounded.change(fn=show_causes,
121
- inputs=[radio_cause_wounded],
122
- outputs=[button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded,
123
- dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded]
124
- )
125
-
126
- # Dropdowns Cause Wounded
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
- # Radio Behavior Wounded
137
- radio_behavior_wounded.change(fn=show_behavior,
138
- inputs=[radio_behavior_wounded, gr.Text("wounded", visible=False)],
139
- outputs=[behavior_checkbox, behavior_text])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
 
141
- # ---------------------------------------------------------
142
- # Radio Physical Wounded
143
- radio_physical_wounded.change(fn=show_physical,
144
- inputs=[radio_physical_wounded, gr.Text("wounded", visible=False)],
145
- outputs=[physical_boxes_wounded])
146
-
147
- # Checkbox Physical Wounded
148
- physical_boxes_wounded.select(find_bounding_box,
149
- inputs=[physical_boxes_wounded, gr.Textbox(value="wounded", visible=False)],
150
- outputs=[checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs
151
- ])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
 
153
  # ---------------------------------------------------------
154
- #Submit Button
155
- with gr.Column(scale=1):
156
- subbutt = gr.Button("SUBMIT YOUR OBSERVATION TO ORNITHO",
157
- elem_id="submit",
158
- icon="https://cdn.iconscout.com/icon/free/png-256/free-send-2451554-2082560.png",
159
- scale=1)
160
- output_message = gr.Markdown("Thank you, you are a champion of biodiversity conservation !")
161
 
162
-
163
 
164
- demo.launch(server_name="0.0.0.0")
 
 
 
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("assets/fonts/LiberationSans-Regular.ttf",
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('assets/images/', gdf)
 
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("/assets/config/config_checkbox_physical.json")
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("/assets/config/config_checkbox_physical.json")
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
- # from gradio_image_prompter import ImagePrompter
 
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
- img_with_boxes = gr.Image(value='assets/images/bird_boxed.png',
 
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: #4CAF50; /* Green */
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
- path = os.getcwd()
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 create_causes
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 create_followup_section
 
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 = create_causes(visible=False)
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
- create_followup_section()
 
 
 
 
 
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