벌크 자막/추출 개선, 검색 필터 무시, geocoding 필드 수정, 네이버맵 링크
- 벌크 자막: 브라우저 우선 + API fallback, 광고 즉시 skip, 대기 시간 단축 - 벌크 자막/추출: 선택한 영상만 처리 가능 (체크박스 선택 후 실행) - 자막 실패 시 no_transcript 상태 마킹하여 재시도 방지 - 검색 시 필터 조건 무시 (채널/장르/가격/지역/영역 초기화) - 리셋 버튼 클릭 시 검색어 입력란 초기화 - RestaurantMapper updateFields에 google_place_id, rating 등 geocoding 필드 추가 - SearchMapper에 tabling_url, catchtable_url, phone, website 필드 추가 - 식당 상세에 네이버 지도 링크 추가 - YouTubeService.getTranscriptApi public 전환 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -393,35 +393,46 @@ function VideosPanel({ isAdmin }: { isAdmin: boolean }) {
|
||||
}
|
||||
};
|
||||
|
||||
const startBulkStream = async (mode: "transcript" | "extract") => {
|
||||
const startBulkStream = async (mode: "transcript" | "extract", ids?: string[]) => {
|
||||
const isTranscript = mode === "transcript";
|
||||
const setRunning = isTranscript ? setBulkTranscripting : setBulkExtracting;
|
||||
const hasSelection = ids && ids.length > 0;
|
||||
|
||||
try {
|
||||
const pending = isTranscript
|
||||
? await api.getBulkTranscriptPending()
|
||||
: await api.getBulkExtractPending();
|
||||
if (pending.count === 0) {
|
||||
alert(isTranscript ? "자막 없는 영상이 없습니다" : "추출 대기 중인 영상이 없습니다");
|
||||
return;
|
||||
let count: number;
|
||||
if (hasSelection) {
|
||||
count = ids.length;
|
||||
} else {
|
||||
const pending = isTranscript
|
||||
? await api.getBulkTranscriptPending()
|
||||
: await api.getBulkExtractPending();
|
||||
if (pending.count === 0) {
|
||||
alert(isTranscript ? "자막 없는 영상이 없습니다" : "추출 대기 중인 영상이 없습니다");
|
||||
return;
|
||||
}
|
||||
count = pending.count;
|
||||
}
|
||||
const msg = isTranscript
|
||||
? `자막 없는 영상 ${pending.count}개의 트랜스크립트를 수집하시겠습니까?\n(영상 당 5~15초 랜덤 딜레이)`
|
||||
: `LLM 추출이 안된 영상 ${pending.count}개를 벌크 처리하시겠습니까?\n(영상 당 3~8초 랜덤 딜레이)`;
|
||||
? `${hasSelection ? "선택한 " : "자막 없는 "}영상 ${count}개의 트랜스크립트를 수집하시겠습니까?`
|
||||
: `${hasSelection ? "선택한 " : "LLM 추출이 안된 "}영상 ${count}개를 벌크 처리하시겠습니까?`;
|
||||
if (!confirm(msg)) return;
|
||||
|
||||
setRunning(true);
|
||||
setBulkProgress({
|
||||
label: isTranscript ? "벌크 자막 수집" : "벌크 LLM 추출",
|
||||
total: pending.count, current: 0, currentTitle: "", results: [],
|
||||
total: count, current: 0, currentTitle: "", results: [],
|
||||
});
|
||||
|
||||
const apiBase = process.env.NEXT_PUBLIC_API_URL || "";
|
||||
const endpoint = isTranscript ? "/api/videos/bulk-transcript" : "/api/videos/bulk-extract";
|
||||
const token = typeof window !== "undefined" ? localStorage.getItem("tasteby_token") : null;
|
||||
const headers: Record<string, string> = {};
|
||||
const headers: Record<string, string> = { "Content-Type": "application/json" };
|
||||
if (token) headers["Authorization"] = `Bearer ${token}`;
|
||||
const resp = await fetch(`${apiBase}${endpoint}`, { method: "POST", headers });
|
||||
const resp = await fetch(`${apiBase}${endpoint}`, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: hasSelection ? JSON.stringify({ ids }) : undefined,
|
||||
});
|
||||
if (!resp.ok) {
|
||||
alert(`벌크 요청 실패: ${resp.status} ${resp.statusText}`);
|
||||
setRunning(false);
|
||||
@@ -757,6 +768,20 @@ function VideosPanel({ isAdmin }: { isAdmin: boolean }) {
|
||||
)}
|
||||
{isAdmin && selected.size > 0 && (
|
||||
<>
|
||||
<button
|
||||
onClick={() => startBulkStream("transcript", Array.from(selected))}
|
||||
disabled={bulkTranscripting || bulkExtracting}
|
||||
className="bg-orange-500 text-white px-4 py-2 rounded text-sm hover:bg-orange-600 disabled:opacity-50"
|
||||
>
|
||||
선택 자막 수집 ({selected.size})
|
||||
</button>
|
||||
<button
|
||||
onClick={() => startBulkStream("extract", Array.from(selected))}
|
||||
disabled={bulkExtracting || bulkTranscripting}
|
||||
className="bg-purple-500 text-white px-4 py-2 rounded text-sm hover:bg-purple-600 disabled:opacity-50"
|
||||
>
|
||||
선택 LLM 추출 ({selected.size})
|
||||
</button>
|
||||
<button
|
||||
onClick={handleBulkSkip}
|
||||
className="bg-gray-500 text-white px-4 py-2 rounded text-sm hover:bg-gray-600"
|
||||
|
||||
Reference in New Issue
Block a user