feat:생성 이력 상세보기 모달 + YouTube Shorts 텍스트 생성

- Veo3Controller에 show 엔드포인트 추가 (시나리오/프롬프트 상세 데이터 반환)
- YouTube Shorts 제목/설명/해시태그 자동 생성 (완료된 영상)
- DetailModal 컴포넌트: 탭 UI (시나리오/프롬프트 | YouTube 텍스트)
- 이력 테이블 행 클릭 시 상세 모달 표시
- 복사 버튼으로 YouTube 텍스트 클립보드 복사

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
김보곤
2026-02-15 13:58:56 +09:00
parent 06c6005771
commit 0859a14e33
3 changed files with 357 additions and 5 deletions

View File

@@ -256,6 +256,95 @@ public function preview(int $id): Response|RedirectResponse|JsonResponse
]);
}
/**
* 생성 이력 상세 (시나리오, 프롬프트, YouTube 텍스트 등)
*/
public function show(int $id): JsonResponse
{
$video = VideoGeneration::where('user_id', auth()->id())->findOrFail($id);
$scenario = $video->scenario ?? [];
$scenes = $scenario['scenes'] ?? [];
// YouTube Shorts 텍스트 생성 (완료된 영상만)
$youtubeText = null;
if ($video->status === VideoGeneration::STATUS_COMPLETED) {
$youtubeText = $this->buildYoutubeText($video, $scenario, $scenes);
}
return response()->json([
'success' => true,
'data' => [
'id' => $video->id,
'keyword' => $video->keyword,
'title' => $video->title,
'status' => $video->status,
'progress' => $video->progress,
'current_step' => $video->current_step,
'error_message' => $video->error_message,
'cost_usd' => $video->cost_usd,
'created_at' => $video->created_at?->toIso8601String(),
'updated_at' => $video->updated_at?->toIso8601String(),
'scenario' => $scenario,
'scenes' => array_map(function ($scene) {
return [
'scene_number' => $scene['scene_number'] ?? null,
'scene_type' => $scene['scene_type'] ?? null,
'narration' => $scene['narration'] ?? '',
'visual_prompt' => $scene['visual_prompt'] ?? '',
'duration' => $scene['duration'] ?? 0,
'mood' => $scene['mood'] ?? '',
];
}, $scenes),
'clips_data' => $video->clips_data,
'youtube_text' => $youtubeText,
],
]);
}
/**
* YouTube Shorts 제목 + 설명 텍스트 빌드
*/
private function buildYoutubeText(VideoGeneration $video, array $scenario, array $scenes): array
{
$title = $video->title ?? '';
$keyword = $video->keyword ?? '';
// 해시태그 생성
$hashtags = ['#shorts', '#쇼츠'];
if ($keyword) {
$hashtags[] = '#' . str_replace(' ', '', $keyword);
}
// 시나리오에서 추가 태그 추출
$bgmMood = $scenario['bgm_mood'] ?? '';
if ($bgmMood) {
$hashtags[] = '#' . $bgmMood;
}
$hashtags = array_merge($hashtags, ['#건강', '#건강정보', '#헬스']);
// 설명란 텍스트
$descLines = [];
$descLines[] = $title;
$descLines[] = '';
// 핵심 내용 요약 (나레이션에서 추출)
foreach ($scenes as $scene) {
$narration = $scene['narration'] ?? '';
if ($narration && ($scene['scene_type'] ?? '') !== 'HOOK') {
$descLines[] = '- ' . mb_substr($narration, 0, 60);
}
}
$descLines[] = '';
$descLines[] = implode(' ', array_unique($hashtags));
return [
'title' => $title,
'description' => implode("\n", $descLines),
'hashtags' => array_unique($hashtags),
];
}
/**
* 생성 이력 목록
*/