From 5d6edef39687e009c5c86421e6f5c0c398bf6e54 Mon Sep 17 00:00:00 2001 From: Mohammad Zwaib Date: Thu, 16 Jul 2026 00:34:42 +0200 Subject: [PATCH] History --- .../homme/demo/controller/ChatController.java | 2 +- .../java/com/homme/demo/dto/ChatRequest.java | 5 +- .../demo/service/AzureMistralService.java | 50 ++++++++++++++++++- .../com/homme/demo/service/RagService.java | 36 ++++++++++++- 4 files changed, 84 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/homme/demo/controller/ChatController.java b/src/main/java/com/homme/demo/controller/ChatController.java index eca83ef..e9e1474 100644 --- a/src/main/java/com/homme/demo/controller/ChatController.java +++ b/src/main/java/com/homme/demo/controller/ChatController.java @@ -35,7 +35,7 @@ public class ChatController { .build(); } - String answer = ragService.answerQuestion(question); + String answer = ragService.answerQuestion(question, request.getHistory()); return AskResponse.builder() .answer(answer).reply(answer).message(answer) diff --git a/src/main/java/com/homme/demo/dto/ChatRequest.java b/src/main/java/com/homme/demo/dto/ChatRequest.java index 9e42435..4f20b7e 100644 --- a/src/main/java/com/homme/demo/dto/ChatRequest.java +++ b/src/main/java/com/homme/demo/dto/ChatRequest.java @@ -8,10 +8,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import lombok.Setter; -/** - * Request body sent by the WordPress chat widget: - * { "session_id": "...", "history": [{role, content}], "message": "..." } - */ + @Getter @Setter @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/src/main/java/com/homme/demo/service/AzureMistralService.java b/src/main/java/com/homme/demo/service/AzureMistralService.java index 6ec7d58..cc18c99 100644 --- a/src/main/java/com/homme/demo/service/AzureMistralService.java +++ b/src/main/java/com/homme/demo/service/AzureMistralService.java @@ -96,10 +96,56 @@ public class AzureMistralService { + " Retry-After = "+ e.getHeaders().getFirst("Retry-After") + " Body = "+ e.getResponseBodyAsString()); }catch (Exception e) { - + throw new RuntimeException("Azure Mistral request failed: "+ e.getMessage()); } } - + + public String askMistral(List> messages, int maxTokens) { + + try { + String url = endPoint + "/openai/v1/chat/completions"; + + System.out.println(">>> MODELL = " + deployment + " | URL = " + url); + + Map requstBody = Map.of( + "model", "gpt-5-mini-datazone", + "messages", messages, + "reasoning_effort", "minimal", + "max_completion_tokens", maxTokens + ); + + long c0 = System.currentTimeMillis(); + String response = webClient.post() + .uri(url) + .header("api-key", apiKey) + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(requstBody) + .retrieve() + .bodyToMono(String.class) + .retryWhen( + Retry.backoff(2, Duration.ofSeconds(5)) + .filter(ex -> ex instanceof WebClientResponseException.TooManyRequests) + .onRetryExhaustedThrow((spec, sig) -> sig.failure()) + ) + .block(); + System.out.println(" askMistral daurte = " + (System.currentTimeMillis() - c0) + "ms"); + + if (response == null || response.isBlank()) { + throw new RuntimeException("Leere Antwort von Azure Mistral"); + } + + JsonNode root = objectMapper.readTree(response); + return root.path("choices").get(0).get("message").path("content").asText(); + + } catch (WebClientResponseException e) { + throw new RuntimeException("Azure Mistral request failed: " + e.getStatusCode() + + " Retry-After = " + e.getHeaders().getFirst("Retry-After") + + " Body = " + e.getResponseBodyAsString()); + } catch (Exception e) { + throw new RuntimeException("Azure Mistral request failed: " + e.getMessage()); + } + } + } diff --git a/src/main/java/com/homme/demo/service/RagService.java b/src/main/java/com/homme/demo/service/RagService.java index 153398d..67ef2e7 100644 --- a/src/main/java/com/homme/demo/service/RagService.java +++ b/src/main/java/com/homme/demo/service/RagService.java @@ -2,12 +2,15 @@ package com.homme.demo.service; import java.time.LocalDate; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import com.homme.demo.dto.ChatRequest; import com.homme.demo.entity.ChatLog; import com.homme.demo.entity.DocumentChunck; import com.homme.demo.repository.ChatLogRepository; @@ -109,7 +112,12 @@ public class RagService { @Transactional public String answerQuestion(String question) { - + return answerQuestion(question, null); + } + + @Transactional + public String answerQuestion(String question, List history) { + long t1 = System.currentTimeMillis(); float[] q = azureEmbeddingService.createEmbeddingFloatArray(question, "query"); @@ -179,8 +187,32 @@ public class RagService { question // current_user_message ); + // Nachrichtenliste bauen: system + Gespraechsverlauf + aktuelle Nachricht (mit Kontext) + List> messages = new ArrayList<>(); + messages.add(Map.of("role", "system", "content", SYSTEM_PROMPT)); + + if (history != null) { + for (int i = 0; i < history.size(); i++) { + ChatRequest.HistoryItem h = history.get(i); + if (h.getContent() == null || h.getContent().isBlank()) { + continue; + } + // das Widget haengt die aktuelle Nachricht ans Ende der history -> nicht doppeln + boolean isLast = (i == history.size() - 1); + if (isLast && question.equals(h.getContent())) { + continue; + } + String role = ("assistant".equalsIgnoreCase(h.getRole()) + || "bot".equalsIgnoreCase(h.getRole())) + ? "assistant" : "user"; + messages.add(Map.of("role", role, "content", h.getContent())); + } + } + + messages.add(Map.of("role", "user", "content", userPrompt)); + long t2 = System.currentTimeMillis(); - String answer = azureMistralService.askMistral(SYSTEM_PROMPT, userPrompt, 800); + String answer = azureMistralService.askMistral(messages, 800); System.out.println("Mistarl = "+ (System.currentTimeMillis() - t2)+ "ms"); Double roundedDistance = (bestDistance == null)