| |
|
|
| import { StateManager } from '../services/state-manager.js'; |
| import { TranslationService } from '../services/translation-service.js'; |
|
|
| export const CarbonTracker = { |
| elements: { |
| toolbarEmissions: null, |
| moreInfoBtn: null, |
| emissionsModal: null, |
| okModalBtn: null, |
| closeModalBtn: null, |
| emissionsTableBody: null, |
|
|
| totalEmissionsCell: null, |
| totalTokensCell: null, |
| totalRepliesCell: null, |
| totalWaterCell: null, |
| totalElectricityCell: null, |
| }, |
|
|
| |
| modelNames: { |
| "champ": "CHAMP (RAG)", |
| "skills_wiki": "CHAMP (wiki)", |
| |
| |
| |
| "openai": "GPT-5.3", |
| "google-conservative": translations[StateManager.currentLang]["gemini_conservative"], |
| "google-creative": translations[StateManager.currentLang]["gemini_creative"], |
| }, |
|
|
| |
| |
| |
| init() { |
| this.elements.toolbarEmissions = document.getElementById('toolbar-emissions'); |
| this.elements.moreInfoBtn = document.getElementById('emissions-more-info'); |
| this.elements.emissionsModal = document.getElementById('emissions-modal'); |
| this.elements.okModalBtn = document.getElementById('ok-emissions-btn'); |
| this.elements.closeModalBtn = document.getElementById('close-emissions-btn'); |
| this.elements.emissionsTableBody = document.getElementById('emissions-table-body'); |
|
|
| this.elements.totalEmissionsCell = document.getElementById('totalEmissions'); |
| this.elements.totalTokensCell = document.getElementById('totalTokens'); |
| this.elements.totalRepliesCell = document.getElementById('totalReplies'); |
| this.elements.totalWaterCell = document.getElementById('totalWater'); |
| this.elements.totalElectricityCell = document.getElementById('totalElectricity'); |
|
|
| this.attachEventListeners(); |
| }, |
|
|
| attachEventListeners() { |
| this.elements.moreInfoBtn.addEventListener('click', () => this.openModal()); |
| this.elements.okModalBtn.addEventListener('click', () => this.closeModal()); |
| this.elements.closeModalBtn.addEventListener('click', () => this.closeModal()); |
|
|
| this.elements.emissionsModal.addEventListener('click', (e) => { |
| if (e.target === this.elements.emissionsModal) { |
| this.closeModal(); |
| } |
| }); |
| }, |
|
|
| |
| |
| |
| |
| |
| formatEmissions(kgCO2eq) { |
| if (kgCO2eq < 0.001) { |
| return `${(kgCO2eq * 1000000).toFixed(3)} mg`; |
| } else if (kgCO2eq < 1) { |
| return `${(kgCO2eq * 1000).toFixed(3)} g`; |
| } else { |
| return `${kgCO2eq.toFixed(3)} kg`; |
| } |
| }, |
|
|
| |
| |
| |
| |
| |
| formatWater(water) { |
| if (water < 1) { |
| return `${(water * 1000).toFixed(3)} ml`; |
| } else { |
| return `${water.toFixed(3)} L`; |
| } |
| }, |
|
|
| |
| |
| |
| |
| |
| formatElectricity(electricity) { |
| if (electricity < 0.001) { |
| return `${(electricity * 1000000).toFixed(3)} mWh`; |
| } else if (electricity < 1) { |
| return `${(electricity * 1000).toFixed(3)} Wh`; |
| } else { |
| return `${electricity.toFixed(3)} kWh`; |
| } |
| }, |
|
|
| |
| |
| |
| |
| |
| formatNumber(num) { |
| return num.toLocaleString(); |
| }, |
|
|
| countReplies(messages) { |
| return messages.filter(msg => |
| msg.role === 'assistant' && msg.content && msg.content !== 'no_reply' |
| ).length; |
| }, |
|
|
| |
| |
| |
| |
| |
| countTokens(messages) { |
| return messages.reduce((total, msg) => { |
| return total + (msg.nTokens || 0); |
| }, 0); |
| }, |
|
|
| |
| |
| |
| updateEmissions() { |
| const totalEmissions = StateManager.getAllEmissions(); |
| this.elements.toolbarEmissions.innerHTML = this.formatEmissions(totalEmissions); |
| }, |
|
|
| |
| |
| |
| populateTable() { |
| this.elements.emissionsTableBody.innerHTML = ''; |
|
|
| let totalEmissions = 0; |
| let totalTokens = 0; |
| let totalReplies = 0; |
| let totalWater = 0; |
| let totalElectricity = 0; |
|
|
| |
| Object.keys(StateManager.modelChats).forEach(modelType => { |
| const chat = StateManager.modelChats[modelType]; |
| const emissions = StateManager.getTotalEmissions(modelType); |
| const water = StateManager.getTotalWater(modelType); |
| const electricity = StateManager.getTotalElectricity(modelType); |
| const tokens = this.countTokens(chat.messages); |
| const replies = this.countReplies(chat.messages); |
| const emissionsPerToken = tokens > 0 ? emissions / tokens : 0; |
|
|
| totalEmissions += emissions; |
| totalTokens += tokens; |
| totalReplies += replies; |
| totalWater += water; |
| totalElectricity += electricity; |
|
|
| const row = document.createElement('tr'); |
| |
| |
| |
| row.innerHTML = ` |
| <td data-label="${translations[StateManager.currentLang]["emissions_model"]}: ">${this.modelNames[modelType] || modelType}</td> |
| <td data-label="${translations[StateManager.currentLang]["emissions_co2"]}: ">${this.formatEmissions(emissions)}</td> |
| <td data-label="${translations[StateManager.currentLang]["emissions_tokens"]}: ">${this.formatNumber(tokens)}</td> |
| <td data-label="${translations[StateManager.currentLang]["emissions_replies"]}: ">${this.formatNumber(replies)}</td> |
| <td data-label="${translations[StateManager.currentLang]["emissions_per_token"]}: ">${emissionsPerToken > 0 ? this.formatEmissions(emissionsPerToken) : '—'}</td> |
| <td data-label="${translations[StateManager.currentLang]["emissions_water"]}: ">${this.formatWater(water)}</td> |
| <td data-label="${translations[StateManager.currentLang]["emissions_electricity"]}: ">${this.formatElectricity(electricity)}</td> |
| `; |
| this.elements.emissionsTableBody.appendChild(row); |
| }); |
|
|
| |
| this.elements.totalEmissionsCell.textContent = this.formatEmissions(totalEmissions); |
| this.elements.totalEmissionsCell.setAttribute('data-label', `${translations[StateManager.currentLang]["emissions_co2"]}: `); |
|
|
| this.elements.totalTokensCell.textContent = this.formatNumber(totalTokens); |
| this.elements.totalTokensCell.setAttribute('data-label', `${translations[StateManager.currentLang]["emissions_tokens"]}: `); |
|
|
| this.elements.totalRepliesCell.textContent = this.formatNumber(totalReplies); |
| this.elements.totalRepliesCell.setAttribute('data-label', `${translations[StateManager.currentLang]["emissions_replies"]}: `); |
|
|
| this.elements.totalWaterCell.textContent = this.formatWater(totalWater); |
| this.elements.totalWaterCell.setAttribute('data-label', `${translations[StateManager.currentLang]["emissions_water"]}: `); |
|
|
| this.elements.totalElectricityCell.textContent = this.formatElectricity(totalElectricity); |
| this.elements.totalElectricityCell.setAttribute('data-label', `${translations[StateManager.currentLang]["emissions_electricity"]}: `); |
|
|
| |
| this.updateEquivalents(totalEmissions); |
| }, |
|
|
| |
| |
| |
| |
| updateEquivalents(kgCO2) { |
| |
| const CARROT_MEALS_PER_KG = 1 / 0.04 |
| const PAPERSHEET_PER_KG = 1 / (5 / 1000) |
| const CAR_M_PER_KG = 1 / (0.2 / 1000); |
| const SMS_PER_KG = 1 / (0.014 / 1000) ; |
| const SPAM_PER_KG = 1 / (0.03 / 1000) ; |
|
|
| const carrotMeals = kgCO2 * CARROT_MEALS_PER_KG; |
| const papersheets = kgCO2 * PAPERSHEET_PER_KG; |
| const carM = kgCO2 * CAR_M_PER_KG; |
| const sms = kgCO2 * SMS_PER_KG; |
| const spam = kgCO2 * SPAM_PER_KG; |
|
|
| document.getElementById('carrot').textContent = carrotMeals.toFixed(1); |
|
|
| document.getElementById('papersheet').textContent = papersheets.toFixed(1); |
|
|
| document.getElementById('carM').textContent = carM.toFixed(1); |
|
|
| document.getElementById('spam').textContent = spam.toFixed(1); |
|
|
| document.getElementById('sms').textContent = sms.toFixed(1); |
| }, |
|
|
| |
| |
| |
| openModal() { |
| this.populateTable(); |
| this.elements.emissionsModal.style.display = ''; |
| TranslationService.applyTranslation(); |
| }, |
|
|
| |
| |
| |
| closeModal() { |
| this.elements.emissionsModal.style.display = 'none'; |
| }, |
| }; |