app.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. from flask import Flask, request, jsonify
  2. import os
  3. from image_search import ImageSearchEngine
  4. import time
  5. import config
  6. app = Flask(__name__)
  7. os.makedirs(config.UPLOAD_FOLDER, exist_ok=True)
  8. # 初始化图像搜索引擎
  9. search_engine = ImageSearchEngine()
  10. def allowed_file(filename):
  11. """检查文件是否允许上传"""
  12. return '.' in filename and filename.rsplit('.', 1)[1].lower() in config.ALLOWED_EXTENSIONS
  13. @app.route('/add', methods=['POST'])
  14. def add_image_file():
  15. """处理图片上传请求"""
  16. try:
  17. # 获取并验证参数
  18. data = request.get_json()
  19. if not data:
  20. return jsonify({'error': '请求必须包含JSON数据'}), 400
  21. product_id = data.get('imageId')
  22. image_url = data.get('url')
  23. if not product_id:
  24. return jsonify({'error': '缺少product_id参数'}), 400
  25. if not image_url:
  26. return jsonify({'error': '缺少url参数'}), 400
  27. if not isinstance(image_url, str) or not (image_url.startswith('http://') or image_url.startswith('https://')):
  28. return jsonify({'error': '无效的图片URL'}), 400
  29. # 添加图片到搜索引擎
  30. if search_engine.add_image_from_url(image_url, product_id):
  31. return jsonify({'message': '上传成功', 'product_id': product_id})
  32. else:
  33. return jsonify({'error': '处理图片失败'}), 500
  34. except Exception as e:
  35. return jsonify({'error': str(e)}), 500
  36. @app.route('/search', methods=['POST'])
  37. def search():
  38. """处理图片搜索请求"""
  39. try:
  40. # 获取并验证参数
  41. data = request.get_json()
  42. if not data:
  43. return jsonify({'error': '请求必须包含JSON数据'}), 400
  44. image_url = data.get('url')
  45. if not image_url:
  46. return jsonify({'error': '缺少url参数'}), 400
  47. if not isinstance(image_url, str) or not (image_url.startswith('http://') or image_url.startswith('https://')):
  48. return jsonify({'error': '无效的图片URL'}), 400
  49. print(f"search payload, type:{type(data)}, data: {data}")
  50. # 获取可选参数
  51. limit = data.get('limit', config.TOP_K)
  52. min_score = data.get('min_score', config.MIN_SCORE)
  53. max_score = data.get('max_score', config.MAX_SCORE)
  54. # 验证参数类型和范围
  55. try:
  56. limit = int(limit)
  57. min_score = float(min_score)
  58. max_score = float(max_score)
  59. if limit <= 0:
  60. return jsonify({'error': 'limit必须大于0'}), 400
  61. if min_score < 0 or min_score > 1.0:
  62. return jsonify({'error': 'min_score必须在0到1之间'}), 400
  63. if max_score < 0 or max_score > 1.0:
  64. return jsonify({'error': 'max_score必须在0到1之间'}), 400
  65. if min_score > max_score:
  66. return jsonify({'error': 'min_score不能大于max_score'}), 400
  67. except ValueError:
  68. return jsonify({'error': '参数类型错误'}), 400
  69. print(f"search apply limit:{limit} min_score:{min_score} max_score:{max_score}")
  70. start_search_time = time.time()
  71. results = search_engine.search(image_url, top_k=limit)
  72. # 格式化结果并过滤不在分数范围内的结果
  73. formatted_results = []
  74. for product_id, score in results:
  75. similarity = score # 转换为百分比
  76. if min_score <= similarity <= max_score:
  77. formatted_results.append({
  78. 'Id': product_id,
  79. 'Score': similarity
  80. })
  81. end_search_time = time.time()
  82. print(f"搜索耗时: { end_search_time - start_search_time } s",)
  83. return jsonify(formatted_results), 200
  84. except Exception as e:
  85. return jsonify({'error': str(e)}), 500
  86. @app.route('/remove/<product_id>', methods=['POST'])
  87. def remove_image(product_id):
  88. """移除指定商品ID的图片特征"""
  89. try:
  90. # 从索引中移除
  91. if search_engine.remove_by_product_id(product_id):
  92. return jsonify({'message': '删除成功', 'product_id': product_id})
  93. else:
  94. return jsonify({'error': '商品ID不存在或删除失败'}), 404
  95. except Exception as e:
  96. return jsonify({'error': str(e)}), 500
  97. @app.route('/clear/<password>', methods=['POST'])
  98. def clear_index(password):
  99. """清空索引"""
  100. if password == "infish@2025":
  101. try:
  102. search_engine.clear()
  103. except Exception as e:
  104. return jsonify({'error': str(e)}), 500
  105. if __name__ == '__main__':
  106. app.run(host='0.0.0.0', port=5000, debug=False)