diff --git a/src/main/java/kz/konturai/parser/controller/ReportController.java b/src/main/java/kz/konturai/parser/controller/ReportController.java index 52c4b44..a00c39f 100644 --- a/src/main/java/kz/konturai/parser/controller/ReportController.java +++ b/src/main/java/kz/konturai/parser/controller/ReportController.java @@ -10,6 +10,7 @@ import kz.konturai.parser.model.ReportHistory; import kz.konturai.parser.repository.ReportHistoryRepository; import kz.konturai.parser.service.ReportGenerationService; import kz.konturai.parser.service.DeepResearchService; +import kz.konturai.parser.service.ResearchPdfService; import kz.konturai.parser.service.ReportSynthesisService; import kz.konturai.parser.service.MinIOService; import org.springframework.data.domain.Page; @@ -37,17 +38,20 @@ public class ReportController { private final ReportHistoryRepository reportHistoryRepository; private final MinIOService minIOService; private final DeepResearchService deepResearchService; + private final ResearchPdfService researchPdfService; private final ReportSynthesisService reportSynthesisService; public ReportController(ReportGenerationService reportGenerationService, ReportHistoryRepository reportHistoryRepository, MinIOService minIOService, DeepResearchService deepResearchService, + ResearchPdfService researchPdfService, ReportSynthesisService reportSynthesisService) { this.reportGenerationService = reportGenerationService; this.reportHistoryRepository = reportHistoryRepository; this.minIOService = minIOService; this.deepResearchService = deepResearchService; + this.researchPdfService = researchPdfService; this.reportSynthesisService = reportSynthesisService; } @@ -96,8 +100,8 @@ public class ReportController { // Предполагаемое время завершения LocalDateTime estimatedCompletion = LocalDateTime.now().plusMinutes(8); - // Асинхронный процесс: deep-research -> synthesis via Ollama -> Markdown -> - // сохранение + // Запускаем асинхронный процесс: deep-research -> synthesis via Ollama -> PDF + // -> сохранение deepResearchService.generateReportAsync(deepRequest) .publishOn(Schedulers.boundedElastic()) .flatMap(researchResponse -> { @@ -118,12 +122,10 @@ public class ReportController { .map(tuple -> { DeepResearchResponse researchResponse = (DeepResearchResponse) tuple[0]; String synthesizedMarkdown = (String) tuple[1]; - String finalMarkdown = buildMarkdownWithSources(synthesizedMarkdown, - researchResponse.getVisitedUrls()); - byte[] mdBytes = finalMarkdown - .getBytes(java.nio.charset.StandardCharsets.UTF_8); - String filename = "research_report_" + System.currentTimeMillis() + ".md"; - saveResearchMarkdownToHistory(request, filename, mdBytes, researchResponse); + byte[] pdfBytes = researchPdfService.generatePdfReport(request.getQuery(), + synthesizedMarkdown, researchResponse.getVisitedUrls()); + String filename = "research_report_" + System.currentTimeMillis() + ".pdf"; + saveResearchReportToHistory(request, filename, pdfBytes, researchResponse); return true; }) .doOnError(e -> { @@ -149,25 +151,6 @@ public class ReportController { return ResponseEntity.ok(ApiResponse.success("Исследовательский отчёт поставлен в очередь", response)); } - private String buildMarkdownWithSources(String synthesizedMarkdown, java.util.List visitedUrls) { - StringBuilder sb = new StringBuilder(); - sb.append(synthesizedMarkdown == null ? "" : synthesizedMarkdown.trim()); - sb.append("\n\n---\n\n"); - sb.append("## Источники\n\n"); - if (visitedUrls == null || visitedUrls.isEmpty()) { - sb.append("(источники не предоставлены)\n"); - return sb.toString(); - } - for (int i = 0; i < visitedUrls.size(); i++) { - String url = visitedUrls.get(i); - if (url == null || url.trim().isEmpty()) { - continue; - } - sb.append((i + 1)).append(". ").append(url.trim()).append("\n"); - } - return sb.toString(); - } - private void saveResearchReportToHistory(ResearchReportRequest request, String filename, byte[] pdfBytes, DeepResearchResponse researchResponse) { try { @@ -194,32 +177,6 @@ public class ReportController { } } - private void saveResearchMarkdownToHistory(ResearchReportRequest request, String filename, - byte[] mdBytes, DeepResearchResponse researchResponse) { - try { - // Загрузка в MinIO - minIOService.uploadFile(filename, mdBytes, - MediaType.parseMediaType("text/markdown; charset=UTF-8").toString()); - - // Сохранение в базу данных - ReportHistory reportHistory = new ReportHistory(); - reportHistory.setReportTitle(request.getQuery()); - reportHistory.setAuthorName("AI Research Agent"); - reportHistory.setCompanyName("Deep Research Service"); - reportHistory.setStartDate(LocalDateTime.now()); - reportHistory.setEndDate(LocalDateTime.now()); - reportHistory.setFormat("MD"); - reportHistory.setFilename(filename); - reportHistory.setFilePath(filename); - reportHistory.setFileSize(mdBytes.length); - reportHistory.setCreatedAt(LocalDateTime.now()); - - reportHistoryRepository.save(reportHistory); - } catch (Exception e) { - System.err.println("Error saving research markdown to history: " + e.getMessage()); - } - } - @GetMapping("/history") public ResponseEntity> history( @RequestParam(name = "page", defaultValue = "0") int page, @@ -254,17 +211,10 @@ public class ReportController { byte[] bytes = inputStream.readAllBytes(); inputStream.close(); - MediaType mt; - if (rh.getFormat() != null && rh.getFormat().equalsIgnoreCase("DOCX")) { - mt = MediaType.parseMediaType( - "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); - } else if (rh.getFormat() != null && (rh.getFormat().equalsIgnoreCase("MD") - || rh.getFilename() != null - && rh.getFilename().toLowerCase().endsWith(".md"))) { - mt = MediaType.parseMediaType("text/markdown; charset=UTF-8"); - } else { - mt = MediaType.APPLICATION_PDF; - } + MediaType mt = rh.getFormat() != null && rh.getFormat().equalsIgnoreCase("DOCX") + ? MediaType + .parseMediaType("application/vnd.openxmlformats-officedocument.wordprocessingml.document") + : MediaType.APPLICATION_PDF; return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + rh.getFilename() + "\"")