hackathon_project / llm_analysis.py
zainab1234awan's picture
Update llm_analysis.py
3162af1 verified
Raw
History Blame Contribute Delete
10.5 kB
"""
PHASE 6: LLM Analysis via Groq API
Model: llama3-70b-8192
Rules:
- LLM ONLY explains and recommends
- LLM does NOT calculate eco score
- LLM does NOT predict impact category
- API key read from environment (HF Spaces Secret: GROQ_API_KEY)
"""
import os
def get_groq_client():
try:
from groq import Groq
api_key = os.getenv("GROQ_API_KEY", "").strip()
if not api_key:
return None, "GROQ_API_KEY not set."
return Groq(api_key=api_key), None
except ImportError:
return None, "groq package not installed."
def generate_eco_explanation(
product_name: str,
category: str,
deforestation_risk: float,
pollution_level: float,
biodiversity_impact: float,
eco_score: float,
predicted_impact: str,
packaging_type: str = "Unknown",
ingredients: str = "Not specified",
) -> dict:
"""
Generate LLM environmental explanation.
LLM receives pre-computed score and label β€” it never recalculates them.
"""
client, error = get_groq_client()
if client is None:
return _fallback(
product_name, category, deforestation_risk,
pollution_level, biodiversity_impact,
eco_score, predicted_impact, error,
)
prompt = f"""You are an environmental scientist providing educational insights.
Product Details:
- Name: {product_name}
- Category: {category}
- Packaging: {packaging_type}
- Ingredients/Materials: {ingredients}
- Eco Score: {eco_score}/10 ← already calculated, do NOT recalculate
- Impact Category: {predicted_impact} ← already predicted by ML, do NOT re-predict
Environmental Risk Metrics (0–1 scale):
- Deforestation Risk: {deforestation_risk}
- Pollution Level: {pollution_level}
- Biodiversity Impact: {biodiversity_impact}
Respond with EXACTLY these four sections:
## Environmental Impact Summary
[2–3 sentences explaining the product's overall environmental footprint in plain language]
## Deforestation Risk Analysis
[Explain what drives this product's deforestation risk, which regions/forests are affected, and why]
## Biodiversity & Species Impact
[Explain which wildlife and ecosystems are at risk; estimate how many species could be affected and why]
## 3 Eco-Friendly Alternatives
1. **[Name]**: [Why it's better and where to find it]
2. **[Name]**: [Why it's better and where to find it]
3. **[Name]**: [Why it's better and where to find it]
## Quick Sustainability Tips
[2–3 actionable tips the consumer can apply immediately]
Keep language accessible. Be factual and educational, not alarmist.
Do NOT produce any numerical eco score or impact category prediction."""
try:
response = client.chat.completions.create(
model="llama-3.3-70b-versatile",
messages=[
{
"role": "system",
"content": (
"You are an expert environmental scientist. Provide factual, "
"accessible sustainability insights. Never recalculate scores "
"or re-predict categories β€” those come from separate systems."
),
},
{"role": "user", "content": prompt},
],
max_tokens=1200,
temperature=0.7,
)
return {
"success": True,
"explanation": response.choices[0].message.content,
"model": "llama-3.3-70b-versatile (Groq)",
"tokens_used": response.usage.total_tokens,
}
except Exception as e:
return _fallback(
product_name, category, deforestation_risk,
pollution_level, biodiversity_impact,
eco_score, predicted_impact, str(e),
)
def _fallback(
product_name, category, deforestation_risk,
pollution_level, biodiversity_impact,
eco_score, predicted_impact, error_msg="",
) -> dict:
"""Template explanation used when Groq API is unavailable."""
if deforestation_risk > 0.5:
defo = (
f"{product_name} carries a high deforestation risk ({deforestation_risk:.0%}). "
"Supply chains likely involve palm oil, wood pulp, or agricultural land clearing "
"in tropical regions such as the Amazon, Southeast Asian rainforests, or the Congo Basin."
)
elif deforestation_risk > 0.2:
defo = (
f"{product_name} has a moderate deforestation risk ({deforestation_risk:.0%}). "
"Some raw materials may be linked to land-use change, though responsible sourcing "
"certifications (FSC, RSPO) can mitigate this."
)
else:
defo = (
f"{product_name} has a low deforestation risk ({deforestation_risk:.0%}). "
"Materials show minimal connection to forest loss, especially if recycled or certified organic."
)
if biodiversity_impact > 0.5:
bio = (
"High biodiversity impact. Estimated 50–200+ species in affected ecosystems "
"face habitat disruption, including pollinators, soil microbiota, and apex predators. "
"Pollution runoff may further threaten aquatic biodiversity."
)
elif biodiversity_impact > 0.2:
bio = (
"Moderate biodiversity impact. Localised ecosystems may experience disruption; "
"approximately 10–50 species could be indirectly affected through habitat "
"fragmentation and chemical pollution."
)
else:
bio = (
"Low biodiversity impact. Minimal disruption to local ecosystems. "
"The product lifecycle has limited spillover effects on wildlife habitats."
)
alts_map = {
"Shampoo": [
"**Ethique Shampoo Bar** β€” Zero-plastic, concentrated, biodegradable",
"**Briogeo Be Gentle** β€” Sulfate-free, plant-based ingredients",
"**Baking Soda & Apple Cider Vinegar** β€” DIY ultra-low-impact alternative",
],
"Snacks": [
"**Local Organic Produce** β€” Minimal packaging, zero transport emissions",
"**Bulk-store Nuts & Seeds** β€” Bring your own container, zero waste",
"**Homemade Granola** β€” Full control over ingredients and packaging",
],
"Plastic": [
"**Stainless Steel Alternatives** β€” Reusable, durable, infinitely recyclable",
"**Compostable Bioplastics (PLA)** β€” Breaks down in industrial composting",
"**Glass Containers** β€” Inert, infinitely recyclable, no chemical leaching",
],
"Cosmetics": [
"**ILIA Beauty** β€” Certified organic, recycled packaging",
"**RMS Beauty** β€” Raw food-grade ingredients, glass packaging",
"**DIY Natural Cosmetics** β€” Beeswax, coconut oil, natural pigments",
],
"Clothing": [
"**Patagonia** β€” Recycled materials, repair programme, lifetime guarantee",
"**Secondhand / Thrift** β€” Zero new production, circular economy",
"**Tentree or Eileen Fisher** β€” Certified organic fibres, ethical supply chains",
],
}
alts = alts_map.get(category, [
"**Local / Organic alternatives** β€” Reduced transport and chemical footprint",
"**Secondhand or refurbished** β€” Circular economy approach",
"**DIY or zero-waste options** β€” Maximum control over environmental impact",
])
explanation = f"""## Environmental Impact Summary
{product_name} is a {category} product with an eco score of {eco_score}/10 ({predicted_impact}). \
{"This product raises significant environmental concerns β€” consider switching to one of the alternatives below." if eco_score < 5 else "This product has moderate to good sustainability credentials, though improvement is always possible."}
## Deforestation Risk Analysis
{defo}
## Biodiversity & Species Impact
{bio}
## 3 Eco-Friendly Alternatives
1. {alts[0]}
2. {alts[1]}
3. {alts[2]}
## Quick Sustainability Tips
- Look for certified eco-labels: FSC, Fair Trade, USDA Organic, or B Corp.
- Choose concentrated formulas and refillable containers to reduce packaging waste.
- Research brand sustainability reports and third-party certifications before purchasing."""
note = f"Groq API unavailable: {error_msg}" if error_msg else "Using template explanation."
return {
"success": True,
"explanation": explanation,
"model": "Template Fallback",
"note": note,
}
def compare_products_llm(product1: dict, product2: dict) -> dict:
"""LLM comparison explanation for two products (scores pre-calculated)."""
client, error = get_groq_client()
if client is None:
winner = product1["name"] if product1.get("eco_score", 5) >= product2.get("eco_score", 5) else product2["name"]
return {
"success": True,
"comparison": f"**{winner}** is the more environmentally friendly choice based on its lower impact scores.",
"model": "Fallback",
}
prompt = f"""Compare these two products' environmental impact in 3–4 sentences.
Product A: {product1['name']} ({product1.get('category','')})
- Eco Score: {product1.get('eco_score','N/A')}/10
- Deforestation: {product1.get('deforestation_risk',0):.2f} | Pollution: {product1.get('pollution_level',0):.2f} | Biodiversity: {product1.get('biodiversity_impact',0):.2f}
Product B: {product2['name']} ({product2.get('category','')})
- Eco Score: {product2.get('eco_score','N/A')}/10
- Deforestation: {product2.get('deforestation_risk',0):.2f} | Pollution: {product2.get('pollution_level',0):.2f} | Biodiversity: {product2.get('biodiversity_impact',0):.2f}
State which is more sustainable, explain the key environmental trade-offs, and give a consumer recommendation.
Do NOT recalculate scores."""
try:
resp = client.chat.completions.create(
model="llama-3.3-70b-versatile",
messages=[{"role": "user", "content": prompt}],
max_tokens=400,
temperature=0.6,
)
return {
"success": True,
"comparison": resp.choices[0].message.content,
"model": "llama-3.3-70b-versatile (Groq)",
}
except Exception as e:
return {"success": False, "comparison": "Comparison unavailable.", "error": str(e)}