PrathameshRaut commited on
Commit
5a7d9c6
·
verified ·
1 Parent(s): 30b21b4

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +69 -18
main.py CHANGED
@@ -5,23 +5,61 @@ import numpy as np
5
  import tensorflow as tf
6
  from tensorflow.keras.preprocessing import image
7
  from pdf2image import convert_from_path
8
- from fastapi import FastAPI, UploadFile, Form, HTTPException
9
  from fastapi.responses import JSONResponse
10
 
11
  # -----------------------------
12
  # CONFIG
13
  # -----------------------------
14
  IMG_SIZE = (224, 224)
15
- MODEL_PATH = "./final_model.keras" # Relative path for deployment
16
  class_names = ['Other', 'Aadhar Card', 'Pan Card', 'Voter Id']
17
 
18
- # Mapping for expected_type input to class names
19
  type_mapping = {
20
  "aadhar_card": "Aadhar Card",
21
  "pan_card": "Pan Card",
22
  "voter_id": "Voter Id"
23
  }
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  # -----------------------------
26
  # LOAD MODEL
27
  # -----------------------------
@@ -33,11 +71,12 @@ model = tf.keras.models.load_model(MODEL_PATH)
33
  def predict_array(img_array):
34
  img_array = tf.cast(img_array, tf.float32)
35
  img_array = tf.image.resize(img_array, IMG_SIZE)
36
- # DO NOT divide by 255.0 (training did not use Rescaling)
37
  img_array = tf.expand_dims(img_array, axis=0)
 
38
  pred = model.predict(img_array, verbose=0)[0]
39
  class_id = int(np.argmax(pred))
40
  conf = float(np.max(pred))
 
41
  return class_names[class_id], conf, pred
42
 
43
  # -----------------------------
@@ -57,22 +96,28 @@ def predict_image(img_path):
57
  # -----------------------------
58
  def predict_pdf(pdf_path, dpi=200, max_pages=2):
59
  pages = convert_from_path(pdf_path, dpi=dpi)
 
60
  if len(pages) > max_pages:
61
  return {
62
  "error": "Maximum page limit reached",
63
  "max_pages": max_pages,
64
  "found_pages": len(pages)
65
  }
 
66
  results = []
67
  labels = []
 
68
  for page in pages:
69
  page_np = np.array(page)
 
70
  # RGBA -> RGB
71
  if page_np.shape[-1] == 4:
72
  page_np = page_np[..., :3]
 
73
  label, conf, _ = predict_array(page_np)
74
  results.append((label, conf))
75
  labels.append(label)
 
76
  # 2 pages validation
77
  if len(labels) == 2:
78
  if labels[0] != labels[1]:
@@ -82,14 +127,16 @@ def predict_pdf(pdf_path, dpi=200, max_pages=2):
82
  "page1_type": labels[0],
83
  "page2_type": labels[1]
84
  }
85
- # both same -> return single output
86
  final_label = labels[0]
87
  final_conf = float(max(results[0][1], results[1][1]))
 
88
  return {
89
  "type": final_label,
90
  "confidence": round(final_conf, 6)
91
  }
92
- # 1-page pdf normal output
 
93
  return {
94
  "type": labels[0],
95
  "confidence": round(float(results[0][1]), 6)
@@ -101,50 +148,54 @@ def predict_pdf(pdf_path, dpi=200, max_pages=2):
101
  def predict_file(path):
102
  if not os.path.exists(path):
103
  return {"error": "File not found", "path": path}
 
104
  ext = os.path.splitext(path)[1].lower()
 
105
  if ext in [".png", ".jpg", ".jpeg", ".bmp", ".webp"]:
106
  return predict_image(path)
 
107
  if ext == ".pdf":
108
  return predict_pdf(path)
 
109
  return {"error": "Unsupported file type", "ext": ext}
110
 
111
  # -----------------------------
112
  # FastAPI App
113
  # -----------------------------
114
- app = FastAPI(title="ID Document Validator", description="Predict document type and authenticate based on expected type.")
 
 
 
115
 
116
  @app.post("/predict")
117
  async def predict(
118
  file: UploadFile,
119
- expected_type: str = Form(None) # Optional form field
 
120
  ):
121
- # Validate file
122
  if not file.filename:
123
  raise HTTPException(status_code=400, detail="No file provided")
124
-
125
- # Save uploaded file temporarily
126
  with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(file.filename)[1]) as temp_file:
127
  temp_path = temp_file.name
128
  temp_file.write(await file.read())
129
-
130
  try:
131
- # Predict
132
  result = predict_file(temp_path)
133
-
134
- # Add authentication if expected_type is provided and no error
135
  if expected_type and expected_type in type_mapping and "type" in result:
136
  if result["type"] == type_mapping[expected_type]:
137
  result["Authentication"] = "Valid"
138
  else:
139
  result["Authentication"] = "Not valid"
140
-
141
  return JSONResponse(content=result)
 
142
  finally:
143
- # Clean up temp file
144
  if os.path.exists(temp_path):
145
  os.unlink(temp_path)
146
 
147
- # Health check endpoint
148
  @app.get("/")
149
  def read_root():
150
  return {"message": "ID Validator API is running"}
 
5
  import tensorflow as tf
6
  from tensorflow.keras.preprocessing import image
7
  from pdf2image import convert_from_path
8
+ from fastapi import FastAPI, UploadFile, Form, HTTPException, Header, Depends
9
  from fastapi.responses import JSONResponse
10
 
11
  # -----------------------------
12
  # CONFIG
13
  # -----------------------------
14
  IMG_SIZE = (224, 224)
15
+ MODEL_PATH = "./final_model.keras"
16
  class_names = ['Other', 'Aadhar Card', 'Pan Card', 'Voter Id']
17
 
 
18
  type_mapping = {
19
  "aadhar_card": "Aadhar Card",
20
  "pan_card": "Pan Card",
21
  "voter_id": "Voter Id"
22
  }
23
 
24
+ # -----------------------------
25
+ # AUTH CONFIG (HF SECRETS)
26
+ # -----------------------------
27
+ MASTER_SECRET_KEY = os.getenv("MASTER_SECRET_KEY")
28
+
29
+ PROJECT_KEYS_JSON = os.getenv("PROJECT_KEYS_JSON", "{}")
30
+ try:
31
+ PROJECT_KEYS = json.loads(PROJECT_KEYS_JSON)
32
+ except Exception:
33
+ PROJECT_KEYS = {}
34
+
35
+ # -----------------------------
36
+ # AUTH VALIDATION
37
+ # -----------------------------
38
+ def verify_keys(
39
+ x_secret_key: str = Header(None),
40
+ x_project_id: str = Header(None),
41
+ x_project_key: str = Header(None),
42
+ ):
43
+ # Server configuration check
44
+ if not MASTER_SECRET_KEY:
45
+ raise HTTPException(status_code=500, detail="MASTER_SECRET_KEY not configured in Space secrets")
46
+
47
+ # 1) Validate master key
48
+ if not x_secret_key or x_secret_key != MASTER_SECRET_KEY:
49
+ raise HTTPException(status_code=401, detail="Invalid Secret Key")
50
+
51
+ # 2) Validate project key
52
+ if not x_project_id or not x_project_key:
53
+ raise HTTPException(status_code=401, detail="Project Id and Project Key are required")
54
+
55
+ if x_project_id not in PROJECT_KEYS:
56
+ raise HTTPException(status_code=401, detail=f"Unknown project: {x_project_id}")
57
+
58
+ if PROJECT_KEYS.get(x_project_id) != x_project_key:
59
+ raise HTTPException(status_code=401, detail="Invalid Project Key")
60
+
61
+ return True
62
+
63
  # -----------------------------
64
  # LOAD MODEL
65
  # -----------------------------
 
71
  def predict_array(img_array):
72
  img_array = tf.cast(img_array, tf.float32)
73
  img_array = tf.image.resize(img_array, IMG_SIZE)
 
74
  img_array = tf.expand_dims(img_array, axis=0)
75
+
76
  pred = model.predict(img_array, verbose=0)[0]
77
  class_id = int(np.argmax(pred))
78
  conf = float(np.max(pred))
79
+
80
  return class_names[class_id], conf, pred
81
 
82
  # -----------------------------
 
96
  # -----------------------------
97
  def predict_pdf(pdf_path, dpi=200, max_pages=2):
98
  pages = convert_from_path(pdf_path, dpi=dpi)
99
+
100
  if len(pages) > max_pages:
101
  return {
102
  "error": "Maximum page limit reached",
103
  "max_pages": max_pages,
104
  "found_pages": len(pages)
105
  }
106
+
107
  results = []
108
  labels = []
109
+
110
  for page in pages:
111
  page_np = np.array(page)
112
+
113
  # RGBA -> RGB
114
  if page_np.shape[-1] == 4:
115
  page_np = page_np[..., :3]
116
+
117
  label, conf, _ = predict_array(page_np)
118
  results.append((label, conf))
119
  labels.append(label)
120
+
121
  # 2 pages validation
122
  if len(labels) == 2:
123
  if labels[0] != labels[1]:
 
127
  "page1_type": labels[0],
128
  "page2_type": labels[1]
129
  }
130
+
131
  final_label = labels[0]
132
  final_conf = float(max(results[0][1], results[1][1]))
133
+
134
  return {
135
  "type": final_label,
136
  "confidence": round(final_conf, 6)
137
  }
138
+
139
+ # 1 page output
140
  return {
141
  "type": labels[0],
142
  "confidence": round(float(results[0][1]), 6)
 
148
  def predict_file(path):
149
  if not os.path.exists(path):
150
  return {"error": "File not found", "path": path}
151
+
152
  ext = os.path.splitext(path)[1].lower()
153
+
154
  if ext in [".png", ".jpg", ".jpeg", ".bmp", ".webp"]:
155
  return predict_image(path)
156
+
157
  if ext == ".pdf":
158
  return predict_pdf(path)
159
+
160
  return {"error": "Unsupported file type", "ext": ext}
161
 
162
  # -----------------------------
163
  # FastAPI App
164
  # -----------------------------
165
+ app = FastAPI(
166
+ title="ID Document Validator",
167
+ description="Predict document type and authenticate based on expected type."
168
+ )
169
 
170
  @app.post("/predict")
171
  async def predict(
172
  file: UploadFile,
173
+ expected_type: str = Form(None),
174
+ auth: bool = Depends(verify_keys) # ✅ Authentication required
175
  ):
 
176
  if not file.filename:
177
  raise HTTPException(status_code=400, detail="No file provided")
178
+
 
179
  with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(file.filename)[1]) as temp_file:
180
  temp_path = temp_file.name
181
  temp_file.write(await file.read())
182
+
183
  try:
 
184
  result = predict_file(temp_path)
185
+
186
+ # authentication based on expected_type
187
  if expected_type and expected_type in type_mapping and "type" in result:
188
  if result["type"] == type_mapping[expected_type]:
189
  result["Authentication"] = "Valid"
190
  else:
191
  result["Authentication"] = "Not valid"
192
+
193
  return JSONResponse(content=result)
194
+
195
  finally:
 
196
  if os.path.exists(temp_path):
197
  os.unlink(temp_path)
198
 
 
199
  @app.get("/")
200
  def read_root():
201
  return {"message": "ID Validator API is running"}