from transformers import BlipProcessor, BlipForConditionalGeneration from sentence_transformers import SentenceTransformer import gradio as gr from PIL import Image import torch import requests from bs4 import BeautifulSoup # Load BLIP Model blip_processor = BlipProcessor.from_pretrained("Salesforce/blip-image-captioning-base") blip_model = BlipForConditionalGeneration.from_pretrained("Salesforce/blip-image-captioning-base") # Map common fish names to FishBase scientific names name_map = { "pufferfish": "Tetraodon", "stonefish": "Synanceia", "lionfish": "Pterois", "tuna": "Thunnus", "salmon": "Salmo-salar", "catfish": "Ictalurus", "tilapia": "Oreochromis" } # Poisonous species (scientific names) poisonous_species = ["Tetraodon", "Synanceia", "Pterois"] # FishBase scraping function def get_fishbase_summary(scientific_name): search_url = f"https://www.fishbase.se/summary/{scientific_name}.html" try: response = requests.get(search_url, timeout=10) if response.status_code != 200: return f"FishBase entry not found for: {scientific_name}" soup = BeautifulSoup(response.text, "html.parser") summary_section = soup.find("div", {"id": "ssummary"}) if summary_section: paragraphs = summary_section.find_all("p") text = "\n\n".join(p.get_text(strip=True) for p in paragraphs if p.get_text(strip=True)) return text or f"No summary available for {scientific_name}" else: return f"No detailed summary found for {scientific_name}" except Exception as e: return f"Error fetching FishBase data for {scientific_name}: {str(e)}" # Fish identification function def identify_fish(image): # Step 1: Generate caption from image inputs = blip_processor(image, return_tensors="pt") out = blip_model.generate(**inputs) caption = blip_processor.decode(out[0], skip_special_tokens=True) # Step 2: Extract fish name from caption fish_name = None for name in name_map: if name in caption.lower(): fish_name = name break if not fish_name: return f"โŒ Could not identify a known fish species in the image caption: '{caption}'" # Step 3: Lookup in FishBase scientific_name = name_map[fish_name] summary = get_fishbase_summary(scientific_name) # Step 4: Check toxicity is_poisonous = "Yes ๐Ÿงช" if scientific_name in poisonous_species else "No โœ…" # Step 5: Final Output return f"**Image Caption:** {caption}\n\n**Detected Fish:** {fish_name.title()}\n**Scientific Name:** {scientific_name}\n**Poisonous:** {is_poisonous}\n\n**๐Ÿ“š FishBase Info:**\n{summary}" # Gradio UI demo = gr.Interface( fn=identify_fish, inputs=gr.Image(type="pil"), outputs="markdown", title="๐ŸŸ Smart Fish Identifier (BLIP + FishBase)", description="Upload a fish image. We use BLIP to describe the fish, match it with known species, then fetch info from FishBase to check if it's poisonous." ) if __name__ == '__main__': demo.launch()