Files
html/api/weval-ia-render.php
2026-04-12 22:57:03 +02:00

149 lines
5.4 KiB
PHP

<?php
/**
* WEVIA Render API — Enrichit les réponses IA avec des rendus visuels
* Mermaid → SVG, Markdown → HTML, Charts → PNG, Full → PDF
* Utilise: mmdc, matplotlib, wkhtmltopdf, CairoSVG, Graphviz
*/
set_time_limit(30);
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
if($_SERVER['REQUEST_METHOD']==='OPTIONS'){http_response_code(200);exit;}
if($_SERVER['REQUEST_METHOD']==='GET'){die(json_encode(['status'=>'ok','capabilities'=>['mermaid_svg','chart_png','pdf','graphviz']]));}
$in=json_decode(file_get_contents('php://input'),true)?:[];
$text=trim($in['text']??'');
$mode=trim($in['mode']??'auto'); // auto|mermaid|chart|pdf
if(!$text)die(json_encode(['error'=>'text required']));
$id=uniqid('wr_');
$assets=[];
// ═══ 1. MERMAID → SVG ═══
function render_mermaid($code,$id,$idx){
$mmd_file="/tmp/{$id}_m{$idx}.mmd";
$svg_file="/var/www/html/test-report/render/{$id}_m{$idx}.svg";
@mkdir("/var/www/html/test-report/render",0777,true);
file_put_contents($mmd_file,$code);
$png_file=str_replace('.svg','.png',$svg_file);
$out=shell_exec("python3 /opt/mermaid-render.py {$mmd_file} {$png_file} 2>&1");
$svg_file=$png_file;
if(file_exists($svg_file)){
return ['type'=>'mermaid_png','url'=>"/test-report/render/{$id}_m{$idx}.svg",'size'=>filesize($svg_file)];
}
return ['type'=>'mermaid_error','error'=>$out];
}
// ═══ 2. CHART → PNG (matplotlib) ═══
function render_chart($spec,$id,$idx){
$json_file="/tmp/{$id}_c{$idx}.json";
$png_file="/var/www/html/test-report/render/{$id}_c{$idx}.png";
@mkdir("/var/www/html/test-report/render",0777,true);
file_put_contents($json_file,json_encode($spec));
$py=<<<'PY'
import json,sys,warnings
warnings.filterwarnings("ignore")
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
d=json.load(open(sys.argv[1]))
t=d.get("type","bar")
fig,ax=plt.subplots(figsize=(8,4))
ax.set_facecolor("#0d1117")
fig.patch.set_facecolor("#0d1117")
ax.tick_params(colors="#c8d6e5")
ax.xaxis.label.set_color("#c8d6e5")
ax.yaxis.label.set_color("#c8d6e5")
for s in ax.spines.values():s.set_color("#21262d")
labels=d.get("labels",[])
values=d.get("values",[])
colors=d.get("colors",["#7c3aed","#06b6d4","#10b981","#f59e0b","#ef4444","#ec4899"])
if t=="bar":
ax.bar(labels,values,color=colors[:len(labels)])
elif t=="pie":
ax.pie(values,labels=labels,colors=colors[:len(labels)],autopct="%1.0f%%",textprops={"color":"#c8d6e5"})
elif t=="line":
ax.plot(labels,values,color="#7c3aed",linewidth=2,marker="o")
ax.fill_between(range(len(labels)),values,alpha=0.2,color="#7c3aed")
if d.get("title"):ax.set_title(d["title"],color="#fff",fontsize=13,fontweight="bold")
if d.get("xlabel"):ax.set_xlabel(d["xlabel"])
if d.get("ylabel"):ax.set_ylabel(d["ylabel"])
plt.tight_layout()
plt.savefig(sys.argv[2],dpi=150,bbox_inches="tight",facecolor="#0d1117")
print("OK")
PY;
$py_file="/tmp/{$id}_c{$idx}.py";
file_put_contents($py_file,$py);
$out=shell_exec("python3 {$py_file} {$json_file} {$png_file} 2>&1");
if(file_exists($png_file)){
return ['type'=>'chart_png','url'=>"/test-report/render/{$id}_c{$idx}.png",'size'=>filesize($png_file)];
}
return ['type'=>'chart_error','error'=>$out];
}
// ═══ 3. GRAPHVIZ → SVG ═══
function render_graphviz($code,$id,$idx){
$dot_file="/tmp/{$id}_g{$idx}.dot";
$svg_file="/var/www/html/test-report/render/{$id}_g{$idx}.svg";
@mkdir("/var/www/html/test-report/render",0777,true);
file_put_contents($dot_file,$code);
shell_exec("dot -Tsvg {$dot_file} -o {$svg_file} 2>&1");
if(file_exists($svg_file)){
return ['type'=>'graphviz_svg','url'=>"/test-report/render/{$id}_g{$idx}.svg"];
}
return null;
}
// ═══ AUTO-DETECT & RENDER ═══
$rendered_text=$text;
$midx=0;
// Find mermaid code blocks
if(preg_match_all('/```(?:mermaid)?\s*((?:graph |flowchart |sequenceDiagram|classDiagram|gantt|pie|erDiagram|stateDiagram|journey)[\s\S]*?)```/i',$text,$matches)){
foreach($matches[1] as $code){
$result=render_mermaid(trim($code),$id,$midx);
$assets[]=$result;
if(isset($result['url'])){
$svg_tag='<img src="'.$result['url'].'" alt="Mermaid diagram" style="max-width:100%;background:#fff;border-radius:8px;padding:8px">';
$rendered_text=str_replace($matches[0][$midx],$svg_tag,$rendered_text);
}
$midx++;
}
}
// Find graphviz
if(preg_match_all('/```(?:dot|graphviz)\s*(digraph[\s\S]*?)```/i',$text,$gmatches)){
foreach($gmatches[1] as $i=>$code){
$result=render_graphviz(trim($code),$id,$i);
if($result)$assets[]=$result;
}
}
// Find chart requests (JSON chart spec)
if(preg_match_all('/```chart\s*(\{[\s\S]*?\})\s*```/i',$text,$cmatches)){
foreach($cmatches[1] as $i=>$spec){
$data=json_decode($spec,true);
if($data){
$result=render_chart($data,$id,$i);
$assets[]=$result;
if(isset($result['url'])){
$img_tag='<img src="'.$result['url'].'" alt="Chart" style="max-width:100%;border-radius:8px">';
$rendered_text=str_replace($cmatches[0][$i],$img_tag,$rendered_text);
}
}
}
}
die(json_encode([
'rendered_text'=>$rendered_text,
'assets'=>$assets,
'asset_count'=>count($assets),
'original_length'=>strlen($text),
'rendered_length'=>strlen($rendered_text)
]));