Spaces:
Sleeping
Sleeping
| import os | |
| from time import sleep | |
| from dotenv import load_dotenv | |
| from google import genai | |
| from reportlab.platypus import Paragraph, Frame | |
| from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle | |
| from reportlab.lib.pagesizes import A4 | |
| from reportlab.lib.utils import ImageReader | |
| from reportlab.pdfgen import canvas | |
| import re | |
| from html import escape | |
| load_dotenv() | |
| api_token = os.environ.get("SYNAP") | |
| class Model(): | |
| def __init__(self, titulo_pdf, titulo, n_paginas): | |
| self.titulo = titulo | |
| self.n_paginas = n_paginas | |
| self.oppo = genai.Client(api_key=api_token, http_options={"api_version": "v1beta"}) | |
| print(f"Escolhendo os Subtemas") | |
| self.subtemas = self.API(f""" | |
| Sobre o tema {titulo}, cria {self.n_paginas} subtemas curtos para um trabalho acadêmico. | |
| - O primeiro subtema deve ser 'Introducao'. | |
| - NÃO inclua o tema principal nos subtemas. | |
| - Cada subtema deve ser curto, claro, bem escrito e **APENAS UMA PALAVRA**, sem espaços ou underscores. | |
| - ENTREGUE apenas os subtemas, separados por vírgula ou espaço. | |
| - Não use hífens, números ou símbolos. | |
| - Nenhuma explicação ou frase adicional, apenas os nomes dos subtemas. | |
| """).split(",") # ou .split() se separar por espaços | |
| sleep(5) | |
| print(f"Subtemas Escolhidos!") | |
| self.largura, self.altura = A4 | |
| self.c = canvas.Canvas(titulo_pdf, pagesize=A4) | |
| self.pagina = 0 | |
| self.pagina_idc = 0 | |
| def capa(self, logo, capaImage, titulo, subtitulo, instituto): | |
| self.logo = ImageReader(logo) | |
| self.capaImage = ImageReader(capaImage) | |
| self.titulo = titulo | |
| self.instituto = instituto | |
| self.professor = professor | |
| x = (self.largura - 350) | |
| y = self.altura - 150 | |
| self.c.drawImage(self.logo, x + 15, y, width=100, height=100) | |
| self.c.setFont("Times-Roman", 10) | |
| self.c.drawCentredString(x + 65, 675, "República de Angola") | |
| self.c.setFont("Times-Roman", 10) | |
| self.c.drawCentredString(x + 65, 660, "Ministério da Educação") | |
| self.c.setFont("Times-Roman", 10) | |
| self.c.drawCentredString(x + 65, 645, instituto) | |
| self.c.setFont("Times-Bold", 35) | |
| self.c.drawCentredString(x + 65, 580, titulo) | |
| self.c.setFont("Times-Roman", 20) | |
| self.c.drawCentredString(x + 65, 550, subtitulo) | |
| self.c.drawImage(self.capaImage, (x - 65) / 2, (self.altura - 610), width=(576 + 270)/2, height=(315 + 200)/2) | |
| margem = 20 | |
| self.c.rect(margem, margem, self.largura - 2*margem, self.altura - 2*margem) | |
| self.c.setFont("Times-Roman", 15) | |
| self.c.drawCentredString(x + 165, 150, "Docente") | |
| self.c.line(320, 100, 490, 100) | |
| def integrantes(self, integrantes, disciplina, grupo, classe, turma, curso, turno): | |
| self.c.showPage() | |
| self.paginar_letra("I") | |
| y = 700 | |
| self.c.setFont("Times-Bold", 20) | |
| self.c.drawCentredString(200, 750, "Integrantes do Grupo") | |
| self.integrantes = integrantes | |
| numero = 1 | |
| for i in integrantes: | |
| self.c.setFont("Times-Roman", 15) | |
| self.c.drawString(110, y, f"{numero}.") | |
| self.c.drawString(130, y, f"{i}") | |
| y -= 25 | |
| numero += 1 | |
| self.c.setFont("Times-Bold", 15) | |
| self.c.drawString(110, 300, "Disciplina: ") | |
| self.c.setFont("Times-Roman", 15) | |
| self.c.drawString(190, 300, disciplina) | |
| self.c.setFont("Times-Bold", 15) | |
| self.c.drawString(110, 280, "Grupo: ") | |
| self.c.setFont("Times-Roman", 15) | |
| self.c.drawString(165, 280, grupo) | |
| self.c.setFont("Times-Bold", 15) | |
| self.c.drawString(110, 260, "Classe: ") | |
| self.c.setFont("Times-Roman", 15) | |
| self.c.drawString(165, 260, classe) | |
| self.c.setFont("Times-Bold", 15) | |
| self.c.drawString(110, 240, "Turma: ") | |
| self.c.setFont("Times-Roman", 15) | |
| self.c.drawString(165, 240, turma) | |
| self.c.setFont("Times-Bold", 15) | |
| self.c.drawString(110, 220, "Curso: ") | |
| self.c.setFont("Times-Roman", 15) | |
| self.c.drawString(165, 220, curso) | |
| self.c.setFont("Times-Bold", 15) | |
| self.c.drawString(110, 200, "Turno: ") | |
| self.c.setFont("Times-Roman", 15) | |
| self.c.drawString(165, 200, turno) | |
| def agradecimentos(self, prof): | |
| prompt = f""" | |
| Você é um assistente especializado em gerar textos acadêmicos claros e objetivos. | |
| Tarefa: Criar um texto de AGRADECIMENTOS para um trabalho acadêmico. | |
| - O texto deve **randomizar destinatários**: pais, professores, IAs/pesquisadores, outros apoiadores. | |
| - Não pergunte nomes, apenas use expressões genéricas como “nossos pais”, “professores”, “pesquisadores” etc. | |
| Regras obrigatórias: | |
| 1. O texto deve ter aproximadamente 3 linhas. | |
| 2. Entregue APENAS o texto dos agradecimentos, sem títulos, notas ou explicações. | |
| 3. Não use símbolos de Markdown (** , ##, ```), apenas HTML permitido: | |
| - <strong>...</strong> para negrito | |
| - <br/> para quebra de linha | |
| - <br/><br/> para separar parágrafos | |
| 4. Cada parágrafo deve ser curto e respeitar a divisão com <br/><br/> | |
| 5. Mantenha tom respeitoso, formal e acadêmico. | |
| Entrega: | |
| - Texto pronto para inserir no PDF usando ReportLab, com tags HTML respeitadas. | |
| """ | |
| print(f"Criando os Agradecimentos - Página {self.pagina}") | |
| texto = self.API(prompt) | |
| sleep(5) | |
| self.c.showPage() | |
| self.paginar_letra("II") | |
| self.c.setFont("Times-Bold", 17) | |
| self.c.drawCentredString(595/2, 750, "Agradecimentos") | |
| styles = getSampleStyleSheet() | |
| text = f"{texto}" | |
| meust = ParagraphStyle( | |
| "Marius", | |
| parent=styles["Normal"], | |
| fontName="Times-Roman", | |
| fontSize=12, | |
| alignment=4 | |
| ) | |
| frame = Frame(100, 100, 400, 630, showBoundary=0) | |
| p = Paragraph(text, meust) | |
| frame.addFromList([p], self.c) | |
| def dedicatoria(self): | |
| prompt = f""" | |
| Você é um assistente especializado em gerar textos acadêmicos claros e objetivos. | |
| Tarefa: Criar uma **DEDICATÓRIA** curta para um trabalho acadêmico. | |
| - Deve ter aproximadamente 3 a 4 linhas. | |
| - Entregue apenas o texto da dedicatória, sem títulos ou explicações. | |
| - Não use símbolos de Markdown (** , ##, ```), apenas HTML permitido: | |
| - <strong>...</strong> para negrito | |
| - <br/> para quebra de linha | |
| - <br/><br/> para separar parágrafos | |
| - Use tom respeitoso, formal e acadêmico. | |
| Entrega: | |
| - Texto pronto para inserir no PDF usando ReportLab, com tags HTML respeitadas. | |
| """ | |
| print(f"Criando a Dedicatória - Página {self.pagina}") | |
| texto = self.API(prompt) | |
| sleep(5) | |
| self.c.showPage() | |
| self.paginar_letra("III") | |
| self.c.setFont("Times-Bold", 17) | |
| self.c.drawCentredString(595/2, 750, "Dedicatória") | |
| styles = getSampleStyleSheet() | |
| text = f"{texto}" | |
| meust = ParagraphStyle( | |
| "Marius", | |
| parent=styles["Normal"], | |
| fontName="Times-Roman", | |
| fontSize=12, | |
| alignment=4 | |
| ) | |
| frame = Frame(100, 100, 400, 630, showBoundary=0) | |
| p = Paragraph(text, meust) | |
| frame.addFromList([p], self.c) | |
| def epigrafe(self): | |
| prompt = "Manda uma frase famosa e aleatoria, com duplos sentidos, OBS: apenas quero a frase, mais nada escrito, interface totalmente limpa, nao usar simbolos como ** ##, apenas texto puro" | |
| print(f"Criando a Epígrafe - Página {self.pagina}") | |
| texto = self.API(prompt) | |
| sleep(5) | |
| self.c.showPage() | |
| self.paginar_letra("IV") | |
| self.c.setFont("Times-Bold", 17) | |
| self.c.drawCentredString(595/2, 750, "Epígrafe") | |
| styles = getSampleStyleSheet() | |
| text = f'"{texto}"' | |
| meust = ParagraphStyle( | |
| "Marius", | |
| parent=styles["Normal"], | |
| fontName="Times-Italic", | |
| fontSize=12, | |
| alignment=2 | |
| ) | |
| frame = Frame(400, -350, 170, 630, showBoundary=0) | |
| p = Paragraph(text, meust) | |
| frame.addFromList([p], self.c) | |
| def resumo(self): | |
| subtemas_str = ", ".join(self.subtemas) # transforma lista em string legível | |
| prompt = f""" | |
| Faz um resumo acadêmico sobre o tema {self.titulo}. | |
| O resumo deve considerar os seguintes subtemas: {subtemas_str}. | |
| - Entrega apenas o resumo, sem títulos, cabeçalhos, listas ou qualquer outro texto extra. | |
| - Não use símbolos de Markdown como **, ##, ``` ou outros. | |
| - Use texto puro. | |
| - Para separar linhas dentro do parágrafo use <br/>. | |
| - Para separar parágrafos use <br/><br/> (duas quebras de linha). | |
| - O resumo deve ser claro, objetivo e bem estruturado, mencionando de forma geral o que cada subtema vai abordar no trabalho. | |
| """ | |
| print(f"Criando o Resumo - Página {self.pagina}") | |
| texto = self.API(prompt) | |
| sleep(5) | |
| self.c.showPage() | |
| self.paginar_letra("V") | |
| self.c.setFont("Times-Bold", 17) | |
| self.c.drawCentredString(595/2, 750, "Resumo") | |
| styles = getSampleStyleSheet() | |
| text = f"{texto}" | |
| meust = ParagraphStyle( | |
| "Marius", | |
| parent=styles["Normal"], | |
| fontName="Times-Roman", | |
| fontSize=12, | |
| alignment=4 | |
| ) | |
| frame = Frame(100, 100, 400, 630, showBoundary=0) | |
| p = Paragraph(text, meust) | |
| frame.addFromList([p], self.c) | |
| def indice(self): | |
| print(f"Criando Índice - Página {self.pagina}") | |
| self.c.showPage() | |
| self.paginar_letra("VI") | |
| y = 700 | |
| self.c.setFont("Times-Bold", 20) | |
| self.c.drawCentredString(595/2, 750, "Índice") | |
| temas = [] | |
| for i in self.subtemas: | |
| temas.append(i.replace("_", " ")) | |
| x_inicial = 110 | |
| x_limite = 500 | |
| temas.append("Conclusão") | |
| temas.append("Referências Bibliográficas") | |
| for nome in temas: | |
| self.pagina_idc +=1 | |
| self.c.setFont("Times-Roman", 15) | |
| self.c.drawString(x_inicial, y, f"{nome} ") | |
| largura_nome = self.c.stringWidth(nome, "Times-Roman", 15) | |
| x_atual = x_inicial + largura_nome | |
| largura_ponto = self.c.stringWidth(".", "Times-Roman", 15) | |
| while x_atual + largura_ponto < x_limite: | |
| self.c.drawString(x_atual, y, ".") | |
| x_atual += largura_ponto | |
| if nome == "Conclusão": | |
| self.c.drawString(x_limite + 10, y, "I") | |
| elif nome == "Referências Bibliográficas": | |
| self.c.drawString(x_limite + 10, y, "II") | |
| else: | |
| self.c.drawString(x_limite + 10, y, str(self.pagina_idc)) | |
| y -= 25 | |
| def desenvolvimento(self): | |
| sub = self.subtemas | |
| sub.append("Conclusão") | |
| temas = [] | |
| for t in sub: | |
| temas.append(t.replace("_", " ")) | |
| for subtemas in temas: | |
| prompt = f""" | |
| Você é um assistente especializado em produzir DESENVOLVIMENTOS DE TEXTOS ACADÊMICOS claros, objetivos e bem estruturados. | |
| INSTRUÇÕES OBRIGATÓRIAS: | |
| - Tema principal: {self.titulo} | |
| - Subtema a desenvolver: {subtemas} | |
| FORMATO E ESTILO (OBEDIÊNCIA ESTRITA): | |
| 1. A saída deve conter APENAS o texto do desenvolvimento. Não inclua títulos, cabeçalhos, explicações, notas, listas, metadados ou comentários. | |
| 2. NÃO utilize Markdown, símbolos de Markdown ou blocos de código. NÃO PRODUZA MARKDOWN. | |
| 3. É ESTRITAMENTE PROIBIDO usar as seguintes tags ou qualquer variação delas: | |
| <para>, <p>, <div>, <section>, <article>, <img>, <h1> a <h6>, listas ou qualquer tag não listada abaixo. | |
| 4. As ÚNICAS tags HTML permitidas são: | |
| - <br/> para quebra curta de linha dentro de um parágrafo. | |
| - <br/><br/> para separar parágrafos (OBRIGATÓRIO: cada novo parágrafo deve iniciar após exatamente <br/><br/>). | |
| - <strong>...</strong> apenas para destaque de termos essenciais. | |
| 5. Não utilize listas numeradas ou marcadores; escreva apenas em parágrafos contínuos. | |
| 6. Mantenha linguagem objetiva, técnica e adequada ao nível acadêmico, sem tom promocional ou opinativo. | |
| 7. Cada parágrafo deve conter no máximo 3 a 5 frases bem definidas. Evite parágrafos longos ou misturados. | |
| 8. Se o subtema permitir maior aprofundamento, desenvolva de forma completa e detalhada, sem medo de extensão. | |
| - Separe parágrafos com <br/><br/> use mesmo 2, para quebrar a linha duas vezes. | |
| - Dentro de cada parágrafo, use <br/> para quebrar linhas longas quando necessário. | |
| - Não use <p>, <div>, <para> ou Markdown. | |
| - Use <strong> apenas para destacar termos importantes. | |
| CONTEÚDO: | |
| - Apresente uma definição clara e direta do subtema no contexto do tema principal. | |
| - Desenvolva de 2 a 4 ideias centrais fundamentais para a compreensão do subtema. | |
| - Finalize com uma frase conclusiva que sintetize a relevância do subtema dentro do tema principal. | |
| EXEMPLO DE FORMATO (APENAS ILUSTRATIVO — NÃO REPRODUZIR): | |
| Parágrafo 1 com explicação inicial...<br/><br/> | |
| Parágrafo 2 com <strong>conceito importante</strong> desenvolvido...<br/><br/> | |
| Parágrafo final com síntese do subtema. | |
| ENTREGA: | |
| - Responda SOMENTE com o desenvolvimento final. | |
| - Não inclua linhas em branco extras no início ou no fim. | |
| - Use exclusivamente <br/><br/> para separar parágrafos e <strong> apenas quando necessário. | |
| Agora, seguindo rigorosamente TODAS as instruções acima, gere o desenvolvimento solicitado. | |
| """ | |
| print(f"Criando o Subtema {subtemas} - Página {self.pagina + 1}") | |
| texto = self.API(prompt) | |
| print(f"Subtema {subtemas} criado!") | |
| sleep(10) | |
| self.pagina += 1 | |
| self.c.showPage() | |
| if subtemas == "Conclusão": | |
| self.paginar_letra("I") | |
| else: | |
| self.paginar(self.pagina) | |
| self.c.setFont("Times-Bold", 17) | |
| self.c.drawCentredString(595/2, 750, subtemas) | |
| styles = getSampleStyleSheet() | |
| text = f"{texto}" | |
| meust = ParagraphStyle( | |
| "Marius", | |
| parent=styles["Normal"], | |
| fontName="Times-Roman", | |
| fontSize=12, | |
| alignment=4 | |
| ) | |
| frame = Frame(100, 100, 400, 630, showBoundary=0) | |
| p = Paragraph(text, meust) | |
| frame.addFromList([p], self.c) | |
| def ref(self): | |
| prompt = f""" | |
| Você é um assistente que gera REFERÊNCIAS BIBLIOGRÁFICAS em formato padronizado. | |
| TEMA: {self.titulo} | |
| INSTRUÇÕES OBRIGATÓRIAS: | |
| 1. Gere EXATAMENTE 5 referências relacionadas ao tema informado. | |
| 2. Cada referência deve conter EXATAMENTE 3 linhas: | |
| - 1ª linha: Autor(es) e ano. | |
| - 2ª linha: Título da obra/artigo. | |
| - 3ª linha: Link em formato HTML, usando exclusivamente <u>...</u>. | |
| 3. Cada referência deve ser separada da seguinte por exatamente `<br/><br/>`. | |
| 4. Não usar listas, não usar markdown, não usar negrito ou itálico nas referências. | |
| 5. Não adicionar explicações, textos extras ou comentários — apenas as referências no formato exigido. | |
| 6. As referências podem ser fictícias, mas devem parecer verossímeis. | |
| FORMATO EXEMPLO (NÃO reproduzir os dados abaixo): | |
| Autor, Ano | |
| Título da obra | |
| <u>link...</u><br/><br/> | |
| Agora gere as 5 referências conforme o tema. | |
| """ | |
| print(f"Criando o Subtema Referências Bibliográficas - Página {self.pagina + 1}") | |
| texto = self.API(prompt) | |
| print(f" Trabalho finalizado criado!") | |
| #sleep(7) | |
| self.c.showPage() | |
| self.pagina += 1 | |
| self.paginar_letra("II") | |
| self.c.setFont("Times-Bold", 17) | |
| self.c.drawCentredString(595/2, 750, "Referências Bibliográficas") | |
| styles = getSampleStyleSheet() | |
| text = f"{texto}" | |
| meust = ParagraphStyle( | |
| "Marius", | |
| parent=styles["Normal"], | |
| fontName="Times-Roman", | |
| fontSize=12, | |
| alignment=4 | |
| ) | |
| frame = Frame(100, 100, 400, 630, showBoundary=0) | |
| p = Paragraph(text, meust) | |
| frame.addFromList([p], self.c) | |
| def paginar(self, pag): | |
| self.c.drawString(500, 50, str(pag)) | |
| def paginar_letra(self, pag): | |
| self.c.drawString(500, 50, pag) | |
| def API(self, prompt): | |
| while True: | |
| try: | |
| sleep(3) | |
| print("Gerando...") | |
| res = self.oppo.models.generate_content(model="gemma-3-27b-it", contents=prompt) | |
| return self.limpar(res.text) | |
| except Exception as e: | |
| print("erro:", e) | |
| print("Tentando novamente") | |
| def limpar(self, texto: str) -> str: | |
| if not texto: | |
| return "" | |
| # Escapa qualquer coisa perigosa primeiro | |
| texto = escape(texto) | |
| # Reverte apenas as tags PERMITIDAS pelo ReportLab | |
| texto = texto.replace("<br/>", "<br/>") | |
| texto = texto.replace("<br>", "<br/>") | |
| texto = texto.replace("<strong>", "<strong>") | |
| texto = texto.replace("</strong>", "</strong>") | |
| # Normaliza <br> | |
| texto = re.sub(r"<br\s*/?>", "<br/>", texto, flags=re.IGNORECASE) | |
| # Remove excesso de quebras | |
| texto = re.sub(r"(?:<br/>){3,}", "<br/><br/>", texto) | |
| return texto.strip() | |
| def save(self): | |
| self.c.save() | |
| def criar_trabalho(logo, capaImage, titulo, subtitulo, instituto, integrantes, prof, disciplina, grupo, classe, turma, curso, turno, n_paginas): | |
| txt = [t[0] for t in integrantes] | |
| txt1 = [] | |
| for i in txt: | |
| txt1.append(i) | |
| nn = Model(f"{titulo}.pdf", titulo, n_paginas) | |
| nn.capa(logo, capaImage, titulo, subtitulo, instituto) | |
| nn.integrantes(txt, disciplina, grupo, classe, turma, curso, turno) | |
| nn.agradecimentos(prof) | |
| nn.dedicatoria() | |
| nn.epigrafe() | |
| nn.resumo() | |
| nn.indice() | |
| nn.desenvolvimento() | |
| nn.ref() | |
| nn.save() | |
| return f"{titulo}.pdf" | |
| logo = "logo.png" | |
| titulo = "Alcoolismo em Angola" | |
| inst = "Complexo Escolar Politécnico Girassol" | |
| professor = "Hélder Vunge" | |
| capa = "images.png" | |
| sub = "Alto nível de alcoolismo em Angola" | |
| #criar_trabalho(logo, capa, titulo, sub, inst) | |
| import numpy as np | |
| import gradio as gr | |
| with gr.Blocks(theme="NoCrypt/miku") as demo: | |
| gr.Markdown("# PaperFlow - As tuas mãos invisíveis") | |
| gr.Textbox( | |
| label="ISSO PODE DEMORAR ~5MIN, MINHA CPU É RUINZINHA KKK", | |
| value="DESENVOLVIDO PELA STARTUP CLOSESOURCE (CS)", | |
| interactive=False | |
| ) | |
| saida_do_pdf = gr.File(label="BAIXAR PDF") | |
| with gr.Row(): | |
| logo = gr.Image(label="LOGO DO INSTITUTO OU ESCOLA", type="filepath") | |
| capaImage = gr.Image(label="IMAGEM DA CAPA", type="filepath") | |
| with gr.Row(): | |
| titulo = gr.Textbox(label="TÍTULO OU TEMA") | |
| subtitulo = gr.Textbox(label="SUBTÍTULO") | |
| instituto = gr.Textbox(label="INSTITUTO") | |
| with gr.Row(): | |
| disciplina = gr.Textbox(label="DISCIPLINA") | |
| grupo = gr.Textbox(label="GRUPO") | |
| classe = gr.Textbox(label="CLASSE") | |
| turma = gr.Textbox(label="TURMA") | |
| curso = gr.Textbox(label="CURSO") | |
| turno = gr.Textbox(label="TURNO") | |
| with gr.Row(): | |
| professor = gr.Textbox(label="NOME DO PROFESSOR") | |
| n_paginas = gr.Textbox(label="NÚMERO DE PÁGINAS (CONTEÚDO)") | |
| integrantes = gr.DataFrame( | |
| headers = ["Nome dos Integrantes"], | |
| row_count=15, | |
| col_count=1, | |
| type="array", | |
| interactive=True, | |
| wrap=True | |
| ) | |
| botao_criar = gr.Button("CRIAR TRABALHO") | |
| botao_criar.click(fn=criar_trabalho, inputs=[logo, capaImage, titulo, subtitulo, instituto, integrantes, professor, disciplina, grupo, classe, turma, curso, turno, n_paginas], outputs=[saida_do_pdf]) | |
| demo.launch(share=True) | |