from fastapi import HTTPException from sqlalchemy.orm import Session from app.services.llm_service import LLMService from app.services.tool_registry import ToolRegistry class OrquestradorService: LOW_VALUE_RESPONSES = { "certo.", "certo", "ok.", "ok", "entendi.", "entendi", "claro.", "claro", } def __init__(self, db: Session): """Inicializa servicos de LLM e registro de tools para a sessao atual.""" self.llm = LLMService() self.registry = ToolRegistry(db) async def handle_message(self, message: str) -> str: """Processa mensagem, executa tool quando necessario e retorna resposta final.""" tools = self.registry.get_tools() llm_result = await self.llm.generate_response( message=self._build_router_prompt(message), tools=tools, ) if not llm_result["tool_call"] and self._is_operational_query(message): llm_result = await self.llm.generate_response( message=self._build_force_tool_prompt(message), tools=tools, ) if llm_result["tool_call"]: tool_name = llm_result["tool_call"]["name"] arguments = llm_result["tool_call"]["arguments"] try: tool_result = await self.registry.execute(tool_name, arguments) except HTTPException as exc: return self._http_exception_detail(exc) final_response = await self.llm.generate_response( message=self._build_result_prompt( user_message=message, tool_name=tool_name, tool_result=tool_result, ), tools=[], ) text = (final_response.get("response") or "").strip() if self._is_low_value_response(text): return self._fallback_format_tool_result(tool_name, tool_result) return text or self._fallback_format_tool_result(tool_name, tool_result) text = (llm_result.get("response") or "").strip() if self._is_low_value_response(text): return "Entendi. Pode me dar mais detalhes para eu consultar corretamente?" return text def _is_low_value_response(self, text: str) -> bool: return text.strip().lower() in self.LOW_VALUE_RESPONSES def _is_operational_query(self, message: str) -> bool: text = message.lower() keywords = ( "estoque", "carro", "carros", "suv", "sedan", "hatch", "pickup", "financi", "cpf", "troca", "revis", "placa", "cancelar pedido", "pedido", ) return any(k in text for k in keywords) def _build_router_prompt(self, user_message: str) -> str: return ( "Voce e um assistente de concessionaria. " "Sempre que a solicitacao depender de dados operacionais (estoque, validacao de cliente, " "avaliacao de troca, agendamento de revisao ou cancelamento de pedido), use a tool correta. " "Se faltar parametro obrigatorio para a tool, responda em texto pedindo apenas o que falta.\n\n" f"Mensagem do usuario: {user_message}" ) def _build_force_tool_prompt(self, user_message: str) -> str: return ( "Reavalie a mensagem e priorize chamar tool se houver intencao operacional. " "Use texto apenas quando faltar dado obrigatorio.\n\n" f"Mensagem do usuario: {user_message}" ) def _build_result_prompt(self, user_message: str, tool_name: str, tool_result) -> str: return ( "Responda ao usuario de forma objetiva usando o resultado da tool abaixo. " "Nao invente dados. Se a lista vier vazia, diga explicitamente que nao encontrou resultados.\n\n" f"Pergunta original: {user_message}\n" f"Tool executada: {tool_name}\n" f"Resultado da tool: {tool_result}" ) def _http_exception_detail(self, exc: HTTPException) -> str: detail = exc.detail if isinstance(detail, str): return detail return "Nao foi possivel concluir a operacao solicitada." def _fallback_format_tool_result(self, tool_name: str, tool_result) -> str: if tool_name == "consultar_estoque": if not tool_result: return "Nao encontrei nenhum veiculo com os criterios informados." return f"Encontrei {len(tool_result)} veiculo(s) com os criterios informados." if tool_name == "cancelar_pedido" and isinstance(tool_result, dict): numero = tool_result.get("numero_pedido", "N/A") status = tool_result.get("status", "N/A") return f"Pedido {numero} atualizado com status {status}." if tool_name == "validar_cliente_venda" and isinstance(tool_result, dict): aprovado = tool_result.get("aprovado") return "Cliente aprovado para financiamento." if aprovado else "Cliente nao aprovado para financiamento." return "Operacao concluida com sucesso."