fmab777 commited on
Commit
c72d246
·
verified ·
1 Parent(s): e47ae70

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +84 -143
main.py CHANGED
@@ -99,34 +99,16 @@ APIFY_API_TOKEN = get_secret('APIFY_API_TOKEN')
99
  RAPIDAPI_KEY = get_secret('RAPIDAPI_KEY')
100
  WEBHOOK_SECRET = get_secret('WEBHOOK_SECRET')
101
 
102
- # --- Model Configurations (Specific April 2025 UPDATE) ---
103
- # Model Priority (first → last):
104
- # 1. Gemini 2.5 Flash Preview
105
- # 2. Gemini 2.5 Pro Exp
106
- # 3. Gemini 2.0 Flash
107
- # 4. OpenRouter DeepSeek V3 Free
108
- # 5. Groq Llama 4 Scout
109
- GEMINI_FLASH_PREVIEW_MODEL = os.environ.get(
110
- "GEMINI_FLASH_PREVIEW_MODEL",
111
- "gemini-2.5-flash-preview"
112
- )
113
- GEMINI_PRO_EXP_MODEL = os.environ.get(
114
- "GEMINI_PRO_EXP_MODEL",
115
- "gemini-2.5-pro-exp-03-25"
116
- )
117
- GEMINI_FLASH_MODEL = os.environ.get(
118
- "GEMINI_FLASH_MODEL",
119
- "gemini-2.0-flash-001"
120
- )
121
- OPENROUTER_DEEPSEEK_MODEL = os.environ.get(
122
- "OPENROUTER_DEEPSEEK_MODEL",
123
- "deepseek/deepseek-chat-v3-0324:free"
124
- )
125
- GROQ_LLAMA4_MODEL = os.environ.get(
126
- "GROQ_LLAMA4_MODEL",
127
- "meta-llama/llama-4-scout-17b-16e-instruct"
128
- )
129
-
130
 
131
  APIFY_ACTOR_ID = os.environ.get("APIFY_ACTOR_ID", "1s7eXiaukVuOr4Ueg") # YT Default
132
  APIFY_STRUCTURED_YT_ACTOR_ID = "gpjTCWkGZS1lHc9pR" # YT Fallback 1 (New Structured Extractor)
@@ -162,27 +144,10 @@ if not SUPADATA_API_KEY: logger.warning("Optional secret 'SUPADATA_API_KEY' not
162
  if not WEBHOOK_SECRET: logger.info("Optional secret 'WEBHOOK_SECRET' not found. Webhook security disabled.")
163
 
164
  logger.info("Secret loading and configuration check finished.")
165
- logger.info(
166
- f"Summariser 1 (Gemini Flash Preview): "
167
- f"{GEMINI_FLASH_PREVIEW_MODEL if _gemini_api_enabled else 'DISABLED'}"
168
- )
169
- logger.info(
170
- f"Summariser 2 (Gemini Pro Exp): "
171
- f"{GEMINI_PRO_EXP_MODEL if _gemini_api_enabled else 'DISABLED'}"
172
- )
173
- logger.info(
174
- f"Summariser 3 (Gemini Flash 2.0): "
175
- f"{GEMINI_FLASH_MODEL if _gemini_api_enabled else 'DISABLED'}"
176
- )
177
- logger.info(
178
- f"Summariser 4 (OpenRouter DeepSeek V3): "
179
- f"{OPENROUTER_DEEPSEEK_MODEL if _openrouter_fallback_enabled else 'DISABLED'}"
180
- )
181
- logger.info(
182
- f"Summariser 5 (Groq Llama 4 Scout): "
183
- f"{GROQ_LLAMA4_MODEL if _groq_enabled else 'DISABLED'}"
184
- )
185
-
186
  # --- Updated Logging ---
187
  logger.info(f"Using Apify Actor (YT Fallback 1 - Structured): {APIFY_STRUCTURED_YT_ACTOR_ID}")
188
  logger.info(f"Using Apify Actor (YT Fallback 3 - Default): {APIFY_ACTOR_ID}") # Now fallback 3
@@ -887,27 +852,19 @@ async def _call_gemini(text: str, summary_type: str, model_name: str) -> Tuple[O
887
  # FIX: Define safety_settings explicitly with the 5 categories from the error log
888
  # Removed the problematic loop that dynamically added potentially unsupported categories.
889
  try:
890
- # safety settings – list‑of‑dict form (docs compliant)
891
- safety_settings = [
892
- {"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE"},
893
- {"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE"},
894
- {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_NONE"},
895
- {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE"},
896
- {"category": "HARM_CATEGORY_CIVIC_INTEGRITY", "threshold": "BLOCK_NONE"},
897
- ]
898
-
899
- list_descr = ", ".join(f"{s['category']}:{s['threshold']}"
900
- for s in safety_settings)
901
- logger.debug(f"[Gemini {model_name}] Using safety settings → {list_descr}")
902
-
903
  except AttributeError:
904
- logger.error(f"[Gemini {model_name}] Failed to define safety settings "
905
- "(HarmCategory/HarmBlockThreshold missing?)")
906
- return None, (
907
- f"Sorry, an internal error occurred configuring the AI service "
908
- f"({model_name})."
909
- )
910
-
911
 
912
  try:
913
  logger.debug(f"[Gemini {model_name}] Initializing model {model_name}")
@@ -1019,91 +976,82 @@ async def _call_openrouter(text: str, summary_type: str) -> Tuple[Optional[str],
1019
 
1020
  async def generate_summary(text: str, summary_type: str) -> str:
1021
  """
1022
- Generates a summary using the April 2025 hierarchy:
1023
- 1. Gemini 2.5 Flash Preview
1024
- 2. Gemini 2.5 Pro Exp
1025
- 3. Gemini 2.0 Flash
1026
- 4. OpenRouter DeepSeek V3 Free
1027
- 5. Groq Llama 4 Scout
1028
  """
1029
- logger.info("[Summary Generation] Starting with updated model hierarchy.")
 
 
 
1030
  summary: Optional[str] = None
1031
  errors: Dict[str, Optional[str]] = {
1032
- "GeminiFlashPreview": None,
1033
  "GeminiProExp": None,
1034
  "GeminiFlash": None,
1035
  "DeepSeekV3": None,
1036
- "Llama4Scout": None,
1037
  }
1038
 
1039
- # Attempt 1: Gemini 2.5 Flash Preview
1040
- if _gemini_api_enabled:
1041
- summary, errors["GeminiFlashPreview"] = await _call_gemini(
1042
- text, summary_type, GEMINI_FLASH_PREVIEW_MODEL
1043
- )
1044
  if summary:
 
1045
  return summary
1046
- logger.warning(
1047
- f"[Summary Generation] Gemini Flash Preview failed: "
1048
- f"{errors['GeminiFlashPreview']}; trying Gemini Pro Exp."
1049
- )
1050
  else:
1051
- errors["GeminiFlashPreview"] = "Service disabled/unavailable."
 
1052
 
1053
- # Attempt 2: Gemini 2.5 Pro Exp
1054
  if _gemini_api_enabled:
1055
- summary, errors["GeminiProExp"] = await _call_gemini(
1056
- text, summary_type, GEMINI_PRO_EXP_MODEL
1057
- )
1058
  if summary:
 
1059
  return summary
1060
- logger.warning(
1061
- f"[Summary Generation] Gemini Pro Exp failed: "
1062
- f"{errors['GeminiProExp']}; trying Gemini Flash 2.0."
1063
- )
1064
-
1065
- # Attempt 3: Gemini 2.0 Flash
1066
- if _gemini_api_enabled:
1067
- summary, errors["GeminiFlash"] = await _call_gemini(
1068
- text, summary_type, GEMINI_FLASH_MODEL
1069
- )
 
1070
  if summary:
 
1071
  return summary
1072
- logger.warning(
1073
- f"[Summary Generation] Gemini Flash 2.0 failed: "
1074
- f"{errors['GeminiFlash']}; trying DeepSeek V3."
1075
- )
 
1076
 
1077
- # Attempt 4: OpenRouter DeepSeek V3
1078
  if _openrouter_fallback_enabled:
 
1079
  summary, errors["DeepSeekV3"] = await _call_openrouter(text, summary_type)
1080
  if summary:
 
1081
  return summary
1082
- logger.warning(
1083
- f"[Summary Generation] DeepSeek V3 failed: "
1084
- f"{errors['DeepSeekV3']}; trying Llama 4 Scout."
1085
- )
1086
  else:
 
1087
  errors["DeepSeekV3"] = "Service disabled/unavailable."
1088
 
1089
- # Attempt 5: Groq Llama 4 Scout
1090
- if _groq_enabled:
1091
- summary, errors["Llama4Scout"] = await _call_groq(text, summary_type)
1092
- if summary:
1093
- return summary
1094
- logger.error(
1095
- f"[Summary Generation] Llama 4 Scout failed: {errors['Llama4Scout']}."
1096
- )
1097
- else:
1098
- errors["Llama4Scout"] = "Service disabled/unavailable."
1099
-
1100
- # All failed
1101
- error_details = "\n".join(f"- {k}: {v}" for k, v in errors.items() if v)
1102
- return (
1103
- "Sorry, I could not generate a summary after trying all available AI models.\n"
1104
- f"Details:\n{error_details}"
1105
- )
1106
-
1107
 
1108
 
1109
  # --- Main Processing Logic ---
@@ -1268,7 +1216,7 @@ async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No
1268
  "2. I'll ask how you want it summarised (paragraph or points).\n"
1269
  "3. Click the button for your choice.\n"
1270
  "4. Wait while I fetch the content and generate the summary!\n\n"
1271
- "⚙️ I try multiple methods to get content, especially for tricky websites or YouTube videos without standard transcripts. I use a five‑step fallback: Gemini 2.5 Flash Preview Gemini 2.5 Pro Exp Gemini 2.0 Flash DeepSeek V3 Llama 4 Scout.\n\n" # Updated help text
1272
  "**Commands:**\n"
1273
  "`/start` - Display the welcome message\n"
1274
  "`/help` - Show this help message" )
@@ -1432,7 +1380,7 @@ async def lifespan(app: Starlette):
1432
 
1433
  async def health_check(request: Request) -> PlainTextResponse:
1434
  """Simple health check endpoint."""
1435
- global GROQ_LLAMA4_MODEL, GEMINI_PRO_EXP_MODEL, GEMINI_FLASH_MODEL, GEMINI_FLASH_PREVIEW_MODEL, OPENROUTER_DEEPSEEK_MODEL
1436
  global APIFY_ACTOR_ID, APIFY_STRUCTURED_YT_ACTOR_ID # Add new ID here
1437
  global _groq_enabled, _gemini_api_enabled, _openrouter_fallback_enabled
1438
  global _apify_token_exists, _urltotext_key_exists, _rapidapi_key_exists, SUPADATA_API_KEY
@@ -1457,18 +1405,11 @@ async def health_check(request: Request) -> PlainTextResponse:
1457
  return PlainTextResponse(
1458
  f"TG Bot Summariser - Status: {bot_status} ({bot_username})\n"
1459
  f"---\n"
1460
- f"Summariser Priority (April 2025):\n"
1461
- f"1. Gemini Flash Preview: "
1462
- f"{GEMINI_FLASH_PREVIEW_MODEL if _gemini_api_enabled else 'DISABLED'}\n"
1463
- f"2. Gemini Pro Exp: "
1464
- f"{GEMINI_PRO_EXP_MODEL if _gemini_api_enabled else 'DISABLED'}\n"
1465
- f"3. Gemini Flash 2.0: "
1466
- f"{GEMINI_FLASH_MODEL if _gemini_api_enabled else 'DISABLED'}\n"
1467
- f"4. OpenRouter DeepSeek V3: "
1468
- f"{OPENROUTER_DEEPSEEK_MODEL if _openrouter_fallback_enabled else 'DISABLED'}\n"
1469
- f"5. Groq Llama 4 Scout: "
1470
- f"{GROQ_LLAMA4_MODEL if _groq_enabled else 'DISABLED'}\n"
1471
-
1472
  f"---\n"
1473
  f"Content Fetching Status:\n"
1474
  # --- Updated YT Fallback List ---
 
99
  RAPIDAPI_KEY = get_secret('RAPIDAPI_KEY')
100
  WEBHOOK_SECRET = get_secret('WEBHOOK_SECRET')
101
 
102
+ # --- Model Configurations (Specific April 2025) ---
103
+ # Model Priority:
104
+ # 1. Groq Llama 4 Scout
105
+ # 2. Gemini 2.5 Pro Exp
106
+ # 3. Gemini 2.0 Flash
107
+ # 4. OpenRouter DeepSeek V3 Free
108
+ GROQ_LLAMA4_MODEL = os.environ.get("GROQ_LLAMA4_MODEL", "meta-llama/llama-4-scout-17b-16e-instruct") # Specific Llama 4 model
109
+ GEMINI_PRO_EXP_MODEL = os.environ.get("GEMINI_PRO_EXP_MODEL", "gemini-2.5-pro-exp-03-25")
110
+ GEMINI_FLASH_MODEL = os.environ.get("GEMINI_FLASH_MODEL", "gemini-2.0-flash-001")
111
+ OPENROUTER_DEEPSEEK_MODEL = os.environ.get("OPENROUTER_DEEPSEEK_MODEL", "deepseek/deepseek-chat-v3-0324:free") # Specific DeepSeek model
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
  APIFY_ACTOR_ID = os.environ.get("APIFY_ACTOR_ID", "1s7eXiaukVuOr4Ueg") # YT Default
114
  APIFY_STRUCTURED_YT_ACTOR_ID = "gpjTCWkGZS1lHc9pR" # YT Fallback 1 (New Structured Extractor)
 
144
  if not WEBHOOK_SECRET: logger.info("Optional secret 'WEBHOOK_SECRET' not found. Webhook security disabled.")
145
 
146
  logger.info("Secret loading and configuration check finished.")
147
+ logger.info(f"Summarizer 1 (Groq): {GROQ_LLAMA4_MODEL if _groq_enabled else 'DISABLED'}")
148
+ logger.info(f"Summarizer 2 (Gemini Pro Exp): {GEMINI_PRO_EXP_MODEL if _gemini_api_enabled else 'DISABLED'}")
149
+ logger.info(f"Summarizer 3 (Gemini Flash): {GEMINI_FLASH_MODEL if _gemini_api_enabled else 'DISABLED'}")
150
+ logger.info(f"Summarizer 4 (OpenRouter): {OPENROUTER_DEEPSEEK_MODEL if _openrouter_fallback_enabled else 'DISABLED'}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  # --- Updated Logging ---
152
  logger.info(f"Using Apify Actor (YT Fallback 1 - Structured): {APIFY_STRUCTURED_YT_ACTOR_ID}")
153
  logger.info(f"Using Apify Actor (YT Fallback 3 - Default): {APIFY_ACTOR_ID}") # Now fallback 3
 
852
  # FIX: Define safety_settings explicitly with the 5 categories from the error log
853
  # Removed the problematic loop that dynamically added potentially unsupported categories.
854
  try:
855
+ safety_settings = {
856
+ HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE,
857
+ HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE,
858
+ HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE,
859
+ HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE,
860
+ HarmCategory.HARM_CATEGORY_CIVIC_INTEGRITY: HarmBlockThreshold.BLOCK_NONE, # Added based on error msg
861
+ }
862
+ logger.debug(f"[Gemini {model_name}] Using safety settings: { {k.name: v.name for k, v in safety_settings.items()} }")
 
 
 
 
 
863
  except AttributeError:
864
+ # Handle case where HarmCategory or HarmBlockThreshold might not be loaded correctly
865
+ # This shouldn't happen if _gemini_sdk_available is True, but defensive coding
866
+ logger.error(f"[Gemini {model_name}] Failed to define safety settings. HarmCategory/HarmBlockThreshold missing?")
867
+ return None, f"Sorry, an internal error occurred configuring the AI service ({model_name})."
 
 
 
868
 
869
  try:
870
  logger.debug(f"[Gemini {model_name}] Initializing model {model_name}")
 
976
 
977
  async def generate_summary(text: str, summary_type: str) -> str:
978
  """
979
+ Generates summary using the specific model hierarchy (April 2025):
980
+ 1. Groq (Llama 4 Scout)
981
+ 2. Gemini (2.5 Pro Exp)
982
+ 3. Gemini (2.0 Flash)
983
+ 4. OpenRouter (DeepSeek V3 Free)
984
+ Returns the summary text or a comprehensive error message.
985
  """
986
+ global _groq_enabled, _gemini_api_enabled, _openrouter_fallback_enabled
987
+ global GROQ_LLAMA4_MODEL, GEMINI_PRO_EXP_MODEL, GEMINI_FLASH_MODEL, OPENROUTER_DEEPSEEK_MODEL
988
+
989
+ logger.info("[Summary Generation] Starting process with specific April 2025 model hierarchy.")
990
  summary: Optional[str] = None
991
  errors: Dict[str, Optional[str]] = {
992
+ "Llama4Scout": None,
993
  "GeminiProExp": None,
994
  "GeminiFlash": None,
995
  "DeepSeekV3": None,
 
996
  }
997
 
998
+ # --- Attempt 1: Groq (Llama 4 Scout) ---
999
+ if _groq_enabled:
1000
+ logger.info(f"[Summary Generation] Attempting 1: Groq ({GROQ_LLAMA4_MODEL})")
1001
+ summary, errors["Llama4Scout"] = await _call_groq(text, summary_type)
 
1002
  if summary:
1003
+ logger.info(f"[Summary Generation] Success with Groq ({GROQ_LLAMA4_MODEL}).")
1004
  return summary
1005
+ else:
1006
+ logger.warning(f"[Summary Generation] Groq Llama 4 Scout failed. Error: {errors['Llama4Scout']}. Proceeding to Gemini 2.5 Pro Exp.")
 
 
1007
  else:
1008
+ logger.warning("[Summary Generation] Groq (Llama 4 Scout) is disabled or unavailable. Skipping.")
1009
+ errors["Llama4Scout"] = "Service disabled/unavailable."
1010
 
1011
+ # --- Attempt 2: Gemini 2.5 Pro Exp ---
1012
  if _gemini_api_enabled:
1013
+ logger.info(f"[Summary Generation] Attempting 2: Gemini ({GEMINI_PRO_EXP_MODEL})")
1014
+ summary, errors["GeminiProExp"] = await _call_gemini(text, summary_type, GEMINI_PRO_EXP_MODEL)
 
1015
  if summary:
1016
+ logger.info(f"[Summary Generation] Success with Gemini ({GEMINI_PRO_EXP_MODEL}).")
1017
  return summary
1018
+ else:
1019
+ logger.warning(f"[Summary Generation] Gemini 2.5 Pro Exp failed. Error: {errors['GeminiProExp']}. Proceeding to Gemini 2.0 Flash.")
1020
+ else:
1021
+ logger.warning("[Summary Generation] Gemini API is disabled or unavailable. Skipping Gemini 2.5 Pro Exp & 2.0 Flash.")
1022
+ errors["GeminiProExp"] = "Service disabled/unavailable."
1023
+ errors["GeminiFlash"] = "Service disabled/unavailable."
1024
+
1025
+ # --- Attempt 3: Gemini 2.0 Flash ---
1026
+ if _gemini_api_enabled and errors["GeminiFlash"] is None: # Check if Gemini API is enabled AND wasn't already marked as failed/skipped
1027
+ logger.info(f"[Summary Generation] Attempting 3: Gemini ({GEMINI_FLASH_MODEL})")
1028
+ summary, errors["GeminiFlash"] = await _call_gemini(text, summary_type, GEMINI_FLASH_MODEL)
1029
  if summary:
1030
+ logger.info(f"[Summary Generation] Success with Gemini ({GEMINI_FLASH_MODEL}).")
1031
  return summary
1032
+ else:
1033
+ logger.warning(f"[Summary Generation] Gemini 2.0 Flash failed. Error: {errors['GeminiFlash']}. Proceeding to OpenRouter DeepSeek V3.")
1034
+ elif errors["GeminiFlash"] is None: # Only log skip message if it wasn't already marked as disabled
1035
+ logger.warning("[Summary Generation] Skipping Gemini 2.0 Flash (API was disabled).")
1036
+ errors["GeminiFlash"] = "Service disabled/unavailable."
1037
 
1038
+ # --- Attempt 4: OpenRouter (DeepSeek V3 Free - Final Fallback) ---
1039
  if _openrouter_fallback_enabled:
1040
+ logger.info(f"[Summary Generation] Attempting 4: OpenRouter ({OPENROUTER_DEEPSEEK_MODEL})")
1041
  summary, errors["DeepSeekV3"] = await _call_openrouter(text, summary_type)
1042
  if summary:
1043
+ logger.info(f"[Summary Generation] Success with OpenRouter ({OPENROUTER_DEEPSEEK_MODEL}).")
1044
  return summary
1045
+ else:
1046
+ logger.error(f"[Summary Generation] OpenRouter DeepSeek V3 (Final Fallback) also failed. Error: {errors['DeepSeekV3']}")
 
 
1047
  else:
1048
+ logger.error("[Summary Generation] OpenRouter fallback (DeepSeek V3) is disabled or unavailable. Cannot proceed.")
1049
  errors["DeepSeekV3"] = "Service disabled/unavailable."
1050
 
1051
+ # --- All Attempts Failed ---
1052
+ logger.error("[Summary Generation] All summarization models failed.")
1053
+ error_details = "\n".join([f"- {model}: {err}" for model, err in errors.items() if err])
1054
+ return f"Sorry, I couldn't generate a summary after trying all available AI models.\nDetails:\n{error_details}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1055
 
1056
 
1057
  # --- Main Processing Logic ---
 
1216
  "2. I'll ask how you want it summarised (paragraph or points).\n"
1217
  "3. Click the button for your choice.\n"
1218
  "4. Wait while I fetch the content and generate the summary!\n\n"
1219
+ "⚙️ I try multiple methods to get content, especially for tricky websites or YouTube videos without standard transcripts. I then use a sequence of AI models (Llama 4 Scout, Gemini 2.5 Pro, Gemini 2.0 Flash, DeepSeek V3) to summarise.\n\n" # Updated help text
1220
  "**Commands:**\n"
1221
  "`/start` - Display the welcome message\n"
1222
  "`/help` - Show this help message" )
 
1380
 
1381
  async def health_check(request: Request) -> PlainTextResponse:
1382
  """Simple health check endpoint."""
1383
+ global GROQ_LLAMA4_MODEL, GEMINI_PRO_EXP_MODEL, GEMINI_FLASH_MODEL, OPENROUTER_DEEPSEEK_MODEL
1384
  global APIFY_ACTOR_ID, APIFY_STRUCTURED_YT_ACTOR_ID # Add new ID here
1385
  global _groq_enabled, _gemini_api_enabled, _openrouter_fallback_enabled
1386
  global _apify_token_exists, _urltotext_key_exists, _rapidapi_key_exists, SUPADATA_API_KEY
 
1405
  return PlainTextResponse(
1406
  f"TG Bot Summariser - Status: {bot_status} ({bot_username})\n"
1407
  f"---\n"
1408
+ f"Summarizer Priority (April 2025 - Specific):\n"
1409
+ f"1. Groq API: {GROQ_LLAMA4_MODEL if _groq_enabled else 'DISABLED'}\n"
1410
+ f"2. Gemini API: {GEMINI_PRO_EXP_MODEL if _gemini_api_enabled else 'DISABLED'}\n"
1411
+ f"3. Gemini API: {GEMINI_FLASH_MODEL if _gemini_api_enabled else 'DISABLED'}\n"
1412
+ f"4. OpenRouter API: {OPENROUTER_DEEPSEEK_MODEL if _openrouter_fallback_enabled else 'DISABLED'}\n"
 
 
 
 
 
 
 
1413
  f"---\n"
1414
  f"Content Fetching Status:\n"
1415
  # --- Updated YT Fallback List ---