feat: [rd] AI CM송 제작 기능 추가
- Gemini API 기반 CM송 가사 생성 + TTS 음성 생성 - 연구개발 대시보드에 CM송 제작 카드 추가 - 서버사이드 API 프록시로 API 키 보호
This commit is contained in:
147
app/Http/Controllers/Rd/CmSongController.php
Normal file
147
app/Http/Controllers/Rd/CmSongController.php
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Rd;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class CmSongController extends Controller
|
||||
{
|
||||
private string $baseUrl;
|
||||
|
||||
private string $apiKey;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->baseUrl = config('services.gemini.base_url');
|
||||
$this->apiKey = config('services.gemini.api_key');
|
||||
}
|
||||
|
||||
/**
|
||||
* CM송 제작 페이지
|
||||
*/
|
||||
public function index(Request $request): View|\Illuminate\Http\Response
|
||||
{
|
||||
if ($request->header('HX-Request')) {
|
||||
return response('', 200)->header('HX-Redirect', route('rd.cm-song.index'));
|
||||
}
|
||||
|
||||
return view('rd.cm-song.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* CM송 가사 생성 (Gemini API)
|
||||
*/
|
||||
public function generateLyrics(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'company_name' => 'required|string|max:100',
|
||||
'industry' => 'required|string|max:200',
|
||||
'mood' => 'required|string|max:50',
|
||||
]);
|
||||
|
||||
$prompt = "당신은 전문 CM송 작사가입니다. 다음 정보를 바탕으로 짧고 기억에 남는 15초 분량의 라디오 CM송 가사를 작성해주세요.
|
||||
|
||||
회사명: {$request->company_name}
|
||||
업종/제품: {$request->industry}
|
||||
분위기: {$request->mood}
|
||||
|
||||
조건:
|
||||
- 3~4줄로 짧게 작성
|
||||
- 운율을 살려서 작성
|
||||
- 지시문(예: (음악 소리), (밝은 목소리로)) 없이 오직 읽을 수 있는 가사 텍스트만 출력할 것.";
|
||||
|
||||
try {
|
||||
$response = Http::timeout(30)->post(
|
||||
"{$this->baseUrl}/models/gemini-2.5-flash:generateContent?key={$this->apiKey}",
|
||||
[
|
||||
'contents' => [
|
||||
['parts' => [['text' => $prompt]]],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
if (! $response->successful()) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'error' => '가사 생성에 실패했습니다: '.$response->status(),
|
||||
], 500);
|
||||
}
|
||||
|
||||
$data = $response->json();
|
||||
$text = $data['candidates'][0]['content']['parts'][0]['text'] ?? '';
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'lyrics' => trim($text),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'error' => '가사 생성 중 오류: '.$e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TTS 음성 생성 (Gemini TTS API)
|
||||
*/
|
||||
public function generateAudio(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'lyrics' => 'required|string|max:2000',
|
||||
]);
|
||||
|
||||
try {
|
||||
$response = Http::timeout(60)->post(
|
||||
"{$this->baseUrl}/models/gemini-2.5-flash-preview-tts:generateContent?key={$this->apiKey}",
|
||||
[
|
||||
'contents' => [
|
||||
['parts' => [['text' => $request->lyrics]]],
|
||||
],
|
||||
'generationConfig' => [
|
||||
'responseModalities' => ['AUDIO'],
|
||||
'speechConfig' => [
|
||||
'voiceConfig' => [
|
||||
'prebuiltVoiceConfig' => [
|
||||
'voiceName' => 'Kore',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
if (! $response->successful()) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'error' => '음성 생성에 실패했습니다: '.$response->status(),
|
||||
], 500);
|
||||
}
|
||||
|
||||
$data = $response->json();
|
||||
$inlineData = $data['candidates'][0]['content']['parts'][0]['inlineData'] ?? null;
|
||||
|
||||
if (! $inlineData || empty($inlineData['data'])) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'error' => '음성 데이터를 받지 못했습니다.',
|
||||
], 500);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'audio_data' => $inlineData['data'],
|
||||
'mime_type' => $inlineData['mimeType'] ?? 'audio/L16;rate=24000',
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'error' => '음성 생성 중 오류: '.$e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user