Skip to content

Commit

Permalink
long transcribes supported
Browse files Browse the repository at this point in the history
  • Loading branch information
pblvrt committed Jan 3, 2025
1 parent 8bb6113 commit d9845c8
Show file tree
Hide file tree
Showing 11 changed files with 260 additions and 50 deletions.
1 change: 1 addition & 0 deletions packages/app/app/[organization]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const Layout = async ({

const userData = await fetchUserAction();

console.log(organization);
if (!organization) {
return NotFound();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,8 @@ export const ClipProvider = ({
organizationId: string;
clipUrl: string;
}) => {
const { handleTermChange, searchParams } = useSearchParams();
const { searchParams } = useSearchParams();

const start = searchParams?.get('start');
const end = searchParams?.get('end');
const [playbackStatus, setPlaybackStatus] = useState<PlaybackStatus | null>(
null
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { fetchOrganization } from '@/lib/services/organizationService';
import {
fetchAllSessions,
fetchAsset,
fetchSession,
sessionImport,
fetchSession
} from '@/lib/services/sessionService';
import { fetchStage, fetchStageRecordings } from '@/lib/services/stageService';
import { ClipsPageParams } from '@/lib/types';
Expand Down Expand Up @@ -31,12 +29,11 @@ const fetchVideoDetails = async (

const stageRecordings = await fetchStageRecordings({ streamId });
if (!stageRecordings?.recordings[0]) return null;

return {
videoSrc: stageRecordings.recordings[0].recordingUrl,
videoSrc: `https://livepeercdn.studio/hls/${liveStage.streamSettings?.playbackId}/index.m3u8`,
type: 'livepeer',
name: liveStage.name,
words: liveStage.transcripts?.text,
words: liveStage.transcripts?.chunks,
liveRecording: stageRecordings.recordings[0],
};
}
Expand All @@ -47,13 +44,13 @@ const fetchVideoDetails = async (

const stage = await fetchStage({ stage: session.stageId as string });
if (!stage?.streamSettings?.playbackId) return null;

console.log('session', session.transcripts?.chunks);
const videoSrc = await getVideoUrlAction(session);
return {
videoSrc,
type: 'livepeer',
name: session.name,
words: session.transcripts?.subtitleUrl,
words: session.transcripts?.chunks,
};
}

Expand All @@ -65,6 +62,7 @@ const fetchVideoDetails = async (
videoSrc: stage.source.m3u8Url,
type: stage.source.type,
name: stage.name,
words: stage.transcripts?.chunks,
};
}

Expand Down Expand Up @@ -106,13 +104,6 @@ const ClipsConfig = async ({ params, searchParams }: ClipsPageParams) => {
clipUrl={videoDetails.videoSrc}
>
<div className="flex flex-row w-full h-full border-t border-gray-200">
{/* <div className="flex flex-col w-[400px] h-full overflow-y-auto">
{words?.split('\n').map((word) => (
<div className="flex flex-col text-sm text-gray-500" key={word}>
{word}
</div>
))}
</div> */}
<div className="flex h-full w-[calc(100%-400px)] flex-col">
<TopBar title={videoDetails.name} organization={organization} />
<ReactHlsPlayer
Expand All @@ -130,6 +121,7 @@ const ClipsConfig = async ({ params, searchParams }: ClipsPageParams) => {
stageSessions={stageSessions.sessions}
organizationId={organizationId}
animations={animations.sessions}
words={videoDetails.words}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"use client"
import { useClipContext } from '../../ClipContext';

const Transcripts = ({
words,
}: {
words: { word: string; start: number }[];
}) => {
const { currentTime, videoRef } = useClipContext();

// Helper function to determine if a word should be highlighted
const isWordActive = (
word: { word: string; start: number },
currentTime: number
) => {
// You might want to adjust this logic based on your requirements
return word.start <= currentTime && word.start + 1 > currentTime;
};

return (
<div className="whitespace-pre-wrap">
{words?.map((word, index) => (
<span
key={`${word.word}-${index}`}
className={`${
isWordActive(word, currentTime) ? 'bg-yellow-200' : ''
} inline-block mr-1 cursor-pointer hover:bg-gray-100`}
onClick={() => {
if (videoRef.current) {
videoRef.current.currentTime = word.start;
}
}}
>
{word.word}
</span>
))}
</div>
);
};

export default Transcripts;
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,24 @@ import CreateClipButton from '../topBar/CreateClipButton';
import AddOrEditMarkerForm from './markers/AddOrEditMarkerForm';
import { IExtendedSession } from '@/lib/types';
import ImportMarkersForm from './markers/ImportMarkersForm';
import Transcripts from './Transcipts';

export default function Sidebar({
organizationId,
stageSessions,
liveRecordingId,
animations,
words,
}: {
organizationId: string;
stageSessions: IExtendedSession[];
liveRecordingId?: string;
animations: IExtendedSession[];
words?: {
word: string;
start: number;
end: number;
}[];
}) {
const { isCreatingClip, isAddingOrEditingMarker, isImportingMarkers } =
useClipContext();
Expand Down Expand Up @@ -57,16 +64,22 @@ export default function Sidebar({
)
)}
<Tabs defaultValue="clips" className="flex flex-col h-full">
<TabsList className="grid w-full grid-cols-2 flex-shrink-0">
<TabsList className="grid w-full grid-cols-3 flex-shrink-0">
<TabsTrigger value="markers">Markers</TabsTrigger>
<TabsTrigger value="clips">Clips</TabsTrigger>
{words && <TabsTrigger value="words">Words</TabsTrigger>}
</TabsList>
<TabsContent value="markers" className="flex-grow overflow-hidden">
{<Markers organizationId={organizationId} />}
</TabsContent>
<TabsContent value="clips" className="flex-grow overflow-hidden">
<SessionSidebar sessions={stageSessions} />
</TabsContent>
{words && (
<TabsContent value="words" className="flex-grow overflow-auto p-4">
<Transcripts words={words} />
</TabsContent>
)}
</Tabs>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,27 +44,41 @@ const SessionTranscriptions = ({
});
};

if (transcriptionState === TranscriptionStatus.processing) {
return (
<div className="flex items-center">
<LuLoader2 className="mr-2 w-4 h-4 animate-spin" /> Processing
transcription...{' '}
<p
className="pl-2 cursor-pointer"
title="refresh"
onClick={() => router.refresh()}
>
<LuRefreshCcw />
</p>
</div>
);
}
// if (transcriptionState === TranscriptionStatus.processing) {
// return (
// <div className="flex items-center">
// <LuLoader2 className="mr-2 w-4 h-4 animate-spin" /> Processing
// transcription...{' '}
// <p
// className="pl-2 cursor-pointer"
// title="refresh"
// onClick={() => router.refresh()}
// >
// <LuRefreshCcw />
// </p>
// </div>
// );
// }

if (
transcriptionState === TranscriptionStatus.completed &&
videoTranscription
) {
return <TextPlaceholder text={videoTranscription} />;
return (
<div className="space-y-4">
<TextPlaceholder text={videoTranscription} />
<Button
variant="outline"
size="sm"
onClick={handleGenerateTranscription}
loading={isGeneratingTranscript}
className="flex items-center gap-2"
>
<LuRefreshCcw className="w-4 h-4" />
Regenerate Transcription
</Button>
</div>
);
}

if (transcriptionState === TranscriptionStatus.failed) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ const EditSession = async ({ params, searchParams }: studioPageParams) => {
session: params.session,
});

console.log(session?.transcripts?.chunks[0]);
if (!session?.playbackId || !organization) return notFound();

return (
Expand Down
3 changes: 3 additions & 0 deletions packages/app/lib/actions/livepeer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ export const getVideoUrlAction = async (
session: IExtendedSession
): Promise<string | null> => {
try {
if (session.playback?.videoUrl) {
return session.playback.videoUrl;
}
if (session.assetId) {
const asset = await fetchAsset({ assetId: session.assetId });
if (asset?.playbackUrl) {
Expand Down
4 changes: 2 additions & 2 deletions packages/server/src/databases/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ console.log('Database:', name);
console.log('Password length:', password?.length);

export const dbConnection = {
url: `mongodb://${user}:${password}@${host}/${name}?authSource=admin&retryWrites=true&w=majority`,
//rl: `mongodb://${user}:${password}@${host}/${name}?authSource=admin&retryWrites=true&w=majority`,
// For local development use this url
// url: `mongodb+srv://${user}:${password}@${host}/${name}?authSource=admin`,
url: `mongodb+srv://${user}:${password}@${host}/${name}?authSource=admin`,
options: {
useNewUrlParser: true,
useUnifiedTopology: true,
Expand Down
24 changes: 17 additions & 7 deletions packages/server/workers/clips/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,31 @@ const processClip = async (data: IClip) => {
);
}
const masterContent = await masterResponse.text();

console.log('masterContent', masterContent);
// 2. Find the 1080p variant
const linesMaster = masterContent.split('\n');
let variantUrl = '';
let maxBandwidth = -1;

for (let i = 0; i < linesMaster.length; i++) {
if (linesMaster[i].includes('1080p0')) {
variantUrl = linesMaster[i + 1].trim();
break;
if (linesMaster[i].startsWith('#EXT-X-STREAM-INF')) {
// Parse bandwidth from the stream info
const bandwidthMatch = linesMaster[i].match(/BANDWIDTH=(\d+)/);
if (bandwidthMatch) {
const bandwidth = parseInt(bandwidthMatch[1]);
if (bandwidth > maxBandwidth) {
maxBandwidth = bandwidth;
variantUrl = linesMaster[i + 1].trim();
}
}
}
}
variantUrl = clipUrl.replace('index.m3u8', variantUrl);

console.log('Selected variant URL:', variantUrl);
variantUrl = clipUrl.replace('index.m3u8', variantUrl);
console.log('Full variant URL:', variantUrl);
if (!variantUrl) {
throw new Error('1080p variant not found in master playlist');
throw new Error('No valid variant found in master playlist');
}

const duration = end - start;
Expand All @@ -77,7 +87,7 @@ const processClip = async (data: IClip) => {
const manifestResponse = await fetch(variantUrl);
if (!manifestResponse.ok) {
throw new Error(
`Failed to fetch manifest: ${manifestResponse.statusText}`,
`Failed to fetch manifest ${variantUrl}: ${manifestResponse.statusText}`,
);
}
const manifestContent = await manifestResponse.text();
Expand Down
Loading

0 comments on commit d9845c8

Please sign in to comment.