Add YouTube transcript auto-fetch button on Knowledge add page

- YouTubeTranscriptService: fetches captions from YouTube page (ko > en > first available)
- GET /api/knowledge/youtube-transcript endpoint
- Frontend: "트랜스크립트 자동 가져오기" button appears when valid YouTube URL entered

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-01 04:20:13 +00:00
parent f0f7b62e3d
commit bb5a601433
3 changed files with 235 additions and 1 deletions

View File

@@ -36,6 +36,7 @@ export default function KnowledgeAddPage() {
const [modelId, setModelId] = useState("");
const [models, setModels] = useState<ModelInfo[]>([]);
const [submitting, setSubmitting] = useState(false);
const [fetchingTranscript, setFetchingTranscript] = useState(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
@@ -52,6 +53,30 @@ export default function KnowledgeAddPage() {
const videoId = useMemo(() => (type === "YOUTUBE" ? extractYouTubeVideoId(url) : null), [type, url]);
const canFetchTranscript = type === "YOUTUBE" && videoId !== null && !fetchingTranscript;
const handleFetchTranscript = async () => {
if (!canFetchTranscript) return;
setError(null);
setFetchingTranscript(true);
try {
const data = await request<{ transcript?: string; error?: string }>({
method: "GET",
url: `/api/knowledge/youtube-transcript?url=${encodeURIComponent(url.trim())}`,
});
if (data.error) {
setError(data.error);
} else if (data.transcript) {
setRawText(data.transcript);
}
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : "트랜스크립트를 가져올 수 없습니다";
setError(msg);
} finally {
setFetchingTranscript(false);
}
};
const canSubmit =
!submitting &&
((type === "TEXT" && rawText.trim().length > 0) ||
@@ -168,6 +193,17 @@ export default function KnowledgeAddPage() {
</div>
)}
{/* Fetch Transcript Button (YOUTUBE) */}
{type === "YOUTUBE" && videoId && (
<button
onClick={handleFetchTranscript}
disabled={!canFetchTranscript}
className="w-full px-4 py-2 bg-[var(--color-bg-card)] border border-[var(--color-border)] hover:border-[var(--color-primary)] disabled:opacity-40 disabled:cursor-not-allowed rounded-lg transition-colors text-sm font-medium"
>
{fetchingTranscript ? "트랜스크립트 가져오는 중..." : "트랜스크립트 자동 가져오기"}
</button>
)}
{/* Text Input (TEXT / YOUTUBE) */}
{type !== "WEB" && (
<div>