- 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>
227 lines
7.6 KiB
Python
227 lines
7.6 KiB
Python
"""
|
|
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)
|