fix
This commit is contained in:
@@ -13,6 +13,8 @@ import kz.konturai.parser.service.MinIOService;
|
||||
import kz.konturai.parser.service.PostingTaskService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -200,6 +202,30 @@ public class MarketingAnalysisV3Controller {
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/videos/{videoFilename}")
|
||||
public ResponseEntity<Resource> getPostVideo(
|
||||
@RequestHeader(value = "Authorization", required = false) String authHeader,
|
||||
@PathVariable String videoFilename
|
||||
) {
|
||||
String userId = extractUserIdFromHeader(authHeader);
|
||||
if (userId == null) return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
|
||||
try {
|
||||
if (!minIOService.fileExists(videoFilename)) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
InputStream inputStream = minIOService.downloadFile(videoFilename);
|
||||
InputStreamResource resource = new InputStreamResource(inputStream);
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_TYPE, "video/mp4")
|
||||
.header(HttpHeaders.CACHE_CONTROL, "public, max-age=3600")
|
||||
.body(resource);
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.internalServerError().build();
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{analysisId}/strategy-preview")
|
||||
public ResponseEntity<?> previewStrategy(
|
||||
@RequestHeader(value = "Authorization", required = false) String authHeader,
|
||||
@@ -283,7 +309,10 @@ public class MarketingAnalysisV3Controller {
|
||||
MarketingStrategy strategy = strategyOpt.get();
|
||||
if (!strategy.getUserId().equals(userId)) return forbiddenResponse();
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(strategy));
|
||||
Map<String, Object> result = strategyService.getStrategyResult(strategyId);
|
||||
if (result == null) return notFoundResponse("Ошибка сборки стратегии");
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
return internalErrorResponse(e);
|
||||
}
|
||||
@@ -305,7 +334,10 @@ public class MarketingAnalysisV3Controller {
|
||||
Optional<MarketingStrategy> strategyOpt = strategyService.getStrategyByAnalysisId(analysisId);
|
||||
if (strategyOpt.isEmpty()) return notFoundResponse("Стратегия не найдена");
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(strategyOpt.get()));
|
||||
Map<String, Object> result = strategyService.getStrategyResult(strategyOpt.get().getId());
|
||||
if (result == null) return notFoundResponse("Ошибка сборки стратегии");
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(result));
|
||||
} catch (Exception e) {
|
||||
return internalErrorResponse(e);
|
||||
}
|
||||
@@ -451,6 +483,8 @@ public class MarketingAnalysisV3Controller {
|
||||
"postIndex", postIndex,
|
||||
"imageUrl", updatedItem.getImageUrl() != null ? updatedItem.getImageUrl() : "",
|
||||
"imageFilename", updatedItem.getImageFilename() != null ? updatedItem.getImageFilename() : "",
|
||||
"videoUrl", updatedItem.getVideoUrl() != null ? updatedItem.getVideoUrl() : "",
|
||||
"videoFilename", updatedItem.getVideoFilename() != null ? updatedItem.getVideoFilename() : "",
|
||||
"theme", updatedItem.getTheme() != null ? updatedItem.getTheme() : "",
|
||||
"platform", updatedItem.getPlatform() != null ? updatedItem.getPlatform() : "",
|
||||
"publishDate", updatedItem.getPublishDate()
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package kz.konturai.parser.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -7,6 +9,7 @@ import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -15,7 +18,8 @@ import java.util.Map;
|
||||
@Slf4j
|
||||
public class GeminiVideoGenerationService {
|
||||
|
||||
private final RestTemplate restTemplate = new RestTemplate(); // Можно заинжектить через @Bean, если есть
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@Value("${gemini.veo.api.url:https://generativelanguage.googleapis.com/v1beta/models/veo:generateVideo}")
|
||||
private String videoApiUrl;
|
||||
@@ -24,7 +28,6 @@ public class GeminiVideoGenerationService {
|
||||
private String apiKey;
|
||||
|
||||
public byte[] generateVideo(String prompt) {
|
||||
log.info("Запуск генерации видео через Gemini Veo. Промпт: {}", prompt);
|
||||
try {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
@@ -37,22 +40,46 @@ public class GeminiVideoGenerationService {
|
||||
|
||||
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
|
||||
|
||||
ResponseEntity<byte[]> response = restTemplate.exchange(
|
||||
ResponseEntity<String> response = restTemplate.exchange(
|
||||
videoApiUrl,
|
||||
HttpMethod.POST,
|
||||
entity,
|
||||
byte[].class
|
||||
String.class
|
||||
);
|
||||
|
||||
if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
|
||||
log.info("Видео успешно сгенерировано. Размер: {} байт", response.getBody().length);
|
||||
return response.getBody();
|
||||
String jsonBody = response.getBody();
|
||||
JsonNode rootNode = objectMapper.readTree(jsonBody);
|
||||
String base64Video = null;
|
||||
|
||||
if (rootNode.has("predictions") && rootNode.get("predictions").isArray()) {
|
||||
JsonNode prediction = rootNode.get("predictions").get(0);
|
||||
if (prediction.has("bytesBase64Encoded")) {
|
||||
base64Video = prediction.get("bytesBase64Encoded").asText();
|
||||
}
|
||||
} else if (rootNode.has("candidates") && rootNode.get("candidates").isArray()) {
|
||||
JsonNode parts = rootNode.at("/candidates/0/content/parts");
|
||||
if (parts.isArray() && parts.size() > 0 && parts.get(0).has("inlineData")) {
|
||||
base64Video = parts.get(0).at("/inlineData/data").asText();
|
||||
}
|
||||
} else if (rootNode.has("videoBase64")) {
|
||||
base64Video = rootNode.get("videoBase64").asText();
|
||||
} else if (rootNode.has("base64")) {
|
||||
base64Video = rootNode.get("base64").asText();
|
||||
}
|
||||
|
||||
if (base64Video != null && !base64Video.isEmpty()) {
|
||||
return Base64.getDecoder().decode(base64Video);
|
||||
} else {
|
||||
if (!jsonBody.trim().startsWith("{")) {
|
||||
return jsonBody.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
log.error("Ошибка API генерации видео. Код: {}", response.getStatusCode());
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Критическая ошибка при генерации видео: {}", e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import kz.konturai.parser.dto.StatusHistoryEntry;
|
||||
import kz.konturai.parser.enums.StrategyModel;
|
||||
import kz.konturai.parser.model.MarketingAnalysisV3Document;
|
||||
import kz.konturai.parser.model.MarketingStrategy;
|
||||
import kz.konturai.parser.model.PostingTask;
|
||||
import kz.konturai.parser.repository.MarketingAnalysisV3Repository;
|
||||
import kz.konturai.parser.repository.MarketingStrategyRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -20,11 +21,7 @@ import org.springframework.stereotype.Service;
|
||||
import java.io.InputStream;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@@ -36,6 +33,7 @@ public class MarketingStrategyV3Service {
|
||||
private final OpenAIAnalyticsService aiService;
|
||||
private final ImageGenerationService imageGenerationService;
|
||||
private final GeminiVideoGenerationService geminiVideoService;
|
||||
private final PostingTaskService postingTaskService;
|
||||
private final MinIOService minIOService;
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper()
|
||||
@@ -127,6 +125,71 @@ public class MarketingStrategyV3Service {
|
||||
}
|
||||
}
|
||||
|
||||
// ИДЕАЛЬНЫЙ СБОРЩИК ОТВЕТА (Интеграция с Автопостингом)
|
||||
public Map<String, Object> getStrategyResult(String strategyId) {
|
||||
Optional<MarketingStrategy> optStrategy = repository.findById(strategyId);
|
||||
if (optStrategy.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MarketingStrategy strategy = optStrategy.get();
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("strategyId", strategy.getId());
|
||||
response.put("analysisId", strategy.getAnalysisId());
|
||||
response.put("status", strategy.getStatus());
|
||||
response.put("createdAt", strategy.getCreatedAt());
|
||||
response.put("completedAt", strategy.getCompletedAt());
|
||||
response.put("durationWeeks", strategy.getDurationWeeks());
|
||||
response.put("priorityPlatforms", strategy.getPriorityPlatforms());
|
||||
response.put("strategyData", strategy.getStrategyData());
|
||||
|
||||
if (strategy.getWeeklyPlans() != null && strategy.getPostCalendar() != null) {
|
||||
Map<String, Object> strategyContent = new HashMap<>();
|
||||
strategyContent.put("weeklyPlans", strategy.getWeeklyPlans());
|
||||
|
||||
List<Map<String, Object>> postCalendarList = new ArrayList<>();
|
||||
List<PostingTask> tasks = postingTaskService.getStrategyTasks(strategyId);
|
||||
|
||||
for (MarketingStrategy.PostCalendarItem item : strategy.getPostCalendar()) {
|
||||
Map<String, Object> dtoItem = new HashMap<>();
|
||||
dtoItem.put("publishDate", item.getPublishDate());
|
||||
dtoItem.put("platform", item.getPlatform());
|
||||
dtoItem.put("contentType", item.getContentType());
|
||||
dtoItem.put("theme", item.getTheme());
|
||||
dtoItem.put("postText", item.getPostText());
|
||||
dtoItem.put("hashtags", item.getHashtags());
|
||||
dtoItem.put("publishTime", item.getPublishTime());
|
||||
dtoItem.put("imageUrl", item.getImageUrl());
|
||||
dtoItem.put("imageFilename", item.getImageFilename());
|
||||
dtoItem.put("videoUrl", item.getVideoUrl());
|
||||
dtoItem.put("videoFilename", item.getVideoFilename());
|
||||
|
||||
Optional<PostingTask> matchingTask = tasks.stream()
|
||||
.filter(task -> task.getPublishDate() != null && item.getPublishDate() != null
|
||||
&& task.getPublishDate().equals(item.getPublishDate())
|
||||
&& task.getPlatform() != null && item.getPlatform() != null
|
||||
&& task.getPlatform().equalsIgnoreCase(item.getPlatform()))
|
||||
.findFirst();
|
||||
|
||||
if (matchingTask.isPresent()) {
|
||||
dtoItem.put("taskId", matchingTask.get().getId());
|
||||
dtoItem.put("taskStatus", matchingTask.get().getStatus());
|
||||
} else {
|
||||
dtoItem.put("taskStatus", null);
|
||||
}
|
||||
|
||||
postCalendarList.add(dtoItem);
|
||||
}
|
||||
strategyContent.put("postCalendar", postCalendarList);
|
||||
|
||||
response.put("strategy", strategyContent);
|
||||
response.put("postCalendar", postCalendarList);
|
||||
response.put("weeklyPlans", strategy.getWeeklyPlans());
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public MarketingStrategy.PostCalendarItem regeneratePostImage(String strategyId, int postIndex) {
|
||||
Optional<MarketingStrategy> optStrategy = repository.findById(strategyId);
|
||||
if (optStrategy.isEmpty()) {
|
||||
|
||||
Reference in New Issue
Block a user