felixkky commited on
Commit
174dfc7
·
verified ·
1 Parent(s): 01d2cba

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +26 -20
app.py CHANGED
@@ -4,9 +4,8 @@ import base64
4
  import json
5
  from io import BytesIO
6
  from PIL import Image, ImageDraw
7
- from mistralai.client import Mistral
8
 
9
- # 在參數中加入 progress=gr.Progress()
10
  def process_document(file, api_key, progress=gr.Progress()):
11
  if not api_key:
12
  return None, "錯誤:請提供 Mistral API 金鑰。"
@@ -25,6 +24,7 @@ def process_document(file, api_key, progress=gr.Progress()):
25
  doc = fitz.open(file.name)
26
  for i in range(len(doc)):
27
  page = doc.load_page(i)
 
28
  pix = page.get_pixmap(dpi=150)
29
  img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
30
  images.append(img)
@@ -37,28 +37,35 @@ def process_document(file, api_key, progress=gr.Progress()):
37
  drawn_images = []
38
  all_json_results = []
39
 
 
40
  prompt = """
41
- 你是一個專門偵測手寫字的 AI 視覺助手請找出這張圖片中「所有學生手寫的文字」,並嚴格忽略所有印刷體。
42
- 請以 JSON 格式輸出提供文內容以及 0.0 到 1.0 相對邊界框座標 [ymin, xmin, ymax, xmax]
43
- 格式如下:
 
 
 
 
 
 
 
44
  {
45
  "handwriting": [
46
- {"text": "辨識出的手寫內容1", "box": [0.12, 0.34, 0.15, 0.55]},
47
- {"text": "辨識出的手寫內容2", "box": [0.60, 0.10, 0.65, 0.80]}
48
  ]
49
  }
50
  """
51
 
52
  for page_num, img in enumerate(images):
53
- progress(0.3, desc=f"處理第 {page_num + 1} 頁:準備圖片發送給 Mistral API...")
54
  buffered = BytesIO()
55
  img.save(buffered, format="JPEG")
56
  img_b64 = base64.b64encode(buffered.getvalue()).decode("utf-8")
57
  base64_image = f"data:image/jpeg;base64,{img_b64}"
58
 
59
  try:
60
- # 這裡是最卡的地方,所以特別提示
61
- progress(0.4, desc=f"第 {page_num + 1} 頁:正在等待 Pixtral 大模型運算與分析 (大約需要 30~60 秒,請耐心等候)...")
62
  response = client.chat.complete(
63
  model="pixtral-large-latest",
64
  messages=[
@@ -73,12 +80,15 @@ def process_document(file, api_key, progress=gr.Progress()):
73
  response_format={"type": "json_object"}
74
  )
75
 
76
- progress(0.8, desc=f"第 {page_num + 1} 頁:收到 API 回應!正在解析 JSON...")
77
  content = response.choices[0].message.content
78
- data = json.loads(content)
 
 
 
 
79
  all_json_results.append({f"Page {page_num + 1}": data})
80
 
81
- progress(0.9, desc=f"第 {page_num + 1} 頁:正在圖片上繪製紅色邊界框...")
82
  draw = ImageDraw.Draw(img)
83
  width, height = img.size
84
 
@@ -90,27 +100,23 @@ def process_document(file, api_key, progress=gr.Progress()):
90
  abs_ymin = ymin * height
91
  abs_xmax = xmax * width
92
  abs_ymax = ymax * height
 
93
  draw.rectangle([abs_xmin, abs_ymin, abs_xmax, abs_ymax], outline="red", width=3)
94
 
95
  drawn_images.append(img)
96
 
97
  except Exception as e:
98
- # 如果 API 超時,會記錄在這裡
99
- error_msg = f"API 發生錯誤: {str(e)}"
100
- print(error_msg) # 顯示在終端機
101
  all_json_results.append({f"Page {page_num + 1} Error": error_msg})
102
  drawn_images.append(img)
103
 
104
  progress(1.0, desc="處理完成!")
105
  return drawn_images, json.dumps(all_json_results, ensure_ascii=False, indent=2)
106
 
107
- # --- Gradio 介面設計 (保持不變) ---
108
- # ... 後面的程式碼不用動 ...
109
-
110
  # --- Gradio 介面設計 ---
111
  with gr.Blocks(title="手寫字偵測與畫框 Demo") as demo:
112
  gr.Markdown("## 📝 手寫字偵測與畫框 Demo (Pixtral-large-latest)")
113
- gr.Markdown("上傳考卷 PDF 或圖片,系統會找出所有的「手寫文字」並用紅框標示出來。")
114
 
115
  with gr.Row():
116
  with gr.Column():
 
4
  import json
5
  from io import BytesIO
6
  from PIL import Image, ImageDraw
7
+ from mistralai import Mistral
8
 
 
9
  def process_document(file, api_key, progress=gr.Progress()):
10
  if not api_key:
11
  return None, "錯誤:請提供 Mistral API 金鑰。"
 
24
  doc = fitz.open(file.name)
25
  for i in range(len(doc)):
26
  page = doc.load_page(i)
27
+ # 設定 DPI,保持清晰度
28
  pix = page.get_pixmap(dpi=150)
29
  img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
30
  images.append(img)
 
37
  drawn_images = []
38
  all_json_results = []
39
 
40
+ # 2. 升級版:極度嚴格的 Prompt (防幻覺、防抓印刷體)
41
  prompt = """
42
+ 你是一個專精於「中文手寫字跡辨識」的 AI 專家
43
+ 這張圖片是一份學生的考卷上面同時包含「電腦打的印刷體題目」以及「學生手寫作答字跡」
44
+ 學生的字跡混合了繁體中文與簡體中文,且字體較為潦草,通常寫在橫線上或空白處。
45
+
46
+ 你的任務是:
47
+ 1. **絕對忽略印刷體**:只尋找並提取「手寫字」。絕對不要轉錄任何電腦印刷體的題目內容!
48
+ 2. **精準辨識(拒絕幻覺)**:請盡最大努力辨識學生的手寫字(包含簡體與繁體)。如果你遇到真的看不懂的草字,請嚴格使用「[無法辨識]」四個字代替。絕對不要自己發明、猜測或聯想詞彙。
49
+ 3. **輸出邊界框**:給出該段手寫文字在圖片上的相對邊界框 [ymin, xmin, ymax, xmax](範圍 0.0 到 1.0)。
50
+
51
+ 請嚴格以 JSON 格式輸出:
52
  {
53
  "handwriting": [
54
+ {"text": "第一段手寫內容", "box": [0.12, 0.34, 0.15, 0.55]},
55
+ {"text": "第二段手寫內容", "box": [0.60, 0.10, 0.65, 0.80]}
56
  ]
57
  }
58
  """
59
 
60
  for page_num, img in enumerate(images):
61
+ progress(0.3, desc=f"處理第 {page_num + 1} 頁:準備圖片資料...")
62
  buffered = BytesIO()
63
  img.save(buffered, format="JPEG")
64
  img_b64 = base64.b64encode(buffered.getvalue()).decode("utf-8")
65
  base64_image = f"data:image/jpeg;base64,{img_b64}"
66
 
67
  try:
68
+ progress(0.4, desc=f"第 {page_num + 1} 頁:Pixtral-large-latest 運算中 (約 30~60 秒)...")
 
69
  response = client.chat.complete(
70
  model="pixtral-large-latest",
71
  messages=[
 
80
  response_format={"type": "json_object"}
81
  )
82
 
83
+ progress(0.8, desc=f"第 {page_num + 1} 頁:正在解析 JSON 並畫框...")
84
  content = response.choices[0].message.content
85
+
86
+ # 清理模型可能多加的 Markdown JSON 標記 (防錯機制)
87
+ clean_content = content.replace("```json", "").replace("```", "").strip()
88
+ data = json.loads(clean_content)
89
+
90
  all_json_results.append({f"Page {page_num + 1}": data})
91
 
 
92
  draw = ImageDraw.Draw(img)
93
  width, height = img.size
94
 
 
100
  abs_ymin = ymin * height
101
  abs_xmax = xmax * width
102
  abs_ymax = ymax * height
103
+ # 畫紅框
104
  draw.rectangle([abs_xmin, abs_ymin, abs_xmax, abs_ymax], outline="red", width=3)
105
 
106
  drawn_images.append(img)
107
 
108
  except Exception as e:
109
+ error_msg = f"API 或解析發生誤: {str(e)}"
 
 
110
  all_json_results.append({f"Page {page_num + 1} Error": error_msg})
111
  drawn_images.append(img)
112
 
113
  progress(1.0, desc="處理完成!")
114
  return drawn_images, json.dumps(all_json_results, ensure_ascii=False, indent=2)
115
 
 
 
 
116
  # --- Gradio 介面設計 ---
117
  with gr.Blocks(title="手寫字偵測與畫框 Demo") as demo:
118
  gr.Markdown("## 📝 手寫字偵測與畫框 Demo (Pixtral-large-latest)")
119
+ gr.Markdown("上傳考卷 PDF 或圖片,系統會自動排除印刷體,找出所有的「手寫文字」並用紅框標示出來。")
120
 
121
  with gr.Row():
122
  with gr.Column():