vancauwe commited on
Commit
21dae66
·
1 Parent(s): d7b6645

chore: format code and update readme

Browse files
Files changed (46) hide show
  1. .github/workflows/sync_dataset_hf.yml +2 -2
  2. .gitignore +2 -2
  3. .pre-commit-config.yaml +1 -1
  4. Dockerfile +2 -2
  5. README.md +19 -21
  6. app/.env.dist +2 -1
  7. app/about.py +29 -20
  8. app/assets/config/config_checkbox_behavior.json +2 -2
  9. app/assets/config/config_checkbox_behavior_simple.json +2 -2
  10. app/assets/config/config_checkbox_physical.json +2 -2
  11. app/assets/config/config_checkbox_physical_simple.json +2 -2
  12. app/assets/config/config_dropdown_circumstances.json +27 -27
  13. app/assets/config/config_followup.json +2 -2
  14. app/behavior/class_behavior.py +36 -15
  15. app/circumstances/circumstances.py +99 -42
  16. app/circumstances/class_circumstance.py +186 -73
  17. app/contacts.py +56 -41
  18. app/dead_wounded/dead.py +86 -27
  19. app/dead_wounded/wounded.py +104 -36
  20. app/follow_up/class_follow_up.py +28 -20
  21. app/follow_up/followup_events.py +63 -24
  22. app/geolocalisation/class_geolocalisation.py +5 -3
  23. app/geolocalisation/js_geolocation.py +9 -7
  24. app/geolocalisation/maps.py +27 -19
  25. app/main.py +8 -5
  26. app/mode_advanced.py +854 -300
  27. app/mode_simple.py +829 -286
  28. app/physical/class_physical.py +38 -48
  29. app/physical/class_physical_simple.py +19 -32
  30. app/physical/physical_boxes_define.py +10 -10
  31. app/physical/physical_boxes_map.py +10 -8
  32. app/physical/physical_checkbox.py +0 -1
  33. app/physical/physical_select_animal.py +48 -18
  34. app/styling/style.py +6 -4
  35. app/styling/theme.py +15 -15
  36. app/sync_dataset_hf.py +11 -15
  37. app/utils/utils_checkbox.py +25 -15
  38. app/utils/utils_config.py +4 -3
  39. app/utils/utils_visible.py +3 -3
  40. app/validation_submission/processing.py +43 -25
  41. app/validation_submission/resets.py +7 -2
  42. app/validation_submission/submission.py +4 -2
  43. app/validation_submission/utils_individual.py +4 -5
  44. app/validation_submission/utils_save.py +6 -4
  45. app/validation_submission/validation.py +31 -14
  46. requirements.txt +1 -1
.github/workflows/sync_dataset_hf.yml CHANGED
@@ -10,7 +10,7 @@ jobs:
10
  steps:
11
  - name: Checkout repository
12
  uses: actions/checkout@v2
13
-
14
  - name: Set up Python
15
  uses: actions/setup-python@v2
16
  with:
@@ -24,4 +24,4 @@ jobs:
24
  - name: Sync Datasets
25
  env:
26
  HF_TOKEN: ${{ secrets.HF_TOKEN }}
27
- run: python app/sync_dataset_hf.py
 
10
  steps:
11
  - name: Checkout repository
12
  uses: actions/checkout@v2
13
+
14
  - name: Set up Python
15
  uses: actions/setup-python@v2
16
  with:
 
24
  - name: Sync Datasets
25
  env:
26
  HF_TOKEN: ${{ secrets.HF_TOKEN }}
27
+ run: python app/sync_dataset_hf.py
.gitignore CHANGED
@@ -5,10 +5,10 @@ __pycache__/
5
  *.py[cod]
6
  *$py.class
7
 
8
- #Data
9
  test/data/*.json
10
  data/*.json
11
- app/assets/tmp_json/*.json
12
 
13
  # C extensions
14
  *.so
 
5
  *.py[cod]
6
  *$py.class
7
 
8
+ #Data
9
  test/data/*.json
10
  data/*.json
11
+ app/assets/tmp_json/*.json
12
 
13
  # C extensions
14
  *.so
.pre-commit-config.yaml CHANGED
@@ -18,4 +18,4 @@ repos:
18
  args: [ --exit-zero ]
19
  verbose: true
20
  - id: ruff-format
21
- types_or: [ python, pyi, jupyter ]
 
18
  args: [ --exit-zero ]
19
  verbose: true
20
  - id: ruff-format
21
+ types_or: [ python, pyi, jupyter ]
Dockerfile CHANGED
@@ -6,7 +6,7 @@ RUN apt-get install python3 python3-pip -y
6
 
7
  # RUN apt update
8
  # RUN apt-get update
9
- # RUN apt install python3.10 python3-pip -y
10
 
11
  # https://stackoverflow.com/questions/75608323/how-do-i-solve-error-externally-managed-environment-every-time-i-use-pip-3
12
  # https://veronneau.org/python-311-pip-and-breaking-system-packages.html
@@ -25,7 +25,7 @@ RUN apt-get update && apt-get -y upgrade \
25
  && apt-get install -y --no-install-recommends \
26
  unzip \
27
  nano \
28
- git \
29
  g++ \
30
  gcc \
31
  htop \
 
6
 
7
  # RUN apt update
8
  # RUN apt-get update
9
+ # RUN apt install python3.10 python3-pip -y
10
 
11
  # https://stackoverflow.com/questions/75608323/how-do-i-solve-error-externally-managed-environment-every-time-i-use-pip-3
12
  # https://veronneau.org/python-311-pip-and-breaking-system-packages.html
 
25
  && apt-get install -y --no-install-recommends \
26
  unzip \
27
  nano \
28
+ git \
29
  g++ \
30
  gcc \
31
  htop \
README.md CHANGED
@@ -8,15 +8,30 @@ pinned: false
8
  short_description: Digiwild
9
  ---
10
 
11
- # digiwild
12
 
13
- ## Docker
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
  ``` bash
16
  docker build -t ordes/digiwild .
17
  ```
18
 
19
-
20
  ``` bash
21
  docker run -it -p 7860:7860 ordes/digiwild
22
  ```
@@ -26,26 +41,9 @@ cd /digiwild/app
26
  python3 main.py
27
  ```
28
 
29
- ### How to develop on docker
30
 
31
  ``` bash
32
  docker run -it -p 7860:7860 -v $(pwd):/home/user/digiwild/ --entrypoint bash ordes/digiwild
33
  ```
34
 
35
- ## TODO
36
-
37
- - [x] Change `wounded` to `wounded / sick`
38
- - [x] Info formatting
39
- - [x] Use in memory object instead of files to avoid writting / reading problems.
40
- - [ ] Connection to a database? Maybe an open MongoDB
41
- - [x] GPS Compatibility
42
- - [x] New fields suggested: Number individuals, Species, Comments
43
- - [ ] Add info and placeholder information to the different components.
44
-
45
- ## Needs
46
-
47
- - Camera with multiples pictures?
48
- - Uploading of pics
49
- - GPS location
50
- - Comments
51
- - Symptomps selection (Dropdown)
 
8
  short_description: Digiwild
9
  ---
10
 
11
+ # Digiwild
12
 
13
+ # Wilf Life monitoring - Bird Monitoring Use-Case
14
+
15
+ ## About
16
+
17
+ This work stemmed from a fruitful collaboration between [Swiss Data Science Center](https://www.datascience.ch) and [Institute for Fish and Wildlife Health, University of Bern](https://www.fiwi.vetsuisse.unibe.ch).
18
+ The resulting [Gradio App is available to use on Hugging Face](https://huggingface.co/spaces/SDSC/digiwild), which is coupled to the [digiwild Hugging Face Dataset](https://huggingface.co/datasets/SDSC/digiwild-dataset).
19
+ Credits and special thanks for the project can be found in the `About` section of the app.
20
+
21
+ ## How to Contact Us?
22
+
23
+ For **code contribution and any technical issues**, please open an `Issue` on this repository, we will address it as soon as possible. For enhancing the app, please open a PR, we welcome any and all enhancements or fixes.
24
+
25
+ For **usage of the app and any monitoring related questions**, please reach out to FIWI via [their contacts](https://www.fiwi.vetsuisse.unibe.ch/about_us/team/index_eng.html).
26
+
27
+ ## Development and Local set-up
28
+
29
+ ### Docker
30
 
31
  ``` bash
32
  docker build -t ordes/digiwild .
33
  ```
34
 
 
35
  ``` bash
36
  docker run -it -p 7860:7860 ordes/digiwild
37
  ```
 
41
  python3 main.py
42
  ```
43
 
44
+ How to develop on docker:
45
 
46
  ``` bash
47
  docker run -it -p 7860:7860 -v $(pwd):/home/user/digiwild/ --entrypoint bash ordes/digiwild
48
  ```
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/.env.dist CHANGED
@@ -1 +1,2 @@
1
- PATH_ASSETS="YOUR_PATH_HERE"
 
 
1
+ PATH_ASSETS="YOUR_PATH_HERE"
2
+ HF_TOKEN="hf_YOUR_TOKEN"
app/about.py CHANGED
@@ -2,17 +2,18 @@ import gradio as gr
2
 
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_ICONS = PATH + PATH_ASSETS + "icons/"
9
 
10
  credits_text = """
11
  # Credits
12
 
13
- This work stemmed from a fruitful collaboration between SDSC and FIWI.
14
 
15
- ## Scientific Expertise : FIWI from UniBE
16
 
17
  From the [Institute for Fish and Wildlife Health, University of Bern](https://www.fiwi.vetsuisse.unibe.ch)
18
  - **Isabelle Wethli**
@@ -25,11 +26,11 @@ From the [Swiss Data Science Center](https://www.datascience.ch)
25
  - **Carlos Viviar Rios**
26
  - **Laure Vancauwenberghe**
27
 
28
- ## How to Contact Us?
29
 
30
  Please reach out to FIWI via [their contacts](https://www.fiwi.vetsuisse.unibe.ch/about_us/team/index_eng.html).
31
 
32
- ## Special Thanks
33
 
34
  - **Vogelwarte** for their advice, especially Samuel Wechsler.
35
  - **Biolovision SA**, providers of **ornitho.ch**, for their collaboration: circumstances are matched to their current data collection schema on ornitho.ch
@@ -40,7 +41,7 @@ icons_text = """
40
  ### Icons' Attributions
41
  (scroll to see all)
42
 
43
- Biolovision for the circumstances icons.
44
 
45
  flying-doves-group: <a href="https://www.flaticon.com/free-icons/animal" title="animal icons">Animal icons created by Freepik - Flaticon</a>
46
 
@@ -81,18 +82,26 @@ help: <a href="https://www.flaticon.com/free-icons/help" title="help icons">Help
81
  question: <a href="https://www.flaticon.com/free-icons/question" title="question icons">Question icons created by Freepik - Flaticon</a>
82
  """
83
 
84
- with gr.Blocks(theme='shivi/calm_seafoam') as about:
85
- with gr.Row(scale = 1):
86
- gr.Image(PATH_ICONS+"sdsc.png",
87
- height=200,
88
- interactive=False,
89
- show_fullscreen_button = False, show_share_button=False,
90
- show_download_button=False, show_label=False)
91
- gr.Image(PATH_ICONS+"fiwi.png",
92
- height=200,
93
- interactive=False,
94
- show_fullscreen_button = False, show_share_button=False,
95
- show_download_button=False, show_label=False)
96
-
 
 
 
 
 
 
 
 
97
  gr.Markdown(credits_text, show_label=False)
98
- gr.Markdown(icons_text, show_label=False, height=100)
 
2
 
3
  from dotenv import load_dotenv
4
  import os
5
+
6
  load_dotenv()
7
  PATH = os.getcwd() + "/"
8
+ PATH_ASSETS = os.getenv("PATH_ASSETS")
9
  PATH_ICONS = PATH + PATH_ASSETS + "icons/"
10
 
11
  credits_text = """
12
  # Credits
13
 
14
+ This work stemmed from a fruitful collaboration between SDSC and FIWI.
15
 
16
+ ## Scientific Expertise : FIWI from UniBE
17
 
18
  From the [Institute for Fish and Wildlife Health, University of Bern](https://www.fiwi.vetsuisse.unibe.ch)
19
  - **Isabelle Wethli**
 
26
  - **Carlos Viviar Rios**
27
  - **Laure Vancauwenberghe**
28
 
29
+ ## How to Contact Us?
30
 
31
  Please reach out to FIWI via [their contacts](https://www.fiwi.vetsuisse.unibe.ch/about_us/team/index_eng.html).
32
 
33
+ ## Special Thanks
34
 
35
  - **Vogelwarte** for their advice, especially Samuel Wechsler.
36
  - **Biolovision SA**, providers of **ornitho.ch**, for their collaboration: circumstances are matched to their current data collection schema on ornitho.ch
 
41
  ### Icons' Attributions
42
  (scroll to see all)
43
 
44
+ Biolovision for the circumstances icons.
45
 
46
  flying-doves-group: <a href="https://www.flaticon.com/free-icons/animal" title="animal icons">Animal icons created by Freepik - Flaticon</a>
47
 
 
82
  question: <a href="https://www.flaticon.com/free-icons/question" title="question icons">Question icons created by Freepik - Flaticon</a>
83
  """
84
 
85
+ with gr.Blocks(theme="shivi/calm_seafoam") as about:
86
+ with gr.Row(scale=1):
87
+ gr.Image(
88
+ PATH_ICONS + "sdsc.png",
89
+ height=200,
90
+ interactive=False,
91
+ show_fullscreen_button=False,
92
+ show_share_button=False,
93
+ show_download_button=False,
94
+ show_label=False,
95
+ )
96
+ gr.Image(
97
+ PATH_ICONS + "fiwi.png",
98
+ height=200,
99
+ interactive=False,
100
+ show_fullscreen_button=False,
101
+ show_share_button=False,
102
+ show_download_button=False,
103
+ show_label=False,
104
+ )
105
+
106
  gr.Markdown(credits_text, show_label=False)
107
+ gr.Markdown(icons_text, show_label=False, height=100)
app/assets/config/config_checkbox_behavior.json CHANGED
@@ -35,8 +35,8 @@
35
  {
36
  "Description": "Non responsive, does not fly away when approached, lethargy"
37
  },
38
- "No changes":
39
  {
40
  "Description": "Animal is acting normally"
41
  }
42
- }
 
35
  {
36
  "Description": "Non responsive, does not fly away when approached, lethargy"
37
  },
38
+ "No changes":
39
  {
40
  "Description": "Animal is acting normally"
41
  }
42
+ }
app/assets/config/config_checkbox_behavior_simple.json CHANGED
@@ -11,8 +11,8 @@
11
  {
12
  "Description": "Circling, incoordination, tremors, convulsions"
13
  },
14
- "No changes":
15
  {
16
  "Description": "Animal is acting normally"
17
  }
18
- }
 
11
  {
12
  "Description": "Circling, incoordination, tremors, convulsions"
13
  },
14
+ "No changes":
15
  {
16
  "Description": "Animal is acting normally"
17
  }
18
+ }
app/assets/config/config_checkbox_physical.json CHANGED
@@ -27,7 +27,7 @@
27
  "Description": "Unusual beak growth"
28
  }
29
  },
30
- "Body":
31
  {
32
  "Emaciation": {
33
  "Description": "Breast muscles are not well developed"},
@@ -49,7 +49,7 @@
49
  "Missing limb": {
50
  "Description": "Missing limb"}
51
  },
52
- "Head incl. eyes":
53
  {
54
  "Ear changes": {
55
  "Description": "Swollen, crusts, plugged, discharge"},
 
27
  "Description": "Unusual beak growth"
28
  }
29
  },
30
+ "Body":
31
  {
32
  "Emaciation": {
33
  "Description": "Breast muscles are not well developed"},
 
49
  "Missing limb": {
50
  "Description": "Missing limb"}
51
  },
52
+ "Head incl. eyes":
53
  {
54
  "Ear changes": {
55
  "Description": "Swollen, crusts, plugged, discharge"},
app/assets/config/config_checkbox_physical_simple.json CHANGED
@@ -12,14 +12,14 @@
12
  "Description": "Material (food, saliva) around/ in the beak, discharge from ears/ eyes/ beak/ nose"
13
  }
14
  },
15
- "Body":
16
  {},
17
  "Feathers/Wings/Tail":
18
  {
19
  "Feathers and skin change": {
20
  "Description": "Blackened/ burnt skin or feathers, deformed feathers, ear changes (swollen, crusts, plugged, discharge), discolored/ missing/ broken/ stained feathers, fluffed up plumage, warts/ crusts/ tumor-like growth, parasites"}
21
  },
22
- "Head incl. eyes":
23
  {
24
  "Eye changes": {
25
  "Description": "Swollen, reddened, closed, discharge, crusts"}
 
12
  "Description": "Material (food, saliva) around/ in the beak, discharge from ears/ eyes/ beak/ nose"
13
  }
14
  },
15
+ "Body":
16
  {},
17
  "Feathers/Wings/Tail":
18
  {
19
  "Feathers and skin change": {
20
  "Description": "Blackened/ burnt skin or feathers, deformed feathers, ear changes (swollen, crusts, plugged, discharge), discolored/ missing/ broken/ stained feathers, fluffed up plumage, warts/ crusts/ tumor-like growth, parasites"}
21
  },
22
+ "Head incl. eyes":
23
  {
24
  "Eye changes": {
25
  "Description": "Swollen, reddened, closed, discharge, crusts"}
app/assets/config/config_dropdown_circumstances.json CHANGED
@@ -1,14 +1,14 @@
1
  {
2
- "Collision with a means of transport":
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
  },
@@ -17,34 +17,34 @@
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
  },
@@ -55,7 +55,7 @@
55
  {
56
  "pylone and electric grid":
57
  {
58
-
59
  "Options": {
60
  "infrastructure" : ["electric line", "pole/pylon", "other structure", "unknown structure"]
61
  },
@@ -65,35 +65,35 @@
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
  }
@@ -101,22 +101,22 @@
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"]
@@ -125,7 +125,7 @@
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"]
 
1
  {
2
+ "Collision with a means of transport":
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
  },
 
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
  },
 
55
  {
56
  "pylone and electric grid":
57
  {
58
+
59
  "Options": {
60
  "infrastructure" : ["electric line", "pole/pylon", "other structure", "unknown structure"]
61
  },
 
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
  }
 
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"]
 
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"]
app/assets/config/config_followup.json CHANGED
@@ -1,5 +1,5 @@
1
  {
2
- "Event follow-up":
3
  {
4
  "Animal collected": {
5
  "Options": ["Yes", "No"]
@@ -20,4 +20,4 @@
20
  "Open": {}
21
  }
22
  }
23
- }
 
1
  {
2
+ "Event follow-up":
3
  {
4
  "Animal collected": {
5
  "Options": ["Yes", "No"]
 
20
  "Open": {}
21
  }
22
  }
23
+ }
app/behavior/class_behavior.py CHANGED
@@ -1,51 +1,71 @@
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,
@@ -57,9 +77,10 @@ BehaviorType = Union[
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"
 
1
  from pydantic import BaseModel, Field
2
  from typing import Literal, List, Union, Optional
3
 
4
+
5
  class Behavior(BaseModel):
6
  type: str
7
  description: Optional[str] = None # Making the description field optional
8
 
9
+
10
  # --- Specific Behavior classes ---
11
  class AbnormalBreathing(Behavior):
12
+ type: Literal["abnormal breathing"]
13
  description: Optional[Literal["Problems breathing, breathing sounds"]] = None
14
 
15
+
16
  class CrashFalling(Behavior):
17
+ type: Literal["crash, falling from the sky"]
18
  description: Optional[Literal["Suddenly falling from the sky"]] = None
19
 
20
+
21
  class Diarrhea(Behavior):
22
+ type: Literal["diarrhea"]
23
  description: Optional[Literal["Observed diarrhea"]] = None
24
 
25
+
26
  class Lameness(Behavior):
27
+ type: Literal["lameness"]
28
+ description: Optional[
29
+ Literal["Apparent limping or not able to walk properly"]
30
+ ] = None
31
+
32
 
33
  class Neurological(Behavior):
34
+ type: Literal["neurological"]
35
+ description: Optional[
36
+ Literal["Circling, incoordination, tremors, convulsions, fast eye movements"]
37
+ ] = None
38
+
39
 
40
  class OtherAbnormalBehavior(Behavior):
41
+ type: Literal["other abnormal behavior"]
42
  description: Optional[Literal["Other than weakness, other than neurologic"]] = None
43
 
44
+
45
  class UnableToFly(Behavior):
46
+ type: Literal["unable to fly"]
47
+ description: Optional[
48
+ Literal["Animal alert and tries to fly but can not take off"]
49
+ ] = None
50
+
51
 
52
  class Vomiting(Behavior):
53
+ type: Literal["vomiting"]
54
  description: Optional[Literal["Throwing up undigested food, regurgitating"]] = None
55
 
56
+
57
  class Weakness(Behavior):
58
+ type: Literal["weakness"]
59
+ description: Optional[
60
+ Literal["Non responsive, does not fly away when approached, lethargy"]
61
+ ] = None
62
+
63
 
64
  class NoChanges(Behavior):
65
+ type: Literal["no changes"]
66
  description: Optional[Literal["Animal is acting normally"]] = None
67
 
68
+
69
  # Union of all possible behaviors
70
  BehaviorType = Union[
71
  AbnormalBreathing,
 
77
  UnableToFly,
78
  Vomiting,
79
  Weakness,
80
+ NoChanges,
81
  ]
82
 
83
+
84
  # Main class that logs multiple behaviors
85
  class Behaviors(BaseModel):
86
  behaviors_radio: str # e.g., "Yes"
app/circumstances/circumstances.py CHANGED
@@ -7,61 +7,118 @@ from validation_submission.utils_individual import add_data_to_individual
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, individual):
17
  visible = set_visible(choice)
18
- individual = add_data_to_individual(
19
- "circumstance_radio",
20
- choice, individual)
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, individual
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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...",
60
- visible=visible, interactive=False, elem_id="dropdown-conditions")
 
 
 
 
61
  openfield_level2 = gr.Textbox(visible=False, elem_id="dropdown-conditions")
62
- dropdown_level2 = gr.Dropdown(choices=[], visible=False, elem_id="dropdown-conditions")
63
- dropdown_extra_level2 = gr.Dropdown(choices=[], visible=False, elem_id="dropdown-conditions")
 
 
 
 
64
  return dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2
65
-
66
-
67
-
 
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, individual):
17
  visible = set_visible(choice)
18
+ individual = add_data_to_individual("circumstance_radio", choice, individual)
19
+ (
20
+ button_collision,
21
+ button_deliberate_destruction,
22
+ button_indirect_destruction,
23
+ button_natural_cause,
24
+ dropdown,
25
+ dropdown_level2,
26
+ openfield_level2,
27
+ dropdown_extra_level2,
28
+ ) = create_circumstances(visible)
29
+ return (
30
+ button_collision,
31
+ button_deliberate_destruction,
32
+ button_indirect_destruction,
33
+ button_natural_cause,
34
+ dropdown,
35
+ dropdown_level2,
36
+ openfield_level2,
37
+ dropdown_extra_level2,
38
+ individual,
39
+ )
40
+
41
 
42
  def create_circumstances(visible):
43
+ (
44
+ button_collision,
45
+ button_deliberate_destruction,
46
+ button_indirect_destruction,
47
+ button_natural_cause,
48
+ ) = create_circumstances_buttons(visible)
49
+ (
50
+ dropdown,
51
+ dropdown_level2,
52
+ openfield_level2,
53
+ dropdown_extra_level2,
54
+ ) = create_circumstances_dropdown(visible)
55
+ return (
56
+ button_collision,
57
+ button_deliberate_destruction,
58
+ button_indirect_destruction,
59
+ button_natural_cause,
60
+ dropdown,
61
+ dropdown_level2,
62
+ openfield_level2,
63
+ dropdown_extra_level2,
64
+ )
65
+
66
 
67
+ def create_circumstances_buttons(visible):
68
  with gr.Row() as image_row:
69
+ with gr.Column(scale=1, min_width=CAUSE_COL_WIDTH):
70
+ button_collision = gr.Button(
71
+ "Collision with a means of transport",
72
+ visible=visible,
73
+ icon=LOGO_PATH + "/van.png",
74
+ elem_id="buttons-conditions",
75
+ )
76
+
77
+ with gr.Column(scale=1, min_width=CAUSE_COL_WIDTH):
78
+ button_deliberate_destruction = gr.Button(
79
+ "Destruction / Deliberatly removed",
80
+ icon=LOGO_PATH + "/destruction.png",
81
+ visible=visible,
82
+ elem_id="buttons-conditions",
83
+ )
84
+
85
+ with gr.Column(scale=1, min_width=CAUSE_COL_WIDTH):
86
+ button_indirect_destruction = gr.Button(
87
+ "Indirect destruction",
88
+ icon=LOGO_PATH + "/indirect.png",
89
+ visible=visible,
90
+ elem_id="buttons-conditions",
91
+ )
92
+
93
+ with gr.Column(scale=1, min_width=CAUSE_COL_WIDTH):
94
+ button_natural_cause = gr.Button(
95
+ "Natural cause",
96
+ icon=LOGO_PATH + "/natural.png",
97
+ visible=visible,
98
+ elem_id="buttons-conditions",
99
+ )
100
+ return (
101
+ button_collision,
102
+ button_deliberate_destruction,
103
+ button_indirect_destruction,
104
+ button_natural_cause,
105
+ )
106
 
 
 
 
 
 
 
107
 
108
  def create_circumstances_dropdown(visible):
109
  with gr.Row() as dropdown_row:
110
+ dropdown = gr.Dropdown(
111
+ choices=[],
112
+ label="Choices will appear here...",
113
+ visible=visible,
114
+ interactive=False,
115
+ elem_id="dropdown-conditions",
116
+ )
117
  openfield_level2 = gr.Textbox(visible=False, elem_id="dropdown-conditions")
118
+ dropdown_level2 = gr.Dropdown(
119
+ choices=[], visible=False, elem_id="dropdown-conditions"
120
+ )
121
+ dropdown_extra_level2 = gr.Dropdown(
122
+ choices=[], visible=False, elem_id="dropdown-conditions"
123
+ )
124
  return dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2
 
 
 
app/circumstances/class_circumstance.py CHANGED
@@ -1,152 +1,264 @@
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 destruction']
 
102
 
103
  class UnknownIndirectDestruction(CircumstanceTypeBase):
104
- type: Literal['unknown indirect destruction']
 
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[
@@ -182,14 +294,15 @@ CircumstanceType = Union[
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
@@ -202,4 +315,4 @@ class Circumstances(BaseModel):
202
  # }
203
  # }
204
  # circumstance_instance = Circumstance(**json_data)
205
- # circumstance_schema = Circumstance.schema_json(indent=2)
 
1
  from pydantic import BaseModel, Field
2
  from typing import Literal, List, Union, Optional
3
 
4
+
5
  # Base class for CircumstanceType with a discriminator field 'type'
6
  class CircumstanceTypeBase(BaseModel):
7
  type: str
8
 
9
+
10
  # Collision with means of transport
11
  class RoadVehicleCollision(CircumstanceTypeBase):
12
+ type: Literal["road_vehicle"]
13
  infrastructure_number: Optional[str] = None
14
+ road_type: Literal[
15
+ "highway", "main road", "secondary road", "local road/path/trail", "parking lot"
16
+ ]
17
+
18
 
19
  class TrainCollision(CircumstanceTypeBase):
20
+ type: Literal["train"]
21
  infrastructure_number: str
22
 
23
+
24
  class AircraftCollision(CircumstanceTypeBase):
25
+ type: Literal["aircraft"]
26
+
27
 
28
  class BoatCollision(CircumstanceTypeBase):
29
+ type: Literal["boat"]
30
+
31
 
32
  class OtherTransportCollision(CircumstanceTypeBase):
33
+ type: Literal["other transport collision"]
34
+
35
 
36
  class UnknownTransportCollision(CircumstanceTypeBase):
37
+ type: Literal["unknown transport collision"]
38
+
39
 
40
  # Destruction / Deliberately removed
41
  class HuntingDestruction(CircumstanceTypeBase):
42
+ type: Literal["hunting"]
43
+ method: Literal[
44
+ "shooting",
45
+ "bow",
46
+ "falconry",
47
+ "hounds hunting",
48
+ "digging up",
49
+ "other hunting",
50
+ "unknow hunting",
51
+ ]
52
+
53
 
54
  class TrapDestruction(CircumstanceTypeBase):
55
+ type: Literal["trap"]
56
+ method: Literal[
57
+ "killing trap",
58
+ "pole trap",
59
+ "trap cage",
60
+ "corvids nasse",
61
+ "net",
62
+ "cage trap",
63
+ "fall-trap",
64
+ "glue trap",
65
+ "insect trap",
66
+ "other trap",
67
+ "unknown trap",
68
+ ]
69
+
70
 
71
  class PoisoningDestruction(CircumstanceTypeBase):
72
+ type: Literal["poisoning"]
73
+
74
 
75
  class RemovalDestruction(CircumstanceTypeBase):
76
+ type: Literal["removal or direct capture"]
77
+ method: Literal[
78
+ "gassing",
79
+ "raptor captured at nest",
80
+ "brood destruction",
81
+ "traffic/trade",
82
+ "capture accident",
83
+ "scientific sample",
84
+ "other removal",
85
+ "unknown removal",
86
+ ]
87
+
88
 
89
  class FishingDestruction(CircumstanceTypeBase):
90
+ type: Literal["fishing"]
91
+ method: Literal[
92
+ "drowned/tangled",
93
+ "beached with capture indications",
94
+ "other fishing",
95
+ "unknown fishing",
96
+ ]
97
+
98
 
99
  class OtherDestruction(CircumstanceTypeBase):
100
+ type: Literal["other destruction"]
101
+
102
 
103
  class UnknownDestruction(CircumstanceTypeBase):
104
+ type: Literal["unknown destruction"]
105
+
106
 
107
  # Indirect destruction
108
  class PylonElectricGridDestruction(CircumstanceTypeBase):
109
+ type: Literal["pylone and electric grid"]
110
+ infrastructure: Literal[
111
+ "electric line", "pole/pylon", "other structure", "unknown structure"
112
+ ]
113
+ cause: Literal["collision", "electrocution"]
114
+
115
 
116
  class WindfarmDestruction(CircumstanceTypeBase):
117
+ type: Literal["windfarm"]
118
+
119
 
120
  class OtherCollisionDestruction(CircumstanceTypeBase):
121
+ type: Literal["other collision"]
122
+ object: Literal[
123
+ "window",
124
+ "building",
125
+ "lighthouse",
126
+ "cable",
127
+ "wire fence/barbed wire",
128
+ "other crash",
129
+ "unknown crash",
130
+ ]
131
+
132
 
133
  class FallDestruction(CircumstanceTypeBase):
134
+ type: Literal["fall"]
135
+ location: Literal[
136
+ "chimney", "empty pole", "hole/well", "other fall", "unknown fall"
137
+ ]
138
+
139
 
140
  class DevelopmentWorkDestruction(CircumstanceTypeBase):
141
+ type: Literal["development work"]
142
+ work_type: Literal[
143
+ "transport infrastructure", "building", "other work", "unknown work"
144
+ ]
145
+
146
 
147
  class PollutionContaminationDestruction(CircumstanceTypeBase):
148
+ type: Literal["pollution / contamination"]
149
+ pollution_type: Literal[
150
+ "oil pollution",
151
+ "chemical pollution",
152
+ "heavy metals",
153
+ "light",
154
+ "noise",
155
+ "plastic ingestion",
156
+ "other pollution",
157
+ "unknown pollution",
158
+ ]
159
+
160
 
161
  class AgriculturalNetProtectionDestruction(CircumstanceTypeBase):
162
+ type: Literal["agricultural net protection"]
163
+
164
 
165
  class VegetalForestWorkDestruction(CircumstanceTypeBase):
166
+ type: Literal["vegetal / forest work"]
167
+ work_type: Literal[
168
+ "clearing/mowing/plowing",
169
+ "tree felling/pruning",
170
+ "other forest work",
171
+ "unknown forest work",
172
+ ]
173
+
174
 
175
  class OtherIndirectDestruction(CircumstanceTypeBase):
176
+ type: Literal["other indirect destruction"]
177
+
178
 
179
  class UnknownIndirectDestruction(CircumstanceTypeBase):
180
+ type: Literal["unknown indirect destruction"]
181
+
182
 
183
  # Natural cause
184
  class Predation(CircumstanceTypeBase):
185
+ type: Literal["predation"]
186
+ predator: Literal[
187
+ "cat",
188
+ "dog",
189
+ "rooster/hen",
190
+ "other domestic animal",
191
+ "wild birds",
192
+ "wild mammal",
193
+ "other predator",
194
+ "unknown predator",
195
+ ]
196
+
197
 
198
  class Weather(CircumstanceTypeBase):
199
+ type: Literal["weather"]
200
+ condition: Literal[
201
+ "cold wave",
202
+ "drought",
203
+ "hail",
204
+ "lightening",
205
+ "storm",
206
+ "other weather",
207
+ "unknown weather",
208
+ ]
209
+
210
 
211
  class NaturalDisaster(CircumstanceTypeBase):
212
+ type: Literal["natural disaster"]
213
+ disaster: Literal[
214
+ "fire",
215
+ "avalanche",
216
+ "rock fall",
217
+ "mudslide",
218
+ "volcanic eruption/ashes",
219
+ "other natural disaster",
220
+ "unknown natural disaster",
221
+ ]
222
+
223
 
224
  class NestFall(CircumstanceTypeBase):
225
+ type: Literal["nest fall"]
226
+
227
 
228
  class StrandingExhaustion(CircumstanceTypeBase):
229
+ type: Literal["stranding due to exhaustion"]
230
+
231
 
232
  class DiseaseParasite(CircumstanceTypeBase):
233
+ type: Literal["disease/parasite"]
234
+
235
 
236
  class AccidentalDrowning(CircumstanceTypeBase):
237
+ type: Literal["accidental drowning"]
238
+ drowning_location: Literal[
239
+ "drinking trough",
240
+ "pool",
241
+ "storm pool",
242
+ "irrigation pool",
243
+ "natural pool",
244
+ "flood",
245
+ "other location",
246
+ "unknown location",
247
+ ]
248
+
249
 
250
  class OtherNaturalCause(CircumstanceTypeBase):
251
+ type: Literal["other natural cause"]
252
+
253
 
254
  class UnknownNaturalCause(CircumstanceTypeBase):
255
+ type: Literal["unknown natural cause"]
256
+
257
 
258
  # Unknown cause
259
  class UnknownCircumstance(CircumstanceTypeBase):
260
+ type: Literal["unknown"]
261
+
262
 
263
  # Union of all possible CircumstanceTypes with 'type' as the discriminator
264
  CircumstanceType = Union[
 
294
  AccidentalDrowning,
295
  OtherNaturalCause,
296
  UnknownNaturalCause,
297
+ UnknownCircumstance,
298
  ]
299
 
300
+
301
  # Main Circumstance class
302
  class Circumstances(BaseModel):
303
  circumstance_radio: str # e.g., "Yes"
304
  circumstance: Optional[str] = None # e.g., "COLLISION"
305
+ circumstance_type: Optional[CircumstanceType] = Field(None, discriminator="type")
306
 
307
 
308
  # Example usage
 
315
  # }
316
  # }
317
  # circumstance_instance = Circumstance(**json_data)
318
+ # circumstance_schema = Circumstance.schema_json(indent=2)
app/contacts.py CHANGED
@@ -2,109 +2,124 @@ import gradio as gr
2
 
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_ICONS = PATH + PATH_ASSETS + "icons/"
9
 
10
  contact_text = """
11
  # Contacts
12
 
13
- You have an animal alive or dead in front of you and you do not know what to do?
14
  Please call the contact below corresponding to your canton. (Cantons are in alphabetical order.)
15
 
16
  ## AG: Aargau
17
  117 | Departement Bau, Verkehr und Umwelt, Abteilung Wald, Sektion Jagd und Fischerei
18
 
19
  ## AI: Appenzell Innerrhoden
20
- 071 788 92 87 | Bau- und Umweltdepartement, Amt für Umwelt, Fachstelle Jagd und Fischerei
21
 
22
  ## AR: Appenzell Ausserrhoden
23
- 079 698 19 16 |Departement Bau und Volkswirtschaft, Amt für Raum und Wald, Abteilung Natur und Wildtiere
24
 
25
  ## BE: Bern
26
- 0800 940 100 | Wirtschafts-, Energie- und Umweltdirektion
27
 
28
  ## BL: Basel-Landschaft
29
- 061 922 03 66, 061 552 56 59 | Volkswirtschafts- und Gesundheitsdirektion, Amt für Wald und Wild beider Basel
30
 
31
  ## BS: Basel-Stadt
32
- 061 922 03 66, 061 552 56 59 | Volkswirtschafts- und Gesundheitsdirektion, Amt für Wald und Wild beider Basel
33
 
34
  ## FR: Fribourg
35
  026 305 23 31 | Energie, Landwirtschaft und Umwelt, Amt für Wald und Natur, Sektion Fauna, Jagd und Fischerei
36
 
37
  ## GE: Geneva
38
- 022 388 55 00 | Office cantonal de l'agriculture et de la nature, Centrale d'engagement et des transmissions (CET)
39
 
40
  ## GL: Glarus
41
- Verwaltung Bau und Umwelt, Umwelt, Wald und Energie, Jagd und Fischerei
42
 
43
  ## GR: Graubünden
44
  055 645 66 66 | Amt für Jagd und Fischerei Jagdbezirke - Über uns
45
 
46
- ## JU: Jura
47
- 032 420 48 00, 032 420 65 65 | Departement de l'environnement, Office de l'environnement, Chasse et protection de la faune sauvage
48
 
49
  ## LU: Luzern
50
- 041 248 81 17, 117 | Bau-, Umwelt- und Wirtschaftsdepartement, Landwirtschaft und Wald, Jagd, Wildhut und Jagdaufsicht
51
 
52
  ## NE: Neuchatel
53
- 032 889 67 80 | Service de la faune, des fôrets et de la nature, faune
54
 
55
  ## NW: Nidwalden
56
- 041 618 44 66 | Justiz- und Sicherheitsdirektion, Amt für Justiz, Abteilung Jagd und Fischerei
57
 
58
  ## OW: Obwalden
59
- 041 666 64 76 | Bau- und Raumentwicklungsdepartement, Amt für Wald und Landschaft, Wildtiere und Jagd
60
 
61
  ## SG: St. Gallen
62
- 117 | Volkwirtschaftsdepartement, Amt für Natur, Jagd und Fischerei
63
 
64
  ## SH: Schaffhausen
65
- 052 632 74 66 | Departement des Innern, Jagd und Fischerei
66
 
67
  ## SO: Solothurn
68
  117| Volkswirtschaftdepartement, Amt für Wald, Jagd und Fischerei
69
 
70
  ## SZ: Schwyz
71
- 041 819 29 29 | Umweltdepartement, Amt für Wald und Natur, Jagd und Wildtiere
72
 
73
  ## TG: Thurgau
74
- 058 345 61 50 | Jagd- und Fischereiverwaltung
75
 
76
  ## TI: Ticino
77
- 091 814 28 71 | Divisione dell'ambiente, Ufficio della caccia e della pesca
78
 
79
  ## UR: Uri
80
- 041 875 2316 | Sicherheitsdirektion, Amt für Forst und Jagd
81
 
82
- ## VD: Vaud
83
- 021 557 88 55 | Environnement, Biodiversité et paysage, Police Faune-nature
84
 
85
  ## VS: Valais
86
- 027 606 70 00, 117 | Umwelt, Energie und Landwirtschaft, Dienststelle für Jagd, Fischerei und Wildtiere
87
 
88
  ## ZG: Zug
89
- 041 595 41 41 | Natur, Umwelt und Tiere, Arten, Lebensräume, Wildhut und Fischereiaufsicht
90
 
91
  """
92
 
93
 
94
- with gr.Blocks(theme='shivi/calm_seafoam') as contacts:
95
- with gr.Row(scale = 1):
96
- gr.Image(PATH_ICONS+"help.png", height=300,
97
- interactive=False,
98
- show_fullscreen_button = False, show_share_button=False,
99
- show_download_button=False, show_label=False)
100
- gr.Image(PATH_ICONS+"contact-information.png", height=300,
101
- interactive=False,
102
- show_fullscreen_button = False, show_share_button=False,
103
- show_download_button=False, show_label=False)
104
- gr.Image(PATH_ICONS+"question.png", height=300,
105
- interactive=False,
106
- show_fullscreen_button = False, show_share_button=False,
107
- show_download_button=False, show_label=False)
108
-
109
- gr.Markdown(contact_text, show_label=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
 
 
2
 
3
  from dotenv import load_dotenv
4
  import os
5
+
6
  load_dotenv()
7
  PATH = os.getcwd() + "/"
8
+ PATH_ASSETS = os.getenv("PATH_ASSETS")
9
  PATH_ICONS = PATH + PATH_ASSETS + "icons/"
10
 
11
  contact_text = """
12
  # Contacts
13
 
14
+ You have an animal alive or dead in front of you and you do not know what to do?
15
  Please call the contact below corresponding to your canton. (Cantons are in alphabetical order.)
16
 
17
  ## AG: Aargau
18
  117 | Departement Bau, Verkehr und Umwelt, Abteilung Wald, Sektion Jagd und Fischerei
19
 
20
  ## AI: Appenzell Innerrhoden
21
+ 071 788 92 87 | Bau- und Umweltdepartement, Amt für Umwelt, Fachstelle Jagd und Fischerei
22
 
23
  ## AR: Appenzell Ausserrhoden
24
+ 079 698 19 16 |Departement Bau und Volkswirtschaft, Amt für Raum und Wald, Abteilung Natur und Wildtiere
25
 
26
  ## BE: Bern
27
+ 0800 940 100 | Wirtschafts-, Energie- und Umweltdirektion
28
 
29
  ## BL: Basel-Landschaft
30
+ 061 922 03 66, 061 552 56 59 | Volkswirtschafts- und Gesundheitsdirektion, Amt für Wald und Wild beider Basel
31
 
32
  ## BS: Basel-Stadt
33
+ 061 922 03 66, 061 552 56 59 | Volkswirtschafts- und Gesundheitsdirektion, Amt für Wald und Wild beider Basel
34
 
35
  ## FR: Fribourg
36
  026 305 23 31 | Energie, Landwirtschaft und Umwelt, Amt für Wald und Natur, Sektion Fauna, Jagd und Fischerei
37
 
38
  ## GE: Geneva
39
+ 022 388 55 00 | Office cantonal de l'agriculture et de la nature, Centrale d'engagement et des transmissions (CET)
40
 
41
  ## GL: Glarus
42
+ Verwaltung Bau und Umwelt, Umwelt, Wald und Energie, Jagd und Fischerei
43
 
44
  ## GR: Graubünden
45
  055 645 66 66 | Amt für Jagd und Fischerei Jagdbezirke - Über uns
46
 
47
+ ## JU: Jura
48
+ 032 420 48 00, 032 420 65 65 | Departement de l'environnement, Office de l'environnement, Chasse et protection de la faune sauvage
49
 
50
  ## LU: Luzern
51
+ 041 248 81 17, 117 | Bau-, Umwelt- und Wirtschaftsdepartement, Landwirtschaft und Wald, Jagd, Wildhut und Jagdaufsicht
52
 
53
  ## NE: Neuchatel
54
+ 032 889 67 80 | Service de la faune, des fôrets et de la nature, faune
55
 
56
  ## NW: Nidwalden
57
+ 041 618 44 66 | Justiz- und Sicherheitsdirektion, Amt für Justiz, Abteilung Jagd und Fischerei
58
 
59
  ## OW: Obwalden
60
+ 041 666 64 76 | Bau- und Raumentwicklungsdepartement, Amt für Wald und Landschaft, Wildtiere und Jagd
61
 
62
  ## SG: St. Gallen
63
+ 117 | Volkwirtschaftsdepartement, Amt für Natur, Jagd und Fischerei
64
 
65
  ## SH: Schaffhausen
66
+ 052 632 74 66 | Departement des Innern, Jagd und Fischerei
67
 
68
  ## SO: Solothurn
69
  117| Volkswirtschaftdepartement, Amt für Wald, Jagd und Fischerei
70
 
71
  ## SZ: Schwyz
72
+ 041 819 29 29 | Umweltdepartement, Amt für Wald und Natur, Jagd und Wildtiere
73
 
74
  ## TG: Thurgau
75
+ 058 345 61 50 | Jagd- und Fischereiverwaltung
76
 
77
  ## TI: Ticino
78
+ 091 814 28 71 | Divisione dell'ambiente, Ufficio della caccia e della pesca
79
 
80
  ## UR: Uri
81
+ 041 875 2316 | Sicherheitsdirektion, Amt für Forst und Jagd
82
 
83
+ ## VD: Vaud
84
+ 021 557 88 55 | Environnement, Biodiversité et paysage, Police Faune-nature
85
 
86
  ## VS: Valais
87
+ 027 606 70 00, 117 | Umwelt, Energie und Landwirtschaft, Dienststelle für Jagd, Fischerei und Wildtiere
88
 
89
  ## ZG: Zug
90
+ 041 595 41 41 | Natur, Umwelt und Tiere, Arten, Lebensräume, Wildhut und Fischereiaufsicht
91
 
92
  """
93
 
94
 
95
+ with gr.Blocks(theme="shivi/calm_seafoam") as contacts:
96
+ with gr.Row(scale=1):
97
+ gr.Image(
98
+ PATH_ICONS + "help.png",
99
+ height=300,
100
+ interactive=False,
101
+ show_fullscreen_button=False,
102
+ show_share_button=False,
103
+ show_download_button=False,
104
+ show_label=False,
105
+ )
106
+ gr.Image(
107
+ PATH_ICONS + "contact-information.png",
108
+ height=300,
109
+ interactive=False,
110
+ show_fullscreen_button=False,
111
+ show_share_button=False,
112
+ show_download_button=False,
113
+ show_label=False,
114
+ )
115
+ gr.Image(
116
+ PATH_ICONS + "question.png",
117
+ height=300,
118
+ interactive=False,
119
+ show_fullscreen_button=False,
120
+ show_share_button=False,
121
+ show_download_button=False,
122
+ show_label=False,
123
+ )
124
 
125
+ gr.Markdown(contact_text, show_label=False)
app/dead_wounded/dead.py CHANGED
@@ -7,47 +7,106 @@ from validation_submission.utils_individual import add_data_to_individual
7
 
8
  from dotenv import load_dotenv
9
  import os
 
10
  load_dotenv()
11
  PATH = os.getcwd() + "/"
12
- PATH_ASSETS = os.getenv('PATH_ASSETS')
13
  PATH_ICONS = PATH + PATH_ASSETS + "icons/"
14
 
 
15
  def show_section_dead(visible, mode, individual):
16
- if visible==True:
17
  individual = add_data_to_individual("wounded_state", "No", individual)
18
  individual = add_data_to_individual("dead_state", "Yes", individual)
19
-
20
  with gr.Column(visible=visible, elem_id="dead") as section_dead:
21
  gr.Markdown("## The animal is dead.")
22
- gr.Button("Do you know what conditions caused this?",
23
- icon=PATH_ICONS + "eye.png",
24
- variant= "primary")
 
 
25
  # gr.Markdown("## Do you know what conditions caused this?", label="description")
26
- radio_cause = gr.Radio(["Yes", "No"], value=None, show_label=False, interactive=True)
27
- button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2 = create_circumstances(visible=False)
28
-
29
- gr.Button("Are there physical changes on the animal?",
30
- icon=PATH_ICONS + "cardiogram.png",
31
- variant= "primary")
32
- radio_physical = gr.Radio(["Yes", "No"], value=None, show_label=False, interactive=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  with gr.Row():
34
  physical_boxes = create_bird_anatomy(False, "dead")
35
  with gr.Column():
36
- checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs = process_body_parts("dead", mode, "None")
 
 
 
 
 
 
 
 
 
 
 
37
 
38
- gr.Button("Follow-Up Events",
39
- icon=PATH_ICONS + "schedule.png",
40
- variant= "primary")
41
  gr.Markdown("Please tell us what you did with the animal.", label="description")
42
- with gr.Row():
43
- fe_collection_dropdown, fe_recepient_dropdown, fe_radio_dropdown, fe_answer_dropdown = create_followup_dropdowns(visible, "dead")
44
- with gr.Row():
 
 
 
 
 
45
  fe_name_recipient, fe_collection_ref = create_followup_open(visible, "dead")
46
 
47
-
48
- return section_dead, individual, radio_cause, radio_physical,\
49
- button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, \
50
- dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2, \
51
- physical_boxes, \
52
- checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs, \
53
- fe_collection_dropdown, fe_recepient_dropdown, fe_radio_dropdown, fe_answer_dropdown, fe_name_recipient, fe_collection_ref
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
  from dotenv import load_dotenv
9
  import os
10
+
11
  load_dotenv()
12
  PATH = os.getcwd() + "/"
13
+ PATH_ASSETS = os.getenv("PATH_ASSETS")
14
  PATH_ICONS = PATH + PATH_ASSETS + "icons/"
15
 
16
+
17
  def show_section_dead(visible, mode, individual):
18
+ if visible == True:
19
  individual = add_data_to_individual("wounded_state", "No", individual)
20
  individual = add_data_to_individual("dead_state", "Yes", individual)
21
+
22
  with gr.Column(visible=visible, elem_id="dead") as section_dead:
23
  gr.Markdown("## The animal is dead.")
24
+ gr.Button(
25
+ "Do you know what conditions caused this?",
26
+ icon=PATH_ICONS + "eye.png",
27
+ variant="primary",
28
+ )
29
  # gr.Markdown("## Do you know what conditions caused this?", label="description")
30
+ radio_cause = gr.Radio(
31
+ ["Yes", "No"], value=None, show_label=False, interactive=True
32
+ )
33
+ (
34
+ button_collision,
35
+ button_deliberate_destruction,
36
+ button_indirect_destruction,
37
+ button_natural_cause,
38
+ dropdown,
39
+ dropdown_level2,
40
+ openfield_level2,
41
+ dropdown_extra_level2,
42
+ ) = create_circumstances(visible=False)
43
+
44
+ gr.Button(
45
+ "Are there physical changes on the animal?",
46
+ icon=PATH_ICONS + "cardiogram.png",
47
+ variant="primary",
48
+ )
49
+ radio_physical = gr.Radio(
50
+ ["Yes", "No"], value=None, show_label=False, interactive=True
51
+ )
52
  with gr.Row():
53
  physical_boxes = create_bird_anatomy(False, "dead")
54
  with gr.Column():
55
+ (
56
+ checkbox_beak,
57
+ text_beak,
58
+ checkbox_body,
59
+ text_body,
60
+ checkbox_feathers,
61
+ text_feathers,
62
+ checkbox_head,
63
+ text_head,
64
+ checkbox_legs,
65
+ text_legs,
66
+ ) = process_body_parts("dead", mode, "None")
67
 
68
+ gr.Button(
69
+ "Follow-Up Events", icon=PATH_ICONS + "schedule.png", variant="primary"
70
+ )
71
  gr.Markdown("Please tell us what you did with the animal.", label="description")
72
+ with gr.Row():
73
+ (
74
+ fe_collection_dropdown,
75
+ fe_recepient_dropdown,
76
+ fe_radio_dropdown,
77
+ fe_answer_dropdown,
78
+ ) = create_followup_dropdowns(visible, "dead")
79
+ with gr.Row():
80
  fe_name_recipient, fe_collection_ref = create_followup_open(visible, "dead")
81
 
82
+ return (
83
+ section_dead,
84
+ individual,
85
+ radio_cause,
86
+ radio_physical,
87
+ button_collision,
88
+ button_deliberate_destruction,
89
+ button_indirect_destruction,
90
+ button_natural_cause,
91
+ dropdown,
92
+ dropdown_level2,
93
+ openfield_level2,
94
+ dropdown_extra_level2,
95
+ physical_boxes,
96
+ checkbox_beak,
97
+ text_beak,
98
+ checkbox_body,
99
+ text_body,
100
+ checkbox_feathers,
101
+ text_feathers,
102
+ checkbox_head,
103
+ text_head,
104
+ checkbox_legs,
105
+ text_legs,
106
+ fe_collection_dropdown,
107
+ fe_recepient_dropdown,
108
+ fe_radio_dropdown,
109
+ fe_answer_dropdown,
110
+ fe_name_recipient,
111
+ fe_collection_ref,
112
+ )
app/dead_wounded/wounded.py CHANGED
@@ -4,61 +4,129 @@ 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.utils_individual import add_data_to_individual
8
 
9
  from dotenv import load_dotenv
10
  import os
 
11
  load_dotenv()
12
  PATH = os.getcwd() + "/"
13
- PATH_ASSETS = os.getenv('PATH_ASSETS')
14
  PATH_ICONS = PATH + PATH_ASSETS + "icons/"
15
 
 
16
  def show_section_wounded(visible, mode, individual):
17
- if visible==True:
18
  individual = add_data_to_individual("wounded_state", "Yes", individual)
19
  individual = add_data_to_individual("dead_state", "No", individual)
20
-
21
  with gr.Column(visible=visible, elem_id="wounded") as wounded_section:
22
  gr.Markdown("## The animal is wounded / sick.")
23
-
24
- gr.Button("Do you know what conditions caused this?",
25
- icon=PATH_ICONS + "eye.png",
26
- variant= "primary")
27
- radio_cause = gr.Radio(["Yes", "No"], value=None, show_label=False, interactive=True)
28
- button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2 = create_circumstances(visible=False)
29
 
30
- gr.Button("Is the animal displaying behavioural changes?",
31
- icon=PATH_ICONS + "neuron.png",
32
- variant= "primary")
33
- radio_behaviour = gr.Radio(["Yes", "No"], value=None, show_label=False, interactive=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  with gr.Row():
35
- behavior_checkbox, behavior_text = create_behavior_checkbox("wounded", mode, False)
 
 
36
 
37
- gr.Button("Are there physical changes on the animal?",
38
- icon=PATH_ICONS + "cardiogram.png",
39
- variant= "primary")
40
- radio_physical = gr.Radio(["Yes", "No"], value=None, show_label=False, interactive=True)
 
 
 
 
41
  with gr.Row():
42
  physical_boxes = create_bird_anatomy(False, "wounded")
43
  with gr.Column():
44
- checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs = process_body_parts("wounded", mode, "None")
 
 
 
 
 
 
 
 
 
 
 
45
 
46
-
47
- gr.Button("Follow-Up Events",
48
- icon=PATH_ICONS + "schedule.png",
49
- variant= "primary")
50
  gr.Markdown("Please tell us what you did with the animal.", label="description")
51
- with gr.Row():
52
- fe_collection_dropdown, fe_recepient_dropdown, fe_radio_dropdown, fe_answer_dropdown = create_followup_dropdowns(visible, "wounded")
53
- with gr.Row():
54
- fe_name_recipient, fe_collection_ref = create_followup_open(visible, "wounded")
55
-
 
 
 
 
 
 
56
 
57
  # Change variables and names
58
- return wounded_section, individual, radio_cause, radio_behaviour, radio_physical, \
59
- button_collision, button_deliberate_destruction, button_indirect_destruction, button_natural_cause, \
60
- dropdown, dropdown_level2, openfield_level2, dropdown_extra_level2, \
61
- behavior_checkbox, behavior_text, \
62
- physical_boxes, \
63
- checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs, \
64
- fe_collection_dropdown, fe_recepient_dropdown, fe_radio_dropdown, fe_answer_dropdown, fe_name_recipient, fe_collection_ref
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.utils_individual import add_data_to_individual
8
 
9
  from dotenv import load_dotenv
10
  import os
11
+
12
  load_dotenv()
13
  PATH = os.getcwd() + "/"
14
+ PATH_ASSETS = os.getenv("PATH_ASSETS")
15
  PATH_ICONS = PATH + PATH_ASSETS + "icons/"
16
 
17
+
18
  def show_section_wounded(visible, mode, individual):
19
+ if visible == True:
20
  individual = add_data_to_individual("wounded_state", "Yes", individual)
21
  individual = add_data_to_individual("dead_state", "No", individual)
22
+
23
  with gr.Column(visible=visible, elem_id="wounded") as wounded_section:
24
  gr.Markdown("## The animal is wounded / sick.")
 
 
 
 
 
 
25
 
26
+ gr.Button(
27
+ "Do you know what conditions caused this?",
28
+ icon=PATH_ICONS + "eye.png",
29
+ variant="primary",
30
+ )
31
+ radio_cause = gr.Radio(
32
+ ["Yes", "No"], value=None, show_label=False, interactive=True
33
+ )
34
+ (
35
+ button_collision,
36
+ button_deliberate_destruction,
37
+ button_indirect_destruction,
38
+ button_natural_cause,
39
+ dropdown,
40
+ dropdown_level2,
41
+ openfield_level2,
42
+ dropdown_extra_level2,
43
+ ) = create_circumstances(visible=False)
44
+
45
+ gr.Button(
46
+ "Is the animal displaying behavioural changes?",
47
+ icon=PATH_ICONS + "neuron.png",
48
+ variant="primary",
49
+ )
50
+ radio_behaviour = gr.Radio(
51
+ ["Yes", "No"], value=None, show_label=False, interactive=True
52
+ )
53
  with gr.Row():
54
+ behavior_checkbox, behavior_text = create_behavior_checkbox(
55
+ "wounded", mode, False
56
+ )
57
 
58
+ gr.Button(
59
+ "Are there physical changes on the animal?",
60
+ icon=PATH_ICONS + "cardiogram.png",
61
+ variant="primary",
62
+ )
63
+ radio_physical = gr.Radio(
64
+ ["Yes", "No"], value=None, show_label=False, interactive=True
65
+ )
66
  with gr.Row():
67
  physical_boxes = create_bird_anatomy(False, "wounded")
68
  with gr.Column():
69
+ (
70
+ checkbox_beak,
71
+ text_beak,
72
+ checkbox_body,
73
+ text_body,
74
+ checkbox_feathers,
75
+ text_feathers,
76
+ checkbox_head,
77
+ text_head,
78
+ checkbox_legs,
79
+ text_legs,
80
+ ) = process_body_parts("wounded", mode, "None")
81
 
82
+ gr.Button(
83
+ "Follow-Up Events", icon=PATH_ICONS + "schedule.png", variant="primary"
84
+ )
 
85
  gr.Markdown("Please tell us what you did with the animal.", label="description")
86
+ with gr.Row():
87
+ (
88
+ fe_collection_dropdown,
89
+ fe_recepient_dropdown,
90
+ fe_radio_dropdown,
91
+ fe_answer_dropdown,
92
+ ) = create_followup_dropdowns(visible, "wounded")
93
+ with gr.Row():
94
+ fe_name_recipient, fe_collection_ref = create_followup_open(
95
+ visible, "wounded"
96
+ )
97
 
98
  # Change variables and names
99
+ return (
100
+ wounded_section,
101
+ individual,
102
+ radio_cause,
103
+ radio_behaviour,
104
+ radio_physical,
105
+ button_collision,
106
+ button_deliberate_destruction,
107
+ button_indirect_destruction,
108
+ button_natural_cause,
109
+ dropdown,
110
+ dropdown_level2,
111
+ openfield_level2,
112
+ dropdown_extra_level2,
113
+ behavior_checkbox,
114
+ behavior_text,
115
+ physical_boxes,
116
+ checkbox_beak,
117
+ text_beak,
118
+ checkbox_body,
119
+ text_body,
120
+ checkbox_feathers,
121
+ text_feathers,
122
+ checkbox_head,
123
+ text_head,
124
+ checkbox_legs,
125
+ text_legs,
126
+ fe_collection_dropdown,
127
+ fe_recepient_dropdown,
128
+ fe_radio_dropdown,
129
+ fe_answer_dropdown,
130
+ fe_name_recipient,
131
+ fe_collection_ref,
132
+ )
app/follow_up/class_follow_up.py CHANGED
@@ -3,48 +3,56 @@ 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
 
3
 
4
  # --- Event follow-up classes ---
5
 
6
+
7
  class AnimalCollectedEvent(BaseModel):
8
+ type: Literal["animal collected"]
9
+ collected: Literal["yes", "no"]
10
+
11
 
12
  class RecipientEvent(BaseModel):
13
+ type: Literal["recipient"]
14
+ recipient: Literal[
15
+ "veterinary", "care center", "local museum", "national museum", "other"
16
+ ]
17
+
18
 
19
  class RadiographyEvent(BaseModel):
20
+ type: Literal["radiography"]
21
+ radiography: Literal["yes", "no", "unknown"]
22
+
23
 
24
  class GivenAnswerEvent(BaseModel):
25
+ type: Literal["given answer"]
26
  answer: Literal[
27
+ "nothing",
28
+ "complaint against x",
29
+ "complaint",
30
+ "police call",
31
+ "discussion with the speaker",
32
+ "press release",
33
+ "unknown",
34
  ]
35
 
36
+
37
  class NameOfRecipientEvent(BaseModel):
38
+ type: Literal["recipient name"]
39
  name: str
40
 
41
+
42
  class CollectionReferenceEvent(BaseModel):
43
+ type: Literal["collection reference"]
44
  reference: str
45
 
46
+
47
  FollowUpEventType = Union[
48
  AnimalCollectedEvent,
49
  RecipientEvent,
50
  RadiographyEvent,
51
  GivenAnswerEvent,
52
  NameOfRecipientEvent,
53
+ CollectionReferenceEvent,
54
  ]
55
 
56
+
57
  class FollowUpEvents(BaseModel):
58
+ follow_up_events: Optional[List[FollowUpEventType]] = None
app/follow_up/followup_events.py CHANGED
@@ -2,46 +2,85 @@ import gradio as gr
2
  from utils.utils_config import get_custom_config_dropdowns
3
  from validation_submission.utils_individual import add_data_to_individual
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, individual):
43
- individual = add_data_to_individual("wounded_dead", "followup " + key.lower(), value.lower())
44
- return individual
 
 
 
 
 
 
45
 
46
 
47
-
 
 
 
 
 
2
  from utils.utils_config import get_custom_config_dropdowns
3
  from validation_submission.utils_individual import add_data_to_individual
4
 
5
+
6
+ def create_followup_dropdowns(visible, elem_id):
7
  followup_config = get_custom_config_dropdowns("config_followup.json")
8
  followup_config = followup_config["Event follow-up"]
9
+ fe_collection_dropdown = create_fe_collection_dropdown(
10
+ followup_config, visible, elem_id
11
+ )
12
+ fe_recipient_dropdown = create_fe_recipient_dropdown(
13
+ followup_config, visible, elem_id
14
+ )
15
  fe_radio_dropdown = create_fe_radio_dropdown(followup_config, visible, elem_id)
16
  fe_answer_dropdown = create_fe_answer_dropdown(followup_config, visible, elem_id)
17
+ return (
18
+ fe_collection_dropdown,
19
+ fe_recipient_dropdown,
20
+ fe_radio_dropdown,
21
+ fe_answer_dropdown,
22
+ )
23
+
24
 
25
+ def create_followup_open(visible, elem_id):
26
+ fe_name_recipient = gr.Textbox(
27
+ label="Name of recipient / museum",
28
+ visible=visible,
29
+ elem_id=elem_id,
30
+ interactive=True,
31
+ )
32
+ fe_collection_ref = gr.Textbox(
33
+ label="Collection reference", visible=visible, elem_id=elem_id, interactive=True
34
+ )
35
  return fe_name_recipient, fe_collection_ref
36
 
37
 
38
  def create_fe_collection_dropdown(followup_config, visible, elem_id):
39
+ fe_collection_dropdown = gr.Dropdown(
40
+ choices=followup_config["Animal collected"]["Options"],
41
+ label="Animal collected",
42
+ visible=visible,
43
+ elem_id=elem_id,
44
+ interactive=True,
45
+ )
46
  return fe_collection_dropdown
47
 
48
+
49
  def create_fe_recipient_dropdown(followup_config, visible, elem_id):
50
+ fe_recipient_dropdown = gr.Dropdown(
51
+ choices=followup_config["Recipient"]["Options"],
52
+ label="Recipient",
53
+ visible=visible,
54
+ elem_id=elem_id,
55
+ interactive=True,
56
+ )
57
  return fe_recipient_dropdown
58
 
59
+
60
+ def create_fe_radio_dropdown(followup_config, visible, elem_id):
61
+ fe_radio_dropdown = gr.Dropdown(
62
+ choices=followup_config["Radiography"]["Options"],
63
+ label="Radiography",
64
+ visible=visible,
65
+ elem_id=elem_id,
66
+ interactive=True,
67
+ )
68
  return fe_radio_dropdown
69
 
 
 
 
 
70
 
71
+ def create_fe_answer_dropdown(followup_config, visible, elem_id):
72
+ fe_answer_dropdown = gr.Dropdown(
73
+ choices=followup_config["Given answer"]["Options"],
74
+ label="Given answer",
75
+ visible=visible,
76
+ elem_id=elem_id,
77
+ interactive=True,
78
+ )
79
+ return fe_answer_dropdown
80
 
81
 
82
+ def save_fe(value, key, individual):
83
+ individual = add_data_to_individual(
84
+ "wounded_dead", "followup " + key.lower(), value.lower()
85
+ )
86
+ return individual
app/geolocalisation/class_geolocalisation.py CHANGED
@@ -1,16 +1,18 @@
1
  from pydantic import BaseModel, Field
2
  from typing import Literal, List, Union, Optional
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: Optional[str]
16
-
 
1
  from pydantic import BaseModel, Field
2
  from typing import Literal, List, Union, Optional
3
 
4
+
5
  class Longitude(BaseModel):
6
+ type: Literal["longitude"]
7
  value: float
8
 
9
+
10
  class Latitude(BaseModel):
11
+ type: Literal["latitude"]
12
  value: float
13
 
14
+
15
  class Geolocalisation(BaseModel):
16
  longitude: Longitude
17
  latitude: Latitude
18
  name: Optional[str]
 
app/geolocalisation/js_geolocation.py CHANGED
@@ -1,6 +1,9 @@
1
- import gradio as gr
2
  import json
3
- from geolocalisation.maps import create_geolocalisation_object, save_geolocalisation_to_json
 
 
 
4
 
5
  # JavaScript code to get location and update hidden_input
6
  js_geocode = """
@@ -35,6 +38,7 @@ js_geocode = """
35
  }
36
  """
37
 
 
38
  def display_location(location_json, individual):
39
  geo_dict = json.loads(location_json)
40
  if "latitude" in geo_dict.keys():
@@ -43,12 +47,10 @@ def display_location(location_json, individual):
43
  geolocalisation = create_geolocalisation_object(latitude, longitude, "NA")
44
  individual = save_geolocalisation_to_json(geolocalisation, individual)
45
  geo_text = f"Latitude: {latitude} | Longitude: {longitude}"
46
- else:
47
  error = geo_dict["error"]
48
  geo_text = f"Error occured ({error}). Give your browser permission to use your geolocalisation or change browsers."
49
  locationtext = gr.Textbox(
50
- geo_text,
51
- visible=True,
52
- show_label=False,
53
- interactive=False)
54
  return locationtext, individual
 
1
+ import gradio as gr
2
  import json
3
+ from geolocalisation.maps import (
4
+ create_geolocalisation_object,
5
+ save_geolocalisation_to_json,
6
+ )
7
 
8
  # JavaScript code to get location and update hidden_input
9
  js_geocode = """
 
38
  }
39
  """
40
 
41
+
42
  def display_location(location_json, individual):
43
  geo_dict = json.loads(location_json)
44
  if "latitude" in geo_dict.keys():
 
47
  geolocalisation = create_geolocalisation_object(latitude, longitude, "NA")
48
  individual = save_geolocalisation_to_json(geolocalisation, individual)
49
  geo_text = f"Latitude: {latitude} | Longitude: {longitude}"
50
+ else:
51
  error = geo_dict["error"]
52
  geo_text = f"Error occured ({error}). Give your browser permission to use your geolocalisation or change browsers."
53
  locationtext = gr.Textbox(
54
+ geo_text, visible=True, show_label=False, interactive=False
55
+ )
 
 
56
  return locationtext, individual
app/geolocalisation/maps.py CHANGED
@@ -4,30 +4,32 @@ from validation_submission.utils_individual 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, individual):
 
19
  geo_dict = geolocalisation.dict()
20
  individual = add_data_to_individual("geolocalisation", geo_dict, individual)
21
  return individual
22
 
 
23
  def get_location(address, individual):
24
- try:
25
  # calling the Nominatim tool
26
  loc = Nominatim(user_agent="GetLoc")
27
-
28
  # entering the location name
29
  getLoc = loc.geocode(address)
30
-
31
  # latitude and longitude
32
  lat = getLoc.latitude
33
  lon = getLoc.longitude
@@ -36,16 +38,22 @@ def get_location(address, individual):
36
  geolocalisation = create_geolocalisation_object(lat, lon, address)
37
  individual = save_geolocalisation_to_json(geolocalisation, individual)
38
 
39
- #display location processing
40
  value = "Latitude = " + str(lat) + "\n" + "Longitude = " + str(lon)
41
- identified_location= gr.Textbox(visible=True, interactive=False,
42
- label="Identified GPS Location",
43
- value=value)
 
 
 
44
  return identified_location, individual
45
-
46
  except:
47
  error = "Please try another less precise location."
48
- identified_location= gr.Textbox(visible=True, interactive=False,
49
- label="Identified GPS Location",
50
- value=error)
51
- return identified_location, 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
+
19
+ def save_geolocalisation_to_json(geolocalisation, individual):
20
  geo_dict = geolocalisation.dict()
21
  individual = add_data_to_individual("geolocalisation", geo_dict, individual)
22
  return individual
23
 
24
+
25
  def get_location(address, individual):
26
+ try:
27
  # calling the Nominatim tool
28
  loc = Nominatim(user_agent="GetLoc")
29
+
30
  # entering the location name
31
  getLoc = loc.geocode(address)
32
+
33
  # latitude and longitude
34
  lat = getLoc.latitude
35
  lon = getLoc.longitude
 
38
  geolocalisation = create_geolocalisation_object(lat, lon, address)
39
  individual = save_geolocalisation_to_json(geolocalisation, individual)
40
 
41
+ # display location processing
42
  value = "Latitude = " + str(lat) + "\n" + "Longitude = " + str(lon)
43
+ identified_location = gr.Textbox(
44
+ visible=True,
45
+ interactive=False,
46
+ label="Identified GPS Location",
47
+ value=value,
48
+ )
49
  return identified_location, individual
50
+
51
  except:
52
  error = "Please try another less precise location."
53
+ identified_location = gr.Textbox(
54
+ visible=True,
55
+ interactive=False,
56
+ label="Identified GPS Location",
57
+ value=error,
58
+ )
59
+ return identified_location, individual
app/main.py CHANGED
@@ -1,17 +1,20 @@
1
  import gradio as gr
2
  from datasets import disable_caching
 
3
  disable_caching()
4
 
5
 
6
- from mode_advanced import advanced
7
  from mode_simple import simple
8
  from contacts import contacts
9
  from about import about
10
 
11
 
12
- demo = gr.TabbedInterface([simple, advanced, contacts, about],
13
- ["Simple Mode" , "Advanced Reporting", "Cantonal Contacts", "About"],
14
- theme='shivi/calm_seafoam')
 
 
15
 
16
  if __name__ == "__main__":
17
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
1
  import gradio as gr
2
  from datasets import disable_caching
3
+
4
  disable_caching()
5
 
6
 
7
+ from mode_advanced import advanced
8
  from mode_simple import simple
9
  from contacts import contacts
10
  from about import about
11
 
12
 
13
+ demo = gr.TabbedInterface(
14
+ [simple, advanced, contacts, about],
15
+ ["Simple Mode", "Advanced Reporting", "Cantonal Contacts", "About"],
16
+ theme="shivi/calm_seafoam",
17
+ )
18
 
19
  if __name__ == "__main__":
20
+ demo.launch(server_name="0.0.0.0", server_port=7860)
app/mode_advanced.py CHANGED
@@ -17,41 +17,60 @@ from validation_submission.utils_individual import generate_random_md5
17
  from validation_submission.utils_individual import add_data_to_individual
18
  from validation_submission.submission import validate_save_individual
19
  from validation_submission.utils_save import save_details, save_image
20
- from validation_submission.resets import reset_individual, reset_error_box, hide_physical
 
 
 
 
21
 
22
  from dotenv import load_dotenv
23
  import os
 
24
  load_dotenv()
25
  PATH = os.getcwd() + "/"
26
- PATH_ASSETS = os.getenv('PATH_ASSETS')
27
  PATH_ICONS = PATH + PATH_ASSETS + "icons/"
28
 
29
- with gr.Blocks(theme='shivi/calm_seafoam') as advanced:
30
  mode = "advanced"
31
  individual = gr.State({})
32
- individual.value = add_data_to_individual("image_md5", generate_random_md5(), individual.value)
 
 
33
 
34
  # ---------------------------------------------------------
35
  # Header Text
36
  with gr.Row():
37
- gr.Image(PATH_ICONS+"impact.png", scale =0.1,
38
- interactive=False,
39
- show_fullscreen_button = False, show_share_button=False,
40
- show_download_button=False, show_label=False)
 
 
 
 
 
41
  with gr.Column(scale=1):
42
- title = gr.Markdown("# Welcome to Digiwild - Advanced Reporting", label="Title")
43
- description = gr.Markdown("### Please record your wildlife observations here !", label="description")
 
 
 
 
 
44
 
45
  # ---------------------------------------------------------
46
  # Camera
47
  with gr.Row():
48
  camera = gr.Image(elem_id="image")
49
  camera.input(save_image, inputs=[camera, individual], outputs=[individual])
50
-
51
  # ---------------------------------------------------------
52
  # General Details
53
  with gr.Column(scale=1):
54
- gr.Button("General Details", icon=PATH_ICONS+"chicken.png", variant="secondary")
 
 
55
 
56
  with gr.Row():
57
  specie = gr.Textbox(
@@ -59,12 +78,13 @@ with gr.Blocks(theme='shivi/calm_seafoam') as advanced:
59
  placeholder="e.g. European Robin, Common Blackbird",
60
  info="Enter the species name if you can identify it. If unsure, provide your best guess or general description (e.g. 'small brown bird')",
61
  visible=True,
62
- interactive=True
 
 
 
 
 
63
  )
64
- specie.change(save_details,
65
- inputs=[gr.Textbox("specie", visible=False),
66
- specie],
67
- outputs=individual)
68
 
69
  # Number of individuals
70
  with gr.Row():
@@ -74,16 +94,17 @@ with gr.Blocks(theme='shivi/calm_seafoam') as advanced:
74
  minimum=1,
75
  precision=0, # Only whole numbers
76
  info="Enter the number of animals observed",
77
- #placeholder="Enter number...",
78
  visible=True,
79
- interactive=True
 
 
 
 
 
80
  )
81
- num_individuals.change(save_details,
82
- inputs=[gr.Textbox("number", visible=False),
83
- num_individuals],
84
- outputs=individual)
85
 
86
- # Introducing text_box for comments
87
  with gr.Row():
88
  comments = gr.TextArea(
89
  label="Additional Comments",
@@ -92,60 +113,92 @@ with gr.Blocks(theme='shivi/calm_seafoam') as advanced:
92
  lines=3,
93
  max_lines=5,
94
  visible=True,
95
- interactive=True
 
 
 
 
 
96
  )
97
- comments.change(save_details,
98
- inputs=[gr.Textbox("comments", visible=False),
99
- comments],
100
- outputs=individual)
101
 
102
  # ---------------------------------------------------------
103
  # Location
104
- gr.Button("Location", icon=PATH_ICONS+"pin.png", variant="secondary")
105
  with gr.Row():
106
  with gr.Column(scale=1):
107
- gr.Markdown("#### Location (Using address)")
108
- location = gr.Textbox(visible=True, interactive=True,
109
- label="Location of Sighting")
110
- #display location processing
111
- identified_location= gr.Textbox(visible=False, interactive=False,
112
- label="Identified GPS Location")
113
- with gr.Row():
114
- #to submit it
115
- submit_location = gr.Button("Get Coordinates using address",
116
- visible=True, interactive=True, scale=3)
117
- submit_location.click(get_location, inputs=[location, individual], outputs=[identified_location, individual])
118
- #to clear it
119
- clear_location = gr.ClearButton(components=[location, identified_location],
120
- visible=True, interactive=True, scale=1
121
- )
122
- clear_location.click()
123
-
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  with gr.Column(scale=1):
125
  # Geolocation
126
- gr.Button("Location", icon=PATH_ICONS+"pin.png", variant="primary")
127
  location_data = gr.JSON(label="Identified GPS Location", visible=False)
128
- hidden_input = gr.Textbox(visible=False, elem_id="textbox_id")
129
- locationtext = gr.Textbox(visible=False, elem_id="textbox_id")
130
- btn_gpslocation = gr.Button("Get Coordinates using GPS (Permission required - May take a few seconds)")
 
 
131
  btn_gpslocation.click(None, [], [], js=js_geocode)
132
- hidden_input.change(display_location,
133
- inputs=[hidden_input, individual],
134
- outputs=[locationtext, individual])
135
-
 
 
136
  # ---------------------------------------------------------
137
  # Dead and Wounded Buttons
138
  gr.Button("State of the Animal", variant="secondary")
139
  with gr.Row():
140
- gr.Image(PATH_ICONS+"medical-app.png", scale =0.1,
141
- interactive=False,
142
- show_fullscreen_button = False, show_share_button=False,
143
- show_download_button=False, show_label=False)
 
 
 
 
 
144
  with gr.Column():
145
  gr.Markdown("## The State of the Animal", label="Title")
146
- gr.Markdown("Please tell us if the animal was wounded / sick or dead.", label="description")
147
- gr.Markdown("Please fill out as many fields as you can, based on what you can see.", label="description")
148
- gr.Markdown("### Do not touch the animal unless absolutely necessary.", label="description")
 
 
 
 
 
 
 
 
 
149
  with gr.Row() as block_form:
150
  with gr.Column(scale=1):
151
  butt_wounded = gr.Button("Wounded / Sick", elem_id="wounded")
@@ -154,24 +207,72 @@ with gr.Blocks(theme='shivi/calm_seafoam') as advanced:
154
 
155
  # ---------------------------------------------------------
156
  # Initiate sections
157
- section_dead, individual, radio_circumstance_dead, radio_physical_dead,\
158
- button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead, \
159
- dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, \
160
- physical_boxes_dead, \
161
- 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, \
162
- fe_collection_dropdown_dead, fe_recepient_dropdown_dead, fe_radio_dropdown_dead, fe_answer_dropdown_dead, \
163
- fe_name_recipient_dead, fe_collection_ref_dead \
164
- = show_section_dead(False, mode, individual)
165
-
166
- section_wounded, individual, radio_circumstance_wounded, radio_behavior_wounded, radio_physical_wounded, \
167
- button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded, \
168
- dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, \
169
- behavior_checkbox, behavior_text, \
170
- physical_boxes_wounded, \
171
- 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, \
172
- fe_collection_dropdown_wounded, fe_recepient_dropdown_wounded, fe_radio_dropdown_wounded, fe_answer_dropdown_wounded, \
173
- fe_name_recipient_wounded, fe_collection_ref_wounded \
174
- = show_section_wounded(False, mode, individual)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
 
176
  # ---------------------------------------------------------
177
  # ---------------------------------------------------------
@@ -179,69 +280,161 @@ with gr.Blocks(theme='shivi/calm_seafoam') as advanced:
179
  # Dead Button Logic
180
  partial_show_section_dead = partial(show_section_dead, True)
181
  partial_hide_section_wounded = partial(show_section_wounded, False)
182
- butt_dead.click(partial_show_section_dead,
183
- inputs=[gr.Text(mode, visible=False),
184
- individual],
185
- outputs=[section_dead,
186
- individual,
187
- radio_circumstance_dead, radio_physical_dead,
188
- button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead,
189
- dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, \
190
- physical_boxes_dead, \
191
- 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, \
192
- fe_collection_dropdown_dead, fe_recepient_dropdown_dead, fe_radio_dropdown_dead, fe_answer_dropdown_dead, \
193
- fe_name_recipient_dead, fe_collection_ref_dead \
194
- ])
195
-
196
- butt_dead.click(partial_hide_section_wounded,
197
- inputs=[gr.Text(mode, visible=False),
198
- individual],
199
- outputs=[section_wounded,
200
- individual,
201
- radio_circumstance_wounded, radio_behavior_wounded, radio_physical_wounded,
202
- button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded,
203
- dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded,
204
- behavior_checkbox, behavior_text,
205
- physical_boxes_wounded, \
206
- 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, \
207
- fe_collection_dropdown_wounded, fe_recepient_dropdown_wounded, fe_radio_dropdown_wounded, fe_answer_dropdown_wounded, \
208
- fe_name_recipient_wounded, fe_collection_ref_wounded \
209
- ])
210
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  # ---------------------------------------------------------
212
  # Wounded Button Logic
213
  partial_show_section_wounded = partial(show_section_wounded, True)
214
  partial_hide_section_dead = partial(show_section_dead, False)
215
 
216
- butt_wounded.click(partial_show_section_wounded,
217
- inputs=[gr.Text(mode, visible=False),
218
- individual],
219
- outputs=[section_wounded,
220
- individual,
221
- radio_circumstance_wounded, radio_behavior_wounded, radio_physical_wounded,
222
- button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded,
223
- dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded,
224
- behavior_checkbox, behavior_text,
225
- physical_boxes_wounded, \
226
- 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, \
227
- fe_collection_dropdown_wounded, fe_recepient_dropdown_wounded, fe_radio_dropdown_wounded, fe_answer_dropdown_wounded, \
228
- fe_name_recipient_wounded, fe_collection_ref_wounded \
229
- ])
230
-
231
- butt_wounded.click(partial_hide_section_dead,
232
- inputs=[gr.Text(mode, visible=False),
233
- individual],
234
- outputs=[section_dead,
235
- individual,
236
- radio_circumstance_dead, radio_physical_dead,
237
- button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead,
238
- dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, \
239
- physical_boxes_dead, \
240
- 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, \
241
- fe_collection_dropdown_dead, fe_recepient_dropdown_dead, fe_radio_dropdown_dead, fe_answer_dropdown_dead, \
242
- fe_name_recipient_dead, fe_collection_ref_dead \
243
- ])
244
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  # ---------------------------------------------------------
246
  # ---------------------------------------------------------
247
  # ---------------------------------------------------------
@@ -249,46 +442,139 @@ with gr.Blocks(theme='shivi/calm_seafoam') as advanced:
249
  # DEAD
250
  # ---------------------------------------------------------
251
  # Radio Circumstance Dead
252
- radio_circumstance_dead.change(fn=show_circumstances,
253
- inputs=[radio_circumstance_dead, individual],
254
- outputs=[button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead,
255
- dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, individual]
256
- )
257
-
 
 
 
 
 
 
 
 
 
 
258
  # Dropdowns Dead
259
- button_collision_dead.click(dropdown_collision,
260
- inputs=[individual],
261
- outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, individual])
262
- button_deliberate_destruction_dead.click(dropdown_deliberate_destruction, inputs=[individual], outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, individual])
263
- button_indirect_destruction_dead.click(dropdown_indirect_destruction, inputs=[individual], outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, individual])
264
- button_natural_cause_dead.click(dropdown_natural_cause, inputs=[individual], outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, individual])
265
-
266
- dropdown_dead.select(on_select, inputs=[individual], outputs=[dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, individual])
267
- dropdown_level2_dead.select(on_select_dropdown_level2, inputs=[individual], outputs=[individual] )
268
- openfield_level2_dead.change(on_change_openfield_level2, inputs=[openfield_level2_dead, individual], outputs=[individual])
269
- dropdown_extra_level2_dead.select(on_select_dropdown_extra_level2, inputs=[individual], outputs=[individual])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  # ---------------------------------------------------------
271
  # Radio Physical Dead
272
- radio_physical_dead.change(fn=show_physical,
273
- inputs=[radio_physical_dead,
274
- gr.Text("dead", visible=False),
275
- individual],
276
- outputs=[physical_boxes_dead, individual])
277
 
278
  # Checkbox Physical Dead
279
- physical_boxes_dead.select(find_bounding_box,
280
- inputs=[physical_boxes_dead, gr.Textbox(value="dead", visible=False)],
281
- outputs=[checkbox_beak_dead, text_beak_dead,
282
- checkbox_body_dead, text_body_dead,
283
- checkbox_feathers_dead, text_feathers_dead,
284
- checkbox_head_dead, text_head_dead,
285
- checkbox_legs_dead, text_legs_dead
286
- ])
287
- checkbox_beak_dead.select(on_select_body_part, inputs=[checkbox_beak_dead, gr.Text("beak", visible=False), individual], outputs=[individual])
288
- checkbox_body_dead.select(on_select_body_part, inputs=[checkbox_body_dead, gr.Text("body", visible=False), individual], outputs=[individual])
289
- checkbox_feathers_dead.select(on_select_body_part, inputs=[checkbox_feathers_dead, gr.Text("feathers", visible=False), individual], outputs=[individual])
290
- checkbox_head_dead.select(on_select_body_part, inputs=[checkbox_head_dead, gr.Text("head", visible=False), individual], outputs=[individual])
291
- checkbox_legs_dead.select(on_select_body_part, inputs=[checkbox_legs_dead, gr.Text("legs", visible=False), individual], outputs=[individual])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  # ---------------------------------------------------------
293
  # ---------------------------------------------------------
294
  # ---------------------------------------------------------
@@ -296,159 +582,427 @@ with gr.Blocks(theme='shivi/calm_seafoam') as advanced:
296
  # WOUNDED
297
  # ---------------------------------------------------------
298
  # Radio Circumstance Wounded
299
- radio_circumstance_wounded.change(fn=show_circumstances,
300
- inputs=[radio_circumstance_wounded, individual],
301
- outputs=[button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded,
302
- dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, individual]
303
- )
304
-
 
 
 
 
 
 
 
 
 
 
305
  # Dropdowns Circumstance Wounded
306
- button_collision_wounded.click(dropdown_collision,
307
- inputs=[individual],
308
- outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, individual])
309
- button_deliberate_destruction_wounded.click(dropdown_deliberate_destruction, inputs=[individual], outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, individual])
310
- button_indirect_destruction_wounded.click(dropdown_indirect_destruction, inputs=[individual], outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, individual])
311
- button_natural_cause_wounded.click(dropdown_natural_cause, inputs=[individual], outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, individual])
312
-
313
- dropdown_wounded.select(on_select, inputs=[individual], outputs=[dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, individual])
314
- dropdown_level2_wounded.select(on_select_dropdown_level2, inputs=[individual], outputs=[individual])
315
- openfield_level2_wounded.change(on_change_openfield_level2, inputs=[openfield_level2_wounded, individual])
316
- dropdown_extra_level2_wounded.select(on_select_dropdown_extra_level2, inputs=[individual], outputs=[individual])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
  # ---------------------------------------------------------
318
  # Radio Behavior Wounded
319
- radio_behavior_wounded.change(fn=show_behavior,
320
- inputs=[radio_behavior_wounded,
321
- gr.Text("wounded / sick", visible=False),
322
- gr.Text(mode, visible=False),
323
- individual],
324
- outputs=[behavior_checkbox, behavior_text, individual])
325
- behavior_checkbox.select(on_select_behavior,
326
- inputs=[behavior_checkbox, individual],
327
- outputs=[individual])
 
 
 
 
328
  # ---------------------------------------------------------
329
  # Radio Physical Wounded
330
- radio_physical_wounded.change(fn=show_physical,
331
- inputs=[radio_physical_wounded,
332
- gr.Text("wounded / sick", visible=False),
333
- individual],
334
- outputs=[physical_boxes_wounded, individual])
 
 
 
 
335
 
336
  # Checkbox Physical Wounded
337
- physical_boxes_wounded.select(find_bounding_box,
338
- inputs=[physical_boxes_wounded, gr.Textbox(value="wounded / sick", visible=False)],
339
- outputs=[checkbox_beak_wounded, text_beak_wounded,
340
- checkbox_body_wounded, text_body_wounded,
341
- checkbox_feathers_wounded, text_feathers_wounded,
342
- checkbox_head_wounded, text_head_wounded,
343
- checkbox_legs_wounded, text_legs_wounded
344
- ])
345
- checkbox_beak_wounded.select(on_select_body_part, inputs=[checkbox_beak_wounded, gr.Text("beak", visible=False), individual], outputs=[individual])
346
- checkbox_body_wounded.select(on_select_body_part, inputs=[checkbox_body_wounded, gr.Text("body", visible=False), individual], outputs=[individual])
347
- checkbox_feathers_wounded.select(on_select_body_part, inputs=[checkbox_feathers_wounded, gr.Text("feathers", visible=False), individual], outputs=[individual])
348
- checkbox_head_wounded.select(on_select_body_part, inputs=[checkbox_head_wounded, gr.Text("head", visible=False), individual], outputs=[individual])
349
- checkbox_legs_wounded.select(on_select_body_part, inputs=[checkbox_legs_wounded, gr.Text("legs", visible=False), individual], outputs=[individual])
350
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
  # ---------------------------------------------------------
352
- # Follow Up Events Wounded
353
- fe_collection_dropdown_wounded.select(save_fe, inputs=[fe_collection_dropdown_wounded, gr.Textbox("animal collected", visible=False), individual], outputs=[individual])
354
- fe_recepient_dropdown_wounded.select(save_fe, inputs=[fe_recepient_dropdown_wounded, gr.Textbox("recipient", visible=False), individual],outputs=[individual])
355
- fe_radio_dropdown_wounded.select(save_fe, inputs=[fe_radio_dropdown_wounded, gr.Textbox("radiography", visible=False), individual],outputs=[individual])
356
- fe_answer_dropdown_wounded.select(save_fe, inputs=[fe_answer_dropdown_wounded, gr.Textbox("given answer", visible=False), individual],outputs=[individual])
357
- fe_name_recipient_wounded.input(save_fe, inputs=[fe_name_recipient_wounded, gr.Textbox("recipient name", visible=False), individual],outputs=[individual])
358
- fe_collection_ref_wounded.input(save_fe, inputs=[fe_collection_ref_wounded, gr.Textbox("collection reference", visible=False), individual],outputs=[individual])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
359
 
360
  # ---------------------------------------------------------
361
- # Follow Up Events Dead
362
- fe_collection_dropdown_dead.select(save_fe, inputs=[fe_collection_dropdown_dead, gr.Textbox("animal collected", visible=False), individual],outputs=[individual])
363
- fe_recepient_dropdown_dead.select(save_fe, inputs=[fe_recepient_dropdown_dead, gr.Textbox("recipient", visible=False), individual],outputs=[individual])
364
- fe_radio_dropdown_dead.select(save_fe, inputs=[fe_radio_dropdown_dead, gr.Textbox("radiography", visible=False), individual],outputs=[individual])
365
- fe_answer_dropdown_dead.select(save_fe, inputs=[fe_answer_dropdown_dead, gr.Textbox("given answer", visible=False), individual],outputs=[individual])
366
- fe_name_recipient_dead.input(save_fe, inputs=[fe_name_recipient_dead, gr.Textbox("recipient name", visible=False), individual],outputs=[individual])
367
- fe_collection_ref_dead.input(save_fe, inputs=[fe_collection_ref_dead, gr.Textbox("collection reference", visible=False), individual], outputs=[individual])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
 
369
  # ---------------------------------------------------------
370
  # Spacer
371
  with gr.Row(elem_id="centered-row"):
372
- gr.Image(PATH_ICONS+"animal.png", height=80, width=80,
373
- interactive=False,
374
- show_fullscreen_button = False, show_share_button=False,
375
- show_download_button=False, show_label=False)
376
- advanced.css = """
 
 
 
 
 
 
377
  #centered-row {
378
  display: flex;
379
  justify-content: center;
380
  }
381
  """
382
-
383
  # ---------------------------------------------------------
384
  # Error Box
385
- with gr.Row():
386
- error_icon = gr.Image(PATH_ICONS+"chicken.png",
387
- height=80, width=80, visible=False,
388
- scale=1)
389
  error_box = gr.Text(value=None, visible=False, scale=3)
390
-
391
-
392
  # ---------------------------------------------------------
393
  # Allow clearing of all previous output
394
- with gr.Row():
395
- button_df = gr.Button("SUBMIT OBSERVATION", icon=PATH_ICONS+"effective.png",
396
- scale = 3)
397
- button_clear = gr.ClearButton(value="CLEAR",
398
- scale = 1,
399
- components=[
400
- camera,
401
- location, identified_location,
402
- #dead reset
403
- radio_circumstance_dead, radio_physical_dead,
404
- button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead,
405
- dropdown_dead, dropdown_level2_dead,
406
- #openfield_level2_dead,
407
- dropdown_extra_level2_dead,
408
- physical_boxes_dead,
409
- 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,
410
- fe_collection_dropdown_dead, fe_recepient_dropdown_dead, fe_radio_dropdown_dead, fe_answer_dropdown_dead,
411
- fe_name_recipient_dead, fe_collection_ref_dead,
412
- #wounded reset
413
- radio_circumstance_wounded, radio_behavior_wounded, radio_physical_wounded,
414
- button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded,
415
- dropdown_wounded, dropdown_level2_wounded,
416
- #openfield_level2_wounded,
417
- dropdown_extra_level2_wounded,
418
- behavior_checkbox, behavior_text,
419
- physical_boxes_wounded,
420
- 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,
421
- fe_collection_dropdown_wounded, fe_recepient_dropdown_wounded, fe_radio_dropdown_wounded, fe_answer_dropdown_wounded,
422
- fe_name_recipient_wounded, fe_collection_ref_wounded,
423
- error_icon, error_box
424
- ])
425
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
426
  # ---------------------------------------------------------
427
- # VALIDATE ANIMAL
428
- button_df.click(validate_save_individual,
429
- inputs=[individual,
430
- error_icon,
431
- error_box,
432
- gr.Text(mode, visible=False)],
433
- outputs=[error_icon, error_box])
434
-
435
  # ---------------------------------------------------------
436
  # CLEAR BUTTON
437
  button_clear.click()
438
- button_clear.click(hide_physical,
439
- inputs =[gr.Text(mode, visible=False)],
440
- outputs=[checkbox_beak_wounded, text_beak_wounded,
441
- checkbox_body_wounded, text_body_wounded,
442
- checkbox_feathers_wounded, text_feathers_wounded,
443
- checkbox_head_wounded, text_head_wounded,
444
- checkbox_legs_wounded, text_legs_wounded])
445
- button_clear.click(hide_physical,
446
- inputs =[gr.Text(mode, visible=False)],
447
- outputs=[checkbox_beak_dead, text_beak_dead,
448
- checkbox_body_dead, text_body_dead,
449
- checkbox_feathers_dead, text_feathers_dead,
450
- checkbox_head_dead, text_head_dead,
451
- checkbox_legs_dead, text_legs_dead])
452
- button_clear.click(reset_error_box, inputs=[error_icon, error_box], outputs=[error_icon, error_box])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
453
  button_clear.click(reset_individual, inputs=[individual], outputs=[individual])
454
-
 
17
  from validation_submission.utils_individual import add_data_to_individual
18
  from validation_submission.submission import validate_save_individual
19
  from validation_submission.utils_save import save_details, save_image
20
+ from validation_submission.resets import (
21
+ reset_individual,
22
+ reset_error_box,
23
+ hide_physical,
24
+ )
25
 
26
  from dotenv import load_dotenv
27
  import os
28
+
29
  load_dotenv()
30
  PATH = os.getcwd() + "/"
31
+ PATH_ASSETS = os.getenv("PATH_ASSETS")
32
  PATH_ICONS = PATH + PATH_ASSETS + "icons/"
33
 
34
+ with gr.Blocks(theme="shivi/calm_seafoam") as advanced:
35
  mode = "advanced"
36
  individual = gr.State({})
37
+ individual.value = add_data_to_individual(
38
+ "image_md5", generate_random_md5(), individual.value
39
+ )
40
 
41
  # ---------------------------------------------------------
42
  # Header Text
43
  with gr.Row():
44
+ gr.Image(
45
+ PATH_ICONS + "impact.png",
46
+ scale=0.1,
47
+ interactive=False,
48
+ show_fullscreen_button=False,
49
+ show_share_button=False,
50
+ show_download_button=False,
51
+ show_label=False,
52
+ )
53
  with gr.Column(scale=1):
54
+ title = gr.Markdown(
55
+ "# Welcome to Digiwild - Advanced Reporting", label="Title"
56
+ )
57
+ description = gr.Markdown(
58
+ "### Please record your wildlife observations here !",
59
+ label="description",
60
+ )
61
 
62
  # ---------------------------------------------------------
63
  # Camera
64
  with gr.Row():
65
  camera = gr.Image(elem_id="image")
66
  camera.input(save_image, inputs=[camera, individual], outputs=[individual])
67
+
68
  # ---------------------------------------------------------
69
  # General Details
70
  with gr.Column(scale=1):
71
+ gr.Button(
72
+ "General Details", icon=PATH_ICONS + "chicken.png", variant="secondary"
73
+ )
74
 
75
  with gr.Row():
76
  specie = gr.Textbox(
 
78
  placeholder="e.g. European Robin, Common Blackbird",
79
  info="Enter the species name if you can identify it. If unsure, provide your best guess or general description (e.g. 'small brown bird')",
80
  visible=True,
81
+ interactive=True,
82
+ )
83
+ specie.change(
84
+ save_details,
85
+ inputs=[gr.Textbox("specie", visible=False), specie],
86
+ outputs=individual,
87
  )
 
 
 
 
88
 
89
  # Number of individuals
90
  with gr.Row():
 
94
  minimum=1,
95
  precision=0, # Only whole numbers
96
  info="Enter the number of animals observed",
97
+ # placeholder="Enter number...",
98
  visible=True,
99
+ interactive=True,
100
+ )
101
+ num_individuals.change(
102
+ save_details,
103
+ inputs=[gr.Textbox("number", visible=False), num_individuals],
104
+ outputs=individual,
105
  )
 
 
 
 
106
 
107
+ # Introducing text_box for comments
108
  with gr.Row():
109
  comments = gr.TextArea(
110
  label="Additional Comments",
 
113
  lines=3,
114
  max_lines=5,
115
  visible=True,
116
+ interactive=True,
117
+ )
118
+ comments.change(
119
+ save_details,
120
+ inputs=[gr.Textbox("comments", visible=False), comments],
121
+ outputs=individual,
122
  )
 
 
 
 
123
 
124
  # ---------------------------------------------------------
125
  # Location
126
+ gr.Button("Location", icon=PATH_ICONS + "pin.png", variant="secondary")
127
  with gr.Row():
128
  with gr.Column(scale=1):
129
+ gr.Markdown("#### Location (Using address)")
130
+ location = gr.Textbox(
131
+ visible=True, interactive=True, label="Location of Sighting"
132
+ )
133
+ # display location processing
134
+ identified_location = gr.Textbox(
135
+ visible=False, interactive=False, label="Identified GPS Location"
136
+ )
137
+ with gr.Row():
138
+ # to submit it
139
+ submit_location = gr.Button(
140
+ "Get Coordinates using address",
141
+ visible=True,
142
+ interactive=True,
143
+ scale=3,
144
+ )
145
+ submit_location.click(
146
+ get_location,
147
+ inputs=[location, individual],
148
+ outputs=[identified_location, individual],
149
+ )
150
+ # to clear it
151
+ clear_location = gr.ClearButton(
152
+ components=[location, identified_location],
153
+ visible=True,
154
+ interactive=True,
155
+ scale=1,
156
+ )
157
+ clear_location.click()
158
+
159
  with gr.Column(scale=1):
160
  # Geolocation
161
+ gr.Button("Location", icon=PATH_ICONS + "pin.png", variant="primary")
162
  location_data = gr.JSON(label="Identified GPS Location", visible=False)
163
+ hidden_input = gr.Textbox(visible=False, elem_id="textbox_id")
164
+ locationtext = gr.Textbox(visible=False, elem_id="textbox_id")
165
+ btn_gpslocation = gr.Button(
166
+ "Get Coordinates using GPS (Permission required - May take a few seconds)"
167
+ )
168
  btn_gpslocation.click(None, [], [], js=js_geocode)
169
+ hidden_input.change(
170
+ display_location,
171
+ inputs=[hidden_input, individual],
172
+ outputs=[locationtext, individual],
173
+ )
174
+
175
  # ---------------------------------------------------------
176
  # Dead and Wounded Buttons
177
  gr.Button("State of the Animal", variant="secondary")
178
  with gr.Row():
179
+ gr.Image(
180
+ PATH_ICONS + "medical-app.png",
181
+ scale=0.1,
182
+ interactive=False,
183
+ show_fullscreen_button=False,
184
+ show_share_button=False,
185
+ show_download_button=False,
186
+ show_label=False,
187
+ )
188
  with gr.Column():
189
  gr.Markdown("## The State of the Animal", label="Title")
190
+ gr.Markdown(
191
+ "Please tell us if the animal was wounded / sick or dead.",
192
+ label="description",
193
+ )
194
+ gr.Markdown(
195
+ "Please fill out as many fields as you can, based on what you can see.",
196
+ label="description",
197
+ )
198
+ gr.Markdown(
199
+ "### Do not touch the animal unless absolutely necessary.",
200
+ label="description",
201
+ )
202
  with gr.Row() as block_form:
203
  with gr.Column(scale=1):
204
  butt_wounded = gr.Button("Wounded / Sick", elem_id="wounded")
 
207
 
208
  # ---------------------------------------------------------
209
  # Initiate sections
210
+ (
211
+ section_dead,
212
+ individual,
213
+ radio_circumstance_dead,
214
+ radio_physical_dead,
215
+ button_collision_dead,
216
+ button_deliberate_destruction_dead,
217
+ button_indirect_destruction_dead,
218
+ button_natural_cause_dead,
219
+ dropdown_dead,
220
+ dropdown_level2_dead,
221
+ openfield_level2_dead,
222
+ dropdown_extra_level2_dead,
223
+ physical_boxes_dead,
224
+ checkbox_beak_dead,
225
+ text_beak_dead,
226
+ checkbox_body_dead,
227
+ text_body_dead,
228
+ checkbox_feathers_dead,
229
+ text_feathers_dead,
230
+ checkbox_head_dead,
231
+ text_head_dead,
232
+ checkbox_legs_dead,
233
+ text_legs_dead,
234
+ fe_collection_dropdown_dead,
235
+ fe_recepient_dropdown_dead,
236
+ fe_radio_dropdown_dead,
237
+ fe_answer_dropdown_dead,
238
+ fe_name_recipient_dead,
239
+ fe_collection_ref_dead,
240
+ ) = show_section_dead(False, mode, individual)
241
+
242
+ (
243
+ section_wounded,
244
+ individual,
245
+ radio_circumstance_wounded,
246
+ radio_behavior_wounded,
247
+ radio_physical_wounded,
248
+ button_collision_wounded,
249
+ button_deliberate_destruction_wounded,
250
+ button_indirect_destruction_wounded,
251
+ button_natural_cause_wounded,
252
+ dropdown_wounded,
253
+ dropdown_level2_wounded,
254
+ openfield_level2_wounded,
255
+ dropdown_extra_level2_wounded,
256
+ behavior_checkbox,
257
+ behavior_text,
258
+ physical_boxes_wounded,
259
+ checkbox_beak_wounded,
260
+ text_beak_wounded,
261
+ checkbox_body_wounded,
262
+ text_body_wounded,
263
+ checkbox_feathers_wounded,
264
+ text_feathers_wounded,
265
+ checkbox_head_wounded,
266
+ text_head_wounded,
267
+ checkbox_legs_wounded,
268
+ text_legs_wounded,
269
+ fe_collection_dropdown_wounded,
270
+ fe_recepient_dropdown_wounded,
271
+ fe_radio_dropdown_wounded,
272
+ fe_answer_dropdown_wounded,
273
+ fe_name_recipient_wounded,
274
+ fe_collection_ref_wounded,
275
+ ) = show_section_wounded(False, mode, individual)
276
 
277
  # ---------------------------------------------------------
278
  # ---------------------------------------------------------
 
280
  # Dead Button Logic
281
  partial_show_section_dead = partial(show_section_dead, True)
282
  partial_hide_section_wounded = partial(show_section_wounded, False)
283
+ butt_dead.click(
284
+ partial_show_section_dead,
285
+ inputs=[gr.Text(mode, visible=False), individual],
286
+ outputs=[
287
+ section_dead,
288
+ individual,
289
+ radio_circumstance_dead,
290
+ radio_physical_dead,
291
+ button_collision_dead,
292
+ button_deliberate_destruction_dead,
293
+ button_indirect_destruction_dead,
294
+ button_natural_cause_dead,
295
+ dropdown_dead,
296
+ dropdown_level2_dead,
297
+ openfield_level2_dead,
298
+ dropdown_extra_level2_dead,
299
+ physical_boxes_dead,
300
+ checkbox_beak_dead,
301
+ text_beak_dead,
302
+ checkbox_body_dead,
303
+ text_body_dead,
304
+ checkbox_feathers_dead,
305
+ text_feathers_dead,
306
+ checkbox_head_dead,
307
+ text_head_dead,
308
+ checkbox_legs_dead,
309
+ text_legs_dead,
310
+ fe_collection_dropdown_dead,
311
+ fe_recepient_dropdown_dead,
312
+ fe_radio_dropdown_dead,
313
+ fe_answer_dropdown_dead,
314
+ fe_name_recipient_dead,
315
+ fe_collection_ref_dead,
316
+ ],
317
+ )
318
+
319
+ butt_dead.click(
320
+ partial_hide_section_wounded,
321
+ inputs=[gr.Text(mode, visible=False), individual],
322
+ outputs=[
323
+ section_wounded,
324
+ individual,
325
+ radio_circumstance_wounded,
326
+ radio_behavior_wounded,
327
+ radio_physical_wounded,
328
+ button_collision_wounded,
329
+ button_deliberate_destruction_wounded,
330
+ button_indirect_destruction_wounded,
331
+ button_natural_cause_wounded,
332
+ dropdown_wounded,
333
+ dropdown_level2_wounded,
334
+ openfield_level2_wounded,
335
+ dropdown_extra_level2_wounded,
336
+ behavior_checkbox,
337
+ behavior_text,
338
+ physical_boxes_wounded,
339
+ checkbox_beak_wounded,
340
+ text_beak_wounded,
341
+ checkbox_body_wounded,
342
+ text_body_wounded,
343
+ checkbox_feathers_wounded,
344
+ text_feathers_wounded,
345
+ checkbox_head_wounded,
346
+ text_head_wounded,
347
+ checkbox_legs_wounded,
348
+ text_legs_wounded,
349
+ fe_collection_dropdown_wounded,
350
+ fe_recepient_dropdown_wounded,
351
+ fe_radio_dropdown_wounded,
352
+ fe_answer_dropdown_wounded,
353
+ fe_name_recipient_wounded,
354
+ fe_collection_ref_wounded,
355
+ ],
356
+ )
357
+
358
  # ---------------------------------------------------------
359
  # Wounded Button Logic
360
  partial_show_section_wounded = partial(show_section_wounded, True)
361
  partial_hide_section_dead = partial(show_section_dead, False)
362
 
363
+ butt_wounded.click(
364
+ partial_show_section_wounded,
365
+ inputs=[gr.Text(mode, visible=False), individual],
366
+ outputs=[
367
+ section_wounded,
368
+ individual,
369
+ radio_circumstance_wounded,
370
+ radio_behavior_wounded,
371
+ radio_physical_wounded,
372
+ button_collision_wounded,
373
+ button_deliberate_destruction_wounded,
374
+ button_indirect_destruction_wounded,
375
+ button_natural_cause_wounded,
376
+ dropdown_wounded,
377
+ dropdown_level2_wounded,
378
+ openfield_level2_wounded,
379
+ dropdown_extra_level2_wounded,
380
+ behavior_checkbox,
381
+ behavior_text,
382
+ physical_boxes_wounded,
383
+ checkbox_beak_wounded,
384
+ text_beak_wounded,
385
+ checkbox_body_wounded,
386
+ text_body_wounded,
387
+ checkbox_feathers_wounded,
388
+ text_feathers_wounded,
389
+ checkbox_head_wounded,
390
+ text_head_wounded,
391
+ checkbox_legs_wounded,
392
+ text_legs_wounded,
393
+ fe_collection_dropdown_wounded,
394
+ fe_recepient_dropdown_wounded,
395
+ fe_radio_dropdown_wounded,
396
+ fe_answer_dropdown_wounded,
397
+ fe_name_recipient_wounded,
398
+ fe_collection_ref_wounded,
399
+ ],
400
+ )
401
+
402
+ butt_wounded.click(
403
+ partial_hide_section_dead,
404
+ inputs=[gr.Text(mode, visible=False), individual],
405
+ outputs=[
406
+ section_dead,
407
+ individual,
408
+ radio_circumstance_dead,
409
+ radio_physical_dead,
410
+ button_collision_dead,
411
+ button_deliberate_destruction_dead,
412
+ button_indirect_destruction_dead,
413
+ button_natural_cause_dead,
414
+ dropdown_dead,
415
+ dropdown_level2_dead,
416
+ openfield_level2_dead,
417
+ dropdown_extra_level2_dead,
418
+ physical_boxes_dead,
419
+ checkbox_beak_dead,
420
+ text_beak_dead,
421
+ checkbox_body_dead,
422
+ text_body_dead,
423
+ checkbox_feathers_dead,
424
+ text_feathers_dead,
425
+ checkbox_head_dead,
426
+ text_head_dead,
427
+ checkbox_legs_dead,
428
+ text_legs_dead,
429
+ fe_collection_dropdown_dead,
430
+ fe_recepient_dropdown_dead,
431
+ fe_radio_dropdown_dead,
432
+ fe_answer_dropdown_dead,
433
+ fe_name_recipient_dead,
434
+ fe_collection_ref_dead,
435
+ ],
436
+ )
437
+
438
  # ---------------------------------------------------------
439
  # ---------------------------------------------------------
440
  # ---------------------------------------------------------
 
442
  # DEAD
443
  # ---------------------------------------------------------
444
  # Radio Circumstance Dead
445
+ radio_circumstance_dead.change(
446
+ fn=show_circumstances,
447
+ inputs=[radio_circumstance_dead, individual],
448
+ outputs=[
449
+ button_collision_dead,
450
+ button_deliberate_destruction_dead,
451
+ button_indirect_destruction_dead,
452
+ button_natural_cause_dead,
453
+ dropdown_dead,
454
+ dropdown_level2_dead,
455
+ openfield_level2_dead,
456
+ dropdown_extra_level2_dead,
457
+ individual,
458
+ ],
459
+ )
460
+
461
  # Dropdowns Dead
462
+ button_collision_dead.click(
463
+ dropdown_collision,
464
+ inputs=[individual],
465
+ outputs=[
466
+ dropdown_dead,
467
+ dropdown_level2_dead,
468
+ openfield_level2_dead,
469
+ dropdown_extra_level2_dead,
470
+ individual,
471
+ ],
472
+ )
473
+ button_deliberate_destruction_dead.click(
474
+ dropdown_deliberate_destruction,
475
+ inputs=[individual],
476
+ outputs=[
477
+ dropdown_dead,
478
+ dropdown_level2_dead,
479
+ openfield_level2_dead,
480
+ dropdown_extra_level2_dead,
481
+ individual,
482
+ ],
483
+ )
484
+ button_indirect_destruction_dead.click(
485
+ dropdown_indirect_destruction,
486
+ inputs=[individual],
487
+ outputs=[
488
+ dropdown_dead,
489
+ dropdown_level2_dead,
490
+ openfield_level2_dead,
491
+ dropdown_extra_level2_dead,
492
+ individual,
493
+ ],
494
+ )
495
+ button_natural_cause_dead.click(
496
+ dropdown_natural_cause,
497
+ inputs=[individual],
498
+ outputs=[
499
+ dropdown_dead,
500
+ dropdown_level2_dead,
501
+ openfield_level2_dead,
502
+ dropdown_extra_level2_dead,
503
+ individual,
504
+ ],
505
+ )
506
+
507
+ dropdown_dead.select(
508
+ on_select,
509
+ inputs=[individual],
510
+ outputs=[
511
+ dropdown_level2_dead,
512
+ openfield_level2_dead,
513
+ dropdown_extra_level2_dead,
514
+ individual,
515
+ ],
516
+ )
517
+ dropdown_level2_dead.select(
518
+ on_select_dropdown_level2, inputs=[individual], outputs=[individual]
519
+ )
520
+ openfield_level2_dead.change(
521
+ on_change_openfield_level2,
522
+ inputs=[openfield_level2_dead, individual],
523
+ outputs=[individual],
524
+ )
525
+ dropdown_extra_level2_dead.select(
526
+ on_select_dropdown_extra_level2, inputs=[individual], outputs=[individual]
527
+ )
528
  # ---------------------------------------------------------
529
  # Radio Physical Dead
530
+ radio_physical_dead.change(
531
+ fn=show_physical,
532
+ inputs=[radio_physical_dead, gr.Text("dead", visible=False), individual],
533
+ outputs=[physical_boxes_dead, individual],
534
+ )
535
 
536
  # Checkbox Physical Dead
537
+ physical_boxes_dead.select(
538
+ find_bounding_box,
539
+ inputs=[physical_boxes_dead, gr.Textbox(value="dead", visible=False)],
540
+ outputs=[
541
+ checkbox_beak_dead,
542
+ text_beak_dead,
543
+ checkbox_body_dead,
544
+ text_body_dead,
545
+ checkbox_feathers_dead,
546
+ text_feathers_dead,
547
+ checkbox_head_dead,
548
+ text_head_dead,
549
+ checkbox_legs_dead,
550
+ text_legs_dead,
551
+ ],
552
+ )
553
+ checkbox_beak_dead.select(
554
+ on_select_body_part,
555
+ inputs=[checkbox_beak_dead, gr.Text("beak", visible=False), individual],
556
+ outputs=[individual],
557
+ )
558
+ checkbox_body_dead.select(
559
+ on_select_body_part,
560
+ inputs=[checkbox_body_dead, gr.Text("body", visible=False), individual],
561
+ outputs=[individual],
562
+ )
563
+ checkbox_feathers_dead.select(
564
+ on_select_body_part,
565
+ inputs=[checkbox_feathers_dead, gr.Text("feathers", visible=False), individual],
566
+ outputs=[individual],
567
+ )
568
+ checkbox_head_dead.select(
569
+ on_select_body_part,
570
+ inputs=[checkbox_head_dead, gr.Text("head", visible=False), individual],
571
+ outputs=[individual],
572
+ )
573
+ checkbox_legs_dead.select(
574
+ on_select_body_part,
575
+ inputs=[checkbox_legs_dead, gr.Text("legs", visible=False), individual],
576
+ outputs=[individual],
577
+ )
578
  # ---------------------------------------------------------
579
  # ---------------------------------------------------------
580
  # ---------------------------------------------------------
 
582
  # WOUNDED
583
  # ---------------------------------------------------------
584
  # Radio Circumstance Wounded
585
+ radio_circumstance_wounded.change(
586
+ fn=show_circumstances,
587
+ inputs=[radio_circumstance_wounded, individual],
588
+ outputs=[
589
+ button_collision_wounded,
590
+ button_deliberate_destruction_wounded,
591
+ button_indirect_destruction_wounded,
592
+ button_natural_cause_wounded,
593
+ dropdown_wounded,
594
+ dropdown_level2_wounded,
595
+ openfield_level2_wounded,
596
+ dropdown_extra_level2_wounded,
597
+ individual,
598
+ ],
599
+ )
600
+
601
  # Dropdowns Circumstance Wounded
602
+ button_collision_wounded.click(
603
+ dropdown_collision,
604
+ inputs=[individual],
605
+ outputs=[
606
+ dropdown_wounded,
607
+ dropdown_level2_wounded,
608
+ openfield_level2_wounded,
609
+ dropdown_extra_level2_wounded,
610
+ individual,
611
+ ],
612
+ )
613
+ button_deliberate_destruction_wounded.click(
614
+ dropdown_deliberate_destruction,
615
+ inputs=[individual],
616
+ outputs=[
617
+ dropdown_wounded,
618
+ dropdown_level2_wounded,
619
+ openfield_level2_wounded,
620
+ dropdown_extra_level2_wounded,
621
+ individual,
622
+ ],
623
+ )
624
+ button_indirect_destruction_wounded.click(
625
+ dropdown_indirect_destruction,
626
+ inputs=[individual],
627
+ outputs=[
628
+ dropdown_wounded,
629
+ dropdown_level2_wounded,
630
+ openfield_level2_wounded,
631
+ dropdown_extra_level2_wounded,
632
+ individual,
633
+ ],
634
+ )
635
+ button_natural_cause_wounded.click(
636
+ dropdown_natural_cause,
637
+ inputs=[individual],
638
+ outputs=[
639
+ dropdown_wounded,
640
+ dropdown_level2_wounded,
641
+ openfield_level2_wounded,
642
+ dropdown_extra_level2_wounded,
643
+ individual,
644
+ ],
645
+ )
646
+
647
+ dropdown_wounded.select(
648
+ on_select,
649
+ inputs=[individual],
650
+ outputs=[
651
+ dropdown_level2_wounded,
652
+ openfield_level2_wounded,
653
+ dropdown_extra_level2_wounded,
654
+ individual,
655
+ ],
656
+ )
657
+ dropdown_level2_wounded.select(
658
+ on_select_dropdown_level2, inputs=[individual], outputs=[individual]
659
+ )
660
+ openfield_level2_wounded.change(
661
+ on_change_openfield_level2, inputs=[openfield_level2_wounded, individual]
662
+ )
663
+ dropdown_extra_level2_wounded.select(
664
+ on_select_dropdown_extra_level2, inputs=[individual], outputs=[individual]
665
+ )
666
  # ---------------------------------------------------------
667
  # Radio Behavior Wounded
668
+ radio_behavior_wounded.change(
669
+ fn=show_behavior,
670
+ inputs=[
671
+ radio_behavior_wounded,
672
+ gr.Text("wounded / sick", visible=False),
673
+ gr.Text(mode, visible=False),
674
+ individual,
675
+ ],
676
+ outputs=[behavior_checkbox, behavior_text, individual],
677
+ )
678
+ behavior_checkbox.select(
679
+ on_select_behavior, inputs=[behavior_checkbox, individual], outputs=[individual]
680
+ )
681
  # ---------------------------------------------------------
682
  # Radio Physical Wounded
683
+ radio_physical_wounded.change(
684
+ fn=show_physical,
685
+ inputs=[
686
+ radio_physical_wounded,
687
+ gr.Text("wounded / sick", visible=False),
688
+ individual,
689
+ ],
690
+ outputs=[physical_boxes_wounded, individual],
691
+ )
692
 
693
  # Checkbox Physical Wounded
694
+ physical_boxes_wounded.select(
695
+ find_bounding_box,
696
+ inputs=[
697
+ physical_boxes_wounded,
698
+ gr.Textbox(value="wounded / sick", visible=False),
699
+ ],
700
+ outputs=[
701
+ checkbox_beak_wounded,
702
+ text_beak_wounded,
703
+ checkbox_body_wounded,
704
+ text_body_wounded,
705
+ checkbox_feathers_wounded,
706
+ text_feathers_wounded,
707
+ checkbox_head_wounded,
708
+ text_head_wounded,
709
+ checkbox_legs_wounded,
710
+ text_legs_wounded,
711
+ ],
712
+ )
713
+ checkbox_beak_wounded.select(
714
+ on_select_body_part,
715
+ inputs=[checkbox_beak_wounded, gr.Text("beak", visible=False), individual],
716
+ outputs=[individual],
717
+ )
718
+ checkbox_body_wounded.select(
719
+ on_select_body_part,
720
+ inputs=[checkbox_body_wounded, gr.Text("body", visible=False), individual],
721
+ outputs=[individual],
722
+ )
723
+ checkbox_feathers_wounded.select(
724
+ on_select_body_part,
725
+ inputs=[
726
+ checkbox_feathers_wounded,
727
+ gr.Text("feathers", visible=False),
728
+ individual,
729
+ ],
730
+ outputs=[individual],
731
+ )
732
+ checkbox_head_wounded.select(
733
+ on_select_body_part,
734
+ inputs=[checkbox_head_wounded, gr.Text("head", visible=False), individual],
735
+ outputs=[individual],
736
+ )
737
+ checkbox_legs_wounded.select(
738
+ on_select_body_part,
739
+ inputs=[checkbox_legs_wounded, gr.Text("legs", visible=False), individual],
740
+ outputs=[individual],
741
+ )
742
+
743
  # ---------------------------------------------------------
744
+ # Follow Up Events Wounded
745
+ fe_collection_dropdown_wounded.select(
746
+ save_fe,
747
+ inputs=[
748
+ fe_collection_dropdown_wounded,
749
+ gr.Textbox("animal collected", visible=False),
750
+ individual,
751
+ ],
752
+ outputs=[individual],
753
+ )
754
+ fe_recepient_dropdown_wounded.select(
755
+ save_fe,
756
+ inputs=[
757
+ fe_recepient_dropdown_wounded,
758
+ gr.Textbox("recipient", visible=False),
759
+ individual,
760
+ ],
761
+ outputs=[individual],
762
+ )
763
+ fe_radio_dropdown_wounded.select(
764
+ save_fe,
765
+ inputs=[
766
+ fe_radio_dropdown_wounded,
767
+ gr.Textbox("radiography", visible=False),
768
+ individual,
769
+ ],
770
+ outputs=[individual],
771
+ )
772
+ fe_answer_dropdown_wounded.select(
773
+ save_fe,
774
+ inputs=[
775
+ fe_answer_dropdown_wounded,
776
+ gr.Textbox("given answer", visible=False),
777
+ individual,
778
+ ],
779
+ outputs=[individual],
780
+ )
781
+ fe_name_recipient_wounded.input(
782
+ save_fe,
783
+ inputs=[
784
+ fe_name_recipient_wounded,
785
+ gr.Textbox("recipient name", visible=False),
786
+ individual,
787
+ ],
788
+ outputs=[individual],
789
+ )
790
+ fe_collection_ref_wounded.input(
791
+ save_fe,
792
+ inputs=[
793
+ fe_collection_ref_wounded,
794
+ gr.Textbox("collection reference", visible=False),
795
+ individual,
796
+ ],
797
+ outputs=[individual],
798
+ )
799
 
800
  # ---------------------------------------------------------
801
+ # Follow Up Events Dead
802
+ fe_collection_dropdown_dead.select(
803
+ save_fe,
804
+ inputs=[
805
+ fe_collection_dropdown_dead,
806
+ gr.Textbox("animal collected", visible=False),
807
+ individual,
808
+ ],
809
+ outputs=[individual],
810
+ )
811
+ fe_recepient_dropdown_dead.select(
812
+ save_fe,
813
+ inputs=[
814
+ fe_recepient_dropdown_dead,
815
+ gr.Textbox("recipient", visible=False),
816
+ individual,
817
+ ],
818
+ outputs=[individual],
819
+ )
820
+ fe_radio_dropdown_dead.select(
821
+ save_fe,
822
+ inputs=[
823
+ fe_radio_dropdown_dead,
824
+ gr.Textbox("radiography", visible=False),
825
+ individual,
826
+ ],
827
+ outputs=[individual],
828
+ )
829
+ fe_answer_dropdown_dead.select(
830
+ save_fe,
831
+ inputs=[
832
+ fe_answer_dropdown_dead,
833
+ gr.Textbox("given answer", visible=False),
834
+ individual,
835
+ ],
836
+ outputs=[individual],
837
+ )
838
+ fe_name_recipient_dead.input(
839
+ save_fe,
840
+ inputs=[
841
+ fe_name_recipient_dead,
842
+ gr.Textbox("recipient name", visible=False),
843
+ individual,
844
+ ],
845
+ outputs=[individual],
846
+ )
847
+ fe_collection_ref_dead.input(
848
+ save_fe,
849
+ inputs=[
850
+ fe_collection_ref_dead,
851
+ gr.Textbox("collection reference", visible=False),
852
+ individual,
853
+ ],
854
+ outputs=[individual],
855
+ )
856
 
857
  # ---------------------------------------------------------
858
  # Spacer
859
  with gr.Row(elem_id="centered-row"):
860
+ gr.Image(
861
+ PATH_ICONS + "animal.png",
862
+ height=80,
863
+ width=80,
864
+ interactive=False,
865
+ show_fullscreen_button=False,
866
+ show_share_button=False,
867
+ show_download_button=False,
868
+ show_label=False,
869
+ )
870
+ advanced.css = """
871
  #centered-row {
872
  display: flex;
873
  justify-content: center;
874
  }
875
  """
876
+
877
  # ---------------------------------------------------------
878
  # Error Box
879
+ with gr.Row():
880
+ error_icon = gr.Image(
881
+ PATH_ICONS + "chicken.png", height=80, width=80, visible=False, scale=1
882
+ )
883
  error_box = gr.Text(value=None, visible=False, scale=3)
884
+
 
885
  # ---------------------------------------------------------
886
  # Allow clearing of all previous output
887
+ with gr.Row():
888
+ button_df = gr.Button(
889
+ "SUBMIT OBSERVATION", icon=PATH_ICONS + "effective.png", scale=3
890
+ )
891
+ button_clear = gr.ClearButton(
892
+ value="CLEAR",
893
+ scale=1,
894
+ components=[
895
+ camera,
896
+ location,
897
+ identified_location,
898
+ # dead reset
899
+ radio_circumstance_dead,
900
+ radio_physical_dead,
901
+ button_collision_dead,
902
+ button_deliberate_destruction_dead,
903
+ button_indirect_destruction_dead,
904
+ button_natural_cause_dead,
905
+ dropdown_dead,
906
+ dropdown_level2_dead,
907
+ # openfield_level2_dead,
908
+ dropdown_extra_level2_dead,
909
+ physical_boxes_dead,
910
+ checkbox_beak_dead,
911
+ text_beak_dead,
912
+ checkbox_body_dead,
913
+ text_body_dead,
914
+ checkbox_feathers_dead,
915
+ text_feathers_dead,
916
+ checkbox_head_dead,
917
+ text_head_dead,
918
+ checkbox_legs_dead,
919
+ text_legs_dead,
920
+ fe_collection_dropdown_dead,
921
+ fe_recepient_dropdown_dead,
922
+ fe_radio_dropdown_dead,
923
+ fe_answer_dropdown_dead,
924
+ fe_name_recipient_dead,
925
+ fe_collection_ref_dead,
926
+ # wounded reset
927
+ radio_circumstance_wounded,
928
+ radio_behavior_wounded,
929
+ radio_physical_wounded,
930
+ button_collision_wounded,
931
+ button_deliberate_destruction_wounded,
932
+ button_indirect_destruction_wounded,
933
+ button_natural_cause_wounded,
934
+ dropdown_wounded,
935
+ dropdown_level2_wounded,
936
+ # openfield_level2_wounded,
937
+ dropdown_extra_level2_wounded,
938
+ behavior_checkbox,
939
+ behavior_text,
940
+ physical_boxes_wounded,
941
+ checkbox_beak_wounded,
942
+ text_beak_wounded,
943
+ checkbox_body_wounded,
944
+ text_body_wounded,
945
+ checkbox_feathers_wounded,
946
+ text_feathers_wounded,
947
+ checkbox_head_wounded,
948
+ text_head_wounded,
949
+ checkbox_legs_wounded,
950
+ text_legs_wounded,
951
+ fe_collection_dropdown_wounded,
952
+ fe_recepient_dropdown_wounded,
953
+ fe_radio_dropdown_wounded,
954
+ fe_answer_dropdown_wounded,
955
+ fe_name_recipient_wounded,
956
+ fe_collection_ref_wounded,
957
+ error_icon,
958
+ error_box,
959
+ ],
960
+ )
961
+
962
  # ---------------------------------------------------------
963
+ # VALIDATE ANIMAL
964
+ button_df.click(
965
+ validate_save_individual,
966
+ inputs=[individual, error_icon, error_box, gr.Text(mode, visible=False)],
967
+ outputs=[error_icon, error_box],
968
+ )
969
+
 
970
  # ---------------------------------------------------------
971
  # CLEAR BUTTON
972
  button_clear.click()
973
+ button_clear.click(
974
+ hide_physical,
975
+ inputs=[gr.Text(mode, visible=False)],
976
+ outputs=[
977
+ checkbox_beak_wounded,
978
+ text_beak_wounded,
979
+ checkbox_body_wounded,
980
+ text_body_wounded,
981
+ checkbox_feathers_wounded,
982
+ text_feathers_wounded,
983
+ checkbox_head_wounded,
984
+ text_head_wounded,
985
+ checkbox_legs_wounded,
986
+ text_legs_wounded,
987
+ ],
988
+ )
989
+ button_clear.click(
990
+ hide_physical,
991
+ inputs=[gr.Text(mode, visible=False)],
992
+ outputs=[
993
+ checkbox_beak_dead,
994
+ text_beak_dead,
995
+ checkbox_body_dead,
996
+ text_body_dead,
997
+ checkbox_feathers_dead,
998
+ text_feathers_dead,
999
+ checkbox_head_dead,
1000
+ text_head_dead,
1001
+ checkbox_legs_dead,
1002
+ text_legs_dead,
1003
+ ],
1004
+ )
1005
+ button_clear.click(
1006
+ reset_error_box, inputs=[error_icon, error_box], outputs=[error_icon, error_box]
1007
+ )
1008
  button_clear.click(reset_individual, inputs=[individual], outputs=[individual])
 
app/mode_simple.py CHANGED
@@ -14,39 +14,54 @@ from follow_up.followup_events import save_fe
14
  from styling.style import *
15
  from validation_submission.submission import validate_save_individual
16
  from validation_submission.utils_save import save_details, save_image
17
- from validation_submission.resets import reset_individual, reset_error_box, hide_physical
 
 
 
 
18
 
19
  from dotenv import load_dotenv
20
  import os
 
21
  load_dotenv()
22
  PATH = os.getcwd() + "/"
23
- PATH_ASSETS = os.getenv('PATH_ASSETS')
24
  PATH_ICONS = PATH + PATH_ASSETS + "icons/"
25
 
26
- with gr.Blocks(theme='shivi/calm_seafoam') as simple:
27
  mode = "simple"
28
  individual = gr.State({})
29
  # ---------------------------------------------------------
30
  # Header Text
31
  with gr.Row():
32
- gr.Image(PATH_ICONS+"swallow.png", scale =0.1,
33
- interactive=False,
34
- show_fullscreen_button = False, show_share_button=False,
35
- show_download_button=False, show_label=False)
 
 
 
 
 
36
  with gr.Column(scale=1):
37
  title = gr.Markdown("# Welcome to Digiwild", label="Title")
38
- description = gr.Markdown("## Please record your wildlife observations here !", label="description")
 
 
 
39
 
40
  # ---------------------------------------------------------
41
  # Camera
42
  with gr.Row():
43
  camera = gr.Image(elem_id="image")
44
  camera.input(save_image, inputs=[camera, individual], outputs=[individual])
45
-
46
  # ---------------------------------------------------------
47
  # General Details
48
  with gr.Column(scale=1):
49
- gr.Button("General Details", icon=PATH_ICONS+"pigeon.png", variant="primary")
 
 
50
 
51
  with gr.Row():
52
  specie = gr.Textbox(
@@ -54,12 +69,13 @@ with gr.Blocks(theme='shivi/calm_seafoam') as simple:
54
  placeholder="e.g. European Robin, Common Blackbird",
55
  info="Enter the species name if you can identify it. If unsure, provide your best guess or general description (e.g. 'small brown bird')",
56
  visible=True,
57
- interactive=True
 
 
 
 
 
58
  )
59
- specie.change(save_details,
60
- inputs=[gr.Textbox("specie", visible=False),
61
- specie],
62
- outputs=individual)
63
 
64
  # Number of individuals
65
  with gr.Row():
@@ -69,16 +85,17 @@ with gr.Blocks(theme='shivi/calm_seafoam') as simple:
69
  minimum=1,
70
  precision=0, # Only whole numbers
71
  info="Enter the number of animals observed",
72
- #placeholder="Enter number...",
73
  visible=True,
74
- interactive=True
 
 
 
 
 
75
  )
76
- num_individuals.change(save_details,
77
- inputs=[gr.Textbox("number", visible=False),
78
- num_individuals],
79
- outputs=individual)
80
 
81
- # Introducing text_box for comments
82
  with gr.Row():
83
  comments = gr.TextArea(
84
  label="Additional Comments",
@@ -87,39 +104,62 @@ with gr.Blocks(theme='shivi/calm_seafoam') as simple:
87
  lines=3,
88
  max_lines=5,
89
  visible=True,
90
- interactive=True
 
 
 
 
 
91
  )
92
- comments.change(save_details,
93
- inputs=[gr.Textbox("comments", visible=False),
94
- comments],
95
- outputs=individual)
96
 
97
- with gr.Row():
98
  with gr.Column(scale=1):
99
  # Geolocation
100
- gr.Button("Location", icon=PATH_ICONS+"pin.png", variant="primary")
101
- location_data = gr.JSON(label="Identified GPS Location", visible=False)
102
- hidden_input = gr.Textbox(visible=False, elem_id="textbox_id")
103
- locationtext = gr.Textbox(visible=False, elem_id="textbox_id")
104
- btn_gpslocation = gr.Button("Get Coordinates using GPS (Permission required - May take a few seconds)")
 
 
 
 
 
 
105
  btn_gpslocation.click(None, [], [], js=js_geocode)
106
- hidden_input.change(display_location,
107
- inputs=[hidden_input, individual],
108
- outputs=[locationtext, individual])
109
-
 
 
110
  # ---------------------------------------------------------
111
  # Dead and Wounded Buttons
112
  gr.Button("State of the Animal", variant="primary")
113
  with gr.Row():
114
- gr.Image(PATH_ICONS+"medical-app.png", scale =0.1,
115
- interactive=False,
116
- show_fullscreen_button = False, show_share_button=False,
117
- show_download_button=False, show_label=False)
 
 
 
 
 
118
  with gr.Column():
119
  gr.Markdown("## The State of the Animal", label="Title")
120
- gr.Markdown("Please tell us if the animal was wounded / sick or dead.", label="description")
121
- gr.Markdown("Please fill out as many fields as you can, based on what you can see.", label="description")
122
- gr.Markdown("### DO NOT TOUCH the animal unless absolutely necessary.", label="description")
 
 
 
 
 
 
 
 
 
123
  with gr.Row() as block_form:
124
  with gr.Column(scale=1):
125
  butt_wounded = gr.Button("Wounded / Sick", elem_id="wounded")
@@ -128,24 +168,72 @@ with gr.Blocks(theme='shivi/calm_seafoam') as simple:
128
 
129
  # ---------------------------------------------------------
130
  # Initiate sections
131
- section_dead, individual, radio_circumstance_dead, radio_physical_dead,\
132
- button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead, \
133
- dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, \
134
- physical_boxes_dead, \
135
- 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, \
136
- fe_collection_dropdown_dead, fe_recepient_dropdown_dead, fe_radio_dropdown_dead, fe_answer_dropdown_dead, \
137
- fe_name_recipient_dead, fe_collection_ref_dead \
138
- = show_section_dead(False, mode, individual)
139
-
140
- section_wounded, individual, radio_circumstance_wounded, radio_behavior_wounded, radio_physical_wounded, \
141
- button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded, \
142
- dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, \
143
- behavior_checkbox, behavior_text, \
144
- physical_boxes_wounded, \
145
- 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, \
146
- fe_collection_dropdown_wounded, fe_recepient_dropdown_wounded, fe_radio_dropdown_wounded, fe_answer_dropdown_wounded, \
147
- fe_name_recipient_wounded, fe_collection_ref_wounded \
148
- = show_section_wounded(False, mode, individual)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
 
150
  # ---------------------------------------------------------
151
  # ---------------------------------------------------------
@@ -153,69 +241,161 @@ with gr.Blocks(theme='shivi/calm_seafoam') as simple:
153
  # Dead Button Logic
154
  partial_show_section_dead = partial(show_section_dead, True)
155
  partial_hide_section_wounded = partial(show_section_wounded, False)
156
- butt_dead.click(partial_show_section_dead,
157
- inputs=[gr.Text(mode, visible=False),
158
- individual],
159
- outputs=[section_dead,
160
- individual,
161
- radio_circumstance_dead, radio_physical_dead,
162
- button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead,
163
- dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, \
164
- physical_boxes_dead, \
165
- 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, \
166
- fe_collection_dropdown_dead, fe_recepient_dropdown_dead, fe_radio_dropdown_dead, fe_answer_dropdown_dead, \
167
- fe_name_recipient_dead, fe_collection_ref_dead \
168
- ])
169
-
170
- butt_dead.click(partial_hide_section_wounded,
171
- inputs=[gr.Text(mode, visible=False),
172
- individual],
173
- outputs=[section_wounded,
174
- individual,
175
- radio_circumstance_wounded, radio_behavior_wounded, radio_physical_wounded,
176
- button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded,
177
- dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded,
178
- behavior_checkbox, behavior_text,
179
- physical_boxes_wounded, \
180
- 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, \
181
- fe_collection_dropdown_wounded, fe_recepient_dropdown_wounded, fe_radio_dropdown_wounded, fe_answer_dropdown_wounded, \
182
- fe_name_recipient_wounded, fe_collection_ref_wounded \
183
- ])
184
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  # ---------------------------------------------------------
186
  # Wounded Button Logic
187
  partial_show_section_wounded = partial(show_section_wounded, True)
188
  partial_hide_section_dead = partial(show_section_dead, False)
189
 
190
- butt_wounded.click(partial_show_section_wounded,
191
- inputs=[gr.Text(mode, visible=False),
192
- individual],
193
- outputs=[section_wounded,
194
- individual,
195
- radio_circumstance_wounded, radio_behavior_wounded, radio_physical_wounded,
196
- button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded,
197
- dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded,
198
- behavior_checkbox, behavior_text,
199
- physical_boxes_wounded, \
200
- 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, \
201
- fe_collection_dropdown_wounded, fe_recepient_dropdown_wounded, fe_radio_dropdown_wounded, fe_answer_dropdown_wounded, \
202
- fe_name_recipient_wounded, fe_collection_ref_wounded \
203
- ])
204
-
205
- butt_wounded.click(partial_hide_section_dead,
206
- inputs=[gr.Text(mode, visible=False),
207
- individual],
208
- outputs=[section_dead,
209
- individual,
210
- radio_circumstance_dead, radio_physical_dead,
211
- button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead,
212
- dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, \
213
- physical_boxes_dead, \
214
- 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, \
215
- fe_collection_dropdown_dead, fe_recepient_dropdown_dead, fe_radio_dropdown_dead, fe_answer_dropdown_dead, \
216
- fe_name_recipient_dead, fe_collection_ref_dead \
217
- ])
218
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  # ---------------------------------------------------------
220
  # ---------------------------------------------------------
221
  # ---------------------------------------------------------
@@ -223,48 +403,143 @@ with gr.Blocks(theme='shivi/calm_seafoam') as simple:
223
  # DEAD
224
  # ---------------------------------------------------------
225
  # Radio Circumstance Dead
226
- radio_circumstance_dead.change(fn=show_circumstances,
227
- inputs=[radio_circumstance_dead, individual],
228
- outputs=[button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead,
229
- dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, individual]
230
- )
231
-
 
 
 
 
 
 
 
 
 
 
232
  # Dropdowns Dead
233
- button_collision_dead.click(dropdown_collision,
234
- inputs=[individual],
235
- outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, individual])
236
- button_deliberate_destruction_dead.click(dropdown_deliberate_destruction, inputs=[individual], outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, individual])
237
- button_indirect_destruction_dead.click(dropdown_indirect_destruction, inputs=[individual], outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, individual])
238
- button_natural_cause_dead.click(dropdown_natural_cause, inputs=[individual], outputs=[dropdown_dead, dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, individual])
239
-
240
- dropdown_dead.select(on_select, inputs=[individual], outputs=[dropdown_level2_dead, openfield_level2_dead, dropdown_extra_level2_dead, individual])
241
- dropdown_level2_dead.select(on_select_dropdown_level2, inputs=[individual], outputs=[individual] )
242
- openfield_level2_dead.change(on_change_openfield_level2, inputs=[openfield_level2_dead, individual], outputs=[individual])
243
- dropdown_extra_level2_dead.select(on_select_dropdown_extra_level2, inputs=[individual], outputs=[individual])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  # ---------------------------------------------------------
245
  # Radio Physical Dead
246
- radio_physical_dead.change(fn=show_physical,
247
- inputs=[radio_physical_dead,
248
- gr.Text("dead", visible=False),
249
- individual],
250
- outputs=[physical_boxes_dead, individual])
251
 
252
  # Checkbox Physical Dead
253
- physical_boxes_dead.select(find_bounding_box,
254
- inputs=[physical_boxes_dead,
255
- gr.Textbox(value="dead", visible=False),
256
- gr.Text(mode, visible=False)],
257
- outputs=[checkbox_beak_dead, text_beak_dead,
258
- checkbox_body_dead, text_body_dead,
259
- checkbox_feathers_dead, text_feathers_dead,
260
- checkbox_head_dead, text_head_dead,
261
- checkbox_legs_dead, text_legs_dead
262
- ])
263
- checkbox_beak_dead.select(on_select_body_part, inputs=[checkbox_beak_dead, gr.Text("beak", visible=False), individual], outputs=[individual])
264
- checkbox_body_dead.select(on_select_body_part, inputs=[checkbox_body_dead, gr.Text("body", visible=False), individual], outputs=[individual])
265
- checkbox_feathers_dead.select(on_select_body_part, inputs=[checkbox_feathers_dead, gr.Text("feathers", visible=False), individual], outputs=[individual])
266
- checkbox_head_dead.select(on_select_body_part, inputs=[checkbox_head_dead, gr.Text("head", visible=False), individual], outputs=[individual])
267
- checkbox_legs_dead.select(on_select_body_part, inputs=[checkbox_legs_dead, gr.Text("legs", visible=False), individual], outputs=[individual])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
  # ---------------------------------------------------------
269
  # ---------------------------------------------------------
270
  # ---------------------------------------------------------
@@ -272,159 +547,427 @@ with gr.Blocks(theme='shivi/calm_seafoam') as simple:
272
  # WOUNDED
273
  # ---------------------------------------------------------
274
  # Radio Circumstance Wounded
275
- radio_circumstance_wounded.change(fn=show_circumstances,
276
- inputs=[radio_circumstance_wounded, individual],
277
- outputs=[button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded,
278
- dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, individual]
279
- )
280
-
 
 
 
 
 
 
 
 
 
 
281
  # Dropdowns Circumstance Wounded
282
- button_collision_wounded.click(dropdown_collision,
283
- inputs=[individual],
284
- outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, individual])
285
- button_deliberate_destruction_wounded.click(dropdown_deliberate_destruction, inputs=[individual], outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, individual])
286
- button_indirect_destruction_wounded.click(dropdown_indirect_destruction, inputs=[individual], outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, individual])
287
- button_natural_cause_wounded.click(dropdown_natural_cause, inputs=[individual], outputs=[dropdown_wounded, dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, individual])
288
-
289
- dropdown_wounded.select(on_select, inputs=[individual], outputs=[dropdown_level2_wounded, openfield_level2_wounded, dropdown_extra_level2_wounded, individual])
290
- dropdown_level2_wounded.select(on_select_dropdown_level2, inputs=[individual], outputs=[individual])
291
- openfield_level2_wounded.change(on_change_openfield_level2, inputs=[openfield_level2_wounded, individual])
292
- dropdown_extra_level2_wounded.select(on_select_dropdown_extra_level2, inputs=[individual], outputs=[individual])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  # ---------------------------------------------------------
294
  # Radio Behavior Wounded
295
- radio_behavior_wounded.change(fn=show_behavior,
296
- inputs=[radio_behavior_wounded,
297
- gr.Text("wounded / sick", visible=False),
298
- gr.Text(mode, visible=False),
299
- individual],
300
- outputs=[behavior_checkbox, behavior_text, individual])
301
- behavior_checkbox.select(on_select_behavior,
302
- inputs=[behavior_checkbox, individual],
303
- outputs=[individual])
 
 
 
 
304
  # ---------------------------------------------------------
305
  # Radio Physical Wounded
306
- radio_physical_wounded.change(fn=show_physical,
307
- inputs=[radio_physical_wounded,
308
- gr.Text("wounded / sick", visible=False),
309
- individual],
310
- outputs=[physical_boxes_wounded, individual])
 
 
 
 
311
 
312
  # Checkbox Physical Wounded
313
- physical_boxes_wounded.select(find_bounding_box,
314
- inputs=[physical_boxes_wounded,
315
- gr.Textbox(value="wounded / sick", visible=False),
316
- gr.Text(mode, visible=False)],
317
- outputs=[checkbox_beak_wounded, text_beak_wounded,
318
- checkbox_body_wounded, text_body_wounded,
319
- checkbox_feathers_wounded, text_feathers_wounded,
320
- checkbox_head_wounded, text_head_wounded,
321
- checkbox_legs_wounded, text_legs_wounded
322
- ])
323
- checkbox_beak_wounded.select(on_select_body_part, inputs=[checkbox_beak_wounded, gr.Text("beak", visible=False), individual], outputs=[individual])
324
- checkbox_body_wounded.select(on_select_body_part, inputs=[checkbox_body_wounded, gr.Text("body", visible=False), individual], outputs=[individual])
325
- checkbox_feathers_wounded.select(on_select_body_part, inputs=[checkbox_feathers_wounded, gr.Text("feathers", visible=False), individual], outputs=[individual])
326
- checkbox_head_wounded.select(on_select_body_part, inputs=[checkbox_head_wounded, gr.Text("head", visible=False), individual], outputs=[individual])
327
- checkbox_legs_wounded.select(on_select_body_part, inputs=[checkbox_legs_wounded, gr.Text("legs", visible=False), individual], outputs=[individual])
328
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
  # ---------------------------------------------------------
330
- # Follow Up Events Wounded
331
- fe_collection_dropdown_wounded.select(save_fe, inputs=[fe_collection_dropdown_wounded, gr.Textbox("animal collected", visible=False), individual], outputs=[individual])
332
- fe_recepient_dropdown_wounded.select(save_fe, inputs=[fe_recepient_dropdown_wounded, gr.Textbox("recipient", visible=False), individual],outputs=[individual])
333
- fe_radio_dropdown_wounded.select(save_fe, inputs=[fe_radio_dropdown_wounded, gr.Textbox("radiography", visible=False), individual],outputs=[individual])
334
- fe_answer_dropdown_wounded.select(save_fe, inputs=[fe_answer_dropdown_wounded, gr.Textbox("given answer", visible=False), individual],outputs=[individual])
335
- fe_name_recipient_wounded.input(save_fe, inputs=[fe_name_recipient_wounded, gr.Textbox("recipient name", visible=False), individual],outputs=[individual])
336
- fe_collection_ref_wounded.input(save_fe, inputs=[fe_collection_ref_wounded, gr.Textbox("collection reference", visible=False), individual],outputs=[individual])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
 
338
  # ---------------------------------------------------------
339
- # Follow Up Events Dead
340
- fe_collection_dropdown_dead.select(save_fe, inputs=[fe_collection_dropdown_dead, gr.Textbox("animal collected", visible=False), individual],outputs=[individual])
341
- fe_recepient_dropdown_dead.select(save_fe, inputs=[fe_recepient_dropdown_dead, gr.Textbox("recipient", visible=False), individual],outputs=[individual])
342
- fe_radio_dropdown_dead.select(save_fe, inputs=[fe_radio_dropdown_dead, gr.Textbox("radiography", visible=False), individual],outputs=[individual])
343
- fe_answer_dropdown_dead.select(save_fe, inputs=[fe_answer_dropdown_dead, gr.Textbox("given answer", visible=False), individual],outputs=[individual])
344
- fe_name_recipient_dead.input(save_fe, inputs=[fe_name_recipient_dead, gr.Textbox("recipient name", visible=False), individual],outputs=[individual])
345
- fe_collection_ref_dead.input(save_fe, inputs=[fe_collection_ref_dead, gr.Textbox("collection reference", visible=False), individual], outputs=[individual])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
 
347
  # ---------------------------------------------------------
348
  # Spacer
349
  with gr.Row(elem_id="centered-row"):
350
- gr.Image(PATH_ICONS+"chicken.png", height=80, width=80,
351
- interactive=False,
352
- show_fullscreen_button = False, show_share_button=False,
353
- show_download_button=False, show_label=False)
354
- simple.css = """
 
 
 
 
 
 
355
  #centered-row {
356
  display: flex;
357
  justify-content: center;
358
  }
359
  """
360
-
361
  # ---------------------------------------------------------
362
  # Error Box
363
- with gr.Row():
364
- error_icon = gr.Image(PATH_ICONS+"chicken.png", height=80, width=80, visible=False, scale=1)
 
 
365
  error_box = gr.Text(value=None, visible=False, scale=4)
366
-
367
  # ---------------------------------------------------------
368
  # Allow clearing of all previous output
369
- with gr.Row():
370
- button_df = gr.Button("SUBMIT OBSERVATION", icon=PATH_ICONS+"effective.png",
371
- scale = 3)
372
- button_clear = gr.ClearButton(value="CLEAR / Create NEW Observation",
373
- scale = 2,
374
- icon = PATH_ICONS+"balai-magique.png",
375
- components=[
376
- camera,
377
- #dead reset
378
- radio_circumstance_dead, radio_physical_dead,
379
- button_collision_dead, button_deliberate_destruction_dead, button_indirect_destruction_dead, button_natural_cause_dead,
380
- dropdown_dead, dropdown_level2_dead,
381
- #openfield_level2_dead,
382
- dropdown_extra_level2_dead,
383
- physical_boxes_dead,
384
- 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,
385
- fe_collection_dropdown_dead, fe_recepient_dropdown_dead, fe_radio_dropdown_dead, fe_answer_dropdown_dead,
386
- fe_name_recipient_dead, fe_collection_ref_dead,
387
- #wounded reset
388
- radio_circumstance_wounded, radio_behavior_wounded, radio_physical_wounded,
389
- button_collision_wounded, button_deliberate_destruction_wounded, button_indirect_destruction_wounded, button_natural_cause_wounded,
390
- dropdown_wounded, dropdown_level2_wounded,
391
- #openfield_level2_wounded,
392
- dropdown_extra_level2_wounded,
393
- behavior_checkbox, behavior_text,
394
- physical_boxes_wounded,
395
- 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,
396
- fe_collection_dropdown_wounded, fe_recepient_dropdown_wounded, fe_radio_dropdown_wounded, fe_answer_dropdown_wounded,
397
- fe_name_recipient_wounded, fe_collection_ref_wounded,
398
- error_icon, error_box
399
- ])
400
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
  # ---------------------------------------------------------
402
- # VALIDATE & SUBMIT ANIMAL
403
- button_df.click(validate_save_individual,
404
- inputs=[individual,
405
- error_icon,
406
- error_box,
407
- gr.Text(mode, visible=False)],
408
- outputs=[error_icon, error_box])
409
-
410
- # ---------------------------------------------------------
411
- # CLEAR BUTTON
412
  button_clear.click()
413
- button_clear.click(hide_physical,
414
- inputs=[gr.Text(mode, visible=False)],
415
- outputs=[checkbox_beak_wounded, text_beak_wounded,
416
- checkbox_body_wounded, text_body_wounded,
417
- checkbox_feathers_wounded, text_feathers_wounded,
418
- checkbox_head_wounded, text_head_wounded,
419
- checkbox_legs_wounded, text_legs_wounded])
420
- button_clear.click(hide_physical,
421
- inputs=[gr.Text(mode, visible=False)],
422
- outputs=[checkbox_beak_dead, text_beak_dead,
423
- checkbox_body_dead, text_body_dead,
424
- checkbox_feathers_dead, text_feathers_dead,
425
- checkbox_head_dead, text_head_dead,
426
- checkbox_legs_dead, text_legs_dead])
427
- button_clear.click(reset_error_box, inputs=[error_icon, error_box], outputs=[error_icon, error_box])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
428
  button_clear.click(reset_individual, inputs=[individual], outputs=[individual])
429
-
430
-
 
14
  from styling.style import *
15
  from validation_submission.submission import validate_save_individual
16
  from validation_submission.utils_save import save_details, save_image
17
+ from validation_submission.resets import (
18
+ reset_individual,
19
+ reset_error_box,
20
+ hide_physical,
21
+ )
22
 
23
  from dotenv import load_dotenv
24
  import os
25
+
26
  load_dotenv()
27
  PATH = os.getcwd() + "/"
28
+ PATH_ASSETS = os.getenv("PATH_ASSETS")
29
  PATH_ICONS = PATH + PATH_ASSETS + "icons/"
30
 
31
+ with gr.Blocks(theme="shivi/calm_seafoam") as simple:
32
  mode = "simple"
33
  individual = gr.State({})
34
  # ---------------------------------------------------------
35
  # Header Text
36
  with gr.Row():
37
+ gr.Image(
38
+ PATH_ICONS + "swallow.png",
39
+ scale=0.1,
40
+ interactive=False,
41
+ show_fullscreen_button=False,
42
+ show_share_button=False,
43
+ show_download_button=False,
44
+ show_label=False,
45
+ )
46
  with gr.Column(scale=1):
47
  title = gr.Markdown("# Welcome to Digiwild", label="Title")
48
+ description = gr.Markdown(
49
+ "## Please record your wildlife observations here !",
50
+ label="description",
51
+ )
52
 
53
  # ---------------------------------------------------------
54
  # Camera
55
  with gr.Row():
56
  camera = gr.Image(elem_id="image")
57
  camera.input(save_image, inputs=[camera, individual], outputs=[individual])
58
+
59
  # ---------------------------------------------------------
60
  # General Details
61
  with gr.Column(scale=1):
62
+ gr.Button(
63
+ "General Details", icon=PATH_ICONS + "pigeon.png", variant="primary"
64
+ )
65
 
66
  with gr.Row():
67
  specie = gr.Textbox(
 
69
  placeholder="e.g. European Robin, Common Blackbird",
70
  info="Enter the species name if you can identify it. If unsure, provide your best guess or general description (e.g. 'small brown bird')",
71
  visible=True,
72
+ interactive=True,
73
+ )
74
+ specie.change(
75
+ save_details,
76
+ inputs=[gr.Textbox("specie", visible=False), specie],
77
+ outputs=individual,
78
  )
 
 
 
 
79
 
80
  # Number of individuals
81
  with gr.Row():
 
85
  minimum=1,
86
  precision=0, # Only whole numbers
87
  info="Enter the number of animals observed",
88
+ # placeholder="Enter number...",
89
  visible=True,
90
+ interactive=True,
91
+ )
92
+ num_individuals.change(
93
+ save_details,
94
+ inputs=[gr.Textbox("number", visible=False), num_individuals],
95
+ outputs=individual,
96
  )
 
 
 
 
97
 
98
+ # Introducing text_box for comments
99
  with gr.Row():
100
  comments = gr.TextArea(
101
  label="Additional Comments",
 
104
  lines=3,
105
  max_lines=5,
106
  visible=True,
107
+ interactive=True,
108
+ )
109
+ comments.change(
110
+ save_details,
111
+ inputs=[gr.Textbox("comments", visible=False), comments],
112
+ outputs=individual,
113
  )
 
 
 
 
114
 
115
+ with gr.Row():
116
  with gr.Column(scale=1):
117
  # Geolocation
118
+ gr.Button(
119
+ "Location", icon=PATH_ICONS + "pin.png", variant="primary"
120
+ )
121
+ location_data = gr.JSON(
122
+ label="Identified GPS Location", visible=False
123
+ )
124
+ hidden_input = gr.Textbox(visible=False, elem_id="textbox_id")
125
+ locationtext = gr.Textbox(visible=False, elem_id="textbox_id")
126
+ btn_gpslocation = gr.Button(
127
+ "Get Coordinates using GPS (Permission required - May take a few seconds)"
128
+ )
129
  btn_gpslocation.click(None, [], [], js=js_geocode)
130
+ hidden_input.change(
131
+ display_location,
132
+ inputs=[hidden_input, individual],
133
+ outputs=[locationtext, individual],
134
+ )
135
+
136
  # ---------------------------------------------------------
137
  # Dead and Wounded Buttons
138
  gr.Button("State of the Animal", variant="primary")
139
  with gr.Row():
140
+ gr.Image(
141
+ PATH_ICONS + "medical-app.png",
142
+ scale=0.1,
143
+ interactive=False,
144
+ show_fullscreen_button=False,
145
+ show_share_button=False,
146
+ show_download_button=False,
147
+ show_label=False,
148
+ )
149
  with gr.Column():
150
  gr.Markdown("## The State of the Animal", label="Title")
151
+ gr.Markdown(
152
+ "Please tell us if the animal was wounded / sick or dead.",
153
+ label="description",
154
+ )
155
+ gr.Markdown(
156
+ "Please fill out as many fields as you can, based on what you can see.",
157
+ label="description",
158
+ )
159
+ gr.Markdown(
160
+ "### DO NOT TOUCH the animal unless absolutely necessary.",
161
+ label="description",
162
+ )
163
  with gr.Row() as block_form:
164
  with gr.Column(scale=1):
165
  butt_wounded = gr.Button("Wounded / Sick", elem_id="wounded")
 
168
 
169
  # ---------------------------------------------------------
170
  # Initiate sections
171
+ (
172
+ section_dead,
173
+ individual,
174
+ radio_circumstance_dead,
175
+ radio_physical_dead,
176
+ button_collision_dead,
177
+ button_deliberate_destruction_dead,
178
+ button_indirect_destruction_dead,
179
+ button_natural_cause_dead,
180
+ dropdown_dead,
181
+ dropdown_level2_dead,
182
+ openfield_level2_dead,
183
+ dropdown_extra_level2_dead,
184
+ physical_boxes_dead,
185
+ checkbox_beak_dead,
186
+ text_beak_dead,
187
+ checkbox_body_dead,
188
+ text_body_dead,
189
+ checkbox_feathers_dead,
190
+ text_feathers_dead,
191
+ checkbox_head_dead,
192
+ text_head_dead,
193
+ checkbox_legs_dead,
194
+ text_legs_dead,
195
+ fe_collection_dropdown_dead,
196
+ fe_recepient_dropdown_dead,
197
+ fe_radio_dropdown_dead,
198
+ fe_answer_dropdown_dead,
199
+ fe_name_recipient_dead,
200
+ fe_collection_ref_dead,
201
+ ) = show_section_dead(False, mode, individual)
202
+
203
+ (
204
+ section_wounded,
205
+ individual,
206
+ radio_circumstance_wounded,
207
+ radio_behavior_wounded,
208
+ radio_physical_wounded,
209
+ button_collision_wounded,
210
+ button_deliberate_destruction_wounded,
211
+ button_indirect_destruction_wounded,
212
+ button_natural_cause_wounded,
213
+ dropdown_wounded,
214
+ dropdown_level2_wounded,
215
+ openfield_level2_wounded,
216
+ dropdown_extra_level2_wounded,
217
+ behavior_checkbox,
218
+ behavior_text,
219
+ physical_boxes_wounded,
220
+ checkbox_beak_wounded,
221
+ text_beak_wounded,
222
+ checkbox_body_wounded,
223
+ text_body_wounded,
224
+ checkbox_feathers_wounded,
225
+ text_feathers_wounded,
226
+ checkbox_head_wounded,
227
+ text_head_wounded,
228
+ checkbox_legs_wounded,
229
+ text_legs_wounded,
230
+ fe_collection_dropdown_wounded,
231
+ fe_recepient_dropdown_wounded,
232
+ fe_radio_dropdown_wounded,
233
+ fe_answer_dropdown_wounded,
234
+ fe_name_recipient_wounded,
235
+ fe_collection_ref_wounded,
236
+ ) = show_section_wounded(False, mode, individual)
237
 
238
  # ---------------------------------------------------------
239
  # ---------------------------------------------------------
 
241
  # Dead Button Logic
242
  partial_show_section_dead = partial(show_section_dead, True)
243
  partial_hide_section_wounded = partial(show_section_wounded, False)
244
+ butt_dead.click(
245
+ partial_show_section_dead,
246
+ inputs=[gr.Text(mode, visible=False), individual],
247
+ outputs=[
248
+ section_dead,
249
+ individual,
250
+ radio_circumstance_dead,
251
+ radio_physical_dead,
252
+ button_collision_dead,
253
+ button_deliberate_destruction_dead,
254
+ button_indirect_destruction_dead,
255
+ button_natural_cause_dead,
256
+ dropdown_dead,
257
+ dropdown_level2_dead,
258
+ openfield_level2_dead,
259
+ dropdown_extra_level2_dead,
260
+ physical_boxes_dead,
261
+ checkbox_beak_dead,
262
+ text_beak_dead,
263
+ checkbox_body_dead,
264
+ text_body_dead,
265
+ checkbox_feathers_dead,
266
+ text_feathers_dead,
267
+ checkbox_head_dead,
268
+ text_head_dead,
269
+ checkbox_legs_dead,
270
+ text_legs_dead,
271
+ fe_collection_dropdown_dead,
272
+ fe_recepient_dropdown_dead,
273
+ fe_radio_dropdown_dead,
274
+ fe_answer_dropdown_dead,
275
+ fe_name_recipient_dead,
276
+ fe_collection_ref_dead,
277
+ ],
278
+ )
279
+
280
+ butt_dead.click(
281
+ partial_hide_section_wounded,
282
+ inputs=[gr.Text(mode, visible=False), individual],
283
+ outputs=[
284
+ section_wounded,
285
+ individual,
286
+ radio_circumstance_wounded,
287
+ radio_behavior_wounded,
288
+ radio_physical_wounded,
289
+ button_collision_wounded,
290
+ button_deliberate_destruction_wounded,
291
+ button_indirect_destruction_wounded,
292
+ button_natural_cause_wounded,
293
+ dropdown_wounded,
294
+ dropdown_level2_wounded,
295
+ openfield_level2_wounded,
296
+ dropdown_extra_level2_wounded,
297
+ behavior_checkbox,
298
+ behavior_text,
299
+ physical_boxes_wounded,
300
+ checkbox_beak_wounded,
301
+ text_beak_wounded,
302
+ checkbox_body_wounded,
303
+ text_body_wounded,
304
+ checkbox_feathers_wounded,
305
+ text_feathers_wounded,
306
+ checkbox_head_wounded,
307
+ text_head_wounded,
308
+ checkbox_legs_wounded,
309
+ text_legs_wounded,
310
+ fe_collection_dropdown_wounded,
311
+ fe_recepient_dropdown_wounded,
312
+ fe_radio_dropdown_wounded,
313
+ fe_answer_dropdown_wounded,
314
+ fe_name_recipient_wounded,
315
+ fe_collection_ref_wounded,
316
+ ],
317
+ )
318
+
319
  # ---------------------------------------------------------
320
  # Wounded Button Logic
321
  partial_show_section_wounded = partial(show_section_wounded, True)
322
  partial_hide_section_dead = partial(show_section_dead, False)
323
 
324
+ butt_wounded.click(
325
+ partial_show_section_wounded,
326
+ inputs=[gr.Text(mode, visible=False), individual],
327
+ outputs=[
328
+ section_wounded,
329
+ individual,
330
+ radio_circumstance_wounded,
331
+ radio_behavior_wounded,
332
+ radio_physical_wounded,
333
+ button_collision_wounded,
334
+ button_deliberate_destruction_wounded,
335
+ button_indirect_destruction_wounded,
336
+ button_natural_cause_wounded,
337
+ dropdown_wounded,
338
+ dropdown_level2_wounded,
339
+ openfield_level2_wounded,
340
+ dropdown_extra_level2_wounded,
341
+ behavior_checkbox,
342
+ behavior_text,
343
+ physical_boxes_wounded,
344
+ checkbox_beak_wounded,
345
+ text_beak_wounded,
346
+ checkbox_body_wounded,
347
+ text_body_wounded,
348
+ checkbox_feathers_wounded,
349
+ text_feathers_wounded,
350
+ checkbox_head_wounded,
351
+ text_head_wounded,
352
+ checkbox_legs_wounded,
353
+ text_legs_wounded,
354
+ fe_collection_dropdown_wounded,
355
+ fe_recepient_dropdown_wounded,
356
+ fe_radio_dropdown_wounded,
357
+ fe_answer_dropdown_wounded,
358
+ fe_name_recipient_wounded,
359
+ fe_collection_ref_wounded,
360
+ ],
361
+ )
362
+
363
+ butt_wounded.click(
364
+ partial_hide_section_dead,
365
+ inputs=[gr.Text(mode, visible=False), individual],
366
+ outputs=[
367
+ section_dead,
368
+ individual,
369
+ radio_circumstance_dead,
370
+ radio_physical_dead,
371
+ button_collision_dead,
372
+ button_deliberate_destruction_dead,
373
+ button_indirect_destruction_dead,
374
+ button_natural_cause_dead,
375
+ dropdown_dead,
376
+ dropdown_level2_dead,
377
+ openfield_level2_dead,
378
+ dropdown_extra_level2_dead,
379
+ physical_boxes_dead,
380
+ checkbox_beak_dead,
381
+ text_beak_dead,
382
+ checkbox_body_dead,
383
+ text_body_dead,
384
+ checkbox_feathers_dead,
385
+ text_feathers_dead,
386
+ checkbox_head_dead,
387
+ text_head_dead,
388
+ checkbox_legs_dead,
389
+ text_legs_dead,
390
+ fe_collection_dropdown_dead,
391
+ fe_recepient_dropdown_dead,
392
+ fe_radio_dropdown_dead,
393
+ fe_answer_dropdown_dead,
394
+ fe_name_recipient_dead,
395
+ fe_collection_ref_dead,
396
+ ],
397
+ )
398
+
399
  # ---------------------------------------------------------
400
  # ---------------------------------------------------------
401
  # ---------------------------------------------------------
 
403
  # DEAD
404
  # ---------------------------------------------------------
405
  # Radio Circumstance Dead
406
+ radio_circumstance_dead.change(
407
+ fn=show_circumstances,
408
+ inputs=[radio_circumstance_dead, individual],
409
+ outputs=[
410
+ button_collision_dead,
411
+ button_deliberate_destruction_dead,
412
+ button_indirect_destruction_dead,
413
+ button_natural_cause_dead,
414
+ dropdown_dead,
415
+ dropdown_level2_dead,
416
+ openfield_level2_dead,
417
+ dropdown_extra_level2_dead,
418
+ individual,
419
+ ],
420
+ )
421
+
422
  # Dropdowns Dead
423
+ button_collision_dead.click(
424
+ dropdown_collision,
425
+ inputs=[individual],
426
+ outputs=[
427
+ dropdown_dead,
428
+ dropdown_level2_dead,
429
+ openfield_level2_dead,
430
+ dropdown_extra_level2_dead,
431
+ individual,
432
+ ],
433
+ )
434
+ button_deliberate_destruction_dead.click(
435
+ dropdown_deliberate_destruction,
436
+ inputs=[individual],
437
+ outputs=[
438
+ dropdown_dead,
439
+ dropdown_level2_dead,
440
+ openfield_level2_dead,
441
+ dropdown_extra_level2_dead,
442
+ individual,
443
+ ],
444
+ )
445
+ button_indirect_destruction_dead.click(
446
+ dropdown_indirect_destruction,
447
+ inputs=[individual],
448
+ outputs=[
449
+ dropdown_dead,
450
+ dropdown_level2_dead,
451
+ openfield_level2_dead,
452
+ dropdown_extra_level2_dead,
453
+ individual,
454
+ ],
455
+ )
456
+ button_natural_cause_dead.click(
457
+ dropdown_natural_cause,
458
+ inputs=[individual],
459
+ outputs=[
460
+ dropdown_dead,
461
+ dropdown_level2_dead,
462
+ openfield_level2_dead,
463
+ dropdown_extra_level2_dead,
464
+ individual,
465
+ ],
466
+ )
467
+
468
+ dropdown_dead.select(
469
+ on_select,
470
+ inputs=[individual],
471
+ outputs=[
472
+ dropdown_level2_dead,
473
+ openfield_level2_dead,
474
+ dropdown_extra_level2_dead,
475
+ individual,
476
+ ],
477
+ )
478
+ dropdown_level2_dead.select(
479
+ on_select_dropdown_level2, inputs=[individual], outputs=[individual]
480
+ )
481
+ openfield_level2_dead.change(
482
+ on_change_openfield_level2,
483
+ inputs=[openfield_level2_dead, individual],
484
+ outputs=[individual],
485
+ )
486
+ dropdown_extra_level2_dead.select(
487
+ on_select_dropdown_extra_level2, inputs=[individual], outputs=[individual]
488
+ )
489
  # ---------------------------------------------------------
490
  # Radio Physical Dead
491
+ radio_physical_dead.change(
492
+ fn=show_physical,
493
+ inputs=[radio_physical_dead, gr.Text("dead", visible=False), individual],
494
+ outputs=[physical_boxes_dead, individual],
495
+ )
496
 
497
  # Checkbox Physical Dead
498
+ physical_boxes_dead.select(
499
+ find_bounding_box,
500
+ inputs=[
501
+ physical_boxes_dead,
502
+ gr.Textbox(value="dead", visible=False),
503
+ gr.Text(mode, visible=False),
504
+ ],
505
+ outputs=[
506
+ checkbox_beak_dead,
507
+ text_beak_dead,
508
+ checkbox_body_dead,
509
+ text_body_dead,
510
+ checkbox_feathers_dead,
511
+ text_feathers_dead,
512
+ checkbox_head_dead,
513
+ text_head_dead,
514
+ checkbox_legs_dead,
515
+ text_legs_dead,
516
+ ],
517
+ )
518
+ checkbox_beak_dead.select(
519
+ on_select_body_part,
520
+ inputs=[checkbox_beak_dead, gr.Text("beak", visible=False), individual],
521
+ outputs=[individual],
522
+ )
523
+ checkbox_body_dead.select(
524
+ on_select_body_part,
525
+ inputs=[checkbox_body_dead, gr.Text("body", visible=False), individual],
526
+ outputs=[individual],
527
+ )
528
+ checkbox_feathers_dead.select(
529
+ on_select_body_part,
530
+ inputs=[checkbox_feathers_dead, gr.Text("feathers", visible=False), individual],
531
+ outputs=[individual],
532
+ )
533
+ checkbox_head_dead.select(
534
+ on_select_body_part,
535
+ inputs=[checkbox_head_dead, gr.Text("head", visible=False), individual],
536
+ outputs=[individual],
537
+ )
538
+ checkbox_legs_dead.select(
539
+ on_select_body_part,
540
+ inputs=[checkbox_legs_dead, gr.Text("legs", visible=False), individual],
541
+ outputs=[individual],
542
+ )
543
  # ---------------------------------------------------------
544
  # ---------------------------------------------------------
545
  # ---------------------------------------------------------
 
547
  # WOUNDED
548
  # ---------------------------------------------------------
549
  # Radio Circumstance Wounded
550
+ radio_circumstance_wounded.change(
551
+ fn=show_circumstances,
552
+ inputs=[radio_circumstance_wounded, individual],
553
+ outputs=[
554
+ button_collision_wounded,
555
+ button_deliberate_destruction_wounded,
556
+ button_indirect_destruction_wounded,
557
+ button_natural_cause_wounded,
558
+ dropdown_wounded,
559
+ dropdown_level2_wounded,
560
+ openfield_level2_wounded,
561
+ dropdown_extra_level2_wounded,
562
+ individual,
563
+ ],
564
+ )
565
+
566
  # Dropdowns Circumstance Wounded
567
+ button_collision_wounded.click(
568
+ dropdown_collision,
569
+ inputs=[individual],
570
+ outputs=[
571
+ dropdown_wounded,
572
+ dropdown_level2_wounded,
573
+ openfield_level2_wounded,
574
+ dropdown_extra_level2_wounded,
575
+ individual,
576
+ ],
577
+ )
578
+ button_deliberate_destruction_wounded.click(
579
+ dropdown_deliberate_destruction,
580
+ inputs=[individual],
581
+ outputs=[
582
+ dropdown_wounded,
583
+ dropdown_level2_wounded,
584
+ openfield_level2_wounded,
585
+ dropdown_extra_level2_wounded,
586
+ individual,
587
+ ],
588
+ )
589
+ button_indirect_destruction_wounded.click(
590
+ dropdown_indirect_destruction,
591
+ inputs=[individual],
592
+ outputs=[
593
+ dropdown_wounded,
594
+ dropdown_level2_wounded,
595
+ openfield_level2_wounded,
596
+ dropdown_extra_level2_wounded,
597
+ individual,
598
+ ],
599
+ )
600
+ button_natural_cause_wounded.click(
601
+ dropdown_natural_cause,
602
+ inputs=[individual],
603
+ outputs=[
604
+ dropdown_wounded,
605
+ dropdown_level2_wounded,
606
+ openfield_level2_wounded,
607
+ dropdown_extra_level2_wounded,
608
+ individual,
609
+ ],
610
+ )
611
+
612
+ dropdown_wounded.select(
613
+ on_select,
614
+ inputs=[individual],
615
+ outputs=[
616
+ dropdown_level2_wounded,
617
+ openfield_level2_wounded,
618
+ dropdown_extra_level2_wounded,
619
+ individual,
620
+ ],
621
+ )
622
+ dropdown_level2_wounded.select(
623
+ on_select_dropdown_level2, inputs=[individual], outputs=[individual]
624
+ )
625
+ openfield_level2_wounded.change(
626
+ on_change_openfield_level2, inputs=[openfield_level2_wounded, individual]
627
+ )
628
+ dropdown_extra_level2_wounded.select(
629
+ on_select_dropdown_extra_level2, inputs=[individual], outputs=[individual]
630
+ )
631
  # ---------------------------------------------------------
632
  # Radio Behavior Wounded
633
+ radio_behavior_wounded.change(
634
+ fn=show_behavior,
635
+ inputs=[
636
+ radio_behavior_wounded,
637
+ gr.Text("wounded / sick", visible=False),
638
+ gr.Text(mode, visible=False),
639
+ individual,
640
+ ],
641
+ outputs=[behavior_checkbox, behavior_text, individual],
642
+ )
643
+ behavior_checkbox.select(
644
+ on_select_behavior, inputs=[behavior_checkbox, individual], outputs=[individual]
645
+ )
646
  # ---------------------------------------------------------
647
  # Radio Physical Wounded
648
+ radio_physical_wounded.change(
649
+ fn=show_physical,
650
+ inputs=[
651
+ radio_physical_wounded,
652
+ gr.Text("wounded / sick", visible=False),
653
+ individual,
654
+ ],
655
+ outputs=[physical_boxes_wounded, individual],
656
+ )
657
 
658
  # Checkbox Physical Wounded
659
+ physical_boxes_wounded.select(
660
+ find_bounding_box,
661
+ inputs=[
662
+ physical_boxes_wounded,
663
+ gr.Textbox(value="wounded / sick", visible=False),
664
+ gr.Text(mode, visible=False),
665
+ ],
666
+ outputs=[
667
+ checkbox_beak_wounded,
668
+ text_beak_wounded,
669
+ checkbox_body_wounded,
670
+ text_body_wounded,
671
+ checkbox_feathers_wounded,
672
+ text_feathers_wounded,
673
+ checkbox_head_wounded,
674
+ text_head_wounded,
675
+ checkbox_legs_wounded,
676
+ text_legs_wounded,
677
+ ],
678
+ )
679
+ checkbox_beak_wounded.select(
680
+ on_select_body_part,
681
+ inputs=[checkbox_beak_wounded, gr.Text("beak", visible=False), individual],
682
+ outputs=[individual],
683
+ )
684
+ checkbox_body_wounded.select(
685
+ on_select_body_part,
686
+ inputs=[checkbox_body_wounded, gr.Text("body", visible=False), individual],
687
+ outputs=[individual],
688
+ )
689
+ checkbox_feathers_wounded.select(
690
+ on_select_body_part,
691
+ inputs=[
692
+ checkbox_feathers_wounded,
693
+ gr.Text("feathers", visible=False),
694
+ individual,
695
+ ],
696
+ outputs=[individual],
697
+ )
698
+ checkbox_head_wounded.select(
699
+ on_select_body_part,
700
+ inputs=[checkbox_head_wounded, gr.Text("head", visible=False), individual],
701
+ outputs=[individual],
702
+ )
703
+ checkbox_legs_wounded.select(
704
+ on_select_body_part,
705
+ inputs=[checkbox_legs_wounded, gr.Text("legs", visible=False), individual],
706
+ outputs=[individual],
707
+ )
708
+
709
  # ---------------------------------------------------------
710
+ # Follow Up Events Wounded
711
+ fe_collection_dropdown_wounded.select(
712
+ save_fe,
713
+ inputs=[
714
+ fe_collection_dropdown_wounded,
715
+ gr.Textbox("animal collected", visible=False),
716
+ individual,
717
+ ],
718
+ outputs=[individual],
719
+ )
720
+ fe_recepient_dropdown_wounded.select(
721
+ save_fe,
722
+ inputs=[
723
+ fe_recepient_dropdown_wounded,
724
+ gr.Textbox("recipient", visible=False),
725
+ individual,
726
+ ],
727
+ outputs=[individual],
728
+ )
729
+ fe_radio_dropdown_wounded.select(
730
+ save_fe,
731
+ inputs=[
732
+ fe_radio_dropdown_wounded,
733
+ gr.Textbox("radiography", visible=False),
734
+ individual,
735
+ ],
736
+ outputs=[individual],
737
+ )
738
+ fe_answer_dropdown_wounded.select(
739
+ save_fe,
740
+ inputs=[
741
+ fe_answer_dropdown_wounded,
742
+ gr.Textbox("given answer", visible=False),
743
+ individual,
744
+ ],
745
+ outputs=[individual],
746
+ )
747
+ fe_name_recipient_wounded.input(
748
+ save_fe,
749
+ inputs=[
750
+ fe_name_recipient_wounded,
751
+ gr.Textbox("recipient name", visible=False),
752
+ individual,
753
+ ],
754
+ outputs=[individual],
755
+ )
756
+ fe_collection_ref_wounded.input(
757
+ save_fe,
758
+ inputs=[
759
+ fe_collection_ref_wounded,
760
+ gr.Textbox("collection reference", visible=False),
761
+ individual,
762
+ ],
763
+ outputs=[individual],
764
+ )
765
 
766
  # ---------------------------------------------------------
767
+ # Follow Up Events Dead
768
+ fe_collection_dropdown_dead.select(
769
+ save_fe,
770
+ inputs=[
771
+ fe_collection_dropdown_dead,
772
+ gr.Textbox("animal collected", visible=False),
773
+ individual,
774
+ ],
775
+ outputs=[individual],
776
+ )
777
+ fe_recepient_dropdown_dead.select(
778
+ save_fe,
779
+ inputs=[
780
+ fe_recepient_dropdown_dead,
781
+ gr.Textbox("recipient", visible=False),
782
+ individual,
783
+ ],
784
+ outputs=[individual],
785
+ )
786
+ fe_radio_dropdown_dead.select(
787
+ save_fe,
788
+ inputs=[
789
+ fe_radio_dropdown_dead,
790
+ gr.Textbox("radiography", visible=False),
791
+ individual,
792
+ ],
793
+ outputs=[individual],
794
+ )
795
+ fe_answer_dropdown_dead.select(
796
+ save_fe,
797
+ inputs=[
798
+ fe_answer_dropdown_dead,
799
+ gr.Textbox("given answer", visible=False),
800
+ individual,
801
+ ],
802
+ outputs=[individual],
803
+ )
804
+ fe_name_recipient_dead.input(
805
+ save_fe,
806
+ inputs=[
807
+ fe_name_recipient_dead,
808
+ gr.Textbox("recipient name", visible=False),
809
+ individual,
810
+ ],
811
+ outputs=[individual],
812
+ )
813
+ fe_collection_ref_dead.input(
814
+ save_fe,
815
+ inputs=[
816
+ fe_collection_ref_dead,
817
+ gr.Textbox("collection reference", visible=False),
818
+ individual,
819
+ ],
820
+ outputs=[individual],
821
+ )
822
 
823
  # ---------------------------------------------------------
824
  # Spacer
825
  with gr.Row(elem_id="centered-row"):
826
+ gr.Image(
827
+ PATH_ICONS + "chicken.png",
828
+ height=80,
829
+ width=80,
830
+ interactive=False,
831
+ show_fullscreen_button=False,
832
+ show_share_button=False,
833
+ show_download_button=False,
834
+ show_label=False,
835
+ )
836
+ simple.css = """
837
  #centered-row {
838
  display: flex;
839
  justify-content: center;
840
  }
841
  """
842
+
843
  # ---------------------------------------------------------
844
  # Error Box
845
+ with gr.Row():
846
+ error_icon = gr.Image(
847
+ PATH_ICONS + "chicken.png", height=80, width=80, visible=False, scale=1
848
+ )
849
  error_box = gr.Text(value=None, visible=False, scale=4)
850
+
851
  # ---------------------------------------------------------
852
  # Allow clearing of all previous output
853
+ with gr.Row():
854
+ button_df = gr.Button(
855
+ "SUBMIT OBSERVATION", icon=PATH_ICONS + "effective.png", scale=3
856
+ )
857
+ button_clear = gr.ClearButton(
858
+ value="CLEAR / Create NEW Observation",
859
+ scale=2,
860
+ icon=PATH_ICONS + "balai-magique.png",
861
+ components=[
862
+ camera,
863
+ # dead reset
864
+ radio_circumstance_dead,
865
+ radio_physical_dead,
866
+ button_collision_dead,
867
+ button_deliberate_destruction_dead,
868
+ button_indirect_destruction_dead,
869
+ button_natural_cause_dead,
870
+ dropdown_dead,
871
+ dropdown_level2_dead,
872
+ # openfield_level2_dead,
873
+ dropdown_extra_level2_dead,
874
+ physical_boxes_dead,
875
+ checkbox_beak_dead,
876
+ text_beak_dead,
877
+ checkbox_body_dead,
878
+ text_body_dead,
879
+ checkbox_feathers_dead,
880
+ text_feathers_dead,
881
+ checkbox_head_dead,
882
+ text_head_dead,
883
+ checkbox_legs_dead,
884
+ text_legs_dead,
885
+ fe_collection_dropdown_dead,
886
+ fe_recepient_dropdown_dead,
887
+ fe_radio_dropdown_dead,
888
+ fe_answer_dropdown_dead,
889
+ fe_name_recipient_dead,
890
+ fe_collection_ref_dead,
891
+ # wounded reset
892
+ radio_circumstance_wounded,
893
+ radio_behavior_wounded,
894
+ radio_physical_wounded,
895
+ button_collision_wounded,
896
+ button_deliberate_destruction_wounded,
897
+ button_indirect_destruction_wounded,
898
+ button_natural_cause_wounded,
899
+ dropdown_wounded,
900
+ dropdown_level2_wounded,
901
+ # openfield_level2_wounded,
902
+ dropdown_extra_level2_wounded,
903
+ behavior_checkbox,
904
+ behavior_text,
905
+ physical_boxes_wounded,
906
+ checkbox_beak_wounded,
907
+ text_beak_wounded,
908
+ checkbox_body_wounded,
909
+ text_body_wounded,
910
+ checkbox_feathers_wounded,
911
+ text_feathers_wounded,
912
+ checkbox_head_wounded,
913
+ text_head_wounded,
914
+ checkbox_legs_wounded,
915
+ text_legs_wounded,
916
+ fe_collection_dropdown_wounded,
917
+ fe_recepient_dropdown_wounded,
918
+ fe_radio_dropdown_wounded,
919
+ fe_answer_dropdown_wounded,
920
+ fe_name_recipient_wounded,
921
+ fe_collection_ref_wounded,
922
+ error_icon,
923
+ error_box,
924
+ ],
925
+ )
926
+
927
  # ---------------------------------------------------------
928
+ # VALIDATE & SUBMIT ANIMAL
929
+ button_df.click(
930
+ validate_save_individual,
931
+ inputs=[individual, error_icon, error_box, gr.Text(mode, visible=False)],
932
+ outputs=[error_icon, error_box],
933
+ )
934
+
935
+ # ---------------------------------------------------------
936
+ # CLEAR BUTTON
 
937
  button_clear.click()
938
+ button_clear.click(
939
+ hide_physical,
940
+ inputs=[gr.Text(mode, visible=False)],
941
+ outputs=[
942
+ checkbox_beak_wounded,
943
+ text_beak_wounded,
944
+ checkbox_body_wounded,
945
+ text_body_wounded,
946
+ checkbox_feathers_wounded,
947
+ text_feathers_wounded,
948
+ checkbox_head_wounded,
949
+ text_head_wounded,
950
+ checkbox_legs_wounded,
951
+ text_legs_wounded,
952
+ ],
953
+ )
954
+ button_clear.click(
955
+ hide_physical,
956
+ inputs=[gr.Text(mode, visible=False)],
957
+ outputs=[
958
+ checkbox_beak_dead,
959
+ text_beak_dead,
960
+ checkbox_body_dead,
961
+ text_body_dead,
962
+ checkbox_feathers_dead,
963
+ text_feathers_dead,
964
+ checkbox_head_dead,
965
+ text_head_dead,
966
+ checkbox_legs_dead,
967
+ text_legs_dead,
968
+ ],
969
+ )
970
+ button_clear.click(
971
+ reset_error_box, inputs=[error_icon, error_box], outputs=[error_icon, error_box]
972
+ )
973
  button_clear.click(reset_individual, inputs=[individual], outputs=[individual])
 
 
app/physical/class_physical.py CHANGED
@@ -3,76 +3,66 @@ 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
 
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
+
17
  # --- Beak-related Anomalies ---
18
  class BeakAnomaly(BaseModel):
19
+ type: Literal["beak"]
20
+ anomaly_type: List[Literal["adhesion", "deformation", CommonAnomalies]]
21
+
 
 
 
22
 
23
  # --- Body-related Anomalies ---
24
  class BodyAnomaly(BaseModel):
25
+ type: Literal["body"]
26
+ anomaly_type: List[
27
+ Literal["emaciation", "fluffed up", "stained feathers", CommonAnomalies]
28
+ ]
29
+
 
 
30
 
31
  # --- Legs-related Anomalies ---
32
  class LegAnomaly(BaseModel):
33
+ type: Literal["legs"]
34
+ anomaly_type: List[Literal["missing limb", "deformation", CommonAnomalies]]
35
+
 
 
 
36
 
37
  # --- Feathers/Wings/Tail-related Anomalies ---
38
  class FeathersWingsTailAnomaly(BaseModel):
39
+ type: Literal["feathers/wings/tail"]
40
+ anomaly_type: List[
41
+ Literal[
42
+ "fluffed up",
43
+ "feather abnormalities",
44
+ "stained feathers",
45
+ "abnormal wing posture",
46
+ "missing limb",
47
+ CommonAnomalies,
48
+ ]
49
+ ]
50
+
51
 
52
  # --- Head-related Anomalies (including eyes) ---
53
  class HeadAnomaly(BaseModel):
54
+ type: Literal["head incl. eyes"]
55
+ anomaly_type: List[
56
+ Literal["ear changes", "eye changes", "tilted head", CommonAnomalies]
57
+ ]
 
 
 
58
 
59
 
60
  # Union of all possible anomaly types for specific body parts
61
  AnomalyType = Union[
62
+ BeakAnomaly, BodyAnomaly, LegAnomaly, FeathersWingsTailAnomaly, HeadAnomaly
 
 
 
 
63
  ]
64
 
65
+
66
  # Main PhysicalAnomaly class that logs anomalies across different body parts
67
  class PhysicalAnomalies(BaseModel):
68
  physical_radio: str
app/physical/class_physical_simple.py CHANGED
@@ -2,58 +2,45 @@ from pydantic import BaseModel, Field
2
  from typing import Literal, List, Union, Optional
3
 
4
  # Define common anomalies as a Literal type
5
- CommonAnomaliesSimple = Literal[
6
- 'injury',
7
- 'abnormal position'
8
- ]
9
 
10
  # --- Beak-related Anomalies ---
11
  class BeakAnomaly(BaseModel):
12
- type: Literal['beak']
13
- anomaly_type: List[Literal[
14
- 'adhesion/discharge',
15
- CommonAnomaliesSimple
16
- ]]
17
 
18
  # --- Body-related Anomalies ---
19
  class BodyAnomaly(BaseModel):
20
- type: Literal['body']
21
- anomaly_type: List[Literal[
22
- CommonAnomaliesSimple
23
- ]]
24
 
25
  # --- Feathers/Wings/Tail-related Anomalies ---
26
  class FeathersWingsTailAnomaly(BaseModel):
27
- type: Literal['feathers/wings/tail']
28
- anomaly_type: List[Literal[
29
- 'feather and skin change',
30
- CommonAnomaliesSimple
31
- ]]
32
 
33
  # --- Head-related Anomalies (including eyes) ---
34
  class HeadAnomaly(BaseModel):
35
- type: Literal['head incl. eyes']
36
- anomaly_type: List[Literal[
37
- 'eye changes',
38
- CommonAnomaliesSimple
39
- ]]
40
 
41
  # --- Legs-related Anomalies ---
42
  class LegAnomaly(BaseModel):
43
- type: Literal['legs']
44
- anomaly_type: List[Literal[
45
- CommonAnomaliesSimple
46
- ]]
47
 
48
  # Union of all possible anomaly types for specific body parts
49
  AnomalyTypeSimple = Union[
50
- BeakAnomaly,
51
- BodyAnomaly,
52
- LegAnomaly,
53
- FeathersWingsTailAnomaly,
54
- HeadAnomaly
55
  ]
56
 
 
57
  # Main PhysicalAnomaly class that logs anomalies across different body parts
58
  class PhysicalAnomaliesSimple(BaseModel):
59
  physical_radio: str
 
2
  from typing import Literal, List, Union, Optional
3
 
4
  # Define common anomalies as a Literal type
5
+ CommonAnomaliesSimple = Literal["injury", "abnormal position"]
6
+
 
 
7
 
8
  # --- Beak-related Anomalies ---
9
  class BeakAnomaly(BaseModel):
10
+ type: Literal["beak"]
11
+ anomaly_type: List[Literal["adhesion/discharge", CommonAnomaliesSimple]]
12
+
 
 
13
 
14
  # --- Body-related Anomalies ---
15
  class BodyAnomaly(BaseModel):
16
+ type: Literal["body"]
17
+ anomaly_type: List[Literal[CommonAnomaliesSimple]]
18
+
 
19
 
20
  # --- Feathers/Wings/Tail-related Anomalies ---
21
  class FeathersWingsTailAnomaly(BaseModel):
22
+ type: Literal["feathers/wings/tail"]
23
+ anomaly_type: List[Literal["feather and skin change", CommonAnomaliesSimple]]
24
+
 
 
25
 
26
  # --- Head-related Anomalies (including eyes) ---
27
  class HeadAnomaly(BaseModel):
28
+ type: Literal["head incl. eyes"]
29
+ anomaly_type: List[Literal["eye changes", CommonAnomaliesSimple]]
30
+
 
 
31
 
32
  # --- Legs-related Anomalies ---
33
  class LegAnomaly(BaseModel):
34
+ type: Literal["legs"]
35
+ anomaly_type: List[Literal[CommonAnomaliesSimple]]
36
+
 
37
 
38
  # Union of all possible anomaly types for specific body parts
39
  AnomalyTypeSimple = Union[
40
+ BeakAnomaly, BodyAnomaly, LegAnomaly, FeathersWingsTailAnomaly, HeadAnomaly
 
 
 
 
41
  ]
42
 
43
+
44
  # Main PhysicalAnomaly class that logs anomalies across different body parts
45
  class PhysicalAnomaliesSimple(BaseModel):
46
  physical_radio: str
app/physical/physical_boxes_define.py CHANGED
@@ -6,18 +6,18 @@ bounding_boxes = [
6
  box(250, 375, 350, 485),
7
  # 'Beak and mouth region',
8
  box(200, 450, 250, 485),
9
- # 'Feathers/Wings/Tail',
10
- box(50, 100, 725, 355),
11
- # 'Legs',
12
  box(325, 585, 450, 675),
13
  # 'Body'
14
- box(275, 510, 500, 565)
15
  ]
16
 
17
  # Create a GeoDataFrame from these boxes
18
- gdf = gpd.GeoDataFrame({'geometry': bounding_boxes,
19
- 'name': ['Head incl. eyes',
20
- 'Beak',
21
- 'Feathers/Wings/Tail',
22
- 'Legs',
23
- 'Body']})
 
6
  box(250, 375, 350, 485),
7
  # 'Beak and mouth region',
8
  box(200, 450, 250, 485),
9
+ # 'Feathers/Wings/Tail',
10
+ box(50, 100, 725, 355),
11
+ # 'Legs',
12
  box(325, 585, 450, 675),
13
  # 'Body'
14
+ box(275, 510, 500, 565),
15
  ]
16
 
17
  # Create a GeoDataFrame from these boxes
18
+ gdf = gpd.GeoDataFrame(
19
+ {
20
+ "geometry": bounding_boxes,
21
+ "name": ["Head incl. eyes", "Beak", "Feathers/Wings/Tail", "Legs", "Body"],
22
+ }
23
+ )
app/physical/physical_boxes_map.py CHANGED
@@ -4,27 +4,29 @@ 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")
13
  # Convert the image to an editable format
14
  draw = ImageDraw.Draw(image)
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
 
21
  # Draw each bounding box on the image
22
  for _, row in gdf.iterrows():
23
- xmin, ymin, xmax, ymax = row['geometry'].bounds
24
  draw.rectangle([xmin, ymin, xmax, ymax], outline="purple", width=2)
25
- draw.text((xmin, ymin-22), row['name'], fill="black", font=font)
 
 
26
 
27
- image.save(image_path+'bird_boxed.png', "PNG")
28
 
29
  if __name__ == "__main__":
30
- draw_bounding_boxes(PATH_ASSETS + 'images/', gdf)
 
4
 
5
  from dotenv import load_dotenv
6
  import os
7
+
8
  load_dotenv()
9
+ PATH_ASSETS = os.getenv("PATH_ASSETS")
10
+
11
 
12
  # Function to draw the bounding boxes on the image
13
  def draw_bounding_boxes(image_path, gdf):
14
+ image = Image.open(image_path + "bird.png").convert("RGB")
15
  # Convert the image to an editable format
16
  draw = ImageDraw.Draw(image)
17
 
18
  # Optional: Load a font (requires a TTF file)
19
  # try:
20
+ font = ImageFont.truetype(PATH_ASSETS + "fonts/LiberationSans-Regular.ttf", 20)
 
21
 
22
  # Draw each bounding box on the image
23
  for _, row in gdf.iterrows():
24
+ xmin, ymin, xmax, ymax = row["geometry"].bounds
25
  draw.rectangle([xmin, ymin, xmax, ymax], outline="purple", width=2)
26
+ draw.text((xmin, ymin - 22), row["name"], fill="black", font=font)
27
+
28
+ image.save(image_path + "bird_boxed.png", "PNG")
29
 
 
30
 
31
  if __name__ == "__main__":
32
+ draw_bounding_boxes(PATH_ASSETS + "images/", gdf)
app/physical/physical_checkbox.py CHANGED
@@ -130,4 +130,3 @@ def on_select_body_part(body_part_checkbox, body_part, individual):
130
  "physical_anomaly_" + body_part.lower(), body_part_checkbox, individual
131
  )
132
  return individual
133
-
 
130
  "physical_anomaly_" + body_part.lower(), body_part_checkbox, individual
131
  )
132
  return individual
 
app/physical/physical_select_animal.py CHANGED
@@ -11,7 +11,8 @@ from utils.utils_visible import set_visible
11
  from validation_submission.utils_individual import add_data_to_individual
12
 
13
  load_dotenv()
14
- PATH_ASSETS = os.getenv('PATH_ASSETS')
 
15
 
16
  # Function to find the matching bounding box for a given point and return the image with boxes
17
  def find_bounding_box(evt: gr.SelectData, img, section: str, mode: str):
@@ -19,33 +20,62 @@ def find_bounding_box(evt: gr.SelectData, img, section: str, mode: str):
19
  point = Point(x, y)
20
  match = gdf[gdf.contains(point)]
21
  if not match.empty:
22
- matched_box = match.iloc[0]['name']
23
- checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs = process_body_parts(section, mode, matched_box)
 
 
 
 
 
 
 
 
 
 
 
24
  else:
25
  matched_box = None
26
- checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs = process_body_parts(section, mode, matched_box)
27
- return checkbox_beak, text_beak, checkbox_body, text_body, checkbox_feathers, text_feathers, checkbox_head, text_head, checkbox_legs, text_legs
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
-
30
 
31
  # Gradio app
32
  def create_bird_anatomy(visible, section: str):
33
  # Draw bounding boxes on the image
34
- img_with_boxes = gr.Image(value=PATH_ASSETS+'images/bird_boxed.png',
35
- show_label=False,
36
- height="600px",
37
- elem_id=section,
38
- visible=visible)
 
 
39
  return img_with_boxes
40
 
41
- def show_physical(choice, section: str, individual):
 
42
  visible = set_visible(choice)
43
  physical_boxes = create_bird_anatomy(visible, section)
44
  individual = add_data_to_individual("physical_radio", choice, individual)
45
  return physical_boxes, individual
46
-
47
-
48
-
49
-
50
-
51
-
 
11
  from validation_submission.utils_individual import add_data_to_individual
12
 
13
  load_dotenv()
14
+ PATH_ASSETS = os.getenv("PATH_ASSETS")
15
+
16
 
17
  # Function to find the matching bounding box for a given point and return the image with boxes
18
  def find_bounding_box(evt: gr.SelectData, img, section: str, mode: str):
 
20
  point = Point(x, y)
21
  match = gdf[gdf.contains(point)]
22
  if not match.empty:
23
+ matched_box = match.iloc[0]["name"]
24
+ (
25
+ checkbox_beak,
26
+ text_beak,
27
+ checkbox_body,
28
+ text_body,
29
+ checkbox_feathers,
30
+ text_feathers,
31
+ checkbox_head,
32
+ text_head,
33
+ checkbox_legs,
34
+ text_legs,
35
+ ) = process_body_parts(section, mode, matched_box)
36
  else:
37
  matched_box = None
38
+ (
39
+ checkbox_beak,
40
+ text_beak,
41
+ checkbox_body,
42
+ text_body,
43
+ checkbox_feathers,
44
+ text_feathers,
45
+ checkbox_head,
46
+ text_head,
47
+ checkbox_legs,
48
+ text_legs,
49
+ ) = process_body_parts(section, mode, matched_box)
50
+ return (
51
+ checkbox_beak,
52
+ text_beak,
53
+ checkbox_body,
54
+ text_body,
55
+ checkbox_feathers,
56
+ text_feathers,
57
+ checkbox_head,
58
+ text_head,
59
+ checkbox_legs,
60
+ text_legs,
61
+ )
62
 
 
63
 
64
  # Gradio app
65
  def create_bird_anatomy(visible, section: str):
66
  # Draw bounding boxes on the image
67
+ img_with_boxes = gr.Image(
68
+ value=PATH_ASSETS + "images/bird_boxed.png",
69
+ show_label=False,
70
+ height="600px",
71
+ elem_id=section,
72
+ visible=visible,
73
+ )
74
  return img_with_boxes
75
 
76
+
77
+ def show_physical(choice, section: str, individual):
78
  visible = set_visible(choice)
79
  physical_boxes = create_bird_anatomy(visible, section)
80
  individual = add_data_to_individual("physical_radio", choice, individual)
81
  return physical_boxes, individual
 
 
 
 
 
 
app/styling/style.py CHANGED
@@ -1,6 +1,7 @@
1
- import gradio as gr
2
 
3
- gr.HTML('''
 
4
  <style>
5
  # .custom-button {
6
  # background-color: #3B4C54;
@@ -16,7 +17,8 @@ gr.HTML('''
16
  # border-radius: 8px;
17
  # }
18
  </style>
19
- ''')
 
20
 
21
  # gr.HTML('''
22
  # <style>
@@ -34,4 +36,4 @@ gr.HTML('''
34
  # border-radius: 8px;
35
  # }
36
  # </style>
37
- # ''')
 
1
+ import gradio as gr
2
 
3
+ gr.HTML(
4
+ """
5
  <style>
6
  # .custom-button {
7
  # background-color: #3B4C54;
 
17
  # border-radius: 8px;
18
  # }
19
  </style>
20
+ """
21
+ )
22
 
23
  # gr.HTML('''
24
  # <style>
 
36
  # border-radius: 8px;
37
  # }
38
  # </style>
39
+ # ''')
app/styling/theme.py CHANGED
@@ -1,4 +1,4 @@
1
- css_for_error_box= """
2
  #error {background-color: #e82323 !important;
3
  color: white !important;
4
  font-weight: bold;}
@@ -17,10 +17,10 @@ body {
17
  }
18
 
19
  /* Secondary color for headers and panels */
20
- .gradio-container .card,
21
- .gradio-container h1,
22
- .gradio-container h2,
23
- .gradio-container h3,
24
  .gradio-container h4 {
25
  background-color: #3F543B;
26
  color: #ffffff; /* Ensuring text is readable */
@@ -36,11 +36,11 @@ body {
36
  }
37
 
38
  /* Olive green color for headers within the wounded section */
39
- #wounded h1,
40
- #wounded h2,
41
- #wounded h3,
42
- #wounded h4,
43
- #wounded h5,
44
  #wounded h6 {
45
  color: #ffffff; /* Olive green color for header text */
46
  background-color: #503B54; /* No background color for headers */
@@ -74,11 +74,11 @@ body {
74
  }
75
 
76
  /* Brown color for headers within the dead section */
77
- #dead h1,
78
- #dead h2,
79
- #dead h3,
80
- #dead h4,
81
- #dead h5,
82
  #dead h6 {
83
  color: #ffffff; /* Olive green color for header text */
84
  background-color: #54433B; /* No background color for headers */
 
1
+ css_for_error_box = """
2
  #error {background-color: #e82323 !important;
3
  color: white !important;
4
  font-weight: bold;}
 
17
  }
18
 
19
  /* Secondary color for headers and panels */
20
+ .gradio-container .card,
21
+ .gradio-container h1,
22
+ .gradio-container h2,
23
+ .gradio-container h3,
24
  .gradio-container h4 {
25
  background-color: #3F543B;
26
  color: #ffffff; /* Ensuring text is readable */
 
36
  }
37
 
38
  /* Olive green color for headers within the wounded section */
39
+ #wounded h1,
40
+ #wounded h2,
41
+ #wounded h3,
42
+ #wounded h4,
43
+ #wounded h5,
44
  #wounded h6 {
45
  color: #ffffff; /* Olive green color for header text */
46
  background-color: #503B54; /* No background color for headers */
 
74
  }
75
 
76
  /* Brown color for headers within the dead section */
77
+ #dead h1,
78
+ #dead h2,
79
+ #dead h3,
80
+ #dead h4,
81
+ #dead h5,
82
  #dead h6 {
83
  color: #ffffff; /* Olive green color for header text */
84
  background-color: #54433B; /* No background color for headers */
app/sync_dataset_hf.py CHANGED
@@ -1,7 +1,7 @@
1
  from datasets import load_dataset, DownloadMode
2
  import json
3
- import os
4
- from huggingface_hub import HfApi , hf_hub_download
5
 
6
  dataset_id = "SDSC/digiwild-dataset"
7
  token = os.getenv("HUGGINGFACE_TOKEN")
@@ -13,23 +13,19 @@ api = HfApi(token=token)
13
  files = api.list_repo_files(dataset_id, repo_type="dataset")
14
  json_files = [file for file in files if file.endswith(".json")]
15
 
16
- # Load the metadata compilation
17
- try:
18
  data_files = "data/train-00000-of-00001.parquet"
19
- metadata = load_dataset(
20
- dataset_id,
21
- data_files=data_files)
22
- # Add new json entries to dataset
23
- for file in json_files:
24
  file = hf_hub_download(repo_id=dataset_id, filename=file, repo_type="dataset")
25
  with open(file, "r") as f:
26
  new = json.load(f)
27
- if not(new["image_md5"] in metadata["train"]["image_md5"]):
28
  metadata["train"] = metadata["train"].add_item(new)
29
- except:
30
- metadata = load_dataset(
31
- dataset_id,
32
- data_files=json_files)
33
 
34
 
35
- metadata.push_to_hub(dataset_id, token=token)
 
1
  from datasets import load_dataset, DownloadMode
2
  import json
3
+ import os
4
+ from huggingface_hub import HfApi, hf_hub_download
5
 
6
  dataset_id = "SDSC/digiwild-dataset"
7
  token = os.getenv("HUGGINGFACE_TOKEN")
 
13
  files = api.list_repo_files(dataset_id, repo_type="dataset")
14
  json_files = [file for file in files if file.endswith(".json")]
15
 
16
+ # Load the metadata compilation
17
+ try:
18
  data_files = "data/train-00000-of-00001.parquet"
19
+ metadata = load_dataset(dataset_id, data_files=data_files)
20
+ # Add new json entries to dataset
21
+ for file in json_files:
 
 
22
  file = hf_hub_download(repo_id=dataset_id, filename=file, repo_type="dataset")
23
  with open(file, "r") as f:
24
  new = json.load(f)
25
+ if not (new["image_md5"] in metadata["train"]["image_md5"]):
26
  metadata["train"] = metadata["train"].add_item(new)
27
+ except:
28
+ metadata = load_dataset(dataset_id, data_files=json_files)
 
 
29
 
30
 
31
+ metadata.push_to_hub(dataset_id, token=token)
app/utils/utils_checkbox.py CHANGED
@@ -1,18 +1,28 @@
1
  import gradio as gr
2
 
3
- #---------------------------------------------------------
 
4
  def create_checkbox(value, section, label_checkbox, visible, options, descriptions):
5
- descriptions_info = "<br><br>".join([f"* **{option}**: {description}" for option, description in zip(options, descriptions)])
6
- checkbox = gr.CheckboxGroup(options,
7
- label=label_checkbox + f" {value}:",
8
- visible=visible,
9
- interactive=True,
10
- elem_id=section)
11
- text = gr.Markdown(descriptions_info,
12
- label = "Info",
13
- visible=visible,
14
- #interactive=False,
15
- #lines=13,
16
- #max_lines=15,
17
- elem_id=section)
18
- return checkbox, text
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
 
3
+
4
+ # ---------------------------------------------------------
5
  def create_checkbox(value, section, label_checkbox, visible, options, descriptions):
6
+ descriptions_info = "<br><br>".join(
7
+ [
8
+ f"* **{option}**: {description}"
9
+ for option, description in zip(options, descriptions)
10
+ ]
11
+ )
12
+ checkbox = gr.CheckboxGroup(
13
+ options,
14
+ label=label_checkbox + f" {value}:",
15
+ visible=visible,
16
+ interactive=True,
17
+ elem_id=section,
18
+ )
19
+ text = gr.Markdown(
20
+ descriptions_info,
21
+ label="Info",
22
+ visible=visible,
23
+ # interactive=False,
24
+ # lines=13,
25
+ # max_lines=15,
26
+ elem_id=section,
27
+ )
28
+ return checkbox, text
app/utils/utils_config.py CHANGED
@@ -2,19 +2,20 @@ 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:
12
  config = json.load(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
-
20
-
 
2
  import os
3
  from dotenv import load_dotenv
4
  import os
5
+
6
  load_dotenv()
7
  PATH = os.getcwd() + "/"
8
+ PATH_ASSETS = os.getenv("PATH_ASSETS")
9
  PATH_CONFIG = PATH + PATH_ASSETS + "config/"
10
 
11
+
12
  def load_config(file_path):
13
  with open(file_path) as f:
14
  config = json.load(f)
15
  return config
16
 
17
+
18
  def get_custom_config_dropdowns(config_path):
19
  dropdown_config_path = PATH_CONFIG + config_path
20
  dropdown_config = load_config(dropdown_config_path)
21
  return dropdown_config
 
 
app/utils/utils_visible.py CHANGED
@@ -1,6 +1,6 @@
1
  def set_visible(choice):
2
- if choice=="Yes":
3
  visible = True
4
  else:
5
- visible=False
6
- return visible
 
1
  def set_visible(choice):
2
+ if choice == "Yes":
3
  visible = True
4
  else:
5
+ visible = False
6
+ return visible
app/validation_submission/processing.py CHANGED
@@ -1,71 +1,89 @@
1
- #### PROCESS FUNCTIONS
 
2
 
3
  def process_circumstance(data):
4
  fields_to_check = ["option_dropdown", "open_field", "extra"]
5
- reformatted ={}
6
- if ("circumstance_radio" in data.keys()) and ("circumstance" in data.keys()) and ("circumstance_type" in data.keys()) and (data["circumstance_radio"] == "Yes"):
 
 
 
 
 
7
  reformatted["circumstance_radio"] = data["circumstance_radio"]
8
  reformatted["circumstance"] = data["circumstance"]
9
  reformatted["circumstance_type"] = {}
10
- if "type" in data["circumstance_type"]:
11
  reformatted["circumstance_type"]["type"] = data["circumstance_type"]["type"]
12
  for field in fields_to_check:
13
- if not data["circumstance_type"][field+"_label"] == "NA":
14
  val = data[f"circumstance_{field}"]
15
- key = data["circumstance_type"][field+"_label"]
16
  reformatted["circumstance_type"][key] = val
17
- else:
18
  reformatted["circumstance_radio"] = None
19
  reformatted["circumstance"] = None
20
  reformatted["circumstance_type"] = {}
21
  return reformatted
22
 
 
23
  def process_behaviors(data):
24
- behaviors =[]
25
  reformatted = {}
26
- if ("behaviors_radio" in data.keys()) and ("behaviors_type" in data.keys()) and (data["behaviors_radio"] == "Yes"):
 
 
 
 
27
  reformatted["behaviors_radio"] = data["behaviors_radio"]
28
- for type in data["behaviors_type"]:
29
  new_behavior = {}
30
  new_behavior["type"] = type
31
  behaviors.append(new_behavior)
32
  reformatted["behaviors_type"] = behaviors
33
- else:
34
  reformatted["behaviors_radio"] = None
35
  reformatted["behaviors_type"] = []
36
- return reformatted
 
37
 
38
  def process_physical(data):
39
- body_parts= ["beak", "body", "legs", "feathers/wings/tail", "head incl. eyes"]
40
  body_parts_search = ["beak", "body", "legs", "feathers", "head"]
41
- anomalies=[]
42
  reformatted = {}
43
- if ("physical_radio" in data.keys()) and (data["physical_radio"] == "Yes") and any("type_" in key for key in data.keys()) and any("anomaly_" in key for key in data.keys()):
 
 
 
 
 
44
  reformatted["physical_radio"] = data["physical_radio"]
45
  for b, body_part in enumerate(body_parts_search):
46
  anomaly = {}
47
- for key, val in data.items():
48
- if "type_"+ body_part in key:
49
  anomaly["type"] = body_parts[b]
50
- elif "anomaly_"+ body_part in key:
51
  anomaly["anomaly_type"] = val
52
- if anomaly:
53
  anomalies.append(anomaly)
54
  reformatted["physical_anomalies_type"] = anomalies
55
- else:
56
  reformatted["physical_radio"] = None
57
  reformatted["physical_anomalies_type"] = []
58
  return reformatted
59
 
 
60
  def process_followup(data):
61
  followup_events = []
62
- for key, val in data.items():
63
- followup_event={}
64
  type = key.split("followup")[-1]
65
  option = type.split(" ")[-1]
66
  followup_event["type"] = type.strip()
67
- followup_event[option.strip()] = val
68
  followup_events.append(followup_event)
69
- reformatted ={}
70
  reformatted["follow_up_events"] = followup_events
71
- return reformatted
 
1
+ #### PROCESS FUNCTIONS
2
+
3
 
4
  def process_circumstance(data):
5
  fields_to_check = ["option_dropdown", "open_field", "extra"]
6
+ reformatted = {}
7
+ if (
8
+ ("circumstance_radio" in data.keys())
9
+ and ("circumstance" in data.keys())
10
+ and ("circumstance_type" in data.keys())
11
+ and (data["circumstance_radio"] == "Yes")
12
+ ):
13
  reformatted["circumstance_radio"] = data["circumstance_radio"]
14
  reformatted["circumstance"] = data["circumstance"]
15
  reformatted["circumstance_type"] = {}
16
+ if "type" in data["circumstance_type"]:
17
  reformatted["circumstance_type"]["type"] = data["circumstance_type"]["type"]
18
  for field in fields_to_check:
19
+ if not data["circumstance_type"][field + "_label"] == "NA":
20
  val = data[f"circumstance_{field}"]
21
+ key = data["circumstance_type"][field + "_label"]
22
  reformatted["circumstance_type"][key] = val
23
+ else:
24
  reformatted["circumstance_radio"] = None
25
  reformatted["circumstance"] = None
26
  reformatted["circumstance_type"] = {}
27
  return reformatted
28
 
29
+
30
  def process_behaviors(data):
31
+ behaviors = []
32
  reformatted = {}
33
+ if (
34
+ ("behaviors_radio" in data.keys())
35
+ and ("behaviors_type" in data.keys())
36
+ and (data["behaviors_radio"] == "Yes")
37
+ ):
38
  reformatted["behaviors_radio"] = data["behaviors_radio"]
39
+ for type in data["behaviors_type"]:
40
  new_behavior = {}
41
  new_behavior["type"] = type
42
  behaviors.append(new_behavior)
43
  reformatted["behaviors_type"] = behaviors
44
+ else:
45
  reformatted["behaviors_radio"] = None
46
  reformatted["behaviors_type"] = []
47
+ return reformatted
48
+
49
 
50
  def process_physical(data):
51
+ body_parts = ["beak", "body", "legs", "feathers/wings/tail", "head incl. eyes"]
52
  body_parts_search = ["beak", "body", "legs", "feathers", "head"]
53
+ anomalies = []
54
  reformatted = {}
55
+ if (
56
+ ("physical_radio" in data.keys())
57
+ and (data["physical_radio"] == "Yes")
58
+ and any("type_" in key for key in data.keys())
59
+ and any("anomaly_" in key for key in data.keys())
60
+ ):
61
  reformatted["physical_radio"] = data["physical_radio"]
62
  for b, body_part in enumerate(body_parts_search):
63
  anomaly = {}
64
+ for key, val in data.items():
65
+ if "type_" + body_part in key:
66
  anomaly["type"] = body_parts[b]
67
+ elif "anomaly_" + body_part in key:
68
  anomaly["anomaly_type"] = val
69
+ if anomaly:
70
  anomalies.append(anomaly)
71
  reformatted["physical_anomalies_type"] = anomalies
72
+ else:
73
  reformatted["physical_radio"] = None
74
  reformatted["physical_anomalies_type"] = []
75
  return reformatted
76
 
77
+
78
  def process_followup(data):
79
  followup_events = []
80
+ for key, val in data.items():
81
+ followup_event = {}
82
  type = key.split("followup")[-1]
83
  option = type.split(" ")[-1]
84
  followup_event["type"] = type.strip()
85
+ followup_event[option.strip()] = val
86
  followup_events.append(followup_event)
87
+ reformatted = {}
88
  reformatted["follow_up_events"] = followup_events
89
+ return reformatted
app/validation_submission/resets.py CHANGED
@@ -4,17 +4,22 @@ from physical.physical_checkbox import process_body_parts
4
 
5
  from dotenv import load_dotenv
6
  import os
 
7
  load_dotenv()
8
  PATH = os.getcwd() + "/"
9
- PATH_ASSETS = os.getenv('PATH_ASSETS')
10
  PATH_ICONS = PATH + PATH_ASSETS + "icons/"
11
 
 
12
  def reset_individual(individual):
13
  individual = {}
14
  return individual
15
 
 
16
  def reset_error_box(error_icon, error_box):
17
- error_icon = gr.Image(PATH_ICONS+"supprimer.png", height=80, width=80, visible=False)
 
 
18
  error_box = gr.Text(value=None, visible=False)
19
  return error_icon, error_box
20
 
 
4
 
5
  from dotenv import load_dotenv
6
  import os
7
+
8
  load_dotenv()
9
  PATH = os.getcwd() + "/"
10
+ PATH_ASSETS = os.getenv("PATH_ASSETS")
11
  PATH_ICONS = PATH + PATH_ASSETS + "icons/"
12
 
13
+
14
  def reset_individual(individual):
15
  individual = {}
16
  return individual
17
 
18
+
19
  def reset_error_box(error_icon, error_box):
20
+ error_icon = gr.Image(
21
+ PATH_ICONS + "supprimer.png", height=80, width=80, visible=False
22
+ )
23
  error_box = gr.Text(value=None, visible=False)
24
  return error_icon, error_box
25
 
app/validation_submission/submission.py CHANGED
@@ -1,12 +1,14 @@
1
  import json
2
  from validation_submission.validation import validate_individual
3
- import gradio as gr
4
  from huggingface_hub import HfApi
5
  import os
6
 
7
 
8
  def validate_save_individual(data, error_icon, error_box, mode):
9
- individual, error_icon, error_box = validate_individual(data, error_icon, error_box, mode)
 
 
10
  if individual:
11
  print("pushing to hugging face")
12
  push_to_dataset_hf(individual.model_dump())
 
1
  import json
2
  from validation_submission.validation import validate_individual
3
+ import gradio as gr
4
  from huggingface_hub import HfApi
5
  import os
6
 
7
 
8
  def validate_save_individual(data, error_icon, error_box, mode):
9
+ individual, error_icon, error_box = validate_individual(
10
+ data, error_icon, error_box, mode
11
+ )
12
  if individual:
13
  print("pushing to hugging face")
14
  push_to_dataset_hf(individual.model_dump())
app/validation_submission/utils_individual.py CHANGED
@@ -2,16 +2,15 @@ import random
2
  import string
3
  import hashlib
4
 
 
5
  def generate_random_md5():
6
  # Generate a random string
7
- random_string = ''.join(random.choices(string.ascii_letters + string.digits, k=16))
8
  # Encode the string and compute its MD5 hash
9
  md5_hash = hashlib.md5(random_string.encode()).hexdigest()
10
  return md5_hash
11
 
12
- def add_data_to_individual(key, value, individual):
 
13
  individual[key] = value
14
  return individual
15
-
16
-
17
-
 
2
  import string
3
  import hashlib
4
 
5
+
6
  def generate_random_md5():
7
  # Generate a random string
8
+ random_string = "".join(random.choices(string.ascii_letters + string.digits, k=16))
9
  # Encode the string and compute its MD5 hash
10
  md5_hash = hashlib.md5(random_string.encode()).hexdigest()
11
  return md5_hash
12
 
13
+
14
+ def add_data_to_individual(key, value, individual):
15
  individual[key] = value
16
  return individual
 
 
 
app/validation_submission/utils_save.py CHANGED
@@ -1,9 +1,11 @@
1
  from validation_submission.utils_individual import add_data_to_individual
2
 
 
3
  def save_details(tag, data, individual):
4
- individual = add_data_to_individual(tag, data, individual)
5
- return individual
 
6
 
7
  def save_image(camera, individual):
8
- individual = add_data_to_individual("image", camera.tolist(), individual)
9
- return individual
 
1
  from validation_submission.utils_individual import add_data_to_individual
2
 
3
+
4
  def save_details(tag, data, individual):
5
+ individual = add_data_to_individual(tag, data, individual)
6
+ return individual
7
+
8
 
9
  def save_image(camera, individual):
10
+ individual = add_data_to_individual("image", camera.tolist(), individual)
11
+ return individual
app/validation_submission/validation.py CHANGED
@@ -20,9 +20,10 @@ from validation_submission.resets import reset_error_box
20
 
21
  from dotenv import load_dotenv
22
  import os
 
23
  load_dotenv()
24
  PATH = os.getcwd() + "/"
25
- PATH_ASSETS = os.getenv('PATH_ASSETS')
26
  PATH_ICONS = PATH + PATH_ASSETS + "icons/"
27
 
28
 
@@ -33,14 +34,18 @@ def get_fields(data_dict, keyword):
33
  extract[key] = val
34
  return extract
35
 
 
36
  def field_checker(data):
37
  img = ImageBase64.to_base64(data["image"]) if "image" in data.keys() else None
38
- geolocalisation = data["geolocalisation"] if "geolocalisation" in data.keys() else None
 
 
39
  specie = data["specie"] if "specie" in data.keys() else "NA"
40
- number = data["number"] if "specie" in data.keys() else 1
41
  comments = data["comments"] if "specie" in data.keys() else "NA"
42
  return img, geolocalisation, specie, number, comments
43
 
 
44
  def validate_individual(data, error_icon, error_box, mode: str):
45
  error_icon, error_box = reset_error_box(error_icon, error_box)
46
  # data = get_json_one_individual() # TODO: This should change
@@ -57,7 +62,7 @@ def validate_individual(data, error_icon, error_box, mode: str):
57
  data["wounded_state"] = "No"
58
  data["dead_state"] = "No"
59
  if (data["wounded_state"] == "Yes") or (data["dead_state"] == "Yes"):
60
- data_wounded_dead = data
61
  circumstance, error_circumstance = validate_circumstance(data_wounded_dead)
62
  physical, error_physical = validate_physical(data_wounded_dead, mode)
63
  followup, error_followup = validate_follow_up(data_wounded_dead)
@@ -127,11 +132,17 @@ def validate_individual(data, error_icon, error_box, mode: str):
127
  or error_physical
128
  or error_individual
129
  ):
130
- error_icon = gr.Image(PATH_ICONS+"supprimer.png", height=80, width=80,
131
- interactive=False,
132
- show_fullscreen_button = False, show_share_button=False,
133
- show_download_button=False, show_label=False,
134
- visible=True)
 
 
 
 
 
 
135
  error_box = show_error(
136
  error_box,
137
  error_behavior,
@@ -142,11 +153,17 @@ def validate_individual(data, error_icon, error_box, mode: str):
142
  )
143
  individual = None
144
  else:
145
- error_icon = gr.Image(PATH_ICONS+"correct.png", height=80, width=80,
146
- interactive=False,
147
- show_fullscreen_button = False, show_share_button=False,
148
- show_download_button=False, show_label=False,
149
- visible=True)
 
 
 
 
 
 
150
  error_box = gr.Text(
151
  label="ALL VALID.",
152
  value="Record Registered. Remember to press the CLEAR button before submitting a new record.",
 
20
 
21
  from dotenv import load_dotenv
22
  import os
23
+
24
  load_dotenv()
25
  PATH = os.getcwd() + "/"
26
+ PATH_ASSETS = os.getenv("PATH_ASSETS")
27
  PATH_ICONS = PATH + PATH_ASSETS + "icons/"
28
 
29
 
 
34
  extract[key] = val
35
  return extract
36
 
37
+
38
  def field_checker(data):
39
  img = ImageBase64.to_base64(data["image"]) if "image" in data.keys() else None
40
+ geolocalisation = (
41
+ data["geolocalisation"] if "geolocalisation" in data.keys() else None
42
+ )
43
  specie = data["specie"] if "specie" in data.keys() else "NA"
44
+ number = data["number"] if "specie" in data.keys() else 1
45
  comments = data["comments"] if "specie" in data.keys() else "NA"
46
  return img, geolocalisation, specie, number, comments
47
 
48
+
49
  def validate_individual(data, error_icon, error_box, mode: str):
50
  error_icon, error_box = reset_error_box(error_icon, error_box)
51
  # data = get_json_one_individual() # TODO: This should change
 
62
  data["wounded_state"] = "No"
63
  data["dead_state"] = "No"
64
  if (data["wounded_state"] == "Yes") or (data["dead_state"] == "Yes"):
65
+ data_wounded_dead = data
66
  circumstance, error_circumstance = validate_circumstance(data_wounded_dead)
67
  physical, error_physical = validate_physical(data_wounded_dead, mode)
68
  followup, error_followup = validate_follow_up(data_wounded_dead)
 
132
  or error_physical
133
  or error_individual
134
  ):
135
+ error_icon = gr.Image(
136
+ PATH_ICONS + "supprimer.png",
137
+ height=80,
138
+ width=80,
139
+ interactive=False,
140
+ show_fullscreen_button=False,
141
+ show_share_button=False,
142
+ show_download_button=False,
143
+ show_label=False,
144
+ visible=True,
145
+ )
146
  error_box = show_error(
147
  error_box,
148
  error_behavior,
 
153
  )
154
  individual = None
155
  else:
156
+ error_icon = gr.Image(
157
+ PATH_ICONS + "correct.png",
158
+ height=80,
159
+ width=80,
160
+ interactive=False,
161
+ show_fullscreen_button=False,
162
+ show_share_button=False,
163
+ show_download_button=False,
164
+ show_label=False,
165
+ visible=True,
166
+ )
167
  error_box = gr.Text(
168
  label="ALL VALID.",
169
  value="Record Registered. Remember to press the CLEAR button before submitting a new record.",
requirements.txt CHANGED
@@ -5,4 +5,4 @@ geopandas
5
  pillow
6
  python-dotenv
7
  datasets
8
- huggingface_hub
 
5
  pillow
6
  python-dotenv
7
  datasets
8
+ huggingface_hub