DeepLearning101 commited on
Commit
a334638
·
verified ·
1 Parent(s): 8fe1c58

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +78 -86
app.py CHANGED
@@ -6,7 +6,8 @@ import asyncio
6
  import aiohttp
7
  import subprocess
8
 
9
- # pip 升級
 
10
  def upgrade_pip():
11
  try:
12
  subprocess.check_call([os.sys.executable, "-m", "pip", "install", "--upgrade", "pip"])
@@ -17,14 +18,54 @@ def upgrade_pip():
17
  upgrade_pip()
18
 
19
  LLM_API = os.environ.get("LLM_API", "").strip()
20
- LLM_URL = os.environ.get("LLM_URL")
21
  USER_ID = "HuggingFace Space"
22
 
23
- async def send_chat_message(LLM_URL, LLM_API, category, file_url):
24
- print(f"--- 開始請求 ---")
25
- print(f"URL: {LLM_URL}/chat-messages")
26
- print(f"File URL: {file_url}") # 檢查這裡產生的 URL 是否真的公開可讀取
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
 
 
 
 
 
 
 
 
 
28
  payload = {
29
  "inputs": {},
30
  "query": category,
@@ -34,13 +75,15 @@ async def send_chat_message(LLM_URL, LLM_API, category, file_url):
34
  "files": [
35
  {
36
  "type": "image",
37
- "transfer_method": "remote_url",
38
- "url": file_url
39
  }
40
  ]
41
  }
42
 
 
43
  answer = ""
 
44
  try:
45
  async with aiohttp.ClientSession() as session:
46
  async with session.post(
@@ -52,94 +95,45 @@ async def send_chat_message(LLM_URL, LLM_API, category, file_url):
52
  json=payload
53
  ) as response:
54
 
55
- # [DEBUG 1] 檢查狀態碼
56
- print(f"HTTP Status: {response.status}")
57
-
58
  if response.status != 200:
59
- # 如果出錯,讀取錯誤訊息並回傳
60
  error_text = await response.text()
61
- print(f"API Error Response: {error_text}")
62
- return f"API Error {response.status}: {error_text}"
63
 
64
- # [DEBUG 2] 逐行監看回傳內容
65
  async for line_bytes in response.content:
66
  line = line_bytes.decode("utf-8").strip()
67
-
68
- # 印出原始資料 (Debug 用,確認有東西回來)
69
- if line:
70
- print(f"Raw Line: {line}")
71
-
72
  if line.startswith("data: "):
73
  try:
74
  data = json.loads(line[6:])
75
  if "answer" in data:
76
  answer += data["answer"]
77
- # print(f"Current Answer chunk: {data['answer']}") # 選用:即時看片段
78
  if "error" in data:
79
- print(f"Data Error: {data}") # Dify 有時會在 data 裡回傳 error
80
- except Exception as e:
81
- print(f"JSON Parse Error: {e} | Content: {line}")
82
  continue
83
 
84
  except Exception as e:
85
- print(f"Request Exception: {e}")
86
- return f"System Error: {str(e)}"
87
-
88
- if not answer:
89
- print("警告: 請求結束但 answer 為空")
90
-
91
- return answer or "No answer returned (Empty Response)"
92
-
93
- async def upload_file(LLM_URL, LLM_API, file_path, user_id):
94
- if not os.path.exists(file_path):
95
- return f"Error: File {file_path} not found"
96
-
97
- # ✅ 先定義 filename 和 mime_type
98
- mime_type, _ = mimetypes.guess_type(file_path)
99
- filename = os.path.basename(file_path)
100
-
101
- # ✅ print 放在這裡
102
- print("Uploading file:", filename, "mime_type:", mime_type)
103
 
104
- with open(file_path, 'rb') as f:
105
- async with aiohttp.ClientSession() as session:
106
- form_data = aiohttp.FormData()
107
- form_data.add_field('file', f, filename=filename, content_type=mime_type)
108
- form_data.add_field('user', user_id)
109
- async with session.post(
110
- f"{LLM_URL}/files/upload",
111
- headers={"Authorization": f"Bearer {LLM_API}"},
112
- data=form_data
113
- ) as response:
114
- if response.status == 404:
115
- return "Error: Endpoint not found (404)"
116
- response_text = await response.text()
117
- print("Upload response:", response_text)
118
- try:
119
- return json.loads(response_text)
120
- except json.JSONDecodeError:
121
- return "Error: Invalid JSON response"
122
 
 
123
  async def handle_input(file_path, category):
124
- # 取得檔名
125
- filename = os.path.basename(file_path)
126
-
127
- # 直接用 HuggingFace repo URL
128
- file_url = f"https://huggingface.co/spaces/DeepLearning101/Multimodal-Playground/blob/main/DEMO/{filename}?raw=true"
129
 
130
- return await send_chat_message(LLM_URL, LLM_API, category, file_url)
131
- # async def handle_input(file_path, category):
132
- # # 如果 tmp 路徑不存在,改成 repo 內的 DEMO 路徑
133
- # if not os.path.exists(file_path):
134
- # file_path = os.path.join("DEMO", os.path.basename(file_path))
135
 
136
- # upload_response = await upload_file(LLM_URL, LLM_API, file_path, USER_ID)
137
- # if isinstance(upload_response, str) and upload_response.startswith("Error"):
138
- # return upload_response
139
- # file_id = upload_response.get("id")
140
- # if not file_id:
141
- # return "Error: No file ID returned from upload"
142
- # return await send_chat_message(LLM_URL, LLM_API, category, file_id)
 
 
 
143
 
144
  # UI 元件 & 資料
145
  examples = [
@@ -180,21 +174,19 @@ LINKS = """
180
  <a href='https://blog.twman.org/2023/07/HugIE.html' target='_blank'>基於機器閱讀理解和指令微調的統一信息抽取框架之診斷書醫囑資訊擷取分析</a><br>
181
  """
182
 
183
- # Gradio Blocks 寫法(全新修正)
184
  with gr.Blocks() as iface:
185
  gr.HTML(TITLE)
186
- gr.HTML(SUBTITLE)
187
- gr.HTML(LINKS)
188
 
189
  with gr.Row():
190
- file_input = gr.Image(label='圖片上傳', type='filepath')
191
- category = gr.Radio(label="Message Category", choices=[
192
  "機票", "計程車乘車證明", "通行明細 (etag)", "QRCODE發票",
193
- "超商高鐵車票", "高鐵車票", "超商台鐵車票", "台鐵車票", "旅行業代收轉付收據", "電子發票證明", "收據", "診斷證明書",
194
- "身份證正面", "身份證反面", "健保卡", "護照", "居留證", "行照", "勞保個人加保"
195
  ])
196
 
197
- submit_btn = gr.Button("解析")
198
  output_text = gr.Textbox(label="解析結果", lines=10)
199
 
200
  submit_btn.click(fn=handle_input, inputs=[file_input, category], outputs=output_text)
@@ -202,7 +194,7 @@ with gr.Blocks() as iface:
202
  gr.Examples(
203
  examples=examples,
204
  inputs=[file_input, category],
205
- label="範例圖片與類型"
206
  )
207
 
208
  iface.launch()
 
6
  import aiohttp
7
  import subprocess
8
 
9
+ # --- 1. 環境設定 ---
10
+ # pip 升級 (通常 Space 啟動時跑一次即可)
11
  def upgrade_pip():
12
  try:
13
  subprocess.check_call([os.sys.executable, "-m", "pip", "install", "--upgrade", "pip"])
 
18
  upgrade_pip()
19
 
20
  LLM_API = os.environ.get("LLM_API", "").strip()
21
+ LLM_URL = os.environ.get("LLM_URL", "").strip() # 確保去除空格
22
  USER_ID = "HuggingFace Space"
23
 
24
+ # --- 2. 上傳檔案函式 (修正版) ---
25
+ async def upload_file(LLM_URL, LLM_API, file_path, user_id):
26
+ """
27
+ 將本地暫存檔案上傳到 LLM Server,取得 file_id
28
+ """
29
+ if not os.path.exists(file_path):
30
+ return {"error": f"File {file_path} not found"}
31
+
32
+ mime_type, _ = mimetypes.guess_type(file_path)
33
+ if mime_type is None:
34
+ mime_type = 'application/octet-stream'
35
+
36
+ filename = os.path.basename(file_path)
37
+ print(f"正在上傳檔案: {filename} ({mime_type})")
38
+
39
+ try:
40
+ data = aiohttp.FormData()
41
+ # 注意: 這裡必須再次 open file,aiohttp 會自動處理串流
42
+ data.add_field('file', open(file_path, 'rb'), filename=filename, content_type=mime_type)
43
+ data.add_field('user', user_id)
44
+
45
+ async with aiohttp.ClientSession() as session:
46
+ async with session.post(
47
+ f"{LLM_URL}/files/upload",
48
+ headers={"Authorization": f"Bearer {LLM_API}"},
49
+ data=data
50
+ ) as response:
51
+ response_text = await response.text()
52
+ print(f"上傳回應狀態: {response.status}")
53
+
54
+ if response.status != 200 and response.status != 201:
55
+ print(f"上傳失敗回應: {response_text}")
56
+ return {"error": f"Upload failed: {response.status} - {response_text}"}
57
+
58
+ return json.loads(response_text)
59
 
60
+ except Exception as e:
61
+ print(f"上傳過程發生例外: {e}")
62
+ return {"error": str(e)}
63
+
64
+ # --- 3. 對話請求函式 (改用 file_id) ---
65
+ async def send_chat_message(LLM_URL, LLM_API, category, file_id):
66
+ """
67
+ 使用 file_id 發送對話請求
68
+ """
69
  payload = {
70
  "inputs": {},
71
  "query": category,
 
75
  "files": [
76
  {
77
  "type": "image",
78
+ "transfer_method": "local_file", # 注意:使用 ID 時這裡通常是 local_file
79
+ "upload_file_id": file_id
80
  }
81
  ]
82
  }
83
 
84
+ print(f"發送請求中... (File ID: {file_id})")
85
  answer = ""
86
+
87
  try:
88
  async with aiohttp.ClientSession() as session:
89
  async with session.post(
 
95
  json=payload
96
  ) as response:
97
 
 
 
 
98
  if response.status != 200:
 
99
  error_text = await response.text()
100
+ return f"Chat Error {response.status}: {error_text}"
 
101
 
 
102
  async for line_bytes in response.content:
103
  line = line_bytes.decode("utf-8").strip()
 
 
 
 
 
104
  if line.startswith("data: "):
105
  try:
106
  data = json.loads(line[6:])
107
  if "answer" in data:
108
  answer += data["answer"]
 
109
  if "error" in data:
110
+ return f"Stream Error: {data}"
111
+ except:
 
112
  continue
113
 
114
  except Exception as e:
115
+ return f"Request Exception: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
+ return answer or "No answer returned."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
 
119
+ # --- 4. 主處理邏輯 ---
120
  async def handle_input(file_path, category):
121
+ if not file_path:
122
+ return "請先上傳圖片"
 
 
 
123
 
124
+ # 步驟 1: 上傳檔案
125
+ upload_result = await upload_file(LLM_URL, LLM_API, file_path, USER_ID)
 
 
 
126
 
127
+ # 檢查上傳是否成功
128
+ if "error" in upload_result:
129
+ return f"上傳錯誤: {upload_result['error']}"
130
+
131
+ file_id = upload_result.get("id")
132
+ if not file_id:
133
+ return f"錯誤: 上傳成功但未回傳 ID。回應: {upload_result}"
134
+
135
+ # 步驟 2: 發送對話
136
+ return await send_chat_message(LLM_URL, LLM_API, category, file_id)
137
 
138
  # UI 元件 & 資料
139
  examples = [
 
174
  <a href='https://blog.twman.org/2023/07/HugIE.html' target='_blank'>基於機器閱讀理解和指令微調的統一信息抽取框架之診斷書醫囑資訊擷取分析</a><br>
175
  """
176
 
 
177
  with gr.Blocks() as iface:
178
  gr.HTML(TITLE)
179
+ # gr.HTML(LINKS) # 需要時取消註解
 
180
 
181
  with gr.Row():
182
+ file_input = gr.Image(label='圖片上傳', type='filepath') # type='filepath' 很重要
183
+ category = gr.Radio(label="文件類型", choices=[
184
  "機票", "計程車乘車證明", "通行明細 (etag)", "QRCODE發票",
185
+ "超商高鐵車票", "高鐵車票", "超商台鐵車票", "台鐵車票",
186
+ "診斷證明書", "身份證正面", "身份證反面", "健保卡", "護照", "居留證"
187
  ])
188
 
189
+ submit_btn = gr.Button("解析", variant="primary")
190
  output_text = gr.Textbox(label="解析結果", lines=10)
191
 
192
  submit_btn.click(fn=handle_input, inputs=[file_input, category], outputs=output_text)
 
194
  gr.Examples(
195
  examples=examples,
196
  inputs=[file_input, category],
197
+ label="點擊範例直接測試"
198
  )
199
 
200
  iface.launch()