NLong commited on
Commit
95ca342
·
verified ·
1 Parent(s): c20ba74

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +245 -42
app.py CHANGED
@@ -7,6 +7,10 @@ from transformers import AutoTokenizer, AutoModelForSequenceClassification
7
  import re
8
  import os
9
  import numpy as np
 
 
 
 
10
 
11
  GOOGLE_API_KEY = "AIzaSyASwqVh3ELFVKH-W3WuHtmjg3XgtwjJQKg"
12
  SEARCH_ENGINE_ID = "f34f8a4816771488b"
@@ -15,6 +19,11 @@ MODEL_PATH = "./vietnamese_fake_news_model"
15
 
16
  genai.configure(api_key=GEMINI_API_KEY)
17
 
 
 
 
 
 
18
  print("Loading the DistilBERT model we trained...")
19
  try:
20
  if os.path.exists(MODEL_PATH):
@@ -44,6 +53,166 @@ except Exception as e:
44
  tokenizer = None
45
  model = None
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  CREDIBLE_SOURCES = {
48
  'vnexpress.net': 0.95,
49
  'tuoitre.vn': 0.95,
@@ -219,7 +388,7 @@ def google_search(news_text):
219
  result = service.cse().list(
220
  q=search_query,
221
  cx=SEARCH_ENGINE_ID,
222
- num=10
223
  ).execute()
224
 
225
  print(f"API Response keys: {list(result.keys())}")
@@ -351,6 +520,13 @@ def analyze_source_support(news_text, search_results):
351
  def analyze_with_gemini(news_text, search_results, distilbert_prediction, distilbert_confidence):
352
  """Use Gemini AI to analyze the news and compare with our model results"""
353
  try:
 
 
 
 
 
 
 
354
  # Try to use the latest Gemini model available
355
  try:
356
  model = genai.GenerativeModel('gemini-2.0-flash-exp')
@@ -363,11 +539,11 @@ def analyze_with_gemini(news_text, search_results, distilbert_prediction, distil
363
  except:
364
  model = genai.GenerativeModel('gemini-1.5-flash')
365
 
366
- # Format the search results for Gemini
367
  search_summary = ""
368
  if search_results:
369
  search_summary = "Kết quả tìm kiếm Google:\n"
370
- for i, result in enumerate(search_results[:5], 1):
371
  search_summary += f"{i}. {result['title']}\n {result['snippet']}\n Nguồn: {result['link']}\n\n"
372
  else:
373
  search_summary = "Không tìm thấy kết quả tìm kiếm Google cho tin tức này. Điều này có thể do API bị giới hạn hoặc tin tức quá mới/chưa được đăng tải."
@@ -381,35 +557,37 @@ Bạn là một chuyên gia phân tích tin tức chuyên nghiệp. Hãy phân t
381
 
382
  {search_summary}
383
 
 
 
384
  Hãy thực hiện phân tích toàn diện theo các tiêu chí sau:
385
 
386
- 1. **Phân tích nội dung**: Kiểm tra tính logic, mâu thuẫn, ngôn ngữ cảm xúc thái quá
387
- 2. **Phân tích nguồn tin**: Đánh giá uy tín và độ tin cậy của nguồn
388
- 3. **Phân tích ngữ cảnh**: So sánh với thông tin có sẵn và kiến thức thực tế
389
- 4. **Phân tích ngôn ngữ**: Tìm dấu hiệu của tin giả như từ ngữ gây sốc, cảm xúc
390
- 5. **Phân tích thời gian**: Kiểm tra tính hợp lý về mặt thời gian
391
 
392
  Trả lời theo định dạng sau (chỉ bằng tiếng Việt, viết chi tiết và chuyên nghiệp):
393
 
394
- **1. KẾT LUẬN:** [THẬT/GIẢ/KHÔNG XÁC ĐỊNH]
395
 
396
- **2. ĐỘ TIN CẬY:** [X%/Y%] (Trong đó X% là độ tin cậy tin THẬT, Y% là độ tin cậy tin GIẢ, X+Y=100%)
397
 
398
- **3. PHÂN TÍCH CHI TIẾT:**
399
- - **Nội dung:** [Phân tích chi tiết về nội dung tin tức]
400
- - **Nguồn tin:** [Đánh giá về nguồn và độ tin cậy]
401
- - **Ngữ cảnh:** [So sánh với thông tin có sẵn]
402
- - **Ngôn ngữ:** [Phân tích cách sử dụng từ ngữ]
403
- - **Thời gian:** [Kiểm tra tính hợp lý về mặt thời gian]
404
 
405
- **4. CÁC DẤU HIỆU CẢNH BÁO:** [Liệt kê các dấu hiệu đáng ngờ nếu có]
406
 
407
- **5. KHUYẾN NGHỊ CHO NGƯỜI ĐỌC:**
408
  - [Hướng dẫn cụ thể để kiểm chứng thông tin]
409
  - [Các nguồn tin đáng tin cậy để tham khảo]
410
  - [Cách phân biệt tin thật và tin giả]
411
 
412
- QUAN TRỌNG: Trong phần "ĐỘ TIN CẬY", hãy cung cấp tỷ lệ phần trăm chính xác dựa trên phân tích của bạn. Ví dụ: "95%/5%" nghĩa là 95% tin tức này là THẬT, 5% là GIẢ.
413
 
414
  Viết chi tiết, chuyên nghiệp và hữu ích cho người đọc.
415
  """
@@ -420,12 +598,12 @@ Viết chi tiết, chuyên nghiệp và hữu ích cho người đọc.
420
  if search_results:
421
  print(f"DEBUG - First search result title: {search_results[0].get('title', 'No title')}")
422
 
423
- # Use settings optimized for detailed analysis
424
  generation_config = genai.types.GenerationConfig(
425
- temperature=0.3, # Slightly higher for more creative analysis
426
- top_p=0.9, # Allow more diverse vocabulary
427
- top_k=40, # More vocabulary choices for detailed writing
428
- max_output_tokens=2000 # Allow much longer responses
429
  )
430
  response = model.generate_content(prompt, generation_config=generation_config)
431
  print("Gemini API response received successfully")
@@ -473,25 +651,25 @@ Viết chi tiết, chuyên nghiệp và hữu ích cho người đọc.
473
  if len(news_text) < 100:
474
  warning_signs.append("Tin tức quá ngắn, thiếu thông tin chi tiết")
475
 
476
- fallback_analysis = f"""**1. KẾT LUẬN:** {conclusion}
477
 
478
- **2. ĐỘ TIN CẬY:** {'5%/95%' if conclusion == 'GIẢ' else '95%/5%' if conclusion == 'THẬT' else '50%/50%'}
479
 
480
- **3. PHÂN TÍCH CHI TIẾT:**
481
- - **Nội dung:** {'Tin tức có vẻ hợp lý' if distilbert_prediction == 'REAL' else 'Tin tức có nhiều dấu hiệu đáng ngờ' if distilbert_prediction == 'FAKE' else 'Nội dung không rõ ràng'}
482
- - **Nguồn tin:** Google Search không khả dụng (hết quota) - không thể kiểm tra nguồn
483
- - **Ngữ cảnh:** Phân tích từ khóa: {confidence_boost}
484
- - **Ngôn ngữ:** {'Ngôn ngữ trung tính' if fake_score == real_score else 'Có dấu hiệu cảm xúc thái quá' if fake_score > real_score else 'Ngôn ngữ khách quan'}
485
- - **Thời gian:** Không thể xác minh do thiếu thông tin bổ sung
486
 
487
- **4. CÁC DẤU HIỆU CẢNH BÁO:**
488
  {chr(10).join([f"- {sign}" for sign in warning_signs]) if warning_signs else "- Không phát hiện dấu hiệu cảnh báo rõ ràng"}
489
 
490
- **5. KHUYẾN NGHỊ CHO NGƯỜI ĐỌC:**
491
- - **Kiểm tra nguồn:** Tìm kiếm thông tin tương tự trên các trang báo uy tín như VnExpress, Tuổi Trẻ, Thanh Niên
492
- - **Xác minh thời gian:** Kiểm tra xem tin tức có được đăng tải đồng thời trên nhiều nguồn không
493
- - **Đánh giá ngôn ngữ:** Tránh chia sẻ tin tức có ngôn ngữ cảm xúc thái quá hoặc tạo cảm giác cấp bách
494
- - **Lưu ý:** Do hệ thống API tạm thời không khả dụng, kết quả phân tích có thể không hoàn toàn chính xác"""
495
  return fallback_analysis
496
 
497
  # For other errors, see what models are available
@@ -513,8 +691,8 @@ def extract_gemini_percentage(gemini_analysis):
513
  # Look for the confidence percentage pattern
514
  import re
515
 
516
- # Pattern to match "X%/Y%" format
517
- percentage_pattern = r'độ tin cậy.*?(\d+)%/(\d+)%'
518
  match = re.search(percentage_pattern, gemini_lower)
519
 
520
  if match:
@@ -647,10 +825,10 @@ def calculate_combined_confidence(distilbert_prediction, distilbert_confidence,
647
  else:
648
  # Fallback to conclusion analysis
649
  conclusion_score = 0.5 # Default neutral
650
- if "**kết luận:** giả" in gemini_lower or "kết luận:** fake" in gemini_lower or "kết luận:** giả" in gemini_lower:
651
  conclusion_score = 0.1 # Very low for FAKE
652
  print("Gemini Conclusion: FAKE")
653
- elif "**kết luận:** thật" in gemini_lower or "kết luận:** real" in gemini_lower or "kết luận:** thật" in gemini_lower:
654
  conclusion_score = 0.9 # Very high for REAL
655
  print("Gemini Conclusion: REAL")
656
  elif "giả" in gemini_lower and "kết luận" in gemini_lower:
@@ -814,6 +992,26 @@ def analyze_news(news_text):
814
  # Step 6: Format the final results
815
  real_confidence = combined_confidence
816
  fake_confidence = 1 - combined_confidence
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
817
 
818
  # Build the detailed report with better formatting
819
  # Use combined_confidence to determine the final classification (not just DistilBERT)
@@ -953,6 +1151,11 @@ def create_interface():
953
  <div style="background: #f8f9fa; padding: 15px; border-radius: 10px; border-left: 4px solid #17a2b8; margin: 20px 0;">
954
  <p style="margin: 0; color: #495057;"><strong>💡 Lưu ý:</strong> Kết quả có thể thay đổi nhẹ giữa các lần phân tích do tính chất AI của Gemini, nhưng độ chính xác tổng thể vẫn được đảm bảo.</p>
955
  </div>
 
 
 
 
 
956
  </div>
957
  """)
958
 
 
7
  import re
8
  import os
9
  import numpy as np
10
+ import json
11
+ import sqlite3
12
+ from datetime import datetime
13
+ import hashlib
14
 
15
  GOOGLE_API_KEY = "AIzaSyASwqVh3ELFVKH-W3WuHtmjg3XgtwjJQKg"
16
  SEARCH_ENGINE_ID = "f34f8a4816771488b"
 
19
 
20
  genai.configure(api_key=GEMINI_API_KEY)
21
 
22
+ # Knowledge Base Configuration
23
+ KNOWLEDGE_BASE_DB = "knowledge_base.db"
24
+ CONFIDENCE_THRESHOLD = 0.95 # 95% threshold for auto-updating knowledge base
25
+ ENABLE_KNOWLEDGE_BASE_SEARCH = False # Set to True to enable knowledge base search (slower)
26
+
27
  print("Loading the DistilBERT model we trained...")
28
  try:
29
  if os.path.exists(MODEL_PATH):
 
53
  tokenizer = None
54
  model = None
55
 
56
+ # --- KNOWLEDGE BASE MANAGEMENT ---
57
+ def init_knowledge_base():
58
+ """Initialize the SQLite knowledge base"""
59
+ conn = sqlite3.connect(KNOWLEDGE_BASE_DB)
60
+ cursor = conn.cursor()
61
+
62
+ cursor.execute('''
63
+ CREATE TABLE IF NOT EXISTS knowledge_entries (
64
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
65
+ content_hash TEXT UNIQUE,
66
+ news_text TEXT,
67
+ prediction TEXT,
68
+ confidence REAL,
69
+ search_results TEXT,
70
+ gemini_analysis TEXT,
71
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
72
+ last_accessed TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
73
+ access_count INTEGER DEFAULT 1
74
+ )
75
+ ''')
76
+
77
+ conn.commit()
78
+ conn.close()
79
+ print("Knowledge base initialized successfully!")
80
+
81
+ def add_to_knowledge_base(news_text, prediction, confidence, search_results, gemini_analysis):
82
+ """Add high-confidence result to knowledge base"""
83
+ try:
84
+ # Create content hash for deduplication
85
+ content_hash = hashlib.md5(news_text.encode('utf-8')).hexdigest()
86
+
87
+ conn = sqlite3.connect(KNOWLEDGE_BASE_DB)
88
+ cursor = conn.cursor()
89
+
90
+ # Check if entry already exists
91
+ cursor.execute('SELECT id FROM knowledge_entries WHERE content_hash = ?', (content_hash,))
92
+ if cursor.fetchone():
93
+ print(f"Entry already exists in knowledge base (hash: {content_hash[:8]}...)")
94
+ conn.close()
95
+ return False
96
+
97
+ # Insert new entry
98
+ cursor.execute('''
99
+ INSERT INTO knowledge_entries
100
+ (content_hash, news_text, prediction, confidence, search_results, gemini_analysis)
101
+ VALUES (?, ?, ?, ?, ?, ?)
102
+ ''', (
103
+ content_hash,
104
+ news_text,
105
+ prediction,
106
+ confidence,
107
+ json.dumps(search_results, ensure_ascii=False),
108
+ gemini_analysis
109
+ ))
110
+
111
+ conn.commit()
112
+ conn.close()
113
+
114
+ print(f"✅ Added high-confidence result to knowledge base (confidence: {confidence:.1%})")
115
+ print(f" Hash: {content_hash[:8]}...")
116
+ print(f" Prediction: {prediction}")
117
+ return True
118
+
119
+ except Exception as e:
120
+ print(f"Error adding to knowledge base: {e}")
121
+ return False
122
+
123
+ def search_knowledge_base(query_text, limit=5):
124
+ """Search the knowledge base for similar entries"""
125
+ try:
126
+ conn = sqlite3.connect(KNOWLEDGE_BASE_DB)
127
+ cursor = conn.cursor()
128
+
129
+ # Simple text similarity search (you can enhance this with embeddings later)
130
+ cursor.execute('''
131
+ SELECT news_text, prediction, confidence, search_results, gemini_analysis,
132
+ created_at, access_count
133
+ FROM knowledge_entries
134
+ WHERE news_text LIKE ? OR gemini_analysis LIKE ?
135
+ ORDER BY confidence DESC, access_count DESC
136
+ LIMIT ?
137
+ ''', (f'%{query_text[:50]}%', f'%{query_text[:50]}%', limit))
138
+
139
+ results = cursor.fetchall()
140
+
141
+ # Update access count and last_accessed
142
+ for result in results:
143
+ cursor.execute('''
144
+ UPDATE knowledge_entries
145
+ SET access_count = access_count + 1, last_accessed = CURRENT_TIMESTAMP
146
+ WHERE news_text = ?
147
+ ''', (result[0],))
148
+
149
+ conn.commit()
150
+ conn.close()
151
+
152
+ if results:
153
+ print(f"📚 Found {len(results)} similar entries in knowledge base")
154
+ return results
155
+ else:
156
+ return []
157
+
158
+ except Exception as e:
159
+ print(f"Error searching knowledge base: {e}")
160
+ return []
161
+
162
+ def format_knowledge_for_rag(knowledge_results):
163
+ """Format knowledge base results for RAG augmentation"""
164
+ if not knowledge_results:
165
+ return ""
166
+
167
+ knowledge_summary = "\n=== KIẾN THỨC TƯƠNG TỰ TỪ CƠ SỞ DỮ LIỆU ===\n"
168
+
169
+ for i, (news_text, prediction, confidence, search_results, gemini_analysis, created_at, access_count) in enumerate(knowledge_results, 1):
170
+ knowledge_summary += f"\n{i}. Tin tức tương tự (Độ tin cậy: {confidence:.1%}, Lần truy cập: {access_count}):\n"
171
+ knowledge_summary += f" Nội dung: {news_text[:200]}...\n"
172
+ knowledge_summary += f" Kết luận: {prediction}\n"
173
+ knowledge_summary += f" Thời gian: {created_at}\n"
174
+
175
+ knowledge_summary += "\n==========================================\n"
176
+ return knowledge_summary
177
+
178
+ def get_knowledge_base_stats():
179
+ """Get statistics about the knowledge base"""
180
+ try:
181
+ conn = sqlite3.connect(KNOWLEDGE_BASE_DB)
182
+ cursor = conn.cursor()
183
+
184
+ # Get total entries
185
+ cursor.execute('SELECT COUNT(*) FROM knowledge_entries')
186
+ total_entries = cursor.fetchone()[0]
187
+
188
+ # Get entries by prediction
189
+ cursor.execute('SELECT prediction, COUNT(*) FROM knowledge_entries GROUP BY prediction')
190
+ prediction_counts = dict(cursor.fetchall())
191
+
192
+ # Get average confidence
193
+ cursor.execute('SELECT AVG(confidence) FROM knowledge_entries')
194
+ avg_confidence = cursor.fetchone()[0] or 0
195
+
196
+ # Get most accessed entries
197
+ cursor.execute('SELECT news_text, access_count FROM knowledge_entries ORDER BY access_count DESC LIMIT 3')
198
+ top_accessed = cursor.fetchall()
199
+
200
+ conn.close()
201
+
202
+ return {
203
+ 'total_entries': total_entries,
204
+ 'prediction_counts': prediction_counts,
205
+ 'avg_confidence': avg_confidence,
206
+ 'top_accessed': top_accessed
207
+ }
208
+
209
+ except Exception as e:
210
+ print(f"Error getting knowledge base stats: {e}")
211
+ return None
212
+
213
+ # Initialize knowledge base on startup
214
+ init_knowledge_base()
215
+
216
  CREDIBLE_SOURCES = {
217
  'vnexpress.net': 0.95,
218
  'tuoitre.vn': 0.95,
 
388
  result = service.cse().list(
389
  q=search_query,
390
  cx=SEARCH_ENGINE_ID,
391
+ num=5 # Reduced from 10 to 5 for faster processing
392
  ).execute()
393
 
394
  print(f"API Response keys: {list(result.keys())}")
 
520
  def analyze_with_gemini(news_text, search_results, distilbert_prediction, distilbert_confidence):
521
  """Use Gemini AI to analyze the news and compare with our model results"""
522
  try:
523
+ # Knowledge base search (optional for faster performance)
524
+ if ENABLE_KNOWLEDGE_BASE_SEARCH:
525
+ print("🔍 Searching knowledge base for similar entries...")
526
+ knowledge_results = search_knowledge_base(news_text, limit=3)
527
+ knowledge_context = format_knowledge_for_rag(knowledge_results)
528
+ else:
529
+ knowledge_context = ""
530
  # Try to use the latest Gemini model available
531
  try:
532
  model = genai.GenerativeModel('gemini-2.0-flash-exp')
 
539
  except:
540
  model = genai.GenerativeModel('gemini-1.5-flash')
541
 
542
+ # Format the search results for Gemini (limit to top 3 for speed)
543
  search_summary = ""
544
  if search_results:
545
  search_summary = "Kết quả tìm kiếm Google:\n"
546
+ for i, result in enumerate(search_results[:3], 1): # Reduced from 5 to 3
547
  search_summary += f"{i}. {result['title']}\n {result['snippet']}\n Nguồn: {result['link']}\n\n"
548
  else:
549
  search_summary = "Không tìm thấy kết quả tìm kiếm Google cho tin tức này. Điều này có thể do API bị giới hạn hoặc tin tức quá mới/chưa được đăng tải."
 
557
 
558
  {search_summary}
559
 
560
+ {knowledge_context}
561
+
562
  Hãy thực hiện phân tích toàn diện theo các tiêu chí sau:
563
 
564
+ 1. Phân tích nội dung: Kiểm tra tính logic, mâu thuẫn, ngôn ngữ cảm xúc thái quá
565
+ 2. Phân tích nguồn tin: Đánh giá uy tín và độ tin cậy của nguồn
566
+ 3. Phân tích ngữ cảnh: So sánh với thông tin có sẵn và kiến thức thực tế
567
+ 4. Phân tích ngôn ngữ: Tìm dấu hiệu của tin giả như từ ngữ gây sốc, cảm xúc
568
+ 5. Phân tích thời gian: Kiểm tra tính hợp lý về mặt thời gian
569
 
570
  Trả lời theo định dạng sau (chỉ bằng tiếng Việt, viết chi tiết và chuyên nghiệp):
571
 
572
+ 1. KẾT LUẬN: [THẬT/GIẢ/KHÔNG XÁC ĐỊNH]
573
 
574
+ 2. ĐỘ TIN CẬY: [THẬT: X% / GIẢ: Y%] (Trong đó X% là độ tin cậy tin THẬT, Y% là độ tin cậy tin GIẢ, X+Y=100%)
575
 
576
+ 3. PHÂN TÍCH CHI TIẾT:
577
+ - Nội dung: [Phân tích chi tiết về nội dung tin tức]
578
+ - Nguồn tin: [Đánh giá về nguồn và độ tin cậy]
579
+ - Ngữ cảnh: [So sánh với thông tin có sẵn]
580
+ - Ngôn ngữ: [Phân tích cách sử dụng từ ngữ]
581
+ - Thời gian: [Kiểm tra tính hợp lý về mặt thời gian]
582
 
583
+ 4. CÁC DẤU HIỆU CẢNH BÁO: [Liệt kê các dấu hiệu đáng ngờ nếu có]
584
 
585
+ 5. KHUYẾN NGHỊ CHO NGƯỜI ĐỌC:
586
  - [Hướng dẫn cụ thể để kiểm chứng thông tin]
587
  - [Các nguồn tin đáng tin cậy để tham khảo]
588
  - [Cách phân biệt tin thật và tin giả]
589
 
590
+ QUAN TRỌNG: Trong phần "ĐỘ TIN CẬY", hãy cung cấp tỷ lệ phần trăm chính xác dựa trên phân tích của bạn. Ví dụ: "THẬT: 95% / GIẢ: 5%" nghĩa là 95% tin tức này là THẬT, 5% là GIẢ.
591
 
592
  Viết chi tiết, chuyên nghiệp và hữu ích cho người đọc.
593
  """
 
598
  if search_results:
599
  print(f"DEBUG - First search result title: {search_results[0].get('title', 'No title')}")
600
 
601
+ # Use settings optimized for faster processing
602
  generation_config = genai.types.GenerationConfig(
603
+ temperature=0.3, # Lower for more consistent results
604
+ top_p=0.8, # Reduced for faster processing
605
+ top_k=20, # Reduced for faster processing
606
+ max_output_tokens=1000 # Reduced for faster responses
607
  )
608
  response = model.generate_content(prompt, generation_config=generation_config)
609
  print("Gemini API response received successfully")
 
651
  if len(news_text) < 100:
652
  warning_signs.append("Tin tức quá ngắn, thiếu thông tin chi tiết")
653
 
654
+ fallback_analysis = f"""1. KẾT LUẬN: {conclusion}
655
 
656
+ 2. ĐỘ TIN CẬY: {'THẬT: 5% / GIẢ: 95%' if conclusion == 'GIẢ' else 'THẬT: 95% / GIẢ: 5%' if conclusion == 'THẬT' else 'THẬT: 50% / GIẢ: 50%'}
657
 
658
+ 3. PHÂN TÍCH CHI TIẾT:
659
+ - Nội dung: {'Tin tức có vẻ hợp lý' if distilbert_prediction == 'REAL' else 'Tin tức có nhiều dấu hiệu đáng ngờ' if distilbert_prediction == 'FAKE' else 'Nội dung không rõ ràng'}
660
+ - Nguồn tin: Google Search kh��ng khả dụng (hết quota) - không thể kiểm tra nguồn
661
+ - Ngữ cảnh: Phân tích từ khóa: {confidence_boost}
662
+ - Ngôn ngữ: {'Ngôn ngữ trung tính' if fake_score == real_score else 'Có dấu hiệu cảm xúc thái quá' if fake_score > real_score else 'Ngôn ngữ khách quan'}
663
+ - Thời gian: Không thể xác minh do thiếu thông tin bổ sung
664
 
665
+ 4. CÁC DẤU HIỆU CẢNH BÁO:
666
  {chr(10).join([f"- {sign}" for sign in warning_signs]) if warning_signs else "- Không phát hiện dấu hiệu cảnh báo rõ ràng"}
667
 
668
+ 5. KHUYẾN NGHỊ CHO NGƯỜI ĐỌC:
669
+ - Kiểm tra nguồn: Tìm kiếm thông tin tương tự trên các trang báo uy tín như VnExpress, Tuổi Trẻ, Thanh Niên
670
+ - Xác minh thời gian: Kiểm tra xem tin tức có được đăng tải đồng thời trên nhiều nguồn không
671
+ - Đánh giá ngôn ngữ: Tránh chia sẻ tin tức có ngôn ngữ cảm xúc thái quá hoặc tạo cảm giác cấp bách
672
+ - Lưu ý: Do hệ thống API tạm thời không khả dụng, kết quả phân tích có thể không hoàn toàn chính xác"""
673
  return fallback_analysis
674
 
675
  # For other errors, see what models are available
 
691
  # Look for the confidence percentage pattern
692
  import re
693
 
694
+ # Pattern to match "THẬT: X% / GIẢ: Y%" format
695
+ percentage_pattern = r'độ tin cậy.*?thật.*?(\d+)%.*?giả.*?(\d+)%'
696
  match = re.search(percentage_pattern, gemini_lower)
697
 
698
  if match:
 
825
  else:
826
  # Fallback to conclusion analysis
827
  conclusion_score = 0.5 # Default neutral
828
+ if "kết luận: giả" in gemini_lower or "kết luận: fake" in gemini_lower:
829
  conclusion_score = 0.1 # Very low for FAKE
830
  print("Gemini Conclusion: FAKE")
831
+ elif "kết luận: thật" in gemini_lower or "kết luận: real" in gemini_lower:
832
  conclusion_score = 0.9 # Very high for REAL
833
  print("Gemini Conclusion: REAL")
834
  elif "giả" in gemini_lower and "kết luận" in gemini_lower:
 
992
  # Step 6: Format the final results
993
  real_confidence = combined_confidence
994
  fake_confidence = 1 - combined_confidence
995
+
996
+ # Step 7: Check if result should be added to knowledge base
997
+ max_confidence = max(real_confidence, fake_confidence)
998
+ if max_confidence > CONFIDENCE_THRESHOLD:
999
+ print(f"🚀 High confidence result detected ({max_confidence:.1%}) - adding to knowledge base...")
1000
+ final_prediction = "REAL" if real_confidence > fake_confidence else "FAKE"
1001
+
1002
+ # Add to knowledge base
1003
+ success = add_to_knowledge_base(
1004
+ news_text=news_text,
1005
+ prediction=final_prediction,
1006
+ confidence=max_confidence,
1007
+ search_results=search_results,
1008
+ gemini_analysis=gemini_analysis
1009
+ )
1010
+
1011
+ if success:
1012
+ print("✅ Successfully added to knowledge base for future RAG retrieval!")
1013
+ else:
1014
+ print("⚠️ Failed to add to knowledge base (duplicate or error)")
1015
 
1016
  # Build the detailed report with better formatting
1017
  # Use combined_confidence to determine the final classification (not just DistilBERT)
 
1151
  <div style="background: #f8f9fa; padding: 15px; border-radius: 10px; border-left: 4px solid #17a2b8; margin: 20px 0;">
1152
  <p style="margin: 0; color: #495057;"><strong>💡 Lưu ý:</strong> Kết quả có thể thay đổi nhẹ giữa các lần phân tích do tính chất AI của Gemini, nhưng độ chính xác tổng thể vẫn được đảm bảo.</p>
1153
  </div>
1154
+
1155
+ <div style="background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%); padding: 15px; border-radius: 10px; margin: 20px 0;">
1156
+ <h4 style="margin: 0 0 10px 0; color: #333;">🧠 Hệ thống RAG với Cơ sở Tri thức Tự động</h4>
1157
+ <p style="margin: 0; color: #555; font-size: 14px;">Khi độ tin cậy > 95%, hệ thống sẽ tự động lưu kết quả vào cơ sở tri thức để sử dụng cho các phân tích tương lai.</p>
1158
+ </div>
1159
  </div>
1160
  """)
1161