Spaces:
Sleeping
Sleeping
package com.example.p1.service; | |
import com.example.p1.config.AiConfiguration; | |
import com.example.p1.controller.ChatController; | |
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | |
import com.fasterxml.jackson.annotation.JsonProperty; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import org.springframework.stereotype.Service; | |
import org.springframework.web.reactive.function.client.WebClient; | |
import reactor.core.publisher.Flux; | |
import reactor.core.publisher.Mono; | |
import java.time.Duration; | |
import java.util.List; | |
import java.util.stream.Collectors; | |
public class ChatService { | |
private static final Logger logger = LoggerFactory.getLogger(ChatService.class); | |
private final WebClient webClient; | |
private final AiConfiguration config; | |
public ChatService(WebClient geminiWebClient, AiConfiguration config) { | |
this.webClient = geminiWebClient; | |
this.config = config; | |
} | |
public Mono<String> generateResponse(String message) { | |
logger.debug("Generating response for message: {}", message); | |
GeminiRequest request = createSimpleRequest(message); | |
return callGeminiAPI(request) | |
.map(this::extractTextFromResponse) | |
.doOnSuccess(response -> logger.debug("Generated response: {}", response)) | |
.doOnError(error -> logger.error("Error generating response", error)); | |
} | |
public Mono<String> generateConversationResponse(List<ChatController.ConversationRequest.Message> messages) { | |
logger.debug("Generating conversation response for {} messages", messages.size()); | |
String conversationContext = buildConversationContext(messages); | |
return generateResponse(conversationContext); | |
} | |
public Flux<String> generateStreamingResponse(String message) { | |
// For demonstration - in real implementation, you'd use Gemini's streaming API | |
return generateResponse(message) | |
.flatMapMany(response -> { | |
String[] words = response.split("\\s+"); | |
return Flux.fromArray(words) | |
.delayElements(Duration.ofMillis(100)) | |
.map(word -> word + " "); | |
}); | |
} | |
private Mono<GeminiResponse> callGeminiAPI(GeminiRequest request) { | |
return webClient.post() | |
.uri("/{model}:generateContent?key={apiKey}", | |
config.getModel(), config.getKey()) | |
.bodyValue(request) | |
.retrieve() | |
.bodyToMono(GeminiResponse.class) | |
.timeout(Duration.ofMillis(config.getTimeout())); | |
} | |
private GeminiRequest createSimpleRequest(String message) { | |
GeminiRequest.Part part = new GeminiRequest.Part(message); | |
GeminiRequest.Content content = new GeminiRequest.Content(List.of(part)); | |
return new GeminiRequest(List.of(content)); | |
} | |
private String buildConversationContext(List<ChatController.ConversationRequest.Message> messages) { | |
StringBuilder context = new StringBuilder(); | |
context.append("Previous conversation:\n"); | |
for (ChatController.ConversationRequest.Message msg : messages) { | |
context.append(msg.getRole().toUpperCase()) | |
.append(": ") | |
.append(msg.getContent()) | |
.append("\n"); | |
} | |
return context.toString(); | |
} | |
private String extractTextFromResponse(GeminiResponse response) { | |
if (response.getCandidates() != null && !response.getCandidates().isEmpty()) { | |
GeminiResponse.Candidate candidate = response.getCandidates().get(0); | |
if (candidate.getContent() != null && | |
candidate.getContent().getParts() != null && | |
!candidate.getContent().getParts().isEmpty()) { | |
return candidate.getContent().getParts().get(0).getText(); | |
} | |
} | |
return "No response generated"; | |
} | |
// Gemini API DTOs | |
public static class GeminiRequest { | |
private List<Content> contents; | |
public GeminiRequest(List<Content> contents) { | |
this.contents = contents; | |
} | |
public List<Content> getContents() { return contents; } | |
public void setContents(List<Content> contents) { this.contents = contents; } | |
public static class Content { | |
private List<Part> parts; | |
public Content(List<Part> parts) { | |
this.parts = parts; | |
} | |
public List<Part> getParts() { return parts; } | |
public void setParts(List<Part> parts) { this.parts = parts; } | |
} | |
public static class Part { | |
private String text; | |
public Part(String text) { | |
this.text = text; | |
} | |
public String getText() { return text; } | |
public void setText(String text) { this.text = text; } | |
} | |
} | |
public static class GeminiResponse { | |
private List<Candidate> candidates; | |
public List<Candidate> getCandidates() { return candidates; } | |
public void setCandidates(List<Candidate> candidates) { this.candidates = candidates; } | |
public static class Candidate { | |
private Content content; | |
public Content getContent() { return content; } | |
public void setContent(Content content) { this.content = content; } | |
} | |
public static class Content { | |
private List<Part> parts; | |
public List<Part> getParts() { return parts; } | |
public void setParts(List<Part> parts) { this.parts = parts; } | |
} | |
public static class Part { | |
private String text; | |
public String getText() { return text; } | |
public void setText(String text) { this.text = text; } | |
} | |
} | |
} |