bichnhan2701 commited on
Commit
2432a11
·
1 Parent(s): 54bf491

fix error 503

Browse files
app/services/mindmap_service.py CHANGED
@@ -1,33 +1,47 @@
1
- # app/services/mindmap_service.py
2
  import asyncio
3
  import json
4
  import logging
 
 
 
5
 
6
- from app.config import GEMINI_API_KEY, GEMINI_MODEL
7
 
8
- import google.genai as genai
9
- from google.api_core.exceptions import GoogleAPIError
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
- _MINDMAP_MODEL = GEMINI_MODEL
12
  _gemini_client = None
13
 
14
- if not GEMINI_API_KEY:
15
- logging.warning("[mindmap_service] GEMINI_API_KEY is not set; mindmap generation disabled")
16
- elif not _MINDMAP_MODEL:
17
- logging.warning("[mindmap_service] GEMINI_MODEL is not set; mindmap generation disabled")
18
  else:
19
  try:
20
  _gemini_client = genai.Client(api_key=GEMINI_API_KEY)
21
- logging.info(f"[mindmap_service] Initialized google.genai client; model={_MINDMAP_MODEL}")
22
  except Exception as e:
23
  logging.exception(f"[mindmap_service] Failed to init google.genai client: {e}")
24
  _gemini_client = None
25
 
26
 
27
  async def generate_mindmap(text: str) -> dict:
28
- """
29
- Sinh cấu trúc mindmap JSON từ văn bản.
30
- Fallback: trả {} nếu không có model hoặc lỗi.
31
  """
32
  if not _gemini_client:
33
  return {}
@@ -58,19 +72,47 @@ Cấu trúc JSON bắt buộc:
58
  ]
59
  }}
60
  }}
61
-
62
  Văn bản:
63
  \"\"\"{text}\"\"\"
64
  """
65
 
66
  loop = asyncio.get_event_loop()
67
 
 
 
 
68
  def call():
69
- resp = _gemini_client.models.generate_content(
70
- model=_MINDMAP_MODEL,
71
- contents=prompt,
72
- )
73
- return resp.text or ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
 
75
  try:
76
  raw = await loop.run_in_executor(None, call)
@@ -88,4 +130,34 @@ Văn bản:
88
  except Exception as e:
89
  logging.exception(f"[mindmap_service] generate_mindmap failed: {e}")
90
 
91
- return {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import asyncio
2
  import json
3
  import logging
4
+ import random
5
+ import re
6
+ import time
7
 
8
+ from app.config import GEMINI_API_KEY
9
 
10
+ try:
11
+ import google.genai as genai
12
+ try:
13
+ from google.genai import errors as genai_errors
14
+ except Exception:
15
+ genai_errors = None
16
+ except Exception:
17
+ genai = None
18
+ genai_errors = None
19
+ logging.warning("[mindmap_service] google.genai module not found; mindmap generation disabled")
20
+
21
+ try:
22
+ from google.api_core.exceptions import GoogleAPIError
23
+ except Exception:
24
+ GoogleAPIError = Exception
25
 
26
+ _MINDMAP_MODEL = "gemini-2.5-flash"
27
  _gemini_client = None
28
 
29
+ if not genai:
30
+ logging.warning("[mindmap_service] google.genai not available, mindmap generation will be disabled")
31
+ elif not GEMINI_API_KEY:
32
+ logging.warning("[mindmap_service] GEMINI_API_KEY is not set, mindmap generation will be disabled")
33
  else:
34
  try:
35
  _gemini_client = genai.Client(api_key=GEMINI_API_KEY)
36
+ logging.info(f"[mindmap_service] Initialized google.genai client with model={_MINDMAP_MODEL}")
37
  except Exception as e:
38
  logging.exception(f"[mindmap_service] Failed to init google.genai client: {e}")
39
  _gemini_client = None
40
 
41
 
42
  async def generate_mindmap(text: str) -> dict:
43
+ """Sinh cấu trúc mindmap JSON từ văn bản.
44
+ Fallback: trả {{}} nếu không model hoặc lỗi.
 
45
  """
46
  if not _gemini_client:
47
  return {}
 
72
  ]
73
  }}
74
  }}
 
75
  Văn bản:
76
  \"\"\"{text}\"\"\"
77
  """
78
 
79
  loop = asyncio.get_event_loop()
80
 
81
+ MAX_RETRIES = 3
82
+ BASE_DELAY = 1.0
83
+
84
  def call():
85
+ last_exc = None
86
+ for attempt in range(1, MAX_RETRIES + 1):
87
+ try:
88
+ resp = _gemini_client.models.generate_content(
89
+ model=_MINDMAP_MODEL,
90
+ contents=prompt,
91
+ )
92
+ return resp.text or ""
93
+ except Exception as e:
94
+ last_exc = e
95
+ is_server_error = False
96
+ try:
97
+ if genai_errors and isinstance(e, genai_errors.ServerError):
98
+ is_server_error = True
99
+ except Exception:
100
+ is_server_error = False
101
+
102
+ msg = str(e)
103
+ if "503" in msg or "UNAVAILABLE" in msg or is_server_error:
104
+ if attempt < MAX_RETRIES:
105
+ delay = BASE_DELAY * (2 ** (attempt - 1))
106
+ delay = delay + random.uniform(0, 0.5 * delay)
107
+ logging.warning(f"[mindmap_service] model overloaded (attempt {attempt}/{MAX_RETRIES}), retrying after {delay:.2f}s")
108
+ time.sleep(delay)
109
+ continue
110
+ logging.exception(f"[mindmap_service] generate_mindmap call failed on attempt {attempt}: {e}")
111
+ break
112
+
113
+ if last_exc:
114
+ raise last_exc
115
+ return ""
116
 
117
  try:
118
  raw = await loop.run_in_executor(None, call)
 
130
  except Exception as e:
131
  logging.exception(f"[mindmap_service] generate_mindmap failed: {e}")
132
 
133
+ # fallback: build a minimal mindmap from the text (best-effort)
134
+ try:
135
+ # use first sentence as root label (shortened)
136
+ sentences = re.split(r"(?<=[.!?])\s+", text.strip())
137
+ root_label = sentences[0] if sentences else "Topic"
138
+ # shorten to ~8 words
139
+ root_label = " ".join(root_label.split()[:8]).strip()
140
+
141
+ children = []
142
+ # take up to 3 next sentences as child labels
143
+ for s in sentences[1:4]:
144
+ label = " ".join(s.split()[:6]).strip()
145
+ if label:
146
+ children.append({
147
+ "label": label,
148
+ "colorHex": "#F59E2B",
149
+ "children": []
150
+ })
151
+
152
+ fallback = {
153
+ "root": {
154
+ "label": root_label or "Topic",
155
+ "colorHex": "#6200EE",
156
+ "children": children,
157
+ }
158
+ }
159
+ logging.info("[mindmap_service] Returning fallback mindmap after errors")
160
+ return fallback
161
+ except Exception:
162
+ return {}
163
+
app/services/summary_service.py CHANGED
@@ -1,37 +1,45 @@
1
  import asyncio
2
  import logging
 
 
 
3
 
4
- from app.config import GEMINI_API_KEY, GEMINI_MODEL
5
 
6
  try:
7
  import google.genai as genai
 
 
 
 
8
  except Exception:
9
  genai = None
 
10
  logging.warning("[summary_service] google.genai module not found; summaries disabled")
11
 
12
- from google.api_core.exceptions import GoogleAPIError
 
 
 
13
 
14
- _SUMMARY_MODEL = GEMINI_MODEL
15
  _gemini_client = None
16
 
17
  if not genai:
18
- logging.warning("[summary_service] google.genai not available; summaries disabled")
19
  elif not GEMINI_API_KEY:
20
- logging.warning("[summary_service] GEMINI_API_KEY is not set; summaries disabled")
21
- elif not _SUMMARY_MODEL:
22
- logging.warning("[summary_service] GEMINI_MODEL is not set; summaries disabled")
23
  else:
24
  try:
25
  _gemini_client = genai.Client(api_key=GEMINI_API_KEY)
26
- logging.info(f"[summary_service] Initialized google.genai client; model={_SUMMARY_MODEL}")
27
  except Exception as e:
28
  logging.exception(f"[summary_service] Failed to init google.genai client: {e}")
29
  _gemini_client = None
30
 
31
 
32
  async def generate_summary(text: str) -> str:
33
- """
34
- Tạo tóm tắt ngắn gọn 3-5 câu, một đoạn văn duy nhất.
35
  Fallback: trả "" nếu không có model hoặc lỗi.
36
  """
37
  if not _gemini_client:
@@ -52,20 +60,65 @@ Văn bản:
52
 
53
  loop = asyncio.get_event_loop()
54
 
 
 
 
55
  def call():
56
- resp = _gemini_client.models.generate_content(
57
- model=_SUMMARY_MODEL,
58
- contents=prompt,
59
- )
60
- return (resp.text or "").strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
  try:
63
  result = await loop.run_in_executor(None, call)
64
- # clean backticks nếu model có lỡ bọc
65
- return result.replace("```", "").strip()
 
66
  except GoogleAPIError as e:
67
  logging.error(f"[summary_service] Gemini API error: {e}")
68
  except Exception as e:
69
  logging.exception(f"[summary_service] generate_summary failed: {e}")
70
 
71
- return ""
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import asyncio
2
  import logging
3
+ import random
4
+ import re
5
+ import time
6
 
7
+ from app.config import GEMINI_API_KEY
8
 
9
  try:
10
  import google.genai as genai
11
+ try:
12
+ from google.genai import errors as genai_errors
13
+ except Exception:
14
+ genai_errors = None
15
  except Exception:
16
  genai = None
17
+ genai_errors = None
18
  logging.warning("[summary_service] google.genai module not found; summaries disabled")
19
 
20
+ try:
21
+ from google.api_core.exceptions import GoogleAPIError
22
+ except Exception:
23
+ GoogleAPIError = Exception
24
 
25
+ _SUMMARY_MODEL = "gemini-2.5-flash"
26
  _gemini_client = None
27
 
28
  if not genai:
29
+ logging.warning("[summary_service] google.genai not available, summary will be empty")
30
  elif not GEMINI_API_KEY:
31
+ logging.warning("[summary_service] GEMINI_API_KEY is not set, summary will be empty")
 
 
32
  else:
33
  try:
34
  _gemini_client = genai.Client(api_key=GEMINI_API_KEY)
35
+ logging.info(f"[summary_service] Initialized google.genai client with model={_SUMMARY_MODEL}")
36
  except Exception as e:
37
  logging.exception(f"[summary_service] Failed to init google.genai client: {e}")
38
  _gemini_client = None
39
 
40
 
41
  async def generate_summary(text: str) -> str:
42
+ """Tạo tóm tắt ngắn gọn 3-5 câu, một đoạn văn duy nhất.
 
43
  Fallback: trả "" nếu không có model hoặc lỗi.
44
  """
45
  if not _gemini_client:
 
60
 
61
  loop = asyncio.get_event_loop()
62
 
63
+ MAX_RETRIES = 3
64
+ BASE_DELAY = 1.0
65
+
66
  def call():
67
+ last_exc = None
68
+ for attempt in range(1, MAX_RETRIES + 1):
69
+ try:
70
+ resp = _gemini_client.models.generate_content(
71
+ model=_SUMMARY_MODEL,
72
+ contents=prompt,
73
+ )
74
+ return (resp.text or "").strip()
75
+ except Exception as e:
76
+ last_exc = e
77
+ is_server_error = False
78
+ try:
79
+ if genai_errors and isinstance(e, genai_errors.ServerError):
80
+ is_server_error = True
81
+ except Exception:
82
+ is_server_error = False
83
+
84
+ msg = str(e)
85
+ if "503" in msg or "UNAVAILABLE" in msg or is_server_error:
86
+ if attempt < MAX_RETRIES:
87
+ delay = BASE_DELAY * (2 ** (attempt - 1))
88
+ # add jitter
89
+ delay = delay + random.uniform(0, 0.5 * delay)
90
+ logging.warning(f"[summary_service] model overloaded (attempt {attempt}/{MAX_RETRIES}), retrying after {delay:.2f}s")
91
+ time.sleep(delay)
92
+ continue
93
+ # non-retryable or out of retries
94
+ logging.exception(f"[summary_service] generate_summary call failed on attempt {attempt}: {e}")
95
+ break
96
+
97
+ # propagate last exception to outer handler
98
+ if last_exc:
99
+ raise last_exc
100
+ return ""
101
 
102
  try:
103
  result = await loop.run_in_executor(None, call)
104
+ result = result.replace("```", "").strip()
105
+ if result:
106
+ return result
107
  except GoogleAPIError as e:
108
  logging.error(f"[summary_service] Gemini API error: {e}")
109
  except Exception as e:
110
  logging.exception(f"[summary_service] generate_summary failed: {e}")
111
 
112
+ # fallback: return a very small extracted summary (first 1-2 sentences) or empty
113
+ try:
114
+ sentences = re.split(r"(?<=[.!?])\s+", text.strip())
115
+ if not sentences:
116
+ return ""
117
+ fallback = " ".join(sentences[:2]).strip()
118
+ # keep fallback reasonably short
119
+ if len(fallback) > 400:
120
+ fallback = fallback[:400].rsplit(" ", 1)[0] + "..."
121
+ logging.info("[summary_service] Returning fallback summary after errors")
122
+ return fallback
123
+ except Exception:
124
+ return ""