diff --git a/app/analyze/[videoId]/page.tsx b/app/analyze/[videoId]/page.tsx index 8ba3af1c..31e8d727 100644 --- a/app/analyze/[videoId]/page.tsx +++ b/app/analyze/[videoId]/page.tsx @@ -1909,6 +1909,42 @@ export default function AnalyzePage() { )} + {videoId && topics.length === 0 && pageState === 'IDLE' && !error && ( +
+ +
+
+

+ No highlights found +

+

+ We processed the transcript but couldn't find any standout highlights matching your criteria. This sometimes happens if the video is very short, has no dialogue, or if the AI filters were too strict. +

+
+
+ + Go to home + + +
+
+
+
+ )} + {videoId && topics.length > 0 && pageState === 'IDLE' && (
{error && ( diff --git a/lib/ai-processing.ts b/lib/ai-processing.ts index 7974cd96..dce60e9e 100644 --- a/lib/ai-processing.ts +++ b/lib/ai-processing.ts @@ -14,7 +14,7 @@ import { import { generateAIResponse } from '@/lib/ai-client'; import { getProviderKey } from '@/lib/ai-providers'; import { topicGenerationSchema } from '@/lib/schemas'; -import { parseTimestampRange } from '@/lib/timestamp-utils'; +import { parseTimestampRange, formatTimestamp } from '@/lib/timestamp-utils'; import { getLanguageName } from '@/lib/language-utils'; import { repairJson } from '@/lib/json-utils'; import { z } from 'zod'; @@ -210,7 +210,7 @@ function buildChunkPrompt( language?: string ): string { const transcript = formatTranscriptWithTimestamps(chunk.segments); - const chunkWindow = `[${formatTime(chunk.start)}-${formatTime(chunk.end)}]`; + const chunkWindow = `[${formatTimestamp(chunk.start)}-${formatTimestamp(chunk.end)}]`; const videoInfoBlock = formatVideoInfoForPrompt(videoInfo); const themeInstruction = theme ? ` Focus exclusively on material that clearly expresses the theme "${theme}". Skip anything unrelated.\n` @@ -283,7 +283,7 @@ function buildReducePrompt( .map((candidate, idx) => { const timestamp = candidate.quote?.timestamp ?? '[??:??-??:??]'; const quoteText = candidate.quote?.text ?? ''; - const chunkWindow = `[${formatTime(candidate.chunkStart)}-${formatTime( + const chunkWindow = `[${formatTimestamp(candidate.chunkStart)}-${formatTimestamp( candidate.chunkEnd )}]`; return `Candidate ${idx + 1} @@ -464,7 +464,7 @@ function buildFallbackTopics( fallbackTopics.push({ title: theme ? `${theme} — part ${i + 1}` : `Part ${i + 1}`, quote: { - timestamp: `[${formatTime(startTime)}-${formatTime(endTime)}]`, + timestamp: `[${formatTimestamp(startTime)}-${formatTimestamp(endTime)}]`, text: chunkSegments .map((s) => s.text) @@ -602,7 +602,7 @@ ${transcriptWithTimestamps} { title: fallbackLabel, quote: { - timestamp: `[00:00-${formatTime(fallbackEnd)}]`, + timestamp: `[00:00-${formatTimestamp(fallbackEnd)}]`, text: fullText.substring(0, 200) } } @@ -629,21 +629,13 @@ function combineTranscript(segments: TranscriptSegment[]): string { function formatTranscriptWithTimestamps(segments: TranscriptSegment[]): string { return segments .map((s) => { - const startTime = formatTime(s.start); - const endTime = formatTime(s.start + s.duration); + const startTime = formatTimestamp(s.start); + const endTime = formatTimestamp(s.start + s.duration); return `[${startTime}-${endTime}] ${s.text}`; }) .join('\n'); } -function formatTime(seconds: number): string { - const mins = Math.floor(seconds / 60); - const secs = Math.floor(seconds % 60); - return `${mins.toString().padStart(2, '0')}:${secs - .toString() - .padStart(2, '0')}`; -} - async function findExactQuotes( transcript: TranscriptSegment[], quotes: Array<{ timestamp: string; text: string }>, diff --git a/lib/timestamp-utils.ts b/lib/timestamp-utils.ts index 75e1233c..9fea845a 100644 --- a/lib/timestamp-utils.ts +++ b/lib/timestamp-utils.ts @@ -27,7 +27,10 @@ export function parseTimestamp(timestamp: string): number | null { // Validate time values if (hours < 0 || hours >= 24) return null; - if (minutes < 0 || minutes >= 60) return null; + if (minutes < 0) return null; + // Relax minute check to allow MM:SS where MM >= 60 (fallback scenarios) + // unless hours are present, in which case strict 0-59 applies + if (hours > 0 && minutes >= 60) return null; if (seconds < 0 || seconds >= 60) return null; return hours * 3600 + minutes * 60 + seconds;