Guilherme Favaron
Remove public API - require Google Cloud authentication
ed17ba2
"""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})
---
"""