| """ |
| API Routes - 简化的路由处理 |
| 消除复杂的异步状态管理,直接返回结果 |
| """ |
| import base64 |
| from flask import Blueprint, request, jsonify |
| from .fal_client import FALClient, get_api_key_from_request, validate_generation_request, prepare_fal_arguments |
| from monitoring import log_api_call, log_generation_metrics, log_error, get_health_status, log_request_id |
|
|
| api = Blueprint('api', __name__) |
|
|
|
|
| @api.route('/generate', methods=['POST']) |
| @log_api_call |
| def generate(): |
| """ |
| 图像生成接口 - 简化为同步处理 |
| 消除复杂的请求跟踪和状态管理 |
| """ |
| try: |
| |
| data = request.json |
| validation = validate_generation_request(data) |
| if not validation['valid']: |
| return jsonify({'error': validation['error']}), 400 |
|
|
| |
| api_key = get_api_key_from_request(request) |
| if not api_key: |
| return jsonify({'error': 'API key not provided'}), 401 |
|
|
| |
| model_endpoint = request.headers.get('X-Model-Endpoint', 'fal-ai/bytedance/seedream/v4/edit') |
|
|
| |
| fal_arguments = prepare_fal_arguments(data, model_endpoint) |
|
|
| |
| log_generation_metrics( |
| model_endpoint, |
| len(data.get('prompt', '')), |
| len(data.get('image_urls', [])) |
| ) |
|
|
| |
| client = FALClient(api_key) |
| result = client.generate_image(model_endpoint, fal_arguments) |
|
|
| if result['success']: |
| |
| log_request_id( |
| result['request_id'], |
| action="generated", |
| model=model_endpoint, |
| prompt=data.get('prompt', '') |
| ) |
|
|
| return jsonify({ |
| 'status': 'submitted', |
| 'request_id': result['request_id'] |
| }), 200 |
| else: |
| return jsonify({ |
| 'status': 'error', |
| 'error': result['error'], |
| 'request_id': result['request_id'] |
| }), 500 |
|
|
| except Exception as e: |
| return jsonify({'error': str(e)}), 500 |
|
|
|
|
| @api.route('/status/<request_id>', methods=['GET']) |
| @log_api_call |
| def check_status(request_id): |
| """ |
| 检查生成状态 - 解决FAL子路径问题 |
| 按照专家建议,正确处理model endpoint的子路径 |
| """ |
| try: |
| |
| api_key = get_api_key_from_request(request) |
| if not api_key: |
| return jsonify({'error': 'API key not provided'}), 401 |
|
|
| |
| model_endpoint = request.headers.get('X-Model-Endpoint', 'fal-ai/bytedance/seedream/v4/edit') |
|
|
| |
| client = FALClient(api_key) |
| result = client.get_status(model_endpoint, request_id) |
|
|
| if result['success']: |
| response = { |
| 'request_id': request_id, |
| 'status': result['status'], |
| 'logs': result['logs'] |
| } |
|
|
| |
| if 'queue_position' in result: |
| response['queue_position'] = result['queue_position'] |
|
|
| |
| if result.get('result'): |
| response['result'] = result['result'] |
|
|
| return jsonify(response), 200 |
| else: |
| |
| return jsonify({ |
| 'request_id': request_id, |
| 'status': 'error', |
| 'error': result['error'] |
| }), 200 |
|
|
| except Exception as e: |
| |
| return jsonify({ |
| 'request_id': request_id, |
| 'status': 'error', |
| 'error': str(e) |
| }), 200 |
|
|
|
|
| @api.route('/upload', methods=['POST']) |
| def upload_file(): |
| """文件上传接口 - 简化处理""" |
| try: |
| if 'file' not in request.files: |
| return jsonify({'error': 'No file provided'}), 400 |
|
|
| file = request.files['file'] |
| if file.filename == '': |
| return jsonify({'error': 'No file selected'}), 400 |
|
|
| |
| file_content = file.read() |
| file_type = file.content_type or 'application/octet-stream' |
| base64_content = base64.b64encode(file_content).decode('utf-8') |
| data_url = f"data:{file_type};base64,{base64_content}" |
|
|
| return jsonify({'url': data_url}), 200 |
|
|
| except Exception as e: |
| return jsonify({'error': str(e)}), 500 |
|
|
|
|
| @api.route('/upload-to-fal', methods=['POST']) |
| def upload_to_fal(): |
| """上传到FAL存储 - 简化处理""" |
| try: |
| data = request.json |
| if 'image_data' not in data: |
| return jsonify({'error': 'No image data provided'}), 400 |
|
|
| |
| api_key = get_api_key_from_request(request) |
| if not api_key: |
| return jsonify({'error': 'API key not provided'}), 401 |
|
|
| |
| client = FALClient(api_key) |
| result = client.upload_file(data['image_data']) |
|
|
| if result['success']: |
| return jsonify({'url': result['url']}), 200 |
| else: |
| return jsonify({'error': result['error']}), 500 |
|
|
| except Exception as e: |
| return jsonify({'error': str(e)}), 500 |
|
|
|
|
| @api.route('/health', methods=['GET']) |
| def health_check(): |
| """健康检查""" |
| return jsonify(get_health_status()), 200 |