330 lines
10 KiB
Python
330 lines
10 KiB
Python
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/<task_id>', 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/<task_id>', 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/<task_id>', 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'
|
||
}) |