Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import requests | |
| from bs4 import BeautifulSoup | |
| import json | |
| from datetime import datetime | |
| def calculate_trust_score(url): | |
| try: | |
| if not url.startswith(('http://', 'https://')): | |
| url = 'https://' + url | |
| headers = { | |
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' | |
| } | |
| response = requests.get(url, headers=headers, timeout=10) | |
| soup = BeautifulSoup(response.text, 'html.parser') | |
| trust_score = 0 | |
| details = { | |
| 'identity': {'score': 0, 'max': 40, 'items': []}, | |
| 'content': {'score': 0, 'max': 40, 'items': []}, | |
| 'signals': {'score': 0, 'max': 20, 'items': []} | |
| } | |
| scripts = soup.find_all('script', type='application/ld+json') | |
| has_organization = False | |
| has_person = False | |
| has_same_as = False | |
| for script in scripts: | |
| try: | |
| data = json.loads(script.string) | |
| data_items = data if isinstance(data, list) else [data] | |
| for item in data_items: | |
| if "@type" in item: | |
| if item["@type"] == "Organization": | |
| has_organization = True | |
| details['identity']['score'] += 15 | |
| details['identity']['items'].append("✅ Organização identificada") | |
| if "logo" in item: | |
| details['identity']['score'] += 5 | |
| details['identity']['items'].append("✅ Logo definida") | |
| if "sameAs" in item: | |
| has_same_as = True | |
| details['identity']['score'] += 10 | |
| details['identity']['items'].append("✅ Links de verificação (sameAs)") | |
| elif item["@type"] == "Person": | |
| has_person = True | |
| details['identity']['score'] += 10 | |
| details['identity']['items'].append("✅ Pessoa identificada") | |
| if "sameAs" in item: | |
| has_same_as = True | |
| details['identity']['score'] += 10 | |
| details['identity']['items'].append("✅ Links sociais da pessoa") | |
| elif item["@type"] == "Article": | |
| details['content']['score'] += 15 | |
| details['content']['items'].append("✅ Artigo estruturado") | |
| if "author" in item: | |
| details['content']['score'] += 10 | |
| details['content']['items'].append("✅ Autor identificado") | |
| if "datePublished" in item: | |
| details['content']['score'] += 5 | |
| details['content']['items'].append("✅ Data de publicação") | |
| except: | |
| continue | |
| h1_count = len(soup.find_all('h1')) | |
| h2_count = len(soup.find_all('h2')) | |
| if h1_count == 1: | |
| details['content']['score'] += 5 | |
| details['content']['items'].append("✅ Estrutura H1 única") | |
| elif h1_count > 1: | |
| details['content']['items'].append("⚠️ Múltiplos H1 encontrados") | |
| if h2_count > 0: | |
| details['content']['score'] += 5 | |
| details['content']['items'].append("✅ Estrutura H2 presente") | |
| title = soup.find('title') | |
| meta_desc = soup.find('meta', attrs={'name': 'description'}) | |
| if title and len(title.get_text().strip()) > 10: | |
| details['content']['score'] += 5 | |
| details['content']['items'].append("✅ Título adequado") | |
| if meta_desc and len(meta_desc.get('content', '').strip()) > 50: | |
| details['content']['score'] += 5 | |
| details['content']['items'].append("✅ Meta description presente") | |
| if url.startswith('https://'): | |
| details['signals']['score'] += 10 | |
| details['signals']['items'].append("✅ HTTPS ativo") | |
| contact_indicators = ['contact', 'email', 'phone', 'address', 'sobre', 'about'] | |
| page_text = soup.get_text().lower() | |
| if any(indicator in page_text for indicator in contact_indicators): | |
| details['signals']['score'] += 5 | |
| details['signals']['items'].append("✅ Informações de contato") | |
| external_links = soup.find_all('a', href=True) | |
| quality_domains = ['github.com', 'linkedin.com', 'medium.com', 'wikidata.org', 'keybase.io'] | |
| for link in external_links: | |
| href = link.get('href', '') | |
| if any(domain in href for domain in quality_domains): | |
| details['signals']['score'] += 5 | |
| details['signals']['items'].append("✅ Links para plataformas confiáveis") | |
| break | |
| total_score = min( | |
| details['identity']['score'] + | |
| details['content']['score'] + | |
| details['signals']['score'], | |
| 100 | |
| ) | |
| if total_score >= 80: | |
| level = "🚀 Excelente" | |
| level_color = "🟢" | |
| elif total_score >= 60: | |
| level = "👍 Bom" | |
| level_color = "🟡" | |
| elif total_score >= 40: | |
| level = "⚠️ Precisa melhorar" | |
| level_color = "🟠" | |
| else: | |
| level = "❌ Crítico" | |
| level_color = "🔴" | |
| suggestions = [] | |
| if not has_organization and not has_person: | |
| suggestions.append("🎯 **Prioridade Alta**: Adicione schema.org com @type Organization ou Person") | |
| if not has_same_as: | |
| suggestions.append("🔗 Adicione links 'sameAs' para LinkedIn, GitHub ou outras plataformas") | |
| if details['content']['score'] < 20: | |
| suggestions.append("📝 Melhore a estrutura do conteúdo com headings H1/H2 e meta tags") | |
| if details['signals']['score'] < 10: | |
| suggestions.append("🔒 Garanta HTTPS e adicione informações de contato") | |
| if total_score >= 80: | |
| suggestions.append("🎉 Parabéns! Seu site está bem otimizado para LLMs") | |
| report = f"""# {level_color} **Trust Score: {total_score}/100** | |
| ## {level} | |
| ### 📊 **Detalhamento por Categoria** | |
| #### 🏢 **Identidade Digital** ({details['identity']['score']}/{details['identity']['max']} pontos) | |
| {chr(10).join(details['identity']['items']) if details['identity']['items'] else "❌ Nenhuma identidade estruturada encontrada"} | |
| #### 📝 **Conteúdo Estruturado** ({details['content']['score']}/{details['content']['max']} pontos) | |
| {chr(10).join(details['content']['items']) if details['content']['items'] else "❌ Estrutura de conteúdo não otimizada"} | |
| #### 🔒 **Sinais de Confiança** ({details['signals']['score']}/{details['signals']['max']} pontos) | |
| {chr(10).join(details['signals']['items']) if details['signals']['items'] else "❌ Sinais de confiança ausentes"} | |
| ### 💡 **Próximos Passos** | |
| {chr(10).join(f"• {tip}" for tip in suggestions)} | |
| ### 📚 **Recursos Úteis** | |
| • [Schema.org Generator](https://schema.org/) | |
| • [Google Rich Results Test](https://search.google.com/test/rich-results) | |
| • [Structured Data Markup Helper](https://www.google.com/webmasters/markup-helper/) | |
| ----- | |
| *💡 Dica: Um site bem estruturado não só melhora a visibilidade para LLMs, mas também para mecanismos de busca!* | |
| """ | |
| return report | |
| except requests.exceptions.RequestException as e: | |
| return f"❌ **Erro de conexão**: Não foi possível acessar o site.\n\n*Verifique se a URL está correta e o site está online.*" | |
| except Exception as e: | |
| return f"❌ **Erro inesperado**: {str(e)}\n\n*Tente novamente ou verifique se a URL está no formato correto.*" | |
| import gradio as gr | |
| with gr.Blocks(title="🤖 LLM Trust Score") as demo: | |
| gr.Markdown("## 🤖 LLM Trust Score Calculator\nDescubra como seu site é percebido por modelos como ChatGPT, Claude, Perplexity e Grok.") | |
| url_input = gr.Textbox(label="🌐 URL do seu site", placeholder="exemplo.com ou https://seusite.com.br") | |
| output = gr.Markdown() | |
| analyze_btn = gr.Button("🔍 Analisar Site") | |
| analyze_btn.click(fn=calculate_trust_score, inputs=url_input, outputs=output) | |
| demo.launch() | |