lyrics-transcriber 0.43.0__py3-none-any.whl → 0.44.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. lyrics_transcriber/core/controller.py +58 -24
  2. lyrics_transcriber/correction/anchor_sequence.py +22 -8
  3. lyrics_transcriber/correction/corrector.py +47 -3
  4. lyrics_transcriber/correction/handlers/llm.py +15 -12
  5. lyrics_transcriber/correction/handlers/llm_providers.py +60 -0
  6. lyrics_transcriber/frontend/.yarn/install-state.gz +0 -0
  7. lyrics_transcriber/frontend/dist/assets/{index-D0Gr3Ep7.js → index-DVoI6Z16.js} +10799 -7490
  8. lyrics_transcriber/frontend/dist/assets/index-DVoI6Z16.js.map +1 -0
  9. lyrics_transcriber/frontend/dist/index.html +1 -1
  10. lyrics_transcriber/frontend/src/App.tsx +4 -4
  11. lyrics_transcriber/frontend/src/api.ts +37 -0
  12. lyrics_transcriber/frontend/src/components/AddLyricsModal.tsx +114 -0
  13. lyrics_transcriber/frontend/src/components/AudioPlayer.tsx +14 -10
  14. lyrics_transcriber/frontend/src/components/CorrectionMetrics.tsx +62 -56
  15. lyrics_transcriber/frontend/src/components/EditModal.tsx +232 -237
  16. lyrics_transcriber/frontend/src/components/FindReplaceModal.tsx +467 -0
  17. lyrics_transcriber/frontend/src/components/GlobalSyncEditor.tsx +675 -0
  18. lyrics_transcriber/frontend/src/components/Header.tsx +141 -101
  19. lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx +146 -80
  20. lyrics_transcriber/frontend/src/components/ModeSelector.tsx +22 -13
  21. lyrics_transcriber/frontend/src/components/PreviewVideoSection.tsx +1 -0
  22. lyrics_transcriber/frontend/src/components/ReferenceView.tsx +29 -12
  23. lyrics_transcriber/frontend/src/components/ReviewChangesModal.tsx +21 -4
  24. lyrics_transcriber/frontend/src/components/TimelineEditor.tsx +29 -15
  25. lyrics_transcriber/frontend/src/components/TranscriptionView.tsx +34 -16
  26. lyrics_transcriber/frontend/src/components/WordDivider.tsx +186 -0
  27. lyrics_transcriber/frontend/src/components/shared/components/HighlightedText.tsx +89 -41
  28. lyrics_transcriber/frontend/src/components/shared/components/SourceSelector.tsx +9 -2
  29. lyrics_transcriber/frontend/src/components/shared/components/Word.tsx +28 -3
  30. lyrics_transcriber/frontend/src/components/shared/types.ts +17 -2
  31. lyrics_transcriber/frontend/src/components/shared/utils/keyboardHandlers.ts +63 -14
  32. lyrics_transcriber/frontend/src/components/shared/utils/segmentOperations.ts +192 -0
  33. lyrics_transcriber/frontend/src/hooks/useManualSync.ts +267 -0
  34. lyrics_transcriber/frontend/src/main.tsx +7 -1
  35. lyrics_transcriber/frontend/src/theme.ts +177 -0
  36. lyrics_transcriber/frontend/src/types.ts +1 -1
  37. lyrics_transcriber/frontend/tsconfig.tsbuildinfo +1 -1
  38. lyrics_transcriber/lyrics/base_lyrics_provider.py +2 -2
  39. lyrics_transcriber/lyrics/user_input_provider.py +44 -0
  40. lyrics_transcriber/output/generator.py +40 -12
  41. lyrics_transcriber/output/video.py +18 -8
  42. lyrics_transcriber/review/server.py +238 -8
  43. {lyrics_transcriber-0.43.0.dist-info → lyrics_transcriber-0.44.0.dist-info}/METADATA +3 -2
  44. {lyrics_transcriber-0.43.0.dist-info → lyrics_transcriber-0.44.0.dist-info}/RECORD +47 -41
  45. lyrics_transcriber/frontend/dist/assets/index-D0Gr3Ep7.js.map +0 -1
  46. lyrics_transcriber/frontend/src/components/DetailsModal.tsx +0 -252
  47. lyrics_transcriber/frontend/src/components/WordEditControls.tsx +0 -110
  48. {lyrics_transcriber-0.43.0.dist-info → lyrics_transcriber-0.44.0.dist-info}/LICENSE +0 -0
  49. {lyrics_transcriber-0.43.0.dist-info → lyrics_transcriber-0.44.0.dist-info}/WHEEL +0 -0
  50. {lyrics_transcriber-0.43.0.dist-info → lyrics_transcriber-0.44.0.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,9 @@
1
- import { Box, Button, Typography, useMediaQuery, useTheme, Switch, FormControlLabel, Tooltip, CircularProgress } from '@mui/material'
1
+ import { Box, Button, Typography, useMediaQuery, useTheme, Switch, FormControlLabel, Tooltip, Paper } from '@mui/material'
2
2
  import LockIcon from '@mui/icons-material/Lock'
3
3
  import UploadFileIcon from '@mui/icons-material/UploadFile'
4
+ import TextSnippetIcon from '@mui/icons-material/TextSnippet'
5
+ import FindReplaceIcon from '@mui/icons-material/FindReplace'
6
+ import TimerIcon from '@mui/icons-material/Timer'
4
7
  import { CorrectionData } from '../types'
5
8
  import CorrectionMetrics from './CorrectionMetrics'
6
9
  import ModeSelector from './ModeSelector'
@@ -26,6 +29,9 @@ interface HeaderProps {
26
29
  onHandlerToggle: (handler: string, enabled: boolean) => void
27
30
  isUpdatingHandlers: boolean
28
31
  onHandlerClick?: (handler: string) => void
32
+ onAddLyrics?: () => void
33
+ onFindReplace?: () => void
34
+ onEditSync?: () => void
29
35
  }
30
36
 
31
37
  export default function Header({
@@ -40,7 +46,10 @@ export default function Header({
40
46
  onTimeUpdate,
41
47
  onHandlerToggle,
42
48
  isUpdatingHandlers,
43
- onHandlerClick
49
+ onHandlerClick,
50
+ onAddLyrics,
51
+ onFindReplace,
52
+ onEditSync
44
53
  }: HeaderProps) {
45
54
  const theme = useTheme()
46
55
  const isMobile = useMediaQuery(theme.breakpoints.down('md'))
@@ -89,28 +98,29 @@ export default function Header({
89
98
  return (
90
99
  <>
91
100
  {isReadOnly && (
92
- <Box sx={{ display: 'flex', alignItems: 'center', mb: 2, color: 'text.secondary' }}>
93
- <LockIcon sx={{ mr: 1 }} />
94
- <Typography variant="body2">
101
+ <Box sx={{ display: 'flex', alignItems: 'center', mb: 0.8, color: 'text.secondary' }}>
102
+ <LockIcon sx={{ mr: 0.5 }} fontSize="small" />
103
+ <Typography variant="body2" sx={{ fontSize: '0.75rem' }}>
95
104
  View Only Mode
96
105
  </Typography>
97
106
  </Box>
98
107
  )}
99
108
 
100
- <Box sx={{
101
- display: 'flex',
109
+ <Box sx={{
110
+ display: 'flex',
102
111
  flexDirection: isMobile ? 'column' : 'row',
103
- gap: 2,
112
+ gap: 1,
104
113
  justifyContent: 'space-between',
105
114
  alignItems: isMobile ? 'stretch' : 'center',
106
- mb: 3
115
+ mb: 1
107
116
  }}>
108
- <Typography variant="h4" sx={{ fontSize: isMobile ? '1.75rem' : '2.125rem' }}>
109
- Lyrics Correction Review
117
+ <Typography variant="h4" sx={{ fontSize: isMobile ? '1.3rem' : '1.5rem' }}>
118
+ Nomad Karaoke: Lyrics Transcription Review
110
119
  </Typography>
111
120
  {isReadOnly && (
112
121
  <Button
113
122
  variant="outlined"
123
+ size="small"
114
124
  startIcon={<UploadFileIcon />}
115
125
  onClick={onFileLoad}
116
126
  fullWidth={isMobile}
@@ -122,87 +132,74 @@ export default function Header({
122
132
 
123
133
  <Box sx={{
124
134
  display: 'flex',
125
- gap: 2,
126
- mb: 3,
127
- flexDirection: isMobile ? 'column' : 'row'
135
+ gap: 1,
136
+ mb: 1,
137
+ flexDirection: isMobile ? 'column' : 'row',
138
+ height: '140px'
128
139
  }}>
129
140
  <Box sx={{
130
- display: 'flex',
131
- flexDirection: 'column',
132
- gap: 1,
133
- minWidth: '250px',
134
- position: 'relative'
141
+ width: '280px',
142
+ position: 'relative',
143
+ height: '100%'
135
144
  }}>
136
- <Typography variant="subtitle2" color="text.secondary">
137
- Correction Handlers
138
- </Typography>
145
+ <Paper sx={{
146
+ p: 0.8,
147
+ height: '100%',
148
+ display: 'flex',
149
+ flexDirection: 'column'
150
+ }}>
151
+ <Typography variant="subtitle2" color="text.secondary" sx={{ mb: 0.5, fontSize: '0.7rem' }}>
152
+ Correction Handlers
153
+ </Typography>
139
154
 
140
- {availableHandlers.map(handler => (
141
- <Tooltip
142
- key={handler.id}
143
- title={handler.description}
144
- placement="right"
145
- >
146
- <FormControlLabel
147
- control={
148
- <Switch
149
- checked={enabledHandlers.has(handler.id)}
150
- onChange={(e) => onHandlerToggle(handler.id, e.target.checked)}
151
- size="small"
152
- disabled={isUpdatingHandlers}
153
- />
154
- }
155
- label={`${handler.name} (${handlerCounts[handler.id] || 0})`}
156
- onClick={(e) => {
157
- if ((e.target as HTMLElement).tagName !== 'INPUT') {
158
- e.preventDefault();
159
- e.stopPropagation();
160
- onHandlerClick?.(handler.id);
161
- }
162
- }}
163
- sx={{
164
- ml: 0,
165
- '& .MuiFormControlLabel-label': {
166
- fontSize: '0.875rem',
167
- cursor: 'pointer'
168
- }
169
- }}
170
- />
171
- </Tooltip>
172
- ))}
173
-
174
- {isUpdatingHandlers && (
175
155
  <Box sx={{
176
- position: 'absolute',
177
- top: 0,
178
- left: 0,
179
- right: 0,
180
- bottom: 0,
156
+ flex: 1,
157
+ overflow: 'auto',
181
158
  display: 'flex',
182
- alignItems: 'center',
183
- justifyContent: 'center',
184
- backgroundColor: 'rgba(255, 255, 255, 0.7)',
185
- borderRadius: 1,
186
- zIndex: 1
159
+ flexDirection: 'column'
187
160
  }}>
188
- <Box sx={{
189
- display: 'flex',
190
- alignItems: 'center',
191
- gap: 2,
192
- padding: 2,
193
- backgroundColor: 'rgba(255, 255, 255, 0.9)',
194
- borderRadius: 1,
195
- boxShadow: 1
196
- }}>
197
- <CircularProgress size={24} />
198
- <Typography variant="body2" color="text.secondary">
199
- Updating corrections...
200
- </Typography>
201
- </Box>
161
+ {availableHandlers.map(handler => (
162
+ <Box key={handler.id} sx={{ mb: 0.5 }}>
163
+ <Tooltip
164
+ title={handler.description}
165
+ placement="right"
166
+ >
167
+ <FormControlLabel
168
+ control={
169
+ <Switch
170
+ checked={enabledHandlers.has(handler.id)}
171
+ onChange={(e) => onHandlerToggle(handler.id, e.target.checked)}
172
+ size="small"
173
+ disabled={isUpdatingHandlers}
174
+ />
175
+ }
176
+ label={`${handler.name} (${handlerCounts[handler.id] || 0})`}
177
+ onClick={(e) => {
178
+ if ((e.target as HTMLElement).tagName !== 'INPUT') {
179
+ e.preventDefault();
180
+ e.stopPropagation();
181
+ onHandlerClick?.(handler.id);
182
+ }
183
+ }}
184
+ sx={{
185
+ ml: 0,
186
+ py: 0,
187
+ my: 0,
188
+ minHeight: '24px',
189
+ '& .MuiFormControlLabel-label': {
190
+ fontSize: '0.7rem',
191
+ cursor: 'pointer',
192
+ lineHeight: 1.2
193
+ }
194
+ }}
195
+ />
196
+ </Tooltip>
197
+ </Box>
198
+ ))}
202
199
  </Box>
203
- )}
200
+ </Paper>
204
201
  </Box>
205
- <Box sx={{ flexGrow: 1 }}>
202
+ <Box sx={{ flex: 1, height: '100%' }}>
206
203
  <CorrectionMetrics
207
204
  // Anchor metrics
208
205
  anchorCount={data.metadata.anchor_sequences_count}
@@ -226,24 +223,67 @@ export default function Header({
226
223
  </Box>
227
224
  </Box>
228
225
 
229
- <Box sx={{
230
- display: 'flex',
231
- flexDirection: isMobile ? 'column' : 'row',
232
- gap: 5,
233
- alignItems: 'flex-start',
234
- justifyContent: 'flex-start',
235
- mb: 3
236
- }}>
237
- <ModeSelector
238
- effectiveMode={effectiveMode}
239
- onChange={onModeChange}
240
- />
241
- <AudioPlayer
242
- apiClient={apiClient}
243
- onTimeUpdate={onTimeUpdate}
244
- audioHash={audioHash}
245
- />
246
- </Box>
226
+ <Paper sx={{ p: 0.8, mb: 1 }}>
227
+ <Box sx={{
228
+ display: 'flex',
229
+ flexDirection: isMobile ? 'column' : 'row',
230
+ gap: 1,
231
+ alignItems: isMobile ? 'flex-start' : 'center',
232
+ justifyContent: 'space-between',
233
+ width: '100%'
234
+ }}>
235
+ <Box sx={{
236
+ display: 'flex',
237
+ gap: 1,
238
+ flexDirection: isMobile ? 'column' : 'row',
239
+ alignItems: isMobile ? 'flex-start' : 'center',
240
+ height: '32px'
241
+ }}>
242
+ <ModeSelector
243
+ effectiveMode={effectiveMode}
244
+ onChange={onModeChange}
245
+ />
246
+ {!isReadOnly && (
247
+ <Button
248
+ variant="outlined"
249
+ size="small"
250
+ onClick={onFindReplace}
251
+ startIcon={<FindReplaceIcon />}
252
+ sx={{ minWidth: 'fit-content', height: '32px' }}
253
+ >
254
+ Find/Replace
255
+ </Button>
256
+ )}
257
+ {!isReadOnly && onEditSync && (
258
+ <Button
259
+ variant="outlined"
260
+ size="small"
261
+ onClick={onEditSync}
262
+ startIcon={<TimerIcon />}
263
+ sx={{ minWidth: 'fit-content', height: '32px' }}
264
+ >
265
+ Edit Sync
266
+ </Button>
267
+ )}
268
+ <AudioPlayer
269
+ apiClient={apiClient}
270
+ onTimeUpdate={onTimeUpdate}
271
+ audioHash={audioHash}
272
+ />
273
+ </Box>
274
+ {!isReadOnly && apiClient && onAddLyrics && (
275
+ <Button
276
+ variant="outlined"
277
+ size="small"
278
+ onClick={onAddLyrics}
279
+ startIcon={<TextSnippetIcon />}
280
+ sx={{ minWidth: 'fit-content', height: '32px' }}
281
+ >
282
+ Add Reference Lyrics
283
+ </Button>
284
+ )}
285
+ </Box>
286
+ </Paper>
247
287
  </>
248
288
  )
249
289
  }