h-lab/src/main/java/com/hlab/yanalyst/service/AnalysisWorkflowService.java

181 lines
7.6 KiB
Java

package com.hlab.yanalyst.service;
import com.hlab.yanalyst.domain.opal.*;
import com.hlab.yanalyst.domain.script.ScriptGen;
import com.hlab.yanalyst.domain.script.ScriptGenRepository;
import com.hlab.yanalyst.domain.video.YtVideo;
import com.hlab.yanalyst.domain.video.YtVideoRepository;
import com.hlab.yanalyst.service.external.ExternalApiService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
@Service
@RequiredArgsConstructor
@Transactional
public class AnalysisWorkflowService {
private final YtVideoRepository ytVideoRepository;
private final ScriptGenRepository scriptGenRepository;
private final OpalDraftRepository opalDraftRepository;
private final OpalFinalRepository opalFinalRepository;
private final OpalFinalAssetRepository opalFinalAssetRepository;
private final ExternalApiService externalApiService;
private final ObjectMapper objectMapper;
public ScriptGen generateScript(Long videoId) {
YtVideo video = ytVideoRepository.findById(videoId)
.orElseThrow(() -> new IllegalArgumentException("Video not found"));
String scriptContent = externalApiService.generateScript(video.getVideoUrl());
ScriptGen scriptGen = scriptGenRepository.findById(videoId).orElse(new ScriptGen());
if (scriptGen.getVideoId() == null) {
scriptGen.setVideo(video);
}
scriptGen.setResponseText(scriptContent);
scriptGen.setStatus("SUCCESS");
// Update video status
video.setStatus("SCRIPT_READY");
return scriptGenRepository.save(scriptGen);
}
public OpalDraft generateDraft(Long videoId, String feedback, String mode) {
YtVideo video = ytVideoRepository.findById(videoId)
.orElseThrow(() -> new IllegalArgumentException("Video not found"));
ScriptGen scriptGen = scriptGenRepository.findById(videoId)
.orElseThrow(() -> new IllegalArgumentException("Script not found"));
var draftDto = externalApiService.generateOpalDraft(scriptGen.getResponseText(), feedback, mode);
OpalDraft draft = new OpalDraft();
draft.setVideo(video);
draft.setOldScriptSummary(draftDto.getOldScriptSummary());
draft.setNewScriptSummary(draftDto.getNewScriptSummary());
// For compatibility, we can concatenate or just leave responseText empty/null, or use New Summary as main response
draft.setResponseText(draftDto.getNewScriptSummary());
draft.setUserFeedback(feedback);
Integer maxVersion = opalDraftRepository.findByVideo_VideoIdOrderByVersionNoDesc(videoId)
.stream().findFirst().map(OpalDraft::getVersionNo).orElse(0);
draft.setVersionNo(maxVersion + 1);
draft.setStatus("SUCCESS");
video.setStatus("DRAFTING");
return opalDraftRepository.save(draft);
}
public OpalFinal acceptDraft(Long videoId, Long draftId) {
YtVideo video = ytVideoRepository.findById(videoId).orElseThrow();
OpalDraft draft = opalDraftRepository.findById(draftId).orElseThrow();
if (!draft.getVideo().getVideoId().equals(videoId)) {
throw new IllegalArgumentException("Draft does not match video");
}
// Deactivate existing active final
opalFinalRepository.findByVideo_VideoIdAndIsActiveTrue(videoId)
.ifPresent(existing -> {
existing.setIsActive(false);
opalFinalRepository.save(existing);
});
// Mark draft accepted
draft.setIsAccepted(true);
draft.setAcceptedAt(LocalDateTime.now());
opalDraftRepository.save(draft);
OpalFinal opalFinal = new OpalFinal();
opalFinal.setVideo(video);
opalFinal.setDraft(draft);
opalFinal.setFinalScriptText(draft.getResponseText());
opalFinal.setIsActive(true);
return opalFinalRepository.save(opalFinal);
}
public OpalFinalAsset generateFinalAsset(Long videoId) {
YtVideo video = ytVideoRepository.findById(videoId).orElseThrow();
OpalFinal activeFinal = opalFinalRepository.findByVideo_VideoIdAndIsActiveTrue(videoId)
.orElse(null);
if (activeFinal == null) {
OpalDraft latestDraft = opalDraftRepository.findByVideo_VideoIdOrderByVersionNoDesc(videoId)
.stream().findFirst()
.orElseThrow(() -> new IllegalArgumentException("No active final script and no drafts found. Please generate a draft first."));
activeFinal = new OpalFinal();
activeFinal.setVideo(video);
activeFinal.setDraft(latestDraft);
activeFinal.setIsActive(true);
activeFinal.setFinalScriptText("");
activeFinal = opalFinalRepository.save(activeFinal);
}
// 1. Fetch updated final script from external source (GDoc)
String updatedFinalScript = externalApiService.fetchFinalScript();
// 2. Update and save active final script
activeFinal.setFinalScriptText(updatedFinalScript);
opalFinalRepository.save(activeFinal);
// 3. Generate asset metadata
var assetMap = externalApiService.generateFinalAsset(activeFinal.getFinalScriptText());
OpalFinalAsset asset = new OpalFinalAsset();
asset.setOpalFinal(activeFinal);
try {
asset.setAssetJson(objectMapper.writeValueAsString(assetMap));
asset.setTitle((String) assetMap.get("title"));
asset.setSummary((String) assetMap.get("summary"));
asset.setTimeline(objectMapper.writeValueAsString(assetMap.get("timeline")));
asset.setVideoPrompt((String) assetMap.get("video_prompt"));
asset.setImageUrls(objectMapper.writeValueAsString(assetMap.get("image_urls")));
} catch (Exception e) {
throw new RuntimeException("JSON processing error", e);
}
video.setStatus("FINALIZED");
return opalFinalAssetRepository.save(asset);
}
public boolean toggleComplete(Long videoId) {
YtVideo video = ytVideoRepository.findById(videoId)
.orElseThrow(() -> new IllegalArgumentException("Video not found"));
boolean newState = video.getIsCompleted() == null ? true : !video.getIsCompleted();
video.setIsCompleted(newState);
ytVideoRepository.save(video);
return newState;
}
public void updateFinalAsset(Long videoId, String newText) {
OpalFinal opalFinal = opalFinalRepository.findByVideo_VideoIdAndIsActiveTrue(videoId)
.orElseThrow(() -> new IllegalArgumentException("No active final asset found for videoId: " + videoId));
opalFinal.setFinalScriptText(newText);
opalFinalRepository.save(opalFinal);
}
public void generateOpening(Long videoId, String docId) {
YtVideo video = ytVideoRepository.findById(videoId)
.orElseThrow(() -> new IllegalArgumentException("Video not found"));
String openingScript = externalApiService.fetchOpeningScript(docId);
video.setOpeningScript(openingScript);
ytVideoRepository.save(video);
}
public void resetOpening(Long videoId) {
YtVideo video = ytVideoRepository.findById(videoId)
.orElseThrow(() -> new IllegalArgumentException("Video not found"));
video.setOpeningScript(null);
ytVideoRepository.save(video);
}
}