Team Ai
Apppublic

DeveloperSSEV/assistente-utfpr

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
streamlit_app.py194 linesDownload Raw Back to root
1import os2from dotenv import load_dotenv3 4import streamlit as st5from google import genai6from google.genai.types import GenerateContentConfig7from pypdf import PdfReader  # para ler PDFs. [web:466]8 9 10# -------------------------------------------------------11# Carregar variáveis de ambiente12# -------------------------------------------------------13load_dotenv()14GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")15 16if not GEMINI_API_KEY:17    raise ValueError("Defina a variável de ambiente GEMINI_API_KEY (no .env local ou em Secrets do Space).")18 19 20# -------------------------------------------------------21# Configurar cliente Gemini (SDK novo)22# -------------------------------------------------------23client = genai.Client(api_key=GEMINI_API_KEY)24MODEL_ID = "gemini-2.5-flash"  # modelo rápido, adequado para chat. [web:280]25 26 27# -------------------------------------------------------28# Função para carregar texto dos PDFs29# -------------------------------------------------------30def carregar_pdfs_texto(pasta: str = "documents") -> str:31    """32    Lê todos os PDFs da pasta indicada e concatena o texto.33    Retorna uma string com o conteúdo de todos os documentos.34    """35    textos = []36 37    if not os.path.isdir(pasta):38        return ""39 40    for nome in os.listdir(pasta):41        if not nome.lower().endswith(".pdf"):42            continue43 44        caminho = os.path.join(pasta, nome)45        try:46            reader = PdfReader(caminho)47            partes_pdf = []48            for page in reader.pages:49                texto_pag = page.extract_text() or ""50                partes_pdf.append(texto_pag)51            texto_pdf = "\n".join(partes_pdf)52 53            textos.append(f"\n\n=== INÍCIO DO DOCUMENTO: {nome} ===\n{texto_pdf}")54        except Exception as e:55            textos.append(f"\n\n[ERRO AO LER {nome}: {e}]")56 57    return "\n".join(textos)58 59 60# Carrega o texto dos PDFs uma vez, na inicialização do app61TEXTOS_PDFS = carregar_pdfs_texto("documents")62 63 64# -------------------------------------------------------65# System prompt (instruções do assistente)66# -------------------------------------------------------67SYSTEM_PROMPT = """68Você é um assistente especializado em pós-graduação stricto sensu da UTFPR.69 70INSTRUÇÕES GERAIS:71- Responda sempre em português do Brasil, de forma clara, objetiva e acolhedora.72- Estruture as respostas com seções, listas numeradas e bullets quando isso ajudar na compreensão.73- Foque em orientar estudantes e candidatos sobre mestrado e doutorado (processos seletivos, matrícula, bolsas, prazos, créditos, qualificação, defesa, vida acadêmica).74 75CONHECIMENTO E FONTES:76- Use seu conhecimento geral sobre pós-graduação no Brasil (CAPES, CNPq, práticas comuns em universidades federais) quando a pergunta não citar regras específicas.77- Quando a pergunta for específica da UTFPR, explique o que é mais comum e, se houver variação entre campi ou programas, deixe isso explícito.78- Sempre que falar de regras, prazos ou documentos oficiais, recomende confirmar em:79  - editais do programa,80  - regulamentos internos,81  - secretaria ou coordenação da pós-graduação.82 83ESTILO DE RESPOSTA:84- Evite respostas muito curtas; traga contexto suficiente para que um aluno iniciante entenda o assunto.85- Evite jargões sem explicação. Quando usar termos técnicos (por exemplo, “conceito CAPES” ou “créditos”), explique em linguagem simples.86- Se a pergunta estiver confusa ou incompleta, peça esclarecimentos de forma educada antes de assumir algo importante.87 88LIMITAÇÕES:89- Não invente nomes de pessoas, documentos oficiais, números de vaga ou prazos específicos. Em vez disso, diga que esses detalhes podem variar e devem ser consultados no edital ou site oficial.90- Se não tiver informação suficiente para responder com segurança, diga claramente o que não é possível afirmar e indique caminhos para o aluno buscar a confirmação.91"""92 93 94# -------------------------------------------------------95# Configuração de geração (respostas completas)96# -------------------------------------------------------97GENERATION_CONFIG = GenerateContentConfig(98    max_output_tokens=1500,   # mais espaço para respostas longas. [web:470][web:476]99    temperature=0.6,100    top_p=0.9,101    top_k=40,102)103 104 105# -------------------------------------------------------106# Função para chamar o modelo usando PDFs + histórico107# -------------------------------------------------------108def chamar_gemini(mensagens: list[dict]) -> str:109    """110    mensagens: lista de dicionários:111      {"role": "user" ou "assistant", "content": "texto"}112    Retorna o texto da resposta do modelo.113    """114 115    partes = [SYSTEM_PROMPT.strip()]116 117    # Se houver PDFs carregados, inclui um bloco com esses textos118    if TEXTOS_PDFS.strip():119        partes.append(120            "\n\nA seguir estão trechos de documentos oficiais (regulamentos, editais, normas) "121            "relacionados à pós-graduação da UTFPR. Use esses textos como referência principal "122            "quando a pergunta envolver regras, prazos, procedimentos formais ou exigências.\n"123        )124        partes.append(TEXTOS_PDFS)125 126    partes.append("\n\nHistórico da conversa:")127    for msg in mensagens:128        prefixo = "Usuário" if msg["role"] == "user" else "Assistente"129        partes.append(f"{prefixo}: {msg['content']}")130 131    partes.append(132        "\nResponda agora como o assistente, em português do Brasil, "133        "com uma resposta completa e contínua, sem cortar no meio, "134        "citando o que for relevante dos documentos quando necessário."135    )136 137    prompt = "\n".join(partes)138 139    response = client.models.generate_content(140        model=MODEL_ID,141        contents=prompt,   # string única com tudo (instruções, PDFs, histórico). [web:280][web:408]142        config=GENERATION_CONFIG,143    )144 145    return response.text146 147 148# -------------------------------------------------------149# Interface Streamlit150# -------------------------------------------------------151st.set_page_config(page_title="Assistente de Pós-graduação UTFPR", page_icon="🎓")152st.title("Assistente de Pós-graduação UTFPR 🎓")153 154st.write(155    "Faça perguntas sobre mestrado e doutorado na UTFPR "156    "(processos seletivos, bolsas, créditos, prazos, regulamentos, defesas etc.)."157)158 159# Mostrar aviso se nenhum PDF foi encontrado160if not TEXTOS_PDFS.strip():161    st.warning(162        "Nenhum PDF foi encontrado na pasta 'documents'. "163        "Para usar documentos oficiais, envie os PDFs para o Space em 'documents/'."164    )165 166# Histórico na sessão167if "messages" not in st.session_state:168    st.session_state.messages = []169 170# Mostrar histórico no chat171for msg in st.session_state.messages:172    with st.chat_message("user" if msg["role"] == "user" else "assistant"):173        st.markdown(msg["content"])174 175# Entrada do usuário176pergunta = st.chat_input("Digite sua pergunta sobre pós-graduação...")177 178if pergunta:179    # Adiciona pergunta ao histórico180    st.session_state.messages.append({"role": "user", "content": pergunta})181 182    # Mostra pergunta183    with st.chat_message("user"):184        st.markdown(pergunta)185 186    # Gera resposta187    with st.chat_message("assistant"):188        with st.spinner("Pensando..."):189            resposta = chamar_gemini(st.session_state.messages)190            st.markdown(resposta)191 192    # Guarda resposta no histórico193    st.session_state.messages.append({"role": "assistant", "content": resposta})194