Article image
Sebastiao Junior
Sebastiao Junior20/08/2024 18:04
Compartilhe

Criando uma aplicativo em java para conversar com Gemini-1.5-flash

  • #Java
  • #Inteligência Artificial (IA)

Nos dias de hoje, o uso crescente de Large Language Models (LLMs) tem impulsionado a necessidade de incorporá-los em nossos projetos. No entanto, encontrar exemplos específicos de como integrar esses modelos em aplicativos Java pode ser um desafio. Neste contexto, a criação de um aplicativo Java para conversar com o Gemini 1.5 Flash pode ser uma excelente oportunidade para explorar essa tecnologia e aprender como introduzir LLMs em nossos próprios projetos. 

O aplicativo é um Chat usando o console, de maneira que o código ficasse o mais simples possível. Essa abordagem evitou o uso de dependências externas e com isso o código ficou com 78 linhas.

O código basicamente tem 4 métodos:

  • Método main(): Este é o ponto de entrada da aplicação. Ele cria um Scanner para receber a entrada do usuário em um loop infinito que simula um chat. Quando o usuário digita "quit", o programa é encerrado. 
  • Método sendRequest(): é responsável por enviar a solicitação à API da Google. Primeiro, ele constrói o prompt completo, combinando o histórico de conversa e a pergunta atual. Em seguida, chama o método conversationHistory() para atualizar o histórico. Depois, constrói o corpo da solicitação HTTP no formato JSON e cria um HttpClient e um HttpRequest com a URL, cabeçalhos e corpo da solicitação. O HttpClient envia a solicitação e recebe a resposta, que é processada pelo método processResponse(). 
  • Método processResponse(): lida com a resposta recebida da API da Google. Ele verifica o código de status da resposta e, se necessário, imprime um erro. Além disso, utiliza um padrão regular para extrair o texto da resposta e constrói a resposta final a partir do texto extraído.
  • Método conversationHistory(): têm a função de manter um registro das interações em um sistema de conversação. Sua principal responsabilidade é gerenciar o histórico dessas conversas, garantindo que ele não cresça indefinidamente e que as informações mais recentes estejam sempre acessíveis.

Regex ao invés de APIs Json

O Método processResponse() usa uma expressão regular para “desmontar” a resposta json. O uso dessa estratégia foi simplesmente para diminuir o número de linhas de código. Após muita pesquisa cheguei nessa expressão: "\"text\"\\s:\\s\"([^\"]+)\"

Explicação de cada parte da expressão:

  • "text": Procura literalmente a palavra "text" no texto.
  • \\s: Corresponde a qualquer caractere de espaço em branco, como espaço, tabulação ou quebra de linha.
  • :: Procura literalmente o caractere dois pontos.
  • \"([^\"]+)\":
  • \": Procura literalmente uma aspa dupla.
  • ([^\"])+:
  • ( e ): Agrupam a expressão dentro dos parênteses.
  • [^"]: Corresponde a qualquer caractere que não seja uma aspa dupla.
  • +: Indica que o caractere anterior (qualquer caractere que não seja aspa dupla) pode ocorrer uma ou mais vezes.
  • \": Procura literalmente uma aspa dupla novamente.

Em um código de produção, talvez não fosse uma boa estratégia usar expressões regulares por sua complexidade e dificuldade de entendimento.

Ao criar esse aplicativo, demonstramos o potencial dos LLMs em transformar a maneira como programamos. A integração de LLMs em projetos reais exige um profundo conhecimento das tecnologias envolvidas e muitos testes. Este trabalho pode servir como um ponto de partida para que outros desenvolvedores possam explorar essas novas ferramentas e construir aplicações inovadoras.

Quem quiser dar uma olhada, o projeto está em 

https://github.com/gazolla/GeminiChat

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class App {
  private static final String API_KEY = "<<Adicione sua chave aqui>>";
  private static final String URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:streamGenerateContent";
  private static final ArrayList<String> history = new ArrayList<String>();
  private static final int CAPACITY = 100;
  
  public static void main(String[] args) throws IOException, InterruptedException {
      try(var scanner = new Scanner(System.in)) {
          while(true) {
              System.out.println("you:");
              var ask = scanner.nextLine();
              if (ask.equals("quit")) {
                  System.out.println("answer: bye");
                  System.exit(0);
              }
              sendRequest(ask);
          }
      }
  }

  private static void sendRequest(String prompt) throws IOException, InterruptedException {
      var context = history.stream().collect(Collectors.joining("\n"));
      var fullPrompt = context + "return the result as plain text without any formatting, special characters, or backticks. Question:" + prompt;
      conversationHistory(prompt);
      var jsonRequest = "{\"contents\":[{\"parts\":[{\"text\":\"" + fullPrompt + "\"}],\"role\":\"user\"}]}";
      var httpClient = HttpClient.newHttpClient();
      var request = HttpRequest.newBuilder()
              .uri(URI.create(URL + "?alt=sse&key=" + API_KEY))
              .header("Content-Type", "application/json")
              .POST(HttpRequest.BodyPublishers.ofString(jsonRequest))
              .build();
      HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
      processResponse(response);
  }

  private static void processResponse(HttpResponse<String> response) throws IOException {
      if (response.statusCode() != 200) {
          System.out.println("Error: " + response.statusCode());
          return;
      }
      var pattern = Pattern.compile("\"text\"\\s*:\\s*\"([^\"]+)\"");
      var answer = new StringBuilder();
      String line;
      try(var reader = new BufferedReader(new StringReader(response.body()))){
          while ((line = reader.readLine()) != null) {
              if(line.isEmpty()) continue;
              Matcher matcher = pattern.matcher(line.substring(5));
              if(matcher.find()) {
                  answer.append(matcher.group(1)).append(" ");
              }
          }
      }
      System.out.println("answer: " + answer.toString());
  }
  
  private static String conversationHistory(String prompt) {
      if(history.size() == CAPACITY) {
          history.remove(0);
      }
      history.add(prompt);
      var result = history.stream().collect(Collectors.joining("\n"));
      return result;
  }
}
Compartilhe
Comentários (0)