v1.0 - Version stable: multi-PC, détection UI-DETR-1, 3 modes exécution
- Frontend v4 accessible sur réseau local (192.168.1.40) - Ports ouverts: 3002 (frontend), 5001 (backend), 5004 (dashboard) - Ollama GPU fonctionnel - Self-healing interactif - Dashboard confiance Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
226
visual_workflow_builder/backend/api/templates.py
Normal file
226
visual_workflow_builder/backend/api/templates.py
Normal file
@@ -0,0 +1,226 @@
|
||||
"""
|
||||
Templates API Blueprint
|
||||
|
||||
Provides REST endpoints for workflow template management.
|
||||
"""
|
||||
|
||||
from flask import Blueprint, request, jsonify
|
||||
import logging
|
||||
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from services.template_service import TemplateService
|
||||
from services.serialization import WorkflowSerializer
|
||||
from api.errors import handle_api_error
|
||||
|
||||
templates_bp = Blueprint('templates', __name__)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Initialize services
|
||||
template_service = TemplateService()
|
||||
workflow_serializer = WorkflowSerializer()
|
||||
|
||||
@templates_bp.route('/', methods=['GET'])
|
||||
def list_templates():
|
||||
"""List all templates with optional filtering"""
|
||||
try:
|
||||
# Get query parameters
|
||||
category = request.args.get('category')
|
||||
difficulty = request.args.get('difficulty')
|
||||
|
||||
# Get templates
|
||||
templates = template_service.list_templates(category=category, difficulty=difficulty)
|
||||
|
||||
# Convert to dict format
|
||||
result = []
|
||||
for template in templates:
|
||||
template_dict = template.to_dict()
|
||||
# Remove the full workflow from list view for performance
|
||||
template_dict.pop('workflow', None)
|
||||
result.append(template_dict)
|
||||
|
||||
return jsonify({
|
||||
'templates': result,
|
||||
'count': len(result)
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error listing templates: {e}")
|
||||
return handle_api_error(e)
|
||||
|
||||
@templates_bp.route('/', methods=['POST'])
|
||||
def create_template():
|
||||
"""Create a new template"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
|
||||
if not data:
|
||||
return jsonify({'error': 'No data provided'}), 400
|
||||
|
||||
# Create template
|
||||
template = template_service.create_template(data)
|
||||
|
||||
logger.info(f"Created template: {template.id}")
|
||||
return jsonify(template.to_dict()), 201
|
||||
|
||||
except ValueError as e:
|
||||
logger.warning(f"Template validation error: {e}")
|
||||
return jsonify({'error': str(e)}), 400
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating template: {e}")
|
||||
return handle_api_error(e)
|
||||
|
||||
@templates_bp.route('/<template_id>', methods=['GET'])
|
||||
def get_template(template_id):
|
||||
"""Get a specific template"""
|
||||
try:
|
||||
template = template_service.get_template(template_id)
|
||||
|
||||
if not template:
|
||||
return jsonify({'error': 'Template not found'}), 404
|
||||
|
||||
return jsonify(template.to_dict())
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting template {template_id}: {e}")
|
||||
return handle_api_error(e)
|
||||
|
||||
@templates_bp.route('/<template_id>', methods=['PUT'])
|
||||
def update_template(template_id):
|
||||
"""Update an existing template"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
|
||||
if not data:
|
||||
return jsonify({'error': 'No data provided'}), 400
|
||||
|
||||
template = template_service.update_template(template_id, data)
|
||||
|
||||
if not template:
|
||||
return jsonify({'error': 'Template not found'}), 404
|
||||
|
||||
logger.info(f"Updated template: {template_id}")
|
||||
return jsonify(template.to_dict())
|
||||
|
||||
except ValueError as e:
|
||||
logger.warning(f"Template validation error: {e}")
|
||||
return jsonify({'error': str(e)}), 400
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating template {template_id}: {e}")
|
||||
return handle_api_error(e)
|
||||
|
||||
@templates_bp.route('/<template_id>', methods=['DELETE'])
|
||||
def delete_template(template_id):
|
||||
"""Delete a template"""
|
||||
try:
|
||||
success = template_service.delete_template(template_id)
|
||||
|
||||
if not success:
|
||||
return jsonify({'error': 'Template not found'}), 404
|
||||
|
||||
logger.info(f"Deleted template: {template_id}")
|
||||
return jsonify({'message': 'Template deleted successfully'})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting template {template_id}: {e}")
|
||||
return handle_api_error(e)
|
||||
|
||||
@templates_bp.route('/<template_id>/instantiate', methods=['POST'])
|
||||
def instantiate_template(template_id):
|
||||
"""Create a workflow from a template"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
|
||||
if not data:
|
||||
return jsonify({'error': 'No data provided'}), 400
|
||||
|
||||
# Extract parameters
|
||||
parameters = data.get('parameters', {})
|
||||
workflow_name = data.get('name', f'Workflow from template {template_id}')
|
||||
created_by = data.get('created_by', 'user')
|
||||
|
||||
# Create workflow instance
|
||||
workflow = template_service.instantiate_template(
|
||||
template_id, parameters, workflow_name, created_by
|
||||
)
|
||||
|
||||
if not workflow:
|
||||
return jsonify({'error': 'Template not found'}), 404
|
||||
|
||||
# Save the workflow
|
||||
workflow_data = workflow_serializer.serialize(workflow)
|
||||
workflow_id = workflow_serializer.save_workflow(workflow_data)
|
||||
|
||||
logger.info(f"Instantiated template {template_id} as workflow {workflow_id}")
|
||||
return jsonify({
|
||||
'workflow_id': workflow_id,
|
||||
'workflow': workflow.to_dict()
|
||||
}), 201
|
||||
|
||||
except ValueError as e:
|
||||
logger.warning(f"Template instantiation error: {e}")
|
||||
return jsonify({'error': str(e)}), 400
|
||||
except Exception as e:
|
||||
logger.error(f"Error instantiating template {template_id}: {e}")
|
||||
return handle_api_error(e)
|
||||
|
||||
@templates_bp.route('/from-workflow', methods=['POST'])
|
||||
def create_template_from_workflow():
|
||||
"""Create a template from an existing workflow"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
|
||||
if not data:
|
||||
return jsonify({'error': 'No data provided'}), 400
|
||||
|
||||
# Extract required fields
|
||||
workflow_id = data.get('workflow_id')
|
||||
template_name = data.get('template_name')
|
||||
template_description = data.get('template_description')
|
||||
category = data.get('category', 'Custom')
|
||||
parameters = data.get('parameters', [])
|
||||
|
||||
if not all([workflow_id, template_name, template_description]):
|
||||
return jsonify({
|
||||
'error': 'workflow_id, template_name, and template_description are required'
|
||||
}), 400
|
||||
|
||||
# Load the workflow
|
||||
workflow_data = workflow_serializer.load_workflow(workflow_id)
|
||||
if not workflow_data:
|
||||
return jsonify({'error': 'Workflow not found'}), 404
|
||||
|
||||
workflow = workflow_serializer.deserialize(workflow_data)
|
||||
|
||||
# Create template
|
||||
template = template_service.create_template_from_workflow(
|
||||
workflow, template_name, template_description, category, parameters
|
||||
)
|
||||
|
||||
logger.info(f"Created template {template.id} from workflow {workflow_id}")
|
||||
return jsonify(template.to_dict()), 201
|
||||
|
||||
except ValueError as e:
|
||||
logger.warning(f"Template creation error: {e}")
|
||||
return jsonify({'error': str(e)}), 400
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating template from workflow: {e}")
|
||||
return handle_api_error(e)
|
||||
|
||||
@templates_bp.route('/categories', methods=['GET'])
|
||||
def get_template_categories():
|
||||
"""Get all available template categories"""
|
||||
try:
|
||||
templates = template_service.list_templates()
|
||||
categories = list(set(template.category for template in templates))
|
||||
categories.sort()
|
||||
|
||||
return jsonify({
|
||||
'categories': categories
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting template categories: {e}")
|
||||
return handle_api_error(e)
|
||||
Reference in New Issue
Block a user