Pujan-Dev commited on
Commit
df1b2ad
·
1 Parent(s): 0fc632b

fixed the auth issue

Browse files
config.py CHANGED
@@ -26,6 +26,14 @@ class Config:
26
  REAL_FORGED_MODEL_REPO_ID = os.getenv("REAL_FORGED_MODEL_REPO_ID", "rhnsa/real_forged_classifier")
27
  REAL_FORGED_MODEL_FILENAME = os.getenv("REAL_FORGED_MODEL_FILENAME", "fft_cnn_model_78.pth")
28
  REAL_FORGED_MODEL_LOCAL_PATH = os.getenv("REAL_FORGED_MODEL_LOCAL_PATH", "Model/real_forged/fft_cnn_model_78.pth")
 
 
 
 
 
 
 
 
29
  DOCUMENT_FORGERY_MODEL_PATH = os.getenv(
30
  "DOCUMENT_FORGERY_MODEL_PATH",
31
  "features/Model/document_forgery/pixel_forgery_v3_best.pth",
 
26
  REAL_FORGED_MODEL_REPO_ID = os.getenv("REAL_FORGED_MODEL_REPO_ID", "rhnsa/real_forged_classifier")
27
  REAL_FORGED_MODEL_FILENAME = os.getenv("REAL_FORGED_MODEL_FILENAME", "fft_cnn_model_78.pth")
28
  REAL_FORGED_MODEL_LOCAL_PATH = os.getenv("REAL_FORGED_MODEL_LOCAL_PATH", "Model/real_forged/fft_cnn_model_78.pth")
29
+ DOCUMENT_FORGERY_MODEL_REPO_ID = os.getenv(
30
+ "DOCUMENT_FORGERY_MODEL_REPO_ID",
31
+ IMAGE_CLASSIFIER_REPO_ID
32
+ )
33
+ DOCUMENT_FORGERY_MODEL_FILENAME = os.getenv(
34
+ "DOCUMENT_FORGERY_MODEL_FILENAME",
35
+ "features/Model/document_forgery/pixel_forgery_v3_best.pth",
36
+ )
37
  DOCUMENT_FORGERY_MODEL_PATH = os.getenv(
38
  "DOCUMENT_FORGERY_MODEL_PATH",
39
  "features/Model/document_forgery/pixel_forgery_v3_best.pth",
features/{Model → Modelsdfa}/English_model/feature_names.json RENAMED
File without changes
features/{Model → Modelsdfa}/English_model/metadata.json RENAMED
File without changes
features/real_forged_classifier/controller.py CHANGED
@@ -2,6 +2,8 @@ from typing import IO
2
  import io
3
  import numpy as np
4
  from PIL import Image
 
 
5
  import torch
6
  from torchvision import transforms
7
 
@@ -10,6 +12,19 @@ from .inferencer import interferencer
10
  from .model_loader import models
11
  from config import Config
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  class ClassificationController:
15
  """
@@ -52,14 +67,14 @@ class documentForger:
52
  def is_forged(self, document_file: IO) -> dict:
53
  # Ensure a document model is loaded
54
  if not hasattr(models, 'doc_model') or models.doc_model is None:
55
- return {"error": "Document forgery model not available."}
56
 
57
  # Read file bytes
58
  try:
59
  data = document_file.read()
60
  img = Image.open(io.BytesIO(data)).convert('RGB')
61
  except Exception as e:
62
- return {"error": f"Could not open document image: {e}"}
63
 
64
  # Compute ELA map (same approach as the notebook)
65
  try:
@@ -77,7 +92,7 @@ class documentForger:
77
 
78
  ela_pil = Image.fromarray(ela_arr, mode='RGB')
79
  except Exception as e:
80
- return {"error": f"Failed to compute ELA: {e}"}
81
 
82
  # Transform and run through model
83
  transform = transforms.Compose([
 
2
  import io
3
  import numpy as np
4
  from PIL import Image
5
+ from fastapi import Depends, HTTPException, status
6
+ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
7
  import torch
8
  from torchvision import transforms
9
 
 
12
  from .model_loader import models
13
  from config import Config
14
 
15
+ security = HTTPBearer()
16
+
17
+
18
+ async def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
19
+ token = credentials.credentials
20
+ expected_token = Config.SECRET_TOKEN
21
+ if token != expected_token:
22
+ raise HTTPException(
23
+ status_code=status.HTTP_403_FORBIDDEN,
24
+ detail="Invalid or expired token",
25
+ )
26
+ return token
27
+
28
 
29
  class ClassificationController:
30
  """
 
67
  def is_forged(self, document_file: IO) -> dict:
68
  # Ensure a document model is loaded
69
  if not hasattr(models, 'doc_model') or models.doc_model is None:
70
+ return {"detail": "Document forgery model not available."}
71
 
72
  # Read file bytes
73
  try:
74
  data = document_file.read()
75
  img = Image.open(io.BytesIO(data)).convert('RGB')
76
  except Exception as e:
77
+ return {"detail": f"Could not open document image: {e}"}
78
 
79
  # Compute ELA map (same approach as the notebook)
80
  try:
 
92
 
93
  ela_pil = Image.fromarray(ela_arr, mode='RGB')
94
  except Exception as e:
95
+ return {"detail": f"Failed to compute ELA: {e}"}
96
 
97
  # Transform and run through model
98
  transform = transforms.Compose([
features/real_forged_classifier/model_loader.py CHANGED
@@ -1,8 +1,14 @@
1
  from pathlib import Path
2
  from typing import Any
 
3
  from .model import FFTCNN # Import the FFT CNN architecture (package-relative)
4
  from config import Config
5
 
 
 
 
 
 
6
 
7
  # NOTE: EfficientNet/nn imports are done lazily when torch is available.
8
  ELAForgeryNet = None # will be constructed dynamically when needed
@@ -63,7 +69,7 @@ class ModelLoader:
63
  else:
64
  print("Skipping FFT model load because PyTorch is not installed.")
65
 
66
- # Load document forgery model (ELA CNN) from local path if present
67
  self.doc_model = None
68
  if doc_model_path is None:
69
  doc_model_path = Config.DOCUMENT_FORGERY_MODEL_PATH
@@ -109,22 +115,25 @@ class ModelLoader:
109
  if not path.exists():
110
  print(f"Document forgery model file not found at configured path: {path}")
111
 
112
- # 1) Try features/Model/document_forgery/ela_cnn_model.pth relative to repo root
113
  repo_root = Path(__file__).resolve().parents[2]
114
- candidate = repo_root / 'features' / 'Model' / 'document_forgery' / 'ela_cnn_model.pth'
115
  if candidate.exists():
116
  path = candidate
117
  print(f"Found document forgery model at fallback path: {path}")
118
  else:
119
- # 2) Search the repo for any file named ela_cnn_model.pth
120
- print("Searching repository for 'ela_cnn_model.pth'...")
121
- matches = list(repo_root.rglob('ela_cnn_model.pth'))
122
  if matches:
123
  path = matches[0]
124
  print(f"Found document forgery model at: {path}")
125
  else:
126
- print("Document forgery model not found in repository; skipping load.")
127
- return None
 
 
 
128
 
129
  print(f"Loading document forgery model from: {path}")
130
  # Build the ELA model architecture lazily (requires torchvision & torch.nn)
@@ -158,6 +167,32 @@ class ModelLoader:
158
  model.eval()
159
  return model
160
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
 
162
  # --- Global Model Instance ---
163
  MODEL_REPO_ID = Config.REAL_FORGED_MODEL_REPO_ID
 
1
  from pathlib import Path
2
  from typing import Any
3
+ import shutil
4
  from .model import FFTCNN # Import the FFT CNN architecture (package-relative)
5
  from config import Config
6
 
7
+ try:
8
+ from huggingface_hub import hf_hub_download
9
+ except Exception:
10
+ hf_hub_download = None
11
+
12
 
13
  # NOTE: EfficientNet/nn imports are done lazily when torch is available.
14
  ELAForgeryNet = None # will be constructed dynamically when needed
 
69
  else:
70
  print("Skipping FFT model load because PyTorch is not installed.")
71
 
72
+ # Load document forgery model (ELA CNN), downloading the checkpoint if needed.
73
  self.doc_model = None
74
  if doc_model_path is None:
75
  doc_model_path = Config.DOCUMENT_FORGERY_MODEL_PATH
 
115
  if not path.exists():
116
  print(f"Document forgery model file not found at configured path: {path}")
117
 
118
+ # 1) Try the configured document forgery checkpoint path relative to repo root
119
  repo_root = Path(__file__).resolve().parents[2]
120
+ candidate = repo_root / 'features' / 'Model' / 'document_forgery' / path.name
121
  if candidate.exists():
122
  path = candidate
123
  print(f"Found document forgery model at fallback path: {path}")
124
  else:
125
+ # 2) Search the repo for any file with the configured checkpoint name
126
+ print(f"Searching repository for '{path.name}'...")
127
+ matches = list(repo_root.rglob(path.name))
128
  if matches:
129
  path = matches[0]
130
  print(f"Found document forgery model at: {path}")
131
  else:
132
+ try:
133
+ path = self._download_document_forgery_model(path)
134
+ except Exception as exc:
135
+ print(f"Document forgery model not found in repository and download failed: {exc}")
136
+ return None
137
 
138
  print(f"Loading document forgery model from: {path}")
139
  # Build the ELA model architecture lazily (requires torchvision & torch.nn)
 
167
  model.eval()
168
  return model
169
 
170
+ def _download_document_forgery_model(self, target_path: Path) -> Path:
171
+ """Download the document forgery checkpoint into the configured local path."""
172
+ if hf_hub_download is None:
173
+ raise RuntimeError("huggingface_hub not available")
174
+
175
+ repo_id = getattr(Config, "DOCUMENT_FORGERY_MODEL_REPO_ID", Config.REAL_FORGED_MODEL_REPO_ID)
176
+ configured_name = getattr(Config, "DOCUMENT_FORGERY_MODEL_FILENAME", str(target_path))
177
+ candidate_filenames = []
178
+ for candidate in (configured_name, str(target_path), target_path.name):
179
+ if candidate and candidate not in candidate_filenames:
180
+ candidate_filenames.append(candidate)
181
+
182
+ last_error = None
183
+ for filename in candidate_filenames:
184
+ try:
185
+ print(f"Downloading document forgery model from Hugging Face repo: {repo_id} ({filename})")
186
+ downloaded_path = hf_hub_download(repo_id=repo_id, filename=filename, token=Config.HF_TOKEN)
187
+ target_path.parent.mkdir(parents=True, exist_ok=True)
188
+ shutil.copy2(downloaded_path, target_path)
189
+ print(f"Document forgery model downloaded to: {target_path}")
190
+ return target_path
191
+ except Exception as exc:
192
+ last_error = exc
193
+
194
+ raise RuntimeError(f"unable to download document forgery model: {last_error}")
195
+
196
 
197
  # --- Global Model Instance ---
198
  MODEL_REPO_ID = Config.REAL_FORGED_MODEL_REPO_ID
features/real_forged_classifier/routes.py CHANGED
@@ -1,14 +1,14 @@
1
- from fastapi import APIRouter, File, UploadFile, HTTPException, status
2
  from fastapi.responses import JSONResponse
3
 
4
  # Import the controller instance and document forger
5
- from .controller import controller, document_forger
6
 
7
  # Create an API router
8
  router = APIRouter()
9
 
10
  @router.post("/classify_forgery", summary="Classify an image as Real or Fake")
11
- async def classify_image_endpoint(image: UploadFile = File(...)):
12
  """
13
  Accepts an image file and classifies it as 'real' or 'fake'.
14
 
@@ -36,7 +36,7 @@ async def classify_image_endpoint(image: UploadFile = File(...)):
36
  return JSONResponse(content=result, status_code=status.HTTP_200_OK)
37
 
38
  @router.post("/isforged", summary="Check if the document is forged")
39
- async def is_forged_endpoint(file: UploadFile = File(...)):
40
  """Run the document forgery detector on an uploaded image file.
41
 
42
  Accepts image uploads (multipart/form-data) and returns a JSON verdict with confidence.
@@ -48,7 +48,10 @@ async def is_forged_endpoint(file: UploadFile = File(...)):
48
  )
49
 
50
  result = document_forger.is_forged(file.file)
51
- if isinstance(result, dict) and result.get("error"):
52
- raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=result.get("error"))
 
 
 
53
 
54
  return JSONResponse(content=result, status_code=status.HTTP_200_OK)
 
1
+ from fastapi import APIRouter, File, UploadFile, HTTPException, status, Depends
2
  from fastapi.responses import JSONResponse
3
 
4
  # Import the controller instance and document forger
5
+ from .controller import controller, document_forger, verify_token
6
 
7
  # Create an API router
8
  router = APIRouter()
9
 
10
  @router.post("/classify_forgery", summary="Classify an image as Real or Fake")
11
+ async def classify_image_endpoint(image: UploadFile = File(...), token: str = Depends(verify_token)):
12
  """
13
  Accepts an image file and classifies it as 'real' or 'fake'.
14
 
 
36
  return JSONResponse(content=result, status_code=status.HTTP_200_OK)
37
 
38
  @router.post("/isforged", summary="Check if the document is forged")
39
+ async def is_forged_endpoint(file: UploadFile = File(...), token: str = Depends(verify_token)):
40
  """Run the document forgery detector on an uploaded image file.
41
 
42
  Accepts image uploads (multipart/form-data) and returns a JSON verdict with confidence.
 
48
  )
49
 
50
  result = document_forger.is_forged(file.file)
51
+ if isinstance(result, dict) and (result.get("error") or result.get("detail")):
52
+ raise HTTPException(
53
+ status_code=status.HTTP_400_BAD_REQUEST,
54
+ detail=result.get("error") or result.get("detail"),
55
+ )
56
 
57
  return JSONResponse(content=result, status_code=status.HTTP_200_OK)