diff --git a/src/main/java/com/hlab/yanalyst/domain/production/dto/ScriptResponseDto.java b/src/main/java/com/hlab/yanalyst/domain/production/dto/ScriptResponseDto.java index 26503a0..4958a34 100644 --- a/src/main/java/com/hlab/yanalyst/domain/production/dto/ScriptResponseDto.java +++ b/src/main/java/com/hlab/yanalyst/domain/production/dto/ScriptResponseDto.java @@ -24,5 +24,9 @@ public class ScriptResponseDto { private double start; private double end; private String text; + + /** 화면 자막(Gemini): 번역 전 원문. 음성 전사엔 없으므로 null 이면 직렬화 생략. */ + @com.fasterxml.jackson.annotation.JsonInclude(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL) + private String original; } } diff --git a/src/main/java/com/hlab/yanalyst/service/GeminiSubtitleService.java b/src/main/java/com/hlab/yanalyst/service/GeminiSubtitleService.java index 8e03306..43c357c 100644 --- a/src/main/java/com/hlab/yanalyst/service/GeminiSubtitleService.java +++ b/src/main/java/com/hlab/yanalyst/service/GeminiSubtitleService.java @@ -32,8 +32,11 @@ public class GeminiSubtitleService { + "음성/말소리는 무시하고 화면의 글자만 대상으로 합니다. " + "각 자막이 화면에 나타나는 시작 시각과 사라지는 끝 시각을 '영상 시작 기준 초'로 최대한 정확히 적으세요(예: 0, 2.5, 8.1). " + "중요: 모든 항목의 시간을 0으로 두지 마세요. 자막이 바뀌는 순서대로 start 가 증가해야 합니다. " - + "JSON 배열로만 출력: [{\"start\": 시작초, \"end\": 끝초, \"text\": \"한국어 번역\"}]. " - + "text 는 한국어 번역. 화면 자막이 전혀 없으면 빈 배열 []."; + + "각 자막의 화면 원문(그대로)과 한국어 번역을 함께 주세요. " + + "JSON 배열로만 출력: [{\"start\": 시작초, \"end\": 끝초, \"original\": \"화면 원문 그대로\", \"text\": \"한국어 번역\"}]. " + + "original 은 화면에 보이는 원문 그대로(번역하지 말 것). " + + "text 는 그 원문을 반드시 '한국어'로 번역한 결과입니다 — 영어가 아니라 한국어로 쓰세요. " + + "화면 자막이 전혀 없으면 빈 배열 []."; private final RestTemplate geminiRestTemplate; private final ObjectMapper objectMapper; @@ -124,6 +127,7 @@ public class GeminiSubtitleService { "properties", Map.of( "start", Map.of("type", "NUMBER"), "end", Map.of("type", "NUMBER"), + "original", Map.of("type", "STRING"), "text", Map.of("type", "STRING"))); // Gemini 2.5 Flash 는 'thinking' 모델: 정확한 타임스탬프는 thinking 으로 추론한다(끄면 시간이 전부 0). // 단 thinking 토큰이 출력 한도를 먹어 JSON 이 잘리면 0개가 되므로 maxOutputTokens 를 크게 준다. diff --git a/src/main/resources/templates/rework.html b/src/main/resources/templates/rework.html index 92044b4..e36282c 100644 --- a/src/main/resources/templates/rework.html +++ b/src/main/resources/templates/rework.html @@ -255,6 +255,9 @@ .ai-row { display:flex; gap:8px; padding:6px 10px; cursor:pointer; border-bottom:1px solid var(--surface); font-size:0.85rem; line-height:1.5; } .ai-row:hover { background:var(--surface); } + .ai-txt { display:flex; flex-direction:column; min-width:0; } + .ai-txt .seg-text { color:var(--text); } + .ai-orig { color:var(--text-2); font-size:0.78rem; opacity:0.8; margin-top:1px; } .ai-empty { padding:14px 10px; color:var(--text-2); font-size:0.85rem; text-align:center; } @@ -485,7 +488,10 @@ box.innerHTML = segs.map(sg => '