from flask import jsonify, request, make_response, Blueprint, current_app, send_file from app.api.data_parse import bp from app.core.data_parse.parse import parse_data, process_business_card, update_business_card, get_business_cards, update_business_card_status, create_talent_tag, get_talent_tag_list, update_talent_tag, delete_talent_tag from app.config.config import DevelopmentConfig, ProductionConfig import logging import boto3 from botocore.config import Config from botocore.exceptions import ClientError from io import BytesIO import base64 import os import urllib.parse from minio import Minio # Define logger logger = logging.getLogger(__name__) # For failure responses def failed(message, code=500): return { 'success': False, 'message': message, 'data': None }, code # 根据环境选择配置 if os.environ.get('FLASK_ENV') == 'production': config = ProductionConfig() else: config = DevelopmentConfig() # 使用配置变量 minio_url = f"{'https' if config.MINIO_SECURE else 'http'}://{config.MINIO_HOST}" minio_access_key = config.MINIO_USER minio_secret_key = config.MINIO_PASSWORD minio_bucket = config.MINIO_BUCKET use_ssl = config.MINIO_SECURE def get_minio_client(): """获取 MinIO 客户端实例""" return Minio( '192.168.3.143:9000', access_key=config.MINIO_USER, secret_key=config.MINIO_PASSWORD, secure=config.MINIO_SECURE ) # 测试用的解析数据接口。没有实际使用。 @bp.route('/parse', methods=['POST']) def parse(): """ 解析数据的接口 """ try: data = request.get_json() if not data: return jsonify({'error': 'No data provided'}), 400 result = parse_data(data) return jsonify(result), 200 except Exception as e: return jsonify({'error': str(e)}), 500 # 名片解析接口 @bp.route('/business-card-parse', methods=['POST']) def parse_business_card_route(): """ 处理名片图片并提取信息的API接口 请求参数: - image: 名片图片文件 (multipart/form-data) 返回: - JSON: 包含提取的名片信息和处理状态 """ # 检查是否上传了文件 if 'image' not in request.files: return jsonify({ 'success': False, 'message': '未上传图片', 'data': None }), 400 image_file = request.files['image'] # 检查文件是否为空 if image_file.filename == '': return jsonify({ 'success': False, 'message': '未选择文件', 'data': None }), 400 # 检查文件类型是否为图片 if not image_file.content_type.startswith('image/'): return jsonify({ 'success': False, 'message': '上传的文件不是图片', 'data': None }), 400 # 处理名片图片 result = process_business_card(image_file) if result['success']: return jsonify(result), 200 else: return jsonify(result), 500 # 更新名片信息接口 @bp.route('/business-cards/', methods=['PUT']) def update_business_card_route(card_id): """ 更新名片信息的API接口 路径参数: - card_id: 名片记录ID 请求参数: - JSON格式的名片信息 返回: - JSON: 包含更新后的名片信息和处理状态 """ # 获取请求数据 data = request.json if not data: return jsonify({ 'success': False, 'message': '请求数据为空', 'data': None }), 400 # 调用业务逻辑函数处理更新 result = update_business_card(card_id, data) # 根据处理结果设置HTTP状态码 status_code = 200 if result['success'] else 500 if 'not found' in result.get('message', '').lower() or '未找到' in result.get('message', ''): status_code = 404 return jsonify(result), status_code # 获取所有名片记录的API接口 @bp.route('/get-business-cards', methods=['GET']) def get_business_cards_route(): """ 获取所有名片记录的API接口 返回: - JSON: 包含名片记录列表和处理状态 """ # 调用业务逻辑函数获取名片列表 result = get_business_cards() # 根据处理结果设置HTTP状态码 status_code = 200 if result['success'] else 500 return jsonify(result), status_code @bp.route('/update-business-cards//status', methods=['PUT']) def update_business_card_status_route(card_id): """ 更新名片状态的API接口 路径参数: - card_id: 名片记录ID 请求参数: - JSON格式,包含status字段 返回: - JSON: 包含更新后的名片信息和处理状态 """ # 获取请求数据 data = request.json if not data or 'status' not in data: return jsonify({ 'success': False, 'message': '请求数据为空或缺少status字段', 'data': None }), 400 status = data['status'] # 调用业务逻辑函数处理状态更新 result = update_business_card_status(card_id, status) # 根据处理结果设置HTTP状态码 status_code = 200 if result['success'] else 500 if 'not found' in result.get('message', '').lower() or '未找到' in result.get('message', ''): status_code = 404 return jsonify(result), status_code # 从MinIO获取名片图片的API接口 @bp.route('/business-cards/image/', methods=['GET']) def get_business_card_image(image_path): """ 从MinIO获取名片图片的API接口 路径参数: - image_path: MinIO中的图片路径 返回: - 图片数据流 """ try: # 记录下载请求信息,便于调试 logger.info(f"获取名片图片请求: {image_path}") # 获取 MinIO 客户端 minio_client = get_minio_client() if not minio_client: return jsonify(failed("MinIO客户端初始化失败")), 500 try: # 使用正确的MinIO客户端方法 data = minio_client.get_object(minio_bucket, image_path) # 创建内存文件流 file_stream = BytesIO(data.read()) # 获取文件名 file_name = image_path.split('/')[-1] # 返回文件 return send_file( file_stream, as_attachment=False, # 设置为False,让浏览器直接显示图片 download_name=file_name, mimetype='image/jpeg' # 根据实际图片类型设置 ) except Exception as e: logger.error(f"MinIO获取文件失败: {str(e)}") return jsonify(failed(f"文件获取失败: {str(e)}")), 404 except Exception as e: logger.error(f"文件下载失败: {str(e)}") return jsonify(failed(str(e))), 500 finally: # 确保关闭数据流 if 'data' in locals(): data.close() # 创建人才标签接口 @bp.route('/create-talent-tag', methods=['POST']) def create_talent_tag_route(): """ 创建人才标签的API接口 请求参数: - JSON格式,包含以下字段: - name: 标签名称 - category: 标签分类 - description: 标签描述 - status: 启用状态,默认为'active' 返回: - JSON: 包含创建结果和标签信息 """ try: # 获取请求数据 data = request.get_json() if not data: return jsonify({ 'success': False, 'message': '请求数据为空', 'data': None }), 400 # 验证必要字段 if 'name' not in data or not data['name']: return jsonify({ 'success': False, 'message': '标签名称不能为空', 'data': None }), 400 # 处理分类字段,如果未提供则设置默认值 if 'category' not in data or not data['category']: data['category'] = '未分类' # 调用业务逻辑函数处理创建 result = create_talent_tag(data) # 根据处理结果设置HTTP状态码 status_code = 200 if result['success'] else 500 return jsonify(result), status_code except Exception as e: logger.error(f"创建人才标签失败: {str(e)}") return jsonify({ 'success': False, 'message': f'创建人才标签失败: {str(e)}', 'data': None }), 500 # 获取人才标签列表接口 @bp.route('/get-talent-tag-list', methods=['GET']) def get_talent_tag_list_route(): """ 获取人才标签列表的API接口 返回: - JSON: 包含人才标签列表和处理状态 """ try: # 调用业务逻辑函数获取人才标签列表 result = get_talent_tag_list() # 根据处理结果设置HTTP状态码 status_code = 200 if result['success'] else 500 return jsonify(result), status_code except Exception as e: logger.error(f"获取人才标签列表失败: {str(e)}") return jsonify({ 'success': False, 'message': f'获取人才标签列表失败: {str(e)}', 'data': [] }), 500 # 更新人才标签接口 @bp.route('/update-talent-tag/', methods=['PUT']) def update_talent_tag_route(tag_id): """ 更新人才标签的API接口 路径参数: - tag_id: 标签节点ID 请求参数: - JSON格式,可能包含以下字段: - name: 标签名称 - category: 标签分类 - description: 标签描述 - status: 启用状态 返回: - JSON: 包含更新结果和标签信息 """ try: # 获取请求数据 data = request.get_json() if not data: return jsonify({ 'success': False, 'message': '请求数据为空', 'data': None }), 400 # 调用业务逻辑函数处理更新 result = update_talent_tag(tag_id, data) # 根据处理结果设置HTTP状态码 if not result['success']: if result['code'] == 404: status_code = 404 elif result['code'] == 400: status_code = 400 else: status_code = 500 else: status_code = 200 return jsonify(result), status_code except Exception as e: logger.error(f"更新人才标签失败: {str(e)}") return jsonify({ 'success': False, 'message': f'更新人才标签失败: {str(e)}', 'data': None }), 500 # 删除人才标签接口 @bp.route('/delete-talent-tag/', methods=['DELETE']) def delete_talent_tag_route(tag_id): """ 删除人才标签的API接口 路径参数: - tag_id: 标签节点ID 返回: - JSON: 包含删除结果和被删除的标签信息 """ try: # 调用业务逻辑函数执行删除 result = delete_talent_tag(tag_id) # 根据处理结果设置HTTP状态码 if not result['success']: if result['code'] == 404: status_code = 404 else: status_code = 500 else: status_code = 200 return jsonify(result), status_code except Exception as e: logger.error(f"删除人才标签失败: {str(e)}") return jsonify({ 'success': False, 'message': f'删除人才标签失败: {str(e)}', 'data': None }), 500