bio / app.py
Wall06's picture
Update app.py
98c0a64 verified
import gradio as gr
import requests
import pandas as pd
import plotly.express as px
# ================================================================
# 1. Core Logic (Robust Data Fetching)
# ================================================================
def process_species_data(species_name, habitat, water_disturbance, land_disturbance, noise_level):
if not species_name:
return "Please enter a species name.", None, None
# --- A. Fetch Wikipedia Data (With User-Agent Fix) ---
wiki_url = "https://en.wikipedia.org/w/api.php"
headers = {
'User-Agent': 'BioVigilusApp/1.0 (educational-research-project)'
}
params = {
"action": "query",
"format": "json",
"prop": "extracts",
"titles": species_name.replace(" ", "_"),
"explaintext": True,
"exintro": False,
}
try:
response = requests.get(wiki_url, params=params, headers=headers).json()
pages = response.get("query", {}).get("pages", {})
if "-1" in pages:
extract = f"Species '{species_name}' not found. Please check spelling (e.g., use 'Panthera tigris' instead of 'Tiger')."
else:
page = next(iter(pages.values()))
extract = page.get("extract", "No summary available.")
except Exception as e:
extract = f"Connection Error: {str(e)}"
# --- B. Length Enforcement (150-250 words) ---
words = extract.split()
# If text is too short, append educational filler
if len(words) < 150:
educational_filler = (
"\n\n[Additional Ecological Context]\n"
f"The species {species_name} is an integral part of its local food web. "
"Biodiversity loss regarding this species could trigger a trophic cascade, affecting both prey and predator populations. "
"Conservationists monitor such species as bio-indicators of environmental health. "
"Preserving their natural habitat is essential not just for their survival, but for the stability of the entire ecosystem. "
"Effective conservation strategies include habitat restoration, anti-poaching laws, and community awareness programs."
)
extract += educational_filler
words = extract.split()
# Cap at ~250 words
summary_text = " ".join(words[:250]) + "..."
# --- C. Impact Analysis ---
analysis_section = f"""
------------------------------------------------
๐Ÿ“Š ENVIRONMENTAL IMPACT ANALYSIS
------------------------------------------------
โ€ข Target Habitat: {habitat}
โš ๏ธ STRESS INDICATORS:
โ€ข Water Stress: {water_disturbance}/100
(High levels indicate pollution or drought risk)
โ€ข Land Disturbance: {land_disturbance}/100
(Reflects habitat fragmentation or loss)
โ€ข Noise Pollution: {noise_level}/100
(Impacts communication and breeding patterns)
"""
final_output = summary_text + analysis_section
# --- D. Fetch GBIF Map Data ---
gbif_url = f"https://api.gbif.org/v1/occurrence/search?scientificName={species_name}&limit=300"
coords = []
try:
gbif_res = requests.get(gbif_url).json()
results = gbif_res.get("results", [])
for r in results:
if r.get("decimalLatitude") and r.get("decimalLongitude"):
coords.append({"lat": r.get("decimalLatitude"), "lon": r.get("decimalLongitude")})
except:
pass
if coords:
df = pd.DataFrame(coords)
fig = px.scatter_mapbox(df, lat="lat", lon="lon", zoom=1, height=350)
fig.update_layout(mapbox_style="open-street-map", margin={"r":0,"t":0,"l":0,"b":0})
else:
fig = px.scatter_mapbox(pd.DataFrame({"lat":[], "lon":[]}), lat="lat", lon="lon", zoom=0)
fig.update_layout(mapbox_style="open-street-map", margin={"r":0,"t":0,"l":0,"b":0})
# --- E. Create Download File ---
filename = "BioVigilus_Report.txt"
with open(filename, "w", encoding="utf-8") as f:
f.write(f"=== BioVigilus Project Report ===\n{final_output}")
return final_output, fig, filename
# ================================================================
# 2. VIBRANT CSS (Safe Mode)
# ================================================================
vibrant_css = """
<style>
.gradio-container {
background: linear-gradient(135deg, #004d40 0%, #2e7d32 100%) !important;
}
#main-title {
color: #ffffff !important;
font-family: sans-serif;
font-weight: 800;
font-size: 2.5rem;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
text-align: center;
margin-bottom: 5px;
}
#sub-title {
color: #a5d6a7 !important;
font-size: 1.2rem;
text-align: center;
margin-bottom: 25px;
font-family: sans-serif;
}
.custom-card {
background: #ffffff !important;
padding: 25px !important;
border-radius: 12px !important;
box-shadow: 0 10px 30px rgba(0,0,0,0.2) !important;
border: none !important;
}
/* Button - Gradient Green */
button.primary {
background: linear-gradient(90deg, #1b5e20 0%, #2e7d32 100%) !important;
color: white !important;
font-size: 1.1rem !important;
border-radius: 8px !important;
}
</style>
"""
# ================================================================
# 3. UI Layout
# ================================================================
with gr.Blocks() as demo:
gr.HTML(vibrant_css)
gr.HTML("""
<div id="main-title">๐ŸŒฟ BioVigilus</div>
<div id="sub-title">Advanced Biodiversity & Environmental Stress Analyzer</div>
""")
with gr.Row():
# --- LEFT: INPUTS ---
with gr.Column(elem_classes="custom-card"):
gr.Markdown("### ๐Ÿ” Species Configuration")
species_name = gr.Textbox(
label="Scientific Name",
placeholder="e.g. Panthera tigris",
value="Panthera tigris"
)
habitat = gr.Dropdown(
["Tropical Rainforest", "Savanna", "Desert", "Wetlands", "Urban", "Marine"],
label="Habitat Environment",
value="Tropical Rainforest"
)
gr.Markdown("---")
gr.Markdown("### โš ๏ธ Environmental Stressors")
water = gr.Slider(0, 100, value=25, label="Water Pollution Level")
land = gr.Slider(0, 100, value=65, label="Land Degradation")
noise = gr.Slider(0, 100, value=30, label="Noise Pollution (dB)")
analyze_btn = gr.Button("๐Ÿš€ Run Analysis", variant="primary")
# --- RIGHT: OUTPUTS ---
with gr.Column(elem_classes="custom-card"):
gr.Markdown("### ๐Ÿ“Š Analysis Results")
# REMOVED 'show_copy_button' to fix crash
out_summary = gr.Textbox(
label="Ecological Summary & Impact Report",
lines=12,
interactive=False
)
out_map = gr.Plot(label="Global Occurrence Map")
out_file = gr.File(label="๐Ÿ“ฅ Download Full Report")
analyze_btn.click(
process_species_data,
inputs=[species_name, habitat, water, land, noise],
outputs=[out_summary, out_map, out_file]
)
if __name__ == "__main__":
demo.launch()