Spaces:
Sleeping
Sleeping
| """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}) | |
| --- | |
| """ |