karaoke-gen 0.90.1__py3-none-any.whl → 0.96.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/.coveragerc +20 -0
- backend/.gitignore +37 -0
- backend/Dockerfile +43 -0
- backend/Dockerfile.base +74 -0
- backend/README.md +242 -0
- backend/__init__.py +0 -0
- backend/api/__init__.py +0 -0
- backend/api/dependencies.py +457 -0
- backend/api/routes/__init__.py +0 -0
- backend/api/routes/admin.py +742 -0
- backend/api/routes/audio_search.py +903 -0
- backend/api/routes/auth.py +348 -0
- backend/api/routes/file_upload.py +2076 -0
- backend/api/routes/health.py +344 -0
- backend/api/routes/internal.py +435 -0
- backend/api/routes/jobs.py +1610 -0
- backend/api/routes/review.py +652 -0
- backend/api/routes/themes.py +162 -0
- backend/api/routes/users.py +1014 -0
- backend/config.py +172 -0
- backend/main.py +133 -0
- backend/middleware/__init__.py +5 -0
- backend/middleware/audit_logging.py +124 -0
- backend/models/__init__.py +0 -0
- backend/models/job.py +519 -0
- backend/models/requests.py +123 -0
- backend/models/theme.py +153 -0
- backend/models/user.py +254 -0
- backend/models/worker_log.py +164 -0
- backend/pyproject.toml +29 -0
- backend/quick-check.sh +93 -0
- backend/requirements.txt +29 -0
- backend/run_tests.sh +60 -0
- backend/services/__init__.py +0 -0
- backend/services/audio_analysis_service.py +243 -0
- backend/services/audio_editing_service.py +278 -0
- backend/services/audio_search_service.py +702 -0
- backend/services/auth_service.py +630 -0
- backend/services/credential_manager.py +792 -0
- backend/services/discord_service.py +172 -0
- backend/services/dropbox_service.py +301 -0
- backend/services/email_service.py +1093 -0
- backend/services/encoding_interface.py +454 -0
- backend/services/encoding_service.py +405 -0
- backend/services/firestore_service.py +512 -0
- backend/services/flacfetch_client.py +573 -0
- backend/services/gce_encoding/README.md +72 -0
- backend/services/gce_encoding/__init__.py +22 -0
- backend/services/gce_encoding/main.py +589 -0
- backend/services/gce_encoding/requirements.txt +16 -0
- backend/services/gdrive_service.py +356 -0
- backend/services/job_logging.py +258 -0
- backend/services/job_manager.py +842 -0
- backend/services/job_notification_service.py +271 -0
- backend/services/local_encoding_service.py +590 -0
- backend/services/local_preview_encoding_service.py +407 -0
- backend/services/lyrics_cache_service.py +216 -0
- backend/services/metrics.py +413 -0
- backend/services/packaging_service.py +287 -0
- backend/services/rclone_service.py +106 -0
- backend/services/storage_service.py +209 -0
- backend/services/stripe_service.py +275 -0
- backend/services/structured_logging.py +254 -0
- backend/services/template_service.py +330 -0
- backend/services/theme_service.py +469 -0
- backend/services/tracing.py +543 -0
- backend/services/user_service.py +721 -0
- backend/services/worker_service.py +558 -0
- backend/services/youtube_service.py +112 -0
- backend/services/youtube_upload_service.py +445 -0
- backend/tests/__init__.py +4 -0
- backend/tests/conftest.py +224 -0
- backend/tests/emulator/__init__.py +7 -0
- backend/tests/emulator/conftest.py +88 -0
- backend/tests/emulator/test_e2e_cli_backend.py +1053 -0
- backend/tests/emulator/test_emulator_integration.py +356 -0
- backend/tests/emulator/test_style_loading_direct.py +436 -0
- backend/tests/emulator/test_worker_logs_direct.py +229 -0
- backend/tests/emulator/test_worker_logs_subcollection.py +443 -0
- backend/tests/requirements-test.txt +10 -0
- backend/tests/requirements.txt +6 -0
- backend/tests/test_admin_email_endpoints.py +411 -0
- backend/tests/test_api_integration.py +460 -0
- backend/tests/test_api_routes.py +93 -0
- backend/tests/test_audio_analysis_service.py +294 -0
- backend/tests/test_audio_editing_service.py +386 -0
- backend/tests/test_audio_search.py +1398 -0
- backend/tests/test_audio_services.py +378 -0
- backend/tests/test_auth_firestore.py +231 -0
- backend/tests/test_config_extended.py +68 -0
- backend/tests/test_credential_manager.py +377 -0
- backend/tests/test_dependencies.py +54 -0
- backend/tests/test_discord_service.py +244 -0
- backend/tests/test_distribution_services.py +820 -0
- backend/tests/test_dropbox_service.py +472 -0
- backend/tests/test_email_service.py +492 -0
- backend/tests/test_emulator_integration.py +322 -0
- backend/tests/test_encoding_interface.py +412 -0
- backend/tests/test_file_upload.py +1739 -0
- backend/tests/test_flacfetch_client.py +632 -0
- backend/tests/test_gdrive_service.py +524 -0
- backend/tests/test_instrumental_api.py +431 -0
- backend/tests/test_internal_api.py +343 -0
- backend/tests/test_job_creation_regression.py +583 -0
- backend/tests/test_job_manager.py +339 -0
- backend/tests/test_job_manager_notifications.py +329 -0
- backend/tests/test_job_notification_service.py +443 -0
- backend/tests/test_jobs_api.py +273 -0
- backend/tests/test_local_encoding_service.py +423 -0
- backend/tests/test_local_preview_encoding_service.py +567 -0
- backend/tests/test_main.py +87 -0
- backend/tests/test_models.py +918 -0
- backend/tests/test_packaging_service.py +382 -0
- backend/tests/test_requests.py +201 -0
- backend/tests/test_routes_jobs.py +282 -0
- backend/tests/test_routes_review.py +337 -0
- backend/tests/test_services.py +556 -0
- backend/tests/test_services_extended.py +112 -0
- backend/tests/test_storage_service.py +448 -0
- backend/tests/test_style_upload.py +261 -0
- backend/tests/test_template_service.py +295 -0
- backend/tests/test_theme_service.py +516 -0
- backend/tests/test_unicode_sanitization.py +522 -0
- backend/tests/test_upload_api.py +256 -0
- backend/tests/test_validate.py +156 -0
- backend/tests/test_video_worker_orchestrator.py +847 -0
- backend/tests/test_worker_log_subcollection.py +509 -0
- backend/tests/test_worker_logging.py +365 -0
- backend/tests/test_workers.py +1116 -0
- backend/tests/test_workers_extended.py +178 -0
- backend/tests/test_youtube_service.py +247 -0
- backend/tests/test_youtube_upload_service.py +568 -0
- backend/validate.py +173 -0
- backend/version.py +27 -0
- backend/workers/README.md +597 -0
- backend/workers/__init__.py +11 -0
- backend/workers/audio_worker.py +618 -0
- backend/workers/lyrics_worker.py +683 -0
- backend/workers/render_video_worker.py +483 -0
- backend/workers/screens_worker.py +525 -0
- backend/workers/style_helper.py +198 -0
- backend/workers/video_worker.py +1277 -0
- backend/workers/video_worker_orchestrator.py +701 -0
- backend/workers/worker_logging.py +278 -0
- karaoke_gen/instrumental_review/static/index.html +7 -4
- karaoke_gen/karaoke_finalise/karaoke_finalise.py +6 -1
- karaoke_gen/utils/__init__.py +163 -8
- karaoke_gen/video_background_processor.py +9 -4
- {karaoke_gen-0.90.1.dist-info → karaoke_gen-0.96.0.dist-info}/METADATA +1 -1
- {karaoke_gen-0.90.1.dist-info → karaoke_gen-0.96.0.dist-info}/RECORD +186 -41
- lyrics_transcriber/correction/agentic/providers/config.py +9 -5
- lyrics_transcriber/correction/agentic/providers/langchain_bridge.py +1 -51
- lyrics_transcriber/correction/corrector.py +192 -130
- lyrics_transcriber/correction/operations.py +24 -9
- lyrics_transcriber/frontend/package-lock.json +2 -2
- lyrics_transcriber/frontend/package.json +1 -1
- lyrics_transcriber/frontend/src/components/AIFeedbackModal.tsx +1 -1
- lyrics_transcriber/frontend/src/components/CorrectedWordWithActions.tsx +11 -7
- lyrics_transcriber/frontend/src/components/EditActionBar.tsx +31 -5
- lyrics_transcriber/frontend/src/components/EditModal.tsx +28 -10
- lyrics_transcriber/frontend/src/components/EditTimelineSection.tsx +123 -27
- lyrics_transcriber/frontend/src/components/EditWordList.tsx +112 -60
- lyrics_transcriber/frontend/src/components/Header.tsx +90 -76
- lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx +53 -31
- lyrics_transcriber/frontend/src/components/LyricsSynchronizer/SyncControls.tsx +44 -13
- lyrics_transcriber/frontend/src/components/LyricsSynchronizer/TimelineCanvas.tsx +66 -50
- lyrics_transcriber/frontend/src/components/LyricsSynchronizer/index.tsx +124 -30
- lyrics_transcriber/frontend/src/components/ReferenceView.tsx +1 -1
- lyrics_transcriber/frontend/src/components/TimelineEditor.tsx +12 -5
- lyrics_transcriber/frontend/src/components/TimingOffsetModal.tsx +3 -3
- lyrics_transcriber/frontend/src/components/TranscriptionView.tsx +1 -1
- lyrics_transcriber/frontend/src/components/WordDivider.tsx +11 -7
- lyrics_transcriber/frontend/src/components/shared/components/Word.tsx +4 -2
- lyrics_transcriber/frontend/src/hooks/useManualSync.ts +103 -1
- lyrics_transcriber/frontend/src/theme.ts +42 -15
- lyrics_transcriber/frontend/tsconfig.tsbuildinfo +1 -1
- lyrics_transcriber/frontend/vite.config.js +5 -0
- lyrics_transcriber/frontend/web_assets/assets/{index-BECn1o8Q.js → index-BSMgOq4Z.js} +6959 -5782
- lyrics_transcriber/frontend/web_assets/assets/index-BSMgOq4Z.js.map +1 -0
- lyrics_transcriber/frontend/web_assets/index.html +6 -2
- lyrics_transcriber/frontend/web_assets/nomad-karaoke-logo.svg +5 -0
- lyrics_transcriber/output/generator.py +17 -3
- lyrics_transcriber/output/video.py +60 -95
- lyrics_transcriber/frontend/web_assets/assets/index-BECn1o8Q.js.map +0 -1
- {karaoke_gen-0.90.1.dist-info → karaoke_gen-0.96.0.dist-info}/WHEEL +0 -0
- {karaoke_gen-0.90.1.dist-info → karaoke_gen-0.96.0.dist-info}/entry_points.txt +0 -0
- {karaoke_gen-0.90.1.dist-info → karaoke_gen-0.96.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Health check routes.
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
import logging
|
|
6
|
+
import subprocess
|
|
7
|
+
import platform
|
|
8
|
+
from fastapi import APIRouter
|
|
9
|
+
from typing import Dict, Any, Optional
|
|
10
|
+
|
|
11
|
+
from backend.version import VERSION
|
|
12
|
+
from backend.services.flacfetch_client import get_flacfetch_client
|
|
13
|
+
from backend.services.email_service import get_email_service
|
|
14
|
+
from backend.services.stripe_service import get_stripe_service
|
|
15
|
+
from backend.services.encoding_service import get_encoding_service
|
|
16
|
+
|
|
17
|
+
router = APIRouter()
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_system_info() -> Dict[str, Any]:
|
|
22
|
+
"""Get system information for performance analysis."""
|
|
23
|
+
info = {
|
|
24
|
+
"platform": platform.system(),
|
|
25
|
+
"platform_release": platform.release(),
|
|
26
|
+
"python_version": platform.python_version(),
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# Get CPU info
|
|
30
|
+
try:
|
|
31
|
+
cpu_count = os.cpu_count() or 0
|
|
32
|
+
info["cpu_count"] = cpu_count
|
|
33
|
+
|
|
34
|
+
# Try to get more detailed CPU info on Linux
|
|
35
|
+
if platform.system() == "Linux":
|
|
36
|
+
try:
|
|
37
|
+
with open("/proc/cpuinfo", "r") as f:
|
|
38
|
+
for line in f:
|
|
39
|
+
if "model name" in line:
|
|
40
|
+
info["cpu_model"] = line.split(":")[1].strip()
|
|
41
|
+
break
|
|
42
|
+
except Exception:
|
|
43
|
+
pass
|
|
44
|
+
except Exception as e:
|
|
45
|
+
info["cpu_error"] = str(e)
|
|
46
|
+
|
|
47
|
+
# Get memory info
|
|
48
|
+
try:
|
|
49
|
+
if platform.system() == "Linux":
|
|
50
|
+
with open("/proc/meminfo", "r") as f:
|
|
51
|
+
for line in f:
|
|
52
|
+
if line.startswith("MemTotal:"):
|
|
53
|
+
mem_kb = int(line.split()[1])
|
|
54
|
+
info["memory_gb"] = round(mem_kb / (1024 * 1024), 1)
|
|
55
|
+
break
|
|
56
|
+
except Exception as e:
|
|
57
|
+
info["memory_error"] = str(e)
|
|
58
|
+
|
|
59
|
+
return info
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_ffmpeg_info() -> Dict[str, Any]:
|
|
63
|
+
"""Get FFmpeg version and configuration for debugging encoding performance."""
|
|
64
|
+
try:
|
|
65
|
+
# Get FFmpeg version
|
|
66
|
+
result = subprocess.run(
|
|
67
|
+
["ffmpeg", "-version"],
|
|
68
|
+
capture_output=True,
|
|
69
|
+
text=True,
|
|
70
|
+
timeout=10
|
|
71
|
+
)
|
|
72
|
+
if result.returncode == 0:
|
|
73
|
+
lines = result.stdout.split("\n")
|
|
74
|
+
version_line = lines[0] if lines else "unknown"
|
|
75
|
+
|
|
76
|
+
# Check for hardware acceleration support
|
|
77
|
+
hw_accel = {}
|
|
78
|
+
config_result = subprocess.run(
|
|
79
|
+
["ffmpeg", "-hwaccels"],
|
|
80
|
+
capture_output=True,
|
|
81
|
+
text=True,
|
|
82
|
+
timeout=10
|
|
83
|
+
)
|
|
84
|
+
if config_result.returncode == 0:
|
|
85
|
+
hw_lines = config_result.stdout.strip().split("\n")
|
|
86
|
+
hw_accel["available"] = [h.strip() for h in hw_lines[1:] if h.strip()]
|
|
87
|
+
|
|
88
|
+
# Check encoder availability
|
|
89
|
+
encoders = {}
|
|
90
|
+
encoder_result = subprocess.run(
|
|
91
|
+
["ffmpeg", "-encoders"],
|
|
92
|
+
capture_output=True,
|
|
93
|
+
text=True,
|
|
94
|
+
timeout=10
|
|
95
|
+
)
|
|
96
|
+
if encoder_result.returncode == 0:
|
|
97
|
+
encoder_output = encoder_result.stdout
|
|
98
|
+
# Check for specific encoders we care about
|
|
99
|
+
encoders["libx264"] = "libx264" in encoder_output
|
|
100
|
+
encoders["h264_nvenc"] = "h264_nvenc" in encoder_output
|
|
101
|
+
encoders["h264_vaapi"] = "h264_vaapi" in encoder_output
|
|
102
|
+
encoders["hevc_nvenc"] = "hevc_nvenc" in encoder_output
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
"available": True,
|
|
106
|
+
"version": version_line,
|
|
107
|
+
"hw_acceleration": hw_accel,
|
|
108
|
+
"encoders": encoders,
|
|
109
|
+
}
|
|
110
|
+
else:
|
|
111
|
+
return {
|
|
112
|
+
"available": False,
|
|
113
|
+
"error": result.stderr[:500] if result.stderr else "Unknown error",
|
|
114
|
+
}
|
|
115
|
+
except subprocess.TimeoutExpired:
|
|
116
|
+
return {"available": False, "error": "Timeout getting FFmpeg info"}
|
|
117
|
+
except FileNotFoundError:
|
|
118
|
+
return {"available": False, "error": "FFmpeg not found"}
|
|
119
|
+
except Exception as e:
|
|
120
|
+
return {"available": False, "error": str(e)}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def check_transmission_status() -> Dict[str, Any]:
|
|
124
|
+
"""Check if Transmission daemon is available and responsive."""
|
|
125
|
+
try:
|
|
126
|
+
import transmission_rpc
|
|
127
|
+
host = os.environ.get("TRANSMISSION_HOST", "localhost")
|
|
128
|
+
port = int(os.environ.get("TRANSMISSION_PORT", "9091"))
|
|
129
|
+
|
|
130
|
+
client = transmission_rpc.Client(host=host, port=port, timeout=5)
|
|
131
|
+
stats = client.session_stats()
|
|
132
|
+
|
|
133
|
+
# Get detailed torrent info
|
|
134
|
+
torrents = client.get_torrents()
|
|
135
|
+
torrent_details = []
|
|
136
|
+
for t in torrents:
|
|
137
|
+
torrent_info = {
|
|
138
|
+
"name": t.name,
|
|
139
|
+
"progress": round(t.progress, 1),
|
|
140
|
+
"status": str(t.status),
|
|
141
|
+
"peers": t.peers_connected if hasattr(t, 'peers_connected') else 0,
|
|
142
|
+
"download_speed": round(t.rate_download / 1024, 1) if hasattr(t, 'rate_download') else 0, # KB/s
|
|
143
|
+
}
|
|
144
|
+
# Check if stalled (downloading but no progress and no peers)
|
|
145
|
+
if t.status.downloading and t.progress < 100 and torrent_info['peers'] == 0:
|
|
146
|
+
torrent_info['stalled'] = True
|
|
147
|
+
torrent_details.append(torrent_info)
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
"available": True,
|
|
151
|
+
"host": host,
|
|
152
|
+
"port": port,
|
|
153
|
+
"download_dir": stats.download_dir if hasattr(stats, 'download_dir') else None,
|
|
154
|
+
"active_torrent_count": stats.active_torrent_count if hasattr(stats, 'active_torrent_count') else 0,
|
|
155
|
+
"torrents": torrent_details,
|
|
156
|
+
}
|
|
157
|
+
except ImportError as e:
|
|
158
|
+
return {
|
|
159
|
+
"available": False,
|
|
160
|
+
"error": f"transmission_rpc not installed: {e}",
|
|
161
|
+
}
|
|
162
|
+
except Exception as e:
|
|
163
|
+
return {
|
|
164
|
+
"available": False,
|
|
165
|
+
"host": os.environ.get("TRANSMISSION_HOST", "localhost"),
|
|
166
|
+
"port": int(os.environ.get("TRANSMISSION_PORT", "9091")),
|
|
167
|
+
"error": str(e),
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@router.get("/health")
|
|
172
|
+
async def health_check() -> Dict[str, str]:
|
|
173
|
+
"""Health check endpoint."""
|
|
174
|
+
return {
|
|
175
|
+
"status": "healthy",
|
|
176
|
+
"service": "karaoke-gen-backend"
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
async def check_flacfetch_service_status() -> Dict[str, Any]:
|
|
181
|
+
"""Check if remote flacfetch service is available and healthy."""
|
|
182
|
+
client = get_flacfetch_client()
|
|
183
|
+
|
|
184
|
+
if not client:
|
|
185
|
+
return {
|
|
186
|
+
"configured": False,
|
|
187
|
+
"message": "Remote flacfetch service not configured (FLACFETCH_API_URL not set)",
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
try:
|
|
191
|
+
health = await client.health_check()
|
|
192
|
+
return {
|
|
193
|
+
"configured": True,
|
|
194
|
+
"available": True,
|
|
195
|
+
"status": health.get("status"),
|
|
196
|
+
"version": health.get("version"),
|
|
197
|
+
"transmission": health.get("transmission", {}),
|
|
198
|
+
"disk": health.get("disk", {}),
|
|
199
|
+
"providers": health.get("providers", {}),
|
|
200
|
+
}
|
|
201
|
+
except Exception as e:
|
|
202
|
+
return {
|
|
203
|
+
"configured": True,
|
|
204
|
+
"available": False,
|
|
205
|
+
"error": str(e),
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
async def check_encoding_worker_status() -> Dict[str, Any]:
|
|
210
|
+
"""Check if GCE encoding worker is available and healthy."""
|
|
211
|
+
encoding_service = get_encoding_service()
|
|
212
|
+
|
|
213
|
+
if not encoding_service.is_configured:
|
|
214
|
+
return {
|
|
215
|
+
"configured": False,
|
|
216
|
+
"enabled": encoding_service.settings.use_gce_encoding,
|
|
217
|
+
"message": "GCE encoding worker not configured (ENCODING_WORKER_URL or API key not set)",
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
try:
|
|
221
|
+
health = await encoding_service.health_check()
|
|
222
|
+
return {
|
|
223
|
+
"configured": True,
|
|
224
|
+
"enabled": encoding_service.is_enabled,
|
|
225
|
+
"available": health.get("status") == "ok",
|
|
226
|
+
"status": health.get("status"),
|
|
227
|
+
"active_jobs": health.get("active_jobs", 0),
|
|
228
|
+
"queue_length": health.get("queue_length", 0),
|
|
229
|
+
"ffmpeg_version": health.get("ffmpeg_version"),
|
|
230
|
+
"wheel_version": health.get("wheel_version"),
|
|
231
|
+
}
|
|
232
|
+
except Exception as e:
|
|
233
|
+
return {
|
|
234
|
+
"configured": True,
|
|
235
|
+
"enabled": encoding_service.is_enabled,
|
|
236
|
+
"available": False,
|
|
237
|
+
"error": str(e),
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
@router.get("/health/encoding-worker")
|
|
242
|
+
async def encoding_worker_health() -> Dict[str, Any]:
|
|
243
|
+
"""
|
|
244
|
+
Lightweight endpoint to check encoding worker status.
|
|
245
|
+
|
|
246
|
+
Returns minimal info for frontend footer display.
|
|
247
|
+
No authentication required.
|
|
248
|
+
"""
|
|
249
|
+
status = await check_encoding_worker_status()
|
|
250
|
+
|
|
251
|
+
# Return simplified response for frontend
|
|
252
|
+
if not status.get("configured"):
|
|
253
|
+
return {
|
|
254
|
+
"available": False,
|
|
255
|
+
"status": "not_configured",
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if not status.get("available"):
|
|
259
|
+
return {
|
|
260
|
+
"available": False,
|
|
261
|
+
"status": "offline",
|
|
262
|
+
"error": status.get("error"),
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
"available": True,
|
|
267
|
+
"status": "ok",
|
|
268
|
+
"version": status.get("wheel_version"),
|
|
269
|
+
"active_jobs": status.get("active_jobs", 0),
|
|
270
|
+
"queue_length": status.get("queue_length", 0),
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
@router.get("/health/detailed")
|
|
275
|
+
async def detailed_health_check() -> Dict[str, Any]:
|
|
276
|
+
"""
|
|
277
|
+
Detailed health check including dependencies.
|
|
278
|
+
|
|
279
|
+
Use this to debug issues with Transmission, flacfetch service, etc.
|
|
280
|
+
"""
|
|
281
|
+
transmission_status = check_transmission_status()
|
|
282
|
+
flacfetch_status = await check_flacfetch_service_status()
|
|
283
|
+
encoding_status = await check_encoding_worker_status()
|
|
284
|
+
|
|
285
|
+
# Check email service
|
|
286
|
+
email_service = get_email_service()
|
|
287
|
+
email_status = {
|
|
288
|
+
"configured": email_service.is_configured(),
|
|
289
|
+
"provider": type(email_service.provider).__name__,
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
# Check Stripe service
|
|
293
|
+
stripe_service = get_stripe_service()
|
|
294
|
+
stripe_status = {
|
|
295
|
+
"configured": stripe_service.is_configured(),
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
# Log for debugging
|
|
299
|
+
if not transmission_status.get("available"):
|
|
300
|
+
logger.warning(f"Local Transmission not available: {transmission_status.get('error')}")
|
|
301
|
+
else:
|
|
302
|
+
logger.info(f"Local Transmission available at {transmission_status.get('host')}:{transmission_status.get('port')}")
|
|
303
|
+
|
|
304
|
+
if flacfetch_status.get("configured") and not flacfetch_status.get("available"):
|
|
305
|
+
logger.warning(f"Remote flacfetch service not available: {flacfetch_status.get('error')}")
|
|
306
|
+
elif flacfetch_status.get("available"):
|
|
307
|
+
logger.info(f"Remote flacfetch service healthy: {flacfetch_status.get('status')}")
|
|
308
|
+
|
|
309
|
+
if not email_status["configured"]:
|
|
310
|
+
logger.warning("Email service not configured - magic links will not work")
|
|
311
|
+
|
|
312
|
+
if not stripe_status["configured"]:
|
|
313
|
+
logger.warning("Stripe service not configured - payments will not work")
|
|
314
|
+
|
|
315
|
+
# Get system and FFmpeg info for performance analysis
|
|
316
|
+
system_info = get_system_info()
|
|
317
|
+
ffmpeg_info = get_ffmpeg_info()
|
|
318
|
+
|
|
319
|
+
return {
|
|
320
|
+
"status": "healthy",
|
|
321
|
+
"service": "karaoke-gen-backend",
|
|
322
|
+
"version": VERSION,
|
|
323
|
+
"system": system_info,
|
|
324
|
+
"ffmpeg": ffmpeg_info,
|
|
325
|
+
"dependencies": {
|
|
326
|
+
"transmission_local": transmission_status,
|
|
327
|
+
"flacfetch_remote": flacfetch_status,
|
|
328
|
+
"encoding_worker": encoding_status,
|
|
329
|
+
},
|
|
330
|
+
"services": {
|
|
331
|
+
"email": email_status,
|
|
332
|
+
"stripe": stripe_status,
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
@router.get("/readiness")
|
|
338
|
+
async def readiness_check() -> Dict[str, str]:
|
|
339
|
+
"""Readiness check endpoint for Cloud Run."""
|
|
340
|
+
return {
|
|
341
|
+
"status": "ready",
|
|
342
|
+
"service": "karaoke-gen-backend"
|
|
343
|
+
}
|
|
344
|
+
|