Midnightar commited on
Commit
5f2c279
·
verified ·
1 Parent(s): 193f77c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +68 -47
app.py CHANGED
@@ -6,17 +6,21 @@ from fastapi import FastAPI
6
  from pydantic import BaseModel
7
  import insightface
8
  import gradio as gr
9
- import uvicorn
10
  from fastapi.middleware.cors import CORSMiddleware
 
11
 
12
- # -------------------- Load Face Recognition Model --------------------
 
 
13
  model = insightface.app.FaceAnalysis(name="buffalo_l")
14
  model.prepare(ctx_id=0, det_size=(640, 640))
15
 
16
- # -------------------- FASTAPI APP --------------------
 
 
17
  app = FastAPI()
18
 
19
- # Allow all CORS (FlutterFlow)
20
  app.add_middleware(
21
  CORSMiddleware,
22
  allow_origins=["*"],
@@ -25,74 +29,99 @@ app.add_middleware(
25
  allow_headers=["*"],
26
  )
27
 
28
- # -------------------- Request Schema --------------------
 
 
 
29
  class CompareRequest(BaseModel):
30
  image1: str | None = None
31
  image2: str | None = None
32
  image1_url: str | None = None
33
  image2_url: str | None = None
34
 
35
- # -------------------- Helpers --------------------
 
 
 
36
  def b64_to_img(b64_string):
37
  try:
38
  img_data = base64.b64decode(b64_string)
39
- arr = np.frombuffer(img_data, np.uint8)
40
- return cv2.imdecode(arr, cv2.IMREAD_COLOR)
 
41
  except:
42
  return None
43
 
 
44
  def url_to_img(url):
45
  try:
46
- r = requests.get(url, timeout=5)
47
- arr = np.frombuffer(r.content, np.uint8)
48
- return cv2.imdecode(arr, cv2.IMREAD_COLOR)
 
49
  except:
50
  return None
51
 
52
- def load_any(x):
53
- if x.startswith("http://") or x.startswith("https://"):
54
- return url_to_img(x)
55
- return b64_to_img(x)
56
 
57
  def get_embedding(img):
58
  faces = model.get(img)
59
- if not faces:
60
  return None
61
  return faces[0].embedding
62
 
63
- # -------------------- /compare API --------------------
 
 
 
64
  @app.post("/compare")
65
  async def compare_faces(req: CompareRequest):
66
 
67
- img1 = load_any(req.image1 or req.image1_url or "")
68
- img2 = load_any(req.image2 or req.image2_url or "")
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
  if img1 is None or img2 is None:
71
- return {"error": "Invalid image1/image2 or URLs"}
72
 
73
  emb1 = get_embedding(img1)
74
  emb2 = get_embedding(img2)
75
 
76
  if emb1 is None or emb2 is None:
77
- return {"error": "No face detected in one or both images."}
78
 
79
- similarity = float(
80
- np.dot(emb1, emb2) /
81
- (np.linalg.norm(emb1) * np.linalg.norm(emb2))
82
- )
83
 
84
- return {
85
- "similarity": similarity,
86
- "match": similarity > 0.55
87
- }
88
 
89
- # -------------------- GRADIO UI --------------------
 
 
 
90
  def gradio_ui(img1_text, img2_text):
 
 
 
 
 
 
91
  img1 = load_any(img1_text)
92
  img2 = load_any(img2_text)
93
 
94
  if img1 is None or img2 is None:
95
- return "Invalid base64 or URL."
96
 
97
  emb1 = get_embedding(img1)
98
  emb2 = get_embedding(img2)
@@ -100,28 +129,20 @@ def gradio_ui(img1_text, img2_text):
100
  if emb1 is None or emb2 is None:
101
  return "Face not detected."
102
 
103
- similarity = np.dot(emb1, emb2) / (
104
- np.linalg.norm(emb1) * np.linalg.norm(emb2)
105
- )
 
106
 
107
- return f"Similarity: {similarity:.3f} | Match: {similarity > 0.55}"
108
 
109
- gradio_ui_app = gr.Interface(
110
  fn=gradio_ui,
111
  inputs=[
112
  gr.Textbox(label="Image 1 (base64 or URL)"),
113
- gr.Textbox(label="Image 2 (base64 or URL)")
114
  ],
115
  outputs="text",
116
- title="Face Match API (Text Input)"
117
  )
118
 
119
- # IMPORTANT: Launching Gradio inside FastAPI server
120
- # HuggingFace will call "app" automatically
121
- @app.get("/")
122
- async def serve_gradio():
123
- return gradio_ui_app.launch(
124
- inline=True, # IMPORTANT: embed inside FastAPI
125
- share=False,
126
- prevent_thread_lock=True
127
- )
 
6
  from pydantic import BaseModel
7
  import insightface
8
  import gradio as gr
 
9
  from fastapi.middleware.cors import CORSMiddleware
10
+ from fastapi.staticfiles import StaticFiles
11
 
12
+ # -------------------------------------------
13
+ # Load Face Model
14
+ # -------------------------------------------
15
  model = insightface.app.FaceAnalysis(name="buffalo_l")
16
  model.prepare(ctx_id=0, det_size=(640, 640))
17
 
18
+ # -------------------------------------------
19
+ # FastAPI app
20
+ # -------------------------------------------
21
  app = FastAPI()
22
 
23
+ # CORS for FlutterFlow
24
  app.add_middleware(
25
  CORSMiddleware,
26
  allow_origins=["*"],
 
29
  allow_headers=["*"],
30
  )
31
 
32
+
33
+ # -------------------------------------------
34
+ # Request Schema
35
+ # -------------------------------------------
36
  class CompareRequest(BaseModel):
37
  image1: str | None = None
38
  image2: str | None = None
39
  image1_url: str | None = None
40
  image2_url: str | None = None
41
 
42
+
43
+ # -------------------------------------------
44
+ # Helper Functions
45
+ # -------------------------------------------
46
  def b64_to_img(b64_string):
47
  try:
48
  img_data = base64.b64decode(b64_string)
49
+ np_arr = np.frombuffer(img_data, np.uint8)
50
+ img = cv2.imdecode(np_arr, cv2.IMREAD_COLOR)
51
+ return img
52
  except:
53
  return None
54
 
55
+
56
  def url_to_img(url):
57
  try:
58
+ resp = requests.get(url, timeout=5)
59
+ np_arr = np.frombuffer(resp.content, np.uint8)
60
+ img = cv2.imdecode(np_arr, cv2.IMREAD_COLOR)
61
+ return img
62
  except:
63
  return None
64
 
 
 
 
 
65
 
66
  def get_embedding(img):
67
  faces = model.get(img)
68
+ if len(faces) == 0:
69
  return None
70
  return faces[0].embedding
71
 
72
+
73
+ # -------------------------------------------
74
+ # API Endpoint
75
+ # -------------------------------------------
76
  @app.post("/compare")
77
  async def compare_faces(req: CompareRequest):
78
 
79
+ # Load image 1
80
+ if req.image1:
81
+ img1 = b64_to_img(req.image1)
82
+ elif req.image1_url:
83
+ img1 = url_to_img(req.image1_url)
84
+ else:
85
+ img1 = None
86
+
87
+ # Load image 2
88
+ if req.image2:
89
+ img2 = b64_to_img(req.image2)
90
+ elif req.image2_url:
91
+ img2 = url_to_img(req.image2_url)
92
+ else:
93
+ img2 = None
94
 
95
  if img1 is None or img2 is None:
96
+ return {"error": "Invalid image data or URL"}
97
 
98
  emb1 = get_embedding(img1)
99
  emb2 = get_embedding(img2)
100
 
101
  if emb1 is None or emb2 is None:
102
+ return {"error": "No face detected"}
103
 
104
+ similarity = float(np.dot(emb1, emb2) / (np.linalg.norm(emb1) * np.linalg.norm(emb2)))
105
+ matched = similarity > 0.55
 
 
106
 
107
+ return {"similarity": similarity, "match": matched}
 
 
 
108
 
109
+
110
+ # -------------------------------------------
111
+ # Gradio UI (embedded inside FastAPI)
112
+ # -------------------------------------------
113
  def gradio_ui(img1_text, img2_text):
114
+
115
+ def load_any(s):
116
+ if s.startswith("http"):
117
+ return url_to_img(s)
118
+ return b64_to_img(s)
119
+
120
  img1 = load_any(img1_text)
121
  img2 = load_any(img2_text)
122
 
123
  if img1 is None or img2 is None:
124
+ return "Invalid image or URL"
125
 
126
  emb1 = get_embedding(img1)
127
  emb2 = get_embedding(img2)
 
129
  if emb1 is None or emb2 is None:
130
  return "Face not detected."
131
 
132
+ similarity = float(np.dot(emb1, emb2) / (np.linalg.norm(emb1) * np.linalg.norm(emb2)))
133
+ matched = similarity > 0.55
134
+
135
+ return f"Similarity: {similarity:.3f} | Match: {matched}"
136
 
 
137
 
138
+ ui = gr.Interface(
139
  fn=gradio_ui,
140
  inputs=[
141
  gr.Textbox(label="Image 1 (base64 or URL)"),
142
+ gr.Textbox(label="Image 2 (base64 or URL)"),
143
  ],
144
  outputs="text",
145
+ title="Face Match API",
146
  )
147
 
148
+ app = gr.mount_gradio_app(app, ui, path="/")