fantaxy commited on
Commit
ce55546
Β·
verified Β·
1 Parent(s): fb2d730

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -36
app.py CHANGED
@@ -18,7 +18,7 @@ MODEL_ID = "zai-org/GLM-4.7-Flash"
18
  print(f"[Init] Loading tokenizer from {MODEL_ID}...")
19
  tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True)
20
 
21
- model = None # μ§€μ—° λ‘œλ”©
22
 
23
  def get_model():
24
  global model
@@ -41,7 +41,7 @@ def get_model():
41
  def extract_text_from_pdf(file_path: str) -> str:
42
  """PDF νŒŒμΌμ—μ„œ ν…μŠ€νŠΈ μΆ”μΆœ"""
43
  try:
44
- import fitz # PyMuPDF
45
  doc = fitz.open(file_path)
46
  text_parts = []
47
  for page_num, page in enumerate(doc, 1):
@@ -70,13 +70,10 @@ def extract_text_from_docx(file_path: str) -> str:
70
  try:
71
  from docx import Document
72
  doc = Document(file_path)
73
-
74
  text_parts = []
75
-
76
  for para in doc.paragraphs:
77
  if para.text.strip():
78
  text_parts.append(para.text)
79
-
80
  for table_idx, table in enumerate(doc.tables, 1):
81
  table_text = [f"\n[ν‘œ {table_idx}]"]
82
  for row in table.rows:
@@ -85,7 +82,6 @@ def extract_text_from_docx(file_path: str) -> str:
85
  table_text.append(row_text)
86
  if len(table_text) > 1:
87
  text_parts.append("\n".join(table_text))
88
-
89
  return "\n\n".join(text_parts) if text_parts else "[DOCXμ—μ„œ ν…μŠ€νŠΈλ₯Ό μΆ”μΆœν•  수 μ—†μŠ΅λ‹ˆλ‹€]"
90
  except Exception as e:
91
  return f"[DOCX 읽기 였λ₯˜: {str(e)}]"
@@ -197,13 +193,11 @@ def execute_tool(tool_name: str, arguments: dict) -> str:
197
  def parse_tool_calls(response: str) -> list:
198
  """μ‘λ‹΅μ—μ„œ 도ꡬ 호좜 νŒŒμ‹±"""
199
  tool_calls = []
200
-
201
  patterns = [
202
  r'<\|tool_call\|>(\{.*?\})<\|/tool_call\|>',
203
  r'```json\s*(\{[^`]*"name"[^`]*\})\s*```',
204
  r'\{"name":\s*"(\w+)",\s*"arguments":\s*(\{[^}]+\})\}',
205
  ]
206
-
207
  for pattern in patterns:
208
  matches = re.findall(pattern, response, re.DOTALL)
209
  for match in matches:
@@ -215,11 +209,10 @@ def parse_tool_calls(response: str) -> list:
215
  tool_calls.append(tool_call)
216
  except:
217
  continue
218
-
219
  return tool_calls
220
 
221
  # ═══════════════════════════════════════════════════════════
222
- # πŸ’¬ 슀트리밍 μ±„νŒ… ν•¨μˆ˜
223
  # ═══════════════════════════════════════════════════════════
224
 
225
  file_context = {"name": "", "content": ""}
@@ -235,16 +228,16 @@ def chat_streaming(
235
  enable_thinking: bool,
236
  enable_tools: bool,
237
  ):
238
- """슀트리밍 μ±„νŒ… 생성"""
239
  global file_context
240
 
241
  if not message.strip():
242
- yield history, ""
243
  return
244
 
245
  model = get_model()
246
- messages = []
247
 
 
248
  sys_content = system_prompt if system_prompt.strip() else "You are a helpful AI assistant."
249
 
250
  if file_context["content"]:
@@ -260,20 +253,27 @@ You have access to these tools:
260
  """
261
  sys_content += f"\n\n{tool_desc}"
262
 
263
- messages.append({"role": "system", "content": sys_content})
 
264
 
 
265
  for h in history:
266
- if h[0]:
267
- messages.append({"role": "user", "content": h[0]})
268
- if h[1]:
269
- messages.append({"role": "assistant", "content": h[1]})
270
-
 
 
 
 
271
  user_content = message
272
  if enable_thinking:
273
  user_content = f"<think>\nLet me think step by step.\n</think>\n\n{message}"
274
 
275
  messages.append({"role": "user", "content": user_content})
276
 
 
277
  try:
278
  inputs = tokenizer.apply_chat_template(
279
  messages,
@@ -283,34 +283,51 @@ You have access to these tools:
283
  return_tensors="pt",
284
  ).to(model.device)
285
  except Exception as e:
286
- yield history + [[message, f"ν† ν¬λ‚˜μ΄μ¦ˆ 였λ₯˜: {str(e)}"]], ""
 
 
 
 
287
  return
288
 
 
289
  streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
290
 
 
 
 
 
 
 
 
 
 
 
291
  generation_kwargs = {
292
  **inputs,
293
  "streamer": streamer,
294
- "max_new_tokens": max_tokens,
295
- "temperature": temperature if temperature > 0 else 0.01,
296
- "top_p": top_p,
297
- "do_sample": temperature > 0,
298
- "pad_token_id": tokenizer.pad_token_id or tokenizer.eos_token_id,
299
  }
300
 
301
  thread = Thread(target=model.generate, kwargs=generation_kwargs)
302
  thread.start()
303
 
 
 
 
 
 
 
304
  partial_response = ""
305
- new_history = history + [[message, ""]]
306
 
307
  for new_token in streamer:
308
  partial_response += new_token
309
- new_history[-1][1] = partial_response
310
- yield new_history, ""
311
 
312
  thread.join()
313
 
 
314
  if enable_tools:
315
  tool_calls = parse_tool_calls(partial_response)
316
  if tool_calls:
@@ -321,9 +338,9 @@ You have access to these tools:
321
 
322
  if tool_results:
323
  final_response = partial_response + "\n\nπŸ“Œ **도ꡬ μ‹€ν–‰ κ²°κ³Ό:**\n" + "\n".join(tool_results)
324
- new_history[-1][1] = final_response
325
 
326
- yield new_history, ""
327
 
328
  def handle_file_upload(file):
329
  """파일 μ—…λ‘œλ“œ 처리"""
@@ -354,10 +371,10 @@ def clear_file():
354
 
355
  def clear_chat():
356
  """μ±„νŒ… μ΄ˆκΈ°ν™”"""
357
- return [], ""
358
 
359
  # ═══════════════════════════════════════════════════════════
360
- # 🎨 Gradio UI (6.0 ν˜Έν™˜)
361
  # ═══════════════════════════════════════════════════════════
362
 
363
  with gr.Blocks(title="GLM-4.7-Flash Chatbot") as demo:
@@ -373,6 +390,7 @@ with gr.Blocks(title="GLM-4.7-Flash Chatbot") as demo:
373
  chatbot = gr.Chatbot(
374
  label="λŒ€ν™”",
375
  height=500,
 
376
  )
377
 
378
  with gr.Row():
@@ -425,20 +443,26 @@ with gr.Blocks(title="GLM-4.7-Flash Chatbot") as demo:
425
  inputs=message,
426
  )
427
 
428
- # 이벀트
429
  submit_event = submit_btn.click(
430
  fn=chat_streaming,
431
  inputs=[message, chatbot, system_prompt, max_tokens, temperature, top_p, enable_thinking, enable_tools],
432
- outputs=[chatbot, message],
 
 
 
433
  )
434
 
435
  message.submit(
436
  fn=chat_streaming,
437
  inputs=[message, chatbot, system_prompt, max_tokens, temperature, top_p, enable_thinking, enable_tools],
438
- outputs=[chatbot, message],
 
 
 
439
  )
440
 
441
- clear_btn.click(fn=clear_chat, outputs=[chatbot, message])
442
  stop_btn.click(fn=None, cancels=[submit_event])
443
 
444
  file_upload.change(fn=handle_file_upload, inputs=[file_upload], outputs=[file_status])
 
18
  print(f"[Init] Loading tokenizer from {MODEL_ID}...")
19
  tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, trust_remote_code=True)
20
 
21
+ model = None
22
 
23
  def get_model():
24
  global model
 
41
  def extract_text_from_pdf(file_path: str) -> str:
42
  """PDF νŒŒμΌμ—μ„œ ν…μŠ€νŠΈ μΆ”μΆœ"""
43
  try:
44
+ import fitz
45
  doc = fitz.open(file_path)
46
  text_parts = []
47
  for page_num, page in enumerate(doc, 1):
 
70
  try:
71
  from docx import Document
72
  doc = Document(file_path)
 
73
  text_parts = []
 
74
  for para in doc.paragraphs:
75
  if para.text.strip():
76
  text_parts.append(para.text)
 
77
  for table_idx, table in enumerate(doc.tables, 1):
78
  table_text = [f"\n[ν‘œ {table_idx}]"]
79
  for row in table.rows:
 
82
  table_text.append(row_text)
83
  if len(table_text) > 1:
84
  text_parts.append("\n".join(table_text))
 
85
  return "\n\n".join(text_parts) if text_parts else "[DOCXμ—μ„œ ν…μŠ€νŠΈλ₯Ό μΆ”μΆœν•  수 μ—†μŠ΅λ‹ˆλ‹€]"
86
  except Exception as e:
87
  return f"[DOCX 읽기 였λ₯˜: {str(e)}]"
 
193
  def parse_tool_calls(response: str) -> list:
194
  """μ‘λ‹΅μ—μ„œ 도ꡬ 호좜 νŒŒμ‹±"""
195
  tool_calls = []
 
196
  patterns = [
197
  r'<\|tool_call\|>(\{.*?\})<\|/tool_call\|>',
198
  r'```json\s*(\{[^`]*"name"[^`]*\})\s*```',
199
  r'\{"name":\s*"(\w+)",\s*"arguments":\s*(\{[^}]+\})\}',
200
  ]
 
201
  for pattern in patterns:
202
  matches = re.findall(pattern, response, re.DOTALL)
203
  for match in matches:
 
209
  tool_calls.append(tool_call)
210
  except:
211
  continue
 
212
  return tool_calls
213
 
214
  # ═══════════════════════════════════════════════════════════
215
+ # πŸ’¬ 슀트리밍 μ±„νŒ… ν•¨μˆ˜ (Gradio 6.0 messages format)
216
  # ═══════════════════════════════════════════════════════════
217
 
218
  file_context = {"name": "", "content": ""}
 
228
  enable_thinking: bool,
229
  enable_tools: bool,
230
  ):
231
+ """슀트리밍 μ±„νŒ… 생성 - Gradio 6.0 messages format"""
232
  global file_context
233
 
234
  if not message.strip():
235
+ yield history
236
  return
237
 
238
  model = get_model()
 
239
 
240
+ # μ‹œμŠ€ν…œ ν”„λ‘¬ν”„νŠΈ ꡬ성
241
  sys_content = system_prompt if system_prompt.strip() else "You are a helpful AI assistant."
242
 
243
  if file_context["content"]:
 
253
  """
254
  sys_content += f"\n\n{tool_desc}"
255
 
256
+ # λͺ¨λΈμš© λ©”μ‹œμ§€ ꡬ성
257
+ messages = [{"role": "system", "content": sys_content}]
258
 
259
+ # νžˆμŠ€ν† λ¦¬ λ³€ν™˜ (Gradio 6.0 format -> λͺ¨λΈ format)
260
  for h in history:
261
+ if isinstance(h, dict):
262
+ messages.append({"role": h["role"], "content": h["content"]})
263
+ elif isinstance(h, (list, tuple)) and len(h) == 2:
264
+ if h[0]:
265
+ messages.append({"role": "user", "content": h[0]})
266
+ if h[1]:
267
+ messages.append({"role": "assistant", "content": h[1]})
268
+
269
+ # ν˜„μž¬ λ©”μ‹œμ§€
270
  user_content = message
271
  if enable_thinking:
272
  user_content = f"<think>\nLet me think step by step.\n</think>\n\n{message}"
273
 
274
  messages.append({"role": "user", "content": user_content})
275
 
276
+ # ν† ν¬λ‚˜μ΄μ¦ˆ
277
  try:
278
  inputs = tokenizer.apply_chat_template(
279
  messages,
 
283
  return_tensors="pt",
284
  ).to(model.device)
285
  except Exception as e:
286
+ new_history = history + [
287
+ {"role": "user", "content": message},
288
+ {"role": "assistant", "content": f"ν† ν¬λ‚˜μ΄μ¦ˆ 였λ₯˜: {str(e)}"}
289
+ ]
290
+ yield new_history
291
  return
292
 
293
+ # 슀트리머 μ„€μ •
294
  streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
295
 
296
+ # GenerationConfig μ‚¬μš©
297
+ from transformers import GenerationConfig
298
+ gen_config = GenerationConfig(
299
+ max_new_tokens=max_tokens,
300
+ temperature=temperature if temperature > 0 else 0.01,
301
+ top_p=top_p,
302
+ do_sample=temperature > 0,
303
+ pad_token_id=tokenizer.pad_token_id or tokenizer.eos_token_id,
304
+ )
305
+
306
  generation_kwargs = {
307
  **inputs,
308
  "streamer": streamer,
309
+ "generation_config": gen_config,
 
 
 
 
310
  }
311
 
312
  thread = Thread(target=model.generate, kwargs=generation_kwargs)
313
  thread.start()
314
 
315
+ # Gradio 6.0 messages format으둜 νžˆμŠ€ν† λ¦¬ ꡬ성
316
+ new_history = history + [
317
+ {"role": "user", "content": message},
318
+ {"role": "assistant", "content": ""}
319
+ ]
320
+
321
  partial_response = ""
 
322
 
323
  for new_token in streamer:
324
  partial_response += new_token
325
+ new_history[-1]["content"] = partial_response
326
+ yield new_history
327
 
328
  thread.join()
329
 
330
+ # Tool 호좜 처리
331
  if enable_tools:
332
  tool_calls = parse_tool_calls(partial_response)
333
  if tool_calls:
 
338
 
339
  if tool_results:
340
  final_response = partial_response + "\n\nπŸ“Œ **도ꡬ μ‹€ν–‰ κ²°κ³Ό:**\n" + "\n".join(tool_results)
341
+ new_history[-1]["content"] = final_response
342
 
343
+ yield new_history
344
 
345
  def handle_file_upload(file):
346
  """파일 μ—…λ‘œλ“œ 처리"""
 
371
 
372
  def clear_chat():
373
  """μ±„νŒ… μ΄ˆκΈ°ν™”"""
374
+ return []
375
 
376
  # ═══════════════════════════════════════════════════════════
377
+ # 🎨 Gradio UI (6.0 ν˜Έν™˜ - messages format)
378
  # ═══════════════════════════════════════════════════════════
379
 
380
  with gr.Blocks(title="GLM-4.7-Flash Chatbot") as demo:
 
390
  chatbot = gr.Chatbot(
391
  label="λŒ€ν™”",
392
  height=500,
393
+ type="messages", # Gradio 6.0 messages format
394
  )
395
 
396
  with gr.Row():
 
443
  inputs=message,
444
  )
445
 
446
+ # 이벀트 - Gradio 6.0μ—μ„œλŠ” chatbot만 output
447
  submit_event = submit_btn.click(
448
  fn=chat_streaming,
449
  inputs=[message, chatbot, system_prompt, max_tokens, temperature, top_p, enable_thinking, enable_tools],
450
+ outputs=[chatbot],
451
+ ).then(
452
+ fn=lambda: "",
453
+ outputs=[message],
454
  )
455
 
456
  message.submit(
457
  fn=chat_streaming,
458
  inputs=[message, chatbot, system_prompt, max_tokens, temperature, top_p, enable_thinking, enable_tools],
459
+ outputs=[chatbot],
460
+ ).then(
461
+ fn=lambda: "",
462
+ outputs=[message],
463
  )
464
 
465
+ clear_btn.click(fn=clear_chat, outputs=[chatbot])
466
  stop_btn.click(fn=None, cancels=[submit_event])
467
 
468
  file_upload.change(fn=handle_file_upload, inputs=[file_upload], outputs=[file_status])