# aduc_framework/engineers/prompt_engine.py # # Copyright (C) August 4, 2025 Carlos Rodrigues dos Santos # # Versão 2.0.0 (Context-Aware Prompt Translator) # # O PromptEngine atua como o tradutor entre a lógica de tarefa agnóstica # do Composer e o formato de prompt específico exigido por um LLM. # Esta versão é consciente do contexto, sabendo diferenciar entre # prompts que requerem contexto visual (imagens) e os que são apenas texto. import logging from pathlib import Path from typing import Dict logger = logging.getLogger(__name__) class PromptEngine: """ O PromptEngine traduz prompts genéricos para o formato específico do modelo de linguagem alvo. Ele seleciona o template correto com base na presença de imagens na requisição. """ def __init__(self, model_map_name: str): """ Inicializa o PromptEngine carregando os templates específicos do modelo. Args: model_map_name (str): O nome do diretório do mapa do modelo em 'aduc_framework/prompts/model_maps/'. """ self.model_map_name = model_map_name # Carrega os dois templates essenciais: um para prompts com imagens # e outro para prompts que contêm apenas texto. self.template_with_image = self._load_model_template(model_map_name, "image_template.txt") self.template_text_only = self._load_model_template(model_map_name, "text_template.txt") logger.info(f"PromptEngine inicializado com o mapa de modelo '{model_map_name}'.") def _load_model_template(self, map_name: str, template_file: str) -> str: """ Carrega um arquivo de template de um mapa de modelo específico. """ map_path = Path(__file__).resolve().parent.parent / "prompts" / "model_maps" / map_name / template_file if not map_path.is_file(): # Este é um erro crítico de configuração, então levantamos uma exceção clara. raise FileNotFoundError(f"Template de modelo '{template_file}' não encontrado no mapa '{map_name}' em: {map_path}") with open(map_path, 'r', encoding='utf-8') as f: return f.read() def translate(self, generic_prompt_content: str, has_image: bool) -> str: """ Envolve o conteúdo do prompt genérico com o template específico do modelo, escolhendo o template correto com base na presença de uma imagem. Args: generic_prompt_content (str): O conteúdo do prompt agnóstico gerado pelo Composer. has_image (bool): Sinaliza se a tarefa atual inclui um contexto visual. Returns: str: O prompt final, formatado e pronto para ser enviado ao LLM. """ logger.debug(f"--- PROMPT ENGINE: INICIANDO TRADUÇÃO (Imagem: {has_image}) ---") logger.debug(f"PROMPT GENÉRICO RECEBIDO:\n---\n{generic_prompt_content[:500]}...\n---") # Seleciona o "mapa" correto com base no contexto if has_image: template = self.template_with_image logger.debug("Usando o template de modelo com imagem.") else: template = self.template_text_only logger.debug("Usando o template de modelo apenas de texto.") try: # Insere o conteúdo genérico dentro do template específico do modelo final_prompt = template.format(generic_prompt_content=generic_prompt_content) logger.debug(f"PROMPT FINAL (TRADUZIDO) GERADO:\n---\n{final_prompt}\n---") logger.debug("--- PROMPT ENGINE: TRADUÇÃO CONCLUÍDA ---") return final_prompt except KeyError as e: logger.error(f"PROMPT ENGINE: Erro de chave durante a tradução! Chave não encontrada: {e}", exc_info=True) logger.error("Verifique se o template do modelo contém apenas o placeholder '{generic_prompt_content}'.") raise e # --- Instância Singleton --- # A seleção do mapa de modelo é feita aqui. No futuro, isso poderia ser # lido do arquivo de configuração `config.yaml` para maior flexibilidade. prompt_engine_singleton = PromptEngine(model_map_name="llama_3_2_vision")