from flask import Blueprint, request, jsonify import os from datetime import datetime from video_service import get_video_service from task_queue_manager import get_queue_manager # 创建蓝图 api_bp = Blueprint('api', __name__) @api_bp.route('/api/video/create', methods=['POST']) def create_video_task(): """创建视频生成任务""" content_type = request.content_type # print(f"Content-Type: {content_type}") # print(f"Files: {request.files}") # print(f"Form: {request.form}") # 检查是否为文件上传模式 if content_type and 'multipart/form-data' in content_type: # 文件上传模式 if 'image_file' not in request.files: return jsonify({ 'success': False, 'error': '缺少必需的参数: image_file' }), 400 image_file = request.files['image_file'] if image_file.filename == '': return jsonify({ 'success': False, 'error': '未选择文件' }), 400 # 读取图片文件并进行Base64编码 import base64 image_data = image_file.read() image_base64 = base64.b64encode(image_data).decode('utf-8') # 构建image_url image_url = f"data:image/{image_file.filename.split('.')[-1]};base64,{image_base64}" # 从表单数据获取其他参数 prompt = request.form.get('prompt', '') duration = request.form.get('duration') callback_url = request.form.get('callback_url') elif content_type and 'application/json' in content_type: # JSON请求模式 data = request.get_json() if not data: return jsonify({ 'success': False, 'error': '无效的JSON数据' }), 400 image_url = data.get('image_url') prompt = data.get('prompt', '') duration = data.get('duration') callback_url = data.get('callback_url') if not image_url: return jsonify({ 'success': False, 'error': '缺少必需的参数: image_url' }), 400 else: return jsonify({ 'success': False, 'error': '不支持的请求类型,请使用multipart/form-data或application/json' }), 400 # 验证必需参数 if not prompt: return jsonify({ 'success': False, 'error': '缺少必需的参数: prompt' }), 400 # 构建content content = { 'image_url': image_url, 'prompt': prompt } # 构建parameters parameters = {} if duration is not None and duration != '': try: parameters['duration'] = float(duration) except (ValueError, TypeError): return jsonify({ 'success': False, 'error': 'duration参数必须是数字' }), 400 try: # 获取队列管理器 queue_manager = get_queue_manager() # 检查是否可以直接创建任务 if queue_manager.can_create_task(): # 直接创建任务 video_service = get_video_service() result = video_service.create_video_generation_task(content, callback_url, parameters) if result['success']: task_data = result['data'] task_data['status'] = 'running' # 设置初始状态 # 添加到运行队列 queue_manager.add_task_to_queue(task_data) return jsonify({ 'success': True, 'data': task_data, 'queue_status': 'running' }) else: return jsonify({ 'success': False, 'error': result['error'] }), 500 else: # 队列已满,创建任务但加入等待队列 video_service = get_video_service() result = video_service.create_video_generation_task(content, callback_url, parameters) if result['success']: task_data = result['data'] task_data['status'] = 'waiting' # 设置等待状态 # 添加到等待队列 queue_manager.add_task_to_queue(task_data) return jsonify({ 'success': True, 'data': task_data, 'queue_status': 'waiting', 'message': '任务已创建并加入等待队列,将在有空闲位置时开始执行' }) else: return jsonify({ 'success': False, 'error': result['error'] }), 500 except Exception as e: return jsonify({ 'success': False, 'error': f'创建任务失败: {str(e)}' }), 500 @api_bp.route('/api/video/status/', methods=['GET']) def get_task_status(task_id): """查询任务状态""" video_service = get_video_service() result = video_service.get_task_status(task_id) if result['success']: return jsonify({ 'success': True, 'data': result['data'] }) else: return jsonify({ 'success': False, 'error': result['error'] }), 500 @api_bp.route('/api/video/result/', methods=['GET']) def get_task_result(task_id): """获取任务结果""" try: # 先从缓存查询 queue_manager = get_queue_manager() cached_task = queue_manager.get_task_from_cache(task_id) if cached_task: # 从缓存返回结果 task_data = cached_task print(f"从缓存获取结果: {task_id}") else: # 缓存中没有,调用SDK查询 print(f"缓存中没有,调用SDK查询: {task_id}") video_service = get_video_service() result = video_service.get_task_status(task_id) if not result['success']: return jsonify({ 'success': False, 'error': result['error'] }), 500 task_data = result['data'] # 检查任务状态 if task_data['status'] == 'succeeded': return jsonify({ 'success': True, 'data': { 'task_id': task_data['task_id'], 'status': task_data['status'], 'video_url': task_data.get('content', {}).get('video_url') if task_data.get('content') else None, 'created_at': task_data.get('created_at'), 'updated_at': task_data.get('updated_at') } }) elif task_data['status'] == 'failed': return jsonify({ 'success': False, 'error': f"任务失败: {task_data.get('error', '未知错误')}" }), 500 elif task_data['status'] == 'not_found': return jsonify({ 'success': False, 'error': '任务不存在或已被删除' }), 404 else: return jsonify({ 'success': True, 'data': { 'task_id': task_data['task_id'], 'status': task_data['status'], 'message': '任务正在处理中,请稍后查询' } }) except Exception as e: return jsonify({ 'success': False, 'error': f'查询异常: {str(e)}' }), 500 @api_bp.route('/api/video/tasks', methods=['GET']) def get_task_list(): """获取任务列表""" limit = request.args.get('limit', 20, type=int) offset = request.args.get('offset', 0, type=int) try: # 验证参数 if limit < 1 or limit > 100: return jsonify({ 'success': False, 'error': 'limit必须在1-100之间' }), 400 if offset < 0: return jsonify({ 'success': False, 'error': 'offset必须大于等于0' }), 400 # 调用火山引擎API获取任务列表 video_service = get_video_service() result = video_service.get_task_list(limit, offset) if result['success']: task_data = result['data'] return jsonify({ 'success': True, 'data': task_data }) else: return jsonify({ 'success': False, 'error': result['error'] }), 500 except Exception as e: return jsonify({ 'success': False, 'error': f'获取任务列表失败: {str(e)}' }), 500 @api_bp.route('/api/video/cancel/', methods=['DELETE']) def cancel_task(task_id): """删除任务""" try: # 调用火山引擎API删除任务 video_service = get_video_service() result = video_service.delete_task(task_id) if result['success']: # 同时从队列管理器中删除缓存 queue_manager = get_queue_manager() queue_manager.remove_task_from_cache(task_id) return jsonify({ 'success': True, 'message': '任务删除成功' }) else: return jsonify({ 'success': False, 'error': result['error'] }), 500 except Exception as e: return jsonify({ 'success': False, 'error': f'删除任务失败: {str(e)}' }), 500 @api_bp.route('/api/video/queue/status', methods=['GET']) def get_queue_status(): """获取队列状态""" try: queue_manager = get_queue_manager() status = queue_manager.get_queue_status() return jsonify({ 'success': True, 'data': status }) except Exception as e: return jsonify({ 'success': False, 'error': f'获取队列状态失败: {str(e)}' }), 500 @api_bp.route('/health', methods=['GET']) def health_check(): """健康检查""" return jsonify({ 'status': 'healthy', 'timestamp': datetime.now().isoformat(), 'service': 'video-generation-api' }) @api_bp.route('/queue', methods=['GET']) def status_check(): """状态检测""" try: queue_manager = get_queue_manager() status = queue_manager.get_queue_status() queue_running = status['running_task_ids'] queue_pending = status['waiting_task_ids'] return jsonify({ 'queue_running': queue_running, 'queue_pending': queue_pending }) except Exception as e: return jsonify({ 'queue_running': [], 'queue_pending': [] }), 500