import os import sys import io import warnings # 1. Environment & Protobuf Fixes (Must be at the absolute top) try: import google.protobuf.runtime_version as rv rv.ValidateProtobufRuntimeVersion = lambda *args, **kwargs: None except (ImportError, AttributeError): pass os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3" os.environ["TF_ENABLE_ONEDNN_OPTS"] = "0" os.environ["PYTHONUTF8"] = "1" os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "python" warnings.filterwarnings("ignore", category=FutureWarning) warnings.filterwarnings("ignore", message=".*The name tf.losses.*") warnings.filterwarnings("ignore", message=".*use_fast is unset.*") warnings.filterwarnings("ignore", message=".*does not have a fast version.*") warnings.filterwarnings("ignore", message=".*Multiple distributions found for package optimum.*") # 1.1 DLL Bypass: Block broken torchaudio at sys.modules level (WinError 127 fix) # The AST feature extractor does `import torchaudio.compliance.kaldi` at module scope. # On this Windows system, torchaudio's native DLL is broken. We insert dummy modules # into sys.modules so the import succeeds silently, then tell transformers that # torchaudio/speech is unavailable so it uses its built-in numpy fallback instead. import types import importlib.machinery as _ilm def _block_torchaudio(): """Prevent broken torchaudio DLL from crashing the process.""" _dummy = types.ModuleType("torchaudio") _dummy.__version__ = "0.0.0" _dummy.__path__ = [] _dummy.__file__ = "blocked_by_fakeshield" _dummy.__loader__ = None _dummy.__package__ = "torchaudio" _dummy.__spec__ = _ilm.ModuleSpec("torchaudio", None, origin="blocked") sys.modules["torchaudio"] = _dummy for _sub in [ "torchaudio.functional", "torchaudio.transforms", "torchaudio.compliance", "torchaudio.compliance.kaldi", "torchaudio.sox_effects", "torchaudio.backend", "torchaudio._extension", "torchaudio._extension.utils", ]: _m = types.ModuleType(_sub) _m.__spec__ = _ilm.ModuleSpec(_sub, None, origin="blocked") _m.__path__ = [] _m.__package__ = _sub.rsplit(".", 1)[0] sys.modules[_sub] = _m # DLL Bypass: Attempt to import torchaudio. If it fails with a DLL error, apply the block. try: import torchaudio except OSError: _block_torchaudio() # Patch transformers availability checks so AST uses numpy mel-filterbank path try: import transformers.utils.import_utils as _tf_import_utils _tf_import_utils.is_torchaudio_available = lambda: False _tf_import_utils._torchaudio_available = False # is_speech_available checks torchaudio ΓÇö must also be False if hasattr(_tf_import_utils, "is_speech_available"): _tf_import_utils.is_speech_available = lambda: False except Exception: pass # 2. Force UTF-8 encoding for Windows terminals if sys.platform == "win32": try: sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8') except Exception: pass def robust_print(msg, **kwargs): """Prints message while handling potential UnicodeEncodeErrors on legacy terminals.""" try: print(msg, **kwargs) except UnicodeEncodeError: # Fallback: strip non-ascii clean_msg = msg.encode('ascii', 'ignore').decode('ascii') print(clean_msg, **kwargs) # 3. Suppress Heavy Logging from AI Libraries import transformers transformers.logging.set_verbosity_error() from dotenv import load_dotenv load_dotenv() import os import importlib import importlib.metadata # importlib.metadata (already handled) import sys def _patch_metadata(mod): _orig_version = mod.version def _patched_version(pkg_name): try: v = _orig_version(pkg_name) if v: return v except Exception: pass name = pkg_name.lower() if name == "torch": try: import torch return torch.__version__.split('+')[0] except Exception: return "2.2.1" if name == "transformers": return "4.38.2" if name == "protobuf": return "4.25.3" return "1.0.0" mod.version = _patched_version _patch_metadata(importlib.metadata) # Also patch importlib_metadata backport if it exists try: import importlib_metadata _patch_metadata(importlib_metadata) except ImportError: pass from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.routers.text_router import router as text_router from app.routers.image_router import router as image_router from app.routers.video_router import router as video_router from app.routers.audio_router import router as audio_router from app.routers.auth_router import router as auth_router from app.routers.dashboard_router import router as dashboard_router from app.routers.legacy_router import router as legacy_router # Forensic warm-up functions moved to background task to prevent startup hangs # (Imports moved inside the task below) app = FastAPI( title="FakeShield API", description="Industry-level multimodal deepfake detection", version="2.0.0", docs_url="/docs", redoc_url="/redoc" ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.include_router(text_router) app.include_router(image_router) app.include_router(video_router, prefix="/api/v1") app.include_router(audio_router, prefix="/api/v1") app.include_router(auth_router) app.include_router(dashboard_router) app.include_router(legacy_router) import asyncio @app.on_event("startup") async def startup_event(): from app.database import init_db try: await init_db() except Exception as e: robust_print(f"[DB] Database initialization failed: {e}") robust_print("[DB] Proceeding in OFFLINE mode (history and users will be unavailable).") robust_print("[START] Initializing FakeShield Engine (Background Warmup Enabled)...", flush=True) async def run_universal_warmup(): """Pre-loads all forensic labs in background to ensure zero-latency navigation.""" if os.environ.get("FAKESHIELD_SKIP_WARMUP") == "1": robust_print("[WARMUP] Skipped by environment flag.") return # 1. Text Lab (v16 Elite) try: from app.models.new_forensic_engine import load_models as load_text_models robust_print("[WARMUP] [1/3] Pre-loading Text Forensic Suite...", flush=True) await asyncio.to_thread(load_text_models) robust_print("[WARMUP] Text Lab ready.", flush=True) except Exception as e: robust_print(f"[WARMUP] Text load error: {e}") # 2. Image Lab (DINOv2 + ViT Ensemble) try: from app.models.image_detector import load_image_models robust_print("[WARMUP] [2/3] Pre-loading Image Forensic Suite...", flush=True) await asyncio.to_thread(load_image_models) robust_print("[WARMUP] Image Lab ready.", flush=True) except Exception as e: robust_print(f"[WARMUP] Image load error: {e}") # 3. Audio Lab (WavLM ITW) try: from app.models.audio.signal_wavlm import _load_model as load_wavlm robust_print("[WARMUP] [3/3] Pre-loading Audio Forensic Suite...", flush=True) await asyncio.to_thread(load_wavlm) robust_print("[WARMUP] Audio Lab ready.", flush=True) except Exception as e: robust_print(f"[WARMUP] Audio load error: {e}") robust_print("="*50) robust_print("--- [ALL ENGINES WARMED UP] ---") robust_print("="*50) # Launch universal warmup in background asyncio.create_task(run_universal_warmup()) # DEBUG: print all registered routes for troubleshooting try: robust_print("[ROUTES] Registered FastAPI routes:") try: openapi_paths = app.openapi().get("paths", {}).keys() for path in sorted(openapi_paths): robust_print(f"[OPENAPI] path={path}") except Exception as e: robust_print(f"[OPENAPI] path listing failed: {e}") def print_route(route): try: if hasattr(route, 'routes') and getattr(route, 'routes'): for child in route.routes: print_route(child) else: methods = ",".join(sorted(list(route.methods))) if hasattr(route, 'methods') and route.methods else '' robust_print(f"[ROUTE] path={getattr(route, 'path', str(route))} name={getattr(route, 'name', '')} methods={methods}") except Exception as e: robust_print(f"[ROUTE] path={getattr(route, 'path', str(route))} name={getattr(route, 'name', '')} methods=UNKNOWN error={e}") for r in app.routes: print_route(r) except Exception as e: robust_print(f"[ROUTES] debug failed: {e}") port = int(os.environ.get("PORT", os.environ.get("API_PORT", "7860"))) robust_print("-" * 50, flush=True) robust_print(f"FakeShield API is now ONLINE and listening on port {port}.", flush=True) robust_print("-" * 50, flush=True) @app.get("/") def root(): return { "project": "FakeShield", "version": "2.0.0", "docs": "/docs", "panels": ["text", "image", "audio", "video"] } if __name__ == "__main__": import uvicorn port = int(os.environ.get("PORT", os.environ.get("API_PORT", "7860"))) uvicorn.run(app, host="0.0.0.0", port=port)