Files
wevia-brain/modules/core/output-formatter.php
2026-04-12 23:01:36 +02:00

185 lines
6.9 KiB
PHP
Executable File

<?php
/**
* WEVIA OPUS — Output Formatting Engine
*
* Formate les réponses de WEVIA dans le format optimal:
* - Markdown structuré
* - Code blocks avec syntax highlighting
* - Tableaux pour les comparaisons
* - Mermaid pour les diagrammes
* - JSON pour les données structurées
* - HTML pour les emails/rapports
*/
class OutputFormatter {
/**
* Formate une réponse en fonction du type détecté
*/
public function format(string $content, string $type = 'auto'): string {
if ($type === 'auto') {
$type = $this->detectType($content);
}
switch ($type) {
case 'code': return $this->formatCode($content);
case 'table': return $this->formatTable($content);
case 'list': return $this->formatList($content);
case 'steps': return $this->formatSteps($content);
case 'comparison': return $this->formatComparison($content);
case 'diagram': return $this->formatDiagram($content);
default: return $this->formatProse($content);
}
}
/**
* Détecte le type de contenu optimal
*/
private function detectType(string $content): string {
if (preg_match('/```|function |class |SELECT |def |import |<\?php/', $content)) return 'code';
if (preg_match('/\|.*\|.*\|/', $content)) return 'table';
if (preg_match('/^\s*[-*]\s/m', $content) && substr_count($content, "\n-") > 3) return 'list';
if (preg_match('/étape\s+\d|step\s+\d|1\.\s+.*\n2\.\s+/i', $content)) return 'steps';
if (preg_match('/vs\.?\s|versus|comparaison|comparer/i', $content)) return 'comparison';
if (preg_match('/flowchart|graph|sequenceDiagram|classDiagram/', $content)) return 'diagram';
return 'prose';
}
/**
* Formate du code avec metadata
*/
private function formatCode(string $content): string {
// Détecter le langage si pas spécifié
if (!preg_match('/```(\w+)/', $content)) {
$lang = $this->detectCodeLanguage($content);
$content = preg_replace('/```\n/', "```$lang\n", $content, 1);
}
return $content;
}
private function detectCodeLanguage(string $code): string {
if (preg_match('/<\?php|function\s+\w+\s*\(.*\)\s*{|\$this->/', $code)) return 'php';
if (preg_match('/def\s+\w+|import\s+\w+|from\s+\w+\s+import/', $code)) return 'python';
if (preg_match('/const\s+\w+\s*=|let\s+\w+|=>\s*{|require\(/', $code)) return 'javascript';
if (preg_match('/SELECT\s+|INSERT\s+|CREATE\s+TABLE/i', $code)) return 'sql';
if (preg_match('/#!/', $code)) return 'bash';
return '';
}
/**
* Génère un tableau Markdown depuis des données
*/
public function generateTable(array $headers, array $rows): string {
$table = '| ' . implode(' | ', $headers) . " |\n";
$table .= '| ' . implode(' | ', array_fill(0, count($headers), '---')) . " |\n";
foreach ($rows as $row) {
$table .= '| ' . implode(' | ', array_map('strval', $row)) . " |\n";
}
return $table;
}
/**
* Génère un diagramme Mermaid
*/
public function generateFlowchart(array $steps, string $direction = 'TD'): string {
$mermaid = "```mermaid\nflowchart $direction\n";
foreach ($steps as $i => $step) {
$id = 'S' . ($i + 1);
$mermaid .= " {$id}[\"" . addslashes($step['label']) . "\"]\n";
if (isset($step['next'])) {
foreach ((array)$step['next'] as $next) {
$nextId = 'S' . $next;
$label = $step['edge_label'] ?? '';
$mermaid .= $label ?
" $id -->|\"$label\"| $nextId\n" :
" $id --> $nextId\n";
}
}
// Styling
if (isset($step['style'])) {
$mermaid .= " style $id {$step['style']}\n";
}
}
$mermaid .= "```\n";
return $mermaid;
}
/**
* Génère un diagramme de séquence Mermaid
*/
public function generateSequenceDiagram(array $interactions): string {
$mermaid = "```mermaid\nsequenceDiagram\n";
foreach ($interactions as $interaction) {
$from = $interaction['from'];
$to = $interaction['to'];
$message = addslashes($interaction['message']);
$type = $interaction['type'] ?? '->>'; // ->> solid, -->> dashed
$mermaid .= " $from$type$to: $message\n";
if (isset($interaction['note'])) {
$mermaid .= " Note over $from,$to: {$interaction['note']}\n";
}
}
$mermaid .= "```\n";
return $mermaid;
}
/**
* Formate des étapes numérotées avec statut
*/
public function formatStepsWithStatus(array $steps): string {
$output = '';
foreach ($steps as $i => $step) {
$num = $i + 1;
$status = $step['status'] ?? 'pending';
$emoji = match($status) {
'done' => '✅',
'in_progress' => '🔄',
'failed' => '❌',
'skipped' => '⏭️',
default => '⬜'
};
$output .= "$emoji **Étape $num**: {$step['description']}\n";
if (isset($step['detail'])) {
$output .= " _{$step['detail']}_\n";
}
if (isset($step['command'])) {
$output .= " ```bash\n {$step['command']}\n ```\n";
}
$output .= "\n";
}
return $output;
}
/**
* Génère un résumé exécutif structuré
*/
public function executiveSummary(string $title, array $sections): string {
$md = "# $title\n\n";
$md .= "**Date**: " . date('d/m/Y H:i') . "\n\n";
$md .= "---\n\n";
foreach ($sections as $section) {
$md .= "## {$section['title']}\n\n";
$md .= "{$section['content']}\n\n";
if (isset($section['metrics'])) {
$md .= $this->generateTable(
['Métrique', 'Valeur', 'Status'],
array_map(fn($k, $v) => [$k, $v['value'], $v['status'] ?? ''],
array_keys($section['metrics']), array_values($section['metrics']))
);
$md .= "\n";
}
}
return $md;
}
private function formatProse(string $content): string { return $content; }
private function formatTable(string $content): string { return $content; }
private function formatList(string $content): string { return $content; }
private function formatSteps(string $content): string { return $content; }
private function formatComparison(string $content): string { return $content; }
private function formatDiagram(string $content): string { return $content; }
}