lyrics-transcriber 0.12.9__tar.gz → 0.14.0__tar.gz

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 (16) hide show
  1. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/PKG-INFO +16 -15
  2. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/lyrics_transcriber/transcriber.py +25 -11
  3. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/lyrics_transcriber/utils/cli.py +5 -3
  4. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/pyproject.toml +16 -15
  5. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/LICENSE +0 -0
  6. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/README.md +0 -0
  7. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/lyrics_transcriber/__init__.py +0 -0
  8. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/lyrics_transcriber/llm_prompts/README.md +0 -0
  9. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/lyrics_transcriber/llm_prompts/llm_prompt_lyrics_correction_andrew_handwritten_20231118.txt +0 -0
  10. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/lyrics_transcriber/llm_prompts/llm_prompt_lyrics_correction_gpt_optimised_20231119.txt +0 -0
  11. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/lyrics_transcriber/llm_prompts/llm_prompt_lyrics_matching_andrew_handwritten_20231118.txt +0 -0
  12. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/lyrics_transcriber/llm_prompts/promptfooconfig.yaml +0 -0
  13. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/lyrics_transcriber/llm_prompts/test_data/ABBA-UnderAttack-Genius.txt +0 -0
  14. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/lyrics_transcriber/utils/__init__.py +0 -0
  15. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/lyrics_transcriber/utils/ass.py +0 -0
  16. {lyrics_transcriber-0.12.9 → lyrics_transcriber-0.14.0}/lyrics_transcriber/utils/subtitles.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lyrics-transcriber
3
- Version: 0.12.9
3
+ Version: 0.14.0
4
4
  Summary: Automatically create synchronised lyrics files in ASS and MidiCo LRC formats with word-level timestamps, using Whisper and lyrics from Genius and Spotify
5
5
  Home-page: https://github.com/karaokenerds/python-lyrics-transcriber
6
6
  License: MIT
@@ -13,21 +13,22 @@ Classifier: Programming Language :: Python :: 3.9
13
13
  Classifier: Programming Language :: Python :: 3.10
14
14
  Classifier: Programming Language :: Python :: 3.11
15
15
  Classifier: Programming Language :: Python :: 3.12
16
- Requires-Dist: Cython (>=0,<1)
17
- Requires-Dist: dtw-python (>=1,<2)
18
- Requires-Dist: llvmlite (>=0,<1)
19
- Requires-Dist: lyricsgenius (>=3,<4)
20
- Requires-Dist: numba (>=0.57,<0.58)
21
- Requires-Dist: numpy (>=1,<2)
22
- Requires-Dist: onnx (>=1,<2)
23
- Requires-Dist: onnxruntime (>=1,<2)
16
+ Requires-Dist: Cython (>=0)
17
+ Requires-Dist: dtw-python (>=1)
18
+ Requires-Dist: llvmlite (>=0)
19
+ Requires-Dist: lyricsgenius (>=3)
20
+ Requires-Dist: numba (>=0.57)
21
+ Requires-Dist: numpy (>=1)
22
+ Requires-Dist: onnx (>=1)
23
+ Requires-Dist: onnxruntime (>=1)
24
24
  Requires-Dist: openai (>=1,<2)
25
- Requires-Dist: openai-whisper (==20231117)
26
- Requires-Dist: python-slugify (>=8,<9)
27
- Requires-Dist: syrics (>=0,<1)
28
- Requires-Dist: torch (>1)
29
- Requires-Dist: tqdm (>=4,<5)
30
- Requires-Dist: whisper-timestamped (>=1,<2)
25
+ Requires-Dist: openai-whisper (>=20231117)
26
+ Requires-Dist: python-slugify (>=8)
27
+ Requires-Dist: syrics (>=0)
28
+ Requires-Dist: torch (>=1)
29
+ Requires-Dist: tqdm (>=4)
30
+ Requires-Dist: transformers (>=4)
31
+ Requires-Dist: whisper-timestamped (>=1)
31
32
  Project-URL: Documentation, https://github.com/karaokenerds/python-lyrics-transcriber/blob/main/README.md
32
33
  Project-URL: Repository, https://github.com/karaokenerds/python-lyrics-transcriber
33
34
  Description-Content-Type: text/markdown
@@ -29,7 +29,7 @@ class LyricsTranscriber:
29
29
  log_level=logging.DEBUG,
30
30
  log_formatter=None,
31
31
  transcription_model="medium",
32
- llm_model="gpt-4-1106-preview",
32
+ llm_model="gpt-4o",
33
33
  llm_prompt_matching="lyrics_transcriber/llm_prompts/llm_prompt_lyrics_matching_andrew_handwritten_20231118.txt",
34
34
  llm_prompt_correction="lyrics_transcriber/llm_prompts/llm_prompt_lyrics_correction_andrew_handwritten_20231118.txt",
35
35
  render_video=False,
@@ -66,7 +66,15 @@ class LyricsTranscriber:
66
66
  self.llm_model = llm_model
67
67
  self.llm_prompt_matching = llm_prompt_matching
68
68
  self.llm_prompt_correction = llm_prompt_correction
69
+
69
70
  self.openai_client = OpenAI()
71
+
72
+ # Uncomment for local models e.g. with ollama
73
+ # self.openai_client = OpenAI(
74
+ # base_url="http://localhost:11434/v1",
75
+ # api_key="ollama",
76
+ # )
77
+
70
78
  self.openai_client.log = self.log_level
71
79
 
72
80
  self.render_video = render_video
@@ -190,6 +198,9 @@ class LyricsTranscriber:
190
198
  online_lyrics_text_key = f"{online_lyrics_source}_lyrics_text"
191
199
  online_lyrics_filepath_key = f"{online_lyrics_source}_lyrics_filepath"
192
200
 
201
+ if online_lyrics_text_key not in self.outputs:
202
+ continue
203
+
193
204
  data_input_str = (
194
205
  f'Data input 1:\n{self.outputs["transcribed_lyrics_text"]}\nData input 2:\n{self.outputs[online_lyrics_text_key]}\n'
195
206
  )
@@ -274,7 +285,7 @@ class LyricsTranscriber:
274
285
  total_segments = len(self.outputs["transcription_data_dict"]["segments"])
275
286
  self.logger.info(f"Beginning correction using LLM, total segments: {total_segments}")
276
287
 
277
- with open(self.outputs["llm_transcript_filepath"], "a", buffering=1) as llm_transcript_file:
288
+ with open(self.outputs["llm_transcript_filepath"], "a", buffering=1, encoding="utf-8") as llm_transcript_file:
278
289
  self.logger.debug(f"writing LLM chat instructions: {self.outputs['llm_transcript_filepath']}")
279
290
 
280
291
  llm_transcript_header = f"--- SYSTEM instructions passed in for all segments ---:\n\n{system_prompt}\n"
@@ -370,7 +381,7 @@ class LyricsTranscriber:
370
381
  self.logger.info(f'Successfully processed correction for all {len(corrected_lyrics_dict["segments"])} lyrics segments')
371
382
 
372
383
  self.logger.debug(f"writing corrected lyrics data JSON filepath: {corrected_lyrics_data_json_cache_filepath}")
373
- with open(corrected_lyrics_data_json_cache_filepath, "w") as corrected_lyrics_data_json_cache_file:
384
+ with open(corrected_lyrics_data_json_cache_filepath, "w", encoding="utf-8") as corrected_lyrics_data_json_cache_file:
374
385
  corrected_lyrics_data_json_cache_file.write(json.dumps(corrected_lyrics_dict, indent=4))
375
386
 
376
387
  self.outputs["corrected_lyrics_data_filepath"] = corrected_lyrics_data_json_cache_filepath
@@ -388,8 +399,11 @@ class LyricsTranscriber:
388
399
  },
389
400
  }
390
401
 
391
- input_cost = price_dollars_per_1000_tokens[self.llm_model]["input"] * (self.outputs["llm_token_usage"]["input"] / 1000)
392
- output_cost = price_dollars_per_1000_tokens[self.llm_model]["output"] * (self.outputs["llm_token_usage"]["output"] / 1000)
402
+ input_price = price_dollars_per_1000_tokens.get(self.llm_model, {"input": 0, "output": 0})["input"]
403
+ output_price = price_dollars_per_1000_tokens.get(self.llm_model, {"input": 0, "output": 0})["output"]
404
+
405
+ input_cost = input_price * (self.outputs["llm_token_usage"]["input"] / 1000)
406
+ output_cost = output_price * (self.outputs["llm_token_usage"]["output"] / 1000)
393
407
 
394
408
  self.outputs["llm_costs_usd"]["input"] = round(input_cost, 3)
395
409
  self.outputs["llm_costs_usd"]["output"] = round(output_cost, 3)
@@ -405,7 +419,7 @@ class LyricsTranscriber:
405
419
  self.outputs["corrected_lyrics_text"] = ""
406
420
 
407
421
  self.logger.debug(f"writing lyrics plain text to corrected_lyrics_text_filepath: {corrected_lyrics_text_filepath}")
408
- with open(corrected_lyrics_text_filepath, "w") as f:
422
+ with open(corrected_lyrics_text_filepath, "w", encoding="utf-8") as f:
409
423
  for corrected_segment in self.outputs["corrected_lyrics_data_dict"]["segments"]:
410
424
  self.outputs["corrected_lyrics_text"] += corrected_segment["text"].strip() + "\n"
411
425
  f.write(corrected_segment["text".strip()] + "\n")
@@ -452,7 +466,7 @@ class LyricsTranscriber:
452
466
  self.logger.debug(
453
467
  f"writing lyrics data JSON to spotify_lyrics_data_json_cache_filepath: {spotify_lyrics_data_json_cache_filepath}"
454
468
  )
455
- with open(spotify_lyrics_data_json_cache_filepath, "w") as f:
469
+ with open(spotify_lyrics_data_json_cache_filepath, "w", encoding="utf-8") as f:
456
470
  f.write(spotify_lyrics_json)
457
471
  except Exception as e:
458
472
  self.logger.warn(f"caught exception while attempting to fetch from spotify: ", e)
@@ -472,7 +486,7 @@ class LyricsTranscriber:
472
486
  self.outputs["spotify_lyrics_text"] = ""
473
487
 
474
488
  self.logger.debug(f"writing lyrics plain text to spotify_lyrics_text_filepath: {spotify_lyrics_text_filepath}")
475
- with open(spotify_lyrics_text_filepath, "w") as f:
489
+ with open(spotify_lyrics_text_filepath, "w", encoding="utf-8") as f:
476
490
  for line in lines:
477
491
  self.outputs["spotify_lyrics_text"] += line["words"].strip() + "\n"
478
492
  f.write(line["words"].strip() + "\n")
@@ -504,7 +518,7 @@ class LyricsTranscriber:
504
518
  lyrics = self.clean_genius_lyrics(song.lyrics)
505
519
 
506
520
  self.logger.debug(f"writing clean lyrics to genius_lyrics_cache_filepath: {genius_lyrics_cache_filepath}")
507
- with open(genius_lyrics_cache_filepath, "w") as f:
521
+ with open(genius_lyrics_cache_filepath, "w", encoding="utf-8") as f:
508
522
  f.write(lyrics)
509
523
 
510
524
  self.outputs["genius_lyrics_filepath"] = genius_lyrics_cache_filepath
@@ -558,7 +572,7 @@ class LyricsTranscriber:
558
572
 
559
573
  lrc_filename = self.outputs["midico_lrc_filepath"]
560
574
  self.logger.debug(f"writing midico formatted word timestamps to LRC file: {lrc_filename}")
561
- with open(lrc_filename, "w") as f:
575
+ with open(lrc_filename, "w", encoding="utf-8") as f:
562
576
  f.write("[re:MidiCo]\n")
563
577
  for segment in self.outputs["corrected_lyrics_data_dict"]["segments"]:
564
578
  for i, word in enumerate(segment["words"]):
@@ -752,7 +766,7 @@ class LyricsTranscriber:
752
766
  self.outputs["transcribed_lyrics_text"] = ""
753
767
 
754
768
  self.logger.debug(f"writing lyrics plain text to transcribed_lyrics_text_filepath: {transcribed_lyrics_text_filepath}")
755
- with open(transcribed_lyrics_text_filepath, "w") as f:
769
+ with open(transcribed_lyrics_text_filepath, "w", encoding="utf-8") as f:
756
770
  for segment in self.outputs["transcription_data_dict"]["segments"]:
757
771
  self.outputs["transcribed_lyrics_text"] += segment["text"] + "\n"
758
772
  f.write(segment["text"].strip() + "\n")
@@ -2,7 +2,6 @@
2
2
  import argparse
3
3
  import logging
4
4
  import pkg_resources
5
- from lyrics_transcriber import LyricsTranscriber
6
5
 
7
6
 
8
7
  def main():
@@ -66,8 +65,8 @@ def main():
66
65
 
67
66
  parser.add_argument(
68
67
  "--llm_model",
69
- default="gpt-4-1106-preview",
70
- help="Optional: LLM model to use (currently only supports OpenAI chat completion models, e.g. gpt-4-1106-preview). Default: gpt-3.5-turbo-1106",
68
+ default="gpt-4o",
69
+ help="Optional: LLM model to use (currently only supports OpenAI chat completion compatible models",
71
70
  )
72
71
 
73
72
  parser.add_argument(
@@ -110,6 +109,9 @@ def main():
110
109
 
111
110
  logger.debug("Loading LyricsTranscriber class")
112
111
 
112
+ # Lazy load this class so help output is printed quickly rather than waiting for heavy libraries to load
113
+ from lyrics_transcriber import LyricsTranscriber
114
+
113
115
  transcriber = LyricsTranscriber(
114
116
  args.audio_filepath,
115
117
  genius_api_token=args.genius_api_token,
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "lyrics-transcriber"
3
- version = "0.12.9"
3
+ version = "0.14.0"
4
4
  description = "Automatically create synchronised lyrics files in ASS and MidiCo LRC formats with word-level timestamps, using Whisper and lyrics from Genius and Spotify"
5
5
  authors = ["Andrew Beveridge <andrew@beveridge.uk>"]
6
6
  license = "MIT"
@@ -13,21 +13,22 @@ documentation = "https://github.com/karaokenerds/python-lyrics-transcriber/blob/
13
13
 
14
14
  [tool.poetry.dependencies]
15
15
  python = ">=3.9"
16
- Cython = "^0"
17
- dtw-python = "^1"
18
- llvmlite = "^0"
19
- numba = "^0.57"
20
- numpy = "^1"
21
- onnx = "^1"
22
- onnxruntime = "^1"
23
- torch = ">1"
24
- tqdm = "^4"
25
- lyricsgenius = "^3"
26
- python-slugify = "^8"
27
- syrics = "^0"
16
+ Cython = ">=0"
17
+ dtw-python = ">=1"
18
+ llvmlite = ">=0"
19
+ numba = ">=0.57"
20
+ numpy = ">=1"
21
+ onnx = ">=1"
22
+ onnxruntime = ">=1"
23
+ torch = ">=1"
24
+ tqdm = ">=4"
25
+ lyricsgenius = ">=3"
26
+ python-slugify = ">=8"
27
+ syrics = ">=0"
28
28
  openai = "^1"
29
- openai-whisper = "20231117"
30
- whisper-timestamped = "^1"
29
+ openai-whisper = ">=20231117"
30
+ transformers = ">=4"
31
+ whisper-timestamped = ">=1"
31
32
  # Note: after adding openai-whisper and whisper-timestamped with poetry lock, I then removed all traces of triton
32
33
  # from poetry.lock before running poetry install, as triton doesn't support macOS but isn't actually needed for whisper.
33
34
  # This was the only way I was able to get a working cross-platform build published to PyPI.