Spaces:
Sleeping
Sleeping
import gradio as gr | |
import logging | |
import traceback | |
import time | |
import re | |
import os | |
from functools import wraps, lru_cache | |
from dotenv import load_dotenv | |
from urllib.parse import urlparse | |
# Load environment variables | |
load_dotenv() | |
# Enhanced logging configuration | |
logging.basicConfig( | |
level=logging.INFO, | |
format='%(asctime)s - %(levelname)s - %(message)s', | |
handlers=[ | |
logging.FileHandler('centurion_platform.log', encoding='utf-8', mode='a'), | |
logging.StreamHandler() | |
] | |
) | |
logger = logging.getLogger(__name__) | |
# CSS Configuration | |
css = """ | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
} | |
body { | |
background-color: #ffffff; | |
color: #000000; | |
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; | |
} | |
.header { | |
background: #ffffff; | |
border-bottom: 1px solid #e5e5e5; | |
padding: 1rem 2rem; | |
display: flex; | |
align-items: center; | |
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); | |
} | |
.logo { | |
width: 45px; | |
height: 45px; | |
margin-right: 15px; | |
transition: transform 0.3s ease; | |
} | |
.header-title { | |
color: #000000; | |
font-size: 24px; | |
font-weight: 600; | |
} | |
.container { | |
max-width: 1400px; | |
margin: 0 auto; | |
padding: 2rem; | |
background: #ffffff; | |
} | |
.main-content { | |
background: #ffffff; | |
border-radius: 12px; | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
margin: 2rem 0; | |
overflow: hidden; | |
border: 1px solid #e5e5e5; | |
} | |
.iframe-container { | |
position: relative; | |
width: 100%; | |
height: 0; | |
padding-bottom: 65%; | |
background: #ffffff; | |
} | |
.iframe-container iframe { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
border: none; | |
} | |
.nav-grid { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); | |
gap: 1.5rem; | |
margin-top: 2rem; | |
} | |
.nav-card { | |
background: #ffffff; | |
border: 1px solid #e5e5e5; | |
border-radius: 10px; | |
padding: 1.5rem; | |
transition: all 0.3s ease; | |
} | |
@media (max-width: 768px) { | |
.nav-grid { | |
grid-template-columns: 1fr; | |
} | |
} | |
""" | |
# Performance and security decorators | |
def performance_monitor(func): | |
def wrapper(*args, **kwargs): | |
start = time.time() | |
try: | |
result = func(*args, **kwargs) | |
execution_time = time.time() - start | |
logger.info(f"{func.__name__} execution time: {execution_time:.2f} seconds") | |
return result | |
except Exception as e: | |
logger.error(f"Error in {func.__name__}: {e}") | |
logger.error(traceback.format_exc()) | |
raise | |
return wrapper | |
# URL Validation and Sanitization | |
def validate_and_sanitize_url(url): | |
""" | |
Comprehensive URL validation and sanitization | |
""" | |
try: | |
# Validate URL pattern | |
url_pattern = re.compile( | |
r'^https?://' # http:// or https:// | |
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' # domain... | |
r'localhost|' # localhost... | |
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip | |
r'(?::\d+)?' # optional port | |
r'(?:/?|[/?]\S+)$', re.IGNORECASE) | |
if not url_pattern.match(url): | |
logger.warning(f"Invalid URL format: {url}") | |
return None | |
# Parse and validate URL | |
parsed_url = urlparse(url) | |
# Whitelist allowed domains | |
allowed_domains = [ | |
'noumanjavaid-new-space.hf.space', | |
'noumanjavaid-centurionv2.hf.space', | |
'noumanjavaid-watermark-demo-video.hf.space', | |
'noumanjavaid-centii.hf.space', | |
'localhost' | |
] | |
if parsed_url.netloc not in allowed_domains: | |
logger.warning(f"Unauthorized domain: {parsed_url.netloc}") | |
return None | |
return url | |
except Exception as e: | |
logger.error(f"URL validation error: {e}") | |
return None | |
# Platform Configuration | |
PLATFORM_CONFIG = { | |
'main_platform_url': os.getenv('MAIN_PLATFORM_URL', 'https://noumanjavaid-centii.hf.space'), | |
'launch_config': { | |
'show_error': True, | |
'show_api': False, | |
'show_tips': False, | |
'height': 800, | |
'analytics_enabled': False, | |
'enable_queue': False, | |
'prevent_thread_lock': True | |
} | |
} | |
# Error Notification (Optional) | |
def send_error_notification(error): | |
""" | |
Send error notifications via external service | |
""" | |
try: | |
import requests | |
webhook_url = os.getenv('ERROR_WEBHOOK_URL') | |
if webhook_url: | |
payload = { | |
"text": f"π¨ Centurion Platform Error: {str(error)}", | |
"blocks": [ | |
{ | |
"type": "section", | |
"text": { | |
"type": "mrkdwn", | |
"text": f"```{traceback.format_exc()}```" | |
} | |
} | |
] | |
} | |
requests.post(webhook_url, json=payload) | |
except Exception as log_error: | |
logger.error(f"Error sending notification: {log_error}") | |
# Configuration Validation | |
def validate_configuration(demo): | |
""" | |
Validate Gradio demo configuration | |
""" | |
required_attributes = [ | |
'title', | |
'css', | |
'show_error', | |
'show_api', | |
'show_tips', | |
'height', | |
'analytics_enabled', | |
'enable_queue' | |
] | |
validation_results = {} | |
for attr in required_attributes: | |
try: | |
value = getattr(demo, attr, None) | |
validation_results[attr] = value is not None | |
except Exception as e: | |
logger.error(f"Error validating {attr}: {e}") | |
validation_results[attr] = False | |
return validation_results | |
def create_demo(): | |
""" | |
Create Gradio demo with comprehensive validation | |
""" | |
# Navigation Cards with URL Validation | |
cards = [ | |
{ | |
"icon": "π", | |
"title": "DeepFake Detection", | |
"url": validate_and_sanitize_url(os.getenv('DEEPFAKE_URL', 'https://noumanjavaid-new-space.hf.space')) | |
}, | |
{ | |
"icon": "π", | |
"title": "Document Analysis", "url": validate_and_sanitize_url(os.getenv('DOCUMENT_URL', 'https://noumanjavaid-centurionv2.hf.space')) | |
}, | |
{ | |
"icon": "π₯", | |
"title": "Video Watermarking", | |
"url": validate_and_sanitize_url(os.getenv('WATERMARK_URL', 'https://noumanjavaid-watermark-demo-video.hf.space')) | |
}, | |
{ | |
"icon": "π", | |
"title": "Image Authentication", | |
"url": validate_and_sanitize_url(os.getenv('AUTH_URL', 'https://noumanjavaid-centii.hf.space')) | |
}, | |
] | |
# Validate navigation cards | |
invalid_cards = [card for card in cards if card['url'] is None] | |
if invalid_cards: | |
logger.warning(f"Invalid navigation card URLs: {invalid_cards}") | |
# Generate HTML for navigation cards | |
html_cards = "".join( | |
f''' | |
<div class="nav-card" role="navigation" aria-label="{card['title']}" tabindex="0"> | |
<a href="{card['url']}" target="_blank" rel="noopener noreferrer"> | |
{card['icon']} {card['title']} | |
</a> | |
</div> | |
''' for card in cards if card['url'] is not None | |
) | |
# Create Gradio block | |
with gr.Blocks(css=css, title="Centurion Analysis Platform") as demo: | |
# Header | |
with gr.Row(elem_classes=["header"]): | |
gr.Image( | |
"https://raw.githubusercontent.com/noumanjavaid96/ai-as-an-api/refs/heads/master/image%20(39).png", | |
elem_classes=["logo"], | |
show_label=False, | |
container=False | |
) | |
gr.Markdown("Centurion Analysis", elem_classes=["header-title"]) | |
# Main content | |
with gr.Row(elem_classes=["container"]): | |
with gr.Column(elem_classes=["main-content"]): | |
gr.HTML(f''' | |
<div class="iframe-container"> | |
<iframe | |
src="{PLATFORM_CONFIG['main_platform_url']}" | |
loading="lazy" | |
title="Centurion Main Platform" | |
></iframe> | |
</div> | |
''') | |
# Navigation grid | |
with gr.Row(elem_classes=["nav-grid"]): | |
gr.HTML(html_cards) | |
return demo | |
def main(): | |
try: | |
demo = create_demo() | |
# Validate configuration before launching | |
config_validation = validate_configuration(demo) | |
logger.info(f"Configuration Validation: {config_validation}") | |
validation_errors = [k for k, v in config_validation.items() if not v] | |
if validation_errors: | |
logger.error(f"Configuration validation failed for: {validation_errors}") | |
raise ValueError(f"Invalid configuration: {validation_errors}") | |
demo.launch(**PLATFORM_CONFIG['launch_config']) | |
except Exception as e: | |
logger.critical(f"Application launch failed: {e}") | |
logger.critical(traceback.format_exc()) | |
send_error_notification(e) | |
if __name__ == "__main__": | |
main() |