.
This commit is contained in:
@@ -50,6 +50,36 @@ public class ReportGenerationService {
|
||||
}
|
||||
}
|
||||
|
||||
private static class Sections {
|
||||
private final String annotation;
|
||||
private final String introduction;
|
||||
private final String mainNarrative;
|
||||
private final String recommendations;
|
||||
|
||||
private Sections(String annotation, String introduction, String mainNarrative, String recommendations) {
|
||||
this.annotation = annotation == null ? "" : annotation;
|
||||
this.introduction = introduction == null ? "" : introduction;
|
||||
this.mainNarrative = mainNarrative == null ? "" : mainNarrative;
|
||||
this.recommendations = recommendations == null ? "" : recommendations;
|
||||
}
|
||||
|
||||
public String getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
public String getIntroduction() {
|
||||
return introduction;
|
||||
}
|
||||
|
||||
public String getMainNarrative() {
|
||||
return mainNarrative;
|
||||
}
|
||||
|
||||
public String getRecommendations() {
|
||||
return recommendations;
|
||||
}
|
||||
}
|
||||
|
||||
private final MarketItemRepository marketItemRepository;
|
||||
private final OllamaAnalyticsService ollamaAnalyticsService;
|
||||
private final ReportHistoryRepository reportHistoryRepository;
|
||||
@@ -73,17 +103,17 @@ public class ReportGenerationService {
|
||||
.findByPublishedAtBetween(start, end, org.springframework.data.domain.Pageable.unpaged())
|
||||
.getContent();
|
||||
|
||||
String annotation = buildAnnotation(items);
|
||||
Sections sections = buildSections(req, items);
|
||||
|
||||
ReportBinary rb;
|
||||
if ("DOCX".equalsIgnoreCase(req.getFormat())) {
|
||||
byte[] docx = buildDocx(req, items, annotation);
|
||||
byte[] docx = buildDocx(req, items, sections);
|
||||
String filename = "report_" + end.toLocalDate().toString() + "-" + System.currentTimeMillis() + ".docx";
|
||||
rb = new ReportBinary(filename,
|
||||
MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
|
||||
docx);
|
||||
} else {
|
||||
byte[] pdf = buildPdf(req, items, annotation);
|
||||
byte[] pdf = buildPdf(req, items, sections);
|
||||
String filename = "report_" + end.toLocalDate().toString() + "-" + System.currentTimeMillis() + ".pdf";
|
||||
rb = new ReportBinary(filename, MediaType.APPLICATION_PDF, pdf);
|
||||
}
|
||||
@@ -114,11 +144,15 @@ public class ReportGenerationService {
|
||||
}
|
||||
}
|
||||
|
||||
private String buildAnnotation(List<MarketItem> items) {
|
||||
String combined = items.stream()
|
||||
private String getCombinedSummaries(List<MarketItem> items) {
|
||||
return items.stream()
|
||||
.map(i -> i.getAnalytics() != null ? i.getAnalytics().getSummary() : null)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.joining("\n\n"));
|
||||
}
|
||||
|
||||
private String buildAnnotation(List<MarketItem> items) {
|
||||
String combined = getCombinedSummaries(items);
|
||||
if (combined.isBlank()) {
|
||||
return "";
|
||||
}
|
||||
@@ -127,7 +161,27 @@ public class ReportGenerationService {
|
||||
return res == null ? "" : res;
|
||||
}
|
||||
|
||||
private byte[] buildDocx(ReportGenerateRequest req, List<MarketItem> items, String annotation) {
|
||||
private Sections buildSections(ReportGenerateRequest req, List<MarketItem> items) {
|
||||
String combined = getCombinedSummaries(items);
|
||||
if (combined.isBlank()) {
|
||||
return new Sections("", "", "", "");
|
||||
}
|
||||
String annotation = ollamaAnalyticsService.generateWithInstruction(combined,
|
||||
"На основе кратких сводок новостей напиши краткое содержание (2-3 абзаца), выделив ключевые тренды и события. Стиль: деловой, нейтральный.");
|
||||
|
||||
String intro = ollamaAnalyticsService.generateWithInstruction(combined,
|
||||
"Напиши краткое введение к аналитическому отчёту за период. Укажи цель отчёта, источники данных и подход к анализу. Объём: 1 абзац.");
|
||||
|
||||
String mainPart = ollamaAnalyticsService.generateWithInstruction(combined,
|
||||
"Сформируй основную часть отчёта: перечисли и кратко объясни 3-5 ключевых тенденций и событий периода, добавь замеченные риски и возможности. Используй маркированные пункты и короткие абзацы.");
|
||||
|
||||
String recs = ollamaAnalyticsService.generateWithInstruction(combined,
|
||||
"На основе сводок сформулируй практические рекомендации (4-6 пунктов) для бизнеса/маркетинга. Формат: маркированный список, краткие и конкретные формулировки.");
|
||||
|
||||
return new Sections(annotation, intro, mainPart, recs);
|
||||
}
|
||||
|
||||
private byte[] buildDocx(ReportGenerateRequest req, List<MarketItem> items, Sections sections) {
|
||||
try (XWPFDocument doc = new XWPFDocument(); ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
||||
DateTimeFormatter dt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
||||
|
||||
@@ -144,16 +198,19 @@ public class ReportGenerationService {
|
||||
|
||||
// Annotation
|
||||
addHeading(doc, "Краткое содержание");
|
||||
addParagraph(doc, annotation.isBlank() ? "(недоступно)" : annotation);
|
||||
addParagraph(doc, sections.getAnnotation().isBlank() ? "(недоступно)" : sections.getAnnotation());
|
||||
|
||||
// Intro
|
||||
addHeading(doc, "Введение");
|
||||
addParagraph(doc, String.format(
|
||||
"Целью данного отчёта является анализ новостного фона в сфере маркетинга и бизнеса за период с %s по %s. Были проанализированы публикации из ключевых источников для выявления основных трендов.",
|
||||
req.getStartDate().format(dt), req.getEndDate().format(dt)));
|
||||
addParagraph(doc, sections.getIntroduction().isBlank()
|
||||
? String.format(
|
||||
"Целью данного отчёта является анализ новостного фона в сфере маркетинга и бизнеса за период с %s по %s. Были проанализированы публикации из ключевых источников для выявления основных трендов.",
|
||||
req.getStartDate().format(dt), req.getEndDate().format(dt))
|
||||
: sections.getIntroduction());
|
||||
|
||||
// Main
|
||||
addHeading(doc, "Основная часть");
|
||||
addParagraph(doc, sections.getMainNarrative());
|
||||
addSubheading(doc, "Ключевые публикации");
|
||||
List<MarketItem> top = items.stream()
|
||||
.sorted(Comparator
|
||||
@@ -187,7 +244,9 @@ public class ReportGenerationService {
|
||||
|
||||
// Recommendations
|
||||
addHeading(doc, "Рекомендации");
|
||||
addParagraph(doc, "Рассмотрите возможность усиления присутствия в медиа по ключевым темам отчёта.");
|
||||
addParagraph(doc, sections.getRecommendations().isBlank()
|
||||
? "Рассмотрите возможность усиления присутствия в медиа по ключевым темам отчёта."
|
||||
: sections.getRecommendations());
|
||||
|
||||
// Bibliography
|
||||
addHeading(doc, "Список литературы");
|
||||
@@ -207,7 +266,7 @@ public class ReportGenerationService {
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] buildPdf(ReportGenerateRequest req, List<MarketItem> items, String annotation) {
|
||||
private byte[] buildPdf(ReportGenerateRequest req, List<MarketItem> items, Sections sections) {
|
||||
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
||||
Document pdf = new Document();
|
||||
PdfWriter.getInstance(pdf, out);
|
||||
@@ -223,14 +282,17 @@ public class ReportGenerationService {
|
||||
"\nСодержание: Аннотация, Введение, Основная часть, Рекомендации, Список литературы, Приложения\n"));
|
||||
|
||||
pdf.add(new Paragraph("Краткое содержание"));
|
||||
pdf.add(new Paragraph(annotation.isBlank() ? "(недоступно)" : annotation));
|
||||
pdf.add(new Paragraph(sections.getAnnotation().isBlank() ? "(недоступно)" : sections.getAnnotation()));
|
||||
|
||||
pdf.add(new Paragraph("Введение"));
|
||||
pdf.add(new Paragraph(String.format(
|
||||
"Целью данного отчёта является анализ новостного фона в сфере маркетинга и бизнеса за период с %s по %s. Были проанализированы публикации из ключевых источников для выявления основных трендов.",
|
||||
req.getStartDate().format(dt), req.getEndDate().format(dt))));
|
||||
pdf.add(new Paragraph(sections.getIntroduction().isBlank()
|
||||
? String.format(
|
||||
"Целью данного отчёта является анализ новостного фона в сфере маркетинга и бизнеса за период с %s по %s. Были проанализированы публикации из ключевых источников для выявления основных трендов.",
|
||||
req.getStartDate().format(dt), req.getEndDate().format(dt))
|
||||
: sections.getIntroduction()));
|
||||
|
||||
pdf.add(new Paragraph("Основная часть"));
|
||||
pdf.add(new Paragraph(sections.getMainNarrative()));
|
||||
pdf.add(new Paragraph("Ключевые публикации"));
|
||||
List<MarketItem> top = items.stream()
|
||||
.sorted(Comparator
|
||||
@@ -262,7 +324,9 @@ public class ReportGenerationService {
|
||||
pdf.add(new Paragraph("Персоны: " + formatTop(persons)));
|
||||
|
||||
pdf.add(new Paragraph("Рекомендации"));
|
||||
pdf.add(new Paragraph("Рассмотрите возможность усиления присутствия в медиа по ключевым темам отчёта."));
|
||||
pdf.add(new Paragraph(sections.getRecommendations().isBlank()
|
||||
? "Рассмотрите возможность усиления присутствия в медиа по ключевым темам отчёта."
|
||||
: sections.getRecommendations()));
|
||||
|
||||
pdf.add(new Paragraph("Список литературы"));
|
||||
for (MarketItem mi : items) {
|
||||
|
||||
Reference in New Issue
Block a user