Spaces:
Running
on
A100
Running
on
A100
| import React, { useState } from 'react'; | |
| import { formatTime } from '../utils/subtitleUtils'; | |
| import { useTranscriptionStore } from '../stores/transcriptionStore'; | |
| import { InformationCircleIcon } from '@heroicons/react/24/outline'; | |
| const FullTranscription: React.FC = () => { | |
| const [showInfoTooltip, setShowInfoTooltip] = useState(false); | |
| const [showExpandedChunks, setShowExpandedChunks] = useState(false); | |
| const { transcription, selectedLanguage } = useTranscriptionStore(); | |
| const renderInfoTooltip = () => { | |
| if (!transcription) return null; | |
| const chunks = transcription.chunks || []; | |
| const maxVisibleChunks = 3; | |
| const hasMoreChunks = chunks.length > maxVisibleChunks; | |
| const visibleChunks = showExpandedChunks ? chunks : chunks.slice(0, maxVisibleChunks); | |
| // Calculate better positioning to avoid edge cuts | |
| const tooltipStyle: React.CSSProperties = { | |
| position: 'fixed', | |
| left: '50%', | |
| top: '50%', | |
| transform: 'translate(-50%, -50%)', | |
| maxHeight: '80vh', // Prevent tooltip from being taller than viewport | |
| overflowY: 'auto' as const | |
| }; | |
| return ( | |
| <div | |
| className="z-50 p-3 bg-gray-900 text-white text-xs rounded-lg shadow-xl border border-gray-600 min-w-64 max-w-96" | |
| style={tooltipStyle}> | |
| <div className="font-semibold mb-2 text-blue-300">Transcription Details</div> | |
| <div className="space-y-1"> | |
| <div className="flex justify-between"> | |
| <span className="text-gray-300">Model:</span> | |
| <span>{transcription.model}</span> | |
| </div> | |
| <div className="flex justify-between"> | |
| <span className="text-gray-300">Language:</span> | |
| <span className="font-mono"> | |
| {selectedLanguage || 'auto-detect'} | |
| </span> | |
| </div> | |
| <div className="flex justify-between"> | |
| <span className="text-gray-300">Segments:</span> | |
| <span>{transcription.num_segments}</span> | |
| </div> | |
| <div className="flex justify-between"> | |
| <span className="text-gray-300">Duration:</span> | |
| <span>{formatTime(transcription.total_duration)}</span> | |
| </div> | |
| <div className="flex justify-between"> | |
| <span className="text-gray-300">Device:</span> | |
| <span className="font-mono">{transcription.device}</span> | |
| </div> | |
| {/* Long-form specific info */} | |
| {transcription.num_chunks && ( | |
| <> | |
| <div className="border-t border-gray-600 pt-1 mt-1"> | |
| <div className="text-xs text-blue-300 font-semibold mb-1">Long-form Processing</div> | |
| </div> | |
| <div className="flex justify-between"> | |
| <span className="text-gray-300">Chunks:</span> | |
| <span>{transcription.num_chunks}</span> | |
| </div> | |
| </> | |
| )} | |
| </div> | |
| {/* Improved Chunk details */} | |
| {chunks.length > 0 && ( | |
| <div className="mt-2"> | |
| <div className="flex items-center justify-between mb-1"> | |
| <div className="text-xs text-blue-300 font-semibold">Chunk Details</div> | |
| {hasMoreChunks && ( | |
| <button | |
| onClick={() => setShowExpandedChunks(!showExpandedChunks)} | |
| className="text-xs text-blue-400 hover:text-blue-300 underline transition-colors" | |
| > | |
| {showExpandedChunks ? 'Show Less' : `Show All (${chunks.length})`} | |
| </button> | |
| )} | |
| </div> | |
| <div className="space-y-1 max-h-48 overflow-y-auto"> | |
| {visibleChunks.map((chunk, index) => ( | |
| <div key={index} className="text-xs bg-gray-700 p-2 rounded border border-gray-600"> | |
| <div className="flex justify-between items-start"> | |
| <div className="font-medium text-gray-200"> | |
| Chunk #{index + 1} | |
| </div> | |
| <div className="text-gray-400 text-xs"> | |
| {chunk.duration.toFixed(1)}s | |
| </div> | |
| </div> | |
| <div className="text-gray-300 font-mono mt-1"> | |
| {formatTime(chunk.start_time)} → {formatTime(chunk.end_time)} | |
| </div> | |
| </div> | |
| ))} | |
| {hasMoreChunks && !showExpandedChunks && ( | |
| <div className="text-center py-1"> | |
| <button | |
| onClick={() => setShowExpandedChunks(true)} | |
| className="text-xs text-blue-400 hover:text-blue-300 underline transition-colors" | |
| > | |
| +{chunks.length - maxVisibleChunks} more chunks... | |
| </button> | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| }; | |
| if (!transcription) return null; | |
| return ( | |
| <div className="p-4 bg-gray-800 border-t border-gray-700"> | |
| <div className="flex items-center gap-2 mb-3"> | |
| <h3 className="text-sm font-semibold text-white">Full Transcription</h3> | |
| {/* Info tooltip */} | |
| <div className="relative"> | |
| <InformationCircleIcon | |
| className="w-4 h-4 text-gray-400 hover:text-gray-200 cursor-help transition-colors" | |
| onMouseEnter={() => setShowInfoTooltip(true)} | |
| onMouseLeave={() => setShowInfoTooltip(false)} | |
| /> | |
| {showInfoTooltip && renderInfoTooltip()} | |
| </div> | |
| </div> | |
| <div className="text-sm max-h-32 overflow-y-auto text-gray-300 font-mono bg-gray-900 p-3 rounded border border-gray-600"> | |
| {transcription.transcription} | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default FullTranscription; | |