Midnightar commited on
Commit
5059f37
·
verified ·
1 Parent(s): 18c23ed

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +45 -57
app.py CHANGED
@@ -4,37 +4,25 @@ import numpy as np
4
  import requests
5
  from fastapi import FastAPI
6
  from pydantic import BaseModel
7
- from fastapi.responses import HTMLResponse
8
- from fastapi.middleware.cors import CORSMiddleware
9
  import insightface
10
  import gradio as gr
11
 
12
- # ---------- Load Face Detector ----------
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
- # CORS for FlutterFlow
20
- app.add_middleware(
21
- CORSMiddleware,
22
- allow_origins=["*"],
23
- allow_credentials=True,
24
- allow_methods=["*"],
25
- allow_headers=["*"],
26
- )
27
-
28
-
29
- # ---------- API Request Model ----------
30
  class CompareRequest(BaseModel):
31
- image1: str | None = None
32
- image2: str | None = None
33
- image1_url: str | None = None
34
- image2_url: str | None = None
35
-
36
 
37
- # ---------- Helpers ----------
38
  def b64_to_img(b64_string):
39
  try:
40
  img_data = base64.b64decode(b64_string)
@@ -44,6 +32,7 @@ def b64_to_img(b64_string):
44
  except:
45
  return None
46
 
 
47
  def url_to_img(url):
48
  try:
49
  resp = requests.get(url, timeout=5)
@@ -53,18 +42,18 @@ def url_to_img(url):
53
  except:
54
  return None
55
 
 
56
  def get_embedding(img):
57
  faces = model.get(img)
58
  if len(faces) == 0:
59
  return None
60
- return faces[0].embedding
61
 
62
-
63
- # ---------- POST /compare ----------
64
  @app.post("/compare")
65
  async def compare_faces(req: CompareRequest):
66
 
67
- # Load image 1
68
  if req.image1:
69
  img1 = b64_to_img(req.image1)
70
  elif req.image1_url:
@@ -72,7 +61,7 @@ async def compare_faces(req: CompareRequest):
72
  else:
73
  img1 = None
74
 
75
- # Load image 2
76
  if req.image2:
77
  img2 = b64_to_img(req.image2)
78
  elif req.image2_url:
@@ -87,32 +76,39 @@ async def compare_faces(req: CompareRequest):
87
  emb2 = get_embedding(img2)
88
 
89
  if emb1 is None or emb2 is None:
90
- return {"error": "No face detected."}
91
 
92
- similarity = np.dot(emb1, emb2) / (
93
- np.linalg.norm(emb1) * np.linalg.norm(emb2)
94
- )
95
- matched = similarity > 0.55
96
 
97
  return {
98
  "similarity": float(similarity),
99
  "match": matched
100
  }
101
 
102
-
103
- # ---------- Gradio UI ----------
104
  def gradio_ui(img1_text, img2_text):
105
- # Detect format automatically
106
- def load(s):
107
- if s.startswith("http"):
108
- return url_to_img(s)
109
- return b64_to_img(s)
110
-
111
- img1 = load(img1_text)
112
- img2 = load(img2_text)
 
 
 
 
 
 
 
 
113
 
114
  if img1 is None or img2 is None:
115
- return "Invalid image."
116
 
117
  emb1 = get_embedding(img1)
118
  emb2 = get_embedding(img2)
@@ -120,25 +116,17 @@ def gradio_ui(img1_text, img2_text):
120
  if emb1 is None or emb2 is None:
121
  return "Face not detected."
122
 
123
- similarity = np.dot(emb1, emb2) / (
124
- np.linalg.norm(emb1) * np.linalg.norm(emb2)
125
- )
126
- match = similarity > 0.55
127
-
128
- return f"Similarity: {similarity:.3f} | Match: {match}"
129
 
 
130
 
131
- demo = gr.Interface(
132
  fn=gradio_ui,
133
  inputs=[
134
- gr.Textbox(label="Image 1 (URL or Base64)"),
135
- gr.Textbox(label="Image 2 (URL or Base64)")
136
  ],
137
  outputs="text",
138
- title="Face Compare API"
139
- )
140
-
141
- # ---------- Serve Gradio UI at "/" ----------
142
- @app.get("/", response_class=HTMLResponse)
143
- async def root():
144
- return demo.launch(share=False, inline=True)
 
4
  import requests
5
  from fastapi import FastAPI
6
  from pydantic import BaseModel
7
+ import uvicorn
 
8
  import insightface
9
  import gradio as gr
10
 
11
+ # ---------- Load Face Detector + Recognition Model ----------
12
  model = insightface.app.FaceAnalysis(name="buffalo_l")
13
  model.prepare(ctx_id=0, det_size=(640, 640))
14
 
15
  # ---------- FastAPI App ----------
16
  app = FastAPI()
17
 
18
+ # ---------- API Request Schema ----------
 
 
 
 
 
 
 
 
 
 
19
  class CompareRequest(BaseModel):
20
+ image1: str | None = None # base64
21
+ image2: str | None = None # base64
22
+ image1_url: str | None = None # URL
23
+ image2_url: str | None = None # URL
 
24
 
25
+ # ---------- Helper: Convert base64 to CV2 image ----------
26
  def b64_to_img(b64_string):
27
  try:
28
  img_data = base64.b64decode(b64_string)
 
32
  except:
33
  return None
34
 
35
+ # ---------- Helper: Convert URL to CV2 image ----------
36
  def url_to_img(url):
37
  try:
38
  resp = requests.get(url, timeout=5)
 
42
  except:
43
  return None
44
 
45
+ # ---------- Helper: Extract face embedding ----------
46
  def get_embedding(img):
47
  faces = model.get(img)
48
  if len(faces) == 0:
49
  return None
50
+ return faces[0].embedding # first detected face
51
 
52
+ # ---------- POST /compare API ----------
 
53
  @app.post("/compare")
54
  async def compare_faces(req: CompareRequest):
55
 
56
+ # ---- Load Image 1 ----
57
  if req.image1:
58
  img1 = b64_to_img(req.image1)
59
  elif req.image1_url:
 
61
  else:
62
  img1 = None
63
 
64
+ # ---- Load Image 2 ----
65
  if req.image2:
66
  img2 = b64_to_img(req.image2)
67
  elif req.image2_url:
 
76
  emb2 = get_embedding(img2)
77
 
78
  if emb1 is None or emb2 is None:
79
+ return {"error": "No face detected in one or both images."}
80
 
81
+ # Cosine similarity
82
+ similarity = np.dot(emb1, emb2) / (np.linalg.norm(emb1) * np.linalg.norm(emb2))
83
+
84
+ matched = similarity > 0.55 # threshold
85
 
86
  return {
87
  "similarity": float(similarity),
88
  "match": matched
89
  }
90
 
91
+ # ---------- Gradio UI (TEXT INPUT instead of upload) ----------
 
92
  def gradio_ui(img1_text, img2_text):
93
+ """
94
+ Accepts:
95
+ - base64 string
96
+ - or URL
97
+ Automatically detects which one.
98
+ """
99
+
100
+ # --- Determine type of input ---
101
+ def load_any(input_str):
102
+ if input_str.startswith("http://") or input_str.startswith("https://"):
103
+ return url_to_img(input_str)
104
+ else:
105
+ return b64_to_img(input_str)
106
+
107
+ img1 = load_any(img1_text)
108
+ img2 = load_any(img2_text)
109
 
110
  if img1 is None or img2 is None:
111
+ return "Invalid image data or URL."
112
 
113
  emb1 = get_embedding(img1)
114
  emb2 = get_embedding(img2)
 
116
  if emb1 is None or emb2 is None:
117
  return "Face not detected."
118
 
119
+ similarity = np.dot(emb1, emb2) / (np.linalg.norm(emb1) * np.linalg.norm(emb2))
120
+ matched = similarity > 0.55
 
 
 
 
121
 
122
+ return f"Similarity: {similarity:.3f} | Match: {matched}"
123
 
124
+ gr.Interface(
125
  fn=gradio_ui,
126
  inputs=[
127
+ gr.Textbox(label="Image 1 (base64 or URL)"),
128
+ gr.Textbox(label="Image 2 (base64 or URL)")
129
  ],
130
  outputs="text",
131
+ title="Face Match API (Text Input)"
132
+ ).launch()