first commit
This commit is contained in:
commit
a16d736a5a
53
.gitignore
vendored
Normal file
53
.gitignore
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# Caches
|
||||||
|
.cache/
|
||||||
|
*.cache
|
||||||
|
|
||||||
|
# Virtual environment
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
.venv/
|
||||||
|
|
||||||
|
# Local environment configurations
|
||||||
|
.env
|
||||||
|
*.env
|
||||||
|
|
||||||
|
# Database files
|
||||||
|
*.db
|
||||||
|
*.sqlite3
|
||||||
|
*.db-journal
|
||||||
|
|
||||||
|
# Images, temporary files, and uploads
|
||||||
|
/tmp/
|
||||||
|
*.png
|
||||||
|
*.jpg
|
||||||
|
*.jpeg
|
||||||
|
*.gif
|
||||||
|
*.bmp
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
logs/
|
||||||
|
|
||||||
|
# Jupyter Notebook checkpoints
|
||||||
|
.ipynb_checkpoints/
|
||||||
|
|
||||||
|
# Compiled C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# macOS specific files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Windows specific files
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# System files
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
123
app.py
Normal file
123
app.py
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
from fastapi import FastAPI, File, UploadFile, HTTPException, Form
|
||||||
|
from deepface import DeepFace
|
||||||
|
from manticoresearch import ApiClient, Configuration
|
||||||
|
from manticoresearch.api import IndexApi, SearchApi
|
||||||
|
from manticoresearch.model import SearchRequest
|
||||||
|
from manticoresearch.model import InsertDocumentRequest
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from numpy import dot
|
||||||
|
from numpy.linalg import norm
|
||||||
|
|
||||||
|
# Configurar el cliente API
|
||||||
|
config = Configuration()
|
||||||
|
config.host = "http://localhost:9308"
|
||||||
|
client = ApiClient(configuration=config)
|
||||||
|
|
||||||
|
# Inicializar las APIs
|
||||||
|
index_api = IndexApi(client)
|
||||||
|
search_api = SearchApi(client)
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
# Función para calcular similitud de coseno
|
||||||
|
def cosine_similarity(vec1, vec2):
|
||||||
|
return dot(vec1, vec2) / (norm(vec1) * norm(vec2))
|
||||||
|
|
||||||
|
# Ruta para registrar un nuevo usuario
|
||||||
|
@app.post("/register_user")
|
||||||
|
async def register_user(user_id: str = Form(...), image: UploadFile = File(...)):
|
||||||
|
try:
|
||||||
|
# Guardar la imagen temporalmente
|
||||||
|
img_path = f"/tmp/{image.filename}"
|
||||||
|
with open(img_path, "wb") as buffer:
|
||||||
|
shutil.copyfileobj(image.file, buffer)
|
||||||
|
|
||||||
|
# Obtener los embeddings faciales
|
||||||
|
embedding_result = DeepFace.represent(img_path, model_name="ArcFace")
|
||||||
|
|
||||||
|
# Extraer los embeddings
|
||||||
|
embeddings = embedding_result[0]['embedding'] # Extrae el vector de embeddings
|
||||||
|
|
||||||
|
# Verifica si embeddings tiene 512 valores
|
||||||
|
if len(embeddings) != 512:
|
||||||
|
raise HTTPException(status_code=400, detail=f"Los embeddings generados no tienen 512 valores: {len(embeddings)}")
|
||||||
|
|
||||||
|
# Almacenar los embeddings en Manticore Search
|
||||||
|
doc = {
|
||||||
|
"user_id": user_id,
|
||||||
|
"embeddings": embeddings
|
||||||
|
}
|
||||||
|
|
||||||
|
# Crea la solicitud de inserción de documento
|
||||||
|
insert_request = InsertDocumentRequest(index="users", doc=doc)
|
||||||
|
|
||||||
|
# Inserta el documento en Manticore Search
|
||||||
|
index_api.insert(insert_document_request=insert_request)
|
||||||
|
|
||||||
|
# Eliminar el archivo temporal
|
||||||
|
os.remove(img_path)
|
||||||
|
|
||||||
|
return {"status": "user registered successfully"}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Error registering user: {str(e)}")
|
||||||
|
|
||||||
|
# Ruta para verificar una imagen
|
||||||
|
@app.post("/verify_user")
|
||||||
|
async def verify_user(image: UploadFile = File(...)):
|
||||||
|
try:
|
||||||
|
# Guardar la imagen temporalmente
|
||||||
|
img_path = f"/tmp/{image.filename}"
|
||||||
|
with open(img_path, "wb") as buffer:
|
||||||
|
shutil.copyfileobj(image.file, buffer)
|
||||||
|
|
||||||
|
# Obtener los embeddings faciales de la imagen
|
||||||
|
query_embeddings = DeepFace.represent(img_path, model_name="ArcFace")[0]['embedding']
|
||||||
|
|
||||||
|
# Consulta en Manticore Search para obtener los usuarios registrados
|
||||||
|
query = {
|
||||||
|
"size": 100, # Ajusta el tamaño si tienes muchos usuarios
|
||||||
|
"query": {
|
||||||
|
"match_all": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Crear la solicitud de búsqueda
|
||||||
|
search_request = SearchRequest(index="users", query=query)
|
||||||
|
|
||||||
|
# Realizar la búsqueda
|
||||||
|
result = search_api.search(search_request)
|
||||||
|
|
||||||
|
# Recuperar todos los documentos (usuarios y sus embeddings)
|
||||||
|
hits = result.hits.hits
|
||||||
|
if not hits:
|
||||||
|
raise HTTPException(status_code=404, detail="No registered users found.")
|
||||||
|
|
||||||
|
# Calcular similitud de coseno con cada usuario registrado
|
||||||
|
max_similarity = -1
|
||||||
|
matched_user = None
|
||||||
|
for hit in hits:
|
||||||
|
stored_embeddings = hit['_source']['embeddings'] # Embeddings del usuario en la base de datos
|
||||||
|
similarity = cosine_similarity(query_embeddings, stored_embeddings)
|
||||||
|
|
||||||
|
# Imprimir la similitud de cada usuario para depuración
|
||||||
|
print(f"Similitud con {hit['_source']['user_id']}: {similarity}")
|
||||||
|
|
||||||
|
# Encontrar la mayor similitud
|
||||||
|
if similarity > max_similarity:
|
||||||
|
max_similarity = similarity
|
||||||
|
matched_user = hit['_source']['user_id']
|
||||||
|
|
||||||
|
# Establecer un umbral para decidir si hay coincidencia
|
||||||
|
similarity_threshold = 0.5 # Ajusta este valor según tus necesidades
|
||||||
|
if max_similarity < similarity_threshold:
|
||||||
|
raise HTTPException(status_code=404, detail="No matching user found")
|
||||||
|
|
||||||
|
# Eliminar el archivo temporal
|
||||||
|
os.remove(img_path)
|
||||||
|
|
||||||
|
return {"status": "success", "matched_user": matched_user, "similarity": max_similarity}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Error verifying user: {str(e)}")
|
2
migrations/pacedeep_fastapi.sql
Normal file
2
migrations/pacedeep_fastapi.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
DROP TABLE IF EXISTS users;
|
||||||
|
CREATE TABLE users (user_id text, embeddings float_vector KNN_TYPE='hnsw' KNN_DIMS='512' HNSW_SIMILARITY='cosine');
|
74
requirements.txt
Normal file
74
requirements.txt
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
absl-py==2.1.0
|
||||||
|
annotated-types==0.7.0
|
||||||
|
anyio==4.6.2.post1
|
||||||
|
astunparse==1.6.3
|
||||||
|
beautifulsoup4==4.12.3
|
||||||
|
blinker==1.8.2
|
||||||
|
certifi==2024.8.30
|
||||||
|
charset-normalizer==3.4.0
|
||||||
|
click==8.1.7
|
||||||
|
deepface==0.0.93
|
||||||
|
exceptiongroup==1.2.2
|
||||||
|
fastapi==0.115.2
|
||||||
|
filelock==3.16.1
|
||||||
|
fire==0.7.0
|
||||||
|
Flask==3.0.3
|
||||||
|
Flask-Cors==5.0.0
|
||||||
|
flatbuffers==24.3.25
|
||||||
|
gast==0.6.0
|
||||||
|
gdown==5.2.0
|
||||||
|
google-pasta==0.2.0
|
||||||
|
grpcio==1.67.0
|
||||||
|
gunicorn==23.0.0
|
||||||
|
h11==0.14.0
|
||||||
|
h5py==3.12.1
|
||||||
|
idna==3.10
|
||||||
|
itsdangerous==2.2.0
|
||||||
|
Jinja2==3.1.4
|
||||||
|
joblib==1.4.2
|
||||||
|
keras==3.6.0
|
||||||
|
libclang==18.1.1
|
||||||
|
lz4==4.3.3
|
||||||
|
manticoresearch==4.0.0
|
||||||
|
Markdown==3.7
|
||||||
|
markdown-it-py==3.0.0
|
||||||
|
MarkupSafe==3.0.2
|
||||||
|
mdurl==0.1.2
|
||||||
|
ml-dtypes==0.4.1
|
||||||
|
mtcnn==1.0.0
|
||||||
|
namex==0.0.8
|
||||||
|
numpy==1.26.4
|
||||||
|
opencv-python==4.10.0.84
|
||||||
|
opt_einsum==3.4.0
|
||||||
|
optree==0.13.0
|
||||||
|
packaging==24.1
|
||||||
|
pandas==2.2.3
|
||||||
|
pillow==11.0.0
|
||||||
|
protobuf==4.25.5
|
||||||
|
pydantic==2.9.2
|
||||||
|
pydantic_core==2.23.4
|
||||||
|
Pygments==2.18.0
|
||||||
|
PySocks==1.7.1
|
||||||
|
python-dateutil==2.9.0.post0
|
||||||
|
python-multipart==0.0.12
|
||||||
|
pytz==2024.2
|
||||||
|
requests==2.32.3
|
||||||
|
retina-face==0.0.17
|
||||||
|
rich==13.9.2
|
||||||
|
six==1.16.0
|
||||||
|
sniffio==1.3.1
|
||||||
|
soupsieve==2.6
|
||||||
|
starlette==0.40.0
|
||||||
|
tensorboard==2.17.1
|
||||||
|
tensorboard-data-server==0.7.2
|
||||||
|
tensorflow==2.17.0
|
||||||
|
tensorflow-io-gcs-filesystem==0.37.1
|
||||||
|
termcolor==2.5.0
|
||||||
|
tf_keras==2.17.0
|
||||||
|
tqdm==4.66.5
|
||||||
|
typing_extensions==4.12.2
|
||||||
|
tzdata==2024.2
|
||||||
|
urllib3==2.2.3
|
||||||
|
uvicorn==0.32.0
|
||||||
|
Werkzeug==3.0.4
|
||||||
|
wrapt==1.16.0
|
Loading…
x
Reference in New Issue
Block a user