bichnhan2701 commited on
Commit
65f24bc
·
1 Parent(s): c22837f

Update logic NLP

Browse files
Files changed (1) hide show
  1. app/services/nlp_postprocess.py +69 -111
app/services/nlp_postprocess.py CHANGED
@@ -1,85 +1,31 @@
1
- from app.infra.redis_client import redis_client
2
- from app.utils.hashing import sha256
3
- from app.config.settings import GEMINI_API_KEY
4
- import google.generativeai as genai
5
  import asyncio
6
  import json
 
7
 
8
- # CACHE_TTL = 60 * 60 * 24 * 3 # 3 days
9
-
10
- # if GEMINI_API_KEY:
11
- # genai.configure(api_key=GEMINI_API_KEY)
12
- # _model = genai.GenerativeModel("gemini-pro")
13
- # else:
14
- # _model = None
15
-
16
-
17
- # async def normalize_and_extract(raw_text: str) -> dict:
18
- # """
19
- # return {
20
- # "normalized_text": "...",
21
- # "keywords": [...]
22
- # }
23
- # """
24
- # cache_key = f"nlp:{sha256(raw_text)}"
25
- # cached = redis_client.get(cache_key)
26
- # if cached:
27
- # return json.loads(cached)
28
-
29
- # prompt = f"""
30
- # Bạn là một hệ thống Xử lý Hậu kỳ NLP (NLP Post-Processing) Tiếng Việt.
31
-
32
- # Đầu vào là văn bản thô (raw transcript), có thể thiếu dấu câu và sai chính tả do nhận dạng giọng nói (ví dụ: 'ăn chứa' -> 'ăn chưa').
33
-
34
- # Nhiệm vụ (Trả về JSON duy nhất):
35
- # 1. [ASR Correction & Punctuation]: Sửa lỗi chính tả ASR, thêm dấu câu, viết hoa chuẩn xác.
36
-
37
- # Văn bản đầu vào: \"\"\"{raw_text}\"\"\"
38
-
39
- # Cấu trúc JSON bắt buộc:
40
- # {{
41
- # "normalizedText": "Văn bản đã sửa hoàn chỉnh...",
42
- # "keywords": ["Từ khóa 1", "Từ khóa 2", "..."]
43
- # }}
44
- # """
45
-
46
- # result = {
47
- # "normalized_text": raw_text,
48
- # "keywords": []
49
- # }
50
-
51
- # if _model:
52
- # loop = asyncio.get_event_loop()
53
-
54
- # def call():
55
- # r = _model.generate_content(prompt)
56
- # return r.text
57
-
58
- # text = await loop.run_in_executor(None, call)
59
-
60
- # # clean JSON
61
- # start = text.find("{")
62
- # end = text.rfind("}")
63
- # if start != -1 and end != -1:
64
- # data = json.loads(text[start:end+1])
65
- # result = {
66
- # "normalized_text": data.get("normalizedText", raw_text),
67
- # "keywords": data.get("keywords", [])
68
- # }
69
-
70
- # redis_client.setex(cache_key, CACHE_TTL, json.dumps(result))
71
- # return result
72
 
73
- import logging
74
- import redis # để bắt lỗi ConnectionError nếu cần
 
75
 
76
  CACHE_TTL = 60 * 60 * 24 * 3 # 3 days
77
 
 
 
 
 
78
  if GEMINI_API_KEY:
79
- genai.configure(api_key=GEMINI_API_KEY)
80
- _model = genai.GenerativeModel("gemini-pro")
 
 
 
 
81
  else:
82
- _model = None
 
83
 
84
  async def normalize_and_extract(raw_text: str) -> dict:
85
  """
@@ -90,65 +36,77 @@ async def normalize_and_extract(raw_text: str) -> dict:
90
  """
91
  cache_key = f"nlp:{sha256(raw_text)}"
92
 
93
- # 1) Thử đọc cache từ Redis, nhưng không để lỗi Redis làm vỡ pipeline
94
  try:
95
  cached = redis_client.get(cache_key)
96
  if cached:
97
  return json.loads(cached)
98
  except Exception as e:
99
- logging.warning(f"Redis GET failed in normalize_and_extract, skip cache: {e}")
100
 
 
 
 
 
 
101
 
102
- prompt = f"""
 
 
103
  Bạn là một hệ thống Xử lý Hậu kỳ NLP (NLP Post-Processing) Tiếng Việt.
104
-
105
- Đầu vào là văn bản thô (raw transcript), có thể thiếu dấu câu và sai chính tả do nhận dạng giọng nói (ví dụ: 'ăn chứa' -> 'ăn chưa').
106
 
107
  Nhiệm vụ (Trả về JSON duy nhất):
108
- 1. [ASR Correction & Punctuation]: Sửa lỗi chính tả ASR, thêm dấu câu, viết hoa chuẩn xác, loại bỏ các từ bị lỗi lặp lại.
 
109
 
110
- Văn bản đầu vào: \"\"\"{raw_text}\"\"\"
 
111
 
112
- Cấu trúc JSON bắt buộc:
113
  {{
114
- "normalizedText": "Văn bản đã sửa hoàn chỉnh...",
115
- "keywords": ["Từ khóa 1", "Từ khóa 2", "..."]
116
  }}
117
  """
118
 
119
- # 2) Giá trị mặc định nếu không có model
120
- result = {
121
- "normalized_text": raw_text,
122
- "keywords": []
123
- }
124
-
125
- # 3) Gọi Gemini nếu có cấu hình
126
- if _model:
127
  loop = asyncio.get_event_loop()
128
 
129
  def call():
130
- r = _model.generate_content(prompt)
131
- return r.text
132
-
133
- text = await loop.run_in_executor(None, call)
134
-
135
- # clean JSON
136
- start = text.find("{")
137
- end = text.rfind("}")
138
- if start != -1 and end != -1:
139
- try:
140
- data = json.loads(text[start:end + 1])
141
- result = {
142
- "normalized_text": data.get("normalizedText", raw_text),
143
- "keywords": data.get("keywords", []),
144
- }
145
- except Exception as e:
146
- logging.warning(f"Failed to parse Gemini JSON, fallback to raw_text: {e}")
147
-
148
- # 4) Thử ghi cache lại, cũng không để lỗi Redis làm vỡ pipeline
 
 
 
 
 
 
 
 
 
 
 
 
149
  try:
150
  redis_client.setex(cache_key, CACHE_TTL, json.dumps(result))
151
  except Exception as e:
152
- logging.warning(f"Redis SETEX failed in normalize_and_extract, skip cache: {e}")
153
 
154
  return result
 
 
 
 
 
1
  import asyncio
2
  import json
3
+ import logging
4
 
5
+ from app.infra.redis_client import redis_client
6
+ from app.utils.hashing import sha256
7
+ from app.config.settings import GEMINI_API_KEY
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
+ # New official client
10
+ import google.genai as genai
11
+ from google.api_core.exceptions import GoogleAPIError # optional but useful
12
 
13
  CACHE_TTL = 60 * 60 * 24 * 3 # 3 days
14
 
15
+ # Tạo client Gemini nếu có API key
16
+ _gemini_client = None
17
+ _GEMINI_MODEL = "gemini-1.5-flash" # hoặc "gemini-1.5-flash-latest"
18
+
19
  if GEMINI_API_KEY:
20
+ try:
21
+ _gemini_client = genai.Client(api_key=GEMINI_API_KEY)
22
+ logging.info(f"[nlp_postprocess] Initialized google.genai client with model={_GEMINI_MODEL}")
23
+ except Exception as e:
24
+ logging.exception(f"[nlp_postprocess] Failed to init google.genai client: {e}")
25
+ _gemini_client = None
26
  else:
27
+ logging.warning("[nlp_postprocess] GEMINI_API_KEY is not set, using raw_text as normalization fallback")
28
+
29
 
30
  async def normalize_and_extract(raw_text: str) -> dict:
31
  """
 
36
  """
37
  cache_key = f"nlp:{sha256(raw_text)}"
38
 
39
+ # 1) Try get from Redis cache (best effort)
40
  try:
41
  cached = redis_client.get(cache_key)
42
  if cached:
43
  return json.loads(cached)
44
  except Exception as e:
45
+ logging.warning(f"[nlp_postprocess] Redis GET failed, skip cache: {e}")
46
 
47
+ # 2) Default fallback result (if no model or error)
48
+ result = {
49
+ "normalized_text": raw_text,
50
+ "keywords": [],
51
+ }
52
 
53
+ # 3) Call Gemini if available
54
+ if _gemini_client:
55
+ prompt = f"""
56
  Bạn là một hệ thống Xử lý Hậu kỳ NLP (NLP Post-Processing) Tiếng Việt.
57
+ Đầu vào là văn bản thô (raw transcript), có thể thiếu dấu câu và sai chính tả do nhận dạng giọng nói.
 
58
 
59
  Nhiệm vụ (Trả về JSON duy nhất):
60
+ 1. Sửa lỗi chính tả ASR, thêm dấu câu, viết hoa chuẩn xác, loại bỏ các từ bị lặp lại vô nghĩa.
61
+ 2. Trích xuất danh sách từ khóa quan trọng (keywords) liên quan đến chủ đề, độ dài từ 1-4 từ.
62
 
63
+ Văn bản đ��u vào:
64
+ \"\"\"{raw_text}\"\"\"
65
 
66
+ Cấu trúc JSON bắt buộc (chỉ trả JSON, không giải thích thêm):
67
  {{
68
+ "normalizedText": "Văn bản đã sửa hoàn chỉnh...",
69
+ "keywords": ["Từ khóa 1", "Từ khóa 2", "..."]
70
  }}
71
  """
72
 
 
 
 
 
 
 
 
 
73
  loop = asyncio.get_event_loop()
74
 
75
  def call():
76
+ # Nếu lỗi từ API, để try/except bên ngoài handle
77
+ resp = _gemini_client.models.generate_content(
78
+ model=_GEMINI_MODEL,
79
+ contents=prompt,
80
+ )
81
+ # resp.text là chuỗi model trả (có thể chứa code block)
82
+ return resp.text
83
+
84
+ try:
85
+ text = await loop.run_in_executor(None, call)
86
+ if text:
87
+ # clean JSON
88
+ start = text.find("{")
89
+ end = text.rfind("}")
90
+ if start != -1 and end != -1:
91
+ try:
92
+ data = json.loads(text[start:end + 1])
93
+ result = {
94
+ "normalized_text": data.get("normalizedText", raw_text),
95
+ "keywords": data.get("keywords", []) or [],
96
+ }
97
+ except Exception as e:
98
+ logging.warning(f"[nlp_postprocess] Failed to parse Gemini JSON, fallback to raw_text: {e}")
99
+ else:
100
+ logging.warning("[nlp_postprocess] Gemini response has no JSON block, fallback to raw_text")
101
+ except GoogleAPIError as e:
102
+ logging.error(f"[nlp_postprocess] Gemini API error: {e}")
103
+ except Exception as e:
104
+ logging.exception(f"[nlp_postprocess] Gemini call failed, fallback to raw_text: {e}")
105
+
106
+ # 4) Try write back to Redis (best effort)
107
  try:
108
  redis_client.setex(cache_key, CACHE_TTL, json.dumps(result))
109
  except Exception as e:
110
+ logging.warning(f"[nlp_postprocess] Redis SETEX failed, skip cache: {e}")
111
 
112
  return result