- 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>
200 lines
6.9 KiB
Python
200 lines
6.9 KiB
Python
"""
|
|
Template Data Models
|
|
|
|
Contains data models for workflow templates and template parameters.
|
|
"""
|
|
|
|
from dataclasses import dataclass, field
|
|
from datetime import datetime
|
|
from enum import Enum
|
|
from typing import Any, Dict, List, Optional
|
|
from uuid import uuid4
|
|
|
|
from .visual_workflow import VisualWorkflow, ParameterType
|
|
|
|
|
|
class TemplateDifficulty(Enum):
|
|
"""Difficulty levels for templates"""
|
|
BEGINNER = 'beginner'
|
|
INTERMEDIATE = 'intermediate'
|
|
ADVANCED = 'advanced'
|
|
|
|
|
|
@dataclass
|
|
class TemplateParameter:
|
|
"""Configurable parameter for a template"""
|
|
name: str
|
|
type: ParameterType
|
|
description: str
|
|
default_value: Optional[Any] = None
|
|
|
|
# Mapping to workflow nodes
|
|
node_id: str = ""
|
|
parameter_name: str = ""
|
|
|
|
# UI hints
|
|
label: str = ""
|
|
placeholder: Optional[str] = None
|
|
required: bool = True
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
return {
|
|
'name': self.name,
|
|
'type': self.type.value,
|
|
'description': self.description,
|
|
'default_value': self.default_value,
|
|
'node_id': self.node_id,
|
|
'parameter_name': self.parameter_name,
|
|
'label': self.label,
|
|
'placeholder': self.placeholder,
|
|
'required': self.required
|
|
}
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: Dict[str, Any]) -> 'TemplateParameter':
|
|
return cls(
|
|
name=data['name'],
|
|
type=ParameterType(data['type']),
|
|
description=data['description'],
|
|
default_value=data.get('default_value'),
|
|
node_id=data.get('node_id', ''),
|
|
parameter_name=data.get('parameter_name', ''),
|
|
label=data.get('label', ''),
|
|
placeholder=data.get('placeholder'),
|
|
required=data.get('required', True)
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class WorkflowTemplate:
|
|
"""Template for creating workflows"""
|
|
id: str
|
|
name: str
|
|
description: str
|
|
category: str
|
|
|
|
# Template workflow structure
|
|
workflow: VisualWorkflow
|
|
|
|
# Configurable parameters
|
|
parameters: List[TemplateParameter] = field(default_factory=list)
|
|
|
|
# Metadata
|
|
tags: List[str] = field(default_factory=list)
|
|
difficulty: TemplateDifficulty = TemplateDifficulty.BEGINNER
|
|
estimated_time: int = 5 # minutes
|
|
|
|
# Usage statistics
|
|
usage_count: int = 0
|
|
rating: float = 0.0
|
|
|
|
# Timestamps
|
|
created_at: datetime = field(default_factory=datetime.now)
|
|
updated_at: datetime = field(default_factory=datetime.now)
|
|
created_by: str = "system"
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
return {
|
|
'id': self.id,
|
|
'name': self.name,
|
|
'description': self.description,
|
|
'category': self.category,
|
|
'workflow': self.workflow.to_dict(),
|
|
'parameters': [p.to_dict() for p in self.parameters],
|
|
'tags': self.tags,
|
|
'difficulty': self.difficulty.value,
|
|
'estimated_time': self.estimated_time,
|
|
'usage_count': self.usage_count,
|
|
'rating': self.rating,
|
|
'created_at': self.created_at.isoformat(),
|
|
'updated_at': self.updated_at.isoformat(),
|
|
'created_by': self.created_by
|
|
}
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: Dict[str, Any]) -> 'WorkflowTemplate':
|
|
return cls(
|
|
id=data['id'],
|
|
name=data['name'],
|
|
description=data['description'],
|
|
category=data['category'],
|
|
workflow=VisualWorkflow.from_dict(data['workflow']),
|
|
parameters=[TemplateParameter.from_dict(p) for p in data.get('parameters', [])],
|
|
tags=data.get('tags', []),
|
|
difficulty=TemplateDifficulty(data.get('difficulty', 'beginner')),
|
|
estimated_time=data.get('estimated_time', 5),
|
|
usage_count=data.get('usage_count', 0),
|
|
rating=data.get('rating', 0.0),
|
|
created_at=datetime.fromisoformat(data.get('created_at', datetime.now().isoformat())),
|
|
updated_at=datetime.fromisoformat(data.get('updated_at', datetime.now().isoformat())),
|
|
created_by=data.get('created_by', 'system')
|
|
)
|
|
|
|
def instantiate(self, parameters: Dict[str, Any], workflow_name: str, created_by: str = "user") -> VisualWorkflow:
|
|
"""Create a new workflow instance from this template"""
|
|
# Create a copy of the template workflow
|
|
workflow_data = self.workflow.to_dict()
|
|
|
|
# Generate new IDs
|
|
workflow_data['id'] = str(uuid4())
|
|
workflow_data['name'] = workflow_name
|
|
workflow_data['created_at'] = datetime.now().isoformat()
|
|
workflow_data['updated_at'] = datetime.now().isoformat()
|
|
workflow_data['created_by'] = created_by
|
|
workflow_data['is_template'] = False
|
|
|
|
# Apply parameter substitutions
|
|
for param in self.parameters:
|
|
if param.name in parameters:
|
|
value = parameters[param.name]
|
|
|
|
# Find the target node and update its parameter
|
|
for node_data in workflow_data['nodes']:
|
|
if node_data['id'] == param.node_id:
|
|
node_data['parameters'][param.parameter_name] = value
|
|
break
|
|
|
|
# Generate new node and edge IDs to avoid conflicts
|
|
node_id_mapping = {}
|
|
for i, node_data in enumerate(workflow_data['nodes']):
|
|
old_id = node_data['id']
|
|
new_id = f"{workflow_data['id']}_node_{i}"
|
|
node_id_mapping[old_id] = new_id
|
|
node_data['id'] = new_id
|
|
|
|
# Update edge references
|
|
for edge_data in workflow_data['edges']:
|
|
edge_data['id'] = str(uuid4())
|
|
edge_data['source'] = node_id_mapping.get(edge_data['source'], edge_data['source'])
|
|
edge_data['target'] = node_id_mapping.get(edge_data['target'], edge_data['target'])
|
|
|
|
return VisualWorkflow.from_dict(workflow_data)
|
|
|
|
def validate(self) -> List[str]:
|
|
"""Validate template structure"""
|
|
errors = []
|
|
|
|
# Basic validation
|
|
if not self.id:
|
|
errors.append("Template ID is required")
|
|
if not self.name:
|
|
errors.append("Template name is required")
|
|
if not self.category:
|
|
errors.append("Template category is required")
|
|
|
|
# Validate workflow
|
|
workflow_errors = self.workflow.validate()
|
|
errors.extend([f"Workflow: {err}" for err in workflow_errors])
|
|
|
|
# Validate parameters
|
|
node_ids = {node.id for node in self.workflow.nodes}
|
|
for param in self.parameters:
|
|
if param.node_id and param.node_id not in node_ids:
|
|
errors.append(f"Parameter {param.name} references non-existent node {param.node_id}")
|
|
|
|
return errors
|
|
|
|
|
|
def generate_template_id() -> str:
|
|
"""Generate a unique template ID"""
|
|
return f"template_{str(uuid4())[:8]}" |