# Project export: pranAI

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 12.0
- Tagline: cleaner prompts for a greener world
- Devpost: https://devpost.com/software/energy-tracker-ywnszp
- GitHub: https://github.com/smrithi-0121/calhacks2025.git
- Video: https://player.vimeo.com/video/1130688369?byline=0&portrait=0&title=0#t=
- Team: 3 GitHub contributor(s) — smrithi-0121 (7 commits), ririRKR (6 commits), vedashnii (1 commits)

## Devpost submission (written by the team)

### Overview

Overview pranAI is a Chrome extension that helps users understand the environmental impact of their AI prompts. It estimates the energy and carbon cost of each request, suggests more efficient rewrites, and tracks total energy saved with real-world comparisons. Goal: Our goal: make sustainable AI use transparent, measurable, and fun.

### Inspiration

As AI becomes part of daily life, few people realize the hidden energy cost behind every prompt. Research shows that running a large language model (LLM) query can use as much energy as charging a smartphone multiple times — and when millions of people use AI daily, that adds up to enormous carbon emissions. We wanted to answer one question: “What if people could see the impact of their AI usage — and actually do something about it?” That idea became pranAI: a lightweight, accessible tool that empowers users to make mindful choices while still enjoying the power of AI. Key Features Prompt Energy Estimation: Calculates approximate energy and CO₂ footprint for each AI request. Smart Rewrite Suggestions: Uses linguistic heuristics to produce a shorter, equally effective prompt. Impact Dashboard: Tracks energy saved over time and displays real-world equivalents Privacy First: All analysis runs locally; no data is collected or stored externally.

### How we built it

pranAI is built as a Chrome extension using: Main Languages: HTML, CSS, JavaScript Extension Logic: Chrome Extension API (Manifest v3) Data Sources: Public LLM energy token usage and CO₂ equivalency datasets When a user submits a prompt: The extension captures the input text. We estimate token count and computational complexity. Using benchmark data, we approximate energy use We convert that energy into CO₂ equivalents and relatable comparisons The system then offers an optimized rewrite by simplifying sentence structure and removing redundancies.

### Challenges we ran into

Balancing accuracy and usability: We wanted energy estimates that felt meaningful without overwhelming users with scientific detail. Prompt optimization: Generating cleaner prompt suggestions without changing meaning required nuanced linguistic logic. Browser limitations: Handling dynamic text fields in AI chat interfaces (like ChatGPT’s textbox) required creative DOM manipulation.

### Accomplishments we're proud of

Built a fully functional Chrome extension in under 48 hours that integrates seamlessly with AI chat platforms. Translated complex energy data into clear, engaging insights through a user-friendly dashboard. Developed a working energy estimation model and prompt optimizer that reduced estimated energy use by up to 30%. Sparked awareness about sustainable AI and how everyday users can make a measurable impact.

### What we learned

In this project, we discovered how small text changes can significantly affect AI computation costs while gaining hands on experience with Chrome Extension development. We learned to translate abstract data (like joules and emissions) into relatable remarks people actually care about. Most importantly, we learned that sustainability in AI isn’t just a hardware or data center problem — it’s also a user problem.

### What's next

Add gamification — badges, leaderboards, and social challenges for sustainable AI users. Create an pranAI API for developers to integrate sustainability metrics into their own AI tools. Partner with carbon-offset organizations so virtual savings can create real-world environmental impact.

## README (from the GitHub repository)

# 🌱 pranAI — Make Every Prompt Greener

**pranAI** is a Chrome extension that tracks the energy used by your AI prompts and helps you make them more efficient. It estimates the environmental cost of each request, suggests optimized rewrites, and visualizes your total energy savings through real-world comparisons.
---

## Features
* **Energy Calculator:** Instantly estimates the energy and CO₂ footprint of every AI prompt.
* **Smart Rewrite Suggestions:** Recommends shorter, more efficient prompt alternatives that maintain intent and clarity.
* **Impact Tracker:** Visualizes your total energy saved with relatable metrics
* **Real-Time Insights:** Works within ChatGPT and other AI chat interfaces and displays counts as you type.
* **Daily-Life Comparison** Equates energy usage to common activities like charging devices and driving.
---
## How It Works
pranAI uses published model energy benchmarks, obtained from a study by TRG DataCenters, to estimate power consumption per prompt. When you submit a query, it analyzes token length, model type, and processing complexity to calculate your estimated energy use.
Then, it suggests a simpler, lower-energy version of your prompt without losing meaning.

All data stays local to your browser — **no user information is collected or stored.**
---
## Getting Started
1. Clone or download this repository.
2. In Chrome, go to **chrome://extensions** → enable **Developer Mode** → **Load unpacked**.
3. Select the project folder to install pranAI.
4. Open ChatGPT (or another AI interface) and start prompting!
---

## Next Steps
* Add integrations for other major AI platforms.
* Include energy analysis for uploading and generating images
* Implement a leaderboard and community challenges to gamify sustainability.
* Partner with carbon-offset organizations to link virtual savings to real-world impact.
---

## Inspiration
AI’s carbon footprint is growing, but awareness hasn’t caught up. pranAI empowers users to understand and minimize their impact, making sustainability an effortless part of every AI interaction.

**pranAI:** *cleaner prompts for a greener world :)*


## Detected evidence (automated analysis)

Indexed codebase: 8 recognized source files, 52 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (11 of 11)

```
background/background.js
content/content.css
content/content.js
icons/Oak Tree.json
icons/Rain Fall.json
manifest.json
popup/popup.css
popup/popup.html
popup/popup.js
README.md
utils/energy-calculator.js
```

### Dependencies

No dependency index available.

### Recent commits (newest first)

- finetuning optimization
- changed benchmarks
- additional words
- readme
- Update energy-calculator.js
- repo-link
- Update README.md
- read_me
- style changes
- style updates
- cleaned up repo structure
- Merge branch 'main' of https://github.com/smrithi-0121/calhacks2025
- tweaked
- Add files via upload
- cool new features ehehe
- chatgpt fix
- session energy resets once tab closes
- totalprompt implementation
- smrithi version w/ popup
- claude implementation

## Key source files (fetched from GitHub, selected and truncated for size)

### popup/popup.html

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>pranAI</title>
  <link rel="stylesheet" href="popup.css">
</head>
<body>
  <div class="popup-container">
    <div class="popup-header">
      <h1>⚡ pranAI</h1>
      <p class="tagline">cleaner prompts for a greener world</p>
    </div>

    <div class="stats-grid">
      <div class="stat-card">
        <div class="stat-icon">💡</div>
        <div class="stat-info">
          <div class="stat-label">Session Energy</div>
          <div class="stat-value" id="session-energy">0 Wh</div>
        </div>
      </div>

      <div class="stat-card">
        <div class="stat-icon">🌍</div>
        <div class="stat-info">
          <div class="stat-label">Carbon Footprint</div>
          <div class="stat-value" id="session-carbon">0 g CO₂</div>
        </div>
      </div>

      <div class="stat-card">
        <div class="stat-icon">📊</div>
        <div class="stat-info">
          <div class="stat-label">Total Prompts</div>
          <div class="stat-value" id="total-prompts">0</div>
        </div>
      </div>

      <div class="stat-card">
        <div class="stat-icon">🌱</div>
        <div class="stat-info">
          <div class="stat-label">Energy Saved</div>
          <div class="stat-value" id="energy-saved">0 Wh</div>
        </div>
      </div>
    </div>

    <div class="impact-section">
      <h3>Your Impact</h3>
      <div class="impact-comparison" id="impact-comparison">
        Loading...
      </div>
    </div>

    <div class="actions">
      <button id="reset-stats" class="btn btn-secondary">Reset Session</button>
      <button id="learn-more" class="btn btn-primary">Learn More</button>
    </div>

    <div class="footer">
      <p>💚 Every prompt matters</p>
    </div>
  </div>

  <script src="popup.js"></script>
</body>
</html>
```

### popup/popup.css

```css
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  width: 400px;
  font-family: 'Poppins', sans-serif;/* -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; */
  background: linear-gradient(135deg, #5b9bc4 0%, #badbc6 100%);
  color: white;
}

.popup-container {
  padding: 20px;
}

.popup-header {
  text-align: center;
  margin-bottom: 20px;
}

.popup-header h1 {
  font-size: 24px;
  margin-bottom: 5px;
}

.tagline {
  font-size: 14px;
  opacity: 0.9;
}

.stats-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  margin-bottom: 20px;
}

.stat-card {
  background: rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(10px);
  border-radius: 12px;
  padding: 15px;
  display: flex;
  align-items: center;
  gap: 12px;
  transition: transform 0.2s ease;
  border: 1px solid rgba(255, 255, 255, 0.2);
}

.stat-card:hover {
  transform: translateY(-2px);
  background: rgba(255, 255, 255, 0.2);
}

.stat-icon {
  font-size: 32px;
}

.stat-info {
  flex: 1;
}

.stat-label {
  font-size: 11px;
  opacity: 0.8;
  margin-bottom: 4px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.stat-value {
  font-size: 18px;
  font-weight: 700;
}

.impact-section {
  background: rgba(0, 0, 0, 0.2);
  border-radius: 12px;
  padding: 15px;
  margin-bottom: 15px;
}

.impact-section h3 {
  font-size: 16px;
  margin-bottom: 10px;
}

.impact-comparison {
  font-size: 14px;
  line-height: 1.6;
  opacity: 0.95;
}

.actions {
  display: flex;
  gap: 10px;
  margin-bottom: 15px;
}

.btn {
  flex: 1;
  padding: 12px;
  border: none;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
}

.btn-primary {
  background: white;
  color: #667eea;
}

.btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}

.btn-secondary {
  background: rgba(255, 255, 255, 0.2);
  color: white;
  border: 1px solid rgba(255, 255, 255, 0.3);
}

.btn-secondary:hover {
  background: rgba(255, 255, 255, 0.3);
}

.footer {
  text-align: center;
  font-size: 13px;
  opacity: 0.8;
  padding-top: 15px;
  border-top: 1px solid rgba(255, 255, 255, 0.2);
}
```

### content/content.css

```css
/* pranAI Overlay Styles */

#ai-energy-overlay {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 999999;
  font-family: 'Poppins', sans-serif; /*-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;*/
}

.energy-tracker-container {
  background: linear-gradient(135deg, #5b9bc4 0%, #badbc6 100%);
  border-radius: 16px;
  padding: 20px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
  min-width: 300px;
  color: white;
  transition: all 0.3s ease;
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.2);
}

.energy-tracker-container.minimized {
  padding: 10px;
  min-width: auto;
}

.energy-tracker-container.minimized .energy-stats,
.energy-tracker-container.minimized .energy-bar-container,
.energy-tracker-container.minimized .energy-suggestion {
  display: none;
}

.energy-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 15px;
  font-weight: 600;
  font-size: 18px;
}

.energy-icon {
  font-size: 24px;
  animation: pulse 2s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.1); }
}

.energy-title {
  flex: 1;
}

.minimize-btn {
  background: rgba(255, 255, 255, 0.2);
  border: none;
  color: white;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  transition: all 0.2s ease;
  display: flex;
  align-items: center;
  justify-content: center;
}

.minimize-btn:hover {
  background: rgba(255, 255, 255, 0.3);
  transform: scale(1.1);
}

.energy-stats {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 15px;
}

.stat-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  font-size: 14px;
}

.stat-label {
  font-weight: 500;
  opacity: 0.9;
}

.stat-value {
  font-weight: 700;
  font-size: 16px;
}

.session-stats {
  border-top: 1px solid rgba(255, 255, 255, 0.2);
  padding-top: 12px;
  margin-top: 8px;
}

.energy-bar-container {
  background: rgba(0, 0, 0, 0.2);
  height: 8px;
  border-radius: 4px;
  overflow: hidden;
  margin-bottom: 15px;
}

.energy-bar {
  height: 100%;
  transition: width 0.3s ease, background 0.3s ease;
  border-radius: 4px;
}

.energy-suggestion {
  font-size: 13px;
  padding: 12px;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 8px;
  line-height: 1.5;
}

.energy-suggestion small {
  opacity: 0.8;
  font-size: 11px;
  display: block;
  margin-top: 6px;
}

/* Responsive */
@media (max-width: 768px) {
  #ai-energy-overlay {
    top: 10px;
    right: 10px;
  }

  .energy-tracker-container {
    min-width: 260px;
    padding: 15px;
  }
}

/* Animation on load */
@keyframes slideIn {
  from {
    transform: translateX(400px);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

.energy-tracker-container {
  animation: slideIn 0.5s ease-out;
}

/* Optimization Section */
.optimization-section {
  margin-top: 10px;
}

.optimize-btn {
  width: 100%;
  padding: 12px;
  background: linear-gradient(135deg, #4ade80 0%, #22c55e 100%);
  border: none;
  border-radius: 8px;
  color: white;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s ease;
  font-size: 14px;
}

.optimize-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(34, 197, 94, 0.4);
}

.optimization-preview {
  margin-top: 12px;
  padding: 12px;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 8px;
}

.preview-label {
  font-size: 12px;
  opacity: 0.8;
  margin-bottom: 8px;
}

.preview-text {
  background: rgba(255, 255, 255, 0.1);
  padding: 10px;
  border-radius: 6px;
  font-size: 13px;
  line-height: 1.5;
  max-height: 100px;
  overflow-y: auto;
  margin-bottom: 10px;
}

.preview-actions {
  display: flex;
  gap: 8px;
}

.accept-optimize-btn,
.cancel-optimize-btn {
  flex: 1;
  padding: 8px;
  border: none;
  border-radius: 6px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
  font-size: 13px;
}

.accept-optimize-btn {
  background: #4ade80;
  color: white;
}

.accept-optimize-btn:hover {
  background: #22c55e;
}

.cancel-optimize-btn {
  background: rgba(255, 255, 255, 0.2);
  color: white;
}

.cancel-optimize-btn:hover {
  background: rgba(255, 255, 255, 0.3);
}

.saved-stats {
  border: 1px solid rgba(76, 222, 128, 0.3);
}
```

### utils/energy-calculator.js

```javascript
// Energy calculation utilities
const EnergyCalculator = {
  // Energy per token in Watt-hours (Wh)
  ENERGY_PER_TOKEN: {
    'chatgpt': 0.0864,    // GPT-3.5/4
    'claude': 0.0700,     // Claude
    'gemini': 0.0320,     // Gemini
    'perplexity': 0.0800, // Perplexity
    'grok': 0.00340, // Grok
    'llama': 0.0640, // Llama
    'default': 0.005
  },

  // Carbon intensity (gCO2 per kWh) - US average
  CARBON_INTENSITY: 500,

  /**
   * Estimate token count from text
   * Rough approximation: 1 token ≈ 0.75 words or ~4 characters
   */
  estimateTokens(text) {
    if (!text) return 0;
    
    // Method 1: Word count * 1.33
    const wordCount = text.trim().split(/\s+/).length;
    const tokensByWords = Math.ceil(wordCount * 1.33);
    
    // Method 2: Character count / 4
    const tokensByChars = Math.ceil(text.length / 4);
    
    // Use average of both methods
    return Math.ceil((tokensByWords + tokensByChars) / 2);
  },

  /**
   * Calculate energy consumption in Watt-hours
   */
  calculateEnergy(text, platform = 'default') {
    const tokens = this.estimateTokens(text);
    const energyPerToken = this.ENERGY_PER_TOKEN[platform] || this.ENERGY_PER_TOKEN.default;
    return tokens * energyPerToken;
  },

  /**
   * Calculate carbon footprint in grams CO2
   */
  calculateCarbon(energyWh) {
    const energyKWh = energyWh / 1000;
    return energyKWh * this.CARBON_INTENSITY;
  },

  /**
   * Get human-readable energy string
   */
  formatEnergy(energyWh) {
    if (energyWh < 1) {
      return `${(energyWh * 1000).toFixed(2)} mWh`;
    }
    return `${energyWh.toFixed(3)} Wh`;
  },

  /**
   * Get human-readable carbon string
   */
  formatCarbon(carbonG) {
    if (carbonG < 1) {
      return `${(carbonG * 1000).toFixed(2)} mg CO₂`;
    }
    return `${carbonG.toFixed(2)} g CO₂`;
  },

  /**
   * Get color based on energy level
   */
  getEnergyColor(energyWh) {
    if (energyWh < 2) return '#4ade80'; // green
    if (energyWh < 8) return '#fbbf24';   // yellow
    return '#ef4444';                      // red
  },

  /**
 * Get relatable comparison
 */
getComparison(energyWh) {
  const comparisons = [
    { threshold: 1, text: '☕ Less than brewing a cup of coffee' },      // Changed from 0.1
    { threshold: 5, text: '💡 Like a LED bulb for 2 minutes' },         // Changed from 0.5
    { threshold: 10, text: '📱 Like charging your phone 15%' },          // Changed from 1
    { threshold: 20, text: '💻 Like your laptop for 20 minutes' },      // Changed from 5
    { threshold: 50, text: '🔋 Like charging a tablet fully' },         // Changed from 10
    { threshold: Infinity, text: '⚡ Significant energy usage!' }
  ];

  return comparisons.find(c => energyWh < c.threshold).text;
}, 

  /**
 * Suggest optimization
 */
suggestOptimization(text) {
  const tokens = this.estimateTokens(text);
  
  if (tokens < 20) {
    return "✅ Your prompt is already very efficient!";
  }
  
  if (tokens < 50) {
    return "💡 Good length! Small optimizations possible.";
  }
  
  if (tokens < 150) {
    return "💡 Consider removing filler words to save energy.";
  }
  
  const savings = Math.floor((tokens - 100) / tokens * 100);
  return `💡 Try shortening by ~${savings}% to significantly reduce energy use.`;
}, 

  /**
   * Compare energy across different models
   */
  compareModels(text) {
    const tokens = this.estimateTokens(text);
    
    const models = {};
    for (const [model, energyPerToken] of Object.entries(this.ENERGY_PER_TOKEN)) {
      if (model === 'default') continue;
      
      const energy = tokens * energyPerToken;
      const carbon = this.calculateCarbon(energy);
      
      models[model] = {
        energy: energy,
        energyFormatted: this.formatEnergy(energy),
        carbon: carbon,
        carbonFormatted: this.formatCarbon(carbon),
        tokens: tokens
      };
    }
    
    return models;
  }
};

// Prompt Optimizer - Rule-based optimization without AI
const PromptOptimizer = {
  /**
   * Optimize prompt without using AI
   */
  optimizePrompt(text) {
  let optimized = text;
  const suggestions = [];
  
  // 1. Remove excessive repeated characters (NEW!)
  // Matches 10+ repeated characters and reduces to just 1-2
  const repeatedCharPattern = /(.)\1{9,}/g;
  const repeatedMatches = optimized.match(repeatedCharPattern);
  if (repeatedMatches) {
    repeatedMatches.forEach(match => {
      const char = match[0];
      const count = match.length;
      // Keep just 1 character (or 2 for punctuation like "!!")
      const replacement = /[!?.]/.test(char) ? char + char : char;
      optimized = optimized.replace(match, replacement);
      suggestions.push(`Removed ${count - replacement.length} excessive '${char}' characters`);
    });
  }
    
    // 1. Remove filler words
    const fillerWords = [
      'just', 'really', 'very', 'quite', 'rather', 'somewhat',
      'basically', 'actually', 'literally', 'honestly',
      'I think', 'I believe', 'in my opinion', 'it seems like', 'like'
    ];
    
    fillerWords.forEach(filler => {
      const regex = new RegExp(`\\b${filler}\\b`, 'gi');
      if (regex.test(optimized)) {
        optimized = optimized.replace(regex, '');
        suggestions.push(`Removed filler word: "${filler}"`);
      }
    });
    
    // 2. Replace verbose phrases
    const replacements = {
      'a lot of': 'many',
      'in order to': 'to',
      'due to the fact that': 'because',
      'at this point in time': 'now',
      'for the purpose of': 'for',
      'in the event that': 'if',
      'on the grounds that': 'because',
      'with regard to': 'about',
      'give consideration to': 'consider',
      'make a decision': 'decide',
      'come to a conclusion': 'conclude',
      'provide assistance': 'help',
      'please ': '',
      'could you ': '',
      'can you ': '', 
      'thank you': '',
      'good morning': '',
      'good afternoon': '',
      'good night':'', 
      'hi':'',
      'hello':''
    };
    
    Object.entries(
[truncated — 1471 more characters]
```

### popup/popup.js

```javascript
// Popup script
document.addEventListener('DOMContentLoaded', async () => {
  await loadStats();
  setupEventListeners();
  
  // Auto-refresh stats every 2 seconds
  setInterval(loadStats, 2000);
});

async function loadStats() {
  try {
    const result = await chrome.storage.local.get([
      'sessionEnergy',
      'sessionCarbon',
      'totalPrompts',
      'energySaved',
      'lastUpdated'
    ]);

    const sessionEnergy = result.sessionEnergy || 0;
    const sessionCarbon = result.sessionCarbon || 0;
    const totalPrompts = result.totalPrompts || 0;
    const energySaved = result.energySaved || 0;

    // Update display
    document.getElementById('session-energy').textContent = formatEnergy(sessionEnergy);
    document.getElementById('session-carbon').textContent = formatCarbon(sessionCarbon);
    document.getElementById('total-prompts').textContent = totalPrompts;
    document.getElementById('energy-saved').textContent = formatEnergy(energySaved);

    // Update impact comparison
    updateImpactComparison(sessionEnergy, sessionCarbon);
  } catch (error) {
    console.error('Error loading stats:', error);
    showError('Failed to load statistics');
  }
}

function formatEnergy(energyWh) {
  if (energyWh === 0) return '0 Wh';
  if (energyWh < 0.001) {
    return `${(energyWh * 1000000).toFixed(0)} µWh`;
  }
  if (energyWh < 1) {
    return `${(energyWh * 1000).toFixed(0)} mWh`;
  }
  if (energyWh < 1000) {
    return `${energyWh.toFixed(2)} Wh`;
  }
  return `${(energyWh / 1000).toFixed(2)} kWh`;
}

function formatCarbon(carbonG) {
  if (carbonG === 0) return '0 g CO₂';
  if (carbonG < 0.001) {
    return `${(carbonG * 1000000).toFixed(0)} µg CO₂`;
  }
  if (carbonG < 1) {
    return `${(carbonG * 1000).toFixed(0)} mg CO₂`;
  }
  if (carbonG < 1000) {
    return `${carbonG.toFixed(2)} g CO₂`;
  }
  return `${(carbonG / 1000).toFixed(2)} kg CO₂`;
}

function updateImpactComparison(energyWh, carbonG) {
  const comparisonEl = document.getElementById('impact-comparison');
  
  if (energyWh < 0.01) {
    comparisonEl.innerHTML = `
      <div style="text-align: center; padding: 10px;">
        <div style="font-size: 32px; margin-bottom: 8px;">🌱</div>
        <div>Great start! Keep using efficient prompts.</div>
      </div>
    `;
    return;
  }

  // Calculate various comparisons
  const comparisons = generateComparisons(energyWh, carbonG);
  
  comparisonEl.innerHTML = `
    <div style="display: flex; flex-direction: column; gap: 8px;">
      ${comparisons.map(c => `
        <div style="display: flex; align-items: center; gap: 8px; padding: 8px; background: rgba(255,255,255,0.1); border-radius: 6px;">
          <span style="font-size: 20px;">${c.emoji}</span>
          <span style="flex: 1; font-size: 13px;">${c.text}</span>
        </div>
      `).join('')}
    </div>
  `;
}

function generateComparisons(energyWh, carbonG) {
  const comparisons = [];
  
  // Phone charging (15Wh per full charge)
  const phoneCharges = energyWh / 15;
  if (phoneCharges >= 0.01) {
    if (phoneCharges < 1) {
      comparisons.push({
        emoji: '📱',
        text: `${(phoneCharges * 100).toFixed(0)}% of a phone charge`
      });
    } else {
      comparisons.push({
        emoji: '📱',
        text: `${phoneCharges.toFixed(1)} phone charges`
      });
    }
  }
  
  // LED bulb (10W LED)
  const ledMinutes = (energyWh / 10) * 60;
  if (ledMinutes >= 1) {
    if (ledMinutes < 60) {
      comparisons.push({
        emoji: '💡',
        text: `LED bulb for ${Math.round(ledMinutes)} minutes`
      });
    } else {
      const hours = Math.floor(ledMinutes / 60);
      const mins = Math.round(ledMinutes % 60);
      comparisons.push({
        emoji: '💡',
        text: `LED bulb for ${hours}h ${mins}m`
      });
    }
  }
  
  // Laptop usage (50W average)
  const laptopMinutes = (energyWh / 50) * 60;
  if (laptopMinutes >= 1) {
    comparisons.push({
      emoji: '💻',
      text: `Laptop for ${Math.round(laptopMinutes)} minutes`
    });
  }
  
  // Trees needed (21kg CO2 per tree per year)
  const treesNeeded = (carbonG / 1000) / 21;
  comparisons.push({
    emoji: '🌳',
    text: `Offset by ${treesNeeded < 0.001 ? '<0.001' : treesNeeded.toFixed(3)} trees/year`
  });
  
  // Car equivalent (120g CO2 per km average)
  const carMeters = (carbonG / 120) * 1000;
  if (carMeters >= 1) {
    if (carMeters < 1000) {
      comparisons.push({
        emoji: '🚗',
        text: `Driving ${Math.round(carMeters)} meters`
      });
    } else {
      comparisons.push({
        emoji: '🚗',
        text: `Driving ${(carMeters / 1000).toFixed(2)} km`
      });
    }
  }
  
  return comparisons.slice(0, 3); // Return top 3 most relevant
}

function setupEventListeners() {
  // Reset stats button
  document.getElementById('reset-stats').addEventListener('click', async () => {
    if (confirm('Are you sure you want to reset your session stats?')) {
      const btn = document.getElementById('reset-stats');
      btn.disabled = true;
      btn.textContent = 'Resetting...';
      
      try {
        // Get current stats before resetting (to potentially save to history)
        const currentStats = await chrome.storage.local.get([
          'sessionEnergy',
          'sessionCarbon',
          'totalPrompts'
        ]);
        
        // Reset current session
        await chrome.storage.local.set({
          sessionEnergy: 0,
          sessionCarbon: 0,
          totalPrompts: 0,
          lastUpdated: Date.now()
        });
        
        // Optionally save to history
        if (currentStats.sessionEnergy > 0) {
          await addToHistory(currentStats);
        }
        
        // Reload stats display
        await loadStats();
        
        // Show success
        btn.textContent = '✓ Reset Complete!';
        btn.style.background = 'rgba(74, 222, 128, 0.3)';
        
        setTimeout(() => {
          btn.textContent = 'Reset Session';
          btn.style.background = '';
          btn.disabled = f
[truncated — 2766 more characters]
```

### background/background.js

```javascript
/* global chrome */

// Background service worker for pranAI
console.log('pranAI: Background service worker started');

// Initialize storage on install
chrome.runtime.onInstalled.addListener(async (details) => {
  console.log('pranAI: Extension installed/updated', details.reason);
  
  if (details.reason === 'install') {
    // First time installation
    await chrome.storage.local.set({
      sessionEnergy: 0,
      sessionCarbon: 0,
      totalPrompts: 0,
      energySaved: 0,
      installDate: Date.now(),
      lifetimeEnergy: 0,
      lifetimeCarbon: 0,
      lifetimePrompts: 0,
      history: [],
      settings: {
        showOverlay: true,
        enableNotifications: true,
        energyThreshold: 5,
        autoOptimize: false
      }
    });
    
    // Show welcome notification (with error handling)
    try {
      if (chrome.notifications) {
        chrome.notifications.create({
          type: 'basic',
          iconUrl: 'icons/icon128.png',
          title: '⚡ pranAI Installed!',
          message: 'Start tracking your AI energy usage on ChatGPT, Claude, and more.',
          priority: 2
        });
      }
    } catch (error) {
      console.log('Notifications not available:', error);
    }
  } else if (details.reason === 'update') {
    console.log('pranAI: Extension updated');
  }
});

// Listen for messages from content scripts
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  console.log('Background: Received message', message.type);
  
  switch (message.type) {
    case 'PROMPT_SENT':
      handlePromptSent(message.data, sender.tab)
        .then(result => sendResponse({ success: true, data: result }))
        .catch(error => sendResponse({ success: false, error: error.message }));
      return true;
      
    case 'GET_STATS':
      getStats()
        .then(stats => sendResponse({ success: true, stats }))
        .catch(error => sendResponse({ success: false, error: error.message }));
      return true;
      
    case 'RESET_SESSION':
      resetSessionStats()
        .then(() => sendResponse({ success: true }))
        .catch(error => sendResponse({ success: false, error: error.message }));
      return true;
      
    case 'UPDATE_SETTINGS':
      updateSettings(message.settings)
        .then(() => sendResponse({ success: true }))
        .catch(error => sendResponse({ success: false, error: error.message }));
      return true;
      
    case 'GET_HISTORY':
      getHistory(message.days)
        .then(history => sendResponse({ success: true, history }))
        .catch(error => sendResponse({ success: false, error: error.message }));
      return true;
      
    default:
      sendResponse({ success: false, error: 'Unknown message type' });
  }
});

/**
 * Handle a prompt being sent
 */
async function handlePromptSent(data, tab) {
  try {
    const result = await chrome.storage.local.get([
      'sessionEnergy',
      'sessionCarbon',
      'totalPrompts',
      'lifetimeEnergy',
      'lifetimeCarbon',
      'lifetimePrompts',
      'settings'
    ]);
    
    const newSessionEnergy = (result.sessionEnergy || 0) + data.energy;
    const newSessionCarbon = (result.sessionCarbon || 0) + data.carbon;
    const newTotalPrompts = (result.totalPrompts || 0) + 1;
    const newLifetimeEnergy = (result.lifetimeEnergy || 0) + data.energy;
    const newLifetimeCarbon = (result.lifetimeCarbon || 0) + data.carbon;
    const newLifetimePrompts = (result.lifetimePrompts || 0) + 1;
    
    await chrome.storage.local.set({
      sessionEnergy: newSessionEnergy,
      sessionCarbon: newSessionCarbon,
      totalPrompts: newTotalPrompts,
      lifetimeEnergy: newLifetimeEnergy,
      lifetimeCarbon: newLifetimeCarbon,
      lifetimePrompts: newLifetimePrompts,
      lastUpdated: Date.now()
    });
    
    await logPromptEvent({
      timestamp: Date.now(),
      platform: data.platform,
      energy: data.energy,
      carbon: data.carbon,
      tokens: data.tokens,
      url: tab?.url
    });
    
    const settings = result.settings || {};
    if (settings.enableNotifications && data.energy > (settings.energyThreshold || 5)) {
      showHighEnergyNotification(data.energy, data.carbon);
    }
    
    updateBadge(newSessionEnergy);
    
    console.log('pranAI: Stats updated', {
      sessionEnergy: newSessionEnergy,
      sessionCarbon: newSessionCarbon,
      totalPrompts: newTotalPrompts
    });
    
    return {
      sessionEnergy: newSessionEnergy,
      sessionCarbon: newSessionCarbon,
      totalPrompts: newTotalPrompts
    };
  } catch (error) {
    console.error('Error handling prompt sent:', error);
    throw error;
  }
}

/**
 * Get all statistics
 */
async function getStats() {
  try {
    const result = await chrome.storage.local.get([
      'sessionEnergy',
      'sessionCarbon',
      'totalPrompts',
      'energySaved',
      'lifetimeEnergy',
      'lifetimeCarbon',
      'lifetimePrompts',
      'installDate',
      'lastUpdated'
    ]);
    
    return {
      session: {
        energy: result.sessionEnergy || 0,
        carbon: result.sessionCarbon || 0,
        prompts: result.totalPrompts || 0
      },
      lifetime: {
        energy: result.lifetimeEnergy || 0,
        carbon: result.lifetimeCarbon || 0,
        prompts: result.lifetimePrompts || 0
      },
      energySaved: result.energySaved || 0,
      installDate: result.installDate,
      lastUpdated: result.lastUpdated
    };
  } catch (error) {
    console.error('Error getting stats:', error);
    throw error;
  }
}

/**
 * Reset session statistics
 */
async function resetSessionStats() {
  try {
    await chrome.storage.local.set({
      sessionEnergy: 0,
      sessionCarbon: 0,
      totalPrompts: 0,
      lastUpdated: Date.now()
    });
    
    updateBadge(0);
    
    console.log('pranAI: Session stats reset');
  } catch (error) {
    console.error('Error resetting session stats:', error);
    throw error;
  }
}

/**
 * Update user settings
 */
async function 
[truncated — 7163 more characters]
```

### content/content.js

```javascript
// Content script that runs on AI chat websites
console.log('pranAI: Content script loaded');

class AIEnergyTracker {
  constructor() {
    this.platform = this.detectPlatform();
    this.overlayElement = null;
    this.textArea = null;
    this.sessionEnergy = 0;
    this.sessionCarbon = 0;
    this.totalPrompts = 0;
    
    this.init();
  }

  detectPlatform() {
    const hostname = window.location.hostname;
    if (hostname.includes('chatgpt.com')) return 'chatgpt';
    if (hostname.includes('claude.ai')) return 'claude';
    if (hostname.includes('gemini.google.com')) return 'gemini';
    if (hostname.includes('perplexity.ai')) return 'perplexity';
    return 'default';
  }

  init() {
    // Wait for page to load
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', () => this.setup());
    } else {
      this.setup();
    }
  }

  setup() {
    console.log('pranAI: Setting up on', this.platform);
    
    // Find the input textarea
    this.findTextArea();
    
    // Create and inject overlay
    this.createOverlay();
    
    // Load session stats
    this.loadSessionStats();
    
    // Start monitoring
    this.startMonitoring();

    this.monitorTabClose();
  }


  monitorTabClose() {
    // The 'beforeunload' event fires when the page is about to be unloaded.
    window.addEventListener('beforeunload', () => {
      console.log('pranAI: Tab is closing or navigating away...');
      this.sessionEnergy = 0
      this.saveSessionStats()
    });
  }

  findTextArea() {
    // Platform-specific selectors
    const selectors = {
      chatgpt: '#prompt-textarea, textarea[placeholder*="Message"]',
      claude: 'div[contenteditable="true"]',
      gemini: 'textarea, div[contenteditable="true"]',
      perplexity: 'textarea',
      default: 'textarea'
    };

    const selector = selectors[this.platform] || selectors.default;
    
    // Try to find the textarea
    const findTextAreaInterval = setInterval(() => {
      this.textArea = document.querySelector(selector);
      
      if (this.textArea) {
        console.log('pranAI: Found input element');
        clearInterval(findTextAreaInterval);
      }
    }, 1000);

    // Stop trying after 10 seconds
    setTimeout(() => clearInterval(findTextAreaInterval), 10000);
  }

  createOverlay() {
  // Create overlay container
  this.overlayElement = document.createElement('div');
  this.overlayElement.id = 'ai-energy-overlay';
  this.overlayElement.innerHTML = `
    <div class="energy-tracker-container">
      <div class="energy-header">
        <span class="energy-icon">⚡</span>
        <span class="energy-title">Energy Tracker</span>
      </div>
      <div class="energy-stats">
        <div class="stat-item">
          <span class="stat-label">Current Prompt:</span>
          <span class="stat-value current-energy">0 mWh</span>
        </div>
        <div class="stat-item">
          <span class="stat-label">Carbon:</span>
          <span class="stat-value current-carbon">0 mg CO₂</span>
        </div>
        <div class="stat-item session-stats">
          <span class="stat-label">Session Total:</span>
          <span class="stat-value session-energy">0 Wh</span>
        </div>
        <div class="stat-item saved-stats" style="background: rgba(76, 222, 128, 0.2);">
          <span class="stat-label">💚 Energy Saved:</span>
          <span class="stat-value energy-saved">0 Wh</span>
        </div>
      </div>
      <div class="energy-bar-container">
        <div class="energy-bar" style="width: 0%; background: #4ade80;"></div>
      </div>
      <div class="energy-suggestion">
        Type to see energy impact...
      </div>
      <div class="optimization-section" style="display: none;">
        <button class="optimize-btn">
          🌱 Optimize Prompt (-<span class="savings-percent">0</span>% energy)
        </button>
        <div class="optimization-preview" style="display: none;">
          <div class="preview-label">Optimized version:</div>
          <div class="preview-text"></div>
          <div class="preview-actions">
            <button class="accept-optimize-btn">✓ Use This</button>
            <button class="cancel-optimize-btn">✗ Cancel</button>
          </div>
        </div>
      </div>
      <button class="minimize-btn" title="Minimize">−</button>
    </div>
  `;

  // Add to page
  document.body.appendChild(this.overlayElement);

  // Setup button handlers
  this.setupOptimizationButtons();

  // Add minimize functionality
  const minimizeBtn = this.overlayElement.querySelector('.minimize-btn');
  const container = this.overlayElement.querySelector('.energy-tracker-container');
  
  minimizeBtn.addEventListener('click', () => {
    container.classList.toggle('minimized');
    minimizeBtn.textContent = container.classList.contains('minimized') ? '+' : '−';
  });
}

setupOptimizationButtons() {
  const optimizeBtn = this.overlayElement.querySelector('.optimize-btn');
  const optimizationSection = this.overlayElement.querySelector('.optimization-section');
  const optimizationPreview = this.overlayElement.querySelector('.optimization-preview');
  const acceptBtn = this.overlayElement.querySelector('.accept-optimize-btn');
  const cancelBtn = this.overlayElement.querySelector('.cancel-optimize-btn');
  
  let currentOptimization = null;

  optimizeBtn.addEventListener('click', () => {
    const text = this.getTextContent();
    if (!text || text.trim().length === 0) return;

    // Get optimization
    currentOptimization = window.PromptOptimizer.optimizePrompt(text);
    
    // Show preview
    this.overlayElement.querySelector('.preview-text').textContent = 
      currentOptimization.optimized;
    optimizationPreview.style.display = 'block';
  });

  acceptBtn.addEventListener('click', () => {
    if (!currentOptimization) return;

    // Replace text in textarea
    if (this.textArea.tagName === 'TEXTAREA' || this.textArea.tagName === 'INPUT') {
      this.textArea.va
[truncated — 7553 more characters]
```