xuandin commited on
Commit
6fc23f1
·
verified ·
1 Parent(s): 15a70bc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +351 -338
app.py CHANGED
@@ -10,8 +10,6 @@ import pandas as pd
10
  import os
11
  import psutil
12
  import gc
13
- import threading
14
- from queue import Queue
15
 
16
  # Set environment variables to optimize CPU performance
17
  os.environ["OMP_NUM_THREADS"] = str(psutil.cpu_count(logical=False))
@@ -20,391 +18,406 @@ os.environ["MKL_NUM_THREADS"] = str(psutil.cpu_count(logical=False))
20
  # Set device globally
21
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
22
 
23
- # Load models with caching and CPU optimization
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"
28
-
29
- tokenizer = AutoTokenizer.from_pretrained(model_name)
30
- model = model_class.from_pretrained(model_name, num_labels=3 if not is_bc else 2)
31
- model.eval()
32
-
33
- # CPU-specific optimizations
34
- if device == "cpu":
35
- # Use torch's quantization for CPU inference speed boost
36
- try:
37
- import torch.quantization
38
- # Quantize the model to INT8
39
- model = torch.quantization.quantize_dynamic(
40
- model, {torch.nn.Linear}, dtype=torch.qint8
41
- )
42
- except Exception as e:
43
- st.warning(f"Quantization failed, using default model: {e}")
44
-
45
- model.to(device)
46
- return tokenizer, model
47
-
48
- # Pre-process text function to avoid doing it multiple times
49
- @st.cache_data
50
- def preprocess_text(text):
51
- # Add any text cleaning or normalization here
52
- return text.strip()
53
-
54
- # Function to extract evidence in a separate thread for better CPU utilization
55
- def extract_evidence_threaded(queue, claim, context, model_qatc, tokenizer_qatc, device,
56
- tfidf_threshold, length_ratio_threshold):
57
- start_time = time.time()
58
- with torch.no_grad():
59
- evidence = extract_evidence_tfidf_qatc(
60
- claim, context, model_qatc, tokenizer_qatc,
61
- device,
62
- confidence_threshold=tfidf_threshold,
63
- length_ratio_threshold=length_ratio_threshold
64
- )
65
- evidence_time = time.time() - start_time
66
- queue.put((evidence, evidence_time))
67
-
68
- # Function to classify in a separate thread
69
- def classify_claim_threaded(queue, claim, evidence, model, tokenizer, device):
70
- with torch.no_grad():
71
- result = classify_claim(claim, evidence, model, tokenizer, device)
72
- queue.put(result)
73
-
74
- # Optimized function for evidence extraction and classification with better CPU performance
75
- def perform_verification(claim, context, model_qatc, tokenizer_qatc, model_tc, tokenizer_tc,
76
- model_bc, tokenizer_bc, tfidf_threshold, length_ratio_threshold):
77
- # Use thread for evidence extraction to allow garbage collection in between
78
- evidence_queue = Queue()
79
- evidence_thread = threading.Thread(
80
- target=extract_evidence_threaded,
81
- args=(evidence_queue, claim, context, model_qatc, tokenizer_qatc, DEVICE,
82
- tfidf_threshold, length_ratio_threshold)
83
- )
84
- evidence_thread.start()
85
- evidence_thread.join()
86
- evidence, evidence_time = evidence_queue.get()
87
-
88
- # Explicit garbage collection after evidence extraction
89
- gc.collect()
90
-
91
- # Classify the claim
92
- verdict_start_time = time.time()
93
- with torch.no_grad():
94
- verdict = "NEI"
95
- prob3class, pred_tc = classify_claim(
96
- claim, evidence, model_tc, tokenizer_tc, DEVICE
97
- )
98
-
99
- # Only run binary classifier if needed
100
- prob2class, pred_bc = 0, 0
101
- if pred_tc != 0:
102
- prob2class, pred_bc = classify_claim(
103
- claim, evidence, model_bc, tokenizer_bc, DEVICE
104
- )
105
- verdict = "SUPPORTED" if pred_bc == 0 else "REFUTED" if prob2class > prob3class else ["NEI", "SUPPORTED", "REFUTED"][pred_tc]
106
-
107
- verdict_time = time.time() - verdict_start_time
108
-
109
- return {
110
- "evidence": evidence,
111
- "verdict": verdict,
112
- "evidence_time": evidence_time,
113
- "verdict_time": verdict_time,
114
- "prob3class": prob3class.item() if isinstance(prob3class, torch.Tensor) else prob3class,
115
- "pred_tc": pred_tc,
116
- "prob2class": prob2class.item() if isinstance(prob2class, torch.Tensor) else prob2class,
117
- "pred_bc": pred_bc
118
- }
119
-
120
- # Set up page configuration
121
- st.set_page_config(page_title="SemViQA Demo", layout="wide")
122
 
123
- # Custom CSS: fixed header and tabs, dynamic height, result box formatting
124
- # Custom CSS: fixed header and tabs, dynamic height, result box formatting
125
- st.markdown(
126
- """
127
  <style>
128
- html, body {
129
- height: 100%;
130
- margin: 0;
131
- overflow: hidden;
 
 
 
 
132
  }
133
- .main-container {
134
- height: calc(100vh - 55px); /* Browser height - 55px */
135
- overflow-y: auto;
136
- padding: 20px;
 
137
  }
138
- .big-title {
139
- font-size: 36px !important;
 
 
 
 
 
 
 
 
 
 
 
140
  font-weight: bold;
141
- color: var(--primary-color);
142
  text-align: center;
143
- margin-top: 20px;
144
- position: sticky; /* Pin the header */
145
- top: 0;
146
- background-color: var(--background-color); /* Ensure the header covers content when scrolling */
147
- z-index: 100; /* Ensure it's above other content */
148
  }
 
149
  .sub-title {
150
- font-size: 20px;
151
- color: var(--text-color);
152
  text-align: center;
153
- margin-bottom: 20px;
154
  }
 
 
 
 
 
 
 
 
 
 
 
 
155
  .stButton>button {
156
- background-color: var(--primary-color);
157
- color: red;
158
- font-size: 16px;
159
- width: 100%;
160
  border-radius: 8px;
161
- padding: 10px;
162
- border: 2px solid red;
 
 
163
  }
164
- .stTextArea textarea {
165
- font-size: 16px;
166
- min-height: 120px;
167
- background-color: var(--secondary-background-color);
168
- color: var(--text-color);
169
  }
 
 
170
  .result-box {
171
- background-color: var(--secondary-background-color);
172
- padding: 20px;
173
- border-radius: 10px;
174
- box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
175
- margin-top: 20px;
176
- color: var(--text-color);
177
  }
 
178
  .verdict {
179
- font-size: 24px;
180
  font-weight: bold;
181
- margin: 0;
182
- display: flex;
183
- align-items: center;
184
- color: var(--text-color);
185
- }
186
- .verdict-icon {
187
- margin-right: 10px;
188
  }
189
- /* Fix the tabs at the top */
190
- div[data-baseweb="tab-list"] {
191
- position: sticky;
192
- top: 55px; /* Height of the header */
193
- background-color: var(--background-color);
194
- z-index: 99;
195
  }
196
- /* Fix the sidebar content */
197
- .stSidebar .sidebar-content {
198
- background-color: var(--secondary-background-color);
199
- padding: 20px;
200
- border-radius: 10px;
201
- position: sticky;
202
- top: 55px; /* Height of the header */
203
- height: calc(100vh - 75px); /* Adjust height to fit within the viewport */
204
- overflow-y: auto; /* Enable scrolling within the sidebar if content is too long */
205
  }
206
- .stSidebar .st-expander {
207
- background-color: var(--background-color);
208
- border-radius: 10px;
209
- padding: 10px;
210
- margin-bottom: 10px;
211
  }
212
- .stSidebar .stSlider {
213
- margin-bottom: 20px;
214
- }
215
- .stSidebar .stSelectbox {
216
- margin-bottom: 20px;
 
 
217
  }
218
- .stSidebar .stCheckbox {
219
- margin-bottom: 20px;
 
 
 
 
 
 
220
  }
221
-
 
222
  .code-block {
223
- background-color: #f5f5f5; /* Màu nền */
224
- border: 1px solid #ccc; /* Viền */
225
- padding: 10px; /* Khoảng cách bên trong */
226
- border-radius: 5px; /* Bo tròn góc */
227
- font-family: monospace; /* Font chữ đơn cách */
228
- white-space: pre-wrap; /* Giữ nguyên định dạng xuống dòng */
229
- color: #333; /* Màu chữ */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  }
231
  </style>
232
- """,
233
- unsafe_allow_html=True,
234
- )
235
 
236
- # Container for the whole content with dynamic height
237
- with st.container():
238
- st.markdown("<p class='big-title'>SemViQA: A Semantic Question Answering System for Vietnamese Information Fact-Checking</p>", unsafe_allow_html=True)
239
- st.markdown("""
240
- <div style="text-align: center; margin-bottom: 20px;">
241
- <p>
242
- <a href="https://github.com/DAVID-NGUYEN-S16">Nam V. Nguyen</a>*,
243
- <a href="https://github.com/xndien2004">Dien X. Tran</a>*,
244
- Thanh T. Tran,
245
- Anh T. Hoang,
246
- Tai V. Duong,
247
- Di T. Le,
248
- Phuc-Lu Le
249
- </p>
250
- </div>
251
- """, unsafe_allow_html=True)
252
 
253
- # Sidebar: Global Settings
254
- with st.sidebar.expander("⚙️ Settings", expanded=True):
255
- tfidf_threshold = st.slider("TF-IDF Threshold", 0.0, 1.0, 0.5, 0.01)
256
- length_ratio_threshold = st.slider("Length Ratio Threshold", 0.1, 1.0, 0.5, 0.01)
257
- qatc_model_name = st.selectbox("QATC Model", [
 
 
 
 
258
  "SemViQA/qatc-infoxlm-viwikifc",
259
  "SemViQA/qatc-infoxlm-isedsc01",
260
  "SemViQA/qatc-vimrc-viwikifc",
261
  "SemViQA/qatc-vimrc-isedsc01"
262
- ])
263
- bc_model_name = st.selectbox("Binary Classification Model", [
 
 
 
 
264
  "SemViQA/bc-xlmr-viwikifc",
265
  "SemViQA/bc-xlmr-isedsc01",
266
  "SemViQA/bc-infoxlm-viwikifc",
267
  "SemViQA/bc-infoxlm-isedsc01",
268
  "SemViQA/bc-erniem-viwikifc",
269
  "SemViQA/bc-erniem-isedsc01"
270
- ])
271
- tc_model_name = st.selectbox("3-Class Classification Model", [
 
 
 
 
272
  "SemViQA/tc-xlmr-viwikifc",
273
  "SemViQA/tc-xlmr-isedsc01",
274
  "SemViQA/tc-infoxlm-viwikifc",
275
  "SemViQA/tc-infoxlm-isedsc01",
276
  "SemViQA/tc-erniem-viwikifc",
277
  "SemViQA/tc-erniem-isedsc01"
278
- ])
279
- show_details = st.checkbox("Show Probability Details", value=False)
280
-
281
- # Add CPU optimization settings
282
- st.subheader("CPU Performance Settings")
283
- num_threads = st.slider("Number of CPU Threads", 1, psutil.cpu_count(),
284
- psutil.cpu_count(logical=False))
285
- os.environ["OMP_NUM_THREADS"] = str(num_threads)
286
- os.environ["MKL_NUM_THREADS"] = str(num_threads)
287
-
288
- # Load models once and keep them in memory
289
- tokenizer_qatc, model_qatc = load_model(qatc_model_name, QATCForQuestionAnswering, device=DEVICE)
290
- tokenizer_bc, model_bc = load_model(bc_model_name, ClaimModelForClassification, is_bc=True, device=DEVICE)
291
- tokenizer_tc, model_tc = load_model(tc_model_name, ClaimModelForClassification, device=DEVICE)
292
- st.session_state.models_loaded = True
293
-
294
- # Store verification history
295
- if 'history' not in st.session_state:
296
- st.session_state.history = []
297
- if 'latest_result' not in st.session_state:
298
- st.session_state.latest_result = None
299
-
300
- # Icons for results
301
- verdict_icons = {
302
- "SUPPORTED": "✅",
303
- "REFUTED": "❌",
304
- "NEI": "⚠️"
305
- }
306
-
307
- # Tabs: Verify, History
308
- tabs = st.tabs(["Verify", "History"])
309
-
310
- # --- Tab Verify ---
311
- with tabs[0]:
312
- st.subheader("Verify a Claim")
313
- # 2-column layout: input on the left, results on the right
314
- col_input, col_result = st.columns([2, 1])
315
 
316
- with col_input:
317
- claim = st.text_area("Enter Claim", "Chiến tranh với Campuchia đã kết thúc trước khi Việt Nam thống nhất.")
318
- context = st.text_area("Enter Context", "Sau khi thống nhất, Việt Nam tiếp tục gặp khó khăn do sự sụp đổ và tan rã của đồng minh Liên Xô cùng Khối phía Đông, các lệnh cấm vận của Hoa Kỳ, chiến tranh với Campuchia, biên giới giáp Trung Quốc và hậu quả của chính sách bao cấp sau nhiều năm áp dụng. Năm 1986, Đảng Cộng sản ban hành cải cách đổi mới, tạo điều kiện hình thành kinh tế thị trường và hội nhập sâu rộng. Cải cách đổi mới kết hợp cùng quy mô dân số lớn đưa Việt Nam trở thành một trong những nước đang phát triển có tốc độ tăng trưởng thuộc nhóm nhanh nhất thế giới, được coi là Hổ mới châu Á dù cho vẫn gặp phải những thách thức như tham nhũng, tội phạm gia tăng, ô nhiễm môi trường và phúc lợi xã hội chưa đầy đủ. Ngoài ra, giới bất đồng chính kiến, chính phủ một số nước phương Tây và các tổ chức theo dõi nhân quyền có quan điểm chỉ trích hồ sơ nhân quyền của Việt Nam liên quan đến các vấn đề tôn giáo, kiểm duyệt truyền thông, hạn chế hoạt động ủng hộ nhân quyền cùng các quyền tự do dân sự.")
319
- verify_button = st.button("Verify", key="verify_button")
320
 
321
- with col_result:
322
- st.markdown("<h3>Verification Result</h3>", unsafe_allow_html=True)
323
- if verify_button:
324
- # Preprocess texts to improve tokenization speed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
  preprocessed_claim = preprocess_text(claim)
326
  preprocessed_context = preprocess_text(context)
327
 
328
- # Placeholder for displaying result/loading
329
- with st.spinner("Verifying..."):
330
- start_time = time.time()
331
-
332
- # Clear memory before verification
333
- gc.collect()
334
-
335
- # Use the optimized verification function
336
- result = perform_verification(
337
- preprocessed_claim, preprocessed_context,
338
- model_qatc, tokenizer_qatc,
339
- model_tc, tokenizer_tc,
340
- model_bc, tokenizer_bc,
341
- tfidf_threshold, length_ratio_threshold
342
- )
343
-
344
- total_time = time.time() - start_time
345
-
346
- # Format details if needed
347
- details = ""
348
- if show_details:
349
- details = f"""
350
- 3-Class Probability: {result['prob3class']:.2f}
351
- 3-Class Predicted Label: {['NEI', 'SUPPORTED', 'REFUTED'][result['pred_tc']]}
352
- 2-Class Probability: {result['prob2class']:.2f}
353
- 2-Class Predicted Label: {['SUPPORTED', 'REFUTED'][result['pred_bc']] if isinstance(result['pred_bc'], int) and result['pred_tc'] != 0 else 'Not used'}
354
- """
355
-
356
- st.session_state.latest_result = {
357
- "claim": claim,
358
- "evidence": result['evidence'],
359
- "verdict": result['verdict'],
360
- "evidence_time": result['evidence_time'],
361
- "verdict_time": result['verdict_time'],
362
- "total_time": total_time,
363
- "details": details,
364
- "qatc_model": qatc_model_name,
365
- "bc_model": bc_model_name,
366
- "tc_model": tc_model_name
367
- }
368
-
369
- # Add new result to history
370
- st.session_state.history.append(st.session_state.latest_result)
371
-
372
- # Clear memory after processing
373
- gc.collect()
374
-
375
- # Display the result after verification
376
- res = st.session_state.latest_result
377
- st.markdown(f"""
378
- <div class='result-box'>
379
- <p><strong>Claim:</strong> {res['claim']}</p>
380
- <p><strong>Evidence:</strong> {res['evidence']}</p>
381
- <p class='verdict'><span class='verdict-icon'>{verdict_icons.get(res['verdict'], '')}</span>{res['verdict']}</p>
382
- <p><strong>Evidence Inference Time:</strong> {res['evidence_time']:.2f} seconds</p>
383
- <p><strong>Verdict Inference Time:</strong> {res['verdict_time']:.2f} seconds</p>
384
- <p><strong>Total Execution Time:</strong> {res['total_time']:.2f} seconds</p>
385
- {f"<div class='code-block'><pre>{res['details']}</pre></div>" if show_details else ""}
 
 
 
 
 
386
  </div>
387
- """, unsafe_allow_html=True)
388
-
389
- # Download Verification Result Feature
390
- result_text = f"Claim: {res['claim']}\nEvidence: {res['evidence']}\nVerdict: {res['verdict']}\nDetails: {res['details']}"
391
- st.download_button("Download Result", data=result_text, file_name="verification_result.txt", mime="text/plain")
392
- else:
393
- st.info("No verification result yet.")
394
-
395
- # --- Tab History ---
396
- with tabs[1]:
397
- st.subheader("Verification History")
398
- if st.session_state.history:
399
- # Convert history to DataFrame for easy download
400
- history_df = pd.DataFrame(st.session_state.history)
401
- st.download_button(
402
- label="Download Full History",
403
- data=history_df.to_csv(index=False).encode('utf-8'),
404
- file_name="verification_history.csv",
405
- mime="text/csv",
406
- )
407
- for idx, record in enumerate(reversed(st.session_state.history), 1):
408
- st.markdown(f"**{idx}. Claim:** {record['claim']} \n**Result:** {verdict_icons.get(record['verdict'], '')} {record['verdict']}")
409
  else:
410
- st.write("No verification history yet.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  import os
11
  import psutil
12
  import gc
 
 
13
 
14
  # Set environment variables to optimize CPU performance
15
  os.environ["OMP_NUM_THREADS"] = str(psutil.cpu_count(logical=False))
 
18
  # Set device globally
19
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
20
 
21
+ # Set page configuration
22
+ st.set_page_config(
23
+ page_title="SemViQA - Hệ thống Kiểm chứng Thông tin Tiếng Việt",
24
+ page_icon="🔍",
25
+ layout="wide",
26
+ initial_sidebar_state="expanded"
27
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
+ # Custom CSS
30
+ st.markdown("""
 
 
31
  <style>
32
+ /* Main theme colors */
33
+ :root {
34
+ --primary-color: #1f77b4;
35
+ --secondary-color: #2c3e50;
36
+ --accent-color: #e74c3c;
37
+ --background-color: #f8f9fa;
38
+ --text-color: #2c3e50;
39
+ --border-color: #e0e0e0;
40
  }
41
+
42
+ /* General styling */
43
+ .stApp {
44
+ background-color: var(--background-color);
45
+ color: var(--text-color);
46
  }
47
+
48
+ /* Header styling */
49
+ .main-header {
50
+ background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
51
+ color: white;
52
+ padding: 2rem;
53
+ border-radius: 10px;
54
+ margin-bottom: 2rem;
55
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
56
+ }
57
+
58
+ .main-title {
59
+ font-size: 2.5rem;
60
  font-weight: bold;
 
61
  text-align: center;
62
+ margin-bottom: 1rem;
 
 
 
 
63
  }
64
+
65
  .sub-title {
66
+ font-size: 1.2rem;
 
67
  text-align: center;
68
+ opacity: 0.9;
69
  }
70
+
71
+ /* Input styling */
72
+ .stTextArea textarea {
73
+ border: 2px solid var(--border-color);
74
+ border-radius: 8px;
75
+ padding: 1rem;
76
+ font-size: 1rem;
77
+ min-height: 150px;
78
+ background-color: white;
79
+ }
80
+
81
+ /* Button styling */
82
  .stButton>button {
83
+ background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
84
+ color: white;
85
+ border: none;
 
86
  border-radius: 8px;
87
+ padding: 0.8rem 2rem;
88
+ font-size: 1.1rem;
89
+ font-weight: bold;
90
+ transition: all 0.3s ease;
91
  }
92
+
93
+ .stButton>button:hover {
94
+ transform: translateY(-2px);
95
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
 
96
  }
97
+
98
+ /* Result box styling */
99
  .result-box {
100
+ background-color: white;
101
+ border-radius: 12px;
102
+ padding: 2rem;
103
+ margin: 1rem 0;
104
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
 
105
  }
106
+
107
  .verdict {
108
+ font-size: 1.8rem;
109
  font-weight: bold;
110
+ padding: 1rem;
111
+ border-radius: 8px;
112
+ margin: 1rem 0;
113
+ text-align: center;
 
 
 
114
  }
115
+
116
+ .verdict-supported {
117
+ background-color: #d4edda;
118
+ color: #155724;
 
 
119
  }
120
+
121
+ .verdict-refuted {
122
+ background-color: #f8d7da;
123
+ color: #721c24;
 
 
 
 
 
124
  }
125
+
126
+ .verdict-nei {
127
+ background-color: #fff3cd;
128
+ color: #856404;
 
129
  }
130
+
131
+ /* Sidebar styling */
132
+ .css-1d391kg {
133
+ background-color: white;
134
+ padding: 2rem;
135
+ border-radius: 12px;
136
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
137
  }
138
+
139
+ /* Stats box styling */
140
+ .stats-box {
141
+ background-color: white;
142
+ border-radius: 8px;
143
+ padding: 1rem;
144
+ margin: 0.5rem 0;
145
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
146
  }
147
+
148
+ /* Code block styling */
149
  .code-block {
150
+ background-color: #f8f9fa;
151
+ border: 1px solid var(--border-color);
152
+ border-radius: 8px;
153
+ padding: 1rem;
154
+ font-family: monospace;
155
+ margin: 1rem 0;
156
+ }
157
+
158
+ /* Tab styling */
159
+ .stTabs [data-baseweb="tab-list"] {
160
+ gap: 2rem;
161
+ }
162
+
163
+ .stTabs [data-baseweb="tab"] {
164
+ background-color: white;
165
+ border-radius: 8px;
166
+ padding: 0.5rem 1rem;
167
+ margin: 0 0.5rem;
168
+ }
169
+
170
+ .stTabs [aria-selected="true"] {
171
+ background-color: var(--primary-color);
172
+ color: white;
173
  }
174
  </style>
175
+ """, unsafe_allow_html=True)
 
 
176
 
177
+ # Main header
178
+ st.markdown("""
179
+ <div class="main-header">
180
+ <div class="main-title">SemViQA</div>
181
+ <div class="sub-title">Hệ thống Kiểm chứng Thông tin Tiếng Việt</div>
182
+ </div>
183
+ """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
184
 
185
+ # Sidebar
186
+ with st.sidebar:
187
+ st.markdown("### ⚙️ Cài đặt Hệ thống")
188
+
189
+ # Model selection
190
+ st.markdown("#### 🧠 Chọn Mô hình")
191
+ qatc_model_name = st.selectbox(
192
+ "Mô hình QATC",
193
+ [
194
  "SemViQA/qatc-infoxlm-viwikifc",
195
  "SemViQA/qatc-infoxlm-isedsc01",
196
  "SemViQA/qatc-vimrc-viwikifc",
197
  "SemViQA/qatc-vimrc-isedsc01"
198
+ ]
199
+ )
200
+
201
+ bc_model_name = st.selectbox(
202
+ "Mô hình Phân loại Nhị phân",
203
+ [
204
  "SemViQA/bc-xlmr-viwikifc",
205
  "SemViQA/bc-xlmr-isedsc01",
206
  "SemViQA/bc-infoxlm-viwikifc",
207
  "SemViQA/bc-infoxlm-isedsc01",
208
  "SemViQA/bc-erniem-viwikifc",
209
  "SemViQA/bc-erniem-isedsc01"
210
+ ]
211
+ )
212
+
213
+ tc_model_name = st.selectbox(
214
+ "Mô hình Phân loại Ba lớp",
215
+ [
216
  "SemViQA/tc-xlmr-viwikifc",
217
  "SemViQA/tc-xlmr-isedsc01",
218
  "SemViQA/tc-infoxlm-viwikifc",
219
  "SemViQA/tc-infoxlm-isedsc01",
220
  "SemViQA/tc-erniem-viwikifc",
221
  "SemViQA/tc-erniem-isedsc01"
222
+ ]
223
+ )
224
+
225
+ # Threshold settings
226
+ st.markdown("#### ⚖️ Ngưỡng Phân tích")
227
+ tfidf_threshold = st.slider(
228
+ "Ngưỡng TF-IDF",
229
+ 0.0, 1.0, 0.5,
230
+ help="Điều chỉnh độ nhạy trong việc tìm kiếm bằng chứng"
231
+ )
232
+
233
+ length_ratio_threshold = st.slider(
234
+ "Ngưỡng Tỷ lệ Độ dài",
235
+ 0.1, 1.0, 0.5,
236
+ help="Điều chỉnh độ dài tối đa của bằng chứng"
237
+ )
238
+
239
+ # Display settings
240
+ st.markdown("#### 👁️ Hiển thị")
241
+ show_details = st.checkbox(
242
+ "Hiển thị Chi tiết Xác suất",
243
+ value=False,
244
+ help="Hiển thị thông tin chi tiết về xác suất dự đoán"
245
+ )
246
+
247
+ # Performance settings
248
+ st.markdown("#### ⚡ Hiệu suất")
249
+ num_threads = st.slider(
250
+ "Số luồng CPU",
251
+ 1, psutil.cpu_count(),
252
+ psutil.cpu_count(logical=False),
253
+ help="Điều chỉnh hiệu suất xử lý"
254
+ )
255
+ os.environ["OMP_NUM_THREADS"] = str(num_threads)
256
+ os.environ["MKL_NUM_THREADS"] = str(num_threads)
 
 
257
 
258
+ # Main content
259
+ tabs = st.tabs(["🔍 Kiểm chứng", "📊 Lịch sử", "ℹ️ Thông tin"])
 
 
260
 
261
+ # --- Tab Verify ---
262
+ with tabs[0]:
263
+ col1, col2 = st.columns([2, 1])
264
+
265
+ with col1:
266
+ st.markdown("### 📝 Nhập Thông tin")
267
+ claim = st.text_area(
268
+ "Câu khẳng định cần kiểm chứng",
269
+ "Chiến tranh với Campuchia đã kết thúc trước khi Việt Nam thống nhất.",
270
+ help="Nhập câu khẳng định cần được kiểm chứng"
271
+ )
272
+
273
+ context = st.text_area(
274
+ "Ngữ cảnh",
275
+ "Sau khi thống nhất, Việt Nam tiếp tục gặp khó khăn do sự sụp đổ và tan rã của đồng minh Liên Xô cùng Khối phía Đông, các lệnh cấm vận của Hoa Kỳ, chiến tranh với Campuchia, biên giới giáp Trung Quốc và hậu quả của chính sách bao cấp sau nhiều năm áp dụng. Năm 1986, Đảng Cộng sản ban hành cải cách đổi mới, tạo điều kiện hình thành kinh tế thị trường và hội nhập sâu rộng. Cải cách đổi mới kết hợp cùng quy mô dân số lớn đưa Việt Nam trở thành một trong những nước đang phát triển có tốc độ tăng trưởng thuộc nhóm nhanh nhất thế giới, được coi là Hổ mới châu Á dù cho vẫn gặp phải những thách thức như tham nhũng, tội phạm gia tăng, ô nhiễm môi trường và phúc lợi xã hội chưa đầy đủ. Ngoài ra, giới bất đồng chính kiến, chính phủ một số nước phương Tây và các tổ chức theo dõi nhân quyền có quan điểm chỉ trích hồ sơ nhân quyền của Việt Nam liên quan đến các vấn đề tôn giáo, kiểm duyệt truyền thông, hạn chế hoạt động ủng hộ nhân quyền cùng các quyền tự do dân sự.",
276
+ help="Nhập ngữ cảnh hoặc văn bản tham khảo"
277
+ )
278
+
279
+ verify_button = st.button("🔍 Kiểm chứng", use_container_width=True)
280
+
281
+ with col2:
282
+ st.markdown("### 📊 Kết quả")
283
+ if verify_button:
284
+ with st.spinner("Đang kiểm chứng..."):
285
+ # Preprocess texts
286
  preprocessed_claim = preprocess_text(claim)
287
  preprocessed_context = preprocess_text(context)
288
 
289
+ # Clear memory and perform verification
290
+ gc.collect()
291
+ start_time = time.time()
292
+
293
+ result = perform_verification(
294
+ preprocessed_claim, preprocessed_context,
295
+ model_qatc, tokenizer_qatc,
296
+ model_tc, tokenizer_tc,
297
+ model_bc, tokenizer_bc,
298
+ tfidf_threshold, length_ratio_threshold
299
+ )
300
+
301
+ total_time = time.time() - start_time
302
+
303
+ # Format details
304
+ details = ""
305
+ if show_details:
306
+ details = f"""
307
+ 3-Class Probability: {result['prob3class']:.2f}
308
+ 3-Class Predicted Label: {['NEI', 'SUPPORTED', 'REFUTED'][result['pred_tc']]}
309
+ 2-Class Probability: {result['prob2class']:.2f}
310
+ 2-Class Predicted Label: {['SUPPORTED', 'REFUTED'][result['pred_bc']] if isinstance(result['pred_bc'], int) and result['pred_tc'] != 0 else 'Not used'}
311
+ """
312
+
313
+ # Store result
314
+ st.session_state.latest_result = {
315
+ "claim": claim,
316
+ "evidence": result['evidence'],
317
+ "verdict": result['verdict'],
318
+ "evidence_time": result['evidence_time'],
319
+ "verdict_time": result['verdict_time'],
320
+ "total_time": total_time,
321
+ "details": details,
322
+ "qatc_model": qatc_model_name,
323
+ "bc_model": bc_model_name,
324
+ "tc_model": tc_model_name
325
+ }
326
+
327
+ # Add to history
328
+ if 'history' not in st.session_state:
329
+ st.session_state.history = []
330
+ st.session_state.history.append(st.session_state.latest_result)
331
+
332
+ # Display result
333
+ res = st.session_state.latest_result
334
+ verdict_class = {
335
+ "SUPPORTED": "verdict-supported",
336
+ "REFUTED": "verdict-refuted",
337
+ "NEI": "verdict-nei"
338
+ }.get(res['verdict'], "")
339
+
340
+ st.markdown(f"""
341
+ <div class="result-box">
342
+ <h3>Kết quả Kiểm chứng</h3>
343
+ <p><strong>Câu khẳng định:</strong> {res['claim']}</p>
344
+ <p><strong>Bằng chứng:</strong> {res['evidence']}</p>
345
+ <p class="verdict {verdict_class}">
346
+ {verdict_icons.get(res['verdict'], '')} {res['verdict']}
347
+ </p>
348
+ <div class="stats-box">
349
+ <p><strong>Thời gian trích xuất bằng chứng:</strong> {res['evidence_time']:.2f} giây</p>
350
+ <p><strong>Thời gian phân loại:</strong> {res['verdict_time']:.2f} giây</p>
351
+ <p><strong>Tổng thời gian:</strong> {res['total_time']:.2f} giây</p>
352
  </div>
353
+ {f"<div class='code-block'><pre>{res['details']}</pre></div>" if show_details else ""}
354
+ </div>
355
+ """, unsafe_allow_html=True)
356
+
357
+ # Download button
358
+ 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']}"
359
+ st.download_button(
360
+ "📥 Tải kết quả",
361
+ data=result_text,
362
+ file_name="ket_qua_kiem_chung.txt",
363
+ mime="text/plain"
364
+ )
 
 
 
 
 
 
 
 
 
 
365
  else:
366
+ st.info("Vui lòng nhập thông tin và nhấn nút Kiểm chứng để bắt đầu.")
367
+
368
+ # --- Tab History ---
369
+ with tabs[1]:
370
+ st.markdown("### 📊 Lịch sử Kiểm chứng")
371
+ if 'history' in st.session_state and st.session_state.history:
372
+ # Download full history
373
+ history_df = pd.DataFrame(st.session_state.history)
374
+ st.download_button(
375
+ "📥 Tải toàn bộ lịch sử",
376
+ data=history_df.to_csv(index=False).encode('utf-8'),
377
+ file_name="lich_su_kiem_chung.csv",
378
+ mime="text/csv"
379
+ )
380
+
381
+ # Display history
382
+ for idx, record in enumerate(reversed(st.session_state.history), 1):
383
+ st.markdown(f"""
384
+ <div class="result-box">
385
+ <h4>Kiểm chứng #{idx}</h4>
386
+ <p><strong>Câu khẳng định:</strong> {record['claim']}</p>
387
+ <p><strong>Kết luận:</strong> {verdict_icons.get(record['verdict'], '')} {record['verdict']}</p>
388
+ <p><strong>Thời gian:</strong> {record['total_time']:.2f} giây</p>
389
+ </div>
390
+ """, unsafe_allow_html=True)
391
+ else:
392
+ st.info("Chưa có lịch sử kiểm chứng.")
393
+
394
+ # --- Tab Info ---
395
+ with tabs[2]:
396
+ st.markdown("""
397
+ <div class="result-box">
398
+ <h3>ℹ️ Thông tin về SemViQA</h3>
399
+ <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>
400
+
401
+ <h4>🔍 Cách sử dụng</h4>
402
+ <ol>
403
+ <li>Nhập câu khẳng định cần kiểm chứng</li>
404
+ <li>Nhập ngữ cảnh hoặc văn bản tham khảo</li>
405
+ <li>Điều chỉnh các tham số trong phần Cài đặt nếu cần</li>
406
+ <li>Nhấn nút Kiểm chứng</li>
407
+ </ol>
408
+
409
+ <h4>⚙️ Các tham số</h4>
410
+ <ul>
411
+ <li><strong>Ngưỡng TF-IDF:</strong> Điều chỉnh độ nhạy trong việc tìm kiếm bằng chứng</li>
412
+ <li><strong>Ngưỡng Tỷ lệ Độ dài:</strong> Điều chỉnh độ dài tối đa của bằng chứng</li>
413
+ <li><strong>Số luồng CPU:</strong> Điều chỉnh hiệu suất xử lý</li>
414
+ </ul>
415
+
416
+ <h4>📊 Kết quả</h4>
417
+ <ul>
418
+ <li><strong>SUPPORTED:</strong> Câu khẳng định được hỗ trợ bởi bằng chứng</li>
419
+ <li><strong>REFUTED:</strong> Câu khẳng định bị bác bỏ bởi bằng chứng</li>
420
+ <li><strong>NEI:</strong> Không đủ bằng chứng để kết luận</li>
421
+ </ul>
422
+ </div>
423
+ """, unsafe_allow_html=True)