.
This commit is contained in:
@@ -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() + "\"")
|
||||||
|
|||||||
Reference in New Issue
Block a user