This commit is contained in:
root
2025-10-05 17:31:17 +05:00
parent f57e614c7f
commit 129302c136
@@ -10,6 +10,7 @@ import kz.konturai.parser.model.ReportHistory;
import kz.konturai.parser.repository.ReportHistoryRepository; import kz.konturai.parser.repository.ReportHistoryRepository;
import kz.konturai.parser.service.ReportGenerationService; import kz.konturai.parser.service.ReportGenerationService;
import kz.konturai.parser.service.DeepResearchService; import kz.konturai.parser.service.DeepResearchService;
import kz.konturai.parser.service.ResearchPdfService;
import kz.konturai.parser.service.ReportSynthesisService; import kz.konturai.parser.service.ReportSynthesisService;
import kz.konturai.parser.service.MinIOService; import kz.konturai.parser.service.MinIOService;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@@ -37,17 +38,20 @@ public class ReportController {
private final ReportHistoryRepository reportHistoryRepository; private final ReportHistoryRepository reportHistoryRepository;
private final MinIOService minIOService; private final MinIOService minIOService;
private final DeepResearchService deepResearchService; private final DeepResearchService deepResearchService;
private final ResearchPdfService researchPdfService;
private final ReportSynthesisService reportSynthesisService; private final ReportSynthesisService reportSynthesisService;
public ReportController(ReportGenerationService reportGenerationService, public ReportController(ReportGenerationService reportGenerationService,
ReportHistoryRepository reportHistoryRepository, ReportHistoryRepository reportHistoryRepository,
MinIOService minIOService, MinIOService minIOService,
DeepResearchService deepResearchService, DeepResearchService deepResearchService,
ResearchPdfService researchPdfService,
ReportSynthesisService reportSynthesisService) { ReportSynthesisService reportSynthesisService) {
this.reportGenerationService = reportGenerationService; this.reportGenerationService = reportGenerationService;
this.reportHistoryRepository = reportHistoryRepository; this.reportHistoryRepository = reportHistoryRepository;
this.minIOService = minIOService; this.minIOService = minIOService;
this.deepResearchService = deepResearchService; this.deepResearchService = deepResearchService;
this.researchPdfService = researchPdfService;
this.reportSynthesisService = reportSynthesisService; this.reportSynthesisService = reportSynthesisService;
} }
@@ -96,8 +100,8 @@ public class ReportController {
// Предполагаемое время завершения // Предполагаемое время завершения
LocalDateTime estimatedCompletion = LocalDateTime.now().plusMinutes(8); LocalDateTime estimatedCompletion = LocalDateTime.now().plusMinutes(8);
// Асинхронный процесс: deep-research -> synthesis via Ollama -> Markdown -> // Запускаем асинхронный процесс: deep-research -> synthesis via Ollama -> PDF
// сохранение // -> сохранение
deepResearchService.generateReportAsync(deepRequest) deepResearchService.generateReportAsync(deepRequest)
.publishOn(Schedulers.boundedElastic()) .publishOn(Schedulers.boundedElastic())
.flatMap(researchResponse -> { .flatMap(researchResponse -> {
@@ -118,12 +122,10 @@ public class ReportController {
.map(tuple -> { .map(tuple -> {
DeepResearchResponse researchResponse = (DeepResearchResponse) tuple[0]; DeepResearchResponse researchResponse = (DeepResearchResponse) tuple[0];
String synthesizedMarkdown = (String) tuple[1]; String synthesizedMarkdown = (String) tuple[1];
String finalMarkdown = buildMarkdownWithSources(synthesizedMarkdown, byte[] pdfBytes = researchPdfService.generatePdfReport(request.getQuery(),
researchResponse.getVisitedUrls()); synthesizedMarkdown, researchResponse.getVisitedUrls());
byte[] mdBytes = finalMarkdown String filename = "research_report_" + System.currentTimeMillis() + ".pdf";
.getBytes(java.nio.charset.StandardCharsets.UTF_8); saveResearchReportToHistory(request, filename, pdfBytes, researchResponse);
String filename = "research_report_" + System.currentTimeMillis() + ".md";
saveResearchMarkdownToHistory(request, filename, mdBytes, researchResponse);
return true; return true;
}) })
.doOnError(e -> { .doOnError(e -> {
@@ -149,25 +151,6 @@ public class ReportController {
return ResponseEntity.ok(ApiResponse.success("Исследовательский отчёт поставлен в очередь", response)); return ResponseEntity.ok(ApiResponse.success("Исследовательский отчёт поставлен в очередь", response));
} }
private String buildMarkdownWithSources(String synthesizedMarkdown, java.util.List<String> 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, private void saveResearchReportToHistory(ResearchReportRequest request, String filename,
byte[] pdfBytes, DeepResearchResponse researchResponse) { byte[] pdfBytes, DeepResearchResponse researchResponse) {
try { 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") @GetMapping("/history")
public ResponseEntity<PageResponse<ReportHistory>> history( public ResponseEntity<PageResponse<ReportHistory>> history(
@RequestParam(name = "page", defaultValue = "0") int page, @RequestParam(name = "page", defaultValue = "0") int page,
@@ -254,17 +211,10 @@ public class ReportController {
byte[] bytes = inputStream.readAllBytes(); byte[] bytes = inputStream.readAllBytes();
inputStream.close(); inputStream.close();
MediaType mt; MediaType mt = rh.getFormat() != null && rh.getFormat().equalsIgnoreCase("DOCX")
if (rh.getFormat() != null && rh.getFormat().equalsIgnoreCase("DOCX")) { ? MediaType
mt = MediaType.parseMediaType( .parseMediaType("application/vnd.openxmlformats-officedocument.wordprocessingml.document")
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"); : MediaType.APPLICATION_PDF;
} 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;
}
return ResponseEntity.ok() return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, .header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + rh.getFilename() + "\"") "attachment; filename=\"" + rh.getFilename() + "\"")