"""Gradio UI for PageSpeed Insights comparator.""" import os import gradio as gr import pandas as pd from typing import Tuple, Optional from pagespeed_client import PageSpeedClient from analyzer import PageSpeedAnalyzer from models import PageSpeedData, ComparisonResult from config import config class PageSpeedUI: """Gradio user interface for PageSpeed Insights comparison tool.""" def __init__(self): self.client = None self.analyzer = None self.config_error = None try: self.client = PageSpeedClient() # Only initialize analyzer if OpenAI is configured if config.openai_api_key: self.analyzer = PageSpeedAnalyzer() except ValueError as e: self.config_error = str(e) def create_interface(self) -> gr.Blocks: """Create and configure the Gradio interface.""" with gr.Blocks(title="PageSpeed Insights Comparator", theme=gr.themes.Soft()) as demo: if self.config_error: gr.Markdown(f""" # ❌ Configuração do Google Cloud Necessária **Erro:** {self.config_error} Para usar este app com seu projeto Google Cloud, você precisa configurar uma das opções: ## **Opção 1: Google API Key (Recomendado)** 1. Vá para [Google Cloud Console](https://console.cloud.google.com/) 2. Selecione seu projeto 3. Vá para **APIs & Services** → **Library** 4. Pesquise e ative "PageSpeed Insights API" 5. Vá para **APIs & Services** → **Credentials** 6. Clique **+ CREATE CREDENTIALS** → **API key** 7. Copie sua API key (ex: `AIzaSyD...`) 8. Adicione no Space: `GOOGLE_API_KEY` = sua chave ## **Opção 2: Service Account (Avançado)** 1. No Google Cloud Console, vá para **IAM & Admin** → **Service Accounts** 2. Crie uma Service Account 3. Baixe o arquivo JSON 4. Adicione no Space: `GOOGLE_SERVICE_ACCOUNT_JSON` = conteúdo do JSON ## **Configurar no Hugging Face:** 1. Settings → Variables and secrets 2. Adicione uma das variáveis acima 3. Reinicie o Space """) return demo # Check authentication status has_openai = bool(config.openai_api_key) has_google_key = bool(os.environ.get('GOOGLE_API_KEY')) and len(os.environ.get('GOOGLE_API_KEY', '')) < 100 has_google_service = bool(os.environ.get('GOOGLE_SERVICE_ACCOUNT_JSON')) # Build status message auth_status = [] if has_google_key: auth_status.append("✅ Google API Key configurado") elif has_google_service: auth_status.append("✅ Google Service Account configurado") else: auth_status.append("❌ Google authentication não configurado") if has_openai: auth_status.append("✅ OpenAI configurado") else: auth_status.append("⚠️ OpenAI não configurado (análise com IA não disponível)") gr.Markdown(f""" # 🚀 PageSpeed Insights Comparator Compare duas análises do PageSpeed Insights para monitorar melhorias em Core Web Vitals. **Status:** {' | '.join(auth_status)} **Como usar:** 1. Cole a URL da primeira análise (baseline) 2. Cole a URL da segunda análise (atual) 3. Clique em "Comparar Análises" **Exemplo de URL:** `https://pagespeed.web.dev/analysis/https-www-example-com/abc123?form_factor=mobile` """) with gr.Row(): with gr.Column(): url1_input = gr.Textbox( label="📋 URL da Análise Anterior (Baseline)", placeholder="https://pagespeed.web.dev/analysis/...", lines=2 ) url2_input = gr.Textbox( label="📋 URL da Análise Atual", placeholder="https://pagespeed.web.dev/analysis/...", lines=2 ) compare_btn = gr.Button("🔍 Comparar Análises", variant="primary", size="lg") with gr.Row(): summary_output = gr.Markdown(label="Resumo") with gr.Row(): table_output = gr.Dataframe( label="📊 Tabela Comparativa", wrap=True ) with gr.Row(): ai_output = gr.Markdown(label="🤖 Análise Detalhada com IA") # Exemplos gr.Examples( examples=[ [ "https://pagespeed.web.dev/analysis/https-www-griinstitute-org-realestate-company-profile-orion-capital-managers-uk_101/3klkazqpqf?form_factor=mobile", "https://pagespeed.web.dev/analysis/https-www-griinstitute-org-realestate-company-profile-orion-capital-managers-uk_101/3klkazqpqf?form_factor=mobile" ] ], inputs=[url1_input, url2_input] ) compare_btn.click( fn=self.process_comparison, inputs=[url1_input, url2_input], outputs=[summary_output, table_output, ai_output] ) return demo def process_comparison(self, url1: str, url2: str, progress=gr.Progress()) -> Tuple[str, Optional[pd.DataFrame], Optional[str]]: """Process comparison between two PageSpeed Insights URLs.""" if not url1 or not url2: return "❌ Por favor, forneça ambas as URLs", None, None if not url1.startswith('https://pagespeed.web.dev/analysis/'): return "❌ URL 1 inválida. Use uma URL do PageSpeed Insights", None, None if not url2.startswith('https://pagespeed.web.dev/analysis/'): return "❌ URL 2 inválida. Use uma URL do PageSpeed Insights", None, None try: progress(0, desc="Extraindo dados da primeira análise...") data1 = self.client.extract_pagespeed_data(url1) if not data1: return "❌ Erro ao extrair dados da primeira URL. Verifique se a URL está correta.", None, None progress(0.3, desc="Extraindo dados da segunda análise...") data2 = self.client.extract_pagespeed_data(url2) if not data2: return "❌ Erro ao extrair dados da segunda URL. Verifique se a URL está correta.", None, None progress(0.6, desc="Comparando métricas...") comparison = self.analyzer.compare_metrics(data1, data2) progress(0.7, desc="Gerando tabela comparativa...") df = self._create_comparison_table(comparison) if self.analyzer: progress(0.8, desc="Analisando com IA (pode levar alguns segundos)...") ai_analysis = self.analyzer.analyze_with_openai(data1, data2, comparison) else: ai_analysis = "⚠️ Análise com IA não disponível. Configure OPENAI_API_KEY para ativar esta funcionalidade." progress(1.0, desc="Concluído!") summary = self._create_summary(data1, data2) return summary, df, ai_analysis except ValueError as e: return f"❌ Erro de configuração: {str(e)}", None, None except Exception as e: return f"❌ Erro durante o processamento: {str(e)}", None, None def _create_comparison_table(self, comparison: ComparisonResult) -> pd.DataFrame: """Create DataFrame for comparison visualization.""" comparison_dict = comparison.to_dict() df = pd.DataFrame([ { 'Métrica': metric, 'Antes': f"{values['antes']:.2f}" if isinstance(values['antes'], float) else values['antes'], 'Depois': f"{values['depois']:.2f}" if isinstance(values['depois'], float) else values['depois'], 'Diferença': f"{values['diferenca']:+.2f}" if isinstance(values['diferenca'], float) else f"{values['diferenca']:+}", 'Status': '✅ Melhorou' if values['diferenca'] < 0 and 'Score' not in metric else '✅ Melhorou' if values['diferenca'] > 0 and 'Score' in metric else '❌ Piorou' if values['diferenca'] != 0 else '➖ Sem mudança' } for metric, values in comparison_dict.items() ]) return df def _create_summary(self, data1: PageSpeedData, data2: PageSpeedData) -> str: """Create summary text for the comparison results.""" return f""" ## 📊 Resumo da Comparação **URL Analisada:** {data2.url_original} **Dispositivo:** {data2.device.upper()} ### Pontuações Gerais: - **Performance:** {data1.performance_score:.0f} → {data2.performance_score:.0f} ({data2.performance_score-data1.performance_score:+.0f}) - **Accessibility:** {data1.accessibility_score:.0f} → {data2.accessibility_score:.0f} ({data2.accessibility_score-data1.accessibility_score:+.0f}) - **Best Practices:** {data1.best_practices_score:.0f} → {data2.best_practices_score:.0f} ({data2.best_practices_score-data1.best_practices_score:+.0f}) - **SEO:** {data1.seo_score:.0f} → {data2.seo_score:.0f} ({data2.seo_score-data1.seo_score:+.0f}) --- """