File size: 5,263 Bytes
cc0607e
 
 
 
5058d24
cc0607e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5058d24
cc0607e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5058d24
 
 
 
 
 
cc0607e
5058d24
cc0607e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5058d24
 
 
 
 
 
 
cc0607e
5058d24
 
cc0607e
5058d24
cc0607e
 
 
 
 
 
 
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# utils/apis/gemini.py
import os
import pathlib

from typing import Optional, Union, List, Dict, Any
from dotenv import load_dotenv
from google import genai
from google.genai import types

from utils.prompts import icf_gemini_prompt

load_dotenv()

# Chave da API e ID do Modelo obtidos do ambiente
GEMINI_API_KEY = os.getenv('GEMINI_API_KEY')
if not GEMINI_API_KEY:
    raise ValueError("A variável de ambiente 'GEMINI_API_KEY' não foi definida.")

MODEL_ID = os.getenv('MODEL_ID', 'gemini-2.5-flash')
# --- CAMINHOS E ARQUIVOS DE CONTEXTO ---

# Define o caminho para o prompt do sistema e o PDF de contexto usando pathlib para compatibilidade de SO
BASE_DIR = pathlib.Path(__file__).parent.parent.parent
PDF_CONTEXT_PATH = BASE_DIR / "CIF" / "ListaCIF.pdf"
SYSTEM_PROMPT_PATH = BASE_DIR / "utils" / "prompts.py"

def _load_sys_instruction(caminho: pathlib.Path) -> str:
    """Carrega a string do prompt do sistema a partir de um arquivo Python."""
    try:        
        return icf_gemini_prompt
    except (ImportError, FileNotFoundError):
        print(f"Aviso: Não foi possível encontrar ou importar o prompt do sistema de '{caminho}'. Usando um prompt padrão.")
        return "Você é um especialista na Classificação Internacional de Funcionalidade (CIF). Classifique o texto fornecido de acordo com a CIF e forneça uma análise detalhada."

def _create_file_part(file_path_str: str) -> types.Part:
    """
    Valida, lê e cria um objeto Part a partir de um caminho de arquivo.

    Esta função verifica se o arquivo existe e se sua extensão (.txt ou .pdf) é
    suportada. Em caso afirmativo, lê os bytes do arquivo e retorna um objeto
    `types.Part` com o MIME type correto.

    Args:
        file_path_str: O caminho para o arquivo, recebido como string.

    Returns:
        Um objeto `types.Part` pronto para ser enviado à API Gemini.

    Raises:
        FileNotFoundError: Se o arquivo não for encontrado no caminho especificado.
        ValueError: Se a extensão do arquivo não for suportada.
    """
    input_file_path = pathlib.Path(file_path_str)

    if not input_file_path.is_file():
        raise FileNotFoundError(f"O arquivo de entrada do usuário não foi encontrado: {input_file_path}")

    file_extension = input_file_path.suffix.lower()
    
    if file_extension == '.pdf':
        mime_type = 'application/pdf'
    elif file_extension == '.txt':
        mime_type = 'text/plain'
    else:
        raise ValueError(
            f"Tipo de arquivo '{file_extension}' não suportado. "
            "Por favor, envie um arquivo .txt ou .pdf."
        )
    
    return types.Part.from_bytes(
        data=input_file_path.read_bytes(),
        mime_type=mime_type
    )

def api_generate(user_input: Dict[str, Any]) -> str:
    """
    Gera uma análise baseada na CIF a partir de um texto ou arquivo de entrada.

    Utiliza um PDF da CIF como contexto fixo e combina com a entrada do usuário
    (seja um texto direto ou o conteúdo de um arquivo) para gerar uma resposta
    usando a API do Gemini.

    Args:
        input_text: Uma string contendo o texto a ser analisado.
        input_file: O caminho para um arquivo de texto (.txt) cujo conteúdo
                    será analisado.

    Returns:
        A string com a análise gerada pelo modelo.

    Raises:
        ValueError: Se ambos `input_text` e `input_file` forem fornecidos, ou se
                    nenhum dos dois for fornecido.
        FileNotFoundError: Se o arquivo `input_file` ou o PDF de contexto
                           não forem encontrados.
    """
    input_type = user_input.get("type")
    content = user_input.get("content")

    # 1. Validação da Entrada
    if not input_type or not content:
        raise ValueError("Dicionário 'user_input' inválido. Faltando 'type' ou 'content'.")

    # 2. Preparação do Contexto
    if not PDF_CONTEXT_PATH.is_file():
        raise FileNotFoundError(f"Arquivo de contexto PDF não encontrado em: {PDF_CONTEXT_PATH}")

    client = genai.Client(api_key=GEMINI_API_KEY)

    system_instruction = _load_sys_instruction(SYSTEM_PROMPT_PATH)

    llm_config = types.GenerateContentConfig(
        thinking_config = types.ThinkingConfig(
            thinking_budget=-1,
            ),
        response_mime_type='text/plain',
        seed=1,
        system_instruction=[
            types.Part.from_text(text=system_instruction),
        ],
    )

    user_contents = [
        types.Part.from_bytes(
            data=PDF_CONTEXT_PATH.read_bytes(),
            mime_type='application/pdf'
        )
    ]

    # --- Tratamento type & content ---
    if input_type == "text":
        print(f"Processando via texto: \"{str(content)[:100]}...\"")
        user_contents.append(types.Part.from_text(text=str(content)))
    elif input_type == "file":
        print(f"Processando via arquivo: {content}")
        file_part = _create_file_part(str(content))
        user_contents.append(file_part)
    else:
        raise ValueError(f"Tipo de entrada desconhecido: '{input_type}'")
    
    # 3. Chamada à API Gemini    
    response = client.models.generate_content(
        model=MODEL_ID,
        contents=user_contents,
        config=llm_config
    )
    
    return response.text