Rthur2003 commited on
Commit
c5dd8f6
·
1 Parent(s): 8bf6e42

fix: improve error handling and logging in YouTubeAnalysisService

Browse files
Files changed (1) hide show
  1. app/services/youtube_analysis.py +40 -5
app/services/youtube_analysis.py CHANGED
@@ -15,7 +15,7 @@ from typing import List
15
  from .external_clients import ClientResponse, MusicAIDetectorClient, SesAnaliziClient
16
  from .preview_model import create_preview_result
17
  from .url_parser import parse_youtube_url
18
- from .youtube_downloader import YouTubeDownloader
19
  from .logging_config import get_logger
20
  from ..schemas import AnalysisSummary, ServiceResult, YouTubeAnalyzeResponse, YouTubeSource
21
 
@@ -23,6 +23,16 @@ from ..schemas import AnalysisSummary, ServiceResult, YouTubeAnalyzeResponse, Yo
23
  logger = get_logger(__name__)
24
 
25
 
 
 
 
 
 
 
 
 
 
 
26
  def _preview_summary(video_id: str, warnings: List[str]) -> AnalysisSummary:
27
  result = create_preview_result(video_id, warnings)
28
 
@@ -65,11 +75,34 @@ class YouTubeAnalysisService:
65
  try:
66
  download_result = downloader.download(parsed.normalized_url, parsed.video_id)
67
  logger.info(f"Download completed in {time.monotonic() - start_download:.2f}s")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  except Exception as exc:
69
  logger.error(f"Download failed: {exc}")
70
- errors.append(f"download_failed: {exc}")
71
  timings["total_sec"] = round(time.monotonic() - start_total, 4)
72
- summary = _preview_summary(parsed.video_id, warnings)
73
  source = YouTubeSource(
74
  url=url,
75
  normalized_url=parsed.normalized_url,
@@ -83,8 +116,8 @@ class YouTubeAnalysisService:
83
  summary=summary,
84
  music_ai=ServiceResult(available=False, response=None, error="download_failed"),
85
  ses_analizi=ServiceResult(available=False, response=None, error="download_failed"),
86
- warnings=warnings,
87
- errors=errors,
88
  timings=timings,
89
  )
90
 
@@ -143,6 +176,7 @@ class YouTubeAnalysisService:
143
  elif ses_result.error:
144
  warnings.append("ses_analizi_failed")
145
 
 
146
  summary = self._build_summary(music_ai_result, ses_result, parsed.video_id, warnings)
147
  timings["total_sec"] = round(time.monotonic() - start_total, 4)
148
 
@@ -153,6 +187,7 @@ class YouTubeAnalysisService:
153
  if ses_result.error and ses_result.error not in {"ses_analizi_not_configured", "ses_analizi_unsupported_format"}:
154
  errors.append(ses_result.error)
155
 
 
156
  status = "ok" if not errors else "partial"
157
 
158
  source = YouTubeSource(
 
15
  from .external_clients import ClientResponse, MusicAIDetectorClient, SesAnaliziClient
16
  from .preview_model import create_preview_result
17
  from .url_parser import parse_youtube_url
18
+ from .youtube_downloader import YouTubeDownloadError, YouTubeDownloader
19
  from .logging_config import get_logger
20
  from ..schemas import AnalysisSummary, ServiceResult, YouTubeAnalyzeResponse, YouTubeSource
21
 
 
23
  logger = get_logger(__name__)
24
 
25
 
26
+ def _unique_strings(values: List[str]) -> List[str]:
27
+ return list(dict.fromkeys(values))
28
+
29
+
30
+ def _download_error_codes(error_code: str) -> List[str]:
31
+ if error_code == "youtube_authentication_required":
32
+ return ["youtube_authentication_required", "youtube_analysis_failed"]
33
+ return ["youtube_analysis_failed"]
34
+
35
+
36
  def _preview_summary(video_id: str, warnings: List[str]) -> AnalysisSummary:
37
  result = create_preview_result(video_id, warnings)
38
 
 
75
  try:
76
  download_result = downloader.download(parsed.normalized_url, parsed.video_id)
77
  logger.info(f"Download completed in {time.monotonic() - start_download:.2f}s")
78
+ except YouTubeDownloadError as exc:
79
+ logger.error(f"Download failed ({exc.error_code}): {exc}")
80
+ warnings.extend(exc.warnings)
81
+ errors.extend(_download_error_codes(exc.error_code))
82
+ timings["total_sec"] = round(time.monotonic() - start_total, 4)
83
+ summary = _preview_summary(parsed.video_id, _unique_strings(warnings))
84
+ source = YouTubeSource(
85
+ url=url,
86
+ normalized_url=parsed.normalized_url,
87
+ video_id=parsed.video_id,
88
+ start_time_sec=parsed.start_time_sec,
89
+ )
90
+ return YouTubeAnalyzeResponse(
91
+ request_id=request_id,
92
+ status="partial",
93
+ source=source,
94
+ summary=summary,
95
+ music_ai=ServiceResult(available=False, response=None, error=exc.error_code),
96
+ ses_analizi=ServiceResult(available=False, response=None, error=exc.error_code),
97
+ warnings=_unique_strings(warnings),
98
+ errors=_unique_strings(errors),
99
+ timings=timings,
100
+ )
101
  except Exception as exc:
102
  logger.error(f"Download failed: {exc}")
103
+ errors.append("youtube_analysis_failed")
104
  timings["total_sec"] = round(time.monotonic() - start_total, 4)
105
+ summary = _preview_summary(parsed.video_id, _unique_strings(warnings))
106
  source = YouTubeSource(
107
  url=url,
108
  normalized_url=parsed.normalized_url,
 
116
  summary=summary,
117
  music_ai=ServiceResult(available=False, response=None, error="download_failed"),
118
  ses_analizi=ServiceResult(available=False, response=None, error="download_failed"),
119
+ warnings=_unique_strings(warnings),
120
+ errors=_unique_strings(errors),
121
  timings=timings,
122
  )
123
 
 
176
  elif ses_result.error:
177
  warnings.append("ses_analizi_failed")
178
 
179
+ warnings = _unique_strings(warnings)
180
  summary = self._build_summary(music_ai_result, ses_result, parsed.video_id, warnings)
181
  timings["total_sec"] = round(time.monotonic() - start_total, 4)
182
 
 
187
  if ses_result.error and ses_result.error not in {"ses_analizi_not_configured", "ses_analizi_unsupported_format"}:
188
  errors.append(ses_result.error)
189
 
190
+ errors = _unique_strings(errors)
191
  status = "ok" if not errors else "partial"
192
 
193
  source = YouTubeSource(