verbnetbr / app.py
renatosvmor's picture
first commit
64c5bab
import gradio as gr
import sqlite3
import os
DB = "verbnetbr.db"
head_content = """
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<script>
// Força o modo claro no Gradio para evitar conflito de cores no celular
function forceLightMode() {
document.body.classList.remove('dark');
document.documentElement.classList.remove('dark');
}
// Executa ao carregar e monitora mudanças
window.onload = forceLightMode;
setInterval(forceLightMode, 1000);
</script>
"""
# --- Estilos CSS Customizados ---
css = """
.top-header { background-color: #f8f9fa; border-bottom: 1px solid #dee2e6; }
.site-title { font-weight: bold; color: #114278 !important; margin: 0; }
.content-area { padding: 30px 10px; min-height: 400px; color: #212529 !important; }
/* Garante que o fundo do Gradio não fique preto no celular */
.gradio-container { background-color: white !important; }
"""
# --- Funções de Base de Dados ---
def buscar_por_texto(termo):
if not termo or len(termo.strip()) < 2:
return [["Aviso", "Digite pelo menos 2 caracteres para buscar."]]
con = sqlite3.connect(DB)
cur = con.cursor()
# Busca por parte do verbo OU parte da classe
query = """
SELECT verbo, classe FROM candidatos
WHERE (verbo LIKE ? OR classe LIKE ?) AND exp1=1
ORDER BY verbo
"""
cur.execute(query, (f'%{termo}%', f'%{termo}%'))
rows = cur.fetchall()
con.close()
return [list(r) for r in rows] if rows else [["-", "Nenhum resultado encontrado"]]
def buscar_por_letra(letra):
con = sqlite3.connect(DB)
cur = con.cursor()
cur.execute("SELECT verbo, classe FROM candidatos WHERE verbo LIKE ? AND exp1=1 ORDER BY verbo", (letra+'%',))
rows = cur.fetchall()
con.close()
return [list(r) for r in rows]
def buscar_todas_classes():
con = sqlite3.connect(DB)
cur = con.cursor()
cur.execute("SELECT DISTINCT classe FROM candidatos WHERE exp1=1 ORDER BY classe")
rows = cur.fetchall()
con.close()
return [["-", r[0]] for r in rows]
def buscar_detalhes(evt: gr.SelectData):
# evt.index[1] é o índice da coluna. 0 = Verbo, 1 = Classe.
if evt.index[1] == 0:
return gr.update() # Não faz nada se clicar na coluna do Verbo
classe = evt.value
if classe in ["-", "Nenhum resultado encontrado", "Aviso", ""]:
return ""
con = sqlite3.connect(DB)
cur = con.cursor()
cur.execute("SELECT verbo FROM candidatos WHERE classe = ? AND exp1=1", (classe,))
verbos = [r[0] for r in cur.fetchall()]
cur.execute("SELECT papel FROM papeis WHERE classe = ?", (classe,))
papeis = [r[0] for r in cur.fetchall()]
cur.execute("SELECT alternancia, pingles, singles FROM classes WHERE classe = ?", (classe,))
frames_rows = cur.fetchall()
con.close()
html = f"""
<div style='margin-top: 30px; border-top: 2px solid #114278; padding-top: 20px; color: #212529;'>
<center><h2 style="color: #114278;">{classe}</h2></center>
<b>Classe na VerbNet:</b>&nbsp; <a href="http://verbs.colorado.edu/verb-index/vn/{classe}.php" target="_blank" style="color: blue; text-decoration: underline;">{classe}</a><br><br>
<b>Papéis Temáticos:</b>&nbsp; {" ".join(papeis)}<br><br>
<b>Membros:</b> {", ".join(verbos)}<br><br>
<table style='width:100%; border-collapse: collapse;'>
<tr style='color: white; background-color: #114278;'>
<th style='padding: 10px; text-align: left;'>VerbNet.Br</th>
<th style='width: 5%; background-color: white;'></th>
<th style='padding: 10px; text-align: left;'>VerbNet</th>
</tr>
"""
for alt, ping, sing in frames_rows:
html += f"<tr><td style='padding:10px; border-bottom:1px solid #ddd;'>{alt}</td><td style='background-color: white;'></td><td style='padding:10px; border-bottom:1px solid #ddd;'>{ping} - {sing}</td></tr>"
html += "</table></div>"
return html
def carregar_html(nome_arquivo):
if os.path.exists(nome_arquivo):
with open(nome_arquivo, "r", encoding="utf-8") as f:
return f.read()
return f"<p>Arquivo {nome_arquivo} não encontrado.</p>"
# --- Interface Gradio ---
with gr.Blocks(css=css, head=head_content) as demo:
gr.HTML('<header class="top-header py-4"><div class="container"><h1 class="site-title">VerbNet.Br 1.0</h1></div></header>')
with gr.Tabs():
with gr.TabItem("Home"):
gr.HTML(carregar_html("index.html"))
with gr.TabItem("Busca"):
with gr.Column(elem_classes="container content-area"):
# --- NOVO: Campo de busca por texto (idêntico à imagem) ---
with gr.Column(elem_classes="search-container"):
gr.HTML('<h3 style="margin-bottom:15px; font-size: 1.2rem; color: #2d5a27;">Digite parte de um verbo ou de uma classe da VerbNet.Br:</h3>')
with gr.Row():
input_texto = gr.Textbox(show_label=False, placeholder="Ex: correr, consider...", scale=4)
btn_buscar = gr.Button("Buscar", variant="primary", scale=1)
# Botões de Letras
gr.HTML('<p style="margin-bottom:5px;">Ou selecione pela letra inicial do verbo:</p>')
with gr.Row():
letras = "ABCDEFGHILMNOPQRSTUVXZ"
btns_alfabeto = [gr.Button(l, elem_classes="alphabet-btn", min_width=35) for l in letras]
btn_todas = gr.Button("Ver Todas as Classes da VerbNet.Br", variant="secondary")
saida_letra = gr.Dataframe(headers=["Verbo", "Classe"], interactive=False)
saida_classe = gr.HTML()
with gr.TabItem("Publicações"):
gr.HTML(carregar_html("publicacoes.html"))
with gr.TabItem("Contato"):
gr.HTML(carregar_html("contato.html"))
# --- Eventos ---
# Busca por texto (Enter ou Botão)
btn_buscar.click(fn=buscar_por_texto, inputs=input_texto, outputs=saida_letra)
input_texto.submit(fn=buscar_por_texto, inputs=input_texto, outputs=saida_letra)
# Letras e Ver Todas
for btn, letra in zip(btns_alfabeto, letras):
btn.click(fn=lambda l=letra: buscar_por_letra(l), outputs=saida_letra)
btn_todas.click(fn=buscar_todas_classes, outputs=saida_letra)
saida_letra.select(fn=buscar_detalhes, outputs=saida_classe)
if __name__ == "__main__":
demo.launch()