Spaces:
Paused
Paused
| from flask import Flask, render_template, request, jsonify | |
| import re | |
| import requests | |
| from urllib.parse import urlparse, parse_qs | |
| import json | |
| from datetime import datetime | |
| import os | |
| from typing import Dict, List, Tuple | |
| import time | |
| import random | |
| from openai import OpenAI | |
| app = Flask(__name__) | |
| class ScamSignalVerifier: | |
| def __init__(self): | |
| # Initialize OpenAI client | |
| self.openai_client = None | |
| self._init_openai() | |
| self.scam_keywords = [ | |
| 'urgent', 'limited time', 'act now', 'click here', 'guaranteed', | |
| 'free money', 'no risk', 'earn money fast', 'work from home', | |
| 'congratulations', 'you have won', 'claim now', 'verify account', | |
| 'suspended', 'confirm identity', 'update payment', 'bitcoin', | |
| 'cryptocurrency', 'investment opportunity', 'double your money', | |
| 'risk-free', 'government grant', 'tax refund', 'inheritance', | |
| 'lottery', 'sweepstakes', 'prince', 'transfer funds', | |
| 'logged out', 'share details', 'bank account', 'account details', | |
| 'provide details', 'get back', 'restore access' | |
| ] | |
| self.suspicious_domains = [ | |
| 'bit.ly', 'tinyurl.com', 'shortened.link', 'click.me', | |
| 'secure-bank.net', 'paypal-verify.com', 'amazon-update.net' | |
| ] | |
| self.legitimate_domains = [ | |
| 'google.com', 'facebook.com', 'amazon.com', 'paypal.com', | |
| 'microsoft.com', 'apple.com', 'linkedin.com', 'twitter.com', | |
| 'instagram.com', 'youtube.com', 'github.com', 'stackoverflow.com' | |
| ] | |
| def _init_openai(self): | |
| """Initialize OpenAI client with API key from Hugging Face secrets""" | |
| try: | |
| api_key = os.environ.get('OPENAI_API_KEY') | |
| if api_key: | |
| self.openai_client = OpenAI(api_key=api_key) | |
| print("✅ OpenAI API initialized successfully") | |
| else: | |
| print("⚠️ OpenAI API key not found - falling back to rule-based analysis only") | |
| self.openai_client = None | |
| except Exception as e: | |
| print(f"⚠️ Failed to initialize OpenAI API: {str(e)}") | |
| self.openai_client = None | |
| def ai_analyze_scam(self, text: str, url: str = None) -> Dict: | |
| """Use OpenAI to perform intelligent scam analysis""" | |
| if not self.openai_client: | |
| print("DEBUG: OpenAI client not available") | |
| return { | |
| 'ai_available': False, | |
| 'ai_risk_score': 0, | |
| 'ai_confidence': 0, | |
| 'ai_explanation': 'AI analysis unavailable - using rule-based detection only', | |
| 'scam_type': 'Unknown', | |
| 'social_engineering_tactics': [], | |
| 'sophistication_level': 'N/A' | |
| } | |
| try: | |
| print("DEBUG: Making OpenAI API call...") | |
| # Construct the analysis prompt | |
| analysis_prompt = f""" | |
| You are an expert cybersecurity analyst specializing in scam detection. Analyze the following message for scam indicators using advanced pattern recognition and social engineering analysis. | |
| MESSAGE TO ANALYZE: | |
| "{text}" | |
| {f'ASSOCIATED URL: {url}' if url else ''} | |
| Please provide a comprehensive analysis in JSON format with these exact fields: | |
| 1. "ai_risk_score": Integer from 0-100 (0=definitely legitimate, 100=definitely scam) | |
| 2. "ai_confidence": Integer from 0-100 (how confident you are in your assessment) | |
| 3. "scam_type": String identifying the primary scam type (e.g., "Phishing", "419 Scam", "Investment Fraud", "Romance Scam", "Tech Support Scam", "Lottery Scam", "Legitimate") | |
| 4. "social_engineering_tactics": Array of strings describing psychological manipulation techniques used | |
| 5. "sophistication_level": String ("Low", "Medium", "High") - how well-crafted the scam attempt is | |
| 6. "ai_explanation": String with detailed reasoning for your assessment | |
| 7. "grammar_quality": String ("Poor", "Fair", "Good", "Excellent") - grammar and writing quality assessment | |
| 8. "emotional_manipulation": String describing emotional appeals used (urgency, fear, greed, etc.) | |
| Focus on: | |
| - Subtle linguistic patterns that indicate deception | |
| - Psychological manipulation techniques | |
| - Context inconsistencies | |
| - Grammar/spelling patterns typical of scams | |
| - Social engineering red flags | |
| - Urgency and pressure tactics | |
| - Trust-building followed by requests | |
| - Too-good-to-be-true offers | |
| Respond ONLY with valid JSON format. | |
| """ | |
| # Make API call to OpenAI | |
| response = self.openai_client.chat.completions.create( | |
| model="gpt-4o-mini", | |
| messages=[ | |
| { | |
| "role": "system", | |
| "content": "You are an expert scam detection AI. You must respond only with valid JSON format as requested." | |
| }, | |
| { | |
| "role": "user", | |
| "content": analysis_prompt | |
| } | |
| ], | |
| max_tokens=800, | |
| temperature=0.3 # Lower temperature for more consistent analysis | |
| ) | |
| # Parse the AI response | |
| ai_response = response.choices[0].message.content.strip() | |
| print(f"DEBUG: OpenAI raw response: {ai_response}") | |
| # Try to parse JSON response | |
| try: | |
| ai_analysis = json.loads(ai_response) | |
| ai_analysis['ai_available'] = True | |
| print(f"DEBUG: AI analysis successful - risk score: {ai_analysis.get('ai_risk_score', 'N/A')}") | |
| return ai_analysis | |
| except json.JSONDecodeError as je: | |
| print(f"DEBUG: JSON parsing failed: {str(je)}") | |
| # Fallback if JSON parsing fails | |
| return { | |
| 'ai_available': True, | |
| 'ai_risk_score': 50, # Default moderate risk when parsing fails | |
| 'ai_confidence': 30, | |
| 'ai_explanation': f'AI analysis completed but response parsing failed. Raw response: {ai_response[:200]}...', | |
| 'scam_type': 'Analysis Error', | |
| 'social_engineering_tactics': [], | |
| 'sophistication_level': 'Unknown' | |
| } | |
| except Exception as e: | |
| print(f"DEBUG: OpenAI API error: {str(e)}") | |
| return { | |
| 'ai_available': False, | |
| 'ai_risk_score': 0, | |
| 'ai_confidence': 0, | |
| 'ai_explanation': f'AI analysis failed: {str(e)}', | |
| 'scam_type': 'Analysis Failed', | |
| 'social_engineering_tactics': [], | |
| 'sophistication_level': 'N/A' | |
| } | |
| def extract_claims(self, text: str, url: str = None) -> Dict: | |
| claims = { | |
| 'text_content': text, | |
| 'urls': [], | |
| 'phone_numbers': [], | |
| 'email_addresses': [], | |
| 'money_amounts': [], | |
| 'suspicious_phrases': [], | |
| 'urgency_indicators': [] | |
| } | |
| url_pattern = r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+' | |
| claims['urls'] = re.findall(url_pattern, text) | |
| if url: | |
| claims['urls'].append(url) | |
| phone_pattern = r'\b(?:\+?1[-.\s]?)?\(?([0-9]{3})\)?[-.\s]?([0-9]{3})[-.\s]?([0-9]{4})\b' | |
| claims['phone_numbers'] = re.findall(phone_pattern, text) | |
| email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b' | |
| claims['email_addresses'] = re.findall(email_pattern, text) | |
| money_pattern = r'\$[\d,]+\.?\d*|\d+\s*(?:dollars?|USD|euros?|pounds?)' | |
| claims['money_amounts'] = re.findall(money_pattern, text, re.IGNORECASE) | |
| text_lower = text.lower() | |
| for keyword in self.scam_keywords: | |
| if keyword in text_lower: | |
| claims['suspicious_phrases'].append(keyword) | |
| high_risk_patterns = [ | |
| 'you won', 'you have won', 'winner', 'selected winner', | |
| 'send bank details', 'provide bank account', 'wire transfer', | |
| 'inheritance fund', 'beneficiary', 'claim your prize', | |
| 'processing fee', 'activation fee', 'clearance fee', | |
| 'verify your account', 'account suspended', 'account locked', | |
| 'logged out', 'share details', 'get your bank account back', | |
| 'bank account', 'share bank details', 'provide details' | |
| ] | |
| for pattern in high_risk_patterns: | |
| if pattern in text_lower: | |
| claims['suspicious_phrases'].append(pattern) | |
| urgency_patterns = [ | |
| r'within \d+\s*(?:hours?|days?|minutes?)', | |
| r'expires? (?:today|tomorrow|soon)', | |
| r'limited time', | |
| r'act (?:now|immediately|fast)', | |
| r'urgent.{0,20}(?:action|response|reply)' | |
| ] | |
| for pattern in urgency_patterns: | |
| matches = re.findall(pattern, text_lower) | |
| claims['urgency_indicators'].extend(matches) | |
| return claims | |
| def verify_claims(self, claims: Dict) -> Dict: | |
| verification_results = { | |
| 'domain_analysis': {}, | |
| 'keyword_score': 0, | |
| 'urgency_score': 0, | |
| 'contact_info_risk': 0, | |
| 'financial_risk': 0 | |
| } | |
| for url in claims['urls']: | |
| try: | |
| parsed = urlparse(url) | |
| domain = parsed.netloc.lower() | |
| if any(suspicious in domain for suspicious in self.suspicious_domains): | |
| verification_results['domain_analysis'][domain] = 'HIGH_RISK' | |
| elif any(legit in domain for legit in self.legitimate_domains): | |
| verification_results['domain_analysis'][domain] = 'LOW_RISK' | |
| elif len(domain.split('.')) > 3: | |
| verification_results['domain_analysis'][domain] = 'MEDIUM_RISK' | |
| else: | |
| verification_results['domain_analysis'][domain] = 'UNKNOWN' | |
| except: | |
| verification_results['domain_analysis'][url] = 'INVALID_URL' | |
| verification_results['keyword_score'] = min(100, len(claims['suspicious_phrases']) * 15) | |
| verification_results['urgency_score'] = min(100, len(claims['urgency_indicators']) * 25) | |
| if claims['phone_numbers'] and claims['email_addresses']: | |
| verification_results['contact_info_risk'] = 60 | |
| elif claims['phone_numbers'] or claims['email_addresses']: | |
| verification_results['contact_info_risk'] = 30 | |
| if claims['money_amounts']: | |
| verification_results['financial_risk'] = 70 if len(claims['money_amounts']) > 2 else 40 | |
| return verification_results | |
| def calculate_hybrid_risk_score(self, claims: Dict, verification: Dict, ai_analysis: Dict) -> Tuple[int, str]: | |
| """Calculate combined risk score using both rule-based and AI analysis""" | |
| text_lower = claims['text_content'].lower() | |
| print(f"DEBUG: Analyzing text: '{text_lower}'") # Debug line | |
| # Start with base rule-based scoring | |
| rule_based_score = 0 | |
| rule_based_score += verification['keyword_score'] * 0.4 | |
| rule_based_score += verification['urgency_score'] * 0.25 | |
| rule_based_score += verification['contact_info_risk'] * 0.25 | |
| rule_based_score += verification['financial_risk'] * 0.36 | |
| print(f"DEBUG: Base scores - keyword:{verification['keyword_score']}, urgency:{verification['urgency_score']}, contact:{verification['contact_info_risk']}, financial:{verification['financial_risk']}") | |
| # Domain analysis | |
| domain_risk = 0 | |
| for domain, risk in verification['domain_analysis'].items(): | |
| if risk == 'HIGH_RISK': | |
| domain_risk += 30 | |
| elif risk == 'MEDIUM_RISK': | |
| domain_risk += 15 | |
| elif risk == 'INVALID_URL': | |
| domain_risk += 10 | |
| rule_based_score += min(30, domain_risk) | |
| # CRITICAL SCAM PATTERNS - These should trigger HIGH scores immediately | |
| critical_patterns = [ | |
| ('send bank details', 80), | |
| ('provide bank details', 80), | |
| ('share bank details', 80), | |
| ('bank account details', 75), | |
| ('send details', 70), | |
| ('share details', 70), | |
| ('provide details', 65), | |
| ('logged out', 60), | |
| ('account suspended', 65), | |
| ('account locked', 65), | |
| ('verify account', 55), | |
| ('confirm identity', 55) | |
| ] | |
| pattern_bonus = 0 | |
| for pattern, score in critical_patterns: | |
| if pattern in text_lower: | |
| pattern_bonus = max(pattern_bonus, score) | |
| print(f"DEBUG: Found critical pattern '{pattern}' - adding {score} points") | |
| rule_based_score += pattern_bonus | |
| # High-risk combinations | |
| bank_terms = ['bank account', 'bank details', 'account details', 'account info'] | |
| action_terms = ['send', 'provide', 'share', 'give'] | |
| threat_terms = ['logged out', 'suspended', 'locked', 'blocked', 'expired'] | |
| has_bank = any(term in text_lower for term in bank_terms) | |
| has_action = any(term in text_lower for term in action_terms) | |
| has_threat = any(term in text_lower for term in threat_terms) | |
| if has_bank and has_action: | |
| rule_based_score += 40 | |
| print("DEBUG: Bank + Action combo detected - adding 40 points") | |
| if has_threat and (has_bank or has_action): | |
| rule_based_score += 30 | |
| print("DEBUG: Threat + Bank/Action combo detected - adding 30 points") | |
| # Lottery/prize scams | |
| if any(phrase in text_lower for phrase in ['you won', 'you have won', 'congratulations', 'winner']): | |
| if any(word in text_lower for word in ['send', 'provide', 'bank', 'details', 'account']): | |
| rule_based_score += 40 | |
| print("DEBUG: Prize + financial request detected - adding 40 points") | |
| # Investment/money scams | |
| if any(phrase in text_lower for phrase in ['double your money', 'guaranteed return', 'risk-free', 'investment opportunity']): | |
| rule_based_score += 35 | |
| print("DEBUG: Investment scam pattern detected - adding 35 points") | |
| rule_based_score = min(100, int(rule_based_score)) | |
| print(f"DEBUG: Final rule-based score: {rule_based_score}") | |
| # Handle AI analysis | |
| final_score = rule_based_score | |
| if ai_analysis['ai_available'] and ai_analysis.get('ai_risk_score', 0) > 0: | |
| ai_score = ai_analysis['ai_risk_score'] | |
| ai_confidence = ai_analysis.get('ai_confidence', 0) | |
| print(f"DEBUG: AI analysis - score: {ai_score}, confidence: {ai_confidence}") | |
| if ai_confidence > 30: | |
| # Combine scores, but don't let AI override obvious high-risk patterns | |
| ai_weight = min(0.4, ai_confidence / 100 * 0.6) # Reduced AI weight | |
| rule_weight = 1 - ai_weight | |
| combined_score = (rule_based_score * rule_weight) + (ai_score * ai_weight) | |
| # Take the higher of rule-based or combined score | |
| final_score = max(rule_based_score, int(combined_score)) | |
| print(f"DEBUG: Combined with AI - final score: {final_score}") | |
| final_score = min(100, final_score) | |
| # Determine classification | |
| if final_score >= 70: | |
| classification = "HIGH RISK" | |
| elif final_score >= 45: | |
| classification = "MEDIUM RISK" | |
| elif final_score >= 20: | |
| classification = "LOW RISK" | |
| else: | |
| classification = "MINIMAL RISK" | |
| print(f"DEBUG: Final classification: {classification} (score: {final_score})") | |
| return final_score, classification | |
| def generate_enhanced_explanation(self, claims: Dict, verification: Dict, ai_analysis: Dict, risk_score: int, classification: str) -> Dict: | |
| red_flags = [] | |
| recommendations = [] | |
| # Rule-based red flags | |
| if len(claims['suspicious_phrases']) > 0: | |
| red_flags.append(f"Contains {len(claims['suspicious_phrases'])} suspicious keywords/phrases") | |
| if verification['urgency_score'] > 20: | |
| red_flags.append("Uses high-pressure urgency tactics") | |
| for domain, risk in verification['domain_analysis'].items(): | |
| if risk == 'HIGH_RISK': | |
| red_flags.append(f"Uses suspicious domain: {domain}") | |
| elif risk == 'MEDIUM_RISK': | |
| red_flags.append(f"Domain structure looks suspicious: {domain}") | |
| elif risk == 'INVALID_URL': | |
| red_flags.append(f"Contains invalid/malformed URL: {domain}") | |
| if claims['money_amounts']: | |
| red_flags.append("Mentions money/financial transactions") | |
| if len(claims['urls']) > 3: | |
| red_flags.append("Contains multiple links (potential redirect chains)") | |
| text_lower = claims['text_content'].lower() | |
| if any(phrase in text_lower for phrase in ['you won', 'you have won', 'winner']): | |
| red_flags.append("Claims you won money/prizes (common lottery scam)") | |
| if any(phrase in text_lower for phrase in ['send bank', 'provide bank', 'bank details', 'account details', 'share details']): | |
| red_flags.append("Requests bank account details (major red flag)") | |
| if any(phrase in text_lower for phrase in ['logged out', 'account suspended', 'account locked', 'account blocked']): | |
| red_flags.append("Claims account issues to pressure immediate action") | |
| if 'processing fee' in text_lower or 'activation fee' in text_lower: | |
| red_flags.append("Requests upfront fees (advance fee fraud)") | |
| # Add AI-based insights | |
| if ai_analysis['ai_available']: | |
| if ai_analysis.get('scam_type') and ai_analysis['scam_type'] not in ['Legitimate', 'Analysis Error', 'Analysis Failed']: | |
| red_flags.append(f"🤖 AI detected: {ai_analysis['scam_type']} pattern") | |
| for tactic in ai_analysis.get('social_engineering_tactics', []): | |
| red_flags.append(f"🤖 Social engineering: {tactic}") | |
| if ai_analysis.get('sophistication_level') == 'High': | |
| red_flags.append("🤖 AI detected sophisticated scam techniques") | |
| # Enhanced recommendations based on AI analysis | |
| if classification == "HIGH RISK": | |
| recommendations = [ | |
| "🚫 This is very likely a SCAM - Do NOT respond or engage", | |
| "🚫 Do NOT click any links or provide personal information", | |
| "🚫 Do NOT send money or share financial details", | |
| "📧 Report this message as spam/phishing immediately", | |
| "🛡️ Block the sender and delete the message", | |
| "👥 Warn friends/family about this type of scam" | |
| ] | |
| if ai_analysis['ai_available'] and ai_analysis.get('scam_type'): | |
| recommendations.append(f"🤖 Specific threat: This appears to be a {ai_analysis['scam_type']} - research this scam type for more info") | |
| elif classification == "MEDIUM RISK": | |
| recommendations = [ | |
| "⚠️ HIGH CAUTION ADVISED - Verify independently before taking action", | |
| "🔍 Contact the organization directly using official channels", | |
| "🚫 Don't click links - navigate to official websites manually", | |
| "👨👩👧👦 Ask a trusted friend or family member for advice", | |
| "⏰ Take time to think - don't rush into decisions", | |
| "🛡️ Never share sensitive personal or financial information" | |
| ] | |
| elif classification == "LOW RISK": | |
| recommendations = [ | |
| "⚠️ Proceed with caution - some concerning elements detected", | |
| "🔍 Verify any claims through official sources", | |
| "🛡️ Avoid sharing sensitive personal information", | |
| "📞 When in doubt, contact the organization directly" | |
| ] | |
| else: | |
| recommendations = [ | |
| "✅ Message appears relatively safe", | |
| "🛡️ Always practice general online safety", | |
| "🔍 Verify important information independently" | |
| ] | |
| # Enhanced explanation with AI insights | |
| explanation = { | |
| 'risk_score': risk_score, | |
| 'classification': classification, | |
| 'summary': self._generate_enhanced_summary(classification, len(red_flags), ai_analysis), | |
| 'red_flags': red_flags, | |
| 'recommendations': recommendations, | |
| 'ai_insights': { | |
| 'available': ai_analysis['ai_available'], | |
| 'confidence': ai_analysis.get('ai_confidence', 0), | |
| 'scam_type': ai_analysis.get('scam_type', 'N/A'), | |
| 'sophistication': ai_analysis.get('sophistication_level', 'N/A'), | |
| 'explanation': ai_analysis.get('ai_explanation', 'AI analysis not available') | |
| }, | |
| 'report_template': self._generate_report_template(claims) | |
| } | |
| return explanation | |
| def _generate_enhanced_summary(self, classification: str, flag_count: int, ai_analysis: Dict) -> str: | |
| ai_suffix = "" | |
| if ai_analysis['ai_available']: | |
| confidence = ai_analysis.get('ai_confidence', 0) | |
| if confidence > 70: | |
| ai_suffix = f" AI analysis confirms with {confidence}% confidence." | |
| elif confidence > 30: | |
| ai_suffix = f" AI analysis supports this assessment ({confidence}% confidence)." | |
| if classification == "HIGH RISK": | |
| return f"This message shows {flag_count} major warning signs of a scam.{ai_suffix} Avoid all interaction and report immediately." | |
| elif classification == "MEDIUM RISK": | |
| return f"This message has {flag_count} concerning elements.{ai_suffix} Exercise extreme caution and verify independently." | |
| elif classification == "LOW RISK": | |
| return f"While not immediately dangerous, this message has {flag_count} minor concerns.{ai_suffix} Stay alert." | |
| else: | |
| return f"This message appears legitimate.{ai_suffix} Always practice good online safety habits." | |
| def _generate_report_template(self, claims: Dict) -> str: | |
| template = f""" | |
| SCAM REPORT TEMPLATE: | |
| Subject: Reporting Suspicious Message/Scam Attempt | |
| Dear [Platform/Authority], | |
| I received a suspicious message that appears to be a scam attempt. Details: | |
| Date Received: {datetime.now().strftime('%Y-%m-%d %H:%M')} | |
| Suspicious Elements: | |
| - Keywords: {', '.join(claims['suspicious_phrases'][:5])} | |
| - URLs: {', '.join(claims['urls'][:3])} | |
| - Contact Info: {', '.join([str(p) for p in claims['phone_numbers'][:2]])} | |
| Message Content: [Include original message here] | |
| Please investigate and take appropriate action. | |
| Best regards, | |
| [Your Name] | |
| """.strip() | |
| return template | |
| def analyze_message(self, text: str, url: str = None) -> Dict: | |
| """Enhanced analysis combining rule-based and AI methods""" | |
| # Step 1: Extract claims (rule-based) | |
| claims = self.extract_claims(text, url) | |
| # Step 2: Verify claims (rule-based) | |
| verification = self.verify_claims(claims) | |
| # Step 3: AI analysis (new intelligent layer) | |
| ai_analysis = self.ai_analyze_scam(text, url) | |
| # Step 4: Calculate hybrid risk score | |
| risk_score, classification = self.calculate_hybrid_risk_score(claims, verification, ai_analysis) | |
| # Step 5: Generate enhanced explanation | |
| explanation = self.generate_enhanced_explanation(claims, verification, ai_analysis, risk_score, classification) | |
| return { | |
| 'claims': claims, | |
| 'verification': verification, | |
| 'ai_analysis': ai_analysis, | |
| 'explanation': explanation, | |
| 'analysis_method': 'hybrid' if ai_analysis['ai_available'] else 'rule-based', | |
| 'timestamp': datetime.now().isoformat() | |
| } | |
| verifier = ScamSignalVerifier() | |
| def index(): | |
| return render_template('index.html') | |
| def analyze(): | |
| try: | |
| data = request.get_json() | |
| message_text = data.get('message', '').strip() | |
| message_url = data.get('url', '').strip() | |
| debug_mode = data.get('debug', False) # Add debug parameter | |
| if not message_text and not message_url: | |
| return jsonify({'error': 'Please provide either a message or URL to analyze'}), 400 | |
| # Add small delay to prevent API abuse | |
| time.sleep(0.5) # Reduced delay since we now have AI processing time | |
| result = verifier.analyze_message(message_text, message_url if message_url else None) | |
| # Add debug information if requested | |
| if debug_mode: | |
| result['debug_info'] = { | |
| 'rule_based_score_breakdown': { | |
| 'keyword_score': result['verification']['keyword_score'], | |
| 'urgency_score': result['verification']['urgency_score'], | |
| 'domain_risk': result['verification'].get('domain_risk', 0), | |
| 'contact_info_risk': result['verification']['contact_info_risk'], | |
| 'financial_risk': result['verification']['financial_risk'] | |
| }, | |
| 'detected_phrases': result['claims']['suspicious_phrases'], | |
| 'ai_available': result['ai_analysis']['ai_available'], | |
| 'ai_risk_score': result['ai_analysis'].get('ai_risk_score', 0), | |
| 'ai_confidence': result['ai_analysis'].get('ai_confidence', 0) | |
| } | |
| return jsonify(result) | |
| except Exception as e: | |
| return jsonify({'error': f'Analysis failed: {str(e)}'}), 500 | |
| def test_analysis(): | |
| """Test endpoint with detailed debugging""" | |
| try: | |
| data = request.get_json() | |
| message_text = data.get('message', '').strip() | |
| if not message_text: | |
| return jsonify({'error': 'Please provide a message to test'}), 400 | |
| print(f"\n=== TESTING MESSAGE: '{message_text}' ===") | |
| # Test individual components | |
| claims = verifier.extract_claims(message_text) | |
| print(f"Claims extracted: {claims}") | |
| verification = verifier.verify_claims(claims) | |
| print(f"Verification results: {verification}") | |
| ai_analysis = verifier.ai_analyze_scam(message_text) | |
| print(f"AI analysis: {ai_analysis}") | |
| risk_score, classification = verifier.calculate_hybrid_risk_score(claims, verification, ai_analysis) | |
| print(f"Final score: {risk_score}, classification: {classification}") | |
| return jsonify({ | |
| 'message': message_text, | |
| 'claims': claims, | |
| 'verification': verification, | |
| 'ai_analysis': ai_analysis, | |
| 'final_score': risk_score, | |
| 'classification': classification, | |
| 'debug': 'Check server logs for detailed output' | |
| }) | |
| except Exception as e: | |
| print(f"Test failed with error: {str(e)}") | |
| return jsonify({'error': f'Test failed: {str(e)}'}), 500 | |
| def health(): | |
| """Health check endpoint that also reports AI availability""" | |
| ai_status = "available" if verifier.openai_client else "unavailable" | |
| api_key_present = "yes" if os.environ.get('OPENAI_API_KEY') else "no" | |
| return jsonify({ | |
| 'status': 'healthy', | |
| 'ai_status': ai_status, | |
| 'api_key_present': api_key_present, | |
| 'timestamp': datetime.now().isoformat() | |
| }) | |
| if __name__ == '__main__': | |
| port = int(os.environ.get('PORT', 7860)) | |
| app.run(host='0.0.0.0', port=port, debug=False) |