File size: 8,949 Bytes
3a48c1e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
import gradio as gr
import pandas as pd
import random
import time
from datetime import datetime

# --- Simulated Backend Logic ---
# In a real production environment, this would use libraries like `python-telegram-bot` or `Telethon`
# to connect to the Telegram API and a model like Hugging Face's `toxic-bert` for detection.

class TelegramMonitorSimulator:
    def __init__(self):
        self.hate_keywords = ["hate", "violence", "attack", "stupid", "kill", "idiot"]
        self.sample_messages = [
            "Great meeting today everyone!",
            "I really hate the way this is going.",
            "Check out this new article.",
            "This is just stupid, nobody cares.",
            "Lovely weather we are having.",
            "We should attack this problem head on.",
            "Hello world!",
            "I want to kill this process."
        ]
        self.monitored_channels = []

    def add_channel(self, channel_name):
        if channel_name and channel_name not in self.monitored_channels:
            self.monitored_channels.append(channel_name)
            return f"Added '{channel_name}' to monitoring list."
        return "Channel already exists or name is empty."

    def process_incoming_message(self):
        """Simulates the bot receiving a message from a monitored channel."""
        if not self.monitored_channels:
            return None, "No channels monitored. Add a channel first."
        
        # Pick random channel and message
        channel = random.choice(self.monitored_channels)
        text = random.choice(self.sample_messages)
        
        # Simple detection logic (Simulating an AI model)
        detected = any(word in text.lower() for word in self.hate_keywords)
        score = random.uniform(0.7, 0.99) if detected else random.uniform(0.0, 0.3)
        
        return {
            "id": int(time.time() * 1000),
            "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "channel": channel,
            "message": text,
            "score": round(score, 2),
            "status": "Pending Review"
        }, None

# Initialize the simulator
monitor = TelegramMonitorSimulator()

# --- Gradio Application ---

def update_dashboard(logs):
    """Helper to convert logs state to dataframe for display."""
    if not logs:
        return pd.DataFrame(columns=["ID", "Time", "Channel", "Message", "Score", "Status"])
    return pd.DataFrame(logs)[["id", "timestamp", "channel", "message", "score", "status"]]

def add_channel_handler(channel_input, current_channels):
    result = monitor.add_channel(channel_input)
    # Return updated list of channels for the display/State
    updated_channels = monitor.monitored_channels.copy()
    return result, updated_channels

def simulate_traffic_handler(current_logs):
    """Simulates the bot detecting a hate speech event."""
    new_entry, error = monitor.process_incoming_message()
    
    if error:
        return current_logs, update_dashboard(current_logs), error
    
    # Only log if it looks like hate speech (score > 0.6) for the demo purposes
    # or log everything if you want a full history. Let's log flagged only.
    if new_entry['score'] > 0.6:
        updated_logs = current_logs.copy()
        updated_logs.insert(0, new_entry) # Add to top
        return updated_logs, update_dashboard(updated_logs), "⚠️ New Potential Hate Speech Detected!"
    
    return current_logs, update_dashboard(current_logs), "Message received (clean)."

def assess_message(logs, selected_id, assessment):
    """Updates the status of a selected message."""
    if not logs or selected_id is None:
        return logs, update_dashboard(logs), gr.Dropdown(choices=[], value=None), "No message selected."
    
    updated_logs = []
    found = False
    for log in logs:
        if log['id'] == selected_id:
            log['status'] = assessment
            found = True
        updated_logs.append(log)
    
    if found:
        # Refresh dropdown choices (remove the assessed item from pending)
        pending_ids = [l['id'] for l in updated_logs if l['status'] == "Pending Review"]
        return updated_logs, update_dashboard(updated_logs), gr.Dropdown(choices=pending_ids, value=None), f"Message ID {selected_id} marked as {assessment}."
    
    return logs, update_dashboard(logs), gr.Dropdown(choices=[l['id'] for l in logs if l['status'] == "Pending Review"], value=None), "Message not found."

# --- Gradio UI Construction ---

# Note: In Gradio 6, Blocks takes no parameters. Configuration goes in launch().
with gr.Blocks() as demo:
    
    # Header
    gr.HTML("""
        <div style="text-align: center; margin-bottom: 2rem;">
            <h1>πŸ›‘οΈ Telegram Hate Speech Monitor</h1>
            <p>AI-powered monitoring dashboard for public channel safety</p>
            <p style="font-size: 0.9em; color: gray;">
                Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a>
            </p>
        </div>
    """)

    with gr.Row():
        # Left Column: Controls
        with gr.Column(scale=1):
            gr.Markdown("### βš™οΈ Configuration")
            
            with gr.Group():
                channel_input = gr.Textbox(label="Channel Username", placeholder="@example_channel")
                add_channel_btn = gr.Button("Add Channel", variant="primary")
                channel_status = gr.Textbox(label="Status", interactive=False)
                
                monitored_list = gr.JSON(label="Monitored Channels", value=[])
            
            gr.Markdown("### πŸ“‘ Live Monitor (Simulated)")
            gr.Markdown("*Click to simulate incoming messages from monitored channels.*")
            simulate_btn = gr.Button("Simulate Incoming Traffic", variant="secondary")
            monitor_status = gr.Textbox(label="Monitor Log", interactive=False)

        # Right Column: Dashboard
        with gr.Column(scale=3):
            gr.Markdown("### πŸ“‹ Flagged Content Review")
            
            # Dataframe to show logs
            logs_df = gr.Dataframe(
                label="Detected Messages",
                headers=["ID", "Time", "Channel", "Message", "Score", "Status"],
                datatype=["number", "str", "str", "str", "number", "str"],
                interactive=False,
                wrap=True
            )

            gr.Markdown("### ✍️ Human Assessment")
            with gr.Row():
                msg_selector = gr.Dropdown(
                    label="Select Pending Message ID",
                    choices=[],
                    info="Select a message from the list above to review"
                )
            
            with gr.Row():
                approve_btn = gr.Button("βœ… Confirm Hate Speech", variant="stop")
                reject_btn = gr.Button("❌ False Positive", variant="secondary")
            
            assessment_feedback = gr.Textbox(label="Assessment Result", interactive=False)

    # --- State Management ---
    # We store the raw logs in state so we can manipulate them
    logs_state = gr.State(value=[])

    # --- Event Listeners ---
    
    # 1. Add Channel
    add_channel_btn.click(
        fn=add_channel_handler,
        inputs=[channel_input, monitored_list],
        outputs=[channel_status, monitored_list],
        api_visibility="private"
    )

    # 2. Simulate Traffic (The Bot Loop)
    simulate_btn.click(
        fn=simulate_traffic_handler,
        inputs=[logs_state],
        outputs=[logs_state, logs_df, monitor_status],
        api_visibility="private"
    )

    # 3. Assessment Logic
    # Helper to update dropdown choices based on current state
    def update_dropdown(logs):
        pending = [l['id'] for l in logs if l['status'] == "Pending Review"]
        return gr.Dropdown(choices=pending, value=None)

    # When logs change (via simulation), update the dropdown options
    logs_state.change(
        fn=update_dropdown,
        inputs=[logs_state],
        outputs=[msg_selector]
    )

    approve_btn.click(
        fn=assess_message,
        inputs=[logs_state, msg_selector, gr.State("Confirmed Hate Speech")],
        outputs=[logs_state, logs_df, msg_selector, assessment_feedback],
        api_visibility="private"
    )

    reject_btn.click(
        fn=assess_message,
        inputs=[logs_state, msg_selector, gr.State("False Positive")],
        outputs=[logs_state, logs_df, msg_selector, assessment_feedback],
        api_visibility="private"
    )

# --- Launch ---
# In Gradio 6, theme and other app-level params are in launch()
demo.launch(
    theme=gr.themes.Soft(
        primary_hue="red",
        secondary_hue="orange",
        neutral_hue="slate"
    ),
    footer_links=[
        {"label": "View Source", "url": "https://github.com/gradio-app/gradio"},
        {"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"}
    ]
)