Spaces:
Sleeping
Sleeping
| import asyncio | |
| import os | |
| import logging | |
| import random | |
| import time | |
| import re | |
| from app.config import GEMINI_API_KEY, GEMINI_MODEL | |
| try: | |
| import google.genai as genai | |
| try: | |
| from google.genai import errors as genai_errors | |
| except Exception: | |
| genai_errors = None | |
| except Exception: | |
| genai = None | |
| genai_errors = None | |
| logging.warning("[summary_service] google.genai module not found; summary generation disabled") | |
| try: | |
| from google.api_core.exceptions import GoogleAPIError | |
| except Exception: | |
| GoogleAPIError = Exception | |
| gemini_client = None | |
| if not genai: | |
| logging.warning("[summary_service] google.genai not available, summary generation will be disabled") | |
| elif not GEMINI_API_KEY: | |
| logging.warning("[summary_service] GEMINI_API_KEY is not set, summary generation will be disabled") | |
| else: | |
| try: | |
| gemini_client = genai.Client(api_key=GEMINI_API_KEY) | |
| logging.info(f"[summary_service] Initialized google.genai client with model={GEMINI_MODEL}") | |
| except Exception as e: | |
| logging.exception(f"[summary_service] Failed to init google.genai client: {e}") | |
| gemini_client = None | |
| async def generate_summary(text: str) -> str: | |
| if not gemini_client: | |
| return "" | |
| if not text: | |
| return "" | |
| prompt = f""" | |
| Bạn là chuyên gia tóm tắt. Hãy tóm tắt văn bản sau thành một đoạn văn duy nhất. | |
| Yêu cầu: | |
| 1. Viết khoảng 3-5 câu, tổng hợp đầy đủ chủ đề và các ý chính. | |
| 2. Viết liền mạch, KHÔNG xuống dòng, KHÔNG dùng gạch đầu dòng hay đánh số. | |
| 3. Chỉ dựa trên thông tin được cung cấp, tuyệt đối KHÔNG tự thêm thông tin bên ngoài. | |
| 4. Trả về VĂN BẢN THUẦN (plain text), không bọc trong ``` hoặc JSON. | |
| Văn bản: | |
| \"\"\"{text}\"\"\" | |
| """ | |
| loop = asyncio.get_event_loop() | |
| MAX_RETRIES = 3 | |
| BASE_DELAY = 1.0 | |
| def call(): | |
| last_exc = None | |
| for attempt in range(1, MAX_RETRIES + 1): | |
| try: | |
| resp = gemini_client.models.generate_content( | |
| model=GEMINI_MODEL, | |
| contents=prompt, | |
| ) | |
| return (resp.text or "").strip() | |
| except Exception as e: | |
| last_exc = e | |
| is_server_error = False | |
| try: | |
| if genai_errors and isinstance(e, genai_errors.ServerError): | |
| is_server_error = True | |
| except Exception: | |
| is_server_error = False | |
| msg = str(e) | |
| if "503" in msg or "UNAVAILABLE" in msg or is_server_error: | |
| if attempt < MAX_RETRIES: | |
| delay = BASE_DELAY * (2 ** (attempt - 1)) | |
| # add jitter | |
| delay = delay + random.uniform(0, 0.5 * delay) | |
| logging.warning(f"[summary_service] model overloaded (attempt {attempt}/{MAX_RETRIES}), retrying after {delay:.2f}s") | |
| time.sleep(delay) | |
| continue | |
| # non-retryable or out of retries | |
| logging.exception(f"[summary_service] generate_summary call failed on attempt {attempt}: {e}") | |
| break | |
| # propagate last exception to outer handler | |
| if last_exc: | |
| raise last_exc | |
| return "" | |
| try: | |
| result = await loop.run_in_executor(None, call) | |
| result = result.replace("```", "").strip() | |
| if result: | |
| return result | |
| except GoogleAPIError as e: | |
| logging.error(f"[summary_service] Gemini API error: {e}") | |
| except Exception as e: | |
| logging.exception(f"[summary_service] generate_summary failed: {e}") | |
| # fallback: return a very small extracted summary (first 1-2 sentences) or empty | |
| try: | |
| sentences = re.split(r"(?<=[.!?])\s+", text.strip()) | |
| if not sentences: | |
| return "" | |
| fallback = " ".join(sentences[:2]).strip() | |
| # keep fallback reasonably short | |
| if len(fallback) > 400: | |
| fallback = fallback[:400].rsplit(" ", 1)[0] + "..." | |
| logging.info("[summary_service] Returning fallback summary after errors") | |
| return fallback | |
| except Exception: | |
| return "" | |