Spaces:
Running
Running
File size: 5,972 Bytes
7402e0f de4b4f0 7402e0f de4b4f0 7402e0f 0e732c5 7402e0f 0e732c5 7402e0f 0e732c5 7402e0f 0e732c5 7402e0f 0e732c5 7402e0f 0e732c5 7402e0f 0e732c5 7402e0f |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
import asyncio
import os
import logging
import json
import re
import time
import random
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("[normalize_service] google.genai module not found; normalization disabled")
try:
from google.api_core.exceptions import GoogleAPIError
except Exception:
GoogleAPIError = Exception
gemini_client = None
if not genai:
logging.warning("[normalize_service] google.genai not available, normalization will be disabled")
elif not GEMINI_API_KEY:
logging.warning("[normalize_service] GEMINI_API_KEY is not set, normalization will be disabled")
else:
try:
gemini_client = genai.Client(api_key=GEMINI_API_KEY)
logging.info(f"[normalize_service] Initialized google.genai client with model={GEMINI_MODEL}")
except Exception as e:
logging.exception(f"[normalize_service] Failed to init google.genai client: {e}")
gemini_client = None
async def normalize_text(raw_text: str) -> str:
if not raw_text:
return raw_text
prompt = f"""
Bạn là một hệ thống Xử lý Hậu kỳ NLP (NLP Post-Processing) Tiếng Việt.
Đầu vào là văn bản thô (raw transcript), có thể thiếu dấu câu, sai chính tả, Lặp từ, lặp cụm từ, hoặc lặp cả đoạn do lỗi nhận dạng giọng nói.
Nhiệm vụ:
- Sửa lỗi chính tả do ASR.
- Thêm dấu câu phù hợp.
- Viết hoa đúng chuẩn tiếng Việt (đầu câu, tên riêng nếu suy luận được).
- Loại bỏ hoàn toàn các phần bị lặp (từ, cụm từ, câu hoặc đoạn), chỉ giữ MỘT phiên bản hợp lý.
- Giữ nguyên nội dung và ý nghĩa gốc, không rút gọn, không thêm thông tin mới.
YÊU CẦU ĐẦU RA:
- Chỉ trả về văn bản đã chuẩn hóa
- KHÔNG JSON, KHÔNG giải thích, KHÔNG markdown, KHÔNG bọc trong ``` hoặc bất kỳ ký tự đặc biệt nào, chỉ trả về plain text thuần túy.
Văn bản đầu vào:
\"\"\"{raw_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:
if gemini_client:
resp = gemini_client.models.generate_content(
model=GEMINI_MODEL,
contents=prompt,
)
return resp.text or ""
else:
model = genai.GenerativeModel(GEMINI_MODEL) if genai else None
if model:
resp = model.generate_content(prompt)
return getattr(resp, "text", "") or ""
return ""
except Exception as e:
last_exc = e
msg = str(e)
if "503" in msg or "UNAVAILABLE" in msg:
if attempt < MAX_RETRIES:
delay = BASE_DELAY * (2 ** (attempt - 1))
delay += random.uniform(0, 0.5 * delay)
logging.warning(
f"[normalize_service] model overloaded "
f"(attempt {attempt}/{MAX_RETRIES}), retrying after {delay:.2f}s"
)
time.sleep(delay)
continue
logging.exception(
f"[normalize_service] normalize call failed on attempt {attempt}: {e}"
)
break
if last_exc:
raise last_exc
return ""
try:
raw = await loop.run_in_executor(None, call)
def is_valid_normalized(text: str, raw: str) -> bool:
if not text:
return False
if len(text) < 50:
return False
if text.strip() in {".", "…"}:
return False
# không quá ngắn so với raw
if len(text) < 0.3 * len(raw):
return False
return True
if raw:
text = raw.strip()
# remove markdown
text = re.sub(r"^```.*?\n", "", text, flags=re.DOTALL)
text = re.sub(r"```$", "", text)
# remove meta-text Gemini
text = re.sub(
r"^the corrected text.*?is as follows:\s*",
"",
text,
flags=re.IGNORECASE | re.DOTALL,
)
text = text.strip('"').strip("'").strip()
if is_valid_normalized(text, raw_text):
return text
logging.warning(
"[normalize_service] Gemini returned invalid normalized text, falling back"
)
except GoogleAPIError as e:
logging.error(f"[normalize_service] Gemini API error: {e}")
except Exception as e:
logging.exception(f"[normalize_service] normalize_text failed: {e}")
# ===== fallback: best-effort local normalization =====
try:
text = raw_text.strip()
text = re.sub(r"\s+", " ", text)
if not text or len(text) < 50:
return raw_text.strip()
if text[-1] not in ".!?":
text += "."
def cap_sentences(s: str) -> str:
parts = re.split(r'([.!?]\s+)', s)
out = ""
for i in range(0, len(parts), 2):
sentence = parts[i].strip()
sep = parts[i + 1] if i + 1 < len(parts) else ""
if sentence:
sentence = sentence[0].upper() + sentence[1:]
out += sentence + sep
return out
return cap_sentences(text)
except Exception:
return raw_text
|