howard9963 commited on
Commit
95daccd
·
verified ·
1 Parent(s): 03dc522

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -20
app.py CHANGED
@@ -119,6 +119,70 @@ def _ensure_local_model(logs: Optional[List[str]] = None) -> None:
119
  logs.append(f"[LOCAL LLM][ERROR] load failed: {e}")
120
  print(f"[LLM][ERROR] load failed: {e}")
121
  raise
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
  def call_llm(messages: List[dict], model: str, logs: List[str]) -> dict:
124
  """
@@ -152,29 +216,26 @@ def call_llm(messages: List[dict], model: str, logs: List[str]) -> dict:
152
  pad_token_id=_hf_tok.eos_token_id
153
  )
154
  print("torch.no_grad")
155
- full = _hf_tok.decode(out_ids[0], skip_special_tokens=True)
156
- gen = full[len(prompt):] if full.startswith(prompt) else full
157
- print("gen")
158
- logs.append(f"[LOCAL LLM] Gen chars={len(gen)}")
159
- print("****gen begin***")
160
- print(gen)
161
- print("****gen end***")
162
- logs.append("****gen begin***")
163
- logs.append(gen)
164
- logs.append("****gen end***")
165
- # 嘗試解析 JSON
166
  try:
167
- data = json.loads(gen)
168
- logs.append("[LOCAL LLM] JSON parsed.")
169
  return data
170
  except Exception as jerr:
171
- logs.append(f"[LOCAL LLM] JSON parse failed: {jerr}; trying regex.")
172
- m = re.search(r"\{.*\}", gen, flags=re.DOTALL)
173
- if not m:
174
- raise ValueError("模型回傳非 JSON,且未擷取到 JSON 區塊")
175
- data = json.loads(m.group(0))
176
- logs.append("[LOCAL LLM] Extracted JSON by regex.")
177
- return data
 
178
  except Exception as e:
179
  logs.append(f"[LOCAL LLM][ERROR] {e}")
180
  return {
 
119
  logs.append(f"[LOCAL LLM][ERROR] load failed: {e}")
120
  print(f"[LLM][ERROR] load failed: {e}")
121
  raise
122
+ # ---------- Robust JSON parsing helpers ----------
123
+ def _strip_code_fences(s: str) -> str:
124
+ s = s.strip()
125
+ if s.startswith("```"):
126
+ s = s[3:]
127
+ if "```" in s:
128
+ s = s.split("```", 1)[0]
129
+ s = s.replace("```json", "").replace("```JSON", "").strip("` \n\r\t")
130
+ return s
131
+
132
+ def _extract_first_brace_block(s: str) -> str:
133
+ start = s.find("{")
134
+ if start == -1:
135
+ return s
136
+ depth = 0
137
+ for i in range(start, len(s)):
138
+ if s[i] == "{":
139
+ depth += 1
140
+ elif s[i] == "}":
141
+ depth -= 1
142
+ if depth == 0:
143
+ return s[start:i+1]
144
+ return s
145
+
146
+ def safe_parse_json(text: str) -> dict:
147
+ """
148
+ 先嚴格 json.loads;失敗則:
149
+ 1) 去掉 code fences/markdown
150
+ 2) 擷取第一個平衡的 {...}
151
+ 3) 嘗試 json5(允許單引號、尾逗號)
152
+ 4) 修補全形/花式引號與 BOM;必要時把整體單引號轉雙引號
153
+ """
154
+ import json as _json
155
+
156
+ # 直接試一次
157
+ try:
158
+ return _json.loads(text)
159
+ except Exception:
160
+ pass
161
+
162
+ s = _strip_code_fences(text)
163
+ s = _extract_first_brace_block(s)
164
+
165
+ try:
166
+ return _json.loads(s)
167
+ except Exception:
168
+ pass
169
+
170
+ # 可選:json5(若未安裝會直接跳過)
171
+ try:
172
+ import json5 # type: ignore
173
+ return json5.loads(s)
174
+ except Exception:
175
+ pass
176
+
177
+ # 修補引號與 BOM
178
+ repaired = (
179
+ s.replace("\u201c", '"').replace("\u201d", '"')
180
+ .replace("\u2018", "'").replace("\u2019", "'")
181
+ .replace("\ufeff", "").strip()
182
+ )
183
+ if "'" in repaired and '"' not in repaired:
184
+ repaired = repaired.replace("'", '"')
185
+ return _json.loads(repaired)
186
 
187
  def call_llm(messages: List[dict], model: str, logs: List[str]) -> dict:
188
  """
 
216
  pad_token_id=_hf_tok.eos_token_id
217
  )
218
  print("torch.no_grad")
219
+ # 解碼生成內容後
220
+ full_text = _hf_tok.decode(output_ids[0], skip_special_tokens=True)
221
+ gen_text = full_text[len(prompt):] if full_text.startswith(prompt) else full_text
222
+ logs.append(f"[LOCAL LLM] raw_len={len(gen_text)}")
223
+ logs.append(f"[LOCAL LLM] raw_head={gen_text[:200].replace(chr(10),' ')}") # 前 200 字方便 Debug
224
+
225
+ # ★ 強韌解析:剝掉前置描述,只取第一個 {...}
 
 
 
 
226
  try:
227
+ data = safe_parse_json(gen_text)
228
+ logs.append("[LOCAL LLM] JSON 解析成功")
229
  return data
230
  except Exception as jerr:
231
+ logs.append(f"[LOCAL LLM] JSON 解析失敗:{jerr}")
232
+ # 回傳結構化錯誤,避免整個流程中斷
233
+ return {
234
+ "符合情況": "部分符合",
235
+ "原因": [f"模型輸出非合法 JSON:{str(jerr)}"],
236
+ "改進建議": ["請調整提示詞,要求嚴格輸出 JSON(雙引號、無註解、無多餘文字)。"],
237
+ "規則逐點檢核": []
238
+ }
239
  except Exception as e:
240
  logs.append(f"[LOCAL LLM][ERROR] {e}")
241
  return {