AayanSuleri commited on
Commit
c314765
·
verified ·
1 Parent(s): 0e390e9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -432
app.py CHANGED
@@ -1,447 +1,96 @@
 
1
  import os
2
- import re
3
- import requests
4
- from urllib.parse import urlparse
5
- import gradio as gr
6
- import json
7
- from typing import Dict, List, Tuple
8
  import time
9
-
10
- # Initialize OpenAI client with error handling
11
- try:
12
- from openai import OpenAI
13
- api_key = os.getenv("OPENAI_API_KEY")
14
- if not api_key:
15
- raise ValueError("OPENAI_API_KEY environment variable is not set")
16
- client = OpenAI(api_key=api_key)
17
- except Exception as e:
18
- print(f"Error initializing OpenAI client: {e}")
19
- client = None
20
-
21
- class ScamVerifierAgent:
22
- def __init__(self):
23
- self.model = "gpt-4o-mini"
24
- self.temperature = 0.3
25
-
26
- def extract_claims_and_urls(self, text: str) -> Dict:
27
- """Agent 1: Extract claims, URLs, and key information from the input"""
28
- if client is None:
29
- return {"error": "OpenAI client not initialized. Please check your API key."}
30
-
31
- prompt = f"""
32
- You are a claim extraction agent. Analyze the following text and extract:
33
- 1. All URLs found in the text
34
- 2. Key claims being made (offers, promises, threats, urgency indicators)
35
- 3. Contact information (phone numbers, emails, social media handles)
36
- 4. Red flag indicators (urgency language, too-good-to-be-true offers, threats)
37
- 5. The main topic/context of the message
38
-
39
- Text to analyze: "{text}"
40
-
41
- Return your analysis in this JSON format:
42
- {{
43
- "urls": ["list of URLs"],
44
- "claims": ["list of key claims"],
45
- "contact_info": ["list of contact details"],
46
- "red_flags": ["list of suspicious elements"],
47
- "main_topic": "brief description of what this is about",
48
- "urgency_level": "low/medium/high"
49
- }}
50
- """
51
-
52
- try:
53
- response = client.chat.completions.create(
54
- model=self.model,
55
- temperature=self.temperature,
56
- messages=[{"role": "user", "content": prompt}]
57
- )
58
-
59
- content = response.choices[0].message.content
60
- # Try to extract JSON from the response
61
- json_match = re.search(r'\{.*\}', content, re.DOTALL)
62
- if json_match:
63
- return json.loads(json_match.group())
64
- else:
65
- # Fallback parsing
66
- return {"error": "Could not parse extraction results", "raw": content}
67
- except Exception as e:
68
- return {"error": f"Extraction failed: {str(e)}"}
69
-
70
- def verify_claims(self, extracted_data: Dict) -> Dict:
71
- """Agent 2: Verify claims and check URLs"""
72
- claims = extracted_data.get("claims", [])
73
- urls = extracted_data.get("urls", [])
74
-
75
- verification_results = {
76
- "url_analysis": [],
77
- "claim_verification": [],
78
- "overall_risk_score": 0
79
- }
80
-
81
- # Analyze URLs
82
- for url in urls[:3]: # Limit to first 3 URLs
83
- url_result = self._analyze_url(url)
84
- verification_results["url_analysis"].append(url_result)
85
-
86
- # Verify claims using LLM knowledge
87
- if claims:
88
- claim_verification = self._verify_claims_with_llm(claims, extracted_data.get("main_topic", ""))
89
- verification_results["claim_verification"] = claim_verification
90
-
91
- # Calculate risk score
92
- verification_results["overall_risk_score"] = self._calculate_risk_score(
93
- extracted_data, verification_results
94
  )
95
-
96
- return verification_results
97
-
98
- def _analyze_url(self, url: str) -> Dict:
99
- """Analyze a single URL for suspicious characteristics"""
100
- analysis = {
101
- "url": url,
102
- "domain_age": "unknown",
103
- "ssl_status": "unknown",
104
- "suspicious_patterns": [],
105
- "risk_level": "low"
106
- }
107
-
108
- try:
109
- parsed = urlparse(url)
110
- domain = parsed.netloc.lower()
111
-
112
- # Check for suspicious patterns
113
- suspicious_patterns = [
114
- "bit.ly", "tinyurl", "t.co", "shortened",
115
- "secure-", "verify-", "update-", "confirm-",
116
- "urgent", "limited", "expired", "suspended"
117
- ]
118
-
119
- found_patterns = [pattern for pattern in suspicious_patterns if pattern in domain or pattern in url.lower()]
120
- analysis["suspicious_patterns"] = found_patterns
121
-
122
- # Simple risk assessment
123
- if found_patterns:
124
- analysis["risk_level"] = "high" if len(found_patterns) > 2 else "medium"
125
-
126
- # Check if domain looks legitimate
127
- legit_domains = ["amazon", "ebay", "paypal", "microsoft", "google", "apple", "facebook", "instagram"]
128
- if any(legit in domain for legit in legit_domains):
129
- # But check for typosquatting
130
- if not any(domain.endswith(f".{legit}.com") or domain == f"{legit}.com" for legit in legit_domains):
131
- analysis["suspicious_patterns"].append("possible_typosquatting")
132
- analysis["risk_level"] = "high"
133
- else:
134
- analysis["risk_level"] = "low"
135
-
136
- except Exception as e:
137
- analysis["error"] = str(e)
138
- analysis["risk_level"] = "medium"
139
-
140
- return analysis
141
-
142
- def _verify_claims_with_llm(self, claims: List[str], topic: str) -> Dict:
143
- """Use LLM to verify claims against common knowledge"""
144
- if client is None:
145
- return {"error": "OpenAI client not initialized"}
146
-
147
- prompt = f"""
148
- You are a fact-checking agent. Analyze these claims in the context of "{topic}" and identify which ones are likely false, misleading, or use common scam tactics.
149
-
150
- Claims to verify:
151
- {json.dumps(claims, indent=2)}
152
-
153
- For each claim, assess:
154
- 1. Likelihood it's legitimate (high/medium/low)
155
- 2. Common scam tactic indicators
156
- 3. Whether it uses urgency, fear, or greed manipulation
157
-
158
- Respond in JSON format:
159
- {{
160
- "claim_assessments": [
161
- {{
162
- "claim": "the claim text",
163
- "legitimacy": "high/medium/low",
164
- "scam_indicators": ["list of red flags"],
165
- "explanation": "brief explanation"
166
- }}
167
- ],
168
- "overall_assessment": "overall legitimacy assessment"
169
- }}
170
- """
171
-
172
- try:
173
- response = client.chat.completions.create(
174
- model=self.model,
175
- temperature=self.temperature,
176
- messages=[{"role": "user", "content": prompt}]
177
- )
178
-
179
- content = response.choices[0].message.content
180
- json_match = re.search(r'\{.*\}', content, re.DOTALL)
181
- if json_match:
182
- return json.loads(json_match.group())
183
- else:
184
- return {"error": "Could not parse verification results"}
185
- except Exception as e:
186
- return {"error": f"Verification failed: {str(e)}"}
187
-
188
- def _calculate_risk_score(self, extracted_data: Dict, verification_results: Dict) -> int:
189
- """Calculate overall risk score (0-100)"""
190
- score = 0
191
-
192
- # Red flags from extraction
193
- red_flags = len(extracted_data.get("red_flags", []))
194
- score += min(red_flags * 15, 45)
195
-
196
- # Urgency level
197
- urgency = extracted_data.get("urgency_level", "low")
198
- if urgency == "high":
199
- score += 25
200
- elif urgency == "medium":
201
- score += 15
202
-
203
- # URL analysis
204
- for url_analysis in verification_results.get("url_analysis", []):
205
- if url_analysis.get("risk_level") == "high":
206
- score += 20
207
- elif url_analysis.get("risk_level") == "medium":
208
- score += 10
209
-
210
- # Claim verification
211
- claim_verification = verification_results.get("claim_verification", {})
212
- assessments = claim_verification.get("claim_assessments", [])
213
- for assessment in assessments:
214
- if assessment.get("legitimacy") == "low":
215
- score += 15
216
- elif assessment.get("legitimacy") == "medium":
217
- score += 8
218
-
219
- return min(score, 100)
220
 
221
- def generate_explanation(self, extracted_data: Dict, verification_results: Dict) -> str:
222
- """Agent 3: Generate human-friendly explanation and recommendations"""
223
- if client is None:
224
- return "Error: OpenAI client not initialized. Please check your API key configuration."
225
-
226
- risk_score = verification_results.get("overall_risk_score", 0)
227
-
228
- prompt = f"""
229
- You are an AI assistant helping users understand potential scams. Based on this analysis, create a clear, helpful explanation for a non-technical user.
230
-
231
- Analysis Data:
232
- - Risk Score: {risk_score}/100
233
- - Extracted Data: {json.dumps(extracted_data, indent=2)}
234
- - Verification Results: {json.dumps(verification_results, indent=2)}
235
-
236
- Create a response with:
237
- 1. Overall assessment (Is this likely a scam?)
238
- 2. Key warning signs found
239
- 3. Specific recommendations for next steps
240
- 4. General tips to stay safe
241
-
242
- Keep it conversational, clear, and actionable. Use emojis sparingly for clarity.
243
- """
244
-
245
- try:
246
- response = client.chat.completions.create(
247
- model=self.model,
248
- temperature=self.temperature,
249
- messages=[{"role": "user", "content": prompt}]
250
- )
251
-
252
- return response.choices[0].message.content
253
- except Exception as e:
254
- return f"Error generating explanation: {str(e)}"
255
-
256
- def analyze_message(message_text: str) -> Tuple[str, str, Dict]:
257
- """Main function to analyze a message"""
258
- if not message_text.strip():
259
- return "Please enter a message or URL to analyze.", "", {}
260
-
261
- # Check if OpenAI client is available
262
- if client is None:
263
- return "❌ Error: OpenAI API not configured", "Please ensure OPENAI_API_KEY is set correctly in your environment.", {}
264
-
265
- agent = ScamVerifierAgent()
266
-
267
- # Step 1: Extract claims and information
268
- extracted_data = agent.extract_claims_and_urls(message_text)
269
-
270
- if "error" in extracted_data:
271
- return f"Analysis Error: {extracted_data['error']}", "", extracted_data
272
-
273
- # Step 2: Verify claims and URLs
274
- verification_results = agent.verify_claims(extracted_data)
275
-
276
- # Step 3: Generate explanation
277
- explanation = agent.generate_explanation(extracted_data, verification_results)
278
-
279
- risk_score = verification_results.get("overall_risk_score", 0)
280
-
281
- # Create risk level indicator
282
- if risk_score >= 70:
283
- risk_indicator = "🚨 HIGH RISK - Likely Scam"
284
- risk_color = "red"
285
- elif risk_score >= 40:
286
- risk_indicator = "⚠️ MEDIUM RISK - Be Cautious"
287
- risk_color = "orange"
288
- else:
289
- risk_indicator = "✅ LOW RISK - Appears Safe"
290
- risk_color = "green"
291
-
292
- # Format technical details
293
- tech_details = f"""
294
- **Risk Score:** {risk_score}/100
295
-
296
- **Extracted Information:**
297
- - URLs Found: {len(extracted_data.get('urls', []))}
298
- - Claims Identified: {len(extracted_data.get('claims', []))}
299
- - Red Flags: {len(extracted_data.get('red_flags', []))}
300
- - Urgency Level: {extracted_data.get('urgency_level', 'Unknown')}
301
 
302
- **Key Red Flags:**
303
- {chr(10).join(f" {flag}" for flag in extracted_data.get('red_flags', []))}
 
 
 
 
 
304
 
305
- **URLs Analyzed:**
306
- {chr(10).join(f" {url['url']} - Risk: {url['risk_level']}" for url in verification_results.get('url_analysis', []))}
307
- """
308
-
309
- return risk_indicator, explanation, {"technical_details": tech_details, "risk_score": risk_score}
310
 
311
- # Custom CSS for better styling
312
- css = """
313
- .gradio-container {
314
- max-width: 900px !important;
315
- margin: auto !important;
316
- }
317
 
318
- .risk-high {
319
- background-color: #fee !important;
320
- border-left: 4px solid #dc2626 !important;
321
- padding: 10px !important;
322
- }
 
323
 
324
- .risk-medium {
325
- background-color: #fef3cd !important;
326
- border-left: 4px solid #f59e0b !important;
327
- padding: 10px !important;
328
- }
 
329
 
330
- .risk-low {
331
- background-color: #d1fae5 !important;
332
- border-left: 4px solid #059669 !important;
333
- padding: 10px !important;
334
- }
335
 
336
- .header-text {
337
- text-align: center !important;
338
- color: #1f2937 !important;
339
- margin-bottom: 20px !important;
340
- }
341
 
342
- .footer-text {
343
- text-align: center !important;
344
- color: #6b7280 !important;
345
- font-size: 14px !important;
346
- margin-top: 20px !important;
347
- }
348
- """
349
 
350
- # Create Gradio interface
351
- with gr.Blocks(css=css, title="Scam-Signal Verifier") as app:
352
- # Check API status
353
- api_status = "✅ OpenAI API Connected" if client else "❌ OpenAI API Not Connected"
354
- api_color = "green" if client else "red"
355
-
356
- gr.HTML(f"""
357
- <div class="header-text">
358
- <h1>🛡️ Scam-Signal Verifier</h1>
359
- <p>Protect yourself from phishing and fake ads with AI-powered analysis</p>
360
- <p style="color: {api_color}; font-size: 14px; margin-top: 5px;">{api_status}</p>
361
- </div>
362
- """)
363
-
364
- with gr.Row():
365
- with gr.Column(scale=2):
366
- message_input = gr.Textbox(
367
- label="Enter suspicious message or URL",
368
- placeholder="Paste the suspicious message, email, or URL here...",
369
- lines=6,
370
- max_lines=10
371
- )
372
-
373
- analyze_btn = gr.Button("🔍 Analyze for Scams", variant="primary", size="lg")
374
-
375
- gr.HTML("""
376
- <div style="margin-top: 15px; padding: 10px; background-color: #f3f4f6; border-radius: 5px;">
377
- <h4>💡 What this tool can analyze:</h4>
378
- <ul style="margin: 5px 0; padding-left: 20px;">
379
- <li>Suspicious text messages or emails</li>
380
- <li>Social media posts or ads</li>
381
- <li>URLs and links</li>
382
- <li>Marketplace listings</li>
383
- <li>Investment or money-making offers</li>
384
- </ul>
385
- </div>
386
- """)
387
-
388
- with gr.Row():
389
- with gr.Column():
390
- risk_output = gr.Textbox(
391
- label="🎯 Risk Assessment",
392
- interactive=False,
393
- lines=1
394
- )
395
-
396
- explanation_output = gr.Textbox(
397
- label="📋 Detailed Analysis & Recommendations",
398
- interactive=False,
399
- lines=12,
400
- max_lines=20
401
- )
402
-
403
- with gr.Row():
404
- with gr.Column():
405
- with gr.Accordion("🔧 Technical Details", open=False):
406
- tech_details = gr.Textbox(
407
- label="Technical Analysis",
408
- interactive=False,
409
- lines=10
410
- )
411
-
412
- # Event handlers
413
- def process_analysis(message):
414
- if not message.strip():
415
- return "Please enter a message to analyze.", "", ""
416
-
417
- try:
418
- risk_indicator, explanation, details = analyze_message(message)
419
- tech_info = details.get("technical_details", "No technical details available.")
420
- return risk_indicator, explanation, tech_info
421
- except Exception as e:
422
- error_msg = f"Analysis failed: {str(e)}"
423
- return error_msg, error_msg, error_msg
424
-
425
- analyze_btn.click(
426
- process_analysis,
427
- inputs=[message_input],
428
- outputs=[risk_output, explanation_output, tech_details]
429
- )
430
-
431
- # Auto-analyze on Enter key
432
- message_input.submit(
433
- process_analysis,
434
- inputs=[message_input],
435
- outputs=[risk_output, explanation_output, tech_details]
436
- )
437
-
438
- gr.HTML("""
439
- <div class="footer-text">
440
- <p>⚠️ This tool provides guidance but cannot guarantee 100% accuracy. Always use your judgment and consult official sources when in doubt.</p>
441
- <p>🚨 If you believe you've encountered a scam, report it to local authorities and relevant platforms.</p>
442
- </div>
443
- """)
444
 
445
- # Launch the app
446
  if __name__ == "__main__":
447
- app.launch(server_name="0.0.0.0", server_port=7860)
 
1
+ from flask import Flask, render_template, request, jsonify
2
  import os
 
 
 
 
 
 
3
  import time
4
+ from crewai import Agent, Task, Crew
5
+ from langchain_openai import ChatOpenAI
6
+
7
+ app = Flask(__name__)
8
+
9
+ # Ensure API key is set in environment
10
+ os.getenv("OPENAI_API_KEY") # Enter your OpenAI API key or set it via env var
11
+
12
+ def run_scam_analysis(message_content):
13
+ if not message_content.strip():
14
+ return "❗ Please enter a message or URL to analyze."
15
+
16
+ loading_messages = [
17
+ "🛡️ Initializing AI security team...",
18
+ "🔍 Claim Extractor analyzing suspicious content...",
19
+ "⚖️ Fact Checker verifying claims and patterns...",
20
+ "📋 Safety Advisor preparing guidance report...",
21
+ "🚨 Generating comprehensive scam analysis..."
22
+ ]
23
+
24
+ try:
25
+ llm = ChatOpenAI(model_name="gpt-4o-mini", temperature=0.1)
26
+
27
+ extractor_agent = Agent(
28
+ role="Claim Extractor",
29
+ goal="Extract key claims, offers, and suspicious elements from messages or URLs",
30
+ backstory="Expert at parsing and identifying key claims in potentially fraudulent messages.",
31
+ llm=llm,
32
+ verbose=False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
+ verifier_agent = Agent(
36
+ role="Fact Checker",
37
+ goal="Verify claims and assess scam probability using heuristic rules and pattern matching",
38
+ backstory="Cybersecurity expert who specializes in identifying scam patterns.",
39
+ llm=llm,
40
+ verbose=False
41
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
+ explainer_agent = Agent(
44
+ role="Safety Advisor",
45
+ goal="Provide clear, actionable guidance to users about potential scams",
46
+ backstory="Digital safety educator who explains complex security issues simply.",
47
+ llm=llm,
48
+ verbose=False
49
+ )
50
 
51
+ extract_task = Task(
52
+ description=f"Analyze and extract suspicious elements from: {message_content}",
53
+ expected_output="Structured summary of extracted claims, suspicious elements, and language patterns",
54
+ agent=extractor_agent
55
+ )
56
 
57
+ verify_task = Task(
58
+ description="Risk assessment with scam probability score, red flags, and evidence",
59
+ expected_output="Risk assessment with scam probability score, red flags, and evidence",
60
+ agent=verifier_agent,
61
+ context=[extract_task]
62
+ )
63
 
64
+ explain_task = Task(
65
+ description="User-friendly safety report with clear recommendations and next steps",
66
+ expected_output="User-friendly safety report with clear recommendations and next steps",
67
+ agent=explainer_agent,
68
+ context=[extract_task, verify_task]
69
+ )
70
 
71
+ crew = Crew(
72
+ agents=[extractor_agent, verifier_agent, explainer_agent],
73
+ tasks=[extract_task, verify_task, explain_task],
74
+ verbose=False,
75
+ process="sequential"
76
+ )
77
 
78
+ result = crew.kickoff()
79
+ return str(result)
 
 
 
80
 
81
+ except Exception as e:
82
+ return f"❌ Scam analysis failed: {str(e)}"
 
 
 
83
 
84
+ @app.route("/")
85
+ def index():
86
+ return render_template("index.html")
 
 
 
 
87
 
88
+ @app.route("/analyze", methods=["POST"])
89
+ def analyze():
90
+ data = request.get_json()
91
+ message = data.get("message", "")
92
+ result = run_scam_analysis(message)
93
+ return jsonify({"result": result})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
 
 
95
  if __name__ == "__main__":
96
+ app.run(host="0.0.0.0", port=7860)