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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +17 -14
app.py CHANGED
@@ -6,23 +6,25 @@ from io import BytesIO
6
  from PIL import Image, ImageDraw
7
  from mistralai.client import Mistral
8
 
9
- def process_document(file, api_key):
 
10
  if not api_key:
11
  return None, "錯誤:請提供 Mistral API 金鑰。"
12
  if not file:
13
  return None, "錯誤:請上傳檔案。"
14
 
 
15
  client = Mistral(api_key=api_key)
16
  images = []
17
 
18
- # 1. 處理檔案上傳 (支援 PDF 或 圖片)
19
  file_name = file.name.lower()
20
  try:
 
21
  if file_name.endswith('.pdf'):
22
  doc = fitz.open(file.name)
23
  for i in range(len(doc)):
24
  page = doc.load_page(i)
25
- # 設定 DPI 為 150,確保圖片夠清晰但不會太大導致 API 超時
26
  pix = page.get_pixmap(dpi=150)
27
  img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
28
  images.append(img)
@@ -35,7 +37,6 @@ def process_document(file, api_key):
35
  drawn_images = []
36
  all_json_results = []
37
 
38
- # 2. 針對「尋找手寫字」設計極簡 Prompt (防止模型收檔)
39
  prompt = """
40
  你是一個專門偵測手寫字體的 AI 視覺助手。請找出這張圖片中「所有學生手寫的文字」,並嚴格忽略所有印刷體。
41
  請以 JSON 格式輸出,提供文字內容以及 0.0 到 1.0 的相對邊界框座標 [ymin, xmin, ymax, xmax]。
@@ -48,16 +49,16 @@ def process_document(file, api_key):
48
  }
49
  """
50
 
51
- # 3. 逐頁處理
52
  for page_num, img in enumerate(images):
53
- # 轉換為 Base64
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
- # 呼叫 Pixtral 視覺模型
 
61
  response = client.chat.complete(
62
  model="pixtral-large-latest",
63
  messages=[
@@ -72,12 +73,12 @@ def process_document(file, api_key):
72
  response_format={"type": "json_object"}
73
  )
74
 
75
- # 解析 JSON 輸出
76
  content = response.choices[0].message.content
77
  data = json.loads(content)
78
  all_json_results.append({f"Page {page_num + 1}": data})
79
 
80
- # 4. 在圖片上紅色邊界框
81
  draw = ImageDraw.Draw(img)
82
  width, height = img.size
83
 
@@ -85,24 +86,26 @@ def process_document(file, api_key):
85
  box = item.get("box")
86
  if box and len(box) == 4:
87
  ymin, xmin, ymax, xmax = box
88
-
89
- # 將 0.0 ~ 1.0 的相對座標轉換為圖片的實際像素
90
  abs_xmin = xmin * width
91
  abs_ymin = ymin * height
92
  abs_xmax = xmax * width
93
  abs_ymax = ymax * height
94
-
95
- # 畫紅框 (線條寬度 3)
96
  draw.rectangle([abs_xmin, abs_ymin, abs_xmax, abs_ymax], outline="red", width=3)
97
 
98
  drawn_images.append(img)
99
 
100
  except Exception as e:
101
- all_json_results.append({f"Page {page_num + 1} Error": str(e)})
 
 
 
102
  drawn_images.append(img)
103
 
 
104
  return drawn_images, json.dumps(all_json_results, ensure_ascii=False, indent=2)
105
 
 
 
106
 
107
  # --- Gradio 介面設計 ---
108
  with gr.Blocks(title="手寫字偵測與畫框 Demo") as demo:
 
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 金鑰。"
13
  if not file:
14
  return None, "錯誤:請上傳檔案。"
15
 
16
+ progress(0.05, desc="正在初始化 Mistral 客戶端...")
17
  client = Mistral(api_key=api_key)
18
  images = []
19
 
20
+ # 1. 處理檔案上傳
21
  file_name = file.name.lower()
22
  try:
23
+ progress(0.1, desc="正在讀取與轉換圖片...")
24
  if file_name.endswith('.pdf'):
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
  drawn_images = []
38
  all_json_results = []
39
 
 
40
  prompt = """
41
  你是一個專門偵測手寫字體的 AI 視覺助手。請找出這張圖片中「所有學生手寫的文字」,並嚴格忽略所有印刷體。
42
  請以 JSON 格式輸出,提供文字內容以及 0.0 到 1.0 的相對邊界框座標 [ymin, xmin, ymax, xmax]。
 
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
  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
 
 
86
  box = item.get("box")
87
  if box and len(box) == 4:
88
  ymin, xmin, ymax, xmax = box
 
 
89
  abs_xmin = xmin * width
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: