roncc13 commited on
Commit
ef5873e
·
verified ·
1 Parent(s): 042d556

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +235 -107
app.py CHANGED
@@ -30,7 +30,7 @@ def classify(text: str):
30
 
31
 
32
  # --------------------------
33
- # CSS matching the mockup
34
  # --------------------------
35
  custom_css = """
36
  body {
@@ -42,10 +42,17 @@ body {
42
  "Segoe UI", sans-serif;
43
  max-width: 1120px !important;
44
  margin: 0 auto !important;
45
- padding: 32px 24px 40px 24px !important;
46
  color: #f9fafb;
47
  }
48
 
 
 
 
 
 
 
 
49
  /* Main cards */
50
  .glass-card {
51
  background: rgba(15, 23, 42, 0.96); /* near indigo-950 */
@@ -188,12 +195,8 @@ textarea {
188
  """
189
 
190
 
191
- # --------------------------
192
- # UI
193
- # --------------------------
194
- with gr.Blocks(fill_height=True) as demo:
195
- # Header bar
196
- gr.HTML(
197
  """
198
  <header class="cmd-header">
199
  <div class="cmd-header-left">
@@ -211,109 +214,234 @@ with gr.Blocks(fill_height=True) as demo:
211
  """
212
  )
213
 
214
- # Hero section
215
- gr.HTML(
216
- """
217
- <section style="margin-bottom:22px;">
218
- <div class="hero-title">
219
- Check Cebuano text for a misleading writing style.
220
- </div>
221
- <div class="hero-subtitle">
222
- This tool analyzes linguistic patterns and writing style in Cebuano text to detect potential
223
- misinformation. It does not verify factual correctness. The model returns a classification
224
- (Fake/Legit) and a confidence score based on writing patterns.
225
- </div>
226
- </section>
227
- """
228
- )
229
 
230
- # Main two-column layout
231
- with gr.Row(elem_classes=["two-col"], equal_height=True):
232
- # Left: input card
233
- with gr.Column(scale=3):
234
- with gr.Group(elem_classes=["glass-card"]):
235
- gr.Markdown(
236
- "#### Text input\n"
237
- "Cebuano only. This tool checks linguistic patterns; it does not verify facts."
238
- )
239
- gr.Markdown(
240
- "> **Example** \n"
241
- "> “Nakadisubre og milagro nga tambal sa COVID‑19 ang usa ka local doktor, "
242
- "giingon nga walay side effects ug dili kinahanglan og bakuna.”"
243
- )
244
- news_text = gr.Textbox(
245
- lines=7,
246
- label="",
247
- placeholder="Paste Cebuano news text here..."
248
- )
249
- with gr.Row():
250
- analyze_btn = gr.Button("Analyze", elem_classes=["btn-primary-custom"])
251
- clear_btn = gr.Button("Clear", elem_classes=["btn-secondary-custom"])
252
- gr.Markdown(
253
- "<span style='font-size:11px;opacity:0.8;'>"
254
- "Tip: Keep inputs under 1,000 characters for faster results."
255
- "</span>"
256
- )
257
-
258
- # Right: result card
259
- with gr.Column(scale=2):
260
- with gr.Group(elem_classes=["glass-card"]):
261
- gr.Markdown("#### Result")
262
- result_label_html = gr.HTML(
263
- '<span class="badge-pill badge-fake">FAKE</span>'
264
- )
265
- conf_text = gr.HTML(
266
- '<div style="display:flex;align-items:flex-end;gap:6px;margin-top:10px;">'
267
- '<span style="font-size:28px;font-weight:600;" id="conf-val">0.00</span>'
268
- '<span style="font-size:12px;opacity:0.8;">confidence</span>'
269
- '</div>'
270
- )
271
- conf_bar = gr.HTML(
272
- '<div class="conf-bar-bg">'
273
- '<div class="conf-bar-fill" style="width:0%;"></div>'
274
- '</div>'
275
- )
276
- gr.Markdown(
277
- "<span style='font-size:11px;opacity:0.85;'>"
278
- "Model: CMD‑BERT (fine‑tuned BERT‑base). "
279
- "Output: Label and confidence score for the submitted text."
280
- "</span>"
281
- )
282
-
283
- # Backend → UI glue
284
- def analyze_ui(text):
285
- probs = classify(text)
286
- fake_p = probs.get("fake", 0.0)
287
- real_p = probs.get("real", 0.0)
288
- if fake_p >= real_p:
289
- label = "FAKE"
290
- css_class = "badge-pill badge-fake"
291
- conf = fake_p
292
- else:
293
- label = "LEGIT"
294
- css_class = "badge-pill badge-real"
295
- conf = real_p
296
- conf_pct = int(conf * 100)
297
- label_html = f'<span class="{css_class}">{label}</span>'
298
- conf_html = (
299
- '<div style="display:flex;align-items:flex-end;gap:6px;margin-top:10px;">'
300
- f'<span style="font-size:28px;font-weight:600;" id="conf-val">{conf:.2f}</span>'
301
- '<span style="font-size:12px;opacity:0.8;">confidence</span>'
302
- '</div>'
303
  )
304
- bar_html = (
305
- '<div class="conf-bar-bg">'
306
- f'<div class="conf-bar-fill" style="width:{conf_pct}%;"></div>'
307
- '</div>'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  )
309
- return label_html, conf_html, bar_html
310
 
311
- analyze_btn.click(
312
- fn=analyze_ui,
313
- inputs=news_text,
314
- outputs=[result_label_html, conf_text, conf_bar],
315
- )
316
- clear_btn.click(fn=lambda: "", inputs=None, outputs=[news_text])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
 
318
 
319
  if __name__ == "__main__":
 
30
 
31
 
32
  # --------------------------
33
+ # CSS
34
  # --------------------------
35
  custom_css = """
36
  body {
 
42
  "Segoe UI", sans-serif;
43
  max-width: 1120px !important;
44
  margin: 0 auto !important;
45
+ padding: 24px 24px 40px 24px !important;
46
  color: #f9fafb;
47
  }
48
 
49
+ /* Remove default white cards so our glass style shows */
50
+ .gradio-container .block {
51
+ background: transparent !important;
52
+ border: none !important;
53
+ box-shadow: none !important;
54
+ }
55
+
56
  /* Main cards */
57
  .glass-card {
58
  background: rgba(15, 23, 42, 0.96); /* near indigo-950 */
 
195
  """
196
 
197
 
198
+ def header_html():
199
+ return gr.HTML(
 
 
 
 
200
  """
201
  <header class="cmd-header">
202
  <div class="cmd-header-left">
 
214
  """
215
  )
216
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
 
218
+ # --------------------------
219
+ # UI with Tabs
220
+ # --------------------------
221
+ with gr.Blocks(fill_height=True) as demo:
222
+ # small spacer so tabs are not glued to the top
223
+ gr.HTML("<div style='height:8px;'></div>")
224
+
225
+ with gr.Tab("Analyzer"):
226
+ header_html()
227
+ gr.HTML(
228
+ """
229
+ <section style="margin-bottom:22px;">
230
+ <div class="hero-title">
231
+ Check Cebuano text for a misleading writing style.
232
+ </div>
233
+ <div class="hero-subtitle">
234
+ This tool analyzes linguistic patterns and writing style in Cebuano text to detect potential
235
+ misinformation. It does not verify factual correctness. The model returns a classification
236
+ (Fake/Legit) and a confidence score based on writing patterns.
237
+ </div>
238
+ </section>
239
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  )
241
+
242
+ with gr.Row(elem_classes=["two-col"], equal_height=True):
243
+ # Left: input card
244
+ with gr.Column(scale=3):
245
+ with gr.Group(elem_classes=["glass-card"]):
246
+ gr.Markdown(
247
+ "#### Text input\n"
248
+ "Cebuano only. This tool checks linguistic patterns; it does not verify facts."
249
+ )
250
+ gr.Markdown(
251
+ "> **Example** \n"
252
+ "> “Nakadisubre og milagro nga tambal sa COVID‑19 ang usa ka local doktor, "
253
+ "giingon nga walay side effects ug dili kinahanglan og bakuna.”"
254
+ )
255
+ news_text = gr.Textbox(
256
+ lines=7,
257
+ label="",
258
+ placeholder="Paste Cebuano news text here..."
259
+ )
260
+ with gr.Row():
261
+ analyze_btn = gr.Button("Analyze", elem_classes=["btn-primary-custom"])
262
+ clear_btn = gr.Button("Clear", elem_classes=["btn-secondary-custom"])
263
+ gr.Markdown(
264
+ "<span style='font-size:11px;opacity:0.8;'>"
265
+ "Tip: Keep inputs under 1,000 characters for faster results."
266
+ "</span>"
267
+ )
268
+
269
+ # Right: result card
270
+ with gr.Column(scale=2):
271
+ with gr.Group(elem_classes=["glass-card"]):
272
+ gr.Markdown("#### Result")
273
+ result_label_html = gr.HTML(
274
+ '<span class="badge-pill badge-fake">FAKE</span>'
275
+ )
276
+ conf_text = gr.HTML(
277
+ '<div style="display:flex;align-items:flex-end;gap:6px;margin-top:10px;">'
278
+ '<span style="font-size:28px;font-weight:600;" id="conf-val">0.00</span>'
279
+ '<span style="font-size:12px;opacity:0.8;">confidence</span>'
280
+ '</div>'
281
+ )
282
+ conf_bar = gr.HTML(
283
+ '<div class="conf-bar-bg">'
284
+ '<div class="conf-bar-fill" style="width:0%;"></div>'
285
+ '</div>'
286
+ )
287
+ gr.Markdown(
288
+ "<span style='font-size:11px;opacity:0.85;'>"
289
+ "Model: CMD‑BERT (fine‑tuned BERT‑base). "
290
+ "Output: Label and confidence score for the submitted text."
291
+ "</span>"
292
+ )
293
+
294
+ def analyze_ui(text):
295
+ probs = classify(text)
296
+ fake_p = probs.get("fake", 0.0)
297
+ real_p = probs.get("real", 0.0)
298
+ if fake_p >= real_p:
299
+ label = "FAKE"
300
+ css_class = "badge-pill badge-fake"
301
+ conf = fake_p
302
+ else:
303
+ label = "LEGIT"
304
+ css_class = "badge-pill badge-real"
305
+ conf = real_p
306
+ conf_pct = int(conf * 100)
307
+ label_html = f'<span class="{css_class}">{label}</span>'
308
+ conf_html = (
309
+ '<div style="display:flex;align-items:flex-end;gap:6px;margin-top:10px;">'
310
+ f'<span style="font-size:28px;font-weight:600;" id="conf-val">{conf:.2f}</span>'
311
+ '<span style="font-size:12px;opacity:0.8;">confidence</span>'
312
+ '</div>'
313
+ )
314
+ bar_html = (
315
+ '<div class="conf-bar-bg">'
316
+ f'<div class="conf-bar-fill" style="width:{conf_pct}%;"></div>'
317
+ '</div>'
318
+ )
319
+ return label_html, conf_html, bar_html
320
+
321
+ analyze_btn.click(
322
+ fn=analyze_ui,
323
+ inputs=news_text,
324
+ outputs=[result_label_html, conf_text, conf_bar],
325
  )
326
+ clear_btn.click(fn=lambda: "", inputs=None, outputs=[news_text])
327
 
328
+ # -------- How it works tab --------
329
+ with gr.Tab("How it works"):
330
+ header_html()
331
+ with gr.Group(elem_classes=["glass-card"]):
332
+ gr.Markdown(
333
+ "## How CMD‑BERT works\n"
334
+ "CMD‑BERT is an AI‑augmented linguistic model that focuses on writing style, "
335
+ "not literal truth. It looks for patterns such as exaggerated wording, "
336
+ "over‑confident claims, and framing that often appear in misleading content."
337
+ )
338
+ with gr.Row():
339
+ with gr.Column():
340
+ with gr.Group(elem_classes=["glass-card"]):
341
+ gr.Markdown(
342
+ "### 1. Input and preprocessing\n"
343
+ "- User pastes a Cebuano headline, post, or short article.\n"
344
+ "- The text is tokenized and trimmed to a safe maximum length.\n"
345
+ "- Inputs are processed in memory and not stored permanently."
346
+ )
347
+ with gr.Column():
348
+ with gr.Group(elem_classes=["glass-card"]):
349
+ gr.Markdown(
350
+ "### 2. CMD‑BERT analysis\n"
351
+ "- CMD‑BERT is a fine‑tuned BERT‑base model trained on Cebuano news.\n"
352
+ "- It computes probabilities for two classes: **Fake** and **Legit**.\n"
353
+ "- The highest‑probability class becomes the predicted label."
354
+ )
355
+ with gr.Group(elem_classes=["glass-card"]):
356
+ gr.Markdown(
357
+ "### 3. Result and interpretation\n"
358
+ "- The interface shows the predicted label and confidence bar.\n"
359
+ "- Users are reminded that this is a screening tool only.\n"
360
+ "- Final judgment should always involve human critical thinking."
361
+ )
362
+
363
+ # -------- About tab --------
364
+ with gr.Tab("About"):
365
+ header_html()
366
+ with gr.Group(elem_classes=["glass-card"]):
367
+ gr.Markdown(
368
+ "## About CMD‑BERT\n"
369
+ "**CMD‑BERT: An AI Augmented Linguistic Recognition Model for Cebuano Fake News Detection**\n\n"
370
+ "CMD‑BERT is a thesis project in the Department of Computer Engineering at "
371
+ "Cebu Technological University–Main Campus. The tool aims to support Cebuano readers "
372
+ "by highlighting potentially misleading writing patterns in online news and posts."
373
+ )
374
+ with gr.Group(elem_classes=["glass-card"]):
375
+ gr.Markdown(
376
+ "### Thesis information\n"
377
+ "_A Thesis Project presented to the Faculty of the Department of Computer Engineering_\n\n"
378
+ "Cebu Technological University–Main Campus \n"
379
+ "Cebu City, Philippines \n\n"
380
+ "_In partial fulfillment of the requirements for the degree_ \n"
381
+ "**Bachelor of Science in Computer Engineering**\n\n"
382
+ "**By:** \n"
383
+ "- Cabag, Ronilo Jose Jr. S. \n"
384
+ "- Libron, Andio Mart \n"
385
+ "- Omega, Noel \n\n"
386
+ "**Adviser:** Engr. Jueco, M.Eng. \n"
387
+ "January 2026"
388
+ )
389
+
390
+ # -------- Feedback tab --------
391
+ with gr.Tab("Feedback"):
392
+ header_html()
393
+ with gr.Group(elem_classes=["glass-card"]):
394
+ gr.Markdown(
395
+ "## Feedback and model improvement\n"
396
+ "CMD‑BERT is experimental and continuously improving. Your feedback can help "
397
+ "identify model mistakes, usability issues, and opportunities to refine the dataset."
398
+ )
399
+
400
+ with gr.Row():
401
+ with gr.Column():
402
+ with gr.Group(elem_classes=["glass-card"]):
403
+ fb_type = gr.Dropdown(
404
+ ["Bug / technical issue", "Model mistake", "UI suggestion", "Other"],
405
+ label="Feedback type"
406
+ )
407
+ fb_text = gr.Textbox(
408
+ lines=6,
409
+ label="Your message or example text",
410
+ placeholder="Describe the issue or paste an example of text the model misclassified."
411
+ )
412
+ fb_email = gr.Textbox(
413
+ label="Email (optional, for follow‑up)",
414
+ placeholder="you@example.com"
415
+ )
416
+ fb_checkbox = gr.Checkbox(
417
+ label="Allow us to use this text anonymously for future model improvements.",
418
+ value=True
419
+ )
420
+ fb_submit = gr.Button("Submit feedback", elem_classes=["btn-primary-custom"])
421
+
422
+ with gr.Column():
423
+ with gr.Group(elem_classes=["glass-card"]):
424
+ fb_status = gr.Markdown("No feedback submitted yet.")
425
+ gr.Markdown(
426
+ "### FAQ\n"
427
+ "**What happens to my feedback?** \n"
428
+ "It is stored securely and reviewed by the CMD‑BERT thesis team.\n\n"
429
+ "**Will CMD‑BERT replace human fact‑checkers?** \n"
430
+ "No. It is a support tool to encourage critical reading.\n\n"
431
+ "**Who maintains this tool?** \n"
432
+ "The CMD‑BERT thesis team at Cebu Technological University–Main Campus."
433
+ )
434
+
435
+ def save_feedback(ftype, text, email, consent):
436
+ if not text.strip():
437
+ return "Please enter a message before submitting."
438
+ return "Thank you for your feedback! It has been recorded."
439
+
440
+ fb_submit.click(
441
+ fn=save_feedback,
442
+ inputs=[fb_type, fb_text, fb_email, fb_checkbox],
443
+ outputs=fb_status,
444
+ )
445
 
446
 
447
  if __name__ == "__main__":