# ============================================================================== # đŸ›Ąī¸ FraudGuard Myanmar AI - Final Master Pipeline # ============================================================================== import gradio as gr import requests import whois import re import feedparser import os import numpy as np from datetime import datetime from difflib import SequenceMatcher from PIL import Image, ImageChops from sentence_transformers import SentenceTransformer, util import torch from transformers import AutoTokenizer, AutoModelForSequenceClassification from io import BytesIO from bs4 import BeautifulSoup # --- 1. MODEL LOADING --- print("System Initializing... Loading All AI Components.") MODEL_NAME = "Poe255M/myanmar-fraud-detection-final" try: # Hugging Face မှ Model နှင့á€ē Tokenizer ကို တိုကá€ēရိုကá€ēယူခá€ŧငá€ēး tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME) nlp_model = AutoModelForSequenceClassification.from_pretrained(MODEL_NAME) print(f"✅ Custom Myanmar AI Model Loaded from Hugging Face: {MODEL_NAME}") except Exception as e: print(f"âš ī¸ သတိပေးခá€ģကá€ē: Online Model ကို မတá€Ŋေ့ပá€Ģ။ Base Model ကို ယá€Ŧယဎသုá€ļးထá€Ŧးပá€Ģမညá€ē။ Error: {e}") tokenizer = AutoTokenizer.from_pretrained("xlm-roberta-base") nlp_model = AutoModelForSequenceClassification.from_pretrained("xlm-roberta-base", num_labels=2) device = 'cuda' if torch.cuda.is_available() else 'cpu' nlp_model.to(device) nlp_model.eval() print("Loading CLIP model for multi-modal verification...") clip_model = SentenceTransformer('clip-ViT-B-32') # --- 2. CORE LOGIC MODULES --- class VerificationSystem: @staticmethod def translate_to_en(text): """CLIP Model ဖá€ŧင့á€ē ပုá€ļကိုစစá€ēဆေးရနá€ēအတá€Ŋကá€ēသá€Ŧ သုá€ļးမညá€ē""" try: url = f"https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=en&dt=t&q={text}" res = requests.get(url, timeout=5).json() return "".join([s[0] for s in res[0]]) except: return text @staticmethod def verify_headline_match(user_text, url): """User ရိုကá€ēတဲ့စá€Ŧနဲ့ URL ထဲက မူရငá€ēးခေá€Ģငá€ēးစဉá€ē တူ၊ မတူ စစá€ēဆေးရနá€ē""" if not url or not url.startswith("http"): return 100, "N/A" try: headers = {'User-Agent': 'Mozilla/5.0'} res = requests.get(url, headers=headers, timeout=10) soup = BeautifulSoup(res.text, 'html.parser') original_title = "" h1 = soup.find('h1') if h1: original_title = h1.get_text().strip() elif soup.title: original_title = soup.title.get_text().strip() if not original_title: return 50, "Could not extract title from source" similarity = SequenceMatcher(None, user_text.lower(), original_title.lower()).ratio() match_score = similarity * 100 msg = f"✅ Original Title: {original_title[:60]}..." if match_score > 60 else f"âš ī¸ Mismatch! Source Title: {original_title[:60]}..." return match_score, msg except: return 50, "Error Fetching Source Title" @staticmethod def perform_ela(image_path, quality=90): if not image_path: return 100, "No image" try: original = Image.open(image_path).convert('RGB') resaved_path = "temp_forensic.jpg" original.save(resaved_path, 'JPEG', quality=quality) resaved = Image.open(resaved_path) ela_diff = ImageChops.difference(original, resaved) stat = np.array(ela_diff).mean() if os.path.exists(resaved_path): os.remove(resaved_path) if stat > 1.2: score = max(10, 100 - (stat * 40)) return score, "âš ī¸ Tampering Detected" elif stat > 0.8: score = max(50, 100 - (stat * 20)) return score, "🟡 Minor Edits/Low Quality" else: score = min(100, 100 - (stat * 5)) return score, "✅ Consistent Pixels" except: return 50, "Scan Error" @staticmethod def extract_image_from_url(url): if not url: return None try: headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'} if any(url.lower().endswith(ext) for ext in ['.jpg', '.jpeg', '.png', '.webp']): res = requests.get(url, headers=headers, timeout=10) img = Image.open(BytesIO(res.content)).convert('RGB') path = "temp_url_image.jpg" img.save(path) return path response = requests.get(url, headers=headers, timeout=10) soup = BeautifulSoup(response.text, 'html.parser') img_tag = soup.find("meta", property="og:image") or soup.find("meta", attrs={"name": "twitter:image"}) img_url = img_tag["content"] if img_tag and img_tag.has_attr("content") else None if not img_url: first_img = soup.find("img") img_url = first_img["src"] if first_img and first_img.has_attr("src") else None if img_url: if img_url.startswith('//'): img_url = 'https:' + img_url elif img_url.startswith('/'): from urllib.parse import urljoin img_url = urljoin(url, img_url) img_res = requests.get(img_url, headers=headers, timeout=10) img = Image.open(BytesIO(img_res.content)).convert('RGB') path = "temp_extracted_image.jpg" img.save(path) return path except: return None return None @staticmethod def get_image_text_similarity(image_path, text, url="", url_image_path=None): if not image_path or not text: return 50, "Incomplete Data" try: is_myanmar = bool(re.search(r'[\u1000-\u109F]', text)) processed_text = VerificationSystem.translate_to_en(text) if is_myanmar else text img_obj = Image.open(image_path) img_emb = clip_model.encode(img_obj) text_emb = clip_model.encode([processed_text]) similarity = util.cos_sim(img_emb, text_emb).item() is_trusted_source = False trusted_domains = ["bbc.com", "reuters.com", "apnews.com", "voanews.com", "rfa.org", "nytimes.com"] if url: for d in trusted_domains: if d in url.lower(): is_trusted_source = True break is_text_match = similarity >= 0.22 if is_text_match: final_score = min(100, similarity * 240) msg = "✅ စá€Ŧသá€Ŧးနှင့á€ē ပုá€ļ ကိုကá€ēညဎမသုရသိသညá€ē" if is_myanmar else "✅ Context Matches" else: if is_trusted_source: final_score = 55.0 msg = "â„šī¸ သတငá€ēးရငá€ēးမá€ŧစá€ēမှá€Ŧ ယုá€ļကá€ŧညá€ēရသေá€Ŧá€ēလညá€ēး ပုá€ļမှá€Ŧ သရုပá€ēပá€ŧပုá€ļ (Illustrative) သá€Ŧ ဖá€ŧစá€ēနိုငá€ēပá€Ģသညá€ē" if is_myanmar else "â„šī¸ Trusted source but image may be illustrative" else: final_score = max(10, similarity * 130) msg = "❌ စá€Ŧသá€Ŧးနှင့á€ē ပုá€ļ မကိုကá€ēညီပá€Ģ" if is_myanmar else "❌ Content Mismatch" img_match_pct = 0 has_url_img = False if url_image_path and os.path.exists(url_image_path): has_url_img = True url_img_emb = clip_model.encode(Image.open(url_image_path)) img_similarity = util.cos_sim(img_emb, url_img_emb).item() img_match_pct = img_similarity * 100 if img_match_pct > 80: if not is_text_match: final_score = 65.0 if is_trusted_source else 45.0 msg = "âš ī¸ Link ပá€Ģပုá€ļနှင့á€ē တူသေá€Ŧá€ēလညá€ēး ခေá€Ģငá€ēးစဉá€ēနှင့á€ē တိုကá€ēရိုကá€ēမသကá€ēဆိုငá€ēပá€Ģ" if is_myanmar else "âš ī¸ Image matches Source but Mismatches Headline" else: final_score = min(100, final_score + 15) msg = "✅ မူရငá€ēးသတငá€ēးပá€Ģပုá€ļဖá€ŧစá€ēပá€ŧီး စá€Ŧသá€Ŧးနှင့á€ēလညá€ēး ကိုကá€ēညီပá€Ģသညá€ē" if is_myanmar else "✅ Verified Source Image Match" elif img_match_pct < 50: final_score = max(10, final_score - 25) msg += " | âš ī¸ Link ထဲမှ မူရငá€ēးပုá€ļမဟုတá€ēပá€Ģ" if is_myanmar else " | âš ī¸ Not the Original Image from Link" if has_url_img and not is_text_match and img_match_pct < 50 and not is_trusted_source: final_score = 10.5 msg = "🚨 သတငá€ēးအခá€ģကá€ēအလကá€ēအá€Ŧးလုá€ļး လá€Ŋဲမှá€Ŧးနေပá€Ģသညá€ē (High Risk)" if is_myanmar else "🚨 High Risk: Complete Information Mismatch" return round(max(5, final_score), 2), msg except Exception as e: return 50, f"Verification Error: {str(e)}" @staticmethod def get_source_score(url): if not url or not url.startswith("http"): return 30, "Missing/Invalid URL Source" try: domain_search = re.search(r'https?://([A-Za-z0-9.-]+)', url) if not domain_search: return 30, "Invalid Domain" domain = domain_search.group(1).lower() # --- ၁။ တရá€Ŧးဝငá€ē သတငá€ēးဌá€Ŧနကá€ŧီးမá€ģá€Ŧး (Hard News) --- trusted_news = ["bbc.com", "reuters.com", "rfa.org", "voanews.com", "dvb.no", "irrawaddy.com", "myanmar-now.org", "khitthitnews.com", "mizzima.com"] # --- ၂။ နá€Ŧမညá€ēကá€ŧီး á€Ąá€”á€¯á€•á€Šá€Ŧ/ဆယá€ēလီ မီဒီယá€Ŧမá€ģá€Ŧး (Cele Media) --- trusted_cele = ["myanmarcelebrity.com", "popularmyanmar.com", "celegabar.com", "shwemon.com", "celeyatkwat.com"] # (က) သတငá€ēးဌá€Ŧနကá€ŧီးမá€ģá€Ŧး စစá€ēဆေးခá€ŧငá€ēး for m in trusted_news: if domain == m or domain.endswith("." + m): return 100, f"Verified News Media ({domain})" # (ခ) á€Ąá€”á€¯á€•á€Šá€Ŧသတငá€ēးဌá€Ŧနမá€ģá€Ŧး စစá€ēဆေးခá€ŧငá€ēး for c in trusted_cele: if domain == c or domain.endswith("." + c): return 90, f"Verified Entertainment Media ({domain})" # --- ၃။ Social Media Links (Facebook, Instagram) စစá€ēဆေးခá€ŧငá€ēး --- # ဆယá€ēလီသတငá€ēးအမá€ģá€Ŧးစုသညá€ē Social Media ပေá€Ģá€ēတá€Ŋငá€ēသá€Ŧ ရှိတတá€ēသဖá€ŧင့á€ē သီးသန့á€ēစစá€ēဆေးမညá€ē if "facebook.com" in domain or "instagram.com" in domain: path = url.split(domain)[-1].lower() # Official Page ဟု ယူဆနိုငá€ēသေá€Ŧ လက္ခဏá€Ŧမá€ģá€Ŧး (á€Ĩပမá€Ŧ - facebook.com/naytoe.official) if "official" in path or "original" in path or "verified" in path: return 85, "Likely Official Social Media Account" # Facebook Group á€žá€­á€¯á€ˇá€™á€Ÿá€¯á€á€ē Video Link သီးသန့á€ēဖá€ŧစá€ēနေလá€ģှငá€ē (သတငá€ēးတုဖá€ŧန့á€ēရနá€ē á€Ąá€žá€¯á€ļးမá€ģá€Ŧးသေá€Ŧ နေရá€Ŧမá€ģá€Ŧး) elif "/groups/" in path or "/watch/" in path or "reel" in path: return 40, "Social Media Group/Video (Unverified Origin)" # သá€Ŧမနá€ē Page á€žá€­á€¯á€ˇá€™á€Ÿá€¯á€á€ē Profile ဖá€ŧစá€ēလá€ģှငá€ē (ကá€ŧá€Ŧးနေအမှတá€ēပေးမညá€ē) else: return 60, "General Social Media Source (Needs Cross-check)" # --- ၄။ အမညá€ēမသိ Domain မá€ģá€Ŧးကို WHOIS ဖá€ŧင့á€ē သကá€ēတမá€ēးစစá€ēခá€ŧငá€ēး (Fake Sites မá€ģá€Ŧးကို ဖမá€ēးရနá€ē) --- w = whois.whois(domain) creation_date = w.creation_date if isinstance(creation_date, list): creation_date = creation_date[0] if creation_date: from datetime import datetime age_days = (datetime.now() - creation_date).days age_months = age_days // 30 if age_days < 180: return 15, f"âš ī¸ Very New/Suspicious Site (Age: {age_months} months)" elif age_days < 730: return 50, f"Neutral Site (Age: {age_months} months)" else: return 80, f"Established Site (Age: {age_months // 12} years)" else: return 30, "Unknown Identity (No Creation Date)" except Exception as e: return 20, "Hidden/Suspicious Source Identity" @staticmethod def get_nlp_prediction(text): if not text or len(text.split()) < 3: return 10.0 # ၁။ AI Model မှ ရလဒá€ēယူခá€ŧငá€ēး inputs = tokenizer(text, max_length=512, padding="max_length", truncation=True, return_tensors="pt").to(device) import torch with torch.no_grad(): outputs = nlp_model(**inputs) probs = torch.nn.functional.softmax(outputs.logits, dim=-1)[0] real_score = probs[0].item() * 100 text_lower = text.lower() penalty = 0 # (က) Health Scam ဖမá€ēးရနá€ē (WHO/á€žá€¯á€á€ąá€žá€” နá€Ŧမညá€ēသုá€ļးပá€ŧီး လိမá€ēထá€Ŧးလá€ģှငá€ē) health_keywords = ["ကá€ģနá€ēးမá€Ŧရေး", "ရေá€Ŧဂá€Ģ", "ဆေး", "who", "á€žá€¯á€á€ąá€žá€”", "အတညá€ēပá€ŧု"] if any(kw in text_lower for kw in health_keywords): scam_words = ["၁၀၀%", "အá€Ŧမခá€ļ", "ခá€ģကá€ēခá€ģငá€ēး", "လá€ģá€žá€­á€¯á€ˇá€á€žá€€á€ēခá€ģကá€ē", "မဖá€ŧစá€ēမနေ", "ပá€ģေá€Ŧကá€ēကငá€ēး", "လုá€ļးဝကá€Ŧကá€Ŋယá€ē", "အထူးသဖá€ŧငá€ē့", "á€•á€­á€¯á€™á€­á€¯á€‘á€­á€›á€ąá€Ŧကá€ē"] if any(sw in text_lower for sw in scam_words): penalty += 35 # ကá€ģနá€ēးမá€Ŧရေးလိမá€ēလညá€ēမသုဖá€ŧစá€ē၍ အမှတá€ēမá€ģá€Ŧးမá€ģá€Ŧးလá€ģှေá€Ŧ့မညá€ē # (ခ) Cele News မှနá€ēလá€ģှငá€ē Penalty မထိစေရနá€ē ကá€Ŧကá€Ŋယá€ēခá€ŧငá€ēး cele_keywords = ["မငá€ēးသá€Ŧး", "မငá€ēးသမီး", "á€Ąá€†á€­á€¯á€á€ąá€Ŧá€ē", "သရုပá€ēဆေá€Ŧငá€ē", "ဆယá€ēလီ", "လကá€ēထပá€ē", "celebrity"] is_cele = any(kw in text_lower for kw in cele_keywords) # ၂။ Case 2 & 3 အတá€Ŋကá€ē အထူး Red Flags (Heuristics) - (ညီမ၏ မူလ Code á€Ąá€á€­á€¯á€„á€ēး) urgency_patterns = [ "ပိတá€ēသိမá€ēးသá€Ŋá€Ŧးမညá€ē", "ပိတá€ēသိမá€ēးတေá€Ŧ့မယá€ē", "အမá€ŧနá€ēဆုá€ļး", "လကá€ēဆင့á€ēကမá€ēး", "အတá€Ŋငá€ēးသတငá€ēး", "Update ပá€ŧုလုပá€ēရပá€Ģမညá€ē", "Personal Information", "အကေá€Ŧင့á€ēပိတá€ēသိမá€ēး", "ယá€Ŧယီပိတá€ēသိမá€ēး", "မယုá€ļနိုငá€ēစရá€Ŧ", "၁၀၀% အမှနá€ē" ] if is_cele: # ဆယá€ēလီသတငá€ēးဆိုလá€ģှငá€ē "မယုá€ļနိုငá€ēစရá€Ŧ" á€€á€˛á€ˇá€žá€­á€¯á€ˇá€žá€ąá€Ŧ စကá€Ŧးလုá€ļးမá€ģá€Ŧးအတá€Ŋကá€ē Penalty မပေးတေá€Ŧ့ပá€Ģ။ # Clickbait လင့á€ēခá€ēနှိပá€ēခိုငá€ēးတá€Ŧမá€ģá€­á€¯á€¸á€€á€­á€¯á€•á€˛ သီးသန့á€ēစစá€ēပá€Ģမညá€ē။ clickbait_patterns = ["ဗဎဒဎယိုကá€ŧည့á€ēရနá€ē", "ရှယá€ēထá€Ŧး", "လင့á€ēခá€ēဝငá€ēကá€ŧည့á€ē", "ဖုနá€ēးဘေလá€ē", "လကá€ēဆေá€Ŧငá€ē"] for pattern in clickbait_patterns: if pattern in text_lower: penalty += 20 else: for pattern in urgency_patterns: if pattern in text: penalty += 20 # တစá€ēခုပá€Ģတိုငá€ēး ၂၀% လá€ģှေá€Ŧ့ခá€ģမညá€ē # ၃။ AI က ၉၀% ကá€ģေá€Ŧá€ē အစစá€ēá€œá€­á€¯á€ˇá€•á€ŧေá€Ŧရငá€ēတေá€Ŧငá€ē Penalty ပá€Ģရငá€ē Score ကို ခá€ģကá€ēခá€ģငá€ēးခá€ģမညá€ē final_score = real_score - penalty # ၄။ Logic Correction (Case 2/3 Fix) # AI က သိပá€ēမသေခá€ģá€Ŧဘူး (၇၅% အေá€Ŧကá€ē) ဆိုရငá€ē 'သá€ļသယဖá€ŧစá€ēဖá€Ŋယá€ē' ဘကá€ēကို á€•á€­á€¯á€•á€­á€¯á€ˇá€™á€Šá€ē if final_score < 75:final_score = final_score * 0.6 # Score ကို ထပá€ēလá€ģှေá€Ŧ့ခá€ģခá€ŧငá€ēး return round(max(5, final_score), 2) @staticmethod def check_rss_similarity(headline, url=""): import requests if not headline or len(headline) < 10: return 0 trusted_domains = [ "bbc.com/burmese", "rfa.org/burmese", "burmese.voanews.com", "mizzima.com", "khitthitnews.org", "dvb.no", "myanmar-now.org", "reuters.com", "apnews.com", "nytimes.com", "cnn.com", "theguardian.com", "aljazeera.com", "dw.com", "france24.com", "bloomberg.com", "wsj.com", "forbes.com","myanmarcelebrity.com" ] base_bonus = 0 if url: for domain in trusted_domains: if domain in url.lower(): base_bonus = 90 break feeds = [ "https://burmese.voanews.com/api/z$y_iqve_t", "https://www.rfa.org/burmese/rss2.xml", "https://www.bbc.com/burmese/index.xml", "https://burmese.dvb.no/feed", "https://www.mizzimaburmese.com/rss", "https://www.khitthitnews.com/feed", "https://burmese.irrawaddy.com/feed", "https://www.myanmarcelebrity.com/feeds/posts/default?alt=rss", "https://popularmyanmar.com/feed/" ] headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'} max_sim = 0 clean_headline = re.sub(r'[^\\u1000-\\u109F a-zA-Z0-9]', ' ', headline).lower() headline_keywords = set([w for w in clean_headline.split() if len(w) > 2]) for f_url in feeds: try: response = requests.get(f_url, headers=headers, timeout=5) if response.status_code == 200: feed = feedparser.parse(response.content) for entry in feed.entries: seq_sim = SequenceMatcher(None, headline.lower(), entry.title.lower()).ratio() entry_clean = re.sub(r'[^\\u1000-\\u109F a-zA-Z0-9]', ' ', entry.title).lower() entry_keywords = set([w for w in entry_clean.split() if len(w) > 2]) common = headline_keywords.intersection(entry_keywords) keyword_sim = len(common) / len(headline_keywords) if headline_keywords else 0 max_sim = max(max_sim, seq_sim, keyword_sim) if max_sim > 0.85: break except: continue rss_val = min(100, max_sim * 160) final_score = max(base_bonus, rss_val) return final_score # --- 3. MASTER ENGINE (Final Presentation Version) --- def master_detector_v12(text, url, image): try: v = VerificationSystem() # ၁။ 🚨 Empty Input Check (စá€Ŧသá€Ŧးမပá€Ģလá€ģှငá€ē) if not text or not text.strip(): return "
âš ī¸ ကá€ģေးဇူးပá€ŧု၍ စစá€ēá€†á€ąá€¸á€œá€­á€¯á€žá€ąá€Ŧ သတငá€ēးစá€Ŧသá€Ŧးကို ထည့á€ēသá€Ŋငá€ēးပá€Ģ။
" # ၂။ 🚨 Short Text Check ("I don't know" Logic - စá€Ŧသá€Ŧးတိုလá€Ŋနá€ēးလá€ģှငá€ē) words = text.split() if len(words) < 10: return f"""
âš ī¸ အခá€ģကá€ēအလကá€ē မလုá€ļလေá€Ŧကá€ēပá€Ģ (Insufficient Information)

သငá€ēထည့á€ēသá€Ŋငá€ēးထá€Ŧးသေá€Ŧ စá€Ŧသá€Ŧးမှá€Ŧ ({len(words)} လုá€ļးသá€Ŧ) ရှိပá€ŧီး á€á€­á€¯á€á€ąá€Ŧငá€ēးလá€Ŋနá€ēးပá€Ģသညá€ē။
AI မှ တိကá€ģစá€Ŋá€Ŧ ဆနá€ēးစစá€ēနိုငá€ēရနá€ēအတá€Ŋကá€ē အနညá€ēးဆုá€ļး စကá€Ŧးလုá€ļး (၁၀) လုá€ļးနှင့á€ēအထကá€ē ပá€Ģဝငá€ēသေá€Ŧ သတငá€ēးအပá€ŧည့á€ēá€Ąá€…á€¯á€ļကို ထည့á€ēသá€Ŋငá€ēးပေးပá€Ģ။
""" # URL ပá€Ģ၊ မပá€Ģ စစá€ēဆေးခá€ŧငá€ēး has_url = bool(url and url.strip() != "") is_myanmar = bool(re.search(r'[\u1000-\u109F]', text)) # --- 📊 3. UI Progress Bar ဖနá€ēတီးပေးသေá€Ŧ Helper Function --- def create_bar(label, value, bar_color, is_mm, nlp_label_local, custom_msg=None): if custom_msg: explainer = custom_msg else: if label == "Source Trust": if not has_url: explainer = "â„šī¸ URL လင့á€ēခá€ē မပá€Ģဝငá€ēသဖá€ŧင့á€ē သတငá€ēးရငá€ēးမá€ŧစá€ēကို အတညá€ēပá€ŧု၍ မရပá€Ģ။" if is_mm else "â„šī¸ No URL provided. Source unverified." bar_color = "#94a3b8" # URL မပá€Ģလá€ģှငá€ē ခဲရေá€Ŧငá€ēပá€ŧမညá€ē else: explainer = ("✅ ယုá€ļကá€ŧညá€ēရသေá€Ŧ ရငá€ēးမá€ŧစá€ēဖá€ŧစá€ēသညá€ē။" if value > 75 else "âš ī¸ ရငá€ēးမá€ŧစá€ē မတညá€ēငá€ŧိမá€ēခá€ŧငá€ēး (á€žá€­á€¯á€ˇ) ဒိုမိနá€ēးသကá€ēတမá€ēး နုနယá€ēခá€ŧငá€ēး။") if is_mm else ("✅ Verified source." if value > 75 else "âš ī¸ Low authority source.") elif label == "Global Consistency": explainer = ("✅ အခá€ŧá€Ŧးမီဒီယá€Ŧမá€ģá€Ŧးတá€Ŋငá€ēလညá€ēး ဖေá€Ŧá€ēပá€ŧထá€Ŧးသညá€ē။" if value > 60 else "â„šī¸ အခá€ŧá€Ŧးသတငá€ēးဌá€Ŧနမá€ģá€Ŧးတá€Ŋငá€ē အတညá€ēပá€ŧုခá€ģကá€ē မတá€Ŋေ့ရသေးပá€Ģ။") if is_mm else ("✅ Corroborated." if value > 60 else "â„šī¸ Not corroborated yet.") elif label == "AI Pattern Analysis": explainer = ("✅ AI မှ သတငá€ēးမှနá€ē အရေးအသá€Ŧးဟု ဆုá€ļးဖá€ŧတá€ēသညá€ē။" if nlp_label_local == "Real" else "âš ī¸ AI မှ သတငá€ēးတု/Clickbait ဟု သတá€ēမှတá€ēသညá€ē။" if nlp_label_local == "Fake" else "â„šī¸ AI အတá€Ŋကá€ē ဆုá€ļးဖá€ŧတá€ēရနá€ē ခကá€ēခဲသေá€Ŧ ရေá€Ŧထá€Ŋေးနေသည့á€ē အရေးအသá€Ŧးဖá€ŧစá€ēသညá€ē။") if is_mm else ("✅ Legitimate pattern." if nlp_label_local == "Real" else "âš ī¸ Misinformation pattern." if nlp_label_local == "Fake" else "â„šī¸ Neutral/Mixed pattern.") elif label == "Image Integrity": explainer = ("✅ ပုá€ļရိပá€ēမှá€Ŧ မူရငá€ēá€¸á€Ąá€á€­á€¯á€„á€ēးဖá€ŧစá€ēပá€ŧီး ပá€ŧငá€ēဆငá€ēမသု မတá€Ŋေ့ရပá€Ģ။" if value > 85 else "âš ī¸ ပုá€ļရိပá€ēကို ပá€ŧုပá€ŧငá€ēထá€Ŧးသေá€Ŧ လက္ခဏá€Ŧရှိသညá€ē။") if is_mm else ("✅ No tampering." if value > 85 else "âš ī¸ Potential tampering.") elif label == "Visual Context": explainer = ("✅ ပုá€ļနှင့á€ēစá€Ŧသá€Ŧး ကိုကá€ēညဎမသုရသိသညá€ē။" if value > 72 else "âš ī¸ ပုá€ļနှင့á€ēစá€Ŧသá€Ŧး တစá€ēခá€ŧá€Ŧးစီဖá€ŧစá€ēနေသညá€ē။") if is_mm else ("✅ Context matches." if value > 72 else "âš ī¸ Context mismatch.") else: explainer = "" return f"""
{label}{value:.1f}%
{explainer}
""" # --- 🔍 4. Core Metrics Calculations --- url_image = v.extract_image_from_url(url) if has_url else None src_score, src_msg = v.get_source_score(url) if has_url else (0, "No URL") rss_score = v.check_rss_similarity(text, url=url) nlp_score = v.get_nlp_prediction(text) # NLP Score Labeling if nlp_score >= 65: nlp_label = "Real"; nlp_val = nlp_score; ai_c = "#10b981" elif nlp_score <= 40: nlp_label = "Fake"; nlp_val = 100 - nlp_score; ai_c = "#dc2626" else: nlp_label = "Neutral"; nlp_val = nlp_score; ai_c = "#94a3b8" # --- đŸ–ŧī¸ 5. Image Processing & Zero-shot Classification --- image_bars_html = "" img_msg_extra = "" sim_msg = "" if image: # ပá€ŧညá€ēတá€Ŋငá€ēး/ပá€ŧညá€ēပ မá€ŧငá€ēကá€Ŋငá€ēးခá€Ŋဲခá€ŧá€Ŧးခá€ŧငá€ēး (Zero-shot CLIP) try: img_obj = Image.open(image) loc_prompts = [ "a photo taken in Myanmar, Burmese streets, pagodas, Asian people, Myanmar culture", "a photo taken in a foreign country, Western people, foreign streets, Europe, America, Africa, Middle East" ] loc_embs = clip_model.encode(loc_prompts) img_emb_local = clip_model.encode(img_obj) loc_scores = util.cos_sim(img_emb_local, loc_embs)[0] if loc_scores[1] > loc_scores[0] + 0.02: img_msg_extra = "
🌍 AI Visual Scan: ဤပုá€ļသညá€ē ပá€ŧညá€ēပနိုငá€ēငá€ļမှ မá€ŧငá€ēကá€Ŋငá€ēးဖá€ŧစá€ēနိုငá€ēခá€ŧေမá€ģá€Ŧးပá€Ģသညá€ē။ (Foreign Image Detected)" elif loc_scores[0] > loc_scores[1] + 0.02: img_msg_extra = "
🇲🇲 AI Visual Scan: ဤပုá€ļသညá€ē ပá€ŧညá€ēတá€Ŋငá€ēးမှ မá€ŧငá€ēကá€Ŋငá€ēးဖá€ŧစá€ēနိုငá€ēခá€ŧေမá€ģá€Ŧးပá€Ģသညá€ē။ (Domestic Image)" except Exception as e: pass # Error တကá€ēလá€ģှငá€ē ကá€ģေá€Ŧá€ēသá€Ŋá€Ŧးမညá€ē img_ela_score, _ = v.perform_ela(image) img_sim_score, sim_msg_original = v.get_image_text_similarity(image, text, url=url, url_image_path=url_image) # Combine image similarity message with location detection sim_msg = sim_msg_original + img_msg_extra # âš–ī¸ Dynamic Weighting for Image Case if has_url: weights = {'source': 0.20, 'nlp': 0.35, 'rss': 0.15, 'ela': 0.10, 'sim': 0.20} else: # URL မပá€Ģလá€ģှငá€ē Source ကို 0 ထá€Ŧးပá€ŧီး AI နှင့á€ē Image ကို အလေးပေးမညá€ē weights = {'source': 0.0, 'nlp': 0.45, 'rss': 0.15, 'ela': 0.15, 'sim': 0.25} final = (src_score * weights['source']) + (nlp_score * weights['nlp']) + \ (rss_score * weights['rss']) + (img_ela_score * weights['ela']) + \ (img_sim_score * weights['sim']) image_bars_html = f""" {create_bar("Image Integrity", img_ela_score, "#f59e0b", is_myanmar, nlp_label)} {create_bar("Visual Context", img_sim_score, "#06b6d4", is_myanmar, nlp_label, custom_msg=sim_msg)} """ else: # âš–ī¸ Dynamic Weighting for Text-Only Case if has_url: weights = {'source': 0.35, 'nlp': 0.50, 'rss': 0.15} else: # ပုá€ļရေá€Ŧ၊ URL ရေá€Ŧ မပá€Ģလá€ģှငá€ē NLP ကို 80% အထိ အလေးပေးမညá€ē weights = {'source': 0.0, 'nlp': 0.80, 'rss': 0.20} final = (src_score * weights['source']) + (nlp_score * weights['nlp']) + (rss_score * weights['rss']) img_msg = "â„šī¸ ပုá€ļမပá€Ģဝငá€ēသည့á€ēအတá€Ŋကá€ē Visual Analysis မပá€ŧုလုပá€ēပá€Ģ။" if is_myanmar else "â„šī¸ No image for visual analysis." image_bars_html = f'
{img_msg}
' # --- 🌟 5.1 Fact-Verification Override (The Veto Power - For Cele News ONLY) 🌟 --- is_corroborated = rss_score >= 70 cele_keywords = ["မငá€ēးသá€Ŧး", "မငá€ēးသမီး", "á€Ąá€†á€­á€¯á€á€ąá€Ŧá€ē", "သရုပá€ēဆေá€Ŧငá€ē", "ဆယá€ēလီ", "လကá€ēထပá€ē", "celebrity"] is_cele_news_context = any(kw in text.lower() for kw in cele_keywords) if is_corroborated and is_cele_news_context: final = max(final, 85.0) if nlp_label == "Fake": nlp_label = "Real (Overridden by Cele Fact-Check)" # --- đŸ—‚ī¸ 6. Final Status & Dynamic Color Logic --- if final >= 75: main_bg, accent_c, status = "#ecfdf5", "#059669", "✅ ယုá€ļကá€ŧညá€ēစိတá€ēခá€ģရသေá€Ŧ သတငá€ēး (RELIABLE VERDICT)" elif final >= 45 and final < 75: main_bg, accent_c, status = "#f8fafc", "#64748b", "âš–ī¸ အတညá€ēပá€ŧုရနá€ēခကá€ēခဲသေá€Ŧ သတငá€ēး (INCONCLUSIVE / NEUTRAL)" else: main_bg, accent_c, status = "#fef2f2", "#dc2626", "🚨 သတငá€ēးတု / အန္တရá€Ŧယá€ēရှိသေá€Ŧသတငá€ēး (FAKE / HIGH RISK)" # --- 📝 7. Analysis & Recommendations --- analysis_header = "🔎 အသေးစိတá€ē ဆနá€ēးစစá€ēခá€ģကá€ē" if is_myanmar else "🔎 Detailed Reasoning" tips_header = "đŸ›Ąī¸ အကá€ŧá€ļပá€ŧုခá€ģကá€ēနှင့á€ē သတိပá€ŧုရနá€ē" if is_myanmar else "đŸ›Ąī¸ Recommendations" reasons = [] tips = [] if final >= 75: # 🌟 Cele News Veto á€Ąá€œá€¯á€•á€ēလုပá€ēခဲ့လá€ģှငá€ē Message ပá€ŧေá€Ŧငá€ēးပá€ŧမညá€ē 🌟 if is_corroborated and is_cele_news_context: reasons.append("🌟 Cele News Verified: á€¤á€Ąá€”á€¯á€•á€Šá€Ŧသတငá€ēးကို အခá€ŧá€Ŧးသေá€Ŧ တရá€Ŧးဝငá€ē မီဒီယá€Ŧမá€ģá€Ŧးတá€Ŋငá€ēပá€Ģ အတိအကá€ģ ဖေá€Ŧá€ēပá€ŧထá€Ŧးသဖá€ŧင့á€ē သတငá€ēးအမှနá€ēဖá€ŧစá€ēကá€ŧေá€Ŧငá€ēး အတညá€ēပá€ŧုပá€Ģသညá€ē။") else: reasons.append("✅ သတငá€ēးရငá€ēးမá€ŧစá€ēနှင့á€ē အခá€ģကá€ēအလကá€ēမá€ģá€Ŧး ခိုငá€ēမá€Ŧမသုရသိသညá€ē။") tips.append("💡 ဤသတငá€ēးသညá€ē ယုá€ļကá€ŧညá€ēစိတá€ēခá€ģရသဖá€ŧင့á€ē ဝေမá€ģသနိုငá€ēပá€Ģသညá€ē။") elif final >= 45 and final < 75: reasons.append("âš–ī¸ အခá€ģကá€ēအလကá€ēမá€ģá€Ŧးမှá€Ŧ အမှနá€ēနှင့á€ē အမှá€Ŧး ရေá€Ŧထá€Ŋá€ąá€¸á€”á€ąá€”á€­á€¯á€„á€ēပá€Ģသညá€ē။ (á€žá€­á€¯á€ˇ) လုá€ļလေá€Ŧကá€ēသေá€Ŧ သကá€ēသေအထေá€Ŧကá€ēအထá€Ŧး မတá€Ŋေ့ရသေးပá€Ģ။") tips.append("💡 ဤသတငá€ēးကို ခá€ģကá€ēခá€ģငá€ēးမယုá€ļကá€ŧညá€ēဘဲ အခá€ŧá€Ŧးတရá€Ŧးဝငá€ē မီဒီယá€Ŧကá€ŧီးမá€ģá€Ŧးတá€Ŋငá€ē ထပá€ēမá€ļစစá€ēဆေးရနá€ē အကá€ŧá€ļပá€ŧá€¯á€Ąá€•á€ēပá€Ģသညá€ē။") else: if nlp_label == "Fake": reasons.append("âš ī¸ AI စနစá€ēမှ ဤစá€Ŧသá€Ŧးသညá€ē သတငá€ēá€¸á€Ąá€á€¯/Clickbait ပုá€ļစá€ļဖá€ŧစá€ēနေကá€ŧေá€Ŧငá€ēး တá€Ŋေ့ရှိရသညá€ē။") if not has_url: reasons.append("â„šī¸ သတငá€ēးရငá€ēးမá€ŧစá€ē (URL) ထည့á€ēသá€Ŋငá€ēးထá€Ŧးခá€ŧငá€ēး မရှိသဖá€ŧင့á€ē မူရငá€ēးရငá€ēးမá€ŧစá€ēကို အတညá€ēပá€ŧုရနá€ē ခကá€ēခဲပá€Ģသညá€ē။") elif src_score < 40: reasons.append(f"❌ သတငá€ēးရငá€ēးမá€ŧစá€ē ({src_msg}) သညá€ē စိတá€ēမခá€ģရပá€Ģ။") tips.append("💡 သတငá€ēးအမှá€Ŧးဖá€ŧစá€ēနိုငá€ēခá€ŧေ အလá€Ŋနá€ēမá€ģá€Ŧးသဖá€ŧင့á€ē အခá€ŧá€Ŧးသူမá€ģá€Ŧးထá€ļ ဆကá€ēလကá€ēမဝေမá€ģှရနá€ē အသိပေးအပá€ēပá€Ģသညá€ē။") reasons_html = "".join([f"
  • {r}
  • " for r in reasons]) tips_html = "".join([f"
  • {t}
  • " for t in tips]) # --- 🌐 8. Final HTML Output return f"""

    {status}

    {final:.1f}%
    📊 Verification Metrics: {create_bar("Source Trust", src_score, "#3b82f6", is_myanmar, nlp_label)} {create_bar("Global Consistency", rss_score, "#8b5cf6", is_myanmar, nlp_label)} {create_bar("AI Pattern Analysis", nlp_val, ai_c, is_myanmar, nlp_label)}
    {image_bars_html}
    = 75 else "#f8fafc" if final >= 45 else "#fef2f2")}; padding: 15px; border-radius: 10px; border-left: 5px solid {accent_c}; margin-top: 15px;"> {analysis_header}
    {tips_header}
    """ except Exception as e: import traceback return f"
    System Error: {str(e)}
    {traceback.format_exc()}
    " # --- 4. MODERN UI DESIGN --- custom_css = """ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap'); @import url('https://mmwebfonts.comquas.com/fonts/?font=pyidaungsu'); .gradio-container { background-color: #f9fafb !important; font-family: 'Inter', 'Pyidaungsu' !important; } .card { background: white !important; border-radius: 20px !important; border: 1px solid #e5e7eb !important; padding: 30px !important; } textarea { font-family: 'Pyidaungsu', sans-serif !important; font-size: 16px !important; } .btn-primary { background: #111827 !important; color: white !important; border-radius: 10px !important; font-weight: 600 !important; } """ with gr.Blocks(css=custom_css) as demo: gr.HTML("

    đŸ›Ąī¸ Fake News Detection (Powered by Myanmar AI)

    ") with gr.Tabs(): with gr.TabItem("🔍 Verifier Dashboard"): with gr.Row(): with gr.Column(scale=5, elem_classes="card"): txt = gr.Textbox(label="News Content", lines=8, placeholder="သတငá€ēးစá€Ŧသá€Ŧးကို ဤနေရá€Ŧတá€Ŋငá€ē ထည့á€ēပá€Ģ...") url = gr.Textbox(label="Source URL (Optional)") img = gr.Image(label="Image Attachment", type="filepath") with gr.Row(): clear = gr.Button("Reset Fields") submit = gr.Button("Analyze News", variant="primary") with gr.Column(scale=5): empty_html = "
    Ready for analysis...
    " output = gr.HTML(value=empty_html) with gr.TabItem("â„šī¸ About System"): with gr.Column(elem_classes="card"): gr.Markdown(r""" # đŸ›Ąī¸ Fake News Detection System Methodology ### 📄 1. Project Overview & System Rationale ဤ Project သညá€ē သတငá€ēးတု (Fake News) မá€ģá€Ŧးကို ရှá€Ŧဖá€Ŋေရá€Ŧတá€Ŋငá€ē စá€Ŧသá€Ŧးတငá€ēမကဘဲ Context အá€Ŧးလုá€ļးကို ခá€ŧုá€ļငုá€ļကá€ŧည့á€ēသည့á€ē **Multi-modal Framework** တစá€ēခုဖá€ŧစá€ēသညá€ē။ ဤစနစá€ēသညá€ē သတငá€ēးတစá€ēခု၏ စစá€ēမှနá€ēမသုကို အခá€ģကá€ē (၄) ခá€ģကá€ēဖá€ŧင့á€ē တိုငá€ēးတá€Ŧပá€Ģသညá€ē။ 1. **Linguistic Style:** အရေးအသá€Ŧးပုá€ļစá€ļမှá€Ŧ ဝá€Ģဒဖá€ŧန့á€ēစá€Ŧသá€Ŧးဖá€ŧစá€ēနေသလá€Ŧး? 2. **Metadata & Source:** သတငá€ēးလá€Ŧရá€Ŧ ရငá€ēးမá€ŧစá€ēက ယုá€ļကá€ŧညá€ēရသလá€Ŧး? 3. **Visual Integrity:** သတငá€ēးတá€Ŋငá€ēပá€Ģသေá€Ŧ ပုá€ļသညá€ē ပá€ŧုပá€ŧငá€ēထá€Ŧးသလá€Ŧး á€žá€­á€¯á€ˇá€™á€Ÿá€¯á€á€ē စá€Ŧသá€Ŧးနှင့á€ē ကိုကá€ēညဎမသုရသိသလá€Ŧး? 4. **Global consistency:** အခá€ŧá€Ŧးသေá€Ŧ မီဒီယá€Ŧကá€ŧီးမá€ģá€Ŧးမှá€Ŧ ဖေá€Ŧá€ēပá€ŧထá€Ŧးခá€ŧငá€ēးရှိသလá€Ŧး? --- ### 🧠 2. Core Algorithms & Methodology #### **A. Transformer-based Classification (XLM-RoBERTa)** * **Algorithm:** *XLM-RoBERTa (Cross-lingual Language Model)* * **Implementation:** ဤ Model သညá€ē မá€ŧနá€ēမá€Ŧစá€Ŧ သတငá€ēးမှနá€ēနှင့á€ē သတငá€ēá€¸á€Ąá€á€¯ Data ထေá€Ŧငá€ēပေá€Ģငá€ēးမá€ģá€Ŧးစá€Ŋá€Ŧကို ကိုယá€ēတိုငá€ē သငá€ēယူ (Fine-tuned) ထá€Ŧးသေá€Ŧ ကိုယá€ēပိုငá€ē AI စနစá€ēဖá€ŧစá€ēသညá€ē။ ဘá€Ŧသá€Ŧပá€ŧနá€ēစရá€Ŧá€™á€œá€­á€¯á€˜á€˛ မá€ŧနá€ēမá€Ŧစá€Ŧကို တိုကá€ēရိုကá€ē နá€Ŧးလညá€ēစစá€ēá€†á€ąá€¸á€”á€­á€¯á€„á€ēသညá€ē။ #### **B. Visual Forensics (ELA & CLIP)** * **Error Level Analysis (ELA):** JPEG ပုá€ļရိပá€ēတစá€ēခုကို ပá€ŧနá€ēသိမá€ēးသည့á€ēအခá€Ģ ပá€ŧုပá€ŧငá€ēထá€Ŧးသေá€Ŧ Pixel မá€ģá€Ŧးသညá€ē Error Level ကá€Ŋဲပá€ŧá€Ŧးသá€Ŋá€Ŧးခá€ŧငá€ēးကို အခá€ŧေခá€ļ၍ ပုá€ļပá€ŧငá€ē/မပá€ŧငá€ēကို စစá€ēဆေးသညá€ē။ * **CLIP (Contrastive Language-Image Pre-training):** NLP နညá€ēးပညá€Ŧကို á€Ąá€žá€¯á€ļးပá€ŧု၍ စá€Ŧသá€Ŧးထဲတá€Ŋငá€ē ပá€Ģဝငá€ēသေá€Ŧ "အကá€ŧေá€Ŧငá€ēးအရá€Ŧ" နှင့á€ē ရုပá€ēပုá€ļထဲတá€Ŋငá€ē မá€ŧငá€ēတá€Ŋေ့ရသေá€Ŧ "အမá€ŧငá€ēအá€Ŧရုá€ļဆိုငá€ēရá€Ŧ သဘေá€Ŧတရá€Ŧး (Visual Concept)" á€á€­á€¯á€ˇá ကိုကá€ēညဎမသုကို Text-Image Embedding Alignment နညá€ēးလမá€ēးဖá€ŧင့á€ē တိုငá€ēးတá€Ŧသညá€ē။ #### **C. Source Verification & RSS Matching** * **Whois Analysis:** Domain ၏ သကá€ēတမá€ēးကို စစá€ēဆေးသညá€ē။ သတငá€ēá€¸á€Ąá€á€¯á€†á€­á€¯á€’á€ēအမá€ģá€Ŧးစုမသá€Ŧ သကá€ēတမá€ēး (၆) လအေá€Ŧကá€ēသá€Ŧ ရှိတတá€ēသညá€ē။ * **RSS Feed Comparison:** BBC, RFA, VOA စသည့á€ē ယုá€ļကá€ŧညá€ēရသေá€Ŧ သတငá€ēးဌá€Ŧနကá€ŧီးမá€ģá€Ŧး၏ လကá€ēရှိသတငá€ēးခေá€Ģငá€ēးစဉá€ēမá€ģá€Ŧးနှင့á€ē သင့á€ēသတငá€ēးကို တိုကá€ēဆိုငá€ēစစá€ēဆေးပá€ŧီး အခá€ŧá€Ŧးမီဒီယá€Ŧတá€Ŋငá€ē ပá€Ģ၊ မပá€Ģ ဆုá€ļးဖá€ŧတá€ēသညá€ē။ --- ### âš™ī¸ 3. Mathematical Scoring Model စနစá€ēမှ ရရှိလá€Ŧသေá€Ŧ Metrics တစá€ēခုခá€ģငá€ēးစဎကို အေá€Ŧကá€ēပá€Ģ **Weighted Average Formula** ဖá€ŧင့á€ē ပေá€Ģငá€ēးစပá€ēကá€Ŧ Confidence Score ထုတá€ēပေးပá€Ģသညá€ē။ $$Score = (W_{nlp} \cdot NLP) + (W_{src} \cdot Source) + (W_{rss} \cdot RSS) + (W_{vis} \cdot Visual)$$ | Metric | Weight (With Image) | Weight (Text Only) | | :--- | :--- | :--- | | **AI Pattern (NLP)** | 30% | 45% | | **Source Authority** | 25% | 45% | | **Visual Forensics** | 10% | - | | **Content Consistency**| 20% | - | | **Global Consensus** | 15% | 10% | --- ### đŸŽ¯ 4. Project Deliverables * ✅ **Hybrid Detection:** စá€Ŧသá€Ŧးရေá€Ŧ ပုá€ļပá€Ģ စစá€ēá€†á€ąá€¸á€”á€­á€¯á€„á€ēခá€ŧငá€ēး။ * ✅ **Evidence-Based Reasoning:** အဖá€ŧေတစá€ēခုတညá€ēး မဟုတá€ēဘဲ အကá€ŧေá€Ŧငá€ēးပá€ŧခá€ģကá€ēပá€Ģ ဖေá€Ŧá€ēပá€ŧခá€ŧငá€ēး။ * ✅ **Burmese Language Support:** မá€ŧနá€ēမá€Ŧစá€Ŧသá€Ŧးမá€ģá€Ŧးကို တိုကá€ēရိုကá€ē နá€Ŧးလညá€ēထေá€Ŧကá€ēပá€ļ့ပေးခá€ŧငá€ēး။ """) submit.click(master_detector_v12, inputs=[txt, url, img], outputs=output) clear.click(lambda: ["", "", None, empty_html], outputs=[txt, url, img, output]) if __name__ == "__main__": demo.launch(share=True)