feat: update Python processors and add utility scripts
- Update ASR, face, OCR, pose processors - Add release pre-flight check script - Add synonym generation, chunk processing scripts - Add face recognition, stamp search utilities
This commit is contained in:
367
scripts/test_face_recognition_integration.py
Normal file
367
scripts/test_face_recognition_integration.py
Normal file
@@ -0,0 +1,367 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
測試人臉識別完整集成流程
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import numpy as np
|
||||
from pathlib import Path
|
||||
|
||||
# 添加項目根目錄到 Python 路徑
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
# 測試數據庫連接
|
||||
try:
|
||||
import psycopg2
|
||||
from psycopg2.extras import Json
|
||||
|
||||
print("✅ psycopg2 已安裝")
|
||||
except ImportError:
|
||||
print("❌ psycopg2 未安裝,請運行: pip install psycopg2-binary")
|
||||
sys.exit(1)
|
||||
|
||||
# 測試 InsightFace
|
||||
try:
|
||||
import insightface
|
||||
|
||||
print("✅ insightface 已安裝")
|
||||
except ImportError:
|
||||
print("❌ insightface 未安裝,請運行: pip install insightface")
|
||||
sys.exit(1)
|
||||
|
||||
# 測試 ONNX Runtime
|
||||
try:
|
||||
import onnxruntime as ort
|
||||
|
||||
print("✅ onnxruntime 已安裝")
|
||||
|
||||
# 檢查可用的執行提供者
|
||||
available_providers = ort.get_available_providers()
|
||||
print(f"✅ 可用的執行提供者: {available_providers}")
|
||||
|
||||
# 檢查 MPS 支援
|
||||
if "CoreMLExecutionProvider" in available_providers:
|
||||
print("✅ CoreML (MPS) 支援可用")
|
||||
elif "CUDAExecutionProvider" in available_providers:
|
||||
print("✅ CUDA 支援可用")
|
||||
else:
|
||||
print("⚠️ 僅 CPU 支援可用")
|
||||
|
||||
except ImportError:
|
||||
print("❌ onnxruntime 未安裝,請運行: pip install onnxruntime")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def test_database_connection():
|
||||
"""測試數據庫連接"""
|
||||
print("\n=== 測試數據庫連接 ===")
|
||||
try:
|
||||
conn = psycopg2.connect(
|
||||
host="localhost",
|
||||
port=5432,
|
||||
database="momentry",
|
||||
user="accusys",
|
||||
password="accusys",
|
||||
)
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 檢查表是否存在
|
||||
cursor.execute("""
|
||||
SELECT table_name
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name LIKE 'face_%'
|
||||
ORDER BY table_name;
|
||||
""")
|
||||
|
||||
tables = cursor.fetchall()
|
||||
print(f"✅ 找到 {len(tables)} 個人臉相關表:")
|
||||
for table in tables:
|
||||
print(f" - {table[0]}")
|
||||
|
||||
# 檢查函數是否存在
|
||||
cursor.execute("""
|
||||
SELECT proname
|
||||
FROM pg_proc
|
||||
WHERE proname LIKE '%face%'
|
||||
ORDER BY proname;
|
||||
""")
|
||||
|
||||
functions = cursor.fetchall()
|
||||
print(f"✅ 找到 {len(functions)} 個人臉相關函數:")
|
||||
for func in functions:
|
||||
print(f" - {func[0]}")
|
||||
|
||||
# 測試插入和查詢
|
||||
cursor.execute("""
|
||||
SELECT find_or_create_face_identity(
|
||||
'integration_test_001',
|
||||
'Integration Test Person',
|
||||
NULL,
|
||||
'{"age": 25, "gender": "female", "test": true}'::jsonb,
|
||||
'{"source": "integration_test"}'::jsonb
|
||||
) AS identity_id;
|
||||
""")
|
||||
|
||||
identity_id = cursor.fetchone()[0]
|
||||
print(f"✅ 成功創建人臉身份,ID: {identity_id}")
|
||||
|
||||
# 檢查插入的數據
|
||||
cursor.execute("""
|
||||
SELECT id, face_id, name, attributes->>'gender' as gender,
|
||||
attributes->>'age' as age, attributes->>'test' as test
|
||||
FROM face_identities
|
||||
WHERE face_id = 'integration_test_001';
|
||||
""")
|
||||
|
||||
result = cursor.fetchone()
|
||||
print(
|
||||
f"✅ 查詢結果: ID={result[0]}, FaceID={result[1]}, Name={result[2]}, Gender={result[3]}, Age={result[4]}, Test={result[5]}"
|
||||
)
|
||||
|
||||
# 清理測試數據
|
||||
cursor.execute(
|
||||
"DELETE FROM face_identities WHERE face_id = 'integration_test_001';"
|
||||
)
|
||||
conn.commit()
|
||||
print("✅ 清理測試數據完成")
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 數據庫連接測試失敗: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def test_insightface_model():
|
||||
"""測試 InsightFace 模型"""
|
||||
print("\n=== 測試 InsightFace 模型 ===")
|
||||
|
||||
try:
|
||||
# 創建測試圖像(隨機數據)
|
||||
test_image = np.random.randint(0, 255, (640, 480, 3), dtype=np.uint8)
|
||||
print(f"✅ 創建測試圖像: {test_image.shape}")
|
||||
|
||||
# 初始化模型
|
||||
print("正在初始化 InsightFace 模型...")
|
||||
model = insightface.app.FaceAnalysis(name="buffalo_l")
|
||||
model.prepare(ctx_id=-1) # -1 表示 CPU
|
||||
|
||||
print("✅ InsightFace 模型初始化成功")
|
||||
|
||||
# 測試模型推理(使用隨機圖像)
|
||||
print("正在進行模型推理測試...")
|
||||
faces = model.get(test_image)
|
||||
print(f"✅ 模型推理完成,檢測到 {len(faces)} 個人臉")
|
||||
|
||||
if len(faces) > 0:
|
||||
face = faces[0]
|
||||
print(f"✅ 人臉屬性:")
|
||||
print(f" - 邊界框: {face.bbox}")
|
||||
print(f" - 置信度: {face.det_score:.4f}")
|
||||
print(
|
||||
f" - 嵌入向量維度: {face.embedding.shape if hasattr(face, 'embedding') else 'N/A'}"
|
||||
)
|
||||
|
||||
if hasattr(face, "age"):
|
||||
print(f" - 年齡: {face.age}")
|
||||
if hasattr(face, "gender"):
|
||||
print(f" - 性別: {face.gender}")
|
||||
if hasattr(face, "pose"):
|
||||
print(f" - 姿態: {face.pose}")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ InsightFace 模型測試失敗: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def test_face_processor():
|
||||
"""測試人臉處理器"""
|
||||
print("\n=== 測試人臉處理器 ===")
|
||||
|
||||
try:
|
||||
# 導入處理器
|
||||
from scripts.face_recognition_processor import FaceRecognitionProcessor
|
||||
|
||||
# 初始化處理器
|
||||
print("正在初始化人臉識別處理器...")
|
||||
processor = FaceRecognitionProcessor()
|
||||
|
||||
# 加載模型(不使用 MPS)
|
||||
print("正在加載模型...")
|
||||
processor.load_models(use_mps=False)
|
||||
|
||||
print(f"✅ 處理器初始化成功")
|
||||
print(f" - 啟用識別: {processor.enable_recognition}")
|
||||
print(f" - 啟用追蹤: {processor.enable_tracking}")
|
||||
print(f" - 啟用聚類: {processor.enable_clustering}")
|
||||
|
||||
# 創建測試視頻數據
|
||||
test_video_data = {
|
||||
"video_path": "/tmp/test_video.mp4", # 虛擬路徑
|
||||
"video_uuid": "test_video_001",
|
||||
"frame_count": 100,
|
||||
"fps": 30.0,
|
||||
}
|
||||
|
||||
print(f"✅ 創建測試視頻數據: {test_video_data['video_uuid']}")
|
||||
|
||||
# 測試處理器方法
|
||||
print("測試處理器方法...")
|
||||
|
||||
# 測試人臉檢測
|
||||
test_image = np.random.randint(0, 255, (640, 480, 3), dtype=np.uint8)
|
||||
detections = processor.detect_faces(test_image)
|
||||
print(f"✅ 人臉檢測測試完成,檢測到 {len(detections)} 個人臉")
|
||||
|
||||
if len(detections) > 0:
|
||||
detection = detections[0]
|
||||
print(f"✅ 檢測結果示例:")
|
||||
print(
|
||||
f" - 位置: x={detection['x']}, y={detection['y']}, width={detection['width']}, height={detection['height']}"
|
||||
)
|
||||
print(f" - 置信度: {detection['confidence']:.4f}")
|
||||
if "embedding" in detection and detection["embedding"] is not None:
|
||||
embedding = detection["embedding"]
|
||||
if hasattr(embedding, "shape"):
|
||||
print(f" - 嵌入向量: {embedding.shape}")
|
||||
else:
|
||||
print(f" - 嵌入向量長度: {len(embedding)}")
|
||||
else:
|
||||
print(f" - 嵌入向量: N/A")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 人臉處理器測試失敗: {e}")
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
|
||||
def test_api_endpoints():
|
||||
"""測試 API 端點配置"""
|
||||
print("\n=== 測試 API 端點配置 ===")
|
||||
|
||||
try:
|
||||
# 檢查 Rust 代碼編譯
|
||||
print("檢查 Rust 代碼編譯狀態...")
|
||||
|
||||
# 讀取 API 代碼
|
||||
api_file = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
||||
"src",
|
||||
"api",
|
||||
"face_recognition.rs",
|
||||
)
|
||||
|
||||
if os.path.exists(api_file):
|
||||
with open(api_file, "r") as f:
|
||||
content = f.read()
|
||||
|
||||
# 檢查關鍵函數是否存在(根據實際代碼)
|
||||
endpoints = [
|
||||
"register_face_api",
|
||||
"recognize_faces",
|
||||
"search_faces",
|
||||
"get_face_details",
|
||||
"list_faces",
|
||||
"delete_face",
|
||||
"get_recognition_results",
|
||||
"store_recognition_results",
|
||||
]
|
||||
|
||||
found_endpoints = []
|
||||
for endpoint in endpoints:
|
||||
if endpoint in content:
|
||||
found_endpoints.append(endpoint)
|
||||
|
||||
print(f"✅ 找到 {len(found_endpoints)}/{len(endpoints)} 個 API 端點:")
|
||||
for endpoint in found_endpoints:
|
||||
print(f" - {endpoint}")
|
||||
|
||||
if len(found_endpoints) == len(endpoints):
|
||||
print("✅ 所有 API 端點都已定義")
|
||||
else:
|
||||
missing = set(endpoints) - set(found_endpoints)
|
||||
print(f"⚠️ 缺少端點: {missing}")
|
||||
|
||||
# 檢查路由配置
|
||||
server_file = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
||||
"src",
|
||||
"api",
|
||||
"server.rs",
|
||||
)
|
||||
|
||||
if os.path.exists(server_file):
|
||||
with open(server_file, "r") as f:
|
||||
content = f.read()
|
||||
|
||||
if "face_recognition" in content and "merge" in content:
|
||||
print("✅ API 路由已正確配置")
|
||||
else:
|
||||
print("⚠️ API 路由配置可能不完整")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ API 端點測試失敗: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
"""主測試函數"""
|
||||
print("=" * 60)
|
||||
print("人臉識別集成測試")
|
||||
print("=" * 60)
|
||||
|
||||
tests = [
|
||||
("數據庫連接", test_database_connection),
|
||||
("InsightFace 模型", test_insightface_model),
|
||||
("人臉處理器", test_face_processor),
|
||||
("API 端點配置", test_api_endpoints),
|
||||
]
|
||||
|
||||
results = []
|
||||
|
||||
for test_name, test_func in tests:
|
||||
try:
|
||||
success = test_func()
|
||||
results.append((test_name, success))
|
||||
except Exception as e:
|
||||
print(f"❌ {test_name} 測試異常: {e}")
|
||||
results.append((test_name, False))
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("測試結果摘要")
|
||||
print("=" * 60)
|
||||
|
||||
passed = 0
|
||||
for test_name, success in results:
|
||||
status = "✅ 通過" if success else "❌ 失敗"
|
||||
print(f"{test_name}: {status}")
|
||||
if success:
|
||||
passed += 1
|
||||
|
||||
print(f"\n總計: {passed}/{len(results)} 個測試通過")
|
||||
|
||||
if passed == len(results):
|
||||
print("\n🎉 所有測試通過!人臉識別集成準備就緒。")
|
||||
return 0
|
||||
else:
|
||||
print(f"\n⚠️ 有 {len(results) - passed} 個測試失敗,請檢查問題。")
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user