stable POC version 1 - chat and topics
This commit is contained in:
@@ -32,6 +32,21 @@ public class ChatController {
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(response);
|
||||
}
|
||||
|
||||
@GetMapping("/sessions")
|
||||
public ResponseEntity<List<Map<String, Object>>> getSessionsByTopic(@RequestParam String topicId) {
|
||||
List<ChatSession> sessions = chatService.getSessionsByTopic(topicId);
|
||||
List<Map<String, Object>> response = sessions.stream()
|
||||
.map(s -> {
|
||||
Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("sessionId", s.getId());
|
||||
m.put("topicId", s.getTopicId());
|
||||
m.put("createdAt", s.getCreatedAt());
|
||||
return m;
|
||||
})
|
||||
.toList();
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@GetMapping("/sessions/{sessionId}/messages")
|
||||
public ResponseEntity<List<Map<String, Object>>> getMessages(@PathVariable UUID sessionId) {
|
||||
List<Message> messages = chatService.getMessages(sessionId);
|
||||
|
||||
@@ -26,17 +26,18 @@ public class ChatService {
|
||||
private static final Logger log = LoggerFactory.getLogger(ChatService.class);
|
||||
|
||||
private static final String SYSTEM_PROMPT = """
|
||||
You are an expert neurosurgery educator assistant. Your role is to answer
|
||||
questions based ONLY on the content from uploaded medical textbooks that has been
|
||||
retrieved for you as context.
|
||||
You are an expert neurosurgery educator assistant. Answer questions using the
|
||||
medical textbook content provided to you as context.
|
||||
|
||||
Rules:
|
||||
- Answer only from the provided context chunks
|
||||
- If the context does not contain enough information, explicitly state:
|
||||
"I could not find relevant information about this topic in the uploaded books."
|
||||
- Cite sources when possible (book title and page number from the context metadata)
|
||||
- Give comprehensive, detailed answers — cover all relevant aspects found in the context: anatomy, indications, contraindications, techniques, procedural steps, complications, outcomes, and clinical considerations
|
||||
- When the context contains related information, synthesize a thorough answer from it — do not apologize for missing definitions or lead with what you couldn't find
|
||||
- Build answers from what is present: procedures, conditions, techniques, and descriptions all contribute; combine them into a rich, structured response
|
||||
- Use clear structure: headings, bullet points, or numbered steps where appropriate to maximize clarity
|
||||
- Only say you cannot answer if the context is entirely unrelated to the question
|
||||
- Cite sources for each major point (book title and page number from the context metadata)
|
||||
- Maintain continuity with the conversation history
|
||||
- Never fabricate clinical information
|
||||
- Never fabricate clinical information not present in the context
|
||||
""";
|
||||
|
||||
private final ChatClient chatClient;
|
||||
@@ -87,7 +88,7 @@ public class ChatService {
|
||||
String fullQuestion = buildQuestionWithHistory(history, userContent, session.getTopicId());
|
||||
|
||||
var qaAdvisor = QuestionAnswerAdvisor.builder(vectorStore)
|
||||
.searchRequest(SearchRequest.builder().similarityThreshold(0.8d).topK(6).build())
|
||||
.searchRequest(SearchRequest.builder().similarityThreshold(0.5d).topK(6).build())
|
||||
.build();
|
||||
|
||||
ChatResponse response = chatClient.prompt()
|
||||
@@ -106,6 +107,10 @@ public class ChatService {
|
||||
return messageRepository.save(assistantMessage);
|
||||
}
|
||||
|
||||
public List<ChatSession> getSessionsByTopic(String topicId) {
|
||||
return sessionRepository.findByTopicIdOrderByCreatedAtDesc(topicId);
|
||||
}
|
||||
|
||||
public void deleteSession(UUID sessionId) {
|
||||
if (!sessionRepository.existsById(sessionId)) {
|
||||
throw new NoSuchElementException("Session not found.");
|
||||
@@ -115,16 +120,17 @@ public class ChatService {
|
||||
|
||||
private String buildQuestionWithHistory(List<Message> history, String currentQuestion,
|
||||
String topicId) {
|
||||
boolean hasTopic = topicId != null && !topicId.equals("free-form");
|
||||
|
||||
if (history.size() <= 1) {
|
||||
// Only the current user message is in history; just ask the question
|
||||
return topicId != null
|
||||
return hasTopic
|
||||
? String.format("[Context: This is a question about the neurosurgery topic '%s']\n%s",
|
||||
topicId, currentQuestion)
|
||||
: currentQuestion;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (topicId != null) {
|
||||
if (hasTopic) {
|
||||
sb.append(String.format("[Context: This conversation is about the neurosurgery topic '%s']\n\n",
|
||||
topicId));
|
||||
}
|
||||
@@ -154,6 +160,7 @@ public class ChatService {
|
||||
Map<String, Object> source = new HashMap<>();
|
||||
source.put("bookTitle", bookTitle);
|
||||
source.put("page", page);
|
||||
source.put("chunkText", doc.getText());
|
||||
sources.add(source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,10 @@ package com.aiteacher.chat;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Repository
|
||||
public interface ChatSessionRepository extends JpaRepository<ChatSession, UUID> {
|
||||
List<ChatSession> findByTopicIdOrderByCreatedAtDesc(String topicId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user