karaoke-gen 0.96.0__py3-none-any.whl → 0.101.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.
- backend/api/routes/admin.py +696 -92
- backend/api/routes/audio_search.py +29 -8
- backend/api/routes/file_upload.py +99 -22
- backend/api/routes/health.py +65 -0
- backend/api/routes/internal.py +6 -0
- backend/api/routes/jobs.py +28 -1
- backend/api/routes/review.py +13 -6
- backend/api/routes/tenant.py +120 -0
- backend/api/routes/users.py +472 -51
- backend/main.py +31 -2
- backend/middleware/__init__.py +7 -1
- backend/middleware/tenant.py +192 -0
- backend/models/job.py +19 -3
- backend/models/tenant.py +208 -0
- backend/models/user.py +18 -0
- backend/services/email_service.py +253 -6
- backend/services/encoding_service.py +128 -31
- backend/services/firestore_service.py +6 -0
- backend/services/job_manager.py +44 -2
- backend/services/langfuse_preloader.py +98 -0
- backend/services/nltk_preloader.py +122 -0
- backend/services/spacy_preloader.py +65 -0
- backend/services/stripe_service.py +133 -11
- backend/services/tenant_service.py +285 -0
- backend/services/user_service.py +85 -7
- backend/tests/emulator/conftest.py +22 -1
- backend/tests/emulator/test_made_for_you_integration.py +167 -0
- backend/tests/test_admin_job_files.py +337 -0
- backend/tests/test_admin_job_reset.py +384 -0
- backend/tests/test_admin_job_update.py +326 -0
- backend/tests/test_email_service.py +233 -0
- backend/tests/test_impersonation.py +223 -0
- backend/tests/test_job_creation_regression.py +4 -0
- backend/tests/test_job_manager.py +171 -9
- backend/tests/test_jobs_api.py +11 -1
- backend/tests/test_made_for_you.py +2086 -0
- backend/tests/test_models.py +139 -0
- backend/tests/test_spacy_preloader.py +119 -0
- backend/tests/test_tenant_api.py +350 -0
- backend/tests/test_tenant_middleware.py +345 -0
- backend/tests/test_tenant_models.py +406 -0
- backend/tests/test_tenant_service.py +418 -0
- backend/utils/test_data.py +27 -0
- backend/workers/screens_worker.py +16 -6
- backend/workers/video_worker.py +8 -3
- {karaoke_gen-0.96.0.dist-info → karaoke_gen-0.101.0.dist-info}/METADATA +1 -1
- {karaoke_gen-0.96.0.dist-info → karaoke_gen-0.101.0.dist-info}/RECORD +58 -39
- lyrics_transcriber/correction/agentic/agent.py +17 -6
- lyrics_transcriber/correction/agentic/providers/langchain_bridge.py +96 -43
- lyrics_transcriber/correction/agentic/providers/model_factory.py +27 -6
- lyrics_transcriber/correction/anchor_sequence.py +151 -37
- lyrics_transcriber/correction/handlers/syllables_match.py +44 -2
- lyrics_transcriber/correction/phrase_analyzer.py +18 -0
- lyrics_transcriber/frontend/src/api.ts +13 -5
- lyrics_transcriber/frontend/src/components/PreviewVideoSection.tsx +90 -57
- {karaoke_gen-0.96.0.dist-info → karaoke_gen-0.101.0.dist-info}/WHEEL +0 -0
- {karaoke_gen-0.96.0.dist-info → karaoke_gen-0.101.0.dist-info}/entry_points.txt +0 -0
- {karaoke_gen-0.96.0.dist-info → karaoke_gen-0.101.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -7,25 +7,28 @@ backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
7
7
|
backend/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
backend/api/dependencies.py,sha256=-61nHBhiihUDSVMQd3VuHLP7uvKrUbm1y-j9RmV6_zc,16871
|
|
9
9
|
backend/api/routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
backend/api/routes/admin.py,sha256=
|
|
11
|
-
backend/api/routes/audio_search.py,sha256=
|
|
10
|
+
backend/api/routes/admin.py,sha256=GI4ANzshBUfAzMdRH3M8cUBnzsCbrL1owRXmIY5HK8A,46506
|
|
11
|
+
backend/api/routes/audio_search.py,sha256=CK2lVaM8RDP7i61XEtLeS0AJDfVJSy0ctnduK-ew-hQ,40129
|
|
12
12
|
backend/api/routes/auth.py,sha256=G1U2KwS3uqBJpgvg2PIe_mZOWCJKPFhhewrmKbW3Z_s,11531
|
|
13
|
-
backend/api/routes/file_upload.py,sha256=
|
|
14
|
-
backend/api/routes/health.py,sha256=
|
|
15
|
-
backend/api/routes/internal.py,sha256=
|
|
16
|
-
backend/api/routes/jobs.py,sha256=
|
|
17
|
-
backend/api/routes/review.py,sha256=
|
|
13
|
+
backend/api/routes/file_upload.py,sha256=nEl06-ZqkKZNzyNZh0RRtuOBox54XvdEOFkYtnSqpv8,95828
|
|
14
|
+
backend/api/routes/health.py,sha256=iZlhJpmz4vminUy_qrzkyk_1tgG1gmITz4jEWaCWJnM,14010
|
|
15
|
+
backend/api/routes/internal.py,sha256=yqzd5V8xGJQ_vTZL85vKIMwmBXf1MIp1nhder-kQEuA,15683
|
|
16
|
+
backend/api/routes/jobs.py,sha256=7i3uAOL9p4cNk1vJHJIIYCBkcJFaJFl6o3iq92Z9KFo,61218
|
|
17
|
+
backend/api/routes/review.py,sha256=BiaXZs-NXl7AVzGiwBzIhzm60fUslcQagSw4XuUByhU,28842
|
|
18
|
+
backend/api/routes/tenant.py,sha256=sM0WVXWGKJeyBNMbPDnAKOD9-SkJBmH4RkMXVWz4dlM,4038
|
|
18
19
|
backend/api/routes/themes.py,sha256=_fPZg9N2KN-yyr1YR2vAy8FIm8PqVowboQ4WEpFTYiQ,4721
|
|
19
|
-
backend/api/routes/users.py,sha256=
|
|
20
|
+
backend/api/routes/users.py,sha256=nKJKuGedzSMuJVLMU4-CXNc7GsM5c82JzjFYeZtzgsg,52771
|
|
20
21
|
backend/config.py,sha256=-HsMaacaKuRftYXUXZJr8GBHPdmacFbrNnFDMk7DHNI,8187
|
|
21
|
-
backend/main.py,sha256=
|
|
22
|
-
backend/middleware/__init__.py,sha256=
|
|
22
|
+
backend/main.py,sha256=yRIdnkv_iIyOiLc2btqomxlflym13A-b3ei3X8gI8Ac,5944
|
|
23
|
+
backend/middleware/__init__.py,sha256=usnVRHqfGW56bWJFqaIXz49pSW91uyciBfwO7ANCpIk,369
|
|
23
24
|
backend/middleware/audit_logging.py,sha256=oGdgbfH_M_3hIMAGrS5HpRvri2jjLxGFnFuA6IiU9BU,4170
|
|
25
|
+
backend/middleware/tenant.py,sha256=a-HEAhyvMUC4uFF6VptaNOO9O6YP64-ZoUitppl79PQ,6373
|
|
24
26
|
backend/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
-
backend/models/job.py,sha256=
|
|
27
|
+
backend/models/job.py,sha256=B1Q12F6448okCOkmLmpBnlwGIKi16TqBjVkRttTmqi0,25663
|
|
26
28
|
backend/models/requests.py,sha256=tCX7ss4to3rKAR_Wu92CZ8uPqNb2nnmCp1XepD4VR5s,4152
|
|
29
|
+
backend/models/tenant.py,sha256=rhj6n7bsX8ClstoHQKCVcLWALI31l5Tepcf_N8IXDdM,7403
|
|
27
30
|
backend/models/theme.py,sha256=cfNSHIigoAV4P41Jku6Sa1okHSRhUHjFpl1XBVF3kCY,4628
|
|
28
|
-
backend/models/user.py,sha256=
|
|
31
|
+
backend/models/user.py,sha256=2Dl81Sa8_c0cuPJ3uddsLSOAN40mtv-5aUETtFZZK8c,8022
|
|
29
32
|
backend/models/worker_log.py,sha256=QDgpdRarm00N1TdFoGhKJxZjP9GmiMjrTJb6msw7pHA,5547
|
|
30
33
|
backend/pyproject.toml,sha256=LAvEXxQSRI94XQcwpBmuSoEu36341HOu53iigsN6dVs,577
|
|
31
34
|
backend/quick-check.sh,sha256=PUvH0wXaGzWrgWwwJG5M4Bxxt3vVA4mmdEdL6VepVHY,2382
|
|
@@ -39,10 +42,10 @@ backend/services/auth_service.py,sha256=rEpb4O9YSTOQaEoP2XXKXRpppWI5sG10AsueQSVc
|
|
|
39
42
|
backend/services/credential_manager.py,sha256=VA--PwvL3gboJ21orQb7MIUiovX8n66FohD6w84exX8,31682
|
|
40
43
|
backend/services/discord_service.py,sha256=LnEasOgaSRlmebDKsVT2yKCdWNDmskUToP3o2wPmdus,5082
|
|
41
44
|
backend/services/dropbox_service.py,sha256=R47MUKCqK2BEXXmQxMLG6zkPWw02htFoES9q9xiaYAw,10717
|
|
42
|
-
backend/services/email_service.py,sha256=
|
|
45
|
+
backend/services/email_service.py,sha256=gpufwXhNWmdElpWCmKrTLtm2LB8S-0Y5wcyJ3n1i6Jg,52868
|
|
43
46
|
backend/services/encoding_interface.py,sha256=Y8hPskDyX9DOyAD557F3-SdHjymaBkGXcoC9E_OW7SE,15825
|
|
44
|
-
backend/services/encoding_service.py,sha256=
|
|
45
|
-
backend/services/firestore_service.py,sha256
|
|
47
|
+
backend/services/encoding_service.py,sha256=XAX4hyL2wIHdpBCTc8yglcjVJboZxRVAjc07lUTxgFg,18025
|
|
48
|
+
backend/services/firestore_service.py,sha256=--Va-2lawugskepxo2p9w3ON2KsMGqacSOutCmU_CDQ,18801
|
|
46
49
|
backend/services/flacfetch_client.py,sha256=zj4VToKamR8bShXZifLvjDmUVa1HHvDhZuaw_b7g4lU,19901
|
|
47
50
|
backend/services/gce_encoding/README.md,sha256=frTFrp7-ugFAvUd_K9EgE4ud8Xu4Qf1V7BNirQn6qJk,2515
|
|
48
51
|
backend/services/gce_encoding/__init__.py,sha256=d2H6zM207NSc5afnfgkd3kwOXUu2gFBYjxBSS7tvX_s,571
|
|
@@ -50,36 +53,44 @@ backend/services/gce_encoding/main.py,sha256=2A0Bd3zYzbV66ikShB3avpqfNoDFBxr8Ja6
|
|
|
50
53
|
backend/services/gce_encoding/requirements.txt,sha256=-hW5ot-PnVoKkxrpY3yV6l68wx7AvzgnLYAWEgDGWNc,408
|
|
51
54
|
backend/services/gdrive_service.py,sha256=3JTXmPBuxpKopAbWDrh6YhqR5L9BLop1R7caXBnIk2A,13266
|
|
52
55
|
backend/services/job_logging.py,sha256=theCkAlwMbqyqAbu7vCCRpVRscaIpkam3UrCs_4Yi1g,8052
|
|
53
|
-
backend/services/job_manager.py,sha256=
|
|
56
|
+
backend/services/job_manager.py,sha256=2vBp-a1r3kwOg-CvXRjjlgkBh9U5AlI6yLeCBAjKLMY,33214
|
|
54
57
|
backend/services/job_notification_service.py,sha256=ywGJUMUDqV23OSDsugOUufpXO6N_24bM9YVaPp8bOk4,9557
|
|
58
|
+
backend/services/langfuse_preloader.py,sha256=t-Rt_ThjZm4K8W3jlyLn2H3cEy7KNUlhrvOPmdg-gYM,3100
|
|
55
59
|
backend/services/local_encoding_service.py,sha256=Q6yK2-QL9tHM_pUBoxdyfT7ln2L5xMx82JB2nC5OfNQ,20680
|
|
56
60
|
backend/services/local_preview_encoding_service.py,sha256=WLuJuIx-kH6u35gcYnvogf4Gt7iEokL2IdfxlrkY5po,14394
|
|
57
61
|
backend/services/lyrics_cache_service.py,sha256=53EIZuDs5jIKr6QiOhIKJjE2mx1Jd1_x15_uAeLnc4A,7598
|
|
58
62
|
backend/services/metrics.py,sha256=hlEeLG4jOR1i_QbWaNQthoko9CSpe-Zn_LHJ2huEFeY,12728
|
|
63
|
+
backend/services/nltk_preloader.py,sha256=TZFghQrpDTi6COcW_rkjL15SlzdRNvPmrdy690fq0hw,3579
|
|
59
64
|
backend/services/packaging_service.py,sha256=MUuBk0jtG3vGQhuOWbDv9u1uIMwbBC4NknLpJYFcWhs,10259
|
|
60
65
|
backend/services/rclone_service.py,sha256=Q6wRAjlBiMMh9FBbbFRp4SHK1ljOQBed9zUJaJgAuhU,3646
|
|
66
|
+
backend/services/spacy_preloader.py,sha256=rpsMZB0CQWcoXjq8nyZCwJBkyjGheKaCFrfhxCOln5w,1836
|
|
61
67
|
backend/services/storage_service.py,sha256=gA7Snz1pihzYpRKZjEZx3eDwyMUBezl3ccLuBdpTwE4,8573
|
|
62
|
-
backend/services/stripe_service.py,sha256=
|
|
68
|
+
backend/services/stripe_service.py,sha256=YPBVE2_ZeBYWklcFCTGoRWOuO1UTI16_Un2NKAE-sqE,14825
|
|
63
69
|
backend/services/structured_logging.py,sha256=daGgZUdc1xIiOdxL9-YtWHDy51hwZqd8ELpomkh2QH4,9063
|
|
64
70
|
backend/services/template_service.py,sha256=5CdSxBGhdBtxIUz24AhvltUfSWcFqZzBIxb9MjlN4YU,11212
|
|
71
|
+
backend/services/tenant_service.py,sha256=AlG5acJww-rpxGEQbw7eOWe1KaHLOcCn3fM95qDZMGw,9709
|
|
65
72
|
backend/services/theme_service.py,sha256=6lJqMpFjmRY09CMJcW9IJ6DVPffLmwE0DnpXDUKaJ0U,17374
|
|
66
73
|
backend/services/tracing.py,sha256=MNpJNMmSOw-9TRlb3dJk7pA8JTmSjAFHj9bSuyM5cOY,17210
|
|
67
|
-
backend/services/user_service.py,sha256=
|
|
74
|
+
backend/services/user_service.py,sha256=0_ztVqXKNH1jqKiZwqgStEfW95YowJbvYOL-eaBw2oY,29339
|
|
68
75
|
backend/services/worker_service.py,sha256=WRgh3kconWYmvraEIsx6eUto2frKacauKApFU1wIEiQ,21093
|
|
69
76
|
backend/services/youtube_service.py,sha256=L2jqcWkw6qIaKh4wEfX894mHaTU0m5qtgIX6TPi6uiQ,3828
|
|
70
77
|
backend/services/youtube_upload_service.py,sha256=fvo4WxLQaKY_I75ViBMLk6vm87ym2ABHK0Fn_StYN6g,16694
|
|
71
78
|
backend/tests/__init__.py,sha256=jTjELMqIzpgHG9dcXwwkszTAAC4Wf-c93C6D1k-toZg,44
|
|
72
79
|
backend/tests/conftest.py,sha256=c4_jH0FIHsiKeUfo3ECPN78MlbW_IARTWwKr9RKLOSM,7843
|
|
73
80
|
backend/tests/emulator/__init__.py,sha256=yOGPU5e0JPNYyUpy-u13jW4gEfWQs3dCJxfincptaCY,156
|
|
74
|
-
backend/tests/emulator/conftest.py,sha256=
|
|
81
|
+
backend/tests/emulator/conftest.py,sha256=VXhoJ3NZg3uiLzSAsushQtozFS7Lt6lmjk7ym-k6V8o,3844
|
|
75
82
|
backend/tests/emulator/test_e2e_cli_backend.py,sha256=BTrWDv4sRTeOlheZ-d4R37tZsvJ2MhdFLbDb9tjbF08,41018
|
|
76
83
|
backend/tests/emulator/test_emulator_integration.py,sha256=pm_JzgA2bmjcnHmGA-mZfJhUAYwGx10jv48A2deujRs,11822
|
|
84
|
+
backend/tests/emulator/test_made_for_you_integration.py,sha256=EYWZrYrQdoYk4Eb8G4M7Cyzq5ncAWqeYLuG8a31EAqc,5470
|
|
77
85
|
backend/tests/emulator/test_style_loading_direct.py,sha256=e-FzlCVW_-ealM9hTGa2qgpwoVRiYKrcXDWB1FjkwXc,16842
|
|
78
86
|
backend/tests/emulator/test_worker_logs_direct.py,sha256=96EeaSxeNQBtDiZ9ky1-CGE6Lv6ZV3dKuoF3inHxO8A,8158
|
|
79
87
|
backend/tests/emulator/test_worker_logs_subcollection.py,sha256=whwUXW_-fF-nQp2Z791PNxi0nnvlRwLo87QacF-yMUI,16834
|
|
80
88
|
backend/tests/requirements-test.txt,sha256=1ixGqdsXFG0hbqUPWUjNGPlKdQgYxo1GajXOiLhs66M,193
|
|
81
89
|
backend/tests/requirements.txt,sha256=1526vDy39B1ZjJ5URZtoiDGnjvwuxiD9dNrjOLd6-gA,95
|
|
82
90
|
backend/tests/test_admin_email_endpoints.py,sha256=C1mOX3K4P-_QqSWa8ZSH4gtMnUJ7hqq5rOi00zSKR8g,16592
|
|
91
|
+
backend/tests/test_admin_job_files.py,sha256=LXeV08a4XuaipM-QFFVJKE02e83Muj-JrjtCPlgExuM,13348
|
|
92
|
+
backend/tests/test_admin_job_reset.py,sha256=PsM6cBPeN5d6HO4pejaOQNyTh7OHTOFNPMTPuulcZCI,14292
|
|
93
|
+
backend/tests/test_admin_job_update.py,sha256=19NFazBk-fU8vrKKOoJV9c7pAvskNcAhihpmdQFZNIk,12157
|
|
83
94
|
backend/tests/test_api_integration.py,sha256=ps4dFoW69NCKJAWvPSr410fEILPxfQNME_YmLPdNqxo,14886
|
|
84
95
|
backend/tests/test_api_routes.py,sha256=j6alBwXgtKspXxbOiDuNCCVMENk6yxdFJkakbife-rM,3193
|
|
85
96
|
backend/tests/test_audio_analysis_service.py,sha256=bKIAgyxfdbUOr7atHH-WCbZcZFkWGmGOOn7IfvRF2ms,11373
|
|
@@ -93,32 +104,39 @@ backend/tests/test_dependencies.py,sha256=kWiOQEMQWFPIbAM8FEMYI921n3dLOQFJ7HXyRH
|
|
|
93
104
|
backend/tests/test_discord_service.py,sha256=OU5mVzjukFtJd_H5e_HxJqSsf78B0TrNfjxhwypbV34,8902
|
|
94
105
|
backend/tests/test_distribution_services.py,sha256=8oB2vMq5T_4rvOs6BURoLLTQiDf0kUJ-jF8dzJzDYRk,33699
|
|
95
106
|
backend/tests/test_dropbox_service.py,sha256=nDN1NjiCMS_f1bICWfe3maqbKT5FbhNuKCb1zjyjKq0,19198
|
|
96
|
-
backend/tests/test_email_service.py,sha256=
|
|
107
|
+
backend/tests/test_email_service.py,sha256=u1VSTBCZl7m3GYR-vKV84tu3q7zhMuIhNA5a4OiCDlE,25290
|
|
97
108
|
backend/tests/test_emulator_integration.py,sha256=m4teGnKLBKQNe9UdFi0-0iR_unnotWs07VWgSd_atuw,10387
|
|
98
109
|
backend/tests/test_encoding_interface.py,sha256=7q9mKX4QG8-bfkxQgZkmeirK_ynfL88UTbgWS0f097U,14609
|
|
99
110
|
backend/tests/test_file_upload.py,sha256=mWEIVj6cK6ZzKf4X0D0JhSk6pmJeCO0dOawV2GED7tc,68038
|
|
100
111
|
backend/tests/test_flacfetch_client.py,sha256=ZquMDLFVgORr9GoNfybOV9Z3eruborRgCvBRY6l-V8A,22614
|
|
101
112
|
backend/tests/test_gdrive_service.py,sha256=fh02KPaFqLEWfPaDQvSehn6r6RLq0bgt6MdXenF1kxA,19762
|
|
113
|
+
backend/tests/test_impersonation.py,sha256=vuCJaYmPOObLvFWuzxRvqadeRtFXgsbQxyOKd4TaxHg,9087
|
|
102
114
|
backend/tests/test_instrumental_api.py,sha256=2eWaoEAYVY02HZgY4esn5echuWGv_sznoO6FYWIgTbQ,17210
|
|
103
115
|
backend/tests/test_internal_api.py,sha256=qMGSDCkYd5OY_Z85vQu10xjqJn1JtaQcaKSnSBpVijw,12980
|
|
104
|
-
backend/tests/test_job_creation_regression.py,sha256=
|
|
105
|
-
backend/tests/test_job_manager.py,sha256=
|
|
116
|
+
backend/tests/test_job_creation_regression.py,sha256=ydd97391bMq40MSTlTlvMn3_zjtFDWzSQLjYczoqR_U,22826
|
|
117
|
+
backend/tests/test_job_manager.py,sha256=9SvwVkgN5VoyaJH-vzVN3VRoXpMJf4YAluLmspZrhzs,18862
|
|
106
118
|
backend/tests/test_job_manager_notifications.py,sha256=WlzXXxTCmHHCrD4XWu2j2fDYODlHGKThOQpZQeyhPXM,12996
|
|
107
119
|
backend/tests/test_job_notification_service.py,sha256=YbXqCWbsK8O5WICItb3VCrEY8qKqoJ3NBEZtwCs7AYM,17892
|
|
108
|
-
backend/tests/test_jobs_api.py,sha256=
|
|
120
|
+
backend/tests/test_jobs_api.py,sha256=z3pGTawTpt75a1bQ5x4ynw3pTlNihLA6vqktTc6mBAU,11092
|
|
109
121
|
backend/tests/test_local_encoding_service.py,sha256=TbBaFOB-8Re09G-qXIQCl8mS9WlQMFNQF01V64IekyI,14638
|
|
110
122
|
backend/tests/test_local_preview_encoding_service.py,sha256=VwxpcAjDdYaVauSsrJ609U575VWRZbLsXew8BqBXpJY,20228
|
|
123
|
+
backend/tests/test_made_for_you.py,sha256=WNiJhmv_zse96Yg4scEXnpu66MMc0Hi4pNyiadfdlQ8,87628
|
|
111
124
|
backend/tests/test_main.py,sha256=BvzcadLUV0SEUO1ViKm0djgy_TEKXm8PPvgfcCCEJAY,3348
|
|
112
|
-
backend/tests/test_models.py,sha256=
|
|
125
|
+
backend/tests/test_models.py,sha256=buUjtm3TaiIff58SCpG0Du1Bnm-S9X8LyaW64zEhb4U,39606
|
|
113
126
|
backend/tests/test_packaging_service.py,sha256=v4Bj8R61Fx0Kng6RoTj3SRN9jmxow5qCVtTJstTWNfE,13916
|
|
114
127
|
backend/tests/test_requests.py,sha256=DI2IG67hHk2rhuzUfz_QNJCLRTy1NZPLsnSdZbIfPA8,6817
|
|
115
128
|
backend/tests/test_routes_jobs.py,sha256=iqOZ93ACKpizSzLEJUx5hIo0vkKe2oIT7s7iZqQUJaE,11258
|
|
116
129
|
backend/tests/test_routes_review.py,sha256=ENo6_wFUDcyXZhRy_NBqajan9dvqV_7f1rIQ7LLLS-U,14334
|
|
117
130
|
backend/tests/test_services.py,sha256=JSsZZSpa0HjNZBSIrXXzBxZfJewfdR9RC3P8tHV8M8E,24288
|
|
118
131
|
backend/tests/test_services_extended.py,sha256=cBcaEicz4WdBo5WZB77AoGZTwWAOC6W4OslpT6VmFI8,4124
|
|
132
|
+
backend/tests/test_spacy_preloader.py,sha256=uWpkrOPUOOcW1-fWClKMKVhXHGk30FXq537kQH5jpd0,4437
|
|
119
133
|
backend/tests/test_storage_service.py,sha256=gorn3aFwKSr8lihxcG7kza7fYvDsTvxJhOxzuTtPK_o,19069
|
|
120
134
|
backend/tests/test_style_upload.py,sha256=8G2dGgvyMGXsh1jk8PcGpTlSdBQAlHn13kpZcKn6rTY,10491
|
|
121
135
|
backend/tests/test_template_service.py,sha256=BKURQ1M-hXXgdBl9LqhPQKfpItWOYDRBSt1y5FXQzaM,10431
|
|
136
|
+
backend/tests/test_tenant_api.py,sha256=P4395WYGldJIX7hYcbk96bIDW0Hogcj2McUG6iApNmc,13441
|
|
137
|
+
backend/tests/test_tenant_middleware.py,sha256=0WflieACxT1c_k-C2-yQ5sap_xm6z6w3p3ys09B8iMA,12577
|
|
138
|
+
backend/tests/test_tenant_models.py,sha256=NwNz197f5IPuhNU8f0d2OGBTeE7y7K2oulHfOJRo1EQ,15228
|
|
139
|
+
backend/tests/test_tenant_service.py,sha256=39bL1B0poa1LyxHDwFdQgSVu-QJ96rpe7Occ_ItC1Zc,16494
|
|
122
140
|
backend/tests/test_theme_service.py,sha256=I_BrXjDAwmqGhxClJA8kE9FDYdQmtdYQINjIwyI3NTs,20454
|
|
123
141
|
backend/tests/test_unicode_sanitization.py,sha256=M4QfJmHGZ8WrhTfg7QPljPj2kUkN5QUNThtofzZhQiE,22930
|
|
124
142
|
backend/tests/test_upload_api.py,sha256=oWXPunON3pSTEnE3oE9vIQk63GC6lKM5RgTmaKKQths,10127
|
|
@@ -130,6 +148,7 @@ backend/tests/test_workers.py,sha256=BW-MDQx5HrgICKOcd1KkvzyBO4sOfJXeLVlMiJDfmBw
|
|
|
130
148
|
backend/tests/test_workers_extended.py,sha256=uFznO4Q2v_H7xjfje5eYXXjS72EnhwXNRcT9YshuB8M,6763
|
|
131
149
|
backend/tests/test_youtube_service.py,sha256=HPm3HUJcu9rKcyRpBfufU6tzMP1lwZ9ZSe0vOoKNypI,9134
|
|
132
150
|
backend/tests/test_youtube_upload_service.py,sha256=o58DXYWLOtp8nmaowO_UHdOErVCDl8YxHJUgI-xvyMs,21428
|
|
151
|
+
backend/utils/test_data.py,sha256=0H0GmV0UnLXe-l0NKAug7COORyQI3PQtbC_qQHllIpI,713
|
|
133
152
|
backend/validate.py,sha256=u8lXKnC1ocXKAaYxNoCE9dRrhvoYI11XrTtaWIp-HLw,5040
|
|
134
153
|
backend/version.py,sha256=Ai-O0n-W-iBIYY_c71-QZikxAsmTpcel4X3T3p8AqVI,677
|
|
135
154
|
backend/workers/README.md,sha256=JYfLyngGkzxl1mRpkppIZB3ou9GR3sRVmZAxIAdURPY,15935
|
|
@@ -137,9 +156,9 @@ backend/workers/__init__.py,sha256=Eswp1Jvb6-97r7zUe7FUXSexsCZvghR08qwx1L_4298,3
|
|
|
137
156
|
backend/workers/audio_worker.py,sha256=9RWIzuhU24fpRMj9JW8cpWODeYsZrbaXhtxddrMFKIo,29088
|
|
138
157
|
backend/workers/lyrics_worker.py,sha256=nsy90pb0BPAl_lbZ0E7d7jIclcXK7W8d9RxxEdJaHVg,35149
|
|
139
158
|
backend/workers/render_video_worker.py,sha256=L6-VCxSBY6MbXBBm0-wu_DXxcIWKfW6ynTv9K03WCjY,25163
|
|
140
|
-
backend/workers/screens_worker.py,sha256=
|
|
159
|
+
backend/workers/screens_worker.py,sha256=vCS7j4dQRQ_tsWNhz-XH5nau7kGyUSzSp-dzyZpeJEo,21402
|
|
141
160
|
backend/workers/style_helper.py,sha256=7-PM79dAUAZHTj-bnATy43ImqNdl_00E9pm94CYg1BM,6906
|
|
142
|
-
backend/workers/video_worker.py,sha256=
|
|
161
|
+
backend/workers/video_worker.py,sha256=5r3PcYdoca16fjZtFzCwfKm-G7QjL98ZLMhw6qGVDNE,55670
|
|
143
162
|
backend/workers/video_worker_orchestrator.py,sha256=NInZjFwztqcYneuxrkDqEFWV7z5BzGlaaoJxj812KA4,27510
|
|
144
163
|
backend/workers/worker_logging.py,sha256=nlbGsjDjdkv28Fm-95vKBumy6P47dGiNN5Zf3r0A480,9928
|
|
145
164
|
karaoke_gen/__init__.py,sha256=wHpDbURJxmJAMNZ0uQjISv5MIT7KD9RWYi15xlYgEhU,1351
|
|
@@ -193,7 +212,7 @@ lyrics_transcriber/core/controller.py,sha256=zRjdxOrJEaa2depvzZvwVQiEFmf8Ew3Aek8
|
|
|
193
212
|
lyrics_transcriber/correction/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
194
213
|
lyrics_transcriber/correction/agentic/__init__.py,sha256=p7PHiebuvRs8RDlPDs-9gLZKzXG5KfWg3fFCdDhY6pE,222
|
|
195
214
|
lyrics_transcriber/correction/agentic/adapter.py,sha256=Z0JBTAA7xlSdctCHqO9nBMl78C4XmqsLKKtS6BvNZNI,2912
|
|
196
|
-
lyrics_transcriber/correction/agentic/agent.py,sha256=
|
|
215
|
+
lyrics_transcriber/correction/agentic/agent.py,sha256=73E2ouAiE0RUiIvxIb_lVaiIo_DJr_YaH3CAaqdjh08,13274
|
|
197
216
|
lyrics_transcriber/correction/agentic/feedback/aggregator.py,sha256=323t8LDbE26ni83woyN7uVMSuSQhnqTgwJc-d-KuDbs,273
|
|
198
217
|
lyrics_transcriber/correction/agentic/feedback/collector.py,sha256=HT-2cAP_bx7Iv-0-tpZv534do111g0FlTUt2XaKoUtA,415
|
|
199
218
|
lyrics_transcriber/correction/agentic/feedback/retention.py,sha256=dUCUsKPCzHVQxiLLBXcdfAZ5NqiG25go0Z6GFXeK0vY,881
|
|
@@ -231,8 +250,8 @@ lyrics_transcriber/correction/agentic/providers/circuit_breaker.py,sha256=D3Jg4Y
|
|
|
231
250
|
lyrics_transcriber/correction/agentic/providers/config.py,sha256=7m4I3imOZyv-6eR8mxuK9vVdqPEDcGuVAkEgdGWu10w,4299
|
|
232
251
|
lyrics_transcriber/correction/agentic/providers/constants.py,sha256=cXLzKTyFVt9q6wQd_gWcv3EZ5Sm27AOAz6NyPapcess,695
|
|
233
252
|
lyrics_transcriber/correction/agentic/providers/health.py,sha256=F8pHY5BQYvylGRDGXUHplcAJooAyiqVLRhBl4kHC1H8,710
|
|
234
|
-
lyrics_transcriber/correction/agentic/providers/langchain_bridge.py,sha256=
|
|
235
|
-
lyrics_transcriber/correction/agentic/providers/model_factory.py,sha256=
|
|
253
|
+
lyrics_transcriber/correction/agentic/providers/langchain_bridge.py,sha256=fgWZjzWiClBZ1NA6E8pf0kp23j6p56Htry_h7vtJ3ZM,12607
|
|
254
|
+
lyrics_transcriber/correction/agentic/providers/model_factory.py,sha256=ZsPdjSwnN1hFZxPwJkH-2rtgv59f9BmNRJmsLYtK67Q,10805
|
|
236
255
|
lyrics_transcriber/correction/agentic/providers/response_cache.py,sha256=Byr7fQJsgUMFlsvHeVCxTiFjjnbsg3KIlEmEEtAo-Gw,7047
|
|
237
256
|
lyrics_transcriber/correction/agentic/providers/response_parser.py,sha256=c2KypM-yHbIXXakHV5s-qh8fl8FhssLPVo3pJbyAiG4,4301
|
|
238
257
|
lyrics_transcriber/correction/agentic/providers/retry_executor.py,sha256=hX21Zwy2cSECAw7k13ndEinWRqwjo4xYoSCQ2B2CUf0,3912
|
|
@@ -241,7 +260,7 @@ lyrics_transcriber/correction/agentic/workflows/__init__.py,sha256=OsBExAbIIKxJg
|
|
|
241
260
|
lyrics_transcriber/correction/agentic/workflows/consensus_workflow.py,sha256=gMuLTUxkgYaciMsI4yrZSC3wi--7V_PgaDNE-Vd6FE8,575
|
|
242
261
|
lyrics_transcriber/correction/agentic/workflows/correction_graph.py,sha256=kgZKnz0h9cG1EfhW7BSSl-kSpQtJrRM_S86kAniXfE4,1815
|
|
243
262
|
lyrics_transcriber/correction/agentic/workflows/feedback_workflow.py,sha256=KsKLD3AP66YYmXfUn-mVZjERYLtU1Zs4a-7CB2zDfas,596
|
|
244
|
-
lyrics_transcriber/correction/anchor_sequence.py,sha256
|
|
263
|
+
lyrics_transcriber/correction/anchor_sequence.py,sha256=-FT4NoNjwGnoxgm4m117Z3DPlJAJAlFYcTe4BeUj9pQ,48974
|
|
245
264
|
lyrics_transcriber/correction/corrector.py,sha256=zqmpwt_LMG1VdijXUIMGr42ny2qIiBqwEIDCslqi2dE,42622
|
|
246
265
|
lyrics_transcriber/correction/feedback/__init__.py,sha256=i1gd0Vb4qvlzZQ3lqA3fJjt288YP7f-MBPwOzZ7Rjh4,68
|
|
247
266
|
lyrics_transcriber/correction/feedback/schemas.py,sha256=OiF_WUqcqiEKIoburYM8kWAIundy82PQE7ImsdP8UCk,4416
|
|
@@ -254,11 +273,11 @@ lyrics_transcriber/correction/handlers/no_space_punct_match.py,sha256=jY2fa547Qc
|
|
|
254
273
|
lyrics_transcriber/correction/handlers/relaxed_word_count_match.py,sha256=x4k__6gav4-STk_TycLcg5Sw4x2vUFAj5fWmOv7Yd_w,3911
|
|
255
274
|
lyrics_transcriber/correction/handlers/repeat.py,sha256=1PJADW44egYh7N9D2fN-gDIusWVglFjGHrCZuTQYNpA,4313
|
|
256
275
|
lyrics_transcriber/correction/handlers/sound_alike.py,sha256=75IvDSfoGUG2xVbYp-xsYuQXf7Jo-0ymsTzdBSOrwwQ,11935
|
|
257
|
-
lyrics_transcriber/correction/handlers/syllables_match.py,sha256=
|
|
276
|
+
lyrics_transcriber/correction/handlers/syllables_match.py,sha256=CV_sYISqPhA2VFbaU2XuX4SbjQcpeuMH7LTw91pgH4I,13103
|
|
258
277
|
lyrics_transcriber/correction/handlers/word_count_match.py,sha256=OltTEs6eYnslxdvak97M5gXDiqXJxMHKk__Q9F_akXc,3595
|
|
259
278
|
lyrics_transcriber/correction/handlers/word_operations.py,sha256=410xhyO9tiqezV5yd5JKwKbxSGwXK9LWHJ7-zNIuOWA,7423
|
|
260
279
|
lyrics_transcriber/correction/operations.py,sha256=rmSxDdlu5H2drbVvR1A9KuaZT60vbHeZKKaB7olD4ns,14659
|
|
261
|
-
lyrics_transcriber/correction/phrase_analyzer.py,sha256=
|
|
280
|
+
lyrics_transcriber/correction/phrase_analyzer.py,sha256=bEGz3KlH8iFAudMK7L0eC-CyVSwZkIZtXr8qh_k4_u8,17576
|
|
262
281
|
lyrics_transcriber/correction/text_utils.py,sha256=7QHK6-PY7Rx1G1E31sWiLBw00mHorRDo-M44KMHFaZs,833
|
|
263
282
|
lyrics_transcriber/frontend/.gitignore,sha256=cR2ofyyWArkna_jByfaWi8gTeMhsKTSoK128PmIw218,262
|
|
264
283
|
lyrics_transcriber/frontend/.yarn/releases/yarn-4.7.0.cjs,sha256=KTYy2KCV2OpHhussV5jIPDdUSr7RftMRhqPsRUmgfAY,2765465
|
|
@@ -282,7 +301,7 @@ lyrics_transcriber/frontend/public/favicon.ico,sha256=ZK7QvdBuZp0QxPkluCW4IKxfle
|
|
|
282
301
|
lyrics_transcriber/frontend/public/nomad-karaoke-logo.png,sha256=jTTBFXV6hGJGolZYQ-dIjgQQbMsehk5XGtsllhLrdzg,212641
|
|
283
302
|
lyrics_transcriber/frontend/public/nomad-karaoke-logo.svg,sha256=0LOH346_a-1JeYquMWd1v2A3XMN8zLDBeujfWAOeNYk,9185
|
|
284
303
|
lyrics_transcriber/frontend/src/App.tsx,sha256=STVmqN3xtXambV_5X4M0MNuwYjARHBQfn1cuCqxNGkw,7979
|
|
285
|
-
lyrics_transcriber/frontend/src/api.ts,sha256=
|
|
304
|
+
lyrics_transcriber/frontend/src/api.ts,sha256=MDTKq1rZUXKdRHb1YFDKaGuFOK-LO2wC3yvladlWjeY,9085
|
|
286
305
|
lyrics_transcriber/frontend/src/components/AIFeedbackModal.tsx,sha256=YvJlBP-3udqrOmvwKuMR7FxfIozZq5pVfTYvmhzbnHo,5602
|
|
287
306
|
lyrics_transcriber/frontend/src/components/AddLyricsModal.tsx,sha256=ubJwQewryjUrXwpBkITQNu4POhoUtDbNA93cqa-yJKY,3416
|
|
288
307
|
lyrics_transcriber/frontend/src/components/AgenticCorrectionMetrics.tsx,sha256=Yg6FG0LtrneRfAYeBu3crt_RdN-_o7FojtYhDMDKi0o,8595
|
|
@@ -309,7 +328,7 @@ lyrics_transcriber/frontend/src/components/MetricsDashboard.tsx,sha256=33XpyHj0s
|
|
|
309
328
|
lyrics_transcriber/frontend/src/components/ModeSelectionModal.tsx,sha256=eihGI49r9tKq-AaEtnmVrbiBOoJApWvabaZW4ydmg-4,5302
|
|
310
329
|
lyrics_transcriber/frontend/src/components/ModeSelector.tsx,sha256=HnBAK_gFgNBJLtMC_ESMVdUapDjmqmoLX8pQeyHfpOw,2651
|
|
311
330
|
lyrics_transcriber/frontend/src/components/ModelSelector.tsx,sha256=lfG_B5VAzSfrU0FqJl8XptN6DVt2kSljU96HMXo8mf4,559
|
|
312
|
-
lyrics_transcriber/frontend/src/components/PreviewVideoSection.tsx,sha256=
|
|
331
|
+
lyrics_transcriber/frontend/src/components/PreviewVideoSection.tsx,sha256=zKR_S1AyYAEmr1hnr2IN14mw1igpYbJB12HjaUrXbH4,6803
|
|
313
332
|
lyrics_transcriber/frontend/src/components/ReferenceView.tsx,sha256=a3CFpbJ8M-kFV3K79xyuo-sfOoC9He_IuXwhIcAOImo,10510
|
|
314
333
|
lyrics_transcriber/frontend/src/components/ReplaceAllLyricsModal.tsx,sha256=pVlqHrSloxXZV_Ib8cbk1invF7WA3uge5b7pnFPe9Pc,12290
|
|
315
334
|
lyrics_transcriber/frontend/src/components/ReviewChangesModal.tsx,sha256=VQg_gBFViAxQu9Z75o6rOsvmH5DZBjKq9FkU8aB_7mI,13790
|
|
@@ -431,8 +450,8 @@ lyrics_transcriber/transcribers/whisper.py,sha256=YcCB1ic9H6zL1GS0jD0emu8-qlcH0Q
|
|
|
431
450
|
lyrics_transcriber/types.py,sha256=UJjaxhVd2o14AG4G8ToU598p0JeYdiTFjpG38jGCoYQ,27917
|
|
432
451
|
lyrics_transcriber/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
433
452
|
lyrics_transcriber/utils/word_utils.py,sha256=-cMGpj9UV4F6IsoDKAV2i1aiqSO8eI91HMAm_igtVMk,958
|
|
434
|
-
karaoke_gen-0.
|
|
435
|
-
karaoke_gen-0.
|
|
436
|
-
karaoke_gen-0.
|
|
437
|
-
karaoke_gen-0.
|
|
438
|
-
karaoke_gen-0.
|
|
453
|
+
karaoke_gen-0.101.0.dist-info/METADATA,sha256=zkFeEtygnskVvZLwCarJ9blhCd4pA60LV75aSZm8RaI,23116
|
|
454
|
+
karaoke_gen-0.101.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
455
|
+
karaoke_gen-0.101.0.dist-info/entry_points.txt,sha256=xIyLe7K84ZyjO8L0_AmNectz93QjGSs5AkApMtlAd4g,160
|
|
456
|
+
karaoke_gen-0.101.0.dist-info/licenses/LICENSE,sha256=81R_4XwMZDODHD7JcZeUR8IiCU8AD7Ajl6bmwR9tYDk,1074
|
|
457
|
+
karaoke_gen-0.101.0.dist-info/RECORD,,
|
|
@@ -86,28 +86,39 @@ class AgenticCorrector:
|
|
|
86
86
|
|
|
87
87
|
@classmethod
|
|
88
88
|
def from_model(
|
|
89
|
-
cls,
|
|
90
|
-
model: str,
|
|
89
|
+
cls,
|
|
90
|
+
model: str,
|
|
91
91
|
config: ProviderConfig | None = None,
|
|
92
92
|
session_id: Optional[str] = None,
|
|
93
|
-
cache_dir: Optional[str] = None
|
|
93
|
+
cache_dir: Optional[str] = None,
|
|
94
|
+
warmup: bool = True
|
|
94
95
|
) -> "AgenticCorrector":
|
|
95
96
|
"""Factory method to create corrector from model specification.
|
|
96
|
-
|
|
97
|
+
|
|
97
98
|
This is a convenience method for the common case where you want
|
|
98
99
|
to use LangChainBridge with a model spec string.
|
|
99
|
-
|
|
100
|
+
|
|
100
101
|
Args:
|
|
101
102
|
model: Model identifier in format "provider/model"
|
|
102
103
|
config: Optional provider configuration
|
|
103
104
|
session_id: Optional Langfuse session ID to group related traces
|
|
104
105
|
cache_dir: Optional cache directory (uses default if not provided)
|
|
105
|
-
|
|
106
|
+
warmup: If True, eagerly initialize the model to avoid delays when
|
|
107
|
+
multiple threads call classify_gap() simultaneously (default: True)
|
|
108
|
+
|
|
106
109
|
Returns:
|
|
107
110
|
AgenticCorrector instance with LangChainBridge provider
|
|
108
111
|
"""
|
|
109
112
|
config = config or ProviderConfig.from_env(cache_dir=cache_dir)
|
|
110
113
|
provider = LangChainBridge(model=model, config=config)
|
|
114
|
+
|
|
115
|
+
# Eagerly initialize the model to avoid lazy initialization delays
|
|
116
|
+
# when multiple threads call classify_gap() simultaneously
|
|
117
|
+
if warmup:
|
|
118
|
+
logger.info(f"🤖 Warming up model {model} before parallel processing...")
|
|
119
|
+
if not provider.warmup():
|
|
120
|
+
logger.warning(f"🤖 Model warmup failed for {model}, will retry on first use")
|
|
121
|
+
|
|
111
122
|
return cls(provider=provider, session_id=session_id)
|
|
112
123
|
|
|
113
124
|
def classify_gap(
|
|
@@ -13,6 +13,7 @@ from __future__ import annotations
|
|
|
13
13
|
|
|
14
14
|
import logging
|
|
15
15
|
import os
|
|
16
|
+
import threading
|
|
16
17
|
import time
|
|
17
18
|
from concurrent.futures import ThreadPoolExecutor, TimeoutError as FuturesTimeoutError
|
|
18
19
|
from typing import List, Dict, Any, Optional
|
|
@@ -94,10 +95,80 @@ class LangChainBridge(BaseAIProvider):
|
|
|
94
95
|
cache_dir=self._config.cache_dir,
|
|
95
96
|
enabled=cache_enabled
|
|
96
97
|
)
|
|
97
|
-
|
|
98
|
-
# Lazy-initialized chat model
|
|
98
|
+
|
|
99
|
+
# Lazy-initialized chat model with thread-safe initialization
|
|
100
|
+
# Lock prevents race condition where multiple threads try to initialize simultaneously
|
|
99
101
|
self._chat_model: Optional[Any] = None
|
|
100
|
-
|
|
102
|
+
self._model_init_lock = threading.Lock()
|
|
103
|
+
|
|
104
|
+
def warmup(self) -> bool:
|
|
105
|
+
"""Eagerly initialize the chat model.
|
|
106
|
+
|
|
107
|
+
Call this after creating the bridge to avoid lazy initialization delays
|
|
108
|
+
when multiple threads call generate_correction_proposals() simultaneously.
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
True if model was initialized successfully, False otherwise
|
|
112
|
+
"""
|
|
113
|
+
if self._chat_model is not None:
|
|
114
|
+
logger.debug(f"🤖 Model {self._model} already initialized")
|
|
115
|
+
return True
|
|
116
|
+
|
|
117
|
+
logger.info(f"🤖 Warming up model {self._model}...")
|
|
118
|
+
# Trigger initialization by calling the initialization logic directly
|
|
119
|
+
try:
|
|
120
|
+
self._ensure_model_initialized()
|
|
121
|
+
return self._chat_model is not None
|
|
122
|
+
except Exception as e:
|
|
123
|
+
logger.error(f"🤖 Warmup failed for {self._model}: {e}")
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
def _ensure_model_initialized(self) -> None:
|
|
127
|
+
"""Ensure the chat model is initialized (thread-safe).
|
|
128
|
+
|
|
129
|
+
This method handles the lazy initialization with proper locking.
|
|
130
|
+
It's separated out so it can be called from both warmup() and
|
|
131
|
+
generate_correction_proposals().
|
|
132
|
+
"""
|
|
133
|
+
if self._chat_model is not None:
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
with self._model_init_lock:
|
|
137
|
+
# Double-check after acquiring lock
|
|
138
|
+
if self._chat_model is not None:
|
|
139
|
+
return
|
|
140
|
+
|
|
141
|
+
timeout = self._config.initialization_timeout_seconds
|
|
142
|
+
logger.info(f"🤖 Initializing model {self._model} with {timeout}s timeout...")
|
|
143
|
+
init_start = time.time()
|
|
144
|
+
|
|
145
|
+
try:
|
|
146
|
+
# Use ThreadPoolExecutor for cross-platform timeout
|
|
147
|
+
with ThreadPoolExecutor(max_workers=1) as executor:
|
|
148
|
+
future = executor.submit(
|
|
149
|
+
self._factory.create_chat_model,
|
|
150
|
+
self._model,
|
|
151
|
+
self._config
|
|
152
|
+
)
|
|
153
|
+
try:
|
|
154
|
+
self._chat_model = future.result(timeout=timeout)
|
|
155
|
+
except FuturesTimeoutError:
|
|
156
|
+
raise InitializationTimeoutError(
|
|
157
|
+
f"Model initialization timed out after {timeout}s. "
|
|
158
|
+
f"This may indicate network issues or service unavailability."
|
|
159
|
+
) from None
|
|
160
|
+
|
|
161
|
+
init_elapsed = time.time() - init_start
|
|
162
|
+
logger.info(f"🤖 Model initialized in {init_elapsed:.2f}s")
|
|
163
|
+
|
|
164
|
+
except InitializationTimeoutError:
|
|
165
|
+
self._circuit_breaker.record_failure(self._model)
|
|
166
|
+
raise
|
|
167
|
+
except Exception as e:
|
|
168
|
+
self._circuit_breaker.record_failure(self._model)
|
|
169
|
+
logger.error(f"🤖 Failed to initialize chat model: {e}")
|
|
170
|
+
raise
|
|
171
|
+
|
|
101
172
|
def name(self) -> str:
|
|
102
173
|
"""Return provider name for logging."""
|
|
103
174
|
return f"langchain:{self._model}"
|
|
@@ -140,46 +211,28 @@ class LangChainBridge(BaseAIProvider):
|
|
|
140
211
|
"until": open_until
|
|
141
212
|
}]
|
|
142
213
|
|
|
143
|
-
# Step 2: Get or create chat model with initialization
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
init_elapsed = time.time() - init_start
|
|
166
|
-
logger.info(f"🤖 Model initialized in {init_elapsed:.2f}s")
|
|
167
|
-
|
|
168
|
-
except InitializationTimeoutError as e:
|
|
169
|
-
self._circuit_breaker.record_failure(self._model)
|
|
170
|
-
logger.exception("🤖 Model initialization timeout")
|
|
171
|
-
return [{
|
|
172
|
-
"error": INIT_TIMEOUT_ERROR,
|
|
173
|
-
"message": str(e),
|
|
174
|
-
"timeout_seconds": timeout
|
|
175
|
-
}]
|
|
176
|
-
except Exception as e:
|
|
177
|
-
self._circuit_breaker.record_failure(self._model)
|
|
178
|
-
logger.error(f"🤖 Failed to initialize chat model: {e}")
|
|
179
|
-
return [{
|
|
180
|
-
"error": MODEL_INIT_ERROR,
|
|
181
|
-
"message": str(e)
|
|
182
|
-
}]
|
|
214
|
+
# Step 2: Get or create chat model with thread-safe initialization
|
|
215
|
+
# Use double-checked locking to avoid race condition where multiple threads
|
|
216
|
+
# all try to initialize the model simultaneously (which caused job 2ccbdf6b
|
|
217
|
+
# to have 5 concurrent model initializations and 6+ minute delays)
|
|
218
|
+
#
|
|
219
|
+
# NOTE: For best performance, call warmup() after creating the bridge to
|
|
220
|
+
# eagerly initialize the model before parallel processing begins.
|
|
221
|
+
try:
|
|
222
|
+
self._ensure_model_initialized()
|
|
223
|
+
except InitializationTimeoutError as e:
|
|
224
|
+
logger.exception("🤖 Model initialization timeout")
|
|
225
|
+
return [{
|
|
226
|
+
"error": INIT_TIMEOUT_ERROR,
|
|
227
|
+
"message": str(e),
|
|
228
|
+
"timeout_seconds": self._config.initialization_timeout_seconds
|
|
229
|
+
}]
|
|
230
|
+
except Exception as e:
|
|
231
|
+
logger.error(f"🤖 Failed to initialize chat model: {e}")
|
|
232
|
+
return [{
|
|
233
|
+
"error": MODEL_INIT_ERROR,
|
|
234
|
+
"message": str(e)
|
|
235
|
+
}]
|
|
183
236
|
|
|
184
237
|
# Step 3: Execute with retry logic
|
|
185
238
|
logger.info(
|
|
@@ -10,6 +10,14 @@ from .config import ProviderConfig
|
|
|
10
10
|
|
|
11
11
|
logger = logging.getLogger(__name__)
|
|
12
12
|
|
|
13
|
+
# Try to import Langfuse preloader (may not exist in standalone library usage)
|
|
14
|
+
try:
|
|
15
|
+
from backend.services.langfuse_preloader import get_preloaded_langfuse_handler
|
|
16
|
+
|
|
17
|
+
_HAS_LANGFUSE_PRELOADER = True
|
|
18
|
+
except ImportError:
|
|
19
|
+
_HAS_LANGFUSE_PRELOADER = False
|
|
20
|
+
|
|
13
21
|
# Error message constant for TRY003 compliance
|
|
14
22
|
GOOGLE_API_KEY_MISSING_ERROR = (
|
|
15
23
|
"GOOGLE_API_KEY environment variable is required for Google/Gemini models. "
|
|
@@ -87,25 +95,38 @@ class ModelFactory:
|
|
|
87
95
|
|
|
88
96
|
def _initialize_langfuse(self, model_spec: str) -> None:
|
|
89
97
|
"""Initialize Langfuse callback handler if keys are present.
|
|
90
|
-
|
|
98
|
+
|
|
99
|
+
First tries to use a preloaded handler (to avoid 200+ second init delay
|
|
100
|
+
on Cloud Run cold starts), then falls back to creating a new one.
|
|
101
|
+
|
|
91
102
|
Langfuse reads credentials from environment variables automatically:
|
|
92
103
|
- LANGFUSE_PUBLIC_KEY
|
|
93
|
-
- LANGFUSE_SECRET_KEY
|
|
104
|
+
- LANGFUSE_SECRET_KEY
|
|
94
105
|
- LANGFUSE_HOST (optional)
|
|
95
|
-
|
|
106
|
+
|
|
96
107
|
Args:
|
|
97
108
|
model_spec: Model specification for logging
|
|
98
|
-
|
|
109
|
+
|
|
99
110
|
Raises:
|
|
100
111
|
RuntimeError: If Langfuse keys are set but initialization fails
|
|
101
112
|
"""
|
|
102
113
|
public_key = os.getenv("LANGFUSE_PUBLIC_KEY")
|
|
103
114
|
secret_key = os.getenv("LANGFUSE_SECRET_KEY")
|
|
104
|
-
|
|
115
|
+
|
|
105
116
|
if not (public_key and secret_key):
|
|
106
117
|
logger.debug("🤖 Langfuse keys not found, tracing disabled")
|
|
107
118
|
return
|
|
108
|
-
|
|
119
|
+
|
|
120
|
+
# Try to use preloaded handler first (avoids 200+ second delay on Cloud Run)
|
|
121
|
+
if _HAS_LANGFUSE_PRELOADER:
|
|
122
|
+
preloaded = get_preloaded_langfuse_handler()
|
|
123
|
+
if preloaded is not None:
|
|
124
|
+
logger.info(f"🤖 Using preloaded Langfuse handler for {model_spec}")
|
|
125
|
+
self._langfuse_handler = preloaded
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
# Fall back to creating new handler
|
|
129
|
+
logger.info(f"🤖 Initializing Langfuse handler (not preloaded) for {model_spec}...")
|
|
109
130
|
try:
|
|
110
131
|
from langfuse.langchain import CallbackHandler
|
|
111
132
|
|