xuandin commited on
Commit
f0d09f3
·
verified ·
1 Parent(s): 4ebd212

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +183 -133
app.py CHANGED
@@ -5,7 +5,6 @@ from semviqa.ser.qatc_model import QATCForQuestionAnswering
5
  from semviqa.tvc.model import ClaimModelForClassification
6
  from semviqa.ser.ser_eval import extract_evidence_tfidf_qatc
7
  from semviqa.tvc.tvc_eval import classify_claim
8
- import time
9
  import io
10
 
11
  # Load models with caching
@@ -19,94 +18,116 @@ def load_model(model_name, model_class, is_bc=False):
19
  # Set up page configuration
20
  st.set_page_config(page_title="SemViQA Demo", layout="wide")
21
 
22
- # Custom CSS cho header cố định và main container (chiều cao = viewport - 55px)
23
  st.markdown("""
24
  <style>
25
- .header-container {
26
- position: fixed;
27
- top: 0;
28
- left: 0;
29
- width: 100%;
30
- height: 55px;
31
- background-color: #fff;
32
- z-index: 1000;
33
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
34
- display: flex;
35
- align-items: center;
36
- justify-content: space-between;
37
- padding: 0 20px;
38
- }
39
- .header-title {
40
- font-size: 14px;
41
- font-weight: bold;
42
- color: #4A90E2;
43
- }
44
- .header-nav {
45
- margin: 0 20px;
46
- }
47
- .header-subtitle {
48
- font-size: 12px;
49
- color: #666;
50
- text-align: right;
51
  }
52
  .main-container {
53
- margin-top: 55px;
54
  height: calc(100vh - 55px);
55
  overflow-y: auto;
56
  padding: 20px;
57
  }
58
- .stButton>button {
59
- background-color: #4CAF50;
60
- color: white;
61
- font-size: 16px;
62
- width: 100%;
63
- border-radius: 8px;
64
- padding: 10px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  }
66
- .stTextArea textarea {
 
 
 
 
 
 
 
 
67
  font-size: 16px;
68
  min-height: 120px;
69
  }
70
- .result-box {
71
- background-color: #f9f9f9;
72
- padding: 20px;
73
- border-radius: 10px;
74
- box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
75
  margin-top: 20px;
76
  }
77
- .verdict {
78
- font-size: 24px;
79
- font-weight: bold;
80
  margin: 0;
81
  display: flex;
82
  align-items: center;
83
  }
84
- .verdict-icon {
85
  margin-right: 10px;
86
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  </style>
88
  """, unsafe_allow_html=True)
89
 
90
- # --- Fixed Header ---
91
- # Sử dụng st.markdown để in ra phần header cố định bao gồm title, nav (radio) và subtitle
92
- st.markdown("""
93
- <div class='header-container'>
94
- <div class='header-title'>SemViQA: Semantic Fact-Checking System for Vietnamese</div>
95
- <div class='header-nav'>
96
- """, unsafe_allow_html=True)
97
- # Navigation: sử dụng st.radio để chuyển đổi các trang (hiển thị theo dạng ngang)
98
- nav_option = st.radio("", ["Verify", "History", "About"], horizontal=True, key="nav")
99
- st.markdown("""
100
- </div>
101
- <div class='header-subtitle'>Enter a claim and context to verify its accuracy</div>
102
- </div>
103
- """, unsafe_allow_html=True)
104
-
105
- # --- Main Container ---
106
  with st.container():
107
- st.markdown("<div class='main-container'>", unsafe_allow_html=True)
108
-
109
- # Sidebar: Global Settings (không thay đổi)
 
110
  with st.sidebar.expander("⚙️ Settings", expanded=True):
111
  tfidf_threshold = st.slider("TF-IDF Threshold", 0.0, 1.0, 0.5, 0.01)
112
  length_ratio_threshold = st.slider("Length Ratio Threshold", 0.1, 1.0, 0.5, 0.01)
@@ -124,7 +145,7 @@ with st.container():
124
  "SemViQA/bc-erniem-viwikifc",
125
  "SemViQA/bc-erniem-isedsc01"
126
  ])
127
- tc_model_name = st.selectbox("Three-Class Classification Model", [
128
  "SemViQA/tc-xlmr-viwikifc",
129
  "SemViQA/tc-xlmr-isedsc01",
130
  "SemViQA/tc-infoxlm-viwikifc",
@@ -134,90 +155,118 @@ with st.container():
134
  ])
135
  show_details = st.checkbox("Show probability details", value=False)
136
 
137
- # Khởi tạo lịch sử kiểm chứng và kết quả mới nhất
138
  if 'history' not in st.session_state:
139
  st.session_state.history = []
140
  if 'latest_result' not in st.session_state:
141
  st.session_state.latest_result = None
 
 
142
 
143
- # Load các mô hình đã chọn
144
  tokenizer_qatc, model_qatc = load_model(qatc_model_name, QATCForQuestionAnswering)
145
  tokenizer_bc, model_bc = load_model(bc_model_name, ClaimModelForClassification, is_bc=True)
146
  tokenizer_tc, model_tc = load_model(tc_model_name, ClaimModelForClassification)
147
 
148
- # Icon cho kết quả
149
  verdict_icons = {
150
  "SUPPORTED": "✅",
151
  "REFUTED": "❌",
152
  "NEI": "⚠️"
153
  }
154
-
155
- # Hiển thị nội dung theo lựa chọn của navigation
156
- if nav_option == "Verify":
157
- st.subheader("Verify a Claim")
158
- # Layout 2 cột: bên trái cho input, bên phải hiển thị kết quả
 
 
 
159
  col_input, col_result = st.columns([2, 1])
160
 
161
  with col_input:
162
  claim = st.text_area("Enter Claim", "Vietnam is a country in Southeast Asia.")
163
  context = st.text_area("Enter Context", "Vietnam is a country located in Southeast Asia, covering an area of over 331,000 km² with a population of more than 98 million people.")
164
- verify_clicked = st.button("Verify", key="verify_button")
 
 
 
 
 
 
165
 
 
166
  with col_result:
167
- if verify_clicked:
168
- with st.spinner("Loading and running verification..."):
169
- # Hiển thị progress bar mô phỏng quá trình xử lý
170
- progress_bar = st.progress(0)
171
- for i in range(1, 101, 20):
172
- time.sleep(0.1)
173
- progress_bar.progress(i)
174
-
175
- with torch.no_grad():
176
- # Trích xuất bằng chứng và phân loại thông tin
177
- evidence = extract_evidence_tfidf_qatc(
178
- claim, context, model_qatc, tokenizer_qatc,
179
- "cuda" if torch.cuda.is_available() else "cpu",
180
- confidence_threshold=tfidf_threshold,
181
- length_ratio_threshold=length_ratio_threshold
182
- )
183
- verdict = "NEI"
184
- details = ""
185
- prob3class, pred_tc = classify_claim(
186
- claim, evidence, model_tc, tokenizer_tc,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  "cuda" if torch.cuda.is_available() else "cpu"
188
  )
189
- if pred_tc != 0:
190
- prob2class, pred_bc = classify_claim(
191
- claim, evidence, model_bc, tokenizer_bc,
192
- "cuda" if torch.cuda.is_available() else "cpu"
193
- )
194
- if pred_bc == 0:
195
- verdict = "SUPPORTED"
196
- elif prob2class > prob3class:
197
- verdict = "REFUTED"
198
- else:
199
- verdict = ["NEI", "SUPPORTED", "REFUTED"][pred_tc]
200
- if show_details:
201
- details = f"<p><strong>3-Class Probability:</strong> {prob3class.item():.2f} - <strong>2-Class Probability:</strong> {prob2class.item():.2f}</p>"
202
-
203
- # Lưu lịch sử và kết quả kiểm chứng mới nhất
204
- st.session_state.history.append({
205
- "claim": claim,
206
- "evidence": evidence,
207
- "verdict": verdict
208
- })
209
- st.session_state.latest_result = {
210
- "claim": claim,
211
- "evidence": evidence,
212
- "verdict": verdict,
213
- "details": details
214
- }
215
-
216
- if torch.cuda.is_available():
217
- torch.cuda.empty_cache()
218
 
 
219
  res = st.session_state.latest_result
220
- st.markdown("<h3>Verification Result</h3>", unsafe_allow_html=True)
221
  st.markdown(f"""
222
  <div class='result-box'>
223
  <p><strong>Claim:</strong> {res['claim']}</p>
@@ -226,12 +275,14 @@ with st.container():
226
  {res['details']}
227
  </div>
228
  """, unsafe_allow_html=True)
 
229
  result_text = f"Claim: {res['claim']}\nEvidence: {res['evidence']}\nVerdict: {res['verdict']}\nDetails: {res['details']}"
230
  st.download_button("Download Result", data=result_text, file_name="verification_result.txt", mime="text/plain")
231
  else:
232
- st.info("No verification result yet.")
233
 
234
- elif nav_option == "History":
 
235
  st.subheader("Verification History")
236
  if st.session_state.history:
237
  for idx, record in enumerate(reversed(st.session_state.history), 1):
@@ -239,7 +290,8 @@ with st.container():
239
  else:
240
  st.write("No verification history yet.")
241
 
242
- elif nav_option == "About":
 
243
  st.subheader("About")
244
  st.markdown("""
245
  <p align="center">
@@ -259,8 +311,6 @@ with st.container():
259
  """, unsafe_allow_html=True)
260
  st.markdown("""
261
  **Description:**
262
- SemViQA is a semantic QA system designed for fact-checking in Vietnamese.
263
- It extracts evidence from the provided context and classifies the claim as **SUPPORTED**, **REFUTED**, or **NEI** (Not Enough Information) using state-of-the-art models.
264
- """)
265
-
266
- st.markdown("</div>", unsafe_allow_html=True)
 
5
  from semviqa.tvc.model import ClaimModelForClassification
6
  from semviqa.ser.ser_eval import extract_evidence_tfidf_qatc
7
  from semviqa.tvc.tvc_eval import classify_claim
 
8
  import io
9
 
10
  # Load models with caching
 
18
  # Set up page configuration
19
  st.set_page_config(page_title="SemViQA Demo", layout="wide")
20
 
21
+ # Custom CSS: fixed navigation, header, and adjusted height
22
  st.markdown("""
23
  <style>
24
+ html, body {
25
+ height: 100%;
26
+ margin: 0;
27
+ overflow: hidden;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  }
29
  .main-container {
 
30
  height: calc(100vh - 55px);
31
  overflow-y: auto;
32
  padding: 20px;
33
  }
34
+ .big-title {
35
+ font-size: 36px;
36
+ font-weight: bold;
37
+ color: #4A90E2;
38
+ text-align: center;
39
+ margin-top: 20px;
40
+ position: sticky;
41
+ top: 0;
42
+ background-color: white;
43
+ z-index: 100;
44
+ padding: 10px 0;
45
+ }
46
+ .sub-title {
47
+ font-size: 20px;
48
+ color: #666;
49
+ text-align: center;
50
+ margin-bottom: 20px;
51
+ position: sticky;
52
+ top: 56px;
53
+ background-color: white;
54
+ z-index: 100;
55
+ padding-bottom: 10px;
56
  }
57
+ .stButton>button {
58
+ background-color: #4CAF50;
59
+ color: white;
60
+ font-size: 16px;
61
+ width: 100%;
62
+ border-radius: 8px;
63
+ padding: 10px;
64
+ }
65
+ .stTextArea textarea {
66
  font-size: 16px;
67
  min-height: 120px;
68
  }
69
+ .result-box {
70
+ background-color: #f9f9f9;
71
+ padding: 20px;
72
+ border-radius: 10px;
73
+ box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
74
  margin-top: 20px;
75
  }
76
+ .verdict {
77
+ font-size: 24px;
78
+ font-weight: bold;
79
  margin: 0;
80
  display: flex;
81
  align-items: center;
82
  }
83
+ .verdict-icon {
84
  margin-right: 10px;
85
  }
86
+ /* Fixed sidebar */
87
+ .css-1d391kg, .css-1cypcdb {
88
+ position: sticky;
89
+ top: 0;
90
+ height: calc(100vh - 55px);
91
+ overflow-y: auto;
92
+ }
93
+ /* Tab content area */
94
+ .stTabs [data-baseweb="tab-panel"] {
95
+ height: calc(100vh - 150px);
96
+ overflow-y: auto;
97
+ }
98
+ /* Loading animation */
99
+ .loading-animation {
100
+ text-align: center;
101
+ padding: 20px;
102
+ }
103
+ .loading-animation .dot {
104
+ display: inline-block;
105
+ width: 12px;
106
+ height: 12px;
107
+ border-radius: 50%;
108
+ background-color: #4A90E2;
109
+ margin: 0 5px;
110
+ animation: pulse 1.4s infinite ease-in-out;
111
+ }
112
+ .loading-animation .dot:nth-child(2) {
113
+ animation-delay: 0.2s;
114
+ }
115
+ .loading-animation .dot:nth-child(3) {
116
+ animation-delay: 0.4s;
117
+ }
118
+ @keyframes pulse {
119
+ 0%, 100% { transform: scale(0.8); opacity: 0.5; }
120
+ 50% { transform: scale(1.2); opacity: 1; }
121
+ }
122
  </style>
123
  """, unsafe_allow_html=True)
124
 
125
+ # Main container with fixed height
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  with st.container():
127
+ st.markdown("<p class='big-title'>SemViQA: Semantic QA Information Verification System for Vietnamese</p>", unsafe_allow_html=True)
128
+ st.markdown("<p class='sub-title'>Enter information to verify and context to check its accuracy</p>", unsafe_allow_html=True)
129
+
130
+ # Sidebar: Global Settings
131
  with st.sidebar.expander("⚙️ Settings", expanded=True):
132
  tfidf_threshold = st.slider("TF-IDF Threshold", 0.0, 1.0, 0.5, 0.01)
133
  length_ratio_threshold = st.slider("Length Ratio Threshold", 0.1, 1.0, 0.5, 0.01)
 
145
  "SemViQA/bc-erniem-viwikifc",
146
  "SemViQA/bc-erniem-isedsc01"
147
  ])
148
+ tc_model_name = st.selectbox("3-Class Classification Model", [
149
  "SemViQA/tc-xlmr-viwikifc",
150
  "SemViQA/tc-xlmr-isedsc01",
151
  "SemViQA/tc-infoxlm-viwikifc",
 
155
  ])
156
  show_details = st.checkbox("Show probability details", value=False)
157
 
158
+ # Store verification history
159
  if 'history' not in st.session_state:
160
  st.session_state.history = []
161
  if 'latest_result' not in st.session_state:
162
  st.session_state.latest_result = None
163
+ if 'is_verifying' not in st.session_state:
164
+ st.session_state.is_verifying = False
165
 
166
+ # Load selected models
167
  tokenizer_qatc, model_qatc = load_model(qatc_model_name, QATCForQuestionAnswering)
168
  tokenizer_bc, model_bc = load_model(bc_model_name, ClaimModelForClassification, is_bc=True)
169
  tokenizer_tc, model_tc = load_model(tc_model_name, ClaimModelForClassification)
170
 
171
+ # Icons for results
172
  verdict_icons = {
173
  "SUPPORTED": "✅",
174
  "REFUTED": "❌",
175
  "NEI": "⚠️"
176
  }
177
+
178
+ # Create tabs: Verify, History, About
179
+ tabs = st.tabs(["Verify", "History", "About"])
180
+
181
+ # --- Verify Tab ---
182
+ with tabs[0]:
183
+ st.subheader("Verify Information")
184
+ # Use 2-column layout: inputs on left, results on right
185
  col_input, col_result = st.columns([2, 1])
186
 
187
  with col_input:
188
  claim = st.text_area("Enter Claim", "Vietnam is a country in Southeast Asia.")
189
  context = st.text_area("Enter Context", "Vietnam is a country located in Southeast Asia, covering an area of over 331,000 km² with a population of more than 98 million people.")
190
+
191
+ def start_verification():
192
+ st.session_state.is_verifying = True
193
+ st.experimental_rerun()
194
+
195
+ if st.button("Verify", key="verify_button", on_click=start_verification):
196
+ pass
197
 
198
+ # Display results in right column
199
  with col_result:
200
+ st.markdown("<h3>Verification Results</h3>", unsafe_allow_html=True)
201
+
202
+ if st.session_state.is_verifying:
203
+ # Show loading animation
204
+ st.markdown("""
205
+ <div class="result-box">
206
+ <p><strong>Processing verification...</strong></p>
207
+ <div class="loading-animation">
208
+ <span class="dot"></span>
209
+ <span class="dot"></span>
210
+ <span class="dot"></span>
211
+ </div>
212
+ <p>1. Extracting evidence...</p>
213
+ <p>2. Running binary classification...</p>
214
+ <p>3. Running 3-class classification...</p>
215
+ <p>4. Determining final verdict...</p>
216
+ </div>
217
+ """, unsafe_allow_html=True)
218
+
219
+ # Perform actual verification
220
+ with torch.no_grad():
221
+ # Extract evidence and classify information
222
+ evidence = extract_evidence_tfidf_qatc(
223
+ claim, context, model_qatc, tokenizer_qatc,
224
+ "cuda" if torch.cuda.is_available() else "cpu",
225
+ confidence_threshold=tfidf_threshold,
226
+ length_ratio_threshold=length_ratio_threshold
227
+ )
228
+ verdict = "NEI"
229
+ details = ""
230
+ prob3class, pred_tc = classify_claim(
231
+ claim, evidence, model_tc, tokenizer_tc,
232
+ "cuda" if torch.cuda.is_available() else "cpu"
233
+ )
234
+ if pred_tc != 0:
235
+ prob2class, pred_bc = classify_claim(
236
+ claim, evidence, model_bc, tokenizer_bc,
237
  "cuda" if torch.cuda.is_available() else "cpu"
238
  )
239
+ if pred_bc == 0:
240
+ verdict = "SUPPORTED"
241
+ elif prob2class > prob3class:
242
+ verdict = "REFUTED"
243
+ else:
244
+ verdict = ["NEI", "SUPPORTED", "REFUTED"][pred_tc]
245
+ if show_details:
246
+ details = f"<p><strong>3-Class Probability:</strong> {prob3class.item():.2f} - <strong>2-Class Probability:</strong> {prob2class.item():.2f}</p>"
247
+
248
+ # Save verification history and latest result
249
+ st.session_state.history.append({
250
+ "claim": claim,
251
+ "evidence": evidence,
252
+ "verdict": verdict
253
+ })
254
+ st.session_state.latest_result = {
255
+ "claim": claim,
256
+ "evidence": evidence,
257
+ "verdict": verdict,
258
+ "details": details
259
+ }
260
+
261
+ if torch.cuda.is_available():
262
+ torch.cuda.empty_cache()
263
+
264
+ # Turn off verification flag
265
+ st.session_state.is_verifying = False
266
+ st.experimental_rerun()
 
267
 
268
+ elif st.session_state.latest_result is not None:
269
  res = st.session_state.latest_result
 
270
  st.markdown(f"""
271
  <div class='result-box'>
272
  <p><strong>Claim:</strong> {res['claim']}</p>
 
275
  {res['details']}
276
  </div>
277
  """, unsafe_allow_html=True)
278
+ # Download verification result
279
  result_text = f"Claim: {res['claim']}\nEvidence: {res['evidence']}\nVerdict: {res['verdict']}\nDetails: {res['details']}"
280
  st.download_button("Download Result", data=result_text, file_name="verification_result.txt", mime="text/plain")
281
  else:
282
+ st.info("No verification results yet.")
283
 
284
+ # --- History Tab ---
285
+ with tabs[1]:
286
  st.subheader("Verification History")
287
  if st.session_state.history:
288
  for idx, record in enumerate(reversed(st.session_state.history), 1):
 
290
  else:
291
  st.write("No verification history yet.")
292
 
293
+ # --- About Tab ---
294
+ with tabs[2]:
295
  st.subheader("About")
296
  st.markdown("""
297
  <p align="center">
 
311
  """, unsafe_allow_html=True)
312
  st.markdown("""
313
  **Description:**
314
+ SemViQA is a Semantic QA system designed to verify information in Vietnamese.
315
+ The system extracts evidence from the provided context and classifies information as **SUPPORTED**, **REFUTED**, or **NEI** (Not Enough Information) based on advanced models.
316
+ """)