Add thai support in summary

This commit is contained in:
Adrien
2026-04-18 19:55:19 +02:00
parent c7a77af2f4
commit ff97c24a55
7 changed files with 147 additions and 25 deletions
@@ -25,10 +25,12 @@ public class ConceptReportController {
}
@PostMapping
public ResponseEntity<ConceptReportResponse> generate(@PathVariable String id) {
public ResponseEntity<ConceptReportResponse> generate(
@PathVariable String id,
@RequestParam(defaultValue = "en") String language) {
Topic topic = topicRepository.findById(id)
.orElseThrow(() -> new NoSuchElementException("Topic not found."));
return ResponseEntity.ok(conceptReportService.generateReport(topic));
return ResponseEntity.ok(conceptReportService.generateReport(topic, language));
}
@GetMapping
@@ -60,7 +60,7 @@ public class ConceptReportService {
this.objectMapper = objectMapper;
}
public ConceptReportResponse generateReport(Topic topic) {
public ConceptReportResponse generateReport(Topic topic, String language) {
List<Book> readyBooks = bookRepository.findAll().stream()
.filter(b -> b.getStatus() == BookStatus.READY)
.toList();
@@ -106,7 +106,7 @@ public class ConceptReportService {
if (mf == null || mf.isEmpty()) continue;
if (facet == ConceptFacet.OTHER) continue; // skip OTHER bucket in the rendered report
String prompt = buildFacetPrompt(topic, facet, mf, sectionLabel, figureLabel);
String prompt = buildFacetPrompt(topic, facet, mf, sectionLabel, figureLabel, language);
String markdown = chatClient.prompt()
.system(SYSTEM_PROMPT)
.user(prompt)
@@ -151,7 +151,8 @@ public class ConceptReportService {
private String buildFacetPrompt(Topic topic, ConceptFacet facet, MergedFacet mf,
Map<String, String> sectionLabel,
Map<String, String> figureLabel) {
Map<String, String> figureLabel,
String language) {
StringBuilder sb = new StringBuilder();
sb.append("CONCEPT: ").append(topic.getName()).append("\n");
sb.append("FACET: ").append(facet.displayTitle()).append("\n\n");
@@ -181,6 +182,17 @@ public class ConceptReportService {
sb.append("Write the ").append(facet.displayTitle()).append(" section of a concept report on \"")
.append(topic.getName())
.append("\". Stay strictly within this facet. Use the [S#]/[F#] labels above for citations.");
if ("th".equalsIgnoreCase(language)) {
sb.append("\n\nIMPORTANT: Write the narrative in Thai. ")
.append("Keep all medical, anatomical, surgical, pharmacological, and clinical ")
.append("terminology in English (e.g., cerebellopontine angle, glioblastoma, craniotomy, ")
.append("dexamethasone). Do NOT translate disease names, anatomical structures, drug names, ")
.append("procedures, eponyms, or imaging modalities. Translate only connective prose, ")
.append("explanations, and general descriptions. Citation labels [S#]/[F#] stay unchanged. ")
.append("The sentinel string for insufficient context must remain exactly: ")
.append("\"The uploaded books do not contain sufficient information on this aspect.\"");
}
return sb.toString();
}
@@ -26,11 +26,13 @@ public class TopicController {
}
@PostMapping("/{id}/summary")
public ResponseEntity<TopicSummaryResponse> generateSummary(@PathVariable String id) {
public ResponseEntity<TopicSummaryResponse> generateSummary(
@PathVariable String id,
@RequestParam(defaultValue = "en") String language) {
Topic topic = topicRepository.findById(id)
.orElseThrow(() -> new NoSuchElementException("Topic not found."));
TopicSummaryResponse response = topicSummaryService.generateSummary(topic);
TopicSummaryResponse response = topicSummaryService.generateSummary(topic, language);
return ResponseEntity.ok(response);
}
@@ -59,7 +59,7 @@ public class TopicSummaryService {
this.objectMapper = objectMapper;
}
public TopicSummaryResponse generateSummary(Topic topic) {
public TopicSummaryResponse generateSummary(Topic topic, String language) {
List<Book> readyBooks = bookRepository.findAll().stream()
.filter(b -> b.getStatus() == BookStatus.READY)
.toList();
@@ -82,7 +82,7 @@ public class TopicSummaryService {
log.debug("Topic reports for '{}': {} sections, {} figures retrieved",
topic.getName(), allSections.size(), allFigures.size());
String contextPrompt = buildContextPrompt(question, allSections, allFigures);
String contextPrompt = buildContextPrompt(question, allSections, allFigures, language);
String summary = chatClient.prompt()
.system(SYSTEM_PROMPT)
.user(contextPrompt)
@@ -142,7 +142,8 @@ public class TopicSummaryService {
private String buildContextPrompt(String question,
List<SectionEntity> sections,
List<FigureEntity> figures) {
List<FigureEntity> figures,
String language) {
StringBuilder sb = new StringBuilder();
if (!sections.isEmpty()) {
@@ -169,6 +170,17 @@ public class TopicSummaryService {
}
sb.append("QUESTION:\n").append(question);
if ("th".equalsIgnoreCase(language)) {
sb.append("\n\nIMPORTANT: Write the narrative in Thai. ")
.append("Keep all medical, anatomical, surgical, pharmacological, and clinical ")
.append("terminology in English (e.g., cerebellopontine angle, glioblastoma, craniotomy, ")
.append("dexamethasone). Do NOT translate disease names, anatomical structures, drug names, ")
.append("procedures, eponyms, or imaging modalities. Translate only connective prose, ")
.append("explanations, and general descriptions. Citation labels [S#]/[F#] stay unchanged. ")
.append("The sentinel string for insufficient context must remain exactly: ")
.append("\"The uploaded books do not contain sufficient information on this topic.\"");
}
return sb.toString();
}