fix
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package kz.konturai.parser.service;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import kz.konturai.parser.dto.*;
|
||||
import kz.konturai.parser.model.MarketingAnalysisV3Document;
|
||||
@@ -29,6 +30,8 @@ public class MarketingAnalysisV3Service {
|
||||
private String highIntelligenceModel;
|
||||
|
||||
public String createAndStartAnalysis(MarketingAnalysisV3Request request, String userId) {
|
||||
log.info("Creating new Analysis V3 for user: {}", userId);
|
||||
|
||||
MarketingAnalysisV3Document doc = new MarketingAnalysisV3Document();
|
||||
doc.setUserId(userId);
|
||||
doc.setRequestData(request);
|
||||
@@ -37,6 +40,7 @@ public class MarketingAnalysisV3Service {
|
||||
doc.setUpdatedAt(LocalDateTime.now());
|
||||
|
||||
doc = repository.save(doc);
|
||||
log.info("Analysis document saved with ID: {}", doc.getId());
|
||||
|
||||
processAnalysisAsync(doc.getId(), request);
|
||||
return doc.getId();
|
||||
@@ -45,21 +49,28 @@ public class MarketingAnalysisV3Service {
|
||||
@Async("reportGenerationExecutor")
|
||||
public void processAnalysisAsync(String docId, MarketingAnalysisV3Request request) {
|
||||
try {
|
||||
log.info("[Analysis ID: {}] Started async processing", docId);
|
||||
updateStatus(docId, "PROCESSING");
|
||||
|
||||
log.info("[Analysis ID: {}] Step 1/3: Executing Deep Research", docId);
|
||||
Map<String, Object> researchPack = executeDeepResearch(request);
|
||||
saveResearchMetaData(docId, researchPack);
|
||||
|
||||
log.info("[Analysis ID: {}] Step 2/3: Building Prompts", docId);
|
||||
String systemPrompt = buildKazakhstanSystemPrompt();
|
||||
String userPrompt = buildDataDrivenUserPrompt(request, researchPack);
|
||||
|
||||
String jsonResponse = generateAiResponseWithRetry(userPrompt, systemPrompt);
|
||||
log.info("[Analysis ID: {}] Step 3/3: Calling AI Model ({})", docId, highIntelligenceModel);
|
||||
String jsonResponse = generateAiResponseWithRetry(docId, userPrompt, systemPrompt);
|
||||
|
||||
log.info("[Analysis ID: {}] Parsing and validating AI result", docId);
|
||||
MarketingAnalysisV3Result result = parseAndValidateResult(jsonResponse);
|
||||
|
||||
completeAnalysis(docId, result);
|
||||
log.info("[Analysis ID: {}] Analysis successfully completed!", docId);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Analysis V3 Failed for ID {}: {}", docId, e.getMessage(), e);
|
||||
log.error("[Analysis ID: {}] FAILED with error: {}", docId, e.getMessage(), e);
|
||||
failAnalysis(docId, e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -91,10 +102,16 @@ public class MarketingAnalysisV3Service {
|
||||
queries.add(String.format("кейс продвижение SMM %s казахстан", niche));
|
||||
|
||||
queries.parallelStream().forEach(q -> {
|
||||
// КРИТИЧЕСКИ ВАЖНО: MongoDB не поддерживает точки (.) в названиях ключей!
|
||||
// Поэтому заменяем точки на нижнее подчеркивание перед сохранением в Map.
|
||||
String safeMongoKey = q.replace(".", "_").replace("$", "");
|
||||
|
||||
try {
|
||||
pack.put(q, searchService.search(q));
|
||||
log.debug("Executing search query: {}", q);
|
||||
pack.put(safeMongoKey, searchService.search(q));
|
||||
} catch (Exception e) {
|
||||
pack.put(q, Map.of("error", e.getMessage(), "status", "ERROR"));
|
||||
log.warn("Search failed for query: {}. Error: {}", q, e.getMessage());
|
||||
pack.put(safeMongoKey, Map.of("error", e.getMessage(), "status", "ERROR"));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -102,13 +119,14 @@ public class MarketingAnalysisV3Service {
|
||||
return pack;
|
||||
}
|
||||
|
||||
private String generateAiResponseWithRetry(String userPrompt, String systemPrompt) {
|
||||
private String generateAiResponseWithRetry(String docId, String userPrompt, String systemPrompt) {
|
||||
int attempts = 0;
|
||||
int maxAttempts = 3;
|
||||
String lastError = "";
|
||||
|
||||
while (attempts < maxAttempts) {
|
||||
try {
|
||||
log.info("[Analysis ID: {}] AI Generation attempt {}/{}", docId, attempts + 1, maxAttempts);
|
||||
String response = aiService.generateWithInstructionWithModel(
|
||||
"{}",
|
||||
userPrompt,
|
||||
@@ -121,24 +139,31 @@ public class MarketingAnalysisV3Service {
|
||||
|
||||
String cleaned = cleanJson(response);
|
||||
if (cleaned != null && cleaned.startsWith("{") && cleaned.endsWith("}")) {
|
||||
// Проверка валидности JSON
|
||||
objectMapper.readTree(cleaned);
|
||||
return cleaned;
|
||||
} else {
|
||||
lastError = "Response is not a valid JSON";
|
||||
lastError = "Response is not a valid JSON structure";
|
||||
log.warn("[Analysis ID: {}] Invalid JSON received from AI", docId);
|
||||
}
|
||||
} catch (JsonProcessingException e) {
|
||||
lastError = "JSON Parse Error: " + e.getMessage();
|
||||
log.warn("[Analysis ID: {}] Failed to parse AI JSON response", docId);
|
||||
} catch (Exception e) {
|
||||
lastError = "API Error: " + e.getMessage();
|
||||
log.warn("[Analysis ID: {}] AI API Call failed: {}", docId, e.getMessage());
|
||||
}
|
||||
attempts++;
|
||||
try { Thread.sleep(2500L * attempts); } catch (InterruptedException ignored) {}
|
||||
try { Thread.sleep(3000L * attempts); } catch (InterruptedException ignored) {}
|
||||
}
|
||||
throw new RuntimeException("Failed to generate valid JSON after " + maxAttempts + " attempts. Last error: " + lastError);
|
||||
}
|
||||
|
||||
private MarketingAnalysisV3Result parseAndValidateResult(String json) throws Exception {
|
||||
return objectMapper.readValue(json, MarketingAnalysisV3Result.class);
|
||||
// Создаем безопасную копию маппера, чтобы он не падал, если ИИ придумает новые поля
|
||||
ObjectMapper safeMapper = this.objectMapper.copy();
|
||||
safeMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
return safeMapper.readValue(json, MarketingAnalysisV3Result.class);
|
||||
}
|
||||
|
||||
private String cleanJson(String response) {
|
||||
@@ -163,10 +188,16 @@ public class MarketingAnalysisV3Service {
|
||||
}
|
||||
|
||||
private void saveResearchMetaData(String id, Map<String, Object> researchPack) {
|
||||
repository.findById(id).ifPresent(doc -> {
|
||||
doc.setResearchMetaData(researchPack);
|
||||
repository.save(doc);
|
||||
});
|
||||
try {
|
||||
repository.findById(id).ifPresent(doc -> {
|
||||
doc.setResearchMetaData(researchPack);
|
||||
repository.save(doc);
|
||||
log.debug("[Analysis ID: {}] Research metadata successfully saved to DB", id);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("[Analysis ID: {}] CRITICAL: Failed to save research metadata to MongoDB. Check for invalid characters in keys. Error: {}", id, e.getMessage());
|
||||
throw e; // Пробрасываем дальше, чтобы уйти в статус FAILED
|
||||
}
|
||||
}
|
||||
|
||||
private void completeAnalysis(String id, MarketingAnalysisV3Result result) {
|
||||
@@ -308,28 +339,6 @@ public class MarketingAnalysisV3Service {
|
||||
"reviews": 0,
|
||||
"strengths": ["string"],
|
||||
"weaknesses": ["string"]
|
||||
},
|
||||
{
|
||||
"name": "РЕАЛЬНОЕ НАЗВАНИЕ БРЕНДА 2",
|
||||
"platform": "string",
|
||||
"followers": 0,
|
||||
"postsPerMonth": 0,
|
||||
"er": 0.0,
|
||||
"rating": 0.0,
|
||||
"reviews": 0,
|
||||
"strengths": ["string"],
|
||||
"weaknesses": ["string"]
|
||||
},
|
||||
{
|
||||
"name": "РЕАЛЬНОЕ НАЗВАНИЕ БРЕНДА 3",
|
||||
"platform": "string",
|
||||
"followers": 0,
|
||||
"postsPerMonth": 0,
|
||||
"er": 0.0,
|
||||
"rating": 0.0,
|
||||
"reviews": 0,
|
||||
"strengths": ["string"],
|
||||
"weaknesses": ["string"]
|
||||
}
|
||||
],
|
||||
"4_content_profile": {
|
||||
|
||||
Reference in New Issue
Block a user