File size: 5,819 Bytes
87a9d43
9edfd4c
 
 
 
 
 
 
52b8580
 
 
 
 
 
8ecc78e
 
 
 
52b8580
 
8ecc78e
 
 
 
52b8580
8ecc78e
 
 
52b8580
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9edfd4c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa68783
 
 
 
95064ac
fa68783
87a9d43
 
9edfd4c
 
 
 
 
 
87a9d43
 
9edfd4c
 
 
 
 
87a9d43
 
9edfd4c
8907d55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d3d4227
8907d55
 
 
 
9edfd4c
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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()