import logging import re import base64 import unicodedata import streamlit as st from modules.config import client_anthropic # --------------- Prompt Enhancer (shared) --------------- _ENHANCER_SYSTEM = ( "Voce e um especialista em engenharia de prompts. " "Sua tarefa e aprimorar o prompt do usuario para obter a melhor resposta possivel " "de um assistente de IA chamado J.A.R.V.I.S. (assistente de PM para squad de Risco e Seguranca do banco Cora).\n\n" "CONTEXTO IMPORTANTE: O J.A.R.V.I.S. ja possui templates internos para PRDs, Tech Specs, " "apresentacoes e outros documentos. Ele tambem carrega contexto automaticamente (OKRs, roadmap, " "metricas, dados do squad). Voce NAO precisa sugerir templates, formatos ou estruturas — " "foque APENAS em melhorar a clareza, especificidade e intencao do pedido do usuario.\n\n" "Regras:\n" "1. Mantenha a INTENCAO original do usuario intacta.\n" "2. Adicione clareza, especificidade e detalhes relevantes (tom, audiencia, foco, exclusoes).\n" "3. NAO sugira templates, formatos, estruturas de documento ou modelos — o sistema ja tem.\n" "4. NAO adicione instrucoes tecnicas sobre como o modelo deve responder (ex: 'use markdown').\n" "5. Se o prompt for trivial (saudacao, agradecimento, pergunta simples de 1 linha), " "retorne-o como esta — nao force complexidade.\n" "6. Responda APENAS com o prompt aprimorado, sem explicacoes ou meta-comentarios.\n" "7. Mantenha o idioma original (portugues brasileiro).\n" "8. Nao adicione emojis a menos que o original tenha." ) _TRIVIAL_RE = re.compile( r"^(oi|ola|hey|obrigad[oa]|valeu|ok|sim|nao|bom dia|boa tarde|boa noite|beleza|blz|fala|e ai)[!?.]*$", re.IGNORECASE, ) def aprimorar_prompt(texto: str) -> str: """Envia o prompt do usuario ao Claude Opus para aprimoramento.""" if _TRIVIAL_RE.match(texto.strip()): return texto try: resp = client_anthropic.messages.create( model="claude-opus-4-6", max_tokens=2048, system=_ENHANCER_SYSTEM, messages=[{"role": "user", "content": texto}], ) aprimorado = resp.content[0].text.strip() return aprimorado if aprimorado else texto except Exception as e: logging.warning(f"[Enhancer] Falha ao aprimorar prompt: {e}") return texto def sanitizar(nome): n = unicodedata.normalize("NFKD", nome).encode("ascii", "ignore").decode("utf-8") return re.sub(r"[^a-zA-Z0-9._-]", "_", n) def extrair_texto_arquivo(uploaded_file) -> str: nome = uploaded_file.name.lower() texto = "" if nome.endswith((".png", ".jpg", ".jpeg")): dados = base64.standard_b64encode(uploaded_file.read()).decode("utf-8") media_type = "image/png" if nome.endswith(".png") else "image/jpeg" resp = client_anthropic.messages.create( model=st.session_state.modelo, max_tokens=2048, messages=[{"role": "user", "content": [ {"type": "image", "source": {"type": "base64", "media_type": media_type, "data": dados}}, {"type": "text", "text": "Extraia e descreva todo o conteudo desta imagem detalhadamente."} ]}] ) texto = resp.content[0].text elif nome.endswith(".pdf"): try: import PyPDF2 reader = PyPDF2.PdfReader(uploaded_file) pages_text = [] for i, page in enumerate(reader.pages, 1): page_content = (page.extract_text() or "").strip() if page_content: pages_text.append(f"--- PAGINA {i} ---\n{page_content}") texto = "\n\n".join(pages_text) except Exception as e: logging.warning(f"[Utils] Falha ao extrair PDF '{nome}': {e}") texto = "" elif nome.endswith(".docx"): try: import docx doc = docx.Document(uploaded_file) texto = "\n".join(p.text for p in doc.paragraphs if p.text.strip()) except Exception as e: logging.warning(f"[Utils] Falha ao extrair DOCX '{nome}': {e}") texto = "" elif nome.endswith(".csv"): try: import pandas as pd texto = pd.read_csv(uploaded_file).to_markdown() except Exception as e: logging.warning(f"[Utils] Falha ao ler CSV '{nome}' como markdown: {e}") texto = uploaded_file.read().decode("utf-8", errors="ignore") elif nome.endswith(".pptx"): try: from pptx import Presentation prs = Presentation(uploaded_file) slides_text = [] for i, slide in enumerate(prs.slides, 1): parts = [] for shape in slide.shapes: if shape.has_text_frame: for para in shape.text_frame.paragraphs: t = para.text.strip() if t: parts.append(t) if shape.has_table: table = shape.table for row in table.rows: row_text = " | ".join(cell.text.strip() for cell in row.cells) if row_text.strip(" |"): parts.append(row_text) slides_text.append(f"--- SLIDE {i} ---\n" + ("\n".join(parts) if parts else "[Slide sem texto extraivel — pode conter imagem, grafico ou SmartArt]")) texto = "\n\n".join(slides_text) except Exception as e: logging.warning(f"[Utils] Falha ao extrair PPTX '{nome}': {e}") texto = "" elif nome.endswith(".txt"): texto = uploaded_file.read().decode("utf-8", errors="ignore") return texto.strip()