Wall06 commited on
Commit
a69b66d
·
verified ·
1 Parent(s): 88da70d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +157 -71
app.py CHANGED
@@ -4,57 +4,86 @@ import pandas as pd
4
  import plotly.express as px
5
 
6
  # ================================================================
7
- # Core Logic
8
  # ================================================================
9
 
10
  def process_species_data(species_name, habitat, water_disturbance, land_disturbance, noise_level):
11
  if not species_name:
12
  return "Please enter a species name.", None, None
13
 
14
- # 1. Fetch Wikipedia
 
15
  wiki_url = "https://en.wikipedia.org/w/api.php"
 
 
 
16
  params = {
17
- "action": "query", "format": "json", "prop": "extracts",
18
- "titles": species_name.replace(" ", "_"), "explaintext": True
 
 
 
 
19
  }
20
 
21
  try:
22
- response = requests.get(wiki_url, params=params).json()
23
  pages = response.get("query", {}).get("pages", {})
 
24
  if "-1" in pages:
25
- extract = "Species not found in Wikipedia."
26
  else:
27
  page = next(iter(pages.values()))
28
  extract = page.get("extract", "No summary available.")
29
- except:
30
- extract = "Error fetching data."
 
31
 
32
- # Pad text
33
  words = extract.split()
34
- if len(words) < 200:
35
- extract += "\n\n" + ("Conservation of this species is critical for biodiversity. " * 5)
36
 
37
- summary = " ".join(words[:300]) + "..."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
- # Analysis text
40
- analysis = f"""
 
 
 
 
 
41
 
42
- ENVIRONMENTAL IMPACT REPORT
43
- ---------------------------
44
- Habitat: {habitat}
45
- Water Stress: {water_disturbance}/100
46
- Land Stress: {land_disturbance}/100
47
- Noise Level: {noise_level}/100
 
48
  """
49
 
50
- full_text = summary + analysis
51
 
52
- # 2. Fetch GBIF Map
53
  gbif_url = f"https://api.gbif.org/v1/occurrence/search?scientificName={species_name}&limit=300"
54
  coords = []
55
  try:
56
  gbif_res = requests.get(gbif_url).json()
57
- for r in gbif_res.get("results", []):
 
58
  if r.get("decimalLatitude") and r.get("decimalLongitude"):
59
  coords.append({"lat": r.get("decimalLatitude"), "lon": r.get("decimalLongitude")})
60
  except:
@@ -68,83 +97,140 @@ def process_species_data(species_name, habitat, water_disturbance, land_disturba
68
  fig = px.scatter_mapbox(pd.DataFrame({"lat":[], "lon":[]}), lat="lat", lon="lon", zoom=0)
69
  fig.update_layout(mapbox_style="open-street-map", margin={"r":0,"t":0,"l":0,"b":0})
70
 
71
- # 3. Create File
72
  filename = "BioVigilus_Report.txt"
73
  with open(filename, "w", encoding="utf-8") as f:
74
- f.write(f"=== BioVigilus Biodiversity Report ===\n{full_text}")
75
 
76
- return full_text, fig, filename
77
 
78
  # ================================================================
79
- # MANUAL BEAUTIFICATION (CSS Injection)
80
  # ================================================================
81
- # This CSS runs inside the browser, so Python won't crash.
82
 
83
- beauty_css = """
84
  <style>
85
- body, .gradio-container {
86
- background: linear-gradient(135deg, #e8f5e9 0%, #c8e6c9 100%) !important;
87
- font-family: sans-serif;
88
  }
89
- h1 {
90
- color: #1b5e20;
91
- text-align: center;
 
 
92
  font-weight: 800;
93
- margin-bottom: 10px;
 
 
 
94
  }
95
- .custom-box {
96
- background: white;
97
- padding: 20px;
98
- border-radius: 12px;
99
- border: 1px solid #a5d6a7;
100
- box-shadow: 0 4px 15px rgba(0,0,0,0.1);
 
101
  }
102
- /* Make the button green */
103
- button.primary {
104
- background: #2e7d32 !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  color: white !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  }
107
  </style>
108
  """
109
 
110
  # ================================================================
111
- # UI Layout (Strict Safe Mode)
112
  # ================================================================
113
 
114
- # CRITICAL: Do NOT put theme= or css= inside gr.Blocks(...)
115
  with gr.Blocks() as demo:
116
 
117
- # We inject the style here instead
118
- gr.HTML(beauty_css)
119
 
120
- gr.Markdown("# 🌿 BioVigilus")
121
- gr.Markdown("<p style='text-align:center; color:#2e7d32'><b>Biodiversity Impact & Species Distribution Analyzer</b></p>")
 
 
 
122
 
123
  with gr.Row():
124
- # Left Column
125
- with gr.Column(elem_classes="custom-box"):
126
- # Note: if 'elem_classes' fails in super old versions, the app will still run, just without white box bg
127
- gr.Markdown("### 🔍 Configuration")
128
- species_name = gr.Textbox(label="Scientific Name", placeholder="e.g. Panthera tigris")
 
 
 
 
129
  habitat = gr.Dropdown(
130
- ["Tropical Rainforest", "Savanna", "Desert", "Wetlands", "Urban"],
131
- label="Habitat", value="Tropical Rainforest"
 
132
  )
133
 
134
- gr.Markdown("### ⚠️ Stress Factors")
135
- water = gr.Slider(0, 100, label="Water Disturbance")
136
- land = gr.Slider(0, 100, label="Land Disturbance")
137
- noise = gr.Slider(0, 100, label="Noise Level")
138
-
139
- analyze_btn = gr.Button("Analyze Impact", variant="primary")
140
-
141
- # Right Column
142
- with gr.Column(elem_classes="custom-box"):
143
- gr.Markdown("### 🌍 Results")
144
- out_summary = gr.Textbox(label="Summary", lines=8)
145
- out_map = gr.Plot(label="Map")
146
- out_file = gr.File(label="Download Report")
 
 
 
 
 
 
 
 
 
 
147
 
 
148
  analyze_btn.click(
149
  process_species_data,
150
  inputs=[species_name, habitat, water, land, noise],
 
4
  import plotly.express as px
5
 
6
  # ================================================================
7
+ # 1. Core Logic (Robust Data Fetching)
8
  # ================================================================
9
 
10
  def process_species_data(species_name, habitat, water_disturbance, land_disturbance, noise_level):
11
  if not species_name:
12
  return "Please enter a species name.", None, None
13
 
14
+ # --- A. Fetch Wikipedia Data (FIXED) ---
15
+ # We must use a User-Agent header, otherwise Wikipedia blocks the request.
16
  wiki_url = "https://en.wikipedia.org/w/api.php"
17
+ headers = {
18
+ 'User-Agent': 'BioVigilusApp/1.0 (educational-research-project)'
19
+ }
20
  params = {
21
+ "action": "query",
22
+ "format": "json",
23
+ "prop": "extracts",
24
+ "titles": species_name.replace(" ", "_"),
25
+ "explaintext": True,
26
+ "exintro": False, # We want the full article, not just the intro
27
  }
28
 
29
  try:
30
+ response = requests.get(wiki_url, params=params, headers=headers).json()
31
  pages = response.get("query", {}).get("pages", {})
32
+
33
  if "-1" in pages:
34
+ extract = f"Species '{species_name}' not found. Please check spelling (e.g., use 'Panthera tigris' instead of 'Tiger')."
35
  else:
36
  page = next(iter(pages.values()))
37
  extract = page.get("extract", "No summary available.")
38
+
39
+ except Exception as e:
40
+ extract = f"Connection Error: {str(e)}"
41
 
42
+ # --- B. Length Enforcement (150-250 words) ---
43
  words = extract.split()
 
 
44
 
45
+ # If text is too short (less than 150 words), we append general educational info to make it robust
46
+ if len(words) < 150:
47
+ educational_filler = (
48
+ "\n\n[Additional Ecological Context]\n"
49
+ f"The species {species_name} is an integral part of its local food web. "
50
+ "Biodiversity loss regarding this species could trigger a trophic cascade, affecting both prey and predator populations. "
51
+ "Conservationists monitor such species as bio-indicators of environmental health. "
52
+ "Preserving their natural habitat is essential not just for their survival, but for the stability of the entire ecosystem. "
53
+ "Effective conservation strategies include habitat restoration, anti-poaching laws, and community awareness programs."
54
+ )
55
+ extract += educational_filler
56
+ words = extract.split() # Update word count
57
+
58
+ # Cap at ~250 words for the UI summary to keep it concise but detailed
59
+ summary_text = " ".join(words[:250]) + "..."
60
 
61
+ # --- C. Impact Analysis (Appended to Summary) ---
62
+ analysis_section = f"""
63
+
64
+ ------------------------------------------------
65
+ 📊 ENVIRONMENTAL IMPACT ANALYSIS
66
+ ------------------------------------------------
67
+ • Target Habitat: {habitat}
68
 
69
+ ⚠️ STRESS INDICATORS:
70
+ • Water Stress: {water_disturbance}/100
71
+ (High levels indicate pollution or drought risk)
72
+ Land Disturbance: {land_disturbance}/100
73
+ (Reflects habitat fragmentation or loss)
74
+ Noise Pollution: {noise_level}/100
75
+ (Impacts communication and breeding patterns)
76
  """
77
 
78
+ final_output = summary_text + analysis_section
79
 
80
+ # --- D. Fetch GBIF Map Data ---
81
  gbif_url = f"https://api.gbif.org/v1/occurrence/search?scientificName={species_name}&limit=300"
82
  coords = []
83
  try:
84
  gbif_res = requests.get(gbif_url).json()
85
+ results = gbif_res.get("results", [])
86
+ for r in results:
87
  if r.get("decimalLatitude") and r.get("decimalLongitude"):
88
  coords.append({"lat": r.get("decimalLatitude"), "lon": r.get("decimalLongitude")})
89
  except:
 
97
  fig = px.scatter_mapbox(pd.DataFrame({"lat":[], "lon":[]}), lat="lat", lon="lon", zoom=0)
98
  fig.update_layout(mapbox_style="open-street-map", margin={"r":0,"t":0,"l":0,"b":0})
99
 
100
+ # --- E. Create Download File ---
101
  filename = "BioVigilus_Report.txt"
102
  with open(filename, "w", encoding="utf-8") as f:
103
+ f.write(f"=== BioVigilus Project Report ===\n{final_output}")
104
 
105
+ return final_output, fig, filename
106
 
107
  # ================================================================
108
+ # 2. VIBRANT CSS (High Contrast & Professional)
109
  # ================================================================
 
110
 
111
+ vibrant_css = """
112
  <style>
113
+ /* Main Background - Stronger Gradient */
114
+ .gradio-container {
115
+ background: linear-gradient(135deg, #004d40 0%, #2e7d32 100%) !important;
116
  }
117
+
118
+ /* Main Title - White and Bold */
119
+ #main-title {
120
+ color: #ffffff !important;
121
+ font-family: 'Poppins', sans-serif;
122
  font-weight: 800;
123
+ font-size: 2.5rem;
124
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
125
+ text-align: center;
126
+ margin-bottom: 5px;
127
  }
128
+
129
+ /* Subtitle */
130
+ #sub-title {
131
+ color: #a5d6a7 !important;
132
+ font-size: 1.2rem;
133
+ text-align: center;
134
+ margin-bottom: 25px;
135
  }
136
+
137
+ /* Cards - Pure White with Strong Shadow */
138
+ .custom-card {
139
+ background: #ffffff !important;
140
+ padding: 25px !important;
141
+ border-radius: 12px !important;
142
+ box-shadow: 0 10px 30px rgba(0,0,0,0.2) !important;
143
+ border: none !important;
144
+ }
145
+
146
+ /* Input Labels */
147
+ label span {
148
+ color: #1b5e20 !important;
149
+ font-weight: bold !important;
150
+ font-size: 1rem !important;
151
+ }
152
+
153
+ /* Button - Gradient Green */
154
+ #analyze-btn {
155
+ background: linear-gradient(90deg, #1b5e20 0%, #2e7d32 100%) !important;
156
  color: white !important;
157
+ font-size: 1.1rem !important;
158
+ border-radius: 8px !important;
159
+ border: none !important;
160
+ box-shadow: 0 4px 15px rgba(0,0,0,0.2) !important;
161
+ }
162
+ #analyze-btn:hover {
163
+ transform: translateY(-2px);
164
+ box-shadow: 0 6px 20px rgba(0,0,0,0.3) !important;
165
+ }
166
+
167
+ /* Summary Text Box */
168
+ textarea {
169
+ font-size: 1rem !important;
170
+ line-height: 1.6 !important;
171
+ color: #333 !important;
172
+ background-color: #f9f9f9 !important;
173
+ border: 1px solid #ddd !important;
174
  }
175
  </style>
176
  """
177
 
178
  # ================================================================
179
+ # 3. UI Layout
180
  # ================================================================
181
 
 
182
  with gr.Blocks() as demo:
183
 
184
+ # Inject CSS
185
+ gr.HTML(vibrant_css)
186
 
187
+ # Header Section
188
+ gr.HTML("""
189
+ <div id="main-title">🌿 BioVigilus</div>
190
+ <div id="sub-title">Advanced Biodiversity & Environmental Stress Analyzer</div>
191
+ """)
192
 
193
  with gr.Row():
194
+ # --- LEFT: INPUTS ---
195
+ with gr.Column(elem_classes="custom-card"):
196
+ gr.Markdown("### 🔍 Species Configuration")
197
+ species_name = gr.Textbox(
198
+ label="Scientific Name",
199
+ placeholder="e.g. Panthera tigris",
200
+ value="Panthera tigris"
201
+ )
202
+
203
  habitat = gr.Dropdown(
204
+ ["Tropical Rainforest", "Savanna", "Desert", "Wetlands", "Urban", "Marine"],
205
+ label="Habitat Environment",
206
+ value="Tropical Rainforest"
207
  )
208
 
209
+ gr.Markdown("---")
210
+ gr.Markdown("### ⚠️ Environmental Stressors")
211
+
212
+ water = gr.Slider(0, 100, value=25, label="Water Pollution Level")
213
+ land = gr.Slider(0, 100, value=65, label="Land Degradation")
214
+ noise = gr.Slider(0, 100, value=30, label="Noise Pollution (dB impact)")
215
+
216
+ analyze_btn = gr.Button("🚀 Run Analysis", elem_id="analyze-btn")
217
+
218
+ # --- RIGHT: OUTPUTS ---
219
+ with gr.Column(elem_classes="custom-card"):
220
+ gr.Markdown("### 📊 Analysis Results")
221
+
222
+ # Summary Box with Scrollbar logic (lines=12 creates a tall box, overflow handles scrolling)
223
+ out_summary = gr.Textbox(
224
+ label="Ecological Summary & Impact Report",
225
+ lines=12, # Ensures it's tall enough to require scrolling for long text
226
+ interactive=False,
227
+ show_copy_button=True
228
+ )
229
+
230
+ out_map = gr.Plot(label="Global Occurrence Map")
231
+ out_file = gr.File(label="📥 Download Full Report")
232
 
233
+ # Click Event
234
  analyze_btn.click(
235
  process_species_data,
236
  inputs=[species_name, habitat, water, land, noise],