karaoke-gen 0.76.20__py3-none-any.whl → 0.82.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.
- karaoke_gen/instrumental_review/static/index.html +179 -16
- karaoke_gen/karaoke_gen.py +5 -4
- karaoke_gen/lyrics_processor.py +25 -6
- {karaoke_gen-0.76.20.dist-info → karaoke_gen-0.82.0.dist-info}/METADATA +79 -3
- {karaoke_gen-0.76.20.dist-info → karaoke_gen-0.82.0.dist-info}/RECORD +33 -31
- lyrics_transcriber/core/config.py +8 -0
- lyrics_transcriber/core/controller.py +43 -1
- lyrics_transcriber/correction/agentic/observability/langfuse_integration.py +178 -5
- lyrics_transcriber/correction/agentic/prompts/__init__.py +23 -0
- lyrics_transcriber/correction/agentic/prompts/classifier.py +66 -6
- lyrics_transcriber/correction/agentic/prompts/langfuse_prompts.py +298 -0
- lyrics_transcriber/correction/agentic/providers/config.py +7 -0
- lyrics_transcriber/correction/agentic/providers/constants.py +1 -1
- lyrics_transcriber/correction/agentic/providers/langchain_bridge.py +22 -7
- lyrics_transcriber/correction/agentic/providers/model_factory.py +28 -13
- lyrics_transcriber/correction/agentic/router.py +18 -13
- lyrics_transcriber/correction/corrector.py +1 -45
- lyrics_transcriber/frontend/.gitignore +1 -0
- lyrics_transcriber/frontend/e2e/agentic-corrections.spec.ts +207 -0
- lyrics_transcriber/frontend/e2e/fixtures/agentic-correction-data.json +226 -0
- lyrics_transcriber/frontend/package.json +4 -1
- lyrics_transcriber/frontend/playwright.config.ts +1 -1
- lyrics_transcriber/frontend/src/components/CorrectedWordWithActions.tsx +34 -30
- lyrics_transcriber/frontend/src/components/Header.tsx +141 -34
- lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx +120 -3
- lyrics_transcriber/frontend/src/components/TranscriptionView.tsx +11 -1
- lyrics_transcriber/frontend/src/components/shared/components/HighlightedText.tsx +122 -35
- lyrics_transcriber/frontend/src/components/shared/types.ts +6 -0
- lyrics_transcriber/output/generator.py +50 -3
- lyrics_transcriber/transcribers/local_whisper.py +260 -0
- lyrics_transcriber/correction/handlers/llm.py +0 -293
- lyrics_transcriber/correction/handlers/llm_providers.py +0 -60
- {karaoke_gen-0.76.20.dist-info → karaoke_gen-0.82.0.dist-info}/WHEEL +0 -0
- {karaoke_gen-0.76.20.dist-info → karaoke_gen-0.82.0.dist-info}/entry_points.txt +0 -0
- {karaoke_gen-0.76.20.dist-info → karaoke_gen-0.82.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -8,12 +8,12 @@ karaoke_gen/instrumental_review/analyzer.py,sha256=Heg8TbrwM4g5IV7bavmO6EfVD4M0U
|
|
|
8
8
|
karaoke_gen/instrumental_review/editor.py,sha256=_DGTjKMk5WhoGtLGtTvHzU522LJyQQ_DSY1r8fULuiA,11568
|
|
9
9
|
karaoke_gen/instrumental_review/models.py,sha256=cUSb_JheJK0cGdKx9f59-9sRvRrhrgdTdKBzQN3lHto,5226
|
|
10
10
|
karaoke_gen/instrumental_review/server.py,sha256=Ick90X77t2EeMRwtx2U08sSybadQyWH7G0tDG-4JqP4,19377
|
|
11
|
-
karaoke_gen/instrumental_review/static/index.html,sha256=
|
|
11
|
+
karaoke_gen/instrumental_review/static/index.html,sha256=1lzo_W5B4HxNStWPiVaP4I6ctqDkXAABJkQmojvBDqc,63235
|
|
12
12
|
karaoke_gen/instrumental_review/waveform.py,sha256=Q6LBPZrJAD6mzZ7TmRf3Tf4gwYhUYTHumJKytLs3hSg,12940
|
|
13
13
|
karaoke_gen/karaoke_finalise/__init__.py,sha256=HqZ7TIhgt_tYZ-nb_NNCaejWAcF_aK-7wJY5TaW_keM,46
|
|
14
14
|
karaoke_gen/karaoke_finalise/karaoke_finalise.py,sha256=Wn1KcdRyINT63UxKUPT9uB-bsrFVih0Im_cjXtequS0,93534
|
|
15
|
-
karaoke_gen/karaoke_gen.py,sha256
|
|
16
|
-
karaoke_gen/lyrics_processor.py,sha256=
|
|
15
|
+
karaoke_gen/karaoke_gen.py,sha256=84n2SE0MixJr01_btLmm5cVdf35hJvp7W638b8TKR-Q,65734
|
|
16
|
+
karaoke_gen/lyrics_processor.py,sha256=9BtL2uJa4Ekrodj2w_SXSeOraVKCB2kzYuHcGHTFpo8,23979
|
|
17
17
|
karaoke_gen/metadata.py,sha256=SZW6TuUpkGGU98gRdjPfrR8F4vWXjnfCSGry2XD5_A4,6689
|
|
18
18
|
karaoke_gen/pipeline/__init__.py,sha256=-MZnba4qobr1qGDamG9CieLl2pWCZMEB5_Yur62RKeM,2106
|
|
19
19
|
karaoke_gen/pipeline/base.py,sha256=yg4LIm7Mc9ER0zCmZcUv4huEkotSSXK_0OAFio-TSNI,6235
|
|
@@ -44,8 +44,8 @@ lyrics_transcriber/__init__.py,sha256=g9ZbJg9U1qo7XzrC25J3bTKcNzzwUJWDVdi_7-hjcM
|
|
|
44
44
|
lyrics_transcriber/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
45
|
lyrics_transcriber/cli/cli_main.py,sha256=F72ENLTj934bXjHAUbRm0toCK73qnuJhwEm9agBVKHQ,11596
|
|
46
46
|
lyrics_transcriber/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
|
-
lyrics_transcriber/core/config.py,sha256=
|
|
48
|
-
lyrics_transcriber/core/controller.py,sha256=
|
|
47
|
+
lyrics_transcriber/core/config.py,sha256=_X_d1wSYTJjSquqbODYCwPdOYpnSR9KERwvr_jkdYls,2056
|
|
48
|
+
lyrics_transcriber/core/controller.py,sha256=dUJvnehr9_Mv3Syj_TWZQsQVsDD1w8AdF5_1xISA2cw,31661
|
|
49
49
|
lyrics_transcriber/correction/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
50
|
lyrics_transcriber/correction/agentic/__init__.py,sha256=p7PHiebuvRs8RDlPDs-9gLZKzXG5KfWg3fFCdDhY6pE,222
|
|
51
51
|
lyrics_transcriber/correction/agentic/adapter.py,sha256=Z0JBTAA7xlSdctCHqO9nBMl78C4XmqsLKKtS6BvNZNI,2912
|
|
@@ -75,29 +75,30 @@ lyrics_transcriber/correction/agentic/models/observability_metrics.py,sha256=xGd
|
|
|
75
75
|
lyrics_transcriber/correction/agentic/models/schemas.py,sha256=skWXqGkJnv9NvmvjktBqrH_4Ohyzg2x0ZMsVINbXKdg,2141
|
|
76
76
|
lyrics_transcriber/correction/agentic/models/utils.py,sha256=tX7flxCB4aLrgZWkHuEt7Gr8kaLkMsXzTdWSec6Xsts,580
|
|
77
77
|
lyrics_transcriber/correction/agentic/observability/__init__.py,sha256=RuaepVsltWdaF1aF_YmNVJTJ6_bbNDFo3Sp-ruBvyHA,85
|
|
78
|
-
lyrics_transcriber/correction/agentic/observability/langfuse_integration.py,sha256=
|
|
78
|
+
lyrics_transcriber/correction/agentic/observability/langfuse_integration.py,sha256=5oBfoFT-QExZttD2wlIzXRhgSglNElFFwz8Et36vZos,7014
|
|
79
79
|
lyrics_transcriber/correction/agentic/observability/metrics.py,sha256=Js_m6ljdI6Xgd9X9eHtboCsf9gjYsN1zOv3_XSwjgKk,1907
|
|
80
80
|
lyrics_transcriber/correction/agentic/observability/performance.py,sha256=ekjzgL65gfs1SpKR_befu1wdWZU9xDlcafJm8htSvks,328
|
|
81
|
-
lyrics_transcriber/correction/agentic/prompts/__init__.py,sha256=
|
|
82
|
-
lyrics_transcriber/correction/agentic/prompts/classifier.py,sha256=
|
|
81
|
+
lyrics_transcriber/correction/agentic/prompts/__init__.py,sha256=riiZ-f4jlvq4QjtyCpmv-sSzfcLy7O99pMBwV1H5Usc,605
|
|
82
|
+
lyrics_transcriber/correction/agentic/prompts/classifier.py,sha256=FwUSL59Y-5q9J1CDW8iyzyiajcy4-uq5MzfWu0If_Yo,11899
|
|
83
|
+
lyrics_transcriber/correction/agentic/prompts/langfuse_prompts.py,sha256=hjQhyY_GBuZt_oY9DacutXvA9dJCZksRY2fKmveJm_A,10898
|
|
83
84
|
lyrics_transcriber/correction/agentic/providers/__init__.py,sha256=PS7C4sKDfa6S9lSo33GXIRamCLsv0Jn7u0GtXuhiRD4,95
|
|
84
85
|
lyrics_transcriber/correction/agentic/providers/base.py,sha256=bExuntMLLInMmWWNzN81_ScWQJhNYbtlF3wZYhlX-qw,1059
|
|
85
86
|
lyrics_transcriber/correction/agentic/providers/circuit_breaker.py,sha256=D3Jg4YHqvy4gzlxfkALa7PztyYQpJb8NwJAonMS0TSI,4694
|
|
86
|
-
lyrics_transcriber/correction/agentic/providers/config.py,sha256=
|
|
87
|
-
lyrics_transcriber/correction/agentic/providers/constants.py,sha256=
|
|
87
|
+
lyrics_transcriber/correction/agentic/providers/config.py,sha256=w6-fkapEy3BgoFIsRfZ44XUCV4zuicFSNoSoVAe5lYE,3282
|
|
88
|
+
lyrics_transcriber/correction/agentic/providers/constants.py,sha256=cXLzKTyFVt9q6wQd_gWcv3EZ5Sm27AOAz6NyPapcess,695
|
|
88
89
|
lyrics_transcriber/correction/agentic/providers/health.py,sha256=F8pHY5BQYvylGRDGXUHplcAJooAyiqVLRhBl4kHC1H8,710
|
|
89
|
-
lyrics_transcriber/correction/agentic/providers/langchain_bridge.py,sha256=
|
|
90
|
-
lyrics_transcriber/correction/agentic/providers/model_factory.py,sha256=
|
|
90
|
+
lyrics_transcriber/correction/agentic/providers/langchain_bridge.py,sha256=H3C3BNjAixfkOJojxWXv-P-svlgj5rJEJdk0zPIjh7E,8540
|
|
91
|
+
lyrics_transcriber/correction/agentic/providers/model_factory.py,sha256=CeVDblf1HdphtUHVn3Cgl07YAeUuSxTjEHHFJN8Frj0,8257
|
|
91
92
|
lyrics_transcriber/correction/agentic/providers/response_cache.py,sha256=Byr7fQJsgUMFlsvHeVCxTiFjjnbsg3KIlEmEEtAo-Gw,7047
|
|
92
93
|
lyrics_transcriber/correction/agentic/providers/response_parser.py,sha256=a8pdUYKBS5X72gck3u1ndFYB__UN0UijAdxNhbHp8ZQ,3809
|
|
93
94
|
lyrics_transcriber/correction/agentic/providers/retry_executor.py,sha256=hX21Zwy2cSECAw7k13ndEinWRqwjo4xYoSCQ2B2CUf0,3912
|
|
94
|
-
lyrics_transcriber/correction/agentic/router.py,sha256=
|
|
95
|
+
lyrics_transcriber/correction/agentic/router.py,sha256=akP28A0lftmsnSyMOW6k7iTC1pv4LEgilXhIkcfJzlE,1437
|
|
95
96
|
lyrics_transcriber/correction/agentic/workflows/__init__.py,sha256=OsBExAbIIKxJgX6FKXFOgcUjIG9AWJQV_fESZVdO8mo,77
|
|
96
97
|
lyrics_transcriber/correction/agentic/workflows/consensus_workflow.py,sha256=gMuLTUxkgYaciMsI4yrZSC3wi--7V_PgaDNE-Vd6FE8,575
|
|
97
98
|
lyrics_transcriber/correction/agentic/workflows/correction_graph.py,sha256=kgZKnz0h9cG1EfhW7BSSl-kSpQtJrRM_S86kAniXfE4,1815
|
|
98
99
|
lyrics_transcriber/correction/agentic/workflows/feedback_workflow.py,sha256=KsKLD3AP66YYmXfUn-mVZjERYLtU1Zs4a-7CB2zDfas,596
|
|
99
100
|
lyrics_transcriber/correction/anchor_sequence.py,sha256=5tl4Cjiw5UlLbEb1Oy-g3ebKCinXSwohdaCB9-rTMtI,43798
|
|
100
|
-
lyrics_transcriber/correction/corrector.py,sha256=
|
|
101
|
+
lyrics_transcriber/correction/corrector.py,sha256=qW6GwOOLM8zxYtYMmGy9Rzk_4mJzdpGiCXW3LQFXn14,38362
|
|
101
102
|
lyrics_transcriber/correction/feedback/__init__.py,sha256=i1gd0Vb4qvlzZQ3lqA3fJjt288YP7f-MBPwOzZ7Rjh4,68
|
|
102
103
|
lyrics_transcriber/correction/feedback/schemas.py,sha256=OiF_WUqcqiEKIoburYM8kWAIundy82PQE7ImsdP8UCk,4416
|
|
103
104
|
lyrics_transcriber/correction/feedback/store.py,sha256=T4IDzf1eRA9n-wdLLrLyAW1ELYgXwK9RikJgX_B3fN8,8788
|
|
@@ -105,8 +106,6 @@ lyrics_transcriber/correction/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JC
|
|
|
105
106
|
lyrics_transcriber/correction/handlers/base.py,sha256=ZXYMFgbCmlD62dpqdFwFPlcePdHKEFrABffnG_Mu5mI,1687
|
|
106
107
|
lyrics_transcriber/correction/handlers/extend_anchor.py,sha256=IADgdPmEMokUQhh6mP-wQWLYf6GfWTvJbBjOk08A-aw,6384
|
|
107
108
|
lyrics_transcriber/correction/handlers/levenshtein.py,sha256=hMERQHVgiUDSHtamYrAjqZ3qMMok4VmQ_MYM2-nrX6w,7864
|
|
108
|
-
lyrics_transcriber/correction/handlers/llm.py,sha256=ufqHtohdU5dUXE3DikzbloAWGVgMu1wnw6P4WHRmpdk,14580
|
|
109
|
-
lyrics_transcriber/correction/handlers/llm_providers.py,sha256=MV-KCRseccg-DEimMS0D2bXJ2xhy59r2n8UZjICUoEY,2067
|
|
110
109
|
lyrics_transcriber/correction/handlers/no_space_punct_match.py,sha256=jY2fa547Qc8B63xIhF9VyWMaq5jds6E6wBqyVq6KANw,7057
|
|
111
110
|
lyrics_transcriber/correction/handlers/relaxed_word_count_match.py,sha256=x4k__6gav4-STk_TycLcg5Sw4x2vUFAj5fWmOv7Yd_w,3911
|
|
112
111
|
lyrics_transcriber/correction/handlers/repeat.py,sha256=1PJADW44egYh7N9D2fN-gDIusWVglFjGHrCZuTQYNpA,4313
|
|
@@ -117,17 +116,19 @@ lyrics_transcriber/correction/handlers/word_operations.py,sha256=410xhyO9tiqezV5
|
|
|
117
116
|
lyrics_transcriber/correction/operations.py,sha256=k5N8w_8BeR7CXiclaJ3zuu_g2KLoWSnnuD4OAmY3kJs,14010
|
|
118
117
|
lyrics_transcriber/correction/phrase_analyzer.py,sha256=dtO_2LjxnPdHJM7De40mYIdHCkozwhizVVQp5XGO7x0,16962
|
|
119
118
|
lyrics_transcriber/correction/text_utils.py,sha256=7QHK6-PY7Rx1G1E31sWiLBw00mHorRDo-M44KMHFaZs,833
|
|
120
|
-
lyrics_transcriber/frontend/.gitignore,sha256=
|
|
119
|
+
lyrics_transcriber/frontend/.gitignore,sha256=cR2ofyyWArkna_jByfaWi8gTeMhsKTSoK128PmIw218,262
|
|
121
120
|
lyrics_transcriber/frontend/.yarn/releases/yarn-4.7.0.cjs,sha256=KTYy2KCV2OpHhussV5jIPDdUSr7RftMRhqPsRUmgfAY,2765465
|
|
122
121
|
lyrics_transcriber/frontend/.yarnrc.yml,sha256=0hZQ1OTcPqTUNBqQeme4VFkIzrsabHNzLtc_M-wSgIM,66
|
|
123
122
|
lyrics_transcriber/frontend/README.md,sha256=-D6CAfKTT7Y0V3EjlZ2fMy7fyctFQ4x2TJ9vx6xtccM,1607
|
|
124
123
|
lyrics_transcriber/frontend/REPLACE_ALL_FUNCTIONALITY.md,sha256=iRZbicW5satHel9gbG-uLyZ7oq3xdp87KQlJEL1ZhK8,8384
|
|
125
124
|
lyrics_transcriber/frontend/__init__.py,sha256=nW8acRSWTjXoRwGqcTU4w-__X7tMAE0iXL0uihBN3CU,836
|
|
125
|
+
lyrics_transcriber/frontend/e2e/agentic-corrections.spec.ts,sha256=yNynyV8dUfwRJ1a0Cdr6o2SZEMFiuGAQG1ZM0Ro8q9o,7359
|
|
126
|
+
lyrics_transcriber/frontend/e2e/fixtures/agentic-correction-data.json,sha256=_h-nI76gPXuqWErpTBrZaTgcc8LNLi6j81t3Wtt--ac,8184
|
|
126
127
|
lyrics_transcriber/frontend/eslint.config.js,sha256=3ADH23ANA4NNBKFy6nCVk65e8bx1DrVd_FIaYNnhuqA,734
|
|
127
128
|
lyrics_transcriber/frontend/index.html,sha256=hcVQvxU1yITMrMS4vVLwn4YwvnlXsfl4XY9UNtXvWAw,1135
|
|
128
129
|
lyrics_transcriber/frontend/package-lock.json,sha256=gQekpsz4CAKMJ8Fi331Q3Pv5yqhZlQ-nbGoDNnF35WE,159262
|
|
129
|
-
lyrics_transcriber/frontend/package.json,sha256=
|
|
130
|
-
lyrics_transcriber/frontend/playwright.config.ts,sha256=
|
|
130
|
+
lyrics_transcriber/frontend/package.json,sha256=qujjeqPUSJizfHxK_2egicJYea8fziJO4O6u2A6N9Xw,1395
|
|
131
|
+
lyrics_transcriber/frontend/playwright.config.ts,sha256=l5aoc_rEbrYxIipTAVbpRER0FL5bAevYtRTT-chGUqA,1523
|
|
131
132
|
lyrics_transcriber/frontend/public/android-chrome-192x192.png,sha256=lg-6aPF5mGLiuG7LyftZk_0RI41srmpA8wj-NkaaQms,17632
|
|
132
133
|
lyrics_transcriber/frontend/public/android-chrome-512x512.png,sha256=x-zuKT3NYsTqAWzhKRTZeD4-0uYoUjqMPZpKTChqNJ8,123447
|
|
133
134
|
lyrics_transcriber/frontend/public/apple-touch-icon.png,sha256=6y5vGra54w5oc8VP6sn2JjoQtN9hWTKn0YPhmdlmfU0,16188
|
|
@@ -143,7 +144,7 @@ lyrics_transcriber/frontend/src/components/AddLyricsModal.tsx,sha256=ubJwQewryjU
|
|
|
143
144
|
lyrics_transcriber/frontend/src/components/AgenticCorrectionMetrics.tsx,sha256=Yg6FG0LtrneRfAYeBu3crt_RdN-_o7FojtYhDMDKi0o,8595
|
|
144
145
|
lyrics_transcriber/frontend/src/components/AppHeader.tsx,sha256=5KUVADDv9cAs2WNX9M31utQIYHKMi81unzrCW3j1fl0,2396
|
|
145
146
|
lyrics_transcriber/frontend/src/components/AudioPlayer.tsx,sha256=XOCz0VtGiAIBs1qnCwrAixwfgHbTSGpjEb1jQg8wqzc,5441
|
|
146
|
-
lyrics_transcriber/frontend/src/components/CorrectedWordWithActions.tsx,sha256=
|
|
147
|
+
lyrics_transcriber/frontend/src/components/CorrectedWordWithActions.tsx,sha256=Z5i0MMaFC1dbafUsZVsNEMkdoqBLjkA6yCWtjoMmqi8,5207
|
|
147
148
|
lyrics_transcriber/frontend/src/components/CorrectionAnnotationModal.tsx,sha256=XtF5XNLL2ztm714tXql7rKi2BX4k_bsizpZ_ZCvpu8s,13368
|
|
148
149
|
lyrics_transcriber/frontend/src/components/CorrectionDetailCard.tsx,sha256=Hp-i1iSB3pzrpPH2wIREtEHHaReimBaYi8vcSUUArlg,9512
|
|
149
150
|
lyrics_transcriber/frontend/src/components/CorrectionMetrics.tsx,sha256=CoTZS9Z3pf4lfPrzpQ2hZvLqFvt-IarSGBSCxFxD-y4,6274
|
|
@@ -154,8 +155,8 @@ lyrics_transcriber/frontend/src/components/EditTimelineSection.tsx,sha256=VQy5fp
|
|
|
154
155
|
lyrics_transcriber/frontend/src/components/EditWordList.tsx,sha256=XN59JnNPYNI4KrSenW7cYC6zUIlK7GvlyRbj9eg-Eac,13716
|
|
155
156
|
lyrics_transcriber/frontend/src/components/FileUpload.tsx,sha256=fwn2rMWtMLPTZLREMb3ps4prSf9nzxGwnjmeC6KYsJA,2383
|
|
156
157
|
lyrics_transcriber/frontend/src/components/FindReplaceModal.tsx,sha256=U7duKns4IqNXwbWFbQfdyaswnvkSRpfsU0UG__-Serc,20192
|
|
157
|
-
lyrics_transcriber/frontend/src/components/Header.tsx,sha256=
|
|
158
|
-
lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx,sha256=
|
|
158
|
+
lyrics_transcriber/frontend/src/components/Header.tsx,sha256=_lIo1ZsObF1lygXYX865Rhj053KPWvPewi7e0p11xuA,23429
|
|
159
|
+
lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx,sha256=9UZbTAXXTcYgFWwr030z-vrd8vklYrmgDCxCrPifho8,59256
|
|
159
160
|
lyrics_transcriber/frontend/src/components/LyricsSynchronizer/SyncControls.tsx,sha256=j4rQjBQVbaPsp1ra_rvEoCqmX3JFJdfNnFvj3BvfsgQ,6069
|
|
160
161
|
lyrics_transcriber/frontend/src/components/LyricsSynchronizer/TimelineCanvas.tsx,sha256=DuQBAdF8bYcAYKNEWVklXSAlEykhIDQKbELq_4SEPCg,27415
|
|
161
162
|
lyrics_transcriber/frontend/src/components/LyricsSynchronizer/UpcomingWordsBar.tsx,sha256=BXkEeo5yMgHkeOCBcZKqxMb1rspjXH-X5_6X9Hl7z3E,2588
|
|
@@ -171,16 +172,16 @@ lyrics_transcriber/frontend/src/components/ReviewChangesModal.tsx,sha256=VQg_gBF
|
|
|
171
172
|
lyrics_transcriber/frontend/src/components/SegmentDetailsModal.tsx,sha256=6ME02FkFwCgDAxW49yW260N4vbr80eAJ332Ex811GOo,1643
|
|
172
173
|
lyrics_transcriber/frontend/src/components/TimelineEditor.tsx,sha256=gJRCxdmJo80g0h5hq5AtDHK-HbOoYhMaQYvP2WgOuRI,13201
|
|
173
174
|
lyrics_transcriber/frontend/src/components/TimingOffsetModal.tsx,sha256=aivGi6ehI6cDqwtoKBb6Eif8gpPqi0t3mJT8i5Feu7Q,4803
|
|
174
|
-
lyrics_transcriber/frontend/src/components/TranscriptionView.tsx,sha256=
|
|
175
|
+
lyrics_transcriber/frontend/src/components/TranscriptionView.tsx,sha256=6FqgDS6NBbdeGMANKQyF1rjxN0CZy6tYAheOq_FTYEE,11827
|
|
175
176
|
lyrics_transcriber/frontend/src/components/WordDivider.tsx,sha256=ynib_j0w0q4iOYAk7D4IyZJCq71LykX7SaD9haGlZeI,6695
|
|
176
|
-
lyrics_transcriber/frontend/src/components/shared/components/HighlightedText.tsx,sha256=
|
|
177
|
+
lyrics_transcriber/frontend/src/components/shared/components/HighlightedText.tsx,sha256=0WFhL8BlcIrjw1BTakP-UgG0j2pripyqG5LK66a1IOE,21333
|
|
177
178
|
lyrics_transcriber/frontend/src/components/shared/components/SourceSelector.tsx,sha256=FpMn-0i1NFxdIHZN0dxHkWzIIsOEi9CJc_rQMpLyxVw,2031
|
|
178
179
|
lyrics_transcriber/frontend/src/components/shared/components/Word.tsx,sha256=CXzepxI3Negx2cqdfqLNGgesNbbIcczomXed71FupNw,2676
|
|
179
180
|
lyrics_transcriber/frontend/src/components/shared/constants.ts,sha256=GByG5KFLJOX0iCs80_PLXxZKQ5FBX5Qw0Mg05Xf8Faw,1142
|
|
180
181
|
lyrics_transcriber/frontend/src/components/shared/hooks/useWordClick.ts,sha256=eEgBHiKIWOzFK8eBzBgcQRv7StKpaPchqh3k2kFlwgY,6253
|
|
181
182
|
lyrics_transcriber/frontend/src/components/shared/styles.ts,sha256=J1jCSuRqpk1mOFYAqJudhxeozH-q1bi-dsOibLukBJU,411
|
|
182
183
|
lyrics_transcriber/frontend/src/components/shared/types.js,sha256=1DqoH1vIn6o1ng-XyBS6JRVVkf8Hj7ub_UD4x8loMjA,77
|
|
183
|
-
lyrics_transcriber/frontend/src/components/shared/types.ts,sha256=
|
|
184
|
+
lyrics_transcriber/frontend/src/components/shared/types.ts,sha256=mA7YELw4x0TI3PG2-6EuB1WmGnG36h_C4iwTOvmIoaY,4249
|
|
184
185
|
lyrics_transcriber/frontend/src/components/shared/utils/keyboardHandlers.ts,sha256=Yh5c_kOdOjE84FtKVB4BBC8QIgkFk5tO0ZJa9oJqqqU,5870
|
|
185
186
|
lyrics_transcriber/frontend/src/components/shared/utils/localStorage.ts,sha256=jpLT65Rk_toaB-8X2lRGyYZ9EoMQDI45GviUT7N9Bp0,3240
|
|
186
187
|
lyrics_transcriber/frontend/src/components/shared/utils/referenceLineCalculator.ts,sha256=TJ2oHDitFFVxm83eFEhdlwvhx--mIt3054YbET2RiXs,2575
|
|
@@ -266,7 +267,7 @@ lyrics_transcriber/output/fonts/Zurich_Cn_BT_Bold.ttf,sha256=WNG5LOQ-uGUF_WWT5aQ
|
|
|
266
267
|
lyrics_transcriber/output/fonts/arial.ttf,sha256=NcDzVZ2NtWnjbDEJW4pg1EFkPZX1kTneQOI_ragZuDM,275572
|
|
267
268
|
lyrics_transcriber/output/fonts/georgia.ttf,sha256=fQuyDGMrtZ6BoIhfVzvSFz9x9zIE3pBY_raM4DIicHI,142964
|
|
268
269
|
lyrics_transcriber/output/fonts/verdana.ttf,sha256=lu0UlJyktzks_yNbnEHVXBJTgqu-DA08K53WaJfK4Ms,139640
|
|
269
|
-
lyrics_transcriber/output/generator.py,sha256=
|
|
270
|
+
lyrics_transcriber/output/generator.py,sha256=eblMtME-OBTbf1awd9BvlTLyUer_XcIXfIo0L-l38b4,13774
|
|
270
271
|
lyrics_transcriber/output/lrc_to_cdg.py,sha256=2pi5tvreD_ADAR4RF5yVwj7OJ4Pf5Zo_EJ7rt4iH3k0,2063
|
|
271
272
|
lyrics_transcriber/output/lyrics_file.py,sha256=_KQyQjCOMIwQdQ0115uEAUIjQWTRmShkSfQuINPKxaw,3741
|
|
272
273
|
lyrics_transcriber/output/plain_text.py,sha256=XARaWcy6MeQeQCUoz0PV_bHoBw5dba-u79bjS7XucnE,3867
|
|
@@ -280,12 +281,13 @@ lyrics_transcriber/storage/dropbox.py,sha256=Dyam1ULTkoxD1X5trkZ5dGp5XhBGCn998mo
|
|
|
280
281
|
lyrics_transcriber/transcribers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
281
282
|
lyrics_transcriber/transcribers/audioshake.py,sha256=RihuLKzhhHfX7m5cjKISwIuTQkGWapCS29D6Qk3hR4U,15869
|
|
282
283
|
lyrics_transcriber/transcribers/base_transcriber.py,sha256=T3m4ZCwZ9Bpv6Jvb2hNcnllk-lmeNmADDJlSySBtP1Q,6480
|
|
284
|
+
lyrics_transcriber/transcribers/local_whisper.py,sha256=oT-MsKdkHMgRpuCdYL4o8vtCZ4Uhls7BzkRDf-QHMHM,9926
|
|
283
285
|
lyrics_transcriber/transcribers/whisper.py,sha256=YcCB1ic9H6zL1GS0jD0emu8-qlcH0QVEjjjYB4aLlIQ,13260
|
|
284
286
|
lyrics_transcriber/types.py,sha256=UJjaxhVd2o14AG4G8ToU598p0JeYdiTFjpG38jGCoYQ,27917
|
|
285
287
|
lyrics_transcriber/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
286
288
|
lyrics_transcriber/utils/word_utils.py,sha256=-cMGpj9UV4F6IsoDKAV2i1aiqSO8eI91HMAm_igtVMk,958
|
|
287
|
-
karaoke_gen-0.
|
|
288
|
-
karaoke_gen-0.
|
|
289
|
-
karaoke_gen-0.
|
|
290
|
-
karaoke_gen-0.
|
|
291
|
-
karaoke_gen-0.
|
|
289
|
+
karaoke_gen-0.82.0.dist-info/METADATA,sha256=k51l0dhnVIM5kn6lFbTCLi1oKbcV_2iSulloMXVkU0Q,23077
|
|
290
|
+
karaoke_gen-0.82.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
291
|
+
karaoke_gen-0.82.0.dist-info/entry_points.txt,sha256=xIyLe7K84ZyjO8L0_AmNectz93QjGSs5AkApMtlAd4g,160
|
|
292
|
+
karaoke_gen-0.82.0.dist-info/licenses/LICENSE,sha256=81R_4XwMZDODHD7JcZeUR8IiCU8AD7Ajl6bmwR9tYDk,1074
|
|
293
|
+
karaoke_gen-0.82.0.dist-info/RECORD,,
|
|
@@ -11,6 +11,14 @@ class TranscriberConfig:
|
|
|
11
11
|
runpod_api_key: Optional[str] = None
|
|
12
12
|
whisper_runpod_id: Optional[str] = None
|
|
13
13
|
|
|
14
|
+
# Local Whisper configuration - reads from environment variables with sensible defaults
|
|
15
|
+
# Environment variables: WHISPER_MODEL_SIZE, WHISPER_DEVICE, WHISPER_CACHE_DIR, WHISPER_LANGUAGE
|
|
16
|
+
enable_local_whisper: bool = True # Enabled by default as fallback
|
|
17
|
+
local_whisper_model_size: str = field(default_factory=lambda: os.getenv("WHISPER_MODEL_SIZE", "medium"))
|
|
18
|
+
local_whisper_device: Optional[str] = field(default_factory=lambda: os.getenv("WHISPER_DEVICE"))
|
|
19
|
+
local_whisper_cache_dir: Optional[str] = field(default_factory=lambda: os.getenv("WHISPER_CACHE_DIR"))
|
|
20
|
+
local_whisper_language: Optional[str] = field(default_factory=lambda: os.getenv("WHISPER_LANGUAGE"))
|
|
21
|
+
|
|
14
22
|
|
|
15
23
|
@dataclass
|
|
16
24
|
class LyricsConfig:
|
|
@@ -7,6 +7,7 @@ from lyrics_transcriber.types import LyricsData, TranscriptionResult, Correction
|
|
|
7
7
|
from lyrics_transcriber.transcribers.base_transcriber import BaseTranscriber
|
|
8
8
|
from lyrics_transcriber.transcribers.audioshake import AudioShakeTranscriber, AudioShakeConfig
|
|
9
9
|
from lyrics_transcriber.transcribers.whisper import WhisperTranscriber, WhisperConfig
|
|
10
|
+
from lyrics_transcriber.transcribers.local_whisper import LocalWhisperTranscriber, LocalWhisperConfig
|
|
10
11
|
from lyrics_transcriber.lyrics.base_lyrics_provider import BaseLyricsProvider, LyricsProviderConfig
|
|
11
12
|
from lyrics_transcriber.lyrics.genius import GeniusProvider
|
|
12
13
|
from lyrics_transcriber.lyrics.spotify import SpotifyProvider
|
|
@@ -206,6 +207,34 @@ class LyricsTranscriber:
|
|
|
206
207
|
else:
|
|
207
208
|
self.logger.debug("Skipping Whisper transcriber - missing runpod_api_key or whisper_runpod_id")
|
|
208
209
|
|
|
210
|
+
# Local Whisper - lowest priority, fallback when cloud services unavailable
|
|
211
|
+
if self.transcriber_config.enable_local_whisper:
|
|
212
|
+
# Check if whisper-timestamped is available
|
|
213
|
+
try:
|
|
214
|
+
import whisper_timestamped # noqa: F401
|
|
215
|
+
|
|
216
|
+
self.logger.debug("Initializing LocalWhisper transcriber")
|
|
217
|
+
transcribers["local_whisper"] = {
|
|
218
|
+
"instance": LocalWhisperTranscriber(
|
|
219
|
+
cache_dir=self.output_config.cache_dir,
|
|
220
|
+
config=LocalWhisperConfig(
|
|
221
|
+
model_size=self.transcriber_config.local_whisper_model_size,
|
|
222
|
+
device=self.transcriber_config.local_whisper_device,
|
|
223
|
+
cache_dir=self.transcriber_config.local_whisper_cache_dir,
|
|
224
|
+
language=self.transcriber_config.local_whisper_language,
|
|
225
|
+
),
|
|
226
|
+
logger=self.logger,
|
|
227
|
+
),
|
|
228
|
+
"priority": 3, # Local Whisper has lowest priority (fallback)
|
|
229
|
+
}
|
|
230
|
+
except ImportError:
|
|
231
|
+
self.logger.debug(
|
|
232
|
+
"Skipping LocalWhisper transcriber - whisper-timestamped not installed. "
|
|
233
|
+
"Install with: pip install karaoke-gen[local-whisper]"
|
|
234
|
+
)
|
|
235
|
+
else:
|
|
236
|
+
self.logger.debug("Skipping LocalWhisper transcriber - disabled via enable_local_whisper=False")
|
|
237
|
+
|
|
209
238
|
return transcribers
|
|
210
239
|
|
|
211
240
|
def _initialize_lyrics_providers(self) -> Dict[str, BaseLyricsProvider]:
|
|
@@ -442,7 +471,7 @@ class LyricsTranscriber:
|
|
|
442
471
|
# Whisper/RunPod status
|
|
443
472
|
has_runpod_key = bool(self.transcriber_config.runpod_api_key)
|
|
444
473
|
has_whisper_id = bool(self.transcriber_config.whisper_runpod_id)
|
|
445
|
-
|
|
474
|
+
|
|
446
475
|
if has_runpod_key and has_whisper_id:
|
|
447
476
|
self.logger.debug(" - Whisper (RunPod): CONFIGURED (API key and endpoint ID provided)")
|
|
448
477
|
elif has_runpod_key:
|
|
@@ -452,6 +481,19 @@ class LyricsTranscriber:
|
|
|
452
481
|
else:
|
|
453
482
|
self.logger.debug(" - Whisper (RunPod): NOT CONFIGURED (missing RUNPOD_API_KEY and WHISPER_RUNPOD_ID)")
|
|
454
483
|
|
|
484
|
+
# Local Whisper status
|
|
485
|
+
if self.transcriber_config.enable_local_whisper:
|
|
486
|
+
try:
|
|
487
|
+
import whisper_timestamped # noqa: F401
|
|
488
|
+
self.logger.debug(
|
|
489
|
+
f" - LocalWhisper: AVAILABLE (model={self.transcriber_config.local_whisper_model_size}, "
|
|
490
|
+
f"device={self.transcriber_config.local_whisper_device or 'auto'})"
|
|
491
|
+
)
|
|
492
|
+
except ImportError:
|
|
493
|
+
self.logger.debug(" - LocalWhisper: ENABLED but whisper-timestamped not installed")
|
|
494
|
+
else:
|
|
495
|
+
self.logger.debug(" - LocalWhisper: DISABLED (enable_local_whisper=False)")
|
|
496
|
+
|
|
455
497
|
def correct_lyrics(self) -> None:
|
|
456
498
|
"""Run lyrics correction using transcription and internet lyrics."""
|
|
457
499
|
self.logger.info("Starting lyrics correction process")
|
|
@@ -1,28 +1,115 @@
|
|
|
1
|
-
|
|
1
|
+
"""LangFuse integration for agentic correction observability and prompt management.
|
|
2
|
+
|
|
3
|
+
This module provides:
|
|
4
|
+
- Client initialization with fail-fast behavior when configured
|
|
5
|
+
- Metrics recording for observability
|
|
6
|
+
- Prompt fetching for dynamic prompt management
|
|
7
|
+
- Dataset fetching for few-shot examples
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import Optional, Dict, Any, List
|
|
2
11
|
import os
|
|
3
|
-
import
|
|
12
|
+
import logging
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
# Module-level client singleton
|
|
17
|
+
_langfuse_client: Optional[Any] = None
|
|
18
|
+
_client_initialized: bool = False
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class LangFuseConfigError(Exception):
|
|
22
|
+
"""Raised when LangFuse is configured but initialization fails."""
|
|
23
|
+
pass
|
|
24
|
+
|
|
4
25
|
|
|
26
|
+
def is_langfuse_configured() -> bool:
|
|
27
|
+
"""Check if LangFuse credentials are configured in environment."""
|
|
28
|
+
public_key = os.getenv("LANGFUSE_PUBLIC_KEY")
|
|
29
|
+
secret_key = os.getenv("LANGFUSE_SECRET_KEY")
|
|
30
|
+
return bool(public_key and secret_key)
|
|
5
31
|
|
|
6
|
-
|
|
32
|
+
|
|
33
|
+
def setup_langfuse() -> Optional[object]:
|
|
7
34
|
"""Initialize Langfuse client if keys are present; return client or None.
|
|
8
35
|
|
|
9
36
|
This avoids hard dependency at import time; caller can check for None and
|
|
10
37
|
no-op if observability is not configured.
|
|
38
|
+
|
|
39
|
+
Note: This function does NOT fail fast - use get_langfuse_client() for
|
|
40
|
+
fail-fast behavior when LangFuse is required.
|
|
11
41
|
"""
|
|
12
42
|
secret = os.getenv("LANGFUSE_SECRET_KEY")
|
|
13
43
|
public = os.getenv("LANGFUSE_PUBLIC_KEY")
|
|
14
|
-
host = os.getenv("LANGFUSE_HOST", "https://cloud.langfuse.com")
|
|
44
|
+
host = os.getenv("LANGFUSE_HOST", "https://us.cloud.langfuse.com")
|
|
15
45
|
if not (secret and public):
|
|
16
46
|
return None
|
|
17
47
|
try:
|
|
18
48
|
from langfuse import Langfuse # type: ignore
|
|
19
49
|
|
|
20
|
-
client = Langfuse(secret_key=secret, public_key=public, host=host
|
|
50
|
+
client = Langfuse(secret_key=secret, public_key=public, host=host)
|
|
21
51
|
return client
|
|
22
52
|
except Exception:
|
|
23
53
|
return None
|
|
24
54
|
|
|
25
55
|
|
|
56
|
+
def get_langfuse_client() -> Optional[Any]:
|
|
57
|
+
"""Get or create the LangFuse client singleton.
|
|
58
|
+
|
|
59
|
+
Unlike setup_langfuse(), this function implements fail-fast behavior:
|
|
60
|
+
if LangFuse keys are configured but initialization fails, it raises
|
|
61
|
+
an exception rather than returning None.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Langfuse client instance, or None if not configured
|
|
65
|
+
|
|
66
|
+
Raises:
|
|
67
|
+
LangFuseConfigError: If keys are set but initialization fails
|
|
68
|
+
"""
|
|
69
|
+
global _langfuse_client, _client_initialized
|
|
70
|
+
|
|
71
|
+
if _client_initialized:
|
|
72
|
+
return _langfuse_client
|
|
73
|
+
|
|
74
|
+
secret = os.getenv("LANGFUSE_SECRET_KEY")
|
|
75
|
+
public = os.getenv("LANGFUSE_PUBLIC_KEY")
|
|
76
|
+
host = os.getenv("LANGFUSE_HOST", "https://us.cloud.langfuse.com")
|
|
77
|
+
|
|
78
|
+
if not (secret and public):
|
|
79
|
+
logger.debug("LangFuse keys not configured, client disabled")
|
|
80
|
+
_client_initialized = True
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
from langfuse import Langfuse
|
|
85
|
+
|
|
86
|
+
_langfuse_client = Langfuse(
|
|
87
|
+
secret_key=secret,
|
|
88
|
+
public_key=public,
|
|
89
|
+
host=host,
|
|
90
|
+
)
|
|
91
|
+
_client_initialized = True
|
|
92
|
+
logger.info(f"LangFuse client initialized (host: {host})")
|
|
93
|
+
return _langfuse_client
|
|
94
|
+
|
|
95
|
+
except Exception as e:
|
|
96
|
+
# Fail fast - if keys are set, we expect LangFuse to work
|
|
97
|
+
raise LangFuseConfigError(
|
|
98
|
+
f"LangFuse keys are set but initialization failed: {e}\n"
|
|
99
|
+
f"Check:\n"
|
|
100
|
+
f" - LANGFUSE_PUBLIC_KEY: {public[:10] if public else 'not set'}...\n"
|
|
101
|
+
f" - LANGFUSE_SECRET_KEY: {'set' if secret else 'not set'}\n"
|
|
102
|
+
f" - LANGFUSE_HOST: {host}"
|
|
103
|
+
) from e
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def reset_langfuse_client() -> None:
|
|
107
|
+
"""Reset the global LangFuse client (for testing)."""
|
|
108
|
+
global _langfuse_client, _client_initialized
|
|
109
|
+
_langfuse_client = None
|
|
110
|
+
_client_initialized = False
|
|
111
|
+
|
|
112
|
+
|
|
26
113
|
def record_metrics(client: Optional[object], name: str, metrics: Dict[str, Any]) -> None:
|
|
27
114
|
"""Record custom metrics to Langfuse if initialized."""
|
|
28
115
|
if client is None:
|
|
@@ -33,3 +120,89 @@ def record_metrics(client: Optional[object], name: str, metrics: Dict[str, Any])
|
|
|
33
120
|
except Exception:
|
|
34
121
|
# Swallow observability errors to never impact core flow
|
|
35
122
|
pass
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def fetch_prompt(name: str, client: Optional[Any] = None, label: Optional[str] = "production") -> Any:
|
|
126
|
+
"""Fetch a prompt template from LangFuse.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
name: The prompt name in LangFuse
|
|
130
|
+
client: Optional pre-initialized client. If None, uses get_langfuse_client()
|
|
131
|
+
label: Prompt label to fetch (default: "production"). If the labeled version
|
|
132
|
+
is not found, falls back to version 1.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
LangFuse prompt object
|
|
136
|
+
|
|
137
|
+
Raises:
|
|
138
|
+
LangFuseConfigError: If LangFuse is not configured
|
|
139
|
+
RuntimeError: If prompt fetch fails
|
|
140
|
+
"""
|
|
141
|
+
if client is None:
|
|
142
|
+
client = get_langfuse_client()
|
|
143
|
+
|
|
144
|
+
if client is None:
|
|
145
|
+
raise LangFuseConfigError(
|
|
146
|
+
f"Cannot fetch prompt '{name}': LangFuse is not configured. "
|
|
147
|
+
f"Set LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY."
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
try:
|
|
151
|
+
# Try to fetch with the specified label (default: production)
|
|
152
|
+
prompt = client.get_prompt(name, label=label)
|
|
153
|
+
logger.debug(f"Fetched prompt '{name}' (label={label}) from LangFuse")
|
|
154
|
+
return prompt
|
|
155
|
+
except Exception as label_error:
|
|
156
|
+
# If labeled version not found, try fetching version 1 as fallback
|
|
157
|
+
# This handles newly created prompts that haven't been promoted yet
|
|
158
|
+
try:
|
|
159
|
+
prompt = client.get_prompt(name, version=1)
|
|
160
|
+
logger.warning(
|
|
161
|
+
f"Prompt '{name}' label '{label}' not found, using version 1. "
|
|
162
|
+
f"Consider promoting this prompt in LangFuse UI."
|
|
163
|
+
)
|
|
164
|
+
return prompt
|
|
165
|
+
except Exception as version_error:
|
|
166
|
+
raise RuntimeError(
|
|
167
|
+
f"Failed to fetch prompt '{name}' from LangFuse: "
|
|
168
|
+
f"Label '{label}' error: {label_error}, "
|
|
169
|
+
f"Version 1 fallback error: {version_error}"
|
|
170
|
+
) from version_error
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def fetch_dataset(name: str, client: Optional[Any] = None) -> List[Dict[str, Any]]:
|
|
174
|
+
"""Fetch a dataset from LangFuse and return its items.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
name: The dataset name in LangFuse
|
|
178
|
+
client: Optional pre-initialized client. If None, uses get_langfuse_client()
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
List of dataset item inputs (the actual example data)
|
|
182
|
+
|
|
183
|
+
Raises:
|
|
184
|
+
LangFuseConfigError: If LangFuse is not configured
|
|
185
|
+
RuntimeError: If dataset fetch fails
|
|
186
|
+
"""
|
|
187
|
+
if client is None:
|
|
188
|
+
client = get_langfuse_client()
|
|
189
|
+
|
|
190
|
+
if client is None:
|
|
191
|
+
raise LangFuseConfigError(
|
|
192
|
+
f"Cannot fetch dataset '{name}': LangFuse is not configured. "
|
|
193
|
+
f"Set LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY."
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
try:
|
|
197
|
+
dataset = client.get_dataset(name)
|
|
198
|
+
items = []
|
|
199
|
+
for item in dataset.items:
|
|
200
|
+
if hasattr(item, 'input') and item.input:
|
|
201
|
+
items.append(item.input)
|
|
202
|
+
|
|
203
|
+
logger.debug(f"Fetched {len(items)} items from dataset '{name}'")
|
|
204
|
+
return items
|
|
205
|
+
except Exception as e:
|
|
206
|
+
raise RuntimeError(
|
|
207
|
+
f"Failed to fetch dataset '{name}' from LangFuse: {e}"
|
|
208
|
+
) from e
|
|
@@ -1,2 +1,25 @@
|
|
|
1
1
|
"""Prompt templates for agentic correction."""
|
|
2
2
|
|
|
3
|
+
from .classifier import (
|
|
4
|
+
build_classification_prompt,
|
|
5
|
+
build_classification_prompt_hardcoded,
|
|
6
|
+
get_hardcoded_examples,
|
|
7
|
+
)
|
|
8
|
+
from .langfuse_prompts import (
|
|
9
|
+
LangFusePromptService,
|
|
10
|
+
LangFusePromptError,
|
|
11
|
+
LangFuseDatasetError,
|
|
12
|
+
get_prompt_service,
|
|
13
|
+
reset_prompt_service,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"build_classification_prompt",
|
|
18
|
+
"build_classification_prompt_hardcoded",
|
|
19
|
+
"get_hardcoded_examples",
|
|
20
|
+
"LangFusePromptService",
|
|
21
|
+
"LangFusePromptError",
|
|
22
|
+
"LangFuseDatasetError",
|
|
23
|
+
"get_prompt_service",
|
|
24
|
+
"reset_prompt_service",
|
|
25
|
+
]
|
|
@@ -1,23 +1,35 @@
|
|
|
1
|
-
"""Gap classification prompt builder for agentic correction.
|
|
1
|
+
"""Gap classification prompt builder for agentic correction.
|
|
2
|
+
|
|
3
|
+
This module provides two modes of operation:
|
|
4
|
+
1. LangFuse mode: Prompts and examples fetched from LangFuse for dynamic iteration
|
|
5
|
+
2. Hardcoded mode: Fallback for local development when LangFuse is not configured
|
|
6
|
+
|
|
7
|
+
The main entry point is `build_classification_prompt()` which automatically
|
|
8
|
+
selects the appropriate mode based on LangFuse configuration.
|
|
9
|
+
"""
|
|
2
10
|
|
|
3
11
|
from typing import Dict, List, Optional
|
|
4
12
|
import yaml
|
|
5
13
|
import os
|
|
14
|
+
import logging
|
|
6
15
|
from pathlib import Path
|
|
7
16
|
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
8
19
|
|
|
9
20
|
def load_few_shot_examples() -> Dict[str, List[Dict]]:
|
|
10
21
|
"""Load few-shot examples from examples.yaml if it exists."""
|
|
11
22
|
examples_path = Path(__file__).parent / "examples.yaml"
|
|
12
|
-
|
|
23
|
+
|
|
13
24
|
if not examples_path.exists():
|
|
14
25
|
return get_hardcoded_examples()
|
|
15
|
-
|
|
26
|
+
|
|
16
27
|
try:
|
|
17
28
|
with open(examples_path, 'r') as f:
|
|
18
29
|
data = yaml.safe_load(f)
|
|
19
30
|
return data.get('examples_by_category', {})
|
|
20
|
-
except Exception:
|
|
31
|
+
except Exception as e:
|
|
32
|
+
logger.warning(f"Failed to load examples.yaml, using hardcoded examples: {e}")
|
|
21
33
|
return get_hardcoded_examples()
|
|
22
34
|
|
|
23
35
|
|
|
@@ -122,7 +134,12 @@ def build_classification_prompt(
|
|
|
122
134
|
gap_id: Optional[str] = None
|
|
123
135
|
) -> str:
|
|
124
136
|
"""Build a prompt for classifying a gap in the transcription.
|
|
125
|
-
|
|
137
|
+
|
|
138
|
+
This function automatically selects between LangFuse and hardcoded prompts:
|
|
139
|
+
- If LangFuse is configured (LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY set),
|
|
140
|
+
fetches the prompt template and examples from LangFuse.
|
|
141
|
+
- Otherwise, uses hardcoded prompts for local development.
|
|
142
|
+
|
|
126
143
|
Args:
|
|
127
144
|
gap_text: The text of the gap that needs classification
|
|
128
145
|
preceding_words: Text immediately before the gap
|
|
@@ -131,7 +148,50 @@ def build_classification_prompt(
|
|
|
131
148
|
artist: Song artist name for context
|
|
132
149
|
title: Song title for context
|
|
133
150
|
gap_id: Identifier for the gap
|
|
134
|
-
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
Formatted prompt string for the LLM
|
|
154
|
+
|
|
155
|
+
Raises:
|
|
156
|
+
LangFusePromptError: If LangFuse is configured but prompt fetch fails
|
|
157
|
+
"""
|
|
158
|
+
from .langfuse_prompts import get_prompt_service
|
|
159
|
+
|
|
160
|
+
service = get_prompt_service()
|
|
161
|
+
return service.get_classification_prompt(
|
|
162
|
+
gap_text=gap_text,
|
|
163
|
+
preceding_words=preceding_words,
|
|
164
|
+
following_words=following_words,
|
|
165
|
+
reference_contexts=reference_contexts,
|
|
166
|
+
artist=artist,
|
|
167
|
+
title=title,
|
|
168
|
+
gap_id=gap_id
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def build_classification_prompt_hardcoded(
|
|
173
|
+
gap_text: str,
|
|
174
|
+
preceding_words: str,
|
|
175
|
+
following_words: str,
|
|
176
|
+
reference_contexts: Dict[str, str],
|
|
177
|
+
artist: Optional[str] = None,
|
|
178
|
+
title: Optional[str] = None,
|
|
179
|
+
gap_id: Optional[str] = None
|
|
180
|
+
) -> str:
|
|
181
|
+
"""Build a prompt for classifying a gap using hardcoded templates.
|
|
182
|
+
|
|
183
|
+
This is the fallback implementation used when LangFuse is not configured.
|
|
184
|
+
It is also used as the source of truth for migrating prompts to LangFuse.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
gap_text: The text of the gap that needs classification
|
|
188
|
+
preceding_words: Text immediately before the gap
|
|
189
|
+
following_words: Text immediately after the gap
|
|
190
|
+
reference_contexts: Dictionary of reference lyrics from each source
|
|
191
|
+
artist: Song artist name for context
|
|
192
|
+
title: Song title for context
|
|
193
|
+
gap_id: Identifier for the gap
|
|
194
|
+
|
|
135
195
|
Returns:
|
|
136
196
|
Formatted prompt string for the LLM
|
|
137
197
|
"""
|