Spaces:
Sleeping
Sleeping
| # -*- coding: utf-8 -*- | |
| import gradio as gr | |
| import os | |
| import tempfile | |
| import time | |
| from typing import Optional, Tuple | |
| from datetime import datetime | |
| # File processing imports | |
| try: | |
| import PyPDF2 | |
| except ImportError: | |
| PyPDF2 = None | |
| try: | |
| import docx | |
| except ImportError: | |
| docx = None | |
| # Import AI detection | |
| try: | |
| from ai_text_detector import AITextDetector | |
| AI_DETECTOR_AVAILABLE = True | |
| print("β Real AI Text Detector imported successfully") | |
| except ImportError as e: | |
| print(f"β οΈ AI Text Detector not found: {e}. Using MOCK detector.") | |
| AI_DETECTOR_AVAILABLE = True | |
| class AITextDetector: | |
| """Mock AI Text Detector for demonstration and testing.""" | |
| def analyze_text(self, text: str) -> dict: | |
| """Analyze text and return AI detection results.""" | |
| import random | |
| if not text.strip(): | |
| raise ValueError("Input text is empty.") | |
| # Simulate processing time | |
| time.sleep(random.uniform(0.5, 1.2)) | |
| # Determine if AI-generated | |
| is_ai = "test ai" in text.lower() or random.choice([True, False]) | |
| if is_ai: | |
| ai_prob = random.uniform(85.0, 99.0) | |
| human_prob = 100.0 - ai_prob | |
| model = random.choice(['GPT-4', 'Claude-3', 'Llama-2']) | |
| analysis = "The text shows patterns consistent with AI generation including uniform sentence structure and low perplexity." | |
| else: | |
| ai_prob = random.uniform(1.0, 15.0) | |
| human_prob = 100.0 - ai_prob | |
| model = 'Human' | |
| analysis = "The text demonstrates natural stylistic variation and lexical diversity typical of human writing." | |
| return { | |
| 'isAI': is_ai, | |
| 'confidence': random.uniform(80.0, 99.0), | |
| 'aiProb': ai_prob, | |
| 'humanProb': human_prob, | |
| 'mostLikelyModel': model, | |
| 'analysis': analysis, | |
| 'detectionMethod': 'Advanced Neural Analysis', | |
| } | |
| class SimpleReportGenerator: | |
| """Generate professional text reports for AI detection analysis.""" | |
| def __init__(self, user: str): | |
| self.user = user | |
| def generate_ai_report(self, text: str, analysis_result: dict, timestamp: str) -> str: | |
| """Generate AI detection report as plain text.""" | |
| try: | |
| is_ai = analysis_result.get('isAI', False) | |
| confidence = analysis_result.get('confidence', 0) | |
| ai_prob = analysis_result.get('aiProb', 0) | |
| human_prob = analysis_result.get('humanProb', 0) | |
| model = analysis_result.get('mostLikelyModel', 'Unknown') | |
| method = analysis_result.get('detectionMethod', 'Advanced AI Detection') | |
| processing_time = analysis_result.get('processingTime', 0) | |
| # Calculate text statistics safely | |
| word_count = len(text.split()) if text.strip() else 0 | |
| avg_word_len = (len(text) / word_count) if word_count > 0 else 0.0 | |
| report = f""" | |
| π€ AI CONTENT DETECTION REPORT | |
| {'=' * 60} | |
| π ANALYSIS SUMMARY | |
| {'=' * 60} | |
| Report Generated: {timestamp} | |
| Analyzed by: {self.user} | |
| Analysis Method: {method} | |
| Processing Time: {processing_time:.2f} seconds | |
| π DETECTION RESULTS | |
| {'=' * 60} | |
| Overall Assessment: {'π€ AI-Generated' if is_ai else 'π€ Human-Written'} | |
| Confidence Level: {confidence:.1f}% | |
| AI Probability: {ai_prob:.1f}% | |
| Human Probability: {human_prob:.1f}% | |
| Most Likely Source: {model.upper()} | |
| π TEXT STATISTICS | |
| {'=' * 60} | |
| Text Length: {len(text):,} characters | |
| Word Count: {word_count:,} words | |
| Average Word Length: {avg_word_len:.1f} characters | |
| π DETAILED ANALYSIS | |
| {'=' * 60} | |
| {analysis_result.get('analysis', 'No detailed analysis available.')} | |
| π― RECOMMENDATIONS | |
| {'=' * 60} | |
| {'β’ Content appears to be AI-generated and may require review' if is_ai else 'β’ Content appears to be authentically human-written'} | |
| {'β’ Consider manual verification for high-stakes applications' if confidence < 80 else 'β’ High confidence in detection result'} | |
| β’ Verify with additional analysis tools if needed | |
| π REPORT METADATA | |
| {'=' * 60} | |
| Platform: OpenAudit AI v1.0.0 | |
| User: {self.user} | |
| Report Type: AI Content Detection | |
| Generation Date: {timestamp} | |
| {'=' * 60} | |
| """ | |
| return report.strip() | |
| except Exception as e: | |
| return f"Error generating report: {str(e)}" | |
| class DocumentProcessor: | |
| """Handle file uploads and text extraction.""" | |
| def extract_text_from_pdf(self, file_path: str) -> str: | |
| """Extract text from PDF files.""" | |
| if PyPDF2 is None: | |
| raise ImportError("PyPDF2 not installed. Install with: pip install PyPDF2") | |
| try: | |
| with open(file_path, 'rb') as file: | |
| pdf_reader = PyPDF2.PdfReader(file) | |
| text = "" | |
| for page in pdf_reader.pages: | |
| page_text = page.extract_text() | |
| if page_text: | |
| text += page_text + "\n" | |
| return text.strip() | |
| except Exception as e: | |
| raise Exception(f"Error reading PDF: {str(e)}") | |
| def extract_text_from_docx(self, file_path: str) -> str: | |
| """Extract text from DOCX files.""" | |
| if docx is None: | |
| raise ImportError("python-docx not installed. Install with: pip install python-docx") | |
| try: | |
| doc = docx.Document(file_path) | |
| text = "\n".join(paragraph.text for paragraph in doc.paragraphs) | |
| return text.strip() | |
| except Exception as e: | |
| raise Exception(f"Error reading DOCX: {str(e)}") | |
| def extract_text_from_txt(self, file_path: str) -> str: | |
| """Extract text from TXT files with encoding fallback.""" | |
| try: | |
| with open(file_path, 'r', encoding='utf-8') as file: | |
| return file.read().strip() | |
| except UnicodeDecodeError: | |
| encodings = ['latin-1', 'cp1252', 'iso-8859-1'] | |
| for encoding in encodings: | |
| try: | |
| with open(file_path, 'r', encoding=encoding) as file: | |
| return file.read().strip() | |
| except UnicodeDecodeError: | |
| continue | |
| raise Exception("Unable to decode text file with supported encodings.") | |
| except Exception as e: | |
| raise Exception(f"Error reading text file: {str(e)}") | |
| def process_file(self, file_path: str) -> str: | |
| """Process uploaded file and extract text.""" | |
| if not file_path: | |
| raise ValueError("No file provided") | |
| file_extension = os.path.splitext(file_path)[1].lower() | |
| if file_extension == '.pdf': | |
| return self.extract_text_from_pdf(file_path) | |
| elif file_extension == '.docx': | |
| return self.extract_text_from_docx(file_path) | |
| elif file_extension == '.txt': | |
| return self.extract_text_from_txt(file_path) | |
| else: | |
| raise ValueError(f"Unsupported file type: {file_extension}. Supported: PDF, DOCX, TXT") | |
| class OpenAuditApp: | |
| """OpenAudit AI - AI Content Detection Platform.""" | |
| def __init__(self): | |
| self.user = "deveshpunjabi" | |
| self.app_version = "1.0.0" | |
| self.init_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S UTC") | |
| self.doc_processor = DocumentProcessor() | |
| self.report_generator = SimpleReportGenerator(self.user) | |
| self.ai_detector = None | |
| self._initialize_detector() | |
| print("β OpenAudit AI initialized successfully") | |
| def _initialize_detector(self): | |
| """Initialize AI detector with error handling.""" | |
| try: | |
| if AI_DETECTOR_AVAILABLE: | |
| print("π§ Initializing AI Text Detector...") | |
| self.ai_detector = AITextDetector() | |
| print("β AI Text Detector ready") | |
| else: | |
| print("β οΈ AI Text Detector not available") | |
| except Exception as e: | |
| print(f"β AI detector initialization failed: {e}") | |
| self.ai_detector = None | |
| def create_app(self) -> gr.Blocks: | |
| """Create modern UI with clean design.""" | |
| custom_css = """ | |
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); | |
| :root { | |
| --primary: #0d9488; | |
| --secondary: #0ea5e9; | |
| --bg-light: #f8fafc; | |
| --bg-white: #ffffff; | |
| --text-dark: #1e293b; | |
| --text-gray: #64748b; | |
| --border: #e2e8f0; | |
| --success: #22c55e; | |
| --error: #ef4444; | |
| } | |
| * { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; } | |
| .gradio-container { background: var(--bg-light); } | |
| .header-section { | |
| background: var(--bg-white); | |
| border-radius: 16px; | |
| padding: 40px 32px; | |
| margin-bottom: 32px; | |
| border: 1px solid var(--border); | |
| box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); | |
| text-align: center; | |
| } | |
| .header-section h1 { | |
| font-size: 2.5rem; | |
| font-weight: 700; | |
| background: linear-gradient(135deg, var(--primary), var(--secondary)); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| margin: 0 0 12px 0; | |
| } | |
| .header-section p { | |
| color: var(--text-gray); | |
| font-size: 1.05rem; | |
| margin: 0; | |
| } | |
| .badges { | |
| display: flex; | |
| gap: 12px; | |
| justify-content: center; | |
| margin-top: 20px; | |
| flex-wrap: wrap; | |
| } | |
| .badge { | |
| background: var(--bg-light); | |
| padding: 8px 16px; | |
| border-radius: 8px; | |
| font-size: 0.9rem; | |
| color: var(--text-gray); | |
| border: 1px solid var(--border); | |
| } | |
| .status-card { | |
| background: var(--bg-white); | |
| border-radius: 16px; | |
| padding: 24px; | |
| margin-bottom: 24px; | |
| border: 1px solid var(--border); | |
| display: flex; | |
| align-items: center; | |
| gap: 16px; | |
| } | |
| .status-card.success { | |
| border-left: 4px solid var(--success); | |
| background: rgba(34, 197, 94, 0.02); | |
| } | |
| .status-card.error { | |
| border-left: 4px solid var(--error); | |
| background: rgba(239, 68, 68, 0.02); | |
| } | |
| .status-icon { | |
| font-size: 2rem; | |
| min-width: 40px; | |
| } | |
| .status-content h3 { | |
| margin: 0 0 8px 0; | |
| font-size: 1.1rem; | |
| color: var(--text-dark); | |
| } | |
| .status-content p { | |
| margin: 0; | |
| font-size: 0.95rem; | |
| color: var(--text-gray); | |
| } | |
| .card { | |
| background: var(--bg-white); | |
| border-radius: 16px; | |
| padding: 28px; | |
| border: 1px solid var(--border); | |
| box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); | |
| } | |
| .card h3 { | |
| margin: 0 0 20px 0; | |
| font-size: 1.2rem; | |
| color: var(--text-dark); | |
| } | |
| .textarea-wrapper textarea { | |
| border-radius: 12px !important; | |
| border: 1px solid var(--border) !important; | |
| background: var(--bg-white) !important; | |
| color: var(--text-dark) !important; | |
| font-size: 0.95rem !important; | |
| padding: 14px !important; | |
| transition: all 0.2s !important; | |
| } | |
| .textarea-wrapper textarea:focus { | |
| border-color: var(--primary) !important; | |
| box-shadow: 0 0 0 3px rgba(13, 148, 136, 0.1) !important; | |
| } | |
| .button-group { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 12px; | |
| margin-top: 20px; | |
| } | |
| .btn-primary { | |
| background: linear-gradient(135deg, var(--primary), var(--secondary)) !important; | |
| border: none !important; | |
| border-radius: 10px !important; | |
| padding: 12px 20px !important; | |
| font-weight: 600 !important; | |
| color: white !important; | |
| transition: all 0.2s !important; | |
| cursor: pointer !important; | |
| } | |
| .btn-primary:hover { | |
| transform: translateY(-2px) !important; | |
| box-shadow: 0 4px 12px rgba(13, 148, 136, 0.3) !important; | |
| } | |
| .btn-secondary { | |
| background: var(--bg-light) !important; | |
| border: 1px solid var(--border) !important; | |
| border-radius: 10px !important; | |
| padding: 12px 20px !important; | |
| font-weight: 600 !important; | |
| color: var(--text-dark) !important; | |
| transition: all 0.2s !important; | |
| } | |
| .btn-secondary:hover { | |
| background: var(--bg-white) !important; | |
| } | |
| .result-card { | |
| background: var(--bg-white); | |
| border-radius: 16px; | |
| padding: 28px; | |
| margin-bottom: 20px; | |
| border: 1px solid var(--border); | |
| text-align: center; | |
| } | |
| .result-ai { | |
| border-top: 4px solid var(--error); | |
| } | |
| .result-human { | |
| border-top: 4px solid var(--success); | |
| } | |
| .result-icon { | |
| font-size: 3rem; | |
| margin-bottom: 16px; | |
| } | |
| .result-title { | |
| font-size: 1.5rem; | |
| font-weight: 700; | |
| margin: 0 0 20px 0; | |
| background: linear-gradient(135deg, var(--primary), var(--secondary)); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| } | |
| .stats-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); | |
| gap: 16px; | |
| margin: 24px 0; | |
| } | |
| .stat-box { | |
| background: var(--bg-light); | |
| border-radius: 12px; | |
| padding: 20px 16px; | |
| text-align: center; | |
| border: 1px solid var(--border); | |
| } | |
| .stat-value { | |
| font-size: 1.8rem; | |
| font-weight: 700; | |
| color: var(--primary); | |
| margin-bottom: 8px; | |
| } | |
| .stat-label { | |
| font-size: 0.85rem; | |
| color: var(--text-gray); | |
| font-weight: 500; | |
| } | |
| .progress-section { | |
| margin: 20px 0; | |
| } | |
| .progress-label { | |
| display: flex; | |
| justify-content: space-between; | |
| margin-bottom: 8px; | |
| font-weight: 500; | |
| font-size: 0.95rem; | |
| color: var(--text-dark); | |
| } | |
| .progress-bar { | |
| background: var(--bg-light); | |
| border-radius: 8px; | |
| height: 10px; | |
| overflow: hidden; | |
| } | |
| .progress-fill-ai { | |
| background: linear-gradient(90deg, var(--error), #f87171); | |
| height: 100%; | |
| border-radius: 8px; | |
| transition: width 1s ease-out; | |
| } | |
| .progress-fill-human { | |
| background: linear-gradient(90deg, var(--success), #4ade80); | |
| height: 100%; | |
| border-radius: 8px; | |
| transition: width 1s ease-out; | |
| } | |
| .info-box { | |
| background: var(--bg-light); | |
| border-left: 4px solid var(--primary); | |
| border-radius: 8px; | |
| padding: 16px; | |
| margin: 16px 0; | |
| font-size: 0.95rem; | |
| color: var(--text-gray); | |
| line-height: 1.6; | |
| } | |
| .text-report { | |
| background: var(--bg-light); | |
| border-radius: 12px; | |
| padding: 16px; | |
| font-family: 'Monaco', 'Courier New', monospace; | |
| font-size: 0.9rem; | |
| color: var(--text-dark); | |
| max-height: 400px; | |
| overflow-y: auto; | |
| } | |
| @media (max-width: 768px) { | |
| .header-section h1 { font-size: 1.8rem; } | |
| .button-group { grid-template-columns: 1fr; } | |
| .stats-grid { grid-template-columns: repeat(2, 1fr); } | |
| } | |
| """ | |
| with gr.Blocks( | |
| title="OpenAudit AI - AI Detection", | |
| theme=gr.themes.Soft(), | |
| css=custom_css | |
| ) as app: | |
| # Header | |
| gr.HTML(f""" | |
| <div class="header-section"> | |
| <h1>OpenAudit AI</h1> | |
| <p>Professional AI Content Detection</p> | |
| <div class="badges"> | |
| <span class="badge">π€ {self.user}</span> | |
| <span class="badge">v{self.app_version}</span> | |
| <span class="badge">π§ Advanced Detection</span> | |
| </div> | |
| </div> | |
| """) | |
| # Status | |
| if self.ai_detector: | |
| gr.HTML(""" | |
| <div class="status-card success"> | |
| <div class="status-icon">β </div> | |
| <div class="status-content"> | |
| <h3>System Active</h3> | |
| <p>AI detection system is ready for analysis</p> | |
| </div> | |
| </div> | |
| """) | |
| else: | |
| gr.HTML(""" | |
| <div class="status-card error"> | |
| <div class="status-icon">β</div> | |
| <div class="status-content"> | |
| <h3>System Unavailable</h3> | |
| <p>AI detection system is not available. Please check configuration.</p> | |
| </div> | |
| </div> | |
| """) | |
| # Main content | |
| with gr.Row(equal_height=False): | |
| with gr.Column(scale=3): | |
| gr.HTML('<div class="card">') | |
| gr.HTML('<h3>π Analyze Text</h3>') | |
| ai_text = gr.Textbox( | |
| label="", | |
| placeholder="Paste your text here...", | |
| lines=10, | |
| max_lines=20, | |
| interactive=bool(self.ai_detector), | |
| elem_classes="textarea-wrapper" | |
| ) | |
| ai_file = gr.File( | |
| label="π Upload Document (PDF, DOCX, TXT)", | |
| file_types=[".pdf", ".docx", ".txt"], | |
| type="filepath", | |
| interactive=bool(self.ai_detector) | |
| ) | |
| with gr.Row(): | |
| ai_analyze_btn = gr.Button( | |
| "π Analyze" if self.ai_detector else "β Unavailable", | |
| variant="primary", | |
| size="lg", | |
| interactive=bool(self.ai_detector), | |
| elem_classes="btn-primary" | |
| ) | |
| ai_clear_btn = gr.Button( | |
| "ποΈ Clear", | |
| variant="secondary", | |
| size="lg", | |
| elem_classes="btn-secondary" | |
| ) | |
| gr.HTML('</div>') | |
| with gr.Column(scale=1): | |
| gr.HTML(""" | |
| <div class="card"> | |
| <h3>βΉοΈ About</h3> | |
| <div class="info-box" style="border-left: 4px solid var(--primary); margin: 0; padding: 0; background: transparent;"> | |
| <strong style="color: var(--text-dark);">Features:</strong><br> | |
| β’ Advanced AI detection<br> | |
| β’ Multi-format support<br> | |
| β’ Detailed reports<br> | |
| β’ Real-time analysis | |
| </div> | |
| </div> | |
| """) | |
| # Results section | |
| with gr.Group(visible=False) as results_section: | |
| gr.HTML("<h2 style='margin: 30px 0 20px 0; font-size: 1.4rem;'>π Analysis Results</h2>") | |
| result_display = gr.HTML() | |
| with gr.Row(): | |
| with gr.Column(): | |
| statistics_display = gr.HTML() | |
| with gr.Column(): | |
| confidence_display = gr.HTML() | |
| detailed_analysis = gr.Textbox( | |
| label="π Report", | |
| lines=12, | |
| interactive=False, | |
| show_copy_button=True, | |
| elem_classes="text-report" | |
| ) | |
| download_report = gr.File( | |
| label="π₯ Download Report", | |
| visible=False | |
| ) | |
| # Event handlers | |
| def handle_file_upload(file_obj): | |
| """Handle file upload and extraction.""" | |
| if not file_obj: | |
| return "", gr.update(value=None) | |
| try: | |
| text = self.doc_processor.process_file(file_obj.name) | |
| return text, gr.update(value=None) | |
| except Exception as e: | |
| gr.Warning(f"File error: {str(e)}") | |
| return "", gr.update(value=None) | |
| def analyze_content(text, file_obj): | |
| """Analyze content for AI generation.""" | |
| start_time = time.time() | |
| # Extract from file if provided | |
| if file_obj and not text.strip(): | |
| try: | |
| text = self.doc_processor.process_file(file_obj.name) | |
| except Exception as e: | |
| error_html = f""" | |
| <div class="result-card result-ai"> | |
| <div class="result-icon">β</div> | |
| <h3 style="color: var(--error); margin: 0;">Error</h3> | |
| <p style="color: var(--text-gray); margin: 10px 0 0 0;">{str(e)}</p> | |
| </div> | |
| """ | |
| return (gr.update(value=error_html), "", "", "", gr.update(visible=True), gr.update(visible=False)) | |
| if not text.strip(): | |
| gr.Warning("Please provide text or upload a file") | |
| return ("", "", "", "", gr.update(visible=False), gr.update(visible=False)) | |
| if not self.ai_detector: | |
| error_html = """ | |
| <div class="result-card result-ai"> | |
| <div class="result-icon">β</div> | |
| <h3 style="color: var(--error); margin: 0;">System Unavailable</h3> | |
| </div> | |
| """ | |
| return (gr.update(value=error_html), "", "", "", gr.update(visible=True), gr.update(visible=False)) | |
| try: | |
| # Run analysis | |
| result = self.ai_detector.analyze_text(text) | |
| is_ai = result.get('isAI', False) | |
| confidence = result.get('confidence', 75) | |
| ai_prob = result.get('aiProb', 50) | |
| human_prob = result.get('humanProb', 50) | |
| model = result.get('mostLikelyModel', 'Unknown') | |
| analysis = result.get('analysis', 'Analysis complete.') | |
| method = result.get('detectionMethod', 'Advanced Analysis') | |
| processing_time = time.time() - start_time | |
| result['processingTime'] = processing_time | |
| # Result display | |
| icon = "π€" if is_ai else "π€" | |
| title = "AI-Generated Content" if is_ai else "Human-Written Content" | |
| card_class = "result-ai" if is_ai else "result-human" | |
| result_html = f""" | |
| <div class="result-card {card_class}"> | |
| <div class="result-icon">{icon}</div> | |
| <h2 class="result-title">{title}</h2> | |
| <div class="stats-grid"> | |
| <div class="stat-box"> | |
| <div class="stat-value">{confidence:.1f}%</div> | |
| <div class="stat-label">Confidence</div> | |
| </div> | |
| <div class="stat-box"> | |
| <div class="stat-value">{model}</div> | |
| <div class="stat-label">Model</div> | |
| </div> | |
| <div class="stat-box"> | |
| <div class="stat-value">{processing_time:.2f}s</div> | |
| <div class="stat-label">Time</div> | |
| </div> | |
| <div class="stat-box"> | |
| <div class="stat-value">{len(text.split()):,}</div> | |
| <div class="stat-label">Words</div> | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| # Statistics | |
| stats_html = f""" | |
| <div class="card"> | |
| <h3>π Probabilities</h3> | |
| <div class="progress-section"> | |
| <div class="progress-label"> | |
| <span>π€ AI Probability</span> | |
| <span>{ai_prob:.1f}%</span> | |
| </div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill-ai" style="width: {ai_prob}%;"></div> | |
| </div> | |
| </div> | |
| <div class="progress-section"> | |
| <div class="progress-label"> | |
| <span>π€ Human Probability</span> | |
| <span>{human_prob:.1f}%</span> | |
| </div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill-human" style="width: {human_prob}%;"></div> | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| # Confidence details | |
| word_count = len(text.split()) | |
| avg_word_len = (len(text) / word_count) if word_count > 0 else 0.0 | |
| confidence_html = f""" | |
| <div class="card"> | |
| <h3>π Details</h3> | |
| <div class="info-box"> | |
| <strong>Method:</strong> {method} | |
| </div> | |
| <div class="info-box"> | |
| <strong>Words:</strong> {word_count:,}<br> | |
| <strong>Characters:</strong> {len(text):,}<br> | |
| <strong>Avg Word Length:</strong> {avg_word_len:.1f} | |
| </div> | |
| </div> | |
| """ | |
| # Report | |
| timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S UTC') | |
| report_content = self.report_generator.generate_ai_report(text, result, timestamp) | |
| # Save report to temp file | |
| report_path = None | |
| try: | |
| temp_file = tempfile.NamedTemporaryFile( | |
| mode='w', | |
| encoding='utf-8', | |
| delete=False, | |
| suffix='.txt', | |
| prefix='ai_report_' | |
| ) | |
| temp_file.write(report_content) | |
| temp_file.close() | |
| report_path = temp_file.name | |
| except Exception as e: | |
| print(f"β οΈ Report file error: {e}") | |
| return ( | |
| gr.update(value=result_html), | |
| gr.update(value=stats_html), | |
| gr.update(value=confidence_html), | |
| gr.update(value=report_content), | |
| gr.update(visible=True), | |
| gr.update(value=report_path, visible=bool(report_path)) | |
| ) | |
| except Exception as e: | |
| processing_time = time.time() - start_time | |
| error_html = f""" | |
| <div class="result-card result-ai"> | |
| <div class="result-icon">β</div> | |
| <h3 style="color: var(--error); margin: 0;">Analysis Failed</h3> | |
| <p style="color: var(--text-gray); margin: 10px 0 0 0;">{str(e)}</p> | |
| <p style="color: var(--text-gray); font-size: 0.9rem;">{processing_time:.2f}s</p> | |
| </div> | |
| """ | |
| return ( | |
| gr.update(value=error_html), | |
| gr.update(value=""), | |
| gr.update(value=""), | |
| gr.update(value=f"Error: {str(e)}"), | |
| gr.update(visible=True), | |
| gr.update(visible=False) | |
| ) | |
| def clear_results(): | |
| """Clear all results and inputs.""" | |
| return ( | |
| gr.update(value=""), | |
| gr.update(value=""), | |
| gr.update(value=""), | |
| gr.update(value=""), | |
| gr.update(value=""), | |
| gr.update(value=None), | |
| gr.update(visible=False), | |
| gr.update(value=None, visible=False) | |
| ) | |
| # Connect events | |
| if self.ai_detector: | |
| ai_file.change( | |
| handle_file_upload, | |
| inputs=[ai_file], | |
| outputs=[ai_text, ai_file] | |
| ) | |
| ai_analyze_btn.click( | |
| analyze_content, | |
| inputs=[ai_text, ai_file], | |
| outputs=[ | |
| result_display, | |
| statistics_display, | |
| confidence_display, | |
| detailed_analysis, | |
| results_section, | |
| download_report | |
| ], | |
| show_progress="full" | |
| ) | |
| ai_clear_btn.click( | |
| clear_results, | |
| outputs=[ | |
| result_display, | |
| statistics_display, | |
| confidence_display, | |
| detailed_analysis, | |
| ai_text, | |
| ai_file, | |
| results_section, | |
| download_report | |
| ] | |
| ) | |
| return app | |
| def main(): | |
| """Main application entry point.""" | |
| print("\n" + "=" * 70) | |
| print("π€ OPENAUDIT AI - AI CONTENT DETECTION PLATFORM") | |
| print("=" * 70) | |
| print(f"π€ User: deveshpunjabi") | |
| print(f"π Version: 1.0.0") | |
| print(f"π¨ UI: Modern & Clean Design") | |
| print("=" * 70 + "\n") | |
| try: | |
| print("π§ Initializing application...") | |
| app_instance = OpenAuditApp() | |
| print("π¨ Creating interface...") | |
| app = app_instance.create_app() | |
| print("\n" + "=" * 70) | |
| print("π LAUNCHING APPLICATION") | |
| print("=" * 70) | |
| print("π‘ Server: 0.0.0.0:7860") | |
| print("β¨ Ready for analysis!") | |
| print("=" * 70 + "\n") | |
| app.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=True, | |
| show_error=True, | |
| quiet=False | |
| ) | |
| except Exception as e: | |
| print("\n" + "=" * 70) | |
| print("β STARTUP ERROR") | |
| print("=" * 70) | |
| print(f"Error: {str(e)}") | |
| print("=" * 70 + "\n") | |
| import traceback | |
| traceback.print_exc() | |
| if __name__ == "__main__": | |
| main() |