From 28d7daccb2f437f6b6ddbdff52a69ede56643373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Hugo=20Belorio=20Sim=C3=A3o?= Date: Thu, 26 Feb 2026 18:25:44 -0300 Subject: [PATCH] feat: ampliando parametros de consulta de estoque e seed de tools --- TEST_CASES.md | 42 +++++++++++++++++ app/api/schemas.py | 6 ++- app/db/tool_seed.py | 72 ++++++++++++++++++++++------- app/repositories/tool_repository.py | 11 +++++ 4 files changed, 112 insertions(+), 19 deletions(-) diff --git a/TEST_CASES.md b/TEST_CASES.md index 69b38a4..7da9f37 100644 --- a/TEST_CASES.md +++ b/TEST_CASES.md @@ -51,6 +51,36 @@ curl -X POST http://localhost:8000/chat \ --- +### 2.1. Consultar Carro Mais Barato + +```bash +curl -X POST http://localhost:8000/chat \ + -H "Content-Type: application/json" \ + -d '{ + "message": "Qual e o carro mais barato que voces tem?", + "user_id": "user-123" + }' +``` + +**Esperado**: Modelo chama `consultar_estoque` com `ordenar_preco=asc` e `limite=1` + +--- + +### 2.2. Consultar Carro Mais Caro + +```bash +curl -X POST http://localhost:8000/chat \ + -H "Content-Type: application/json" \ + -d '{ + "message": "Qual e o carro mais caro que voces tem?", + "user_id": "user-123" + }' +``` + +**Esperado**: Modelo chama `consultar_estoque` com `ordenar_preco=desc` e `limite=1` + +--- + ### 3. Validar Cliente Venda ```bash @@ -147,6 +177,18 @@ curl -X POST http://localhost:8000/mock/consultar-estoque \ -d '{"preco_max": 50000}' ``` +```bash +curl -X POST http://localhost:8000/mock/consultar-estoque \ + -H "Content-Type: application/json" \ + -d '{"ordenar_preco": "asc", "limite": 1}' +``` + +```bash +curl -X POST http://localhost:8000/mock/consultar-estoque \ + -H "Content-Type: application/json" \ + -d '{"ordenar_preco": "desc", "limite": 1}' +``` + ### Ver resposta do Vertex AI Adicione console.log nos handlers para ver o que o Vertex retorna. diff --git a/app/api/schemas.py b/app/api/schemas.py index 05ef34d..f766155 100644 --- a/app/api/schemas.py +++ b/app/api/schemas.py @@ -1,5 +1,5 @@ from pydantic import BaseModel -from typing import Dict, Any, Optional +from typing import Dict, Any, Optional, Literal class ChatRequest(BaseModel): message: str @@ -26,8 +26,10 @@ class ToolResponse(BaseModel): class ConsultarEstoqueRequest(BaseModel): - preco_max: float + preco_max: Optional[float] = None categoria: Optional[str] = None + ordenar_preco: Optional[Literal["asc", "desc"]] = None + limite: Optional[int] = None class ValidarClienteVendaRequest(BaseModel): diff --git a/app/db/tool_seed.py b/app/db/tool_seed.py index 5ea20de..066d6ea 100644 --- a/app/db/tool_seed.py +++ b/app/db/tool_seed.py @@ -6,35 +6,53 @@ def get_tools_definitions(): return [ { "name": "consultar_estoque", - "description": "Use esta ferramenta para consultar veículos disponíveis no estoque até um preço máximo informado pelo cliente, opcionalmente filtrando por categoria (Hatch, Sedan, SUV, etc.). Ideal quando o cliente quer saber quais carros cabem no orçamento ou comparar opções dentro de uma faixa de preço.", + "description": ( + "Use esta ferramenta para consultar veiculos disponiveis no estoque. " + "Voce pode filtrar por preco maximo e categoria, e tambem ordenar por " + "preco para descobrir o carro mais barato (asc + limite=1) ou mais " + "caro (desc + limite=1)." + ), "parameters": { "type": "object", "properties": { "preco_max": { "type": "number", - "description": "Preço máximo do veículo em reais (BRL)." + "description": "Preco maximo do veiculo em reais (BRL). Opcional.", }, "categoria": { "type": "string", - "description": "Categoria do veículo, por exemplo: Hatch, Sedan, SUV. Opcional." + "description": "Categoria do veiculo, por exemplo: Hatch, Sedan, SUV. Opcional.", + }, + "ordenar_preco": { + "type": "string", + "description": "Ordenacao do preco. Use 'asc' para mais barato e 'desc' para mais caro.", + }, + "limite": { + "type": "integer", + "description": "Quantidade maxima de veiculos retornados.", }, }, - "required": ["preco_max"], + "required": [], }, }, { "name": "validar_cliente_venda", - "description": "Use esta ferramenta quando precisar avaliar se o cliente pode financiar um veículo específico. Ela recebe o CPF e o valor do veículo, consulta um score simulado e retorna se o cliente está aprovado ou reprovado para a compra, juntamente com o score e um limite de crédito estimado.", + "description": ( + "Use esta ferramenta quando precisar avaliar se o cliente pode financiar " + "um veiculo especifico. Ela recebe o CPF e o valor do veiculo, consulta " + "um score simulado e retorna se o cliente esta aprovado ou reprovado " + "para a compra, juntamente com o score e um limite de credito estimado." + ), "parameters": { "type": "object", "properties": { "cpf": { "type": "string", - "description": "CPF do cliente, com ou sem formatação (apenas dígitos também é aceito)." + "description": "CPF do cliente, com ou sem formatacao (apenas digitos tambem e aceito).", }, "valor_veiculo": { "type": "number", - "description": "Valor do veículo em reais (BRL) que o cliente deseja comprar." + "description": "Valor do veiculo em reais (BRL) que o cliente deseja comprar.", }, }, "required": ["cpf", "valor_veiculo"], @@ -42,21 +60,26 @@ def get_tools_definitions(): }, { "name": "avaliar_veiculo_troca", - "description": "Use esta ferramenta quando o cliente quiser saber quanto o carro dele vale como entrada em uma negociação. Ela recebe modelo, ano e quilometragem do veículo atual e devolve um valor estimado de avaliação para troca, já considerando depreciação por ano e quilometragem.", + "description": ( + "Use esta ferramenta quando o cliente quiser saber quanto o carro dele " + "vale como entrada em uma negociacao. Ela recebe modelo, ano e " + "quilometragem do veiculo atual e devolve um valor estimado de avaliacao " + "para troca, ja considerando depreciacao por ano e quilometragem." + ), "parameters": { "type": "object", "properties": { "modelo": { "type": "string", - "description": "Modelo do veículo que o cliente deseja oferecer na troca (por exemplo, 'Toyota Corolla')." + "description": "Modelo do veiculo que o cliente deseja oferecer na troca (por exemplo, 'Toyota Corolla').", }, "ano": { "type": "integer", - "description": "Ano de fabricação do veículo do cliente." + "description": "Ano de fabricacao do veiculo do cliente.", }, "km": { "type": "integer", - "description": "Quilometragem atual do veículo do cliente." + "description": "Quilometragem atual do veiculo do cliente.", }, }, "required": ["modelo", "ano", "km"], @@ -64,17 +87,22 @@ def get_tools_definitions(): }, { "name": "agendar_revisao", - "description": "Use esta ferramenta quando o cliente quiser marcar uma revisão ou manutenção para o veículo. Ela recebe a placa e a data/hora desejada, cria um agendamento simulado e retorna um identificador, além do status do agendamento.", + "description": ( + "Use esta ferramenta quando o cliente quiser marcar uma revisao ou " + "manutencao para o veiculo. Ela recebe a placa e a data/hora desejada, " + "cria um agendamento simulado e retorna um identificador, alem do " + "status do agendamento." + ), "parameters": { "type": "object", "properties": { "placa": { "type": "string", - "description": "Placa do veículo que será levado para revisão." + "description": "Placa do veiculo que sera levado para revisao.", }, "data_hora": { "type": "string", - "description": "Data e hora desejada para a revisão, em formato ISO 8601 (por exemplo, '2026-03-10T09:00:00-03:00')." + "description": "Data e hora desejada para a revisao, em formato ISO 8601 (por exemplo, '2026-03-10T09:00:00-03:00').", }, }, "required": ["placa", "data_hora"], @@ -82,17 +110,22 @@ def get_tools_definitions(): }, { "name": "cancelar_pedido", - "description": "Use esta ferramenta quando o cliente solicitar o cancelamento de um pedido já registrado. Ela recebe o número do pedido e o motivo do cancelamento, atualiza o status para 'Cancelado' e retorna os detalhes do cancelamento para que você explique o resultado ao cliente.", + "description": ( + "Use esta ferramenta quando o cliente solicitar o cancelamento de um " + "pedido ja registrado. Ela recebe o numero do pedido e o motivo do " + "cancelamento, atualiza o status para 'Cancelado' e retorna os detalhes " + "do cancelamento para que voce explique o resultado ao cliente." + ), "parameters": { "type": "object", "properties": { "numero_pedido": { "type": "string", - "description": "Número do pedido que o cliente deseja cancelar." + "description": "Numero do pedido que o cliente deseja cancelar.", }, "motivo": { "type": "string", - "description": "Motivo do cancelamento informado pelo cliente (por exemplo, atraso, mudança de planos, condição de pagamento, etc.)." + "description": "Motivo do cancelamento informado pelo cliente (por exemplo, atraso, mudanca de planos, condicao de pagamento, etc.).", }, }, "required": ["numero_pedido", "motivo"], @@ -109,6 +142,11 @@ def seed_tools(): existing_names = {t.name for t in existing} for tool_def in get_tools_definitions(): if tool_def["name"] in existing_names: + repo.update_by_name( + name=tool_def["name"], + description=tool_def["description"], + parameters=tool_def["parameters"], + ) continue repo.create( name=tool_def["name"], diff --git a/app/repositories/tool_repository.py b/app/repositories/tool_repository.py index e9feacd..fe584b9 100644 --- a/app/repositories/tool_repository.py +++ b/app/repositories/tool_repository.py @@ -30,3 +30,14 @@ class ToolRepository: self.db.delete(tool) self.db.commit() return tool + + def update_by_name(self, name: str, description: str, parameters: dict): + tool = self.db.query(Tool).filter(Tool.name == name).first() + if not tool: + return None + + tool.description = description + tool.parameters = parameters + self.db.commit() + self.db.refresh(tool) + return tool