xuandin commited on
Commit
0be0916
·
verified ·
1 Parent(s): 4ab50fb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +222 -367
app.py CHANGED
@@ -10,18 +10,30 @@ import pandas as pd
10
  import os
11
  import psutil
12
  import gc
13
- import plotly.express as px
14
- import plotly.graph_objects as go
15
- from datetime import datetime
 
 
16
 
17
  # Set environment variables to optimize CPU performance
18
  os.environ["OMP_NUM_THREADS"] = str(psutil.cpu_count(logical=False))
19
  os.environ["MKL_NUM_THREADS"] = str(psutil.cpu_count(logical=False))
 
20
 
21
  # Set device globally
22
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
23
 
24
- @st.cache_resource()
 
 
 
 
 
 
 
 
 
25
  def load_model(model_name, model_class, is_bc=False, device=None):
26
  if device is None:
27
  device = "cuda" if torch.cuda.is_available() else "cpu"
@@ -30,18 +42,44 @@ def load_model(model_name, model_class, is_bc=False, device=None):
30
  model = model_class.from_pretrained(model_name, num_labels=3 if not is_bc else 2)
31
  model.eval()
32
 
 
 
 
 
 
33
  model.to(device)
34
  return tokenizer, model
35
 
36
- @st.cache_data
 
37
  def preprocess_text(text):
38
  # Add any text cleaning or normalization here
39
  return text.strip()
40
 
41
- # Optimized function for evidence extraction and classification with better CPU performance
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  def perform_verification(claim, context, model_qatc, tokenizer_qatc, model_tc, tokenizer_tc,
43
- model_bc, tokenizer_bc, tfidf_threshold, length_ratio_threshold):
44
- # Extract evidence
45
  evidence_start_time = time.time()
46
  evidence = extract_evidence_tfidf_qatc(
47
  claim, context, model_qatc, tokenizer_qatc,
@@ -51,25 +89,25 @@ def perform_verification(claim, context, model_qatc, tokenizer_qatc, model_tc, t
51
  )
52
  evidence_time = time.time() - evidence_start_time
53
 
54
- # Explicit garbage collection after evidence extraction
 
 
55
  gc.collect()
56
 
57
- # Classify the claim
 
 
 
 
 
 
 
58
  verdict_start_time = time.time()
59
  with torch.no_grad():
60
  verdict = "NEI"
61
- prob3class, pred_tc = classify_claim(
62
- claim, evidence, model_tc, tokenizer_tc, DEVICE
63
- )
64
-
65
- # Only run binary classifier if needed
66
- prob2class, pred_bc = 0, 0
67
  if pred_tc != 0:
68
- prob2class, pred_bc = classify_claim(
69
- claim, evidence, model_bc, tokenizer_bc, DEVICE
70
- )
71
  verdict = "SUPPORTED" if pred_bc == 0 else "REFUTED" if prob2class > prob3class else ["NEI", "SUPPORTED", "REFUTED"][pred_tc]
72
-
73
  verdict_time = time.time() - verdict_start_time
74
 
75
  return {
@@ -83,69 +121,19 @@ def perform_verification(claim, context, model_qatc, tokenizer_qatc, model_tc, t
83
  "pred_bc": pred_bc
84
  }
85
 
86
- # Add new functions for analysis
87
- def analyze_verdict_distribution(history):
88
- if not history:
89
- return None
90
-
91
- df = pd.DataFrame(history)
92
- verdict_counts = df['verdict'].value_counts()
93
-
94
- fig = px.pie(
95
- values=verdict_counts.values,
96
- names=verdict_counts.index,
97
- title='Phân bố Kết quả Kiểm chứng',
98
- color_discrete_sequence=['#2ecc71', '#e74c3c', '#f1c40f']
99
- )
100
- return fig
101
-
102
- def analyze_processing_time(history):
103
- if not history:
104
- return None
105
-
106
- df = pd.DataFrame(history)
107
- df['timestamp'] = pd.to_datetime(df['timestamp'])
108
-
109
- fig = px.line(
110
- df,
111
- x='timestamp',
112
- y=['evidence_time', 'verdict_time', 'total_time'],
113
- title='Thời gian Xử lý theo Thời gian',
114
- labels={'value': 'Thời gian (giây)', 'timestamp': 'Thời điểm'}
115
- )
116
- return fig
117
-
118
- def generate_report(result):
119
- report = f"""
120
- BÁO CÁO KIỂM CHỨNG THÔNG TIN
121
- Thời gian: {datetime.now().strftime('%d/%m/%Y %H:%M:%S')}
122
-
123
- 1. THÔNG TIN CƠ BẢN
124
- -------------------
125
- Câu khẳng định: {result['claim']}
126
- Kết luận: {result['verdict']}
127
-
128
- 2. BẰNG CHỨNG
129
- -------------
130
- {result['evidence']}
131
-
132
- 3. THỐNG KÊ THỜI GIAN
133
- ---------------------
134
- - Thời gian trích xuất bằng chứng: {result['evidence_time']:.2f} giây
135
- - Thời gian phân loại: {result['verdict_time']:.2f} giây
136
- - Tổng thời gian xử lý: {result['total_time']:.2f} giây
137
-
138
- 4. CHI TIẾT KỸ THUẬT
139
- -------------------
140
- {result['details']}
141
-
142
- 5. MÔ HÌNH SỬ DỤNG
143
- ------------------
144
- - QATC Model: {result['qatc_model']}
145
- - Binary Classification Model: {result['bc_model']}
146
- - 3-Class Classification Model: {result['tc_model']}
147
- """
148
- return report
149
 
150
  # Set page configuration
151
  st.set_page_config(
@@ -160,295 +148,195 @@ st.markdown("""
160
  <style>
161
  /* Main theme colors */
162
  :root {
163
- --primary-color: #2c3e50;
164
- --secondary-color: #3498db;
165
  --accent-color: #e74c3c;
166
- --success-color: #2ecc71;
167
- --warning-color: #f1c40f;
168
  --background-color: #f8f9fa;
169
  --text-color: #2c3e50;
170
  --border-color: #e0e0e0;
171
- --gradient-start: #2c3e50;
172
- --gradient-end: #3498db;
173
  }
174
 
175
  /* General styling */
176
  .stApp {
177
  background-color: var(--background-color);
178
  color: var(--text-color);
179
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
180
  }
181
 
182
  /* Header styling */
183
  .main-header {
184
- background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end));
185
  color: white;
186
- padding: 3rem 2rem;
187
- border-radius: 15px;
188
  margin-bottom: 2rem;
189
- box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
190
- position: relative;
191
- overflow: hidden;
192
- }
193
-
194
- .main-header::before {
195
- content: '';
196
- position: absolute;
197
- top: 0;
198
- left: 0;
199
- right: 0;
200
- bottom: 0;
201
- background: url('data:image/svg+xml,<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><rect width="1" height="1" fill="rgba(255,255,255,0.05)"/></svg>');
202
- opacity: 0.1;
203
  }
204
 
205
  .main-title {
206
- font-size: 3rem;
207
- font-weight: 800;
208
  text-align: center;
209
  margin-bottom: 1rem;
210
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
211
- letter-spacing: 1px;
212
  }
213
 
214
  .sub-title {
215
- font-size: 1.4rem;
216
  text-align: center;
217
  opacity: 0.9;
218
- font-weight: 300;
219
  }
220
 
221
  /* Input styling */
222
  .stTextArea textarea {
223
  border: 2px solid var(--border-color);
224
- border-radius: 12px;
225
- padding: 1.2rem;
226
- font-size: 1.1rem;
227
  min-height: 150px;
228
  background-color: white;
229
- transition: all 0.3s ease;
230
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
231
- }
232
-
233
- .stTextArea textarea:focus {
234
- border-color: var(--secondary-color);
235
- box-shadow: 0 4px 8px rgba(52, 152, 219, 0.1);
236
  }
237
 
238
  /* Button styling */
239
  .stButton>button {
240
- background: linear-gradient(135deg, var(--secondary-color), var(--primary-color));
241
  color: white;
242
  border: none;
243
- border-radius: 12px;
244
- padding: 1rem 2.5rem;
245
- font-size: 1.2rem;
246
- font-weight: 600;
247
  transition: all 0.3s ease;
248
- text-transform: uppercase;
249
- letter-spacing: 1px;
250
  }
251
 
252
  .stButton>button:hover {
253
  transform: translateY(-2px);
254
- box-shadow: 0 8px 16px rgba(52, 152, 219, 0.2);
255
  }
256
 
257
  /* Result box styling */
258
  .result-box {
259
  background-color: white;
260
- border-radius: 15px;
261
- padding: 2.5rem;
262
- margin: 1.5rem 0;
263
- box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
264
- transition: all 0.3s ease;
265
- border: 1px solid rgba(0, 0, 0, 0.05);
266
  }
267
 
268
- .result-box:hover {
269
- transform: translateY(-2px);
270
- box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  }
272
 
273
  .verdict {
274
- font-size: 2rem;
275
- font-weight: 800;
276
- padding: 1.5rem;
277
- border-radius: 12px;
278
- margin: 1.5rem 0;
279
  text-align: center;
280
- transition: all 0.3s ease;
281
  }
282
 
283
  .verdict-supported {
284
- background: linear-gradient(135deg, #2ecc71, #27ae60);
285
- color: white;
286
- box-shadow: 0 4px 8px rgba(46, 204, 113, 0.2);
287
  }
288
 
289
  .verdict-refuted {
290
- background: linear-gradient(135deg, #e74c3c, #c0392b);
291
- color: white;
292
- box-shadow: 0 4px 8px rgba(231, 76, 60, 0.2);
293
  }
294
 
295
  .verdict-nei {
296
- background: linear-gradient(135deg, #f1c40f, #f39c12);
297
- color: white;
298
- box-shadow: 0 4px 8px rgba(241, 196, 15, 0.2);
299
  }
300
 
301
  /* Sidebar styling */
302
  .css-1d391kg {
303
  background-color: white;
304
- padding: 2.5rem;
305
- border-radius: 15px;
306
- box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
307
  }
308
 
309
  /* Stats box styling */
310
  .stats-box {
311
- background: linear-gradient(135deg, #f8f9fa, #e9ecef);
312
- border-radius: 12px;
313
- padding: 1.5rem;
314
- margin: 1rem 0;
315
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
316
  }
317
 
318
  /* Code block styling */
319
  .code-block {
320
- background-color: #2c3e50;
321
- border-radius: 12px;
322
- padding: 1.5rem;
323
- font-family: 'Fira Code', monospace;
324
- margin: 1.5rem 0;
325
- color: #ecf0f1;
326
- overflow-x: auto;
327
  }
328
 
329
  /* Tab styling */
330
  .stTabs [data-baseweb="tab-list"] {
331
  gap: 2rem;
332
- background-color: transparent;
333
  }
334
 
335
  .stTabs [data-baseweb="tab"] {
336
  background-color: white;
337
- border-radius: 12px;
338
- padding: 0.8rem 1.5rem;
339
  margin: 0 0.5rem;
340
- font-weight: 600;
341
- transition: all 0.3s ease;
342
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
343
  }
344
 
345
  .stTabs [aria-selected="true"] {
346
- background: linear-gradient(135deg, var(--secondary-color), var(--primary-color));
347
- color: white;
348
- box-shadow: 0 4px 8px rgba(52, 152, 219, 0.2);
349
- }
350
-
351
- /* Analysis box styling */
352
- .analysis-box {
353
- background-color: white;
354
- border-radius: 15px;
355
- padding: 2rem;
356
- margin: 1.5rem 0;
357
- box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
358
- border-left: 4px solid var(--secondary-color);
359
- }
360
-
361
- /* Search box styling */
362
- .search-box {
363
- background-color: white;
364
- border-radius: 12px;
365
- padding: 1.5rem;
366
- margin-bottom: 1.5rem;
367
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
368
- }
369
-
370
- /* Comparison box styling */
371
- .comparison-box {
372
- background-color: white;
373
- border-radius: 15px;
374
- padding: 2rem;
375
- margin: 1.5rem 0;
376
- box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
377
- border-left: 4px solid var(--secondary-color);
378
- }
379
-
380
- /* Selectbox styling */
381
- .stSelectbox select {
382
- border-radius: 8px;
383
- padding: 0.8rem;
384
- font-size: 1rem;
385
- border: 2px solid var(--border-color);
386
- background-color: white;
387
- transition: all 0.3s ease;
388
- }
389
-
390
- .stSelectbox select:focus {
391
- border-color: var(--secondary-color);
392
- box-shadow: 0 4px 8px rgba(52, 152, 219, 0.1);
393
- }
394
-
395
- /* Slider styling */
396
- .stSlider > div > div {
397
- background-color: var(--secondary-color);
398
- }
399
-
400
- /* Checkbox styling */
401
- .stCheckbox > label {
402
- font-weight: 500;
403
- }
404
-
405
- /* Info box styling */
406
- .info-box {
407
- background: linear-gradient(135deg, #f8f9fa, #e9ecef);
408
- border-radius: 15px;
409
- padding: 2rem;
410
- margin: 1.5rem 0;
411
- box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
412
- }
413
-
414
- /* Chart container styling */
415
- .js-plotly-plot {
416
- border-radius: 12px !important;
417
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05) !important;
418
- }
419
-
420
- /* Dataframe styling */
421
- .dataframe {
422
- border-radius: 12px;
423
- overflow: hidden;
424
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
425
- }
426
-
427
- .dataframe thead th {
428
  background-color: var(--primary-color);
429
  color: white;
430
  }
431
-
432
- /* Download button styling */
433
- .stDownloadButton > button {
434
- background: linear-gradient(135deg, var(--success-color), #27ae60);
435
- color: white;
436
- border: none;
437
- border-radius: 12px;
438
- padding: 0.8rem 2rem;
439
- font-size: 1.1rem;
440
- font-weight: 600;
441
- transition: all 0.3s ease;
442
- }
443
-
444
- .stDownloadButton > button:hover {
445
- transform: translateY(-2px);
446
- box-shadow: 0 4px 8px rgba(46, 204, 113, 0.2);
447
- }
448
  </style>
449
  """, unsafe_allow_html=True)
450
 
451
- # Main header with updated design
452
  st.markdown("""
453
  <div class="main-header">
454
  <div class="main-title">SemViQA</div>
@@ -456,15 +344,11 @@ st.markdown("""
456
  </div>
457
  """, unsafe_allow_html=True)
458
 
459
- # Sidebar with updated design
460
  with st.sidebar:
461
- st.markdown("""
462
- <div class="info-box">
463
- <h3>⚙️ Cài đặt Hệ thống</h3>
464
- </div>
465
- """, unsafe_allow_html=True)
466
 
467
- # Model selection with updated styling
468
  st.markdown("#### 🧠 Chọn Mô hình")
469
  qatc_model_name = st.selectbox(
470
  "Mô hình QATC",
@@ -500,7 +384,7 @@ with st.sidebar:
500
  ]
501
  )
502
 
503
- # Threshold settings with updated styling
504
  st.markdown("#### ⚖️ Ngưỡng Phân tích")
505
  tfidf_threshold = st.slider(
506
  "Ngưỡng TF-IDF",
@@ -514,7 +398,7 @@ with st.sidebar:
514
  help="Điều chỉnh độ dài tối đa của bằng chứng"
515
  )
516
 
517
- # Display settings with updated styling
518
  st.markdown("#### 👁️ Hiển thị")
519
  show_details = st.checkbox(
520
  "Hiển thị Chi tiết Xác suất",
@@ -522,7 +406,7 @@ with st.sidebar:
522
  help="Hiển thị thông tin chi tiết về xác suất dự đoán"
523
  )
524
 
525
- # Performance settings with updated styling
526
  st.markdown("#### ⚡ Hiệu suất")
527
  num_threads = st.slider(
528
  "Số luồng CPU",
@@ -534,7 +418,7 @@ with st.sidebar:
534
  os.environ["MKL_NUM_THREADS"] = str(num_threads)
535
 
536
  # Main content
537
- tabs = st.tabs(["🔍 Kiểm chứng", "📊 Lịch sử", "📈 Phân tích", "ℹ️ Thông tin"])
538
 
539
  tokenizer_qatc, model_qatc = load_model(qatc_model_name, QATCForQuestionAnswering, device=DEVICE)
540
  tokenizer_bc, model_bc = load_model(bc_model_name, ClaimModelForClassification, is_bc=True, device=DEVICE)
@@ -575,8 +459,14 @@ with tabs[0]:
575
 
576
  # Clear memory and perform verification
577
  gc.collect()
 
 
 
578
  start_time = time.time()
579
 
 
 
 
580
  result = perform_verification(
581
  preprocessed_claim, preprocessed_context,
582
  model_qatc, tokenizer_qatc,
@@ -587,6 +477,9 @@ with tabs[0]:
587
 
588
  total_time = time.time() - start_time
589
 
 
 
 
590
  # Format details
591
  details = ""
592
  if show_details:
@@ -595,9 +488,15 @@ with tabs[0]:
595
  3-Class Predicted Label: {['NEI', 'SUPPORTED', 'REFUTED'][result['pred_tc']]}
596
  2-Class Probability: {result['prob2class']:.2f}
597
  2-Class Predicted Label: {['SUPPORTED', 'REFUTED'][result['pred_bc']] if isinstance(result['pred_bc'], int) and result['pred_tc'] != 0 else 'Not used'}
 
 
 
 
 
 
598
  """
599
 
600
- # Store result
601
  st.session_state.latest_result = {
602
  "claim": claim,
603
  "evidence": result['evidence'],
@@ -608,7 +507,8 @@ with tabs[0]:
608
  "details": details,
609
  "qatc_model": qatc_model_name,
610
  "bc_model": bc_model_name,
611
- "tc_model": tc_model_name
 
612
  }
613
 
614
  # Add to history
@@ -616,7 +516,7 @@ with tabs[0]:
616
  st.session_state.history = []
617
  st.session_state.history.append(st.session_state.latest_result)
618
 
619
- # Display result
620
  res = st.session_state.latest_result
621
  verdict_class = {
622
  "SUPPORTED": "verdict-supported",
@@ -636,13 +536,29 @@ with tabs[0]:
636
  <p><strong>Thời gian trích xuất bằng chứng:</strong> {res['evidence_time']:.2f} giây</p>
637
  <p><strong>Thời gian phân loại:</strong> {res['verdict_time']:.2f} giây</p>
638
  <p><strong>Tổng thời gian:</strong> {res['total_time']:.2f} giây</p>
 
 
 
 
 
 
639
  </div>
640
  {f"<div class='code-block'><pre>{res['details']}</pre></div>" if show_details else ""}
641
  </div>
642
  """, unsafe_allow_html=True)
643
 
644
- # Download button
645
- result_text = f"Câu khẳng định: {res['claim']}\nBằng chứng: {res['evidence']}\nKết luận: {res['verdict']}\nChi tiết: {res['details']}"
 
 
 
 
 
 
 
 
 
 
646
  st.download_button(
647
  "📥 Tải kết quả",
648
  data=result_text,
@@ -655,22 +571,9 @@ with tabs[0]:
655
  # --- Tab History ---
656
  with tabs[1]:
657
  st.markdown("### 📊 Lịch sử Kiểm chứng")
658
-
659
- # Add search functionality
660
- search_query = st.text_input("🔍 Tìm kiếm trong lịch sử", "")
661
-
662
  if 'history' in st.session_state and st.session_state.history:
663
- # Filter history based on search query
664
- filtered_history = st.session_state.history
665
- if search_query:
666
- filtered_history = [
667
- record for record in st.session_state.history
668
- if search_query.lower() in record['claim'].lower() or
669
- search_query.lower() in record['evidence'].lower()
670
- ]
671
-
672
  # Download full history
673
- history_df = pd.DataFrame(filtered_history)
674
  st.download_button(
675
  "📥 Tải toàn bộ lịch sử",
676
  data=history_df.to_csv(index=False).encode('utf-8'),
@@ -678,63 +581,23 @@ with tabs[1]:
678
  mime="text/csv"
679
  )
680
 
681
- # Display history with comparison option
682
- for idx, record in enumerate(reversed(filtered_history), 1):
683
- col1, col2 = st.columns([3, 1])
684
-
685
- with col1:
686
- st.markdown(f"""
687
- <div class="result-box">
688
- <h4>Kiểm chứng #{idx}</h4>
689
- <p><strong>Câu khẳng định:</strong> {record['claim']}</p>
690
- <p><strong>Kết luận:</strong> {verdict_icons.get(record['verdict'], '')} {record['verdict']}</p>
691
- <p><strong>Thời gian:</strong> {record['total_time']:.2f} giây</p>
692
- </div>
693
- """, unsafe_allow_html=True)
694
-
695
- with col2:
696
- if st.button("🔄 So sánh", key=f"compare_{idx}"):
697
- st.session_state.selected_for_comparison = record
698
-
699
- # --- Tab Analysis ---
700
- with tabs[2]:
701
- st.markdown("### 📈 Phân tích Chi tiết")
702
-
703
- if 'history' in st.session_state and st.session_state.history:
704
- # Add timestamp to history records
705
- for record in st.session_state.history:
706
- if 'timestamp' not in record:
707
- record['timestamp'] = datetime.now()
708
-
709
- # Distribution analysis
710
- st.markdown("#### 📊 Phân bố Kết quả")
711
- verdict_fig = analyze_verdict_distribution(st.session_state.history)
712
- if verdict_fig:
713
- st.plotly_chart(verdict_fig, use_container_width=True)
714
-
715
- # Processing time analysis
716
- st.markdown("#### ⏱️ Phân tích Thời gian Xử lý")
717
- time_fig = analyze_processing_time(st.session_state.history)
718
- if time_fig:
719
- st.plotly_chart(time_fig, use_container_width=True)
720
-
721
- # Model performance analysis
722
- st.markdown("#### 🧠 Phân tích Hiệu suất Mô hình")
723
- model_stats = pd.DataFrame(st.session_state.history)
724
- if not model_stats.empty:
725
- st.markdown("##### Thống kê theo Mô hình")
726
- model_performance = model_stats.groupby(['qatc_model', 'bc_model', 'tc_model']).agg({
727
- 'total_time': ['mean', 'count'],
728
- 'verdict': lambda x: (x == 'SUPPORTED').mean()
729
- }).round(2)
730
- st.dataframe(model_performance)
731
  else:
732
- st.info("Chưa có dữ liệu để phân tích.")
733
 
734
  # --- Tab Info ---
735
- with tabs[3]:
736
  st.markdown("""
737
- <div class="result-box">
738
  <h3>ℹ️ Thông tin về SemViQA</h3>
739
  <p>SemViQA là hệ thống kiểm chứng thông tin tự động cho tiếng Việt, được phát triển bởi nhóm nghiên cứu tại Đại học Công nghệ Thông tin - Đại học Quốc gia TP.HCM.</p>
740
 
@@ -759,13 +622,5 @@ with tabs[3]:
759
  <li><strong>REFUTED:</strong> Câu khẳng định bị bác bỏ bởi bằng chứng</li>
760
  <li><strong>NEI:</strong> Không đủ bằng chứng để kết luận</li>
761
  </ul>
762
-
763
- <h4>🆕 Tính năng Mới</h4>
764
- <ul>
765
- <li><strong>Phân tích Chi tiết:</strong> Xem thống kê và biểu đồ về kết quả kiểm chứng</li>
766
- <li><strong>Tìm kiếm Lịch sử:</strong> Dễ dàng tìm kiếm trong lịch sử kiểm chứng</li>
767
- <li><strong>So sánh Kết quả:</strong> So sánh các kết quả kiểm chứng với nhau</li>
768
- <li><strong>Báo cáo Chi tiết:</strong> Xuất báo cáo chi tiết về kết quả kiểm chứng</li>
769
- </ul>
770
  </div>
771
  """, unsafe_allow_html=True)
 
10
  import os
11
  import psutil
12
  import gc
13
+ import numpy as np
14
+ from functools import lru_cache
15
+ import threading
16
+ from concurrent.futures import ThreadPoolExecutor
17
+ import torch.nn.functional as F
18
 
19
  # Set environment variables to optimize CPU performance
20
  os.environ["OMP_NUM_THREADS"] = str(psutil.cpu_count(logical=False))
21
  os.environ["MKL_NUM_THREADS"] = str(psutil.cpu_count(logical=False))
22
+ torch.set_num_threads(psutil.cpu_count(logical=False))
23
 
24
  # Set device globally
25
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
26
 
27
+ # Cache for model outputs
28
+ @lru_cache(maxsize=1000)
29
+ def cached_classify_claim(claim, evidence, model_name, is_bc=False):
30
+ tokenizer, model = load_model(model_name, ClaimModelForClassification, is_bc=is_bc, device=DEVICE)
31
+ with torch.no_grad():
32
+ prob, pred = classify_claim(claim, evidence, model, tokenizer, DEVICE)
33
+ return prob, pred
34
+
35
+ # Optimized model loading with caching
36
+ @st.cache_resource(ttl=3600) # Cache for 1 hour
37
  def load_model(model_name, model_class, is_bc=False, device=None):
38
  if device is None:
39
  device = "cuda" if torch.cuda.is_available() else "cpu"
 
42
  model = model_class.from_pretrained(model_name, num_labels=3 if not is_bc else 2)
43
  model.eval()
44
 
45
+ # Optimize model for inference
46
+ if device == "cuda":
47
+ model = model.half() # Use FP16 for faster inference
48
+ torch.cuda.empty_cache()
49
+
50
  model.to(device)
51
  return tokenizer, model
52
 
53
+ # Optimized text preprocessing
54
+ @st.cache_data(ttl=3600)
55
  def preprocess_text(text):
56
  # Add any text cleaning or normalization here
57
  return text.strip()
58
 
59
+ # Batch processing for evidence extraction
60
+ def batch_extract_evidence(claims, contexts, model_qatc, tokenizer_qatc, batch_size=4):
61
+ results = []
62
+ for i in range(0, len(claims), batch_size):
63
+ batch_claims = claims[i:i + batch_size]
64
+ batch_contexts = contexts[i:i + batch_size]
65
+
66
+ with torch.no_grad():
67
+ batch_results = [
68
+ extract_evidence_tfidf_qatc(
69
+ claim, context, model_qatc, tokenizer_qatc,
70
+ DEVICE,
71
+ confidence_threshold=0.5,
72
+ length_ratio_threshold=0.5
73
+ )
74
+ for claim, context in zip(batch_claims, batch_contexts)
75
+ ]
76
+ results.extend(batch_results)
77
+ return results
78
+
79
+ # Optimized verification function with parallel processing
80
  def perform_verification(claim, context, model_qatc, tokenizer_qatc, model_tc, tokenizer_tc,
81
+ model_bc, tokenizer_bc, tfidf_threshold, length_ratio_threshold):
82
+ # Extract evidence with optimized settings
83
  evidence_start_time = time.time()
84
  evidence = extract_evidence_tfidf_qatc(
85
  claim, context, model_qatc, tokenizer_qatc,
 
89
  )
90
  evidence_time = time.time() - evidence_start_time
91
 
92
+ # Clear memory after evidence extraction
93
+ if DEVICE == "cuda":
94
+ torch.cuda.empty_cache()
95
  gc.collect()
96
 
97
+ # Parallel classification using ThreadPoolExecutor
98
+ with ThreadPoolExecutor(max_workers=2) as executor:
99
+ future_tc = executor.submit(cached_classify_claim, claim, evidence, tc_model_name, False)
100
+ future_bc = executor.submit(cached_classify_claim, claim, evidence, bc_model_name, True)
101
+
102
+ prob3class, pred_tc = future_tc.result()
103
+ prob2class, pred_bc = future_bc.result()
104
+
105
  verdict_start_time = time.time()
106
  with torch.no_grad():
107
  verdict = "NEI"
 
 
 
 
 
 
108
  if pred_tc != 0:
 
 
 
109
  verdict = "SUPPORTED" if pred_bc == 0 else "REFUTED" if prob2class > prob3class else ["NEI", "SUPPORTED", "REFUTED"][pred_tc]
110
+
111
  verdict_time = time.time() - verdict_start_time
112
 
113
  return {
 
121
  "pred_bc": pred_bc
122
  }
123
 
124
+ # Add performance monitoring
125
+ def monitor_performance():
126
+ if DEVICE == "cuda":
127
+ return {
128
+ "gpu_memory_used": torch.cuda.memory_allocated() / 1024**2,
129
+ "gpu_memory_cached": torch.cuda.memory_reserved() / 1024**2,
130
+ "cpu_percent": psutil.cpu_percent(),
131
+ "memory_percent": psutil.virtual_memory().percent
132
+ }
133
+ return {
134
+ "cpu_percent": psutil.cpu_percent(),
135
+ "memory_percent": psutil.virtual_memory().percent
136
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
  # Set page configuration
139
  st.set_page_config(
 
148
  <style>
149
  /* Main theme colors */
150
  :root {
151
+ --primary-color: #1f77b4;
152
+ --secondary-color: #2c3e50;
153
  --accent-color: #e74c3c;
 
 
154
  --background-color: #f8f9fa;
155
  --text-color: #2c3e50;
156
  --border-color: #e0e0e0;
 
 
157
  }
158
 
159
  /* General styling */
160
  .stApp {
161
  background-color: var(--background-color);
162
  color: var(--text-color);
 
163
  }
164
 
165
  /* Header styling */
166
  .main-header {
167
+ background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
168
  color: white;
169
+ padding: 2rem;
170
+ border-radius: 10px;
171
  margin-bottom: 2rem;
172
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  }
174
 
175
  .main-title {
176
+ font-size: 2.5rem;
177
+ font-weight: bold;
178
  text-align: center;
179
  margin-bottom: 1rem;
 
 
180
  }
181
 
182
  .sub-title {
183
+ font-size: 1.2rem;
184
  text-align: center;
185
  opacity: 0.9;
 
186
  }
187
 
188
  /* Input styling */
189
  .stTextArea textarea {
190
  border: 2px solid var(--border-color);
191
+ border-radius: 8px;
192
+ padding: 1rem;
193
+ font-size: 1rem;
194
  min-height: 150px;
195
  background-color: white;
 
 
 
 
 
 
 
196
  }
197
 
198
  /* Button styling */
199
  .stButton>button {
200
+ background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
201
  color: white;
202
  border: none;
203
+ border-radius: 8px;
204
+ padding: 0.8rem 2rem;
205
+ font-size: 1.1rem;
206
+ font-weight: bold;
207
  transition: all 0.3s ease;
 
 
208
  }
209
 
210
  .stButton>button:hover {
211
  transform: translateY(-2px);
212
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
213
  }
214
 
215
  /* Result box styling */
216
  .result-box {
217
  background-color: white;
218
+ border-radius: 12px;
219
+ padding: 2rem;
220
+ margin: 1rem 0;
221
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
 
 
222
  }
223
 
224
+ /* Info section styling */
225
+ .info-section {
226
+ background-color: white;
227
+ border-radius: 12px;
228
+ padding: 2rem;
229
+ margin: 1rem 0;
230
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
231
+ }
232
+
233
+ .info-section h3 {
234
+ color: var(--primary-color);
235
+ font-size: 1.8rem;
236
+ margin-bottom: 1.5rem;
237
+ border-bottom: 2px solid var(--border-color);
238
+ padding-bottom: 0.5rem;
239
+ }
240
+
241
+ .info-section h4 {
242
+ color: var(--secondary-color);
243
+ font-size: 1.4rem;
244
+ margin: 1.5rem 0 1rem 0;
245
+ }
246
+
247
+ .info-section p {
248
+ font-size: 1.1rem;
249
+ line-height: 1.6;
250
+ color: var(--text-color);
251
+ margin-bottom: 1.5rem;
252
+ }
253
+
254
+ .info-section ol, .info-section ul {
255
+ margin-left: 1.5rem;
256
+ margin-bottom: 1.5rem;
257
+ }
258
+
259
+ .info-section li {
260
+ font-size: 1.1rem;
261
+ line-height: 1.6;
262
+ margin-bottom: 0.5rem;
263
+ }
264
+
265
+ .info-section strong {
266
+ color: var(--primary-color);
267
  }
268
 
269
  .verdict {
270
+ font-size: 1.8rem;
271
+ font-weight: bold;
272
+ padding: 1rem;
273
+ border-radius: 8px;
274
+ margin: 1rem 0;
275
  text-align: center;
 
276
  }
277
 
278
  .verdict-supported {
279
+ background-color: #d4edda;
280
+ color: #155724;
 
281
  }
282
 
283
  .verdict-refuted {
284
+ background-color: #f8d7da;
285
+ color: #721c24;
 
286
  }
287
 
288
  .verdict-nei {
289
+ background-color: #fff3cd;
290
+ color: #856404;
 
291
  }
292
 
293
  /* Sidebar styling */
294
  .css-1d391kg {
295
  background-color: white;
296
+ padding: 2rem;
297
+ border-radius: 12px;
298
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
299
  }
300
 
301
  /* Stats box styling */
302
  .stats-box {
303
+ background-color: white;
304
+ border-radius: 8px;
305
+ padding: 1rem;
306
+ margin: 0.5rem 0;
307
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
308
  }
309
 
310
  /* Code block styling */
311
  .code-block {
312
+ background-color: #f8f9fa;
313
+ border: 1px solid var(--border-color);
314
+ border-radius: 8px;
315
+ padding: 1rem;
316
+ font-family: monospace;
317
+ margin: 1rem 0;
 
318
  }
319
 
320
  /* Tab styling */
321
  .stTabs [data-baseweb="tab-list"] {
322
  gap: 2rem;
 
323
  }
324
 
325
  .stTabs [data-baseweb="tab"] {
326
  background-color: white;
327
+ border-radius: 8px;
328
+ padding: 0.5rem 1rem;
329
  margin: 0 0.5rem;
 
 
 
330
  }
331
 
332
  .stTabs [aria-selected="true"] {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
  background-color: var(--primary-color);
334
  color: white;
335
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
336
  </style>
337
  """, unsafe_allow_html=True)
338
 
339
+ # Main header
340
  st.markdown("""
341
  <div class="main-header">
342
  <div class="main-title">SemViQA</div>
 
344
  </div>
345
  """, unsafe_allow_html=True)
346
 
347
+ # Sidebar
348
  with st.sidebar:
349
+ st.markdown("### ⚙️ Cài đặt Hệ thống")
 
 
 
 
350
 
351
+ # Model selection
352
  st.markdown("#### 🧠 Chọn Mô hình")
353
  qatc_model_name = st.selectbox(
354
  "Mô hình QATC",
 
384
  ]
385
  )
386
 
387
+ # Threshold settings
388
  st.markdown("#### ⚖️ Ngưỡng Phân tích")
389
  tfidf_threshold = st.slider(
390
  "Ngưỡng TF-IDF",
 
398
  help="Điều chỉnh độ dài tối đa của bằng chứng"
399
  )
400
 
401
+ # Display settings
402
  st.markdown("#### 👁️ Hiển thị")
403
  show_details = st.checkbox(
404
  "Hiển thị Chi tiết Xác suất",
 
406
  help="Hiển thị thông tin chi tiết về xác suất dự đoán"
407
  )
408
 
409
+ # Performance settings
410
  st.markdown("#### ⚡ Hiệu suất")
411
  num_threads = st.slider(
412
  "Số luồng CPU",
 
418
  os.environ["MKL_NUM_THREADS"] = str(num_threads)
419
 
420
  # Main content
421
+ tabs = st.tabs(["🔍 Kiểm chứng", "📊 Lịch sử", "ℹ️ Thông tin"])
422
 
423
  tokenizer_qatc, model_qatc = load_model(qatc_model_name, QATCForQuestionAnswering, device=DEVICE)
424
  tokenizer_bc, model_bc = load_model(bc_model_name, ClaimModelForClassification, is_bc=True, device=DEVICE)
 
459
 
460
  # Clear memory and perform verification
461
  gc.collect()
462
+ if DEVICE == "cuda":
463
+ torch.cuda.empty_cache()
464
+
465
  start_time = time.time()
466
 
467
+ # Monitor initial performance
468
+ initial_perf = monitor_performance()
469
+
470
  result = perform_verification(
471
  preprocessed_claim, preprocessed_context,
472
  model_qatc, tokenizer_qatc,
 
477
 
478
  total_time = time.time() - start_time
479
 
480
+ # Monitor final performance
481
+ final_perf = monitor_performance()
482
+
483
  # Format details
484
  details = ""
485
  if show_details:
 
488
  3-Class Predicted Label: {['NEI', 'SUPPORTED', 'REFUTED'][result['pred_tc']]}
489
  2-Class Probability: {result['prob2class']:.2f}
490
  2-Class Predicted Label: {['SUPPORTED', 'REFUTED'][result['pred_bc']] if isinstance(result['pred_bc'], int) and result['pred_tc'] != 0 else 'Not used'}
491
+
492
+ Performance Metrics:
493
+ - GPU Memory Used: {final_perf.get('gpu_memory_used', 'N/A'):.2f} MB
494
+ - GPU Memory Cached: {final_perf.get('gpu_memory_cached', 'N/A'):.2f} MB
495
+ - CPU Usage: {final_perf['cpu_percent']}%
496
+ - Memory Usage: {final_perf['memory_percent']}%
497
  """
498
 
499
+ # Store result with performance metrics
500
  st.session_state.latest_result = {
501
  "claim": claim,
502
  "evidence": result['evidence'],
 
507
  "details": details,
508
  "qatc_model": qatc_model_name,
509
  "bc_model": bc_model_name,
510
+ "tc_model": tc_model_name,
511
+ "performance_metrics": final_perf
512
  }
513
 
514
  # Add to history
 
516
  st.session_state.history = []
517
  st.session_state.history.append(st.session_state.latest_result)
518
 
519
+ # Display result with performance metrics
520
  res = st.session_state.latest_result
521
  verdict_class = {
522
  "SUPPORTED": "verdict-supported",
 
536
  <p><strong>Thời gian trích xuất bằng chứng:</strong> {res['evidence_time']:.2f} giây</p>
537
  <p><strong>Thời gian phân loại:</strong> {res['verdict_time']:.2f} giây</p>
538
  <p><strong>Tổng thời gian:</strong> {res['total_time']:.2f} giây</p>
539
+ <p><strong>Hiệu suất:</strong></p>
540
+ <ul>
541
+ <li>CPU: {res['performance_metrics']['cpu_percent']}%</li>
542
+ <li>RAM: {res['performance_metrics']['memory_percent']}%</li>
543
+ {f"<li>GPU Memory: {res['performance_metrics'].get('gpu_memory_used', 'N/A'):.2f} MB</li>" if DEVICE == "cuda" else ""}
544
+ </ul>
545
  </div>
546
  {f"<div class='code-block'><pre>{res['details']}</pre></div>" if show_details else ""}
547
  </div>
548
  """, unsafe_allow_html=True)
549
 
550
+ # Download button with performance metrics
551
+ result_text = f"""
552
+ Câu khẳng định: {res['claim']}
553
+ Bằng chứng: {res['evidence']}
554
+ Kết luận: {res['verdict']}
555
+ Chi tiết: {res['details']}
556
+
557
+ Hiệu suất:
558
+ - CPU: {res['performance_metrics']['cpu_percent']}%
559
+ - RAM: {res['performance_metrics']['memory_percent']}%
560
+ {f"- GPU Memory: {res['performance_metrics'].get('gpu_memory_used', 'N/A'):.2f} MB" if DEVICE == "cuda" else ""}
561
+ """
562
  st.download_button(
563
  "📥 Tải kết quả",
564
  data=result_text,
 
571
  # --- Tab History ---
572
  with tabs[1]:
573
  st.markdown("### 📊 Lịch sử Kiểm chứng")
 
 
 
 
574
  if 'history' in st.session_state and st.session_state.history:
 
 
 
 
 
 
 
 
 
575
  # Download full history
576
+ history_df = pd.DataFrame(st.session_state.history)
577
  st.download_button(
578
  "📥 Tải toàn bộ lịch sử",
579
  data=history_df.to_csv(index=False).encode('utf-8'),
 
581
  mime="text/csv"
582
  )
583
 
584
+ # Display history
585
+ for idx, record in enumerate(reversed(st.session_state.history), 1):
586
+ st.markdown(f"""
587
+ <div class="result-box">
588
+ <h4>Kiểm chứng #{idx}</h4>
589
+ <p><strong>Câu khẳng định:</strong> {record['claim']}</p>
590
+ <p><strong>Kết luận:</strong> {verdict_icons.get(record['verdict'], '')} {record['verdict']}</p>
591
+ <p><strong>Thời gian:</strong> {record['total_time']:.2f} giây</p>
592
+ </div>
593
+ """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
594
  else:
595
+ st.info("Chưa có lịch sử kiểm chứng.")
596
 
597
  # --- Tab Info ---
598
+ with tabs[2]:
599
  st.markdown("""
600
+ <div class="info-section">
601
  <h3>ℹ️ Thông tin về SemViQA</h3>
602
  <p>SemViQA là hệ thống kiểm chứng thông tin tự động cho tiếng Việt, được phát triển bởi nhóm nghiên cứu tại Đại học Công nghệ Thông tin - Đại học Quốc gia TP.HCM.</p>
603
 
 
622
  <li><strong>REFUTED:</strong> Câu khẳng định bị bác bỏ bởi bằng chứng</li>
623
  <li><strong>NEI:</strong> Không đủ bằng chứng để kết luận</li>
624
  </ul>
 
 
 
 
 
 
 
 
625
  </div>
626
  """, unsafe_allow_html=True)