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,
|
config,
|
||||||
scenarios,
|
scenarios,
|
||||||
(p) => {
|
(p) => {
|
||||||
setProgress(p);
|
if (typeof p === 'number') setProgress(p);
|
||||||
},
|
},
|
||||||
controller.signal
|
controller.signal
|
||||||
);
|
);
|
||||||
setReport(reportResult);
|
setReport(reportResult);
|
||||||
setStatus('done');
|
setStatus('done');
|
||||||
|
|
||||||
|
// Auto-download MD
|
||||||
|
import('@/lib/audit/export-audit-md').then(m => m.downloadAuditMarkdown(reportResult));
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Error && e.message.includes('Abortado')) {
|
if (e instanceof Error && e.message.includes('Abortado')) {
|
||||||
setStatus('idle');
|
setStatus('idle');
|
||||||
@@ -186,10 +190,16 @@ export default function AuditPanel() {
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{status === 'done' && report && (
|
{status === 'done' && report && (
|
||||||
<Button variant="outline" size="sm" onClick={handleExportPDF}>
|
<>
|
||||||
<FileDown className="w-3.5 h-3.5 mr-1.5" />
|
<Button variant="outline" size="sm" onClick={() => import('@/lib/audit/export-audit-md').then(m => m.downloadAuditMarkdown(report))}>
|
||||||
Exportar PDF
|
<FileDown className="w-3.5 h-3.5 mr-1.5" />
|
||||||
</Button>
|
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>
|
</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>
|
</View>
|
||||||
|
|
||||||
{report.modules.map((mod: ModuleAuditResult) => (
|
{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}>
|
<Text style={styles.moduleTitle}>
|
||||||
{mod.moduleLabel} — {mod.passed}/{mod.totalScenarios} (W:{mod.warnings} F:{mod.failed})
|
{mod.moduleLabel} — {mod.passed}/{mod.totalScenarios} (W:{mod.warnings} F:{mod.failed})
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
Reference in New Issue
Block a user