feat(audit): correcao layout pdf e auto-exportacao para markdown detalhado com chain of thought
This commit is contained in:
@@ -85,12 +85,16 @@ export default function AuditPanel() {
|
||||
config,
|
||||
scenarios,
|
||||
(p) => {
|
||||
setProgress(p);
|
||||
if (typeof p === 'number') setProgress(p);
|
||||
},
|
||||
controller.signal
|
||||
);
|
||||
setReport(reportResult);
|
||||
setStatus('done');
|
||||
|
||||
// Auto-download MD
|
||||
import('@/lib/audit/export-audit-md').then(m => m.downloadAuditMarkdown(reportResult));
|
||||
|
||||
} catch (e) {
|
||||
if (e instanceof Error && e.message.includes('Abortado')) {
|
||||
setStatus('idle');
|
||||
@@ -186,10 +190,16 @@ export default function AuditPanel() {
|
||||
</Button>
|
||||
)}
|
||||
{status === 'done' && report && (
|
||||
<Button variant="outline" size="sm" onClick={handleExportPDF}>
|
||||
<FileDown className="w-3.5 h-3.5 mr-1.5" />
|
||||
Exportar PDF
|
||||
</Button>
|
||||
<>
|
||||
<Button variant="outline" size="sm" onClick={() => import('@/lib/audit/export-audit-md').then(m => m.downloadAuditMarkdown(report))}>
|
||||
<FileDown className="w-3.5 h-3.5 mr-1.5" />
|
||||
Exportar MD
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" onClick={handleExportPDF}>
|
||||
<FileDown className="w-3.5 h-3.5 mr-1.5" />
|
||||
Exportar PDF
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import type { AuditReport } from './types';
|
||||
|
||||
export function generateAuditMarkdown(report: AuditReport): string {
|
||||
let md = `# Relatório de Auditoria — BrainWind\n\n`;
|
||||
md += `**Provedor:** ${report.provider} (${report.model})\n`;
|
||||
md += `**Data:** ${new Date(report.timestamp).toLocaleString('pt-BR')}\n\n`;
|
||||
|
||||
md += `## Resumo Geral\n`;
|
||||
md += `- **Total de Cenários:** ${report.totalScenarios}\n`;
|
||||
md += `- **PASS:** ${report.totalPassed} ✅\n`;
|
||||
md += `- **WARN:** ${report.totalWarnings} ⚠️\n`;
|
||||
md += `- **FAIL:** ${report.totalFailed} ❌\n\n`;
|
||||
|
||||
for (const mod of report.modules) {
|
||||
md += `## Módulo: ${mod.moduleLabel}\n`;
|
||||
md += `**Total:** ${mod.totalScenarios} | **PASS:** ${mod.passed} | **WARN:** ${mod.warnings} | **FAIL:** ${mod.failed}\n\n`;
|
||||
|
||||
for (const sc of mod.scenarios) {
|
||||
const icon = sc.verdict === 'PASS' ? '✅' : sc.verdict === 'WARN' ? '⚠️' : '❌';
|
||||
md += `### ${icon} Cenário: ${sc.scenarioId}\n`;
|
||||
md += `**Veredito:** ${sc.verdict} — *${sc.summary}*\n\n`;
|
||||
|
||||
if (sc.llmNotes) {
|
||||
md += `**Observações da IA:** ${sc.llmNotes}\n\n`;
|
||||
}
|
||||
|
||||
md += `**Raciocínio Matemático (Chain of Thought):**\n`;
|
||||
const calcSteps = sc.calculation_steps || 'Sem raciocínio fornecido pela IA.';
|
||||
md += `> ${calcSteps.split('\n').join('\n> ')}\n\n`;
|
||||
|
||||
md += `**Verificações Individuais:**\n`;
|
||||
for (const chk of sc.checks) {
|
||||
const chkIcon = chk.status === 'PASS' ? '✅' : chk.status === 'WARN' ? '⚠️' : '❌';
|
||||
md += `- ${chkIcon} **${chk.name}:** Calculado IA = \`${chk.expected}\` | App = \`${chk.actual}\`\n`;
|
||||
if (chk.explanation) {
|
||||
md += ` - *Nota:* ${chk.explanation}\n`;
|
||||
}
|
||||
}
|
||||
md += `\n---\n\n`;
|
||||
}
|
||||
}
|
||||
|
||||
return md;
|
||||
}
|
||||
|
||||
export function downloadAuditMarkdown(report: AuditReport) {
|
||||
const md = generateAuditMarkdown(report);
|
||||
const blob = new Blob([md], { type: 'text/markdown;charset=utf-8' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.setAttribute('href', url);
|
||||
link.setAttribute('download', `auditoria-${report.id}.md`);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
@@ -101,7 +101,7 @@ function AuditReportDocument({ report }: ReportPDFProps) {
|
||||
</View>
|
||||
|
||||
{report.modules.map((mod: ModuleAuditResult) => (
|
||||
<View key={mod.module} wrap={false} style={styles.moduleCard}>
|
||||
<View key={mod.module} style={styles.moduleCard}>
|
||||
<Text style={styles.moduleTitle}>
|
||||
{mod.moduleLabel} — {mod.passed}/{mod.totalScenarios} (W:{mod.warnings} F:{mod.failed})
|
||||
</Text>
|
||||
|
||||
Reference in New Issue
Block a user