Atsatoru commited on
Commit
ff45293
·
verified ·
1 Parent(s): 2ceaf9d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +129 -108
app.py CHANGED
@@ -790,13 +790,18 @@ RESPONSE_TEMPLATES = {
790
  " khai_sinh": {
791
  "short": "Dạ để khai sinh cho bé, bác/cháu cần mang: Giấy khai sinh, CCCD của cả cha mẹ, và sổ hộ khẩu. Ra UBND xã/phường nơi cư trú là được ạ!",
792
  "detailed": """Dạ về khai sinh cho bé, em hướng dẫn chi tiết ạ:
 
793
  📋 **HỒ SƠ CẦN CHUẨN BỊ:**
794
  1. Giấy khai sinh (điền đầy đủ thông tin)
795
  2. CCCD/CMND của cả cha và mẹ
796
  3. Sổ hộ khẩu của cha mẹ
 
797
  🏢 **NƠI LÀM:** UBND xã/phường nơi cư trú
 
798
  ⏰ **THỜI GIAN:** 1-3 ngày
 
799
  💰 **LỆ PHÍ:** Miễn phí
 
800
  ⚠️ **LƯU Ý:** Làm trong 60 ngày kể từ khi sinh để tránh phạt nhé!"""
801
  }
802
  }
@@ -930,6 +935,7 @@ Dựa trên tài liệu và quy định hiện hành:
930
  # Bước 4: Tổng hợp câu trả lời
931
  step4 = f"""BƯỚC 4 - TỔNG HỢP TRẢ LỜI:
932
  Hãy trả lời theo phong cách: {persona['tone']}
 
933
  Lưu ý:
934
  - Dùng các mẫu câu: {', '.join(persona['greeting'][:2])}
935
  - Kết thúc bằng: {', '.join(persona['closing'][:2])}
@@ -1192,11 +1198,16 @@ QUY TRÌNH: {proc['steps']}
1192
 
1193
  # Bước 8: Full prompt cho LLM
1194
  full_prompt = f"""Bạn là cán bộ tư vấn thủ tục hành chính công tại UBND. Hãy hỗ trợ người dân.
 
1195
  {cot_prompt}
 
1196
  CÂU HỎI: {query}
 
1197
  {proc_info}
 
1198
  LỊCH SỬ ĐỌC CHUẨN KHI CÓ:
1199
  {relevant_history}
 
1200
  HÃY TRẢ LỜI NGƯỜI DÂNG:"""
1201
 
1202
  messages = [
@@ -1320,22 +1331,23 @@ print()
1320
  print('='*70)
1321
 
1322
  # ======================================================================
1323
- # PHẦN 12.5: GRADIO INTERFACE (BẢN TỐI ƯU - GIỮ BẢN TIN & FULL LOGIN/LOGOUT)
1324
- # ======================================================================
 
1325
 
1326
  import gradio as gr
1327
  print('='*70)
1328
- print('🖥️ KHỞI TẠO GRADIO INTERFACE CHUẨN')
1329
  print('='*70)
1330
  print()
1331
 
1332
- # Danh sách thủ tục quản trị viên
1333
  admin_procedures = list(DICHVUCONG_DATA.values())
1334
 
1335
  def get_procedures_list():
1336
  lines = ["| Mã | Tên thủ tục | Cơ quan |"]
1337
  lines.append("|---|---|---|")
1338
- for p in admin_procedures[:20]: # Giới hạn hiển thị 20 bản ghi đầu tiên
1339
  lines.append(f"| {p['code']} | {p['name']} | {p['coquan']} |")
1340
  return "\n".join(lines)
1341
 
@@ -1346,18 +1358,20 @@ def admin_add(code, name, docs, coquan, time_val, lephi, note, steps):
1346
  'time': time_val, 'lephi': lephi, 'note': note, 'steps': steps
1347
  }
1348
  admin_procedures.append(new_proc)
1349
- return f"✅ Đã thêm thành công thủ tục: {code} - {name}", get_procedures_list()
 
 
1350
 
1351
- # Hàm xử lý hội thoại với AI Process PRO
1352
  def process_chat_pro(audio, text, history, persona="thuong"):
1353
  try:
1354
  if history is None:
1355
  history = []
1356
 
1357
- # Cập nhật trạng thái nhân vật
1358
  conversation_memory.set_persona(persona)
1359
 
1360
- # Chuẩn hóa dữ liệu đầu vào
1361
  query = ''
1362
  if audio and not os.path.isdir(audio):
1363
  query = speech_to_text(audio)
@@ -1367,16 +1381,21 @@ def process_chat_pro(audio, text, history, persona="thuong"):
1367
  if len(query) < 3:
1368
  return history, None, ''
1369
 
1370
- # Gọi mô hình xử lý lõi AI Process PRO
1371
  result = ai_process_pro(query, use_memory=True)
1372
 
1373
- # Định dạng câu trả lời hiển thị
1374
- response = f"""{result['response']}\n\n--- \n_⏱️ Xử lý: {result['process_time']}s | 📄 Tài liệu: {result['docs_count']} | 🌡️ Temp: {result['temperature']}_"""
 
 
 
 
 
1375
 
1376
  history.append({"role": "user", "content": query})
1377
  history.append({"role": "assistant", "content": response})
1378
 
1379
- # Xử lý chuyển đổi văn bản thành giọng nói (TTS) phản hồi
1380
  audio_out = None
1381
  try:
1382
  loop = asyncio.get_event_loop()
@@ -1394,7 +1413,7 @@ def process_chat_pro(audio, text, history, persona="thuong"):
1394
  except Exception as e:
1395
  import traceback
1396
  traceback.print_exc()
1397
- error_msg = f"Hệ thống gặp lỗi: {str(e)}"
1398
  return history, None, error_msg
1399
 
1400
  def clear_chat_pro():
@@ -1410,23 +1429,28 @@ def change_persona(new_persona):
1410
  }
1411
  return f"✅ Đã chuyển sang: {persona_names.get(new_persona, new_persona)}"
1412
 
1413
- # Định hình cấu trúc Style CSS giao diện tĩnh bảo mật
1414
  custom_css = """
 
1415
  .gradio-container {
1416
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif !important;
1417
  background-color: #f8f9fa !important;
1418
  }
 
 
1419
  footer {display: none !important;}
1420
- /* Thanh Topbar (Gradient Xanh Navy) */
 
1421
  .admin-topbar {
1422
  background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
1423
  padding: 20px 30px;
1424
  display: flex;
1425
  align-items: center;
1426
- margin: -20px -20px 0px -20px; /* Kết nối khít với khối bản tin bên dưới */
1427
  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
1428
  color: white;
1429
  }
 
1430
  .admin-icon {
1431
  font-size: 45px;
1432
  margin-right: 20px;
@@ -1434,6 +1458,7 @@ footer {display: none !important;}
1434
  padding: 10px;
1435
  border-radius: 12px;
1436
  }
 
1437
  .admin-brand h1 {
1438
  color: #ffffff !important;
1439
  font-size: 24px !important;
@@ -1442,45 +1467,15 @@ footer {display: none !important;}
1442
  letter-spacing: 1px;
1443
  text-transform: uppercase;
1444
  }
 
1445
  .admin-brand p {
1446
  color: #e0e0e0 !important;
1447
  font-size: 14px !important;
1448
  margin: 5px 0 0 0 !important;
1449
  font-weight: 300 !important;
1450
  }
1451
- /* Khung bọc khu vực Tin tức nằm cố định dưới Taskbar */
1452
- .global-news-container {
1453
- background: #ffffff;
1454
- padding: 15px 20px;
1455
- margin: 0px -20px 20px -20px; /* Tràn lề sát mép màn hình */
1456
- border-bottom: 1px solid #dee2e6;
1457
- box-shadow: 0 2px 8px rgba(0,0,0,0.02);
1458
- }
1459
- .section-title-news {
1460
- color: #1e3c72;
1461
- font-weight: 600;
1462
- margin-bottom: 12px;
1463
- border-bottom: 2px solid #e9ecef;
1464
- padding-bottom: 6px;
1465
- font-size: 15px;
1466
- }
1467
- .news-grid {
1468
- display: grid;
1469
- grid-template-columns: repeat(3, 1fr);
1470
- gap: 15px;
1471
- }
1472
- @media (max-width: 768px) {
1473
- .news-grid {
1474
- grid-template-columns: 1fr;
1475
- }
1476
- }
1477
- .news-card {
1478
- background: #f8fafc;
1479
- padding: 14px 16px;
1480
- border-left: 4px solid #1e3c72;
1481
- border-radius: 6px;
1482
- box-shadow: 0 2px 4px rgba(0,0,0,0.02);
1483
- }
1484
  button.primary {
1485
  background-color: #0056b3 !important;
1486
  color: white !important;
@@ -1489,16 +1484,21 @@ button.primary {
1489
  border: none !important;
1490
  transition: all 0.3s ease;
1491
  }
 
1492
  button.primary:hover {
1493
  background-color: #004494 !important;
1494
  box-shadow: 0 4px 8px rgba(0,86,179,0.3) !important;
1495
  }
 
 
1496
  .main-chatbot {
1497
  border: 1px solid #dee2e6 !important;
1498
  border-radius: 8px !important;
1499
  background-color: #ffffff !important;
1500
  box-shadow: 0 2px 15px rgba(0,0,0,0.03) !important;
1501
  }
 
 
1502
  .section-title {
1503
  color: #1e3c72;
1504
  font-weight: 600;
@@ -1508,15 +1508,22 @@ button.primary:hover {
1508
  }
1509
  """
1510
 
1511
- # Khởi tạo Block giao diện chính thức
1512
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", neutral_hue="slate"), css=custom_css) as demo:
1513
 
1514
- # 1. Header ứng dụng công vụ kết hợp Bản tin điện tử 3 ô nằm NGAY DƯỚI THANH TASKBAR
1515
-
 
 
 
 
 
 
 
 
1516
 
1517
- # 2. Hệ thống chuyển Tab làm việc chính
1518
  with gr.Tabs():
1519
- # TAB 1: Giao diện tương tác tư vấn công dân
1520
  with gr.Tab("💬 Trợ lý AI"):
1521
  with gr.Row():
1522
  with gr.Column(scale=7):
@@ -1533,6 +1540,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", neutral_hue="slate"), cs
1533
  btn_send = gr.Button('GỬI CÂU HỎI', variant='primary')
1534
  btn_clear = gr.Button('Làm mới')
1535
 
 
1536
  gr.HTML("""
1537
  <div style="
1538
  margin-top: 15px;
@@ -1546,9 +1554,9 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", neutral_hue="slate"), cs
1546
  ">
1547
  <strong style="color: #1e3c72;">💡 Cách dùng nhanh:</strong>
1548
  <ul style="margin: 5px 0 0 15px; padding: 0;">
1549
- <li>Nhập câu hỏi văn bản hoặc dùng 🎤 <b>Micro</b> để nói trực tiếp.</li>
1550
- <li>Nhấn nút <b>Gửi câu hỏi</b> để hệ thống xử lý dữ liệu RAG.</li>
1551
- <li>Trợ lý ảo sẽ tự động 🔊 <b>Đọc câu trả lời</b> bằng giọng nói thích hợp.</li>
1552
  </ul>
1553
  </div>
1554
  """)
@@ -1566,34 +1574,28 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", neutral_hue="slate"), cs
1566
  inputs=[audio_in, msg_in]
1567
  )
1568
 
1569
- # Ràng buộc sự kiện Chatbot
1570
  btn_send.click(process_chat_pro, [audio_in, msg_in, chat], [chat, audio_out, msg_in])
1571
  msg_in.submit(process_chat_pro, [audio_in, msg_in, chat], [chat, audio_out, msg_in])
1572
  btn_clear.click(clear_chat_pro, [], [chat, audio_out, msg_in])
1573
-
1574
- # TAB 2: Quản trị viên cập nhật thủ tục (CÓ FULL ĐĂNG NHẬP / ĐĂNG XUẤT)
1575
  with gr.Tab("⚙️ Admin Panel"):
 
1576
 
1577
- # Form đăng nhập (Tài khoản + Mật khẩu) như tài khoản Google
1578
- with gr.Row() as login_form:
1579
- with gr.Column(scale=2):
1580
- input_user = gr.Textbox(label="Tài khoản cán bộ", placeholder="Nhập tên tài khoản...")
1581
- with gr.Column(scale=2):
1582
- input_pass = gr.Textbox(label="Mật khẩu mã hóa", type="password", placeholder="Nhập mật khẩu...")
1583
- with gr.Column(scale=1):
1584
- gr.Markdown("<br>") # Đẩy nút xuống bằng hàng với textbox
1585
- btn_login = gr.Button("Đăng nhập 🔑", variant="primary")
1586
 
1587
- # Khối nội dung quản trị viên - Mặc định ẩn bảo mật
1588
  admin_content = gr.Group(visible=False)
1589
 
1590
  with admin_content:
1591
- with gr.Row():
1592
- gr.Markdown("### 🏛️ KHU VỰC CẬP NHẬT DỮ LIỆU CẤP CAO")
1593
- btn_logout = gr.Button("Đăng xuất ↩️", variant="stop", scale=1, size="sm")
1594
-
1595
  gr.Markdown("---")
1596
- gr.Markdown("### ➕ Thêm thủ tục hành chính mới (Mô hình cập nhật ngay lập tức)")
1597
  with gr.Row():
1598
  with gr.Column():
1599
  admin_code = gr.Textbox(label="Mã thủ tục")
@@ -1602,64 +1604,83 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", neutral_hue="slate"), cs
1602
  admin_coquan = gr.Textbox(label="Cơ quan tiếp nhận")
1603
 
1604
  with gr.Column():
1605
- admin_time = gr.Textbox(label="Thời gian giải quyết")
1606
- admin_lephi = gr.Textbox(label="Lệ phí quy định")
1607
- admin_note = gr.Textbox(label="Lưu ý quan trọng", lines=2)
1608
- admin_steps = gr.Textbox(label="Quy trình thực hiện", lines=3)
1609
 
1610
  btn_add = gr.Button("➕ THÊM VÀO HỆ THỐNG", variant='primary', size='lg')
1611
- add_output = gr.Textbox(label="Trạng thái xử lý yêu cầu")
1612
  procedures_list = gr.Markdown(value=get_procedures_list())
1613
 
1614
- # Cấu trúc logic chuyển đổi trạng thái giao diện an toàn
1615
- def check_admin_login(username, password):
1616
- if username == ACCOUNT and password == ADMIN_PASSWORD:
1617
- gr.Info("Đăng nhập hệ thống thành công!")
1618
- return gr.update(visible=False), gr.update(visible=True)
1619
- else:
1620
- gr.Warning("Tài khoản hoặc mật khẩu không chính xác!")
1621
  return gr.update(visible=True), gr.update(visible=False)
 
 
 
 
1622
 
1623
- def admin_logout():
1624
- gr.Info("Đã đăng xuất an toàn khỏi tài khoản cán bộ.")
1625
- return gr.update(visible=True), gr.update(visible=False), gr.update(value=""), gr.update(value="")
1626
-
1627
- # Đăng ký tương tác sự kiện xác thực
1628
  btn_login.click(
1629
- check_admin_login,
1630
- inputs=[input_user, input_pass],
1631
- outputs=[login_form, admin_content]
1632
- )
1633
-
1634
- btn_logout.click(
1635
- admin_logout,
1636
- inputs=[],
1637
- outputs=[login_form, admin_content, input_user, input_pass]
1638
  )
1639
 
 
1640
  btn_add.click(
1641
  admin_add,
1642
  [admin_code, admin_name, admin_docs, admin_coquan, admin_time, admin_lephi, admin_note, admin_steps],
1643
  [add_output, procedures_list]
1644
  )
1645
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1646
 
1647
  # ======================================================================
1648
- # PHẦN 12.7: LAUNCH SYSTEM APPLICATION
1649
- # ======================================================================
 
1650
 
1651
  print('='*70)
1652
- print('🚀 KHỞI ĐỘNG ỨNG DỤNG AI HÀNH CHÍNH CÔNG CHÍNH THỨC')
1653
  print('='*70)
1654
  print()
1655
 
 
 
1656
  print('='*70)
1657
- print(' Đang đồng bộ mạng và thiết lập public link...')
1658
- print(' Địa chỉ Web-UI sẽ xuất hiện bên dưới...')
1659
  print('='*70)
1660
  print()
1661
 
1662
- # Khởi chạy chương trình
1663
  demo.launch(
1664
  share=True,
1665
  server_name='0.0.0.0',
 
790
  " khai_sinh": {
791
  "short": "Dạ để khai sinh cho bé, bác/cháu cần mang: Giấy khai sinh, CCCD của cả cha mẹ, và sổ hộ khẩu. Ra UBND xã/phường nơi cư trú là được ạ!",
792
  "detailed": """Dạ về khai sinh cho bé, em hướng dẫn chi tiết ạ:
793
+
794
  📋 **HỒ SƠ CẦN CHUẨN BỊ:**
795
  1. Giấy khai sinh (điền đầy đủ thông tin)
796
  2. CCCD/CMND của cả cha và mẹ
797
  3. Sổ hộ khẩu của cha mẹ
798
+
799
  🏢 **NƠI LÀM:** UBND xã/phường nơi cư trú
800
+
801
  ⏰ **THỜI GIAN:** 1-3 ngày
802
+
803
  💰 **LỆ PHÍ:** Miễn phí
804
+
805
  ⚠️ **LƯU Ý:** Làm trong 60 ngày kể từ khi sinh để tránh phạt nhé!"""
806
  }
807
  }
 
935
  # Bước 4: Tổng hợp câu trả lời
936
  step4 = f"""BƯỚC 4 - TỔNG HỢP TRẢ LỜI:
937
  Hãy trả lời theo phong cách: {persona['tone']}
938
+
939
  Lưu ý:
940
  - Dùng các mẫu câu: {', '.join(persona['greeting'][:2])}
941
  - Kết thúc bằng: {', '.join(persona['closing'][:2])}
 
1198
 
1199
  # Bước 8: Full prompt cho LLM
1200
  full_prompt = f"""Bạn là cán bộ tư vấn thủ tục hành chính công tại UBND. Hãy hỗ trợ người dân.
1201
+
1202
  {cot_prompt}
1203
+
1204
  CÂU HỎI: {query}
1205
+
1206
  {proc_info}
1207
+
1208
  LỊCH SỬ ĐỌC CHUẨN KHI CÓ:
1209
  {relevant_history}
1210
+
1211
  HÃY TRẢ LỜI NGƯỜI DÂNG:"""
1212
 
1213
  messages = [
 
1331
  print('='*70)
1332
 
1333
  # ======================================================================
1334
+ # ============================================================
1335
+ # PHẦN 12.5: GRADIO INTERFACE
1336
+ # ============================================================
1337
 
1338
  import gradio as gr
1339
  print('='*70)
1340
+ print('🖥️ KHỞI TẠO GRADIO INTERFACE')
1341
  print('='*70)
1342
  print()
1343
 
1344
+ # Admin functions
1345
  admin_procedures = list(DICHVUCONG_DATA.values())
1346
 
1347
  def get_procedures_list():
1348
  lines = ["| Mã | Tên thủ tục | Cơ quan |"]
1349
  lines.append("|---|---|---|")
1350
+ for p in admin_procedures[:20]: # Limit to 20 for display
1351
  lines.append(f"| {p['code']} | {p['name']} | {p['coquan']} |")
1352
  return "\n".join(lines)
1353
 
 
1358
  'time': time_val, 'lephi': lephi, 'note': note, 'steps': steps
1359
  }
1360
  admin_procedures.append(new_proc)
1361
+ # For simplicity, we are not updating DICHVUCONG_DATA or Pinecone here directly
1362
+ # In a real application, you would update the backend data source
1363
+ return f"✅ Đã thêm: {code} - {name}", get_procedures_list()
1364
 
1365
+ # Chat function với AI Process PRO
1366
  def process_chat_pro(audio, text, history, persona="thuong"):
1367
  try:
1368
  if history is None:
1369
  history = []
1370
 
1371
+ # Cập nhật persona
1372
  conversation_memory.set_persona(persona)
1373
 
1374
+ # Xử lý input
1375
  query = ''
1376
  if audio and not os.path.isdir(audio):
1377
  query = speech_to_text(audio)
 
1381
  if len(query) < 3:
1382
  return history, None, ''
1383
 
1384
+ # Dùng AI Process PRO
1385
  result = ai_process_pro(query, use_memory=True)
1386
 
1387
+ # Format response
1388
+ response = f"""
1389
+
1390
+ {result['response']}
1391
+
1392
+ ---
1393
+ _⏱️ Xử lý: {result['process_time']}s | 📄 Tài liệu: {result['docs_count']} | 🌡️ Temp: {result['temperature']}_"""
1394
 
1395
  history.append({"role": "user", "content": query})
1396
  history.append({"role": "assistant", "content": response})
1397
 
1398
+ # TTS
1399
  audio_out = None
1400
  try:
1401
  loop = asyncio.get_event_loop()
 
1413
  except Exception as e:
1414
  import traceback
1415
  traceback.print_exc()
1416
+ error_msg = f"Lỗi: {str(e)}"
1417
  return history, None, error_msg
1418
 
1419
  def clear_chat_pro():
 
1429
  }
1430
  return f"✅ Đã chuyển sang: {persona_names.get(new_persona, new_persona)}"
1431
 
1432
+ # Build PRO interface
1433
  custom_css = """
1434
+ /* Reset font & nền */
1435
  .gradio-container {
1436
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif !important;
1437
  background-color: #f8f9fa !important;
1438
  }
1439
+
1440
+ /* Ẩn footer mặc định */
1441
  footer {display: none !important;}
1442
+
1443
+ /* Thanh Topbar chuyên nghiệp (Gradient Xanh Navy) */
1444
  .admin-topbar {
1445
  background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
1446
  padding: 20px 30px;
1447
  display: flex;
1448
  align-items: center;
1449
+ margin: -20px -20px 20px -20px; /* Tràn viền */
1450
  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
1451
  color: white;
1452
  }
1453
+
1454
  .admin-icon {
1455
  font-size: 45px;
1456
  margin-right: 20px;
 
1458
  padding: 10px;
1459
  border-radius: 12px;
1460
  }
1461
+
1462
  .admin-brand h1 {
1463
  color: #ffffff !important;
1464
  font-size: 24px !important;
 
1467
  letter-spacing: 1px;
1468
  text-transform: uppercase;
1469
  }
1470
+
1471
  .admin-brand p {
1472
  color: #e0e0e0 !important;
1473
  font-size: 14px !important;
1474
  margin: 5px 0 0 0 !important;
1475
  font-weight: 300 !important;
1476
  }
1477
+
1478
+ /* Tinh chỉnh Nút bấm */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1479
  button.primary {
1480
  background-color: #0056b3 !important;
1481
  color: white !important;
 
1484
  border: none !important;
1485
  transition: all 0.3s ease;
1486
  }
1487
+
1488
  button.primary:hover {
1489
  background-color: #004494 !important;
1490
  box-shadow: 0 4px 8px rgba(0,86,179,0.3) !important;
1491
  }
1492
+
1493
+ /* Tùy chỉnh Khung Chat */
1494
  .main-chatbot {
1495
  border: 1px solid #dee2e6 !important;
1496
  border-radius: 8px !important;
1497
  background-color: #ffffff !important;
1498
  box-shadow: 0 2px 15px rgba(0,0,0,0.03) !important;
1499
  }
1500
+
1501
+ /* Tiêu đề Box */
1502
  .section-title {
1503
  color: #1e3c72;
1504
  font-weight: 600;
 
1508
  }
1509
  """
1510
 
1511
+ # Khởi tạo giao diện với Theme base màu xanh thanh lịch
1512
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", neutral_hue="slate"), css=custom_css) as demo:
1513
 
1514
+ # 1. TOPBAR CHUYÊN NGHIỆP (Không dùng logo/tên thật)
1515
+ gr.HTML("""
1516
+ <div class="admin-topbar">
1517
+ <div class="admin-icon">🏛️</div>
1518
+ <div class="admin-brand">
1519
+ <h1>HỆ THỐNG TRỢ LÝ ẢO TƯ VẤN HÀNH CHÍNH</h1>
1520
+ <p>Giải đáp thông tin thủ tục - Nhanh chóng, Chính xác, Hỗ trợ 24/7</p>
1521
+ </div>
1522
+ </div>
1523
+ """)
1524
 
 
1525
  with gr.Tabs():
1526
+ # Chat Tab
1527
  with gr.Tab("💬 Trợ lý AI"):
1528
  with gr.Row():
1529
  with gr.Column(scale=7):
 
1540
  btn_send = gr.Button('GỬI CÂU HỎI', variant='primary')
1541
  btn_clear = gr.Button('Làm mới')
1542
 
1543
+ # --- Ô HƯỚNG DẪN NHỎ THÊM VÀO ĐÂY ---
1544
  gr.HTML("""
1545
  <div style="
1546
  margin-top: 15px;
 
1554
  ">
1555
  <strong style="color: #1e3c72;">💡 Cách dùng nhanh:</strong>
1556
  <ul style="margin: 5px 0 0 15px; padding: 0;">
1557
+ <li>Nhập câu hỏi hoặc dùng 🎤 <b>Micro</b>.</li>
1558
+ <li>Nhấn <b>Gửi</b> để nhận phản hồi từ AI.</li>
1559
+ <li>Hệ thống sẽ tự động 🔊 <b>Phát loa</b> câu trả lời.</li>
1560
  </ul>
1561
  </div>
1562
  """)
 
1574
  inputs=[audio_in, msg_in]
1575
  )
1576
 
1577
+ # (Các sự kiện click giữ nguyên)
1578
  btn_send.click(process_chat_pro, [audio_in, msg_in, chat], [chat, audio_out, msg_in])
1579
  msg_in.submit(process_chat_pro, [audio_in, msg_in, chat], [chat, audio_out, msg_in])
1580
  btn_clear.click(clear_chat_pro, [], [chat, audio_out, msg_in])
 
 
1581
  with gr.Tab("⚙️ Admin Panel"):
1582
+ gr.Markdown("### 🔐 Xác thực quyền quản trị")
1583
 
1584
+ with gr.Row():
1585
+ input_pass = gr.Textbox(
1586
+ label="Nhập mật khẩu để mở khóa tính năng Admin",
1587
+ type="password",
1588
+ placeholder="nhap mat khau",
1589
+ scale=4
1590
+ )
1591
+ btn_login = gr.Button("Xác thực 🔑", scale=1)
 
1592
 
1593
+ # Group chứa nội dung Admin - Mặc định ẩn (visible=False)
1594
  admin_content = gr.Group(visible=False)
1595
 
1596
  with admin_content:
 
 
 
 
1597
  gr.Markdown("---")
1598
+ gr.Markdown("### ➕ Thêm thủ tục mới (AI sẽ học ngay)")
1599
  with gr.Row():
1600
  with gr.Column():
1601
  admin_code = gr.Textbox(label="Mã thủ tục")
 
1604
  admin_coquan = gr.Textbox(label="Cơ quan tiếp nhận")
1605
 
1606
  with gr.Column():
1607
+ admin_time = gr.Textbox(label="Thời gian")
1608
+ admin_lephi = gr.Textbox(label="Lệ phí")
1609
+ admin_note = gr.Textbox(label="Lưu ý", lines=2)
1610
+ admin_steps = gr.Textbox(label="Quy trình", lines=3)
1611
 
1612
  btn_add = gr.Button("➕ THÊM VÀO HỆ THỐNG", variant='primary', size='lg')
1613
+ add_output = gr.Textbox(label="Kết quả xử lý")
1614
  procedures_list = gr.Markdown(value=get_procedures_list())
1615
 
1616
+ # --- Logic xử lý ẩn hiện và mật khẩu ---
1617
+ def check_admin(password):
1618
+ if password == ADMIN_PASSWORD:
1619
+ # Nếu đúng: Hiện nội dung admin, ẩn ô nhập mật khẩu và hiện thông báo thành công
1620
+ gr.Info("Đăng nhập thành công! Quyền quản trị đã được mở.")
 
 
1621
  return gr.update(visible=True), gr.update(visible=False)
1622
+ else:
1623
+ # Nếu sai: Giữ ẩn nội dung và hiện cảnh báo
1624
+ raise gr.Error("Mật khẩu không chính xác. Vui lòng thử lại!")
1625
+ return gr.update(visible=False), gr.update(visible=True)
1626
 
1627
+ # Sự kiện khi nhấn nút Xác thực
 
 
 
 
1628
  btn_login.click(
1629
+ check_admin,
1630
+ inputs=[input_pass],
1631
+ outputs=[admin_content, input_pass]
 
 
 
 
 
 
1632
  )
1633
 
1634
+ # Sự kiện khi nhấn nút THÊM (giữ nguyên logic cũ của bạn)
1635
  btn_add.click(
1636
  admin_add,
1637
  [admin_code, admin_name, admin_docs, admin_coquan, admin_time, admin_lephi, admin_note, admin_steps],
1638
  [add_output, procedures_list]
1639
  )
1640
 
1641
+ # Memory Tab (mới)
1642
+ with gr.Tab("🧠 Memory Manager"):
1643
+ gr.Markdown("### 📊 Quản lý bộ nhớ hội thoại")
1644
+
1645
+ memory_info = gr.Textbox(label="Ngữ cảnh hiện tại", interactive=False, lines=3)
1646
+ memory_history = gr.Textbox(label="Lịch sử chat", interactive=False, lines=10)
1647
+
1648
+ with gr.Row():
1649
+ btn_refresh = gr.Button("🔄 Làm mới")
1650
+ btn_clear_mem = gr.Button("🗑️ Xóa memory", variant='stop')
1651
+
1652
+ def refresh_memory():
1653
+ ctx = conversation_memory.get_context_summary()
1654
+ hist = "\n".join([f"{m['role']}: {m['content'][:100]}..."
1655
+ for m in conversation_memory.history[-5:]])
1656
+ return ctx or "Không có ngữ cảnh", hist or "Không có lịch sử"
1657
+
1658
+ btn_refresh.click(refresh_memory, [], [memory_info, memory_history])
1659
+ btn_clear_mem.click(clear_chat_pro, [], [chat, audio_out, msg_in])
1660
+
1661
+
1662
+
1663
+
1664
 
1665
  # ======================================================================
1666
+ # ============================================================
1667
+ # PHẦN 12.7: LAUNCH APP PRO
1668
+ # ============================================================
1669
 
1670
  print('='*70)
1671
+ print('🚀 KHỞI ĐỘNG ỨNG DỤNG AI PRO')
1672
  print('='*70)
1673
  print()
1674
 
1675
+
1676
+
1677
  print('='*70)
1678
+ print(' Đang tạo public link...')
1679
+ print(' Link sẽ xuất hiện bên dưới sau vài giây...')
1680
  print('='*70)
1681
  print()
1682
 
1683
+ # Launch với demo_pro thay vì demo
1684
  demo.launch(
1685
  share=True,
1686
  server_name='0.0.0.0',