.github/workflows/deploy.yml ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: CI/CD for Python App
2
+
3
+ on:
4
+ push:
5
+ branches: [main] # hoặc 'master'
6
+
7
+ jobs:
8
+ deploy:
9
+ runs-on: ubuntu-latest
10
+
11
+ steps:
12
+ - name: 📥 Lấy mã nguồn
13
+ uses: actions/checkout@v3
14
+
15
+ - name: 🐍 Cài Python
16
+ uses: actions/setup-python@v4
17
+ with:
18
+ python-version: "3.11"
19
+
20
+ - name: 📦 Cài dependencies
21
+ run: |
22
+ python -m pip install --upgrade pip
23
+ pip install -r requirements.txt
24
+
25
+ - name: ✅ Kiểm tra (test)
26
+ run: |
27
+ pytest || echo "⚠️ Bỏ qua test nếu chưa có"
28
+
29
+ - name: 🚀 Deploy lên Huggingface
30
+ run: curl -X POST ${{ secrets.DEPLOY_HOOK_URL }}
app/app_ui.py CHANGED
@@ -1,7 +1,45 @@
1
  import gradio as gr
 
 
 
 
 
 
2
  from app.gen_ai import generate_response
3
  from app.mlops_logger import log_prompt
4
- from app.safety_check import check_nsfw_image, check_violence_image, is_prompt_safe, check_url
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
  # === Kiểm duyệt Prompt ===
7
  def handle_prompt(prompt):
@@ -9,7 +47,7 @@ def handle_prompt(prompt):
9
  if not safe:
10
  log_prompt(prompt, info, False, "")
11
  return f"🚨 Prompt không an toàn! Phát hiện: {', '.join(info)}", ""
12
-
13
  response = generate_response(prompt)
14
  log_prompt(prompt, "OK", True, response)
15
  return "✅ Prompt an toàn", response
@@ -22,7 +60,7 @@ with gr.Blocks(title="SAIFGuard - HỆ THỐNG KIỂM DUYỆT THÔNG MINH", css=
22
  }
23
  """) as demo:
24
  gr.Markdown("## 🛡️ SAIFGuard: HỆ THỐNG KIỂM DUYỆT THÔNG MINH")
25
-
26
  with gr.Tab("📝 Kiểm duyệt Prompt"):
27
  with gr.Row():
28
  with gr.Column(scale=1):
@@ -32,7 +70,7 @@ with gr.Blocks(title="SAIFGuard - HỆ THỐNG KIỂM DUYỆT THÔNG MINH", css=
32
  prompt_output = gr.Textbox(label="Kết quả GenAI")
33
  prompt_button = gr.Button("Kiểm tra Prompt", elem_classes="yellow-btn")
34
  prompt_button.click(handle_prompt, inputs=prompt_input, outputs=[prompt_status, prompt_output])
35
-
36
  with gr.Tab("🖼️ Kiểm duyệt Hình ảnh"):
37
  gr.Markdown("### 📷 Tải ảnh và kiểm tra từng tiêu chí")
38
 
@@ -59,4 +97,12 @@ with gr.Blocks(title="SAIFGuard - HỆ THỐNG KIỂM DUYỆT THÔNG MINH", css=
59
  url_button = gr.Button("Kiểm tra URL", elem_classes="yellow-btn")
60
  url_button.click(fn=check_url, inputs=url_input, outputs=url_output)
61
 
62
-
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
+ import numpy as np
3
+ import whisper
4
+ import torch
5
+ import scipy.io.wavfile
6
+ import cv2
7
+ from app.safety_check import is_prompt_safe, check_nsfw_image, check_violence_image, check_url
8
  from app.gen_ai import generate_response
9
  from app.mlops_logger import log_prompt
10
+
11
+ # Load Whisper model
12
+ asr_model = whisper.load_model("tiny", device="cuda" if torch.cuda.is_available() else "cpu")
13
+
14
+ # Hàm chuyển giọng nói thành văn bản
15
+ def transcribe_and_check(audio):
16
+ if audio is None:
17
+ return "❌ Không có dữ liệu âm thanh", "", ""
18
+
19
+ sr, data = audio
20
+
21
+ # Chuyển dữ liệu âm thanh sang dạng float32
22
+ audio_fp32 = whisper.pad_or_trim(data.astype(np.float32) / 32768.0)
23
+
24
+ # Tạo spectrogram
25
+ mel = whisper.log_mel_spectrogram(audio_fp32).to(asr_model.device)
26
+
27
+ # Giải mã
28
+ result = asr_model.decode(mel)
29
+ text = result.text.strip()
30
+
31
+ if not text:
32
+ return "⚠️ Không nhận diện được giọng nói.", "", ""
33
+
34
+ # Kiểm tra prompt an toàn
35
+ is_safe, categories = is_prompt_safe(text)
36
+
37
+ if is_safe:
38
+ return "✅ Nội dung an toàn", text, ""
39
+ else:
40
+ cat_text = ", ".join(categories)
41
+ return f"🚨 Phát hiện nội dung không an toàn", text, f"❗ Các danh mục phát hiện: {cat_text}"
42
+
43
 
44
  # === Kiểm duyệt Prompt ===
45
  def handle_prompt(prompt):
 
47
  if not safe:
48
  log_prompt(prompt, info, False, "")
49
  return f"🚨 Prompt không an toàn! Phát hiện: {', '.join(info)}", ""
50
+
51
  response = generate_response(prompt)
52
  log_prompt(prompt, "OK", True, response)
53
  return "✅ Prompt an toàn", response
 
60
  }
61
  """) as demo:
62
  gr.Markdown("## 🛡️ SAIFGuard: HỆ THỐNG KIỂM DUYỆT THÔNG MINH")
63
+
64
  with gr.Tab("📝 Kiểm duyệt Prompt"):
65
  with gr.Row():
66
  with gr.Column(scale=1):
 
70
  prompt_output = gr.Textbox(label="Kết quả GenAI")
71
  prompt_button = gr.Button("Kiểm tra Prompt", elem_classes="yellow-btn")
72
  prompt_button.click(handle_prompt, inputs=prompt_input, outputs=[prompt_status, prompt_output])
73
+
74
  with gr.Tab("🖼️ Kiểm duyệt Hình ảnh"):
75
  gr.Markdown("### 📷 Tải ảnh và kiểm tra từng tiêu chí")
76
 
 
97
  url_button = gr.Button("Kiểm tra URL", elem_classes="yellow-btn")
98
  url_button.click(fn=check_url, inputs=url_input, outputs=url_output)
99
 
100
+ with gr.Tab("🎙️Giọng Nói"):
101
+ audio_input = gr.Audio(type="numpy", label="Thu âm giọng nói")
102
+ btn2 = gr.Button("Chuyển đổi & Kiểm tra")
103
+ stt, trans, gen2 = (
104
+ gr.Textbox(label="Trạng thái kiểm duyệt"),
105
+ gr.Textbox(label="Văn bản chuyển đổi"),
106
+ gr.Textbox(label="Kết quả GenAI"),
107
+ )
108
+ btn2.click(fn=transcribe_and_check, inputs=audio_input, outputs=[stt, trans, gen2])
app/gen_ai.py CHANGED
@@ -1,7 +1,15 @@
1
- from transformers import pipeline
2
 
3
- generator = pipeline("text-generation", model="gpt2")
 
 
 
 
 
 
 
 
4
 
5
  def generate_response(prompt: str):
6
- result = generator(prompt, max_length=100, do_sample=True, temperature=0.7)
7
- return result[0]["generated_text"]
 
1
+ # from transformers import pipeline
2
 
3
+ # generator = pipeline("text-generation", model="gpt2")
4
+
5
+ # def generate_response(prompt: str):
6
+ # result = generator(prompt, max_length=100, do_sample=True, temperature=0.7)
7
+ # return result[0]["generated_text"]
8
+
9
+ from google import genai
10
+
11
+ client = genai.Client(api_key="AIzaSyAYEaSiZq7lcT5eJaVwnZJJ_UMoUTtpjJk")
12
 
13
  def generate_response(prompt: str):
14
+ result = client.models.generate_content(model="gemini-2.0-flash", contents=prompt)
15
+ return result.text
app/safety_check.py CHANGED
@@ -1,3 +1,4 @@
 
1
  from detoxify import Detoxify
2
  from transformers import (
3
  AutoProcessor, AutoModelForImageClassification,
@@ -9,6 +10,43 @@ import torch
9
 
10
  import re
11
  from urllib.parse import urlparse, unquote
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  # Load model phát hiện URL độc hại
14
  classifier = pipeline("zero-shot-classification")
@@ -43,7 +81,6 @@ def generate_caption(image: Image.Image):
43
  out = blip_model.generate(**inputs)
44
  caption = blip_processor.decode(out[0], skip_special_tokens=True)
45
  return caption
46
-
47
  def check_nsfw_image(image: Image.Image) -> str:
48
  """Kiểm tra và trả về kết quả NSFW của ảnh"""
49
  # Xử lý NSFW
@@ -106,6 +143,17 @@ def check_violence_image(image: Image.Image) -> str:
106
  - Độ chính xác: {violence_score:.2f}%
107
  - Mô tả: {caption}"""
108
 
 
 
 
 
 
 
 
 
 
 
 
109
  # ===Hàm check url===
110
  def check_url(url: str):
111
  try:
@@ -182,21 +230,17 @@ def format_report(report: dict, is_safe: bool):
182
  • URL gốc: {report['url']}
183
  • Domain: {report['domain']}
184
  • Đường dẫn: {report['path']}
185
-
186
  📢 CẢNH BÁO:
187
  {warning_text}
188
-
189
  🤖 Phân tích AI:
190
  - Kết quả: {report['ai_analysis']['label']}
191
  - Độ tin cậy: {report['ai_analysis']['confidence']:.2f}%
192
-
193
  🛡️ Khuyến nghị: KHÔNG TRUY CẬP!"""
194
  else:
195
  return f"""✅ URL AN TOÀN
196
  🔍 Phân tích chi tiết:
197
  • URL gốc: {report['url']}
198
  • Domain: {report['domain']}
199
-
200
  🤖 Phân tích AI:
201
  - Kết quả: {report['ai_analysis']['label']}
202
- - Độ tin cậy: {report['ai_analysis']['confidence']:.2f}%"""
 
1
+ import speech_recognition as sr
2
  from detoxify import Detoxify
3
  from transformers import (
4
  AutoProcessor, AutoModelForImageClassification,
 
10
 
11
  import re
12
  from urllib.parse import urlparse, unquote
13
+ # Khởi tạo Detoxify model
14
+ detox_model = Detoxify('original')
15
+
16
+ # Hàm chuyển đổi giọng nói thành văn bản
17
+ def speech_to_text():
18
+ recognizer = sr.Recognizer()
19
+
20
+ with sr.Microphone() as source:
21
+ print("Đang nghe... Hãy nói điều gì đó")
22
+ recognizer.adjust_for_ambient_noise(source)
23
+ audio = recognizer.listen(source)
24
+
25
+ try:
26
+ print("Đang xử lý...")
27
+ text = recognizer.recognize_google(audio, language="vi-VN")
28
+ print(f"Bạn đã nói: {text}")
29
+ return text
30
+ except sr.UnknownValueError:
31
+ print("Không nhận dạng được giọng nói")
32
+ return ""
33
+ except sr.RequestError as e:
34
+ print(f"Lỗi kết nối đến dịch vụ nhận diện giọng nói: {e}")
35
+ return ""
36
+
37
+ # Hàm chính thực hiện quy trình: speech -> text -> toxic detection
38
+ def detect_toxic_speech():
39
+ text = speech_to_text()
40
+
41
+ if not text:
42
+ return "Không có văn bản để phân tích"
43
+
44
+ is_safe, toxic_categories = is_prompt_safe(text)
45
+
46
+ if is_safe:
47
+ return f"Văn bản an toàn: '{text}'"
48
+ else:
49
+ return f"Phát hiện nội dung không an toàn trong: '{text}'\nCác danh mục: {toxic_categories}"
50
 
51
  # Load model phát hiện URL độc hại
52
  classifier = pipeline("zero-shot-classification")
 
81
  out = blip_model.generate(**inputs)
82
  caption = blip_processor.decode(out[0], skip_special_tokens=True)
83
  return caption
 
84
  def check_nsfw_image(image: Image.Image) -> str:
85
  """Kiểm tra và trả về kết quả NSFW của ảnh"""
86
  # Xử lý NSFW
 
143
  - Độ chính xác: {violence_score:.2f}%
144
  - Mô tả: {caption}"""
145
 
146
+ # ===Hàm check url===
147
+ def check_url(url: str):
148
+ try:
149
+ # Chuẩn hóa URL (decode các ký tự đặc biệt)
150
+ decoded_url = unquote(url)
151
+ parsed = urlparse(decoded_url)
152
+
153
+ # Danh sách cảnh báo
154
+ warnings = []
155
+
156
+ # 1. Phát hiện IP thay vì domain (
157
  # ===Hàm check url===
158
  def check_url(url: str):
159
  try:
 
230
  • URL gốc: {report['url']}
231
  • Domain: {report['domain']}
232
  • Đường dẫn: {report['path']}
 
233
  📢 CẢNH BÁO:
234
  {warning_text}
 
235
  🤖 Phân tích AI:
236
  - Kết quả: {report['ai_analysis']['label']}
237
  - Độ tin cậy: {report['ai_analysis']['confidence']:.2f}%
 
238
  🛡️ Khuyến nghị: KHÔNG TRUY CẬP!"""
239
  else:
240
  return f"""✅ URL AN TOÀN
241
  🔍 Phân tích chi tiết:
242
  • URL gốc: {report['url']}
243
  • Domain: {report['domain']}
 
244
  🤖 Phân tích AI:
245
  - Kết quả: {report['ai_analysis']['label']}
246
+ - Độ tin cậy: {report['ai_analysis']['confidence']:.2f}%"""
requirements.txt CHANGED
@@ -5,3 +5,7 @@ protobuf
5
  presidio-analyzer
6
  detoxify
7
  Pillow
 
 
 
 
 
5
  presidio-analyzer
6
  detoxify
7
  Pillow
8
+ google-genai
9
+ openai-whisper
10
+ scipy
11
+ SpeechRecognition