seinfra-app / app.py
tbluhm's picture
Upload app.py
7f0d652 verified
import gradio as gr
import os
import time
import fitz # PyMuPDF
from docx import Document
from docx.shared import Inches
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from tqdm import tqdm
from dotenv import load_dotenv
from modelo_clip import ValidatorVITImgTexto
from openai import OpenAI
import re
from threading import Thread
from queue import Queue
from gradio_pdf import PDF
# 🔹 Carregar variáveis de ambiente
load_dotenv()
secretk = os.environ.get("OPENAI_API_KEY")
cliente_openai = OpenAI(api_key=secretk)
# 🔹 Criar pastas para armazenar arquivos
os.makedirs("uploads", exist_ok=True)
os.makedirs("clippings", exist_ok=True)
# 🔹 Justificar parágrafos no Word
def justify_paragraph(paragraph):
p = paragraph._element
pPr = p.get_or_add_pPr()
jc = OxmlElement('w:jc')
jc.set(qn('w:val'), 'both')
pPr.append(jc)
# 🔹 Função para extrair texto do PDF
def extract_content(pdf_path):
doc = fitz.open(pdf_path)
extracted_data = []
for page_num, page in enumerate(doc, start=1):
page_data = {
"page_number": page_num,
"text": page.get_text("text"),
"link": f"{os.path.basename(pdf_path)}#page={page_num}"
}
extracted_data.append(page_data)
return extracted_data
# 🔹 Função para identificar palavras-chave no texto
def find_keywords(text, keywords):
detected = [kw for kw in keywords if kw.lower() in text.lower()]
return detected
# 🔹 Função para gerar resumos via OpenAI
def generate_summary(text):
prompt = f"Resuma o seguinte texto em poucas frases mantendo os pontos principais:\n\n{text}"
try:
response = cliente_openai.chat.completions.create(
model="gpt-4o",
messages=[{"role": "system", "content": "Você é um assistente que resume textos de forma objetiva."},
{"role": "user", "content": prompt}],
temperature=0.3,
max_tokens=150
)
return response.choices[0].message.content.strip()
except Exception as e:
return f"Erro ao gerar resumo: {e}"
# 🔹 Filtrar conteúdo com base nas palavras-chave e gerar resumos
def filter_content(extracted_data, keywords):
filtered_data = []
for page in extracted_data:
detected_keywords = find_keywords(page["text"], keywords)
if detected_keywords:
summary = generate_summary(page["text"])
filtered_data.append({
"page_number": page["page_number"],
"summary": summary,
"text": page["text"],
"keywords": ", ".join(detected_keywords),
"link": page["link"]
})
return filtered_data
# 🔹 Criar um documento Word com os resumos
def generate_word_from_summary(filtered_data, output_path):
doc = Document()
if not filtered_data:
doc.add_paragraph("Nenhum conteúdo relevante encontrado.")
else:
for page in filtered_data:
doc.add_heading(f"Resumo da Página {page['page_number']}", level=2)
doc.add_paragraph(f"**Palavras-chave encontradas:** {page['keywords']}")
doc.add_paragraph(f"**Resumo:** {page['summary']}")
doc.add_paragraph(f"📎 [Acesse a Página]({page['link']})")
doc.add_paragraph("-" * 50)
doc.save(output_path)
def generate_clickable_link(pdf_path, page_number):
"""
Gera um link funcional para acessar uma página específica do PDF dentro do Gradio.
"""
pdf_filename = os.path.basename(pdf_path) # Pega apenas o nome do arquivo
link = f'<a href="{pdf_filename}#page={page_number}" target="_blank">📄 Acesse a Página {page_number}</a>'
return link
# 🔹 Processamento do PDF no Gradio
def process_pdf(uploaded_pdf):
if not uploaded_pdf:
return "Nenhum arquivo enviado.", None
pdf_path = uploaded_pdf
output_docx = os.path.join("clippings", f"clipping_{int(time.time())}.docx")
keywords = ["Governo Federal", "Ceará", "infraestrutura", "saúde", "educação", "segurança pública"]
extracted_data = extract_content(pdf_path)
filtered_data = filter_content(extracted_data, keywords)
generate_word_from_summary(filtered_data, output_docx)
resumos = []
for page in extracted_data:
summary = generate_summary(page["text"])
resumos.append({
"page_number": page["page_number"],
"summary": summary
})
return resumos
# 🔹 Criar botões e resumos interativos em Markdown com HTML
def create_summary_buttons(resumos):
markdown_content = ""
for r in resumos:
page_num = r["page_number"]
summary = r["summary"]
markdown_content += f"""
<button style='padding:5px;margin:5px;' onclick='
const pages = document.querySelectorAll(".pdf-container .page");
if(pages && pages.length >= {page_num}){{
pages[{page_num}-1].scrollIntoView({{ behavior: "smooth" }});
}}
'>📄 Ir para Página {page_num}</button>
<strong>🔑 Resumo:</strong> {summary}<br><hr>
"""
return markdown_content if markdown_content else "Nenhum resumo disponível."
# 🔹 Interface Gradio
with gr.Blocks() as demo:
gr.Markdown("### 📑 Clipapptor - IA para Resumo de PDFs")
with gr.Row():
with gr.Column(scale=1): # Lado esquerdo
uploaded_pdf = PDF(label="📤 Faça upload do PDF", interactive=True, height=650)
#page_input = gr.Number(value=1, label="Página", interactive=True)
#go_to_page_button = gr.Button("Ir para Página", elem_id="go-to-page-button")
with gr.Column(scale=1): # Lado direito
process_button = gr.Button("📄 Gerar Clippings do Jornal")
resumo_output = gr.Markdown("Aguardando resumos...", render=True, height=650)
# 🔹 Função para navegação no PDF
# def go_to_page(page_number):
# return page_number
def process_and_create_buttons(pdf):
resumos = process_pdf(pdf)
return create_summary_buttons(resumos)
process_button.click(
fn=process_and_create_buttons,
inputs=[uploaded_pdf],
outputs=[resumo_output]
)
# go_to_page_button.click(fn=go_to_page, inputs=[page_input], outputs=[page_input])
demo.launch(share=True)