8
respostas

Projeto final. Meu chatbot não consegue fazer 3 perguntas. Erro "Path parameter "thread_id" value must not be null. (parameter #1) for method OpenAiApi.retrieveRun"

Professor boa tarde,

O meu chatbot funciona todas as perguntas mas na terceira pergunta, ele processa muito e não responde nem o mais simples como por exemplo "Qual o nome da loja?". Quando aperto limpar conversa ele acusa erro no springboot: for method OpenAiApi.retrieveRun] with root cause

java.lang.IllegalArgumentException: Path parameter "thread_id" value must not be null. (parameter #1) for method OpenAiApi.retrieveRun at retrofit2.Utils.methodError(Utils.java:54) ~[retrofit-2.9.0.jar:na] at retrofit2.Utils.methodError(Utils.java:43) ~[retrofit-2.9.0.jar:na] at retrofit2.Utils.parameterError(Utils.java:64) ~[retrofit-2.9.0.jar:na] at retrofit2.ParameterHandler$Path.apply(ParameterHandler.java:113) ~[retrofit-2.9.0.jar:na] at retrofit2.RequestFactory.create(RequestFactory.java:129) ~[retrofit-2.9.0.jar:na] at retrofit2.OkHttpCall.createRawCall(OkHttpCall.java:208) ~[retrofit-2.9.0.jar:na] at retrofit2.OkHttpCall.getRawCall(OkHttpCall.java:107) ~[retrofit-2.9.0.jar:na] at retrofit2.OkHttpCall.execute(OkHttpCall.java:197) ~[retrofit-2.9.0.jar:na] at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:46) ~[adapter-rxjava2-2.9.0.jar:na] at io.reactivex.Observable.subscribe(Observable.java:10151) ~[rxjava-2.0.0.jar:2.0.0] at retrofit2.adapter.rxjava2.BodyObservable.subscribeActual(BodyObservable.java:35) ~[adapter-rxjava2-2.9.0.jar:na] at io.reactivex.Observable.subscribe(Observable.java:10151) ~[rxjava-2.0.0.jar:2.0.0] at io.reactivex.internal.operators.observable.ObservableSingleSingle.subscribeActual(ObservableSingleSingle.java:35) ~[rxjava-2.0.0.jar:2.0.0] at io.reactivex.Single.subscribe(Single.java:2517) ~[rxjava-2.0.0.jar:2.0.0] at io.reactivex.Single.blockingGet(Single.java:2001) ~[rxjava-2.0.0.jar:2.0.0] at com.theokanning.openai.service.OpenAiService.execute(OpenAiService.java:513) ~[service-0.18.2.jar:na] at com.theokanning.openai.service.OpenAiService.retrieveRun(OpenAiService.java:467) ~[service-0.18.2.jar:na] at br.com.alura.ecomart.chatbot.infra.openai.OpenAIClient.enviarRequisicaoChatCompletion(OpenAIClient.java:76) ~[classes/:na] at br.com.alura.ecomart.chatbot.domain.service.ChatBotService.responderPergunta(ChatBotService.java:22) ~[classes/:na] at br.com.alura.ecomart.chatbot.web.controller.ChatController.responderPergunta(ChatController.java:36) ~[classes/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:254) ~[spring-web-6.1.1.jar:6.1.1] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:182) ~[spring-web-6.1.1.jar:6.1.1] at

8 respostas

org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) ~[spring-webmvc-6.1.1.jar:6.1.1] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:917) ~[spring-webmvc-6.1.1.jar:6.1.1] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:829) ~[spring-webmvc-6.1.1.jar:6.1.1] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-6.1.1.jar:6.1.1] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) ~[spring-webmvc-6.1.1.jar:6.1.1] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) ~[spring-webmvc-6.1.1.jar:6.1.1] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.1.1.jar:6.1.1] at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914) ~[spring-webmvc-6.1.1.jar:6.1.1] at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590) ~[tomcat-embed-core-10.1.16.jar:6.0] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.1.1.jar:6.1.1] at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-10.1.16.jar:6.0] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-10.1.16.jar:10.1.16] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.1.1.jar:6.1.1] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.1.jar:6.1.1] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.16.jar:10.1.16]

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.1.1.jar:6.1.1] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.1.jar:6.1.1] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.1.1.jar:6.1.1] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.1.jar:6.1.1] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:340) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-10.1.16.jar:10.1.16] at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]

Analisando o erro, ele mostra dentro try catch onde está o while:

try {
            while (!concluido) {
                Thread.sleep(1000 * 10);
                run = service.retrieveRun(threadId, run.getId());
                concluido = run.getStatus().equalsIgnoreCase("completed");
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        
        Observação: Estou usando chatGPT 3.5-turbo-1106.
        
        Será que o problema está no chatGPT?

Oi!

Manda aqui o código da sua classe OpenAIClient

Bom dia Professor desculpa a demora. Tá aí a Classe OpenAIClient.

@Component public class OpenAIClient {

private final String apiKey;
private final String assistantId;
private String threadId;
private final OpenAiService service;
private final CalculadorDeFrete calculadorDeFrete;

public OpenAIClient(@Value("${app.openai.api.key}") String apiKey, @Value("${app.openai.assistant.id}") String assistantId, CalculadorDeFrete calculadorDeFrete) {
    this.apiKey = apiKey;
    this.service = new OpenAiService(apiKey, Duration.ofSeconds(60));
    this.assistantId = assistantId;
    this.calculadorDeFrete = calculadorDeFrete;
}

public String enviarRequisicaoChatCompletion(DadosRequisicaoChatCompletion dados) {
    var messageRequest = MessageRequest
            .builder()
            .role(ChatMessageRole.USER.value())
            .content(dados.promptUsuario())
            .build();

    if (this.threadId == null) {
        var threadRequest = ThreadRequest
                .builder()
                .messages(Arrays.asList(messageRequest))
                .build();

        var thread = service.createThread(threadRequest);
        this.threadId = thread.getId();
    } else {
        service.createMessage(this.threadId, messageRequest);
    }

    var runRequest = RunCreateRequest
            .builder()
            .assistantId(assistantId)
            .build();
    var run = service.createRun(threadId, runRequest);

    var concluido = false;
    var precisaChamarFuncao = false;
    try {
        while (!concluido && !precisaChamarFuncao) {
            Thread.sleep(1000 * 10);
            run = service.retrieveRun(threadId, run.getId());
            concluido = run.getStatus().equalsIgnoreCase("completed");
            precisaChamarFuncao = run.getRequiredAction() != null;
        }
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }

    if (precisaChamarFuncao) {
        var precoDoFrete = chamarFuncao(run);
        var submitRequest = SubmitToolOutputsRequest
                .builder()
                .toolOutputs(Arrays.asList(
                        new SubmitToolOutputRequestItem(run
                                        .getRequiredAction()
                                        .getSubmitToolOutputs()
                                        .getToolCalls()
                                        .get(0)
                                        .getId(),
                                precoDoFrete)
                ))
                .build();
        service.submitToolOutputs(threadId, run.getId(), submitRequest);

        try {
            while (!concluido) {
                Thread.sleep(1000 * 10);
                run = service.retrieveRun(threadId, run.getId());
                concluido = run.getStatus().equalsIgnoreCase("completed");
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    var mensagens = service.listMessages(threadId);
    return mensagens
            .getData()
            .stream()
            .sorted(Comparator.comparingInt(Message::getCreatedAt).reversed())
            .findFirst().get().getContent().get(0).getText().getValue()
            .replaceAll("\\\u3010.*?\\\u3011", "");
}

Segunda parte da Classe.

private String chamarFuncao(Run run) { try { var funcao = run.getRequiredAction().getSubmitToolOutputs().getToolCalls().get(0).getFunction(); var funcaoCalcularFrete = ChatFunction.builder() .name("calcularFrete") .executor(DadosCalculoFrete.class, d -> calculadorDeFrete.calcular(d)) .build();

        var executorDeFuncoes = new FunctionExecutor(Arrays.asList(funcaoCalcularFrete));
        var functionCall = new ChatFunctionCall(funcao.getName(), new ObjectMapper().readTree(funcao.getArguments()));
        return executorDeFuncoes.execute(functionCall).toString();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

public List<String> carregarHistoricoDeMensagens() {
    var mensagens = new ArrayList<String>();

    if (this.threadId != null) {
        mensagens.addAll(
                service
                        .listMessages(this.threadId)
                        .getData()
                        .stream()
                        .sorted(Comparator.comparingInt(Message::getCreatedAt))
                        .map(m -> m.getContent().get(0).getText().getValue())
                        .collect(Collectors.toList())
        );
    }

    return mensagens;
}

public void apagarThread() {
    if (this.threadId != null) {
        service.deleteThread(this.threadId);
        this.threadId = null;
    }
}

}

Blz. Manda aqui também o código das suas classes Controller e Service

Boa noite professor, estou lhe enviando as classes Services:

package br.com.alura.ecomart.chatbot.domain.service;

import br.com.alura.ecomart.chatbot.domain.DadosCalculoFrete;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

@Service
public class CalculadorDeFrete {

    public BigDecimal calcular(DadosCalculoFrete dados) {
        //lógica para cálculo de frete aqui...

        return new BigDecimal("3.45").multiply(new BigDecimal(dados.quantidadeProdutos()));
    }

}
package br.com.alura.ecomart.chatbot.domain.service;

import java.util.List;

import org.springframework.stereotype.Service;

import br.com.alura.ecomart.chatbot.infra.openai.DadosRequisicaoChatCompletion;
import br.com.alura.ecomart.chatbot.infra.openai.OpenAIClient;

@Service
public class ChatBotService {
    
    private OpenAIClient client;	
        
    public ChatBotService(OpenAIClient client) {		
        this.client = client;
    }

    public String responderPergunta(String pergunta) {
        var promptSistema = "Você é um chatbot de atendimento a clientes de um ecommerce e deve responder apenas perguntas relacionadas com ecommerce";
        var dados = new DadosRequisicaoChatCompletion(promptSistema, pergunta);
        return client.enviarRequisicaoChatCompletion(dados);		
    }
    
    public List<String> carregarHistorico(){
        return client.carregarHistoricoDeMensagens();
    }

    public void limparHistorico() {
        client.apagarThread();
        
    }

}

Mandando a classe Controller:

package br.com.alura.ecomart.chatbot.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import br.com.alura.ecomart.chatbot.domain.service.ChatBotService;
import br.com.alura.ecomart.chatbot.web.dto.PerguntaDto;

@Controller
@RequestMapping({"/", "chat"})
public class ChatController {

    private static final String PAGINA_CHAT = "chat";
    
    private ChatBotService chatBotService;    

    public ChatController(ChatBotService chatBotService) {
        this.chatBotService = chatBotService;
    }

    @GetMapping
    public String carregarPaginaChatbot(Model model) {
        var mensagens = chatBotService.carregarHistorico();
        model.addAttribute("historico", mensagens);
        return PAGINA_CHAT;
    }

    @PostMapping
    @ResponseBody
    public String responderPergunta(@RequestBody PerguntaDto dto) {
        return chatBotService.responderPergunta(dto.pergunta());
    }

    @GetMapping("limpar")
    public String limparConversa() {
        chatBotService.limparHistorico();    	
        return "redirect:/chat";
    }

}

Olhando o código, está tudo certinho e não detectei erros. Mas pela stacktrace o problema aconteceu ao enviar uma nova pergunta e não ao limpar o chat.