🚀 Auto-deploy: BrainWind atualizado em 15/07/2026 21:36:38

This commit is contained in:
2026-07-15 21:36:38 +00:00
parent 5f0329c400
commit f38492cf88
13 changed files with 480 additions and 34 deletions
+45 -14
View File
@@ -1,4 +1,4 @@
import { Document, Page, Text, View, StyleSheet, pdf } from '@react-pdf/renderer';
import { Document, Page, Text, View, StyleSheet, pdf, Image } from '@react-pdf/renderer';
import type { AuditReport, ModuleAuditResult, ScenarioResult, CheckStatus } from './types';
const styles = StyleSheet.create({
@@ -73,11 +73,16 @@ function AuditReportDocument({ report }: ReportPDFProps) {
return (
<Document>
<Page size="A4" style={styles.page}>
<View style={styles.header}>
<Text style={styles.title}>Relatório de Auditoria BrainWind</Text>
<Text style={styles.subtitle}>
Provedor: {report.provider} ({report.model}) | {new Date(report.timestamp).toLocaleString('pt-BR')}
</Text>
<View style={[styles.header, { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }]}>
<View>
<Text style={styles.title}>Relatório de Auditoria</Text>
<Text style={styles.subtitle}>
Auditor IA: {report.provider} ({report.model}) | {new Date(report.timestamp).toLocaleString('pt-BR')}
</Text>
</View>
{typeof window !== 'undefined' && window.location && (
<Image src={`${window.location.origin}/logo_brainwind.png`} style={{ width: 120, height: 40, objectFit: 'contain' }} />
)}
</View>
<View style={styles.section}>
@@ -87,15 +92,15 @@ function AuditReportDocument({ report }: ReportPDFProps) {
<Text style={styles.summaryValue}>{report.totalScenarios}</Text>
</View>
<View style={styles.summaryRow}>
<Text style={[styles.summaryLabel, { color: '#16a34a' }]}>Pass:</Text>
<Text style={[styles.summaryLabel, { color: '#16a34a' }]}>Aprovado:</Text>
<Text style={styles.summaryValue}>{report.totalPassed}</Text>
</View>
<View style={styles.summaryRow}>
<Text style={[styles.summaryLabel, { color: '#d97706' }]}>Warn:</Text>
<Text style={[styles.summaryLabel, { color: '#d97706' }]}>Atenção:</Text>
<Text style={styles.summaryValue}>{report.totalWarnings}</Text>
</View>
<View style={styles.summaryRow}>
<Text style={[styles.summaryLabel, { color: '#dc2626' }]}>Fail:</Text>
<Text style={[styles.summaryLabel, { color: '#dc2626' }]}>Falha:</Text>
<Text style={styles.summaryValue}>{report.totalFailed}</Text>
</View>
</View>
@@ -103,13 +108,33 @@ function AuditReportDocument({ report }: ReportPDFProps) {
{report.modules.map((mod: ModuleAuditResult) => (
<View key={mod.module} style={styles.moduleCard}>
<Text style={styles.moduleTitle}>
{mod.moduleLabel} {mod.passed}/{mod.totalScenarios} (W:{mod.warnings} F:{mod.failed})
{mod.moduleLabel} {mod.passed}/{mod.totalScenarios} (Alertas: {mod.warnings} | Falhas: {mod.failed})
</Text>
{mod.scenarios.map((sc: ScenarioResult) => (
{mod.scenarios.map((sc: ScenarioResult) => {
const summaryTranslated = (sc.summary || '')
.replace(/Verdict PASS\.?/gi, 'Veredito: APROVADO.')
.replace(/Verdict WARN\.?/gi, 'Veredito: ATENÇÃO.')
.replace(/Verdict FAIL\.?/gi, 'Veredito: FALHA.');
return (
<View key={sc.scenarioId} style={styles.scenarioItem}>
<Text style={styles.scenarioId}>
{sc.scenarioId} {sc.verdict === 'PASS' ? '✓' : sc.verdict === 'WARN' ? '⚠' : '✗'} {sc.summary}
{sc.scenarioId} {sc.verdict === 'PASS' ? '✓' : sc.verdict === 'WARN' ? '⚠' : '✗'} {summaryTranslated}
</Text>
{sc.enunciado_problema && (
<Text style={{ fontSize: 8, color: '#444', marginBottom: 2 }}>Enunciado: {sc.enunciado_problema}</Text>
)}
{sc.tabelas_nbr_consultadas && (
<Text style={{ fontSize: 8, color: '#444', marginBottom: 2 }}>Tabelas: {sc.tabelas_nbr_consultadas}</Text>
)}
{sc.resultado_app && (
<Text style={{ fontSize: 8, color: '#444', marginBottom: 2 }}>Avaliação do App: {sc.resultado_app}</Text>
)}
{sc.calculation_steps && (
<Text style={{ fontSize: 8, color: '#444', marginBottom: 4, fontStyle: 'italic' }}>
CoT: {sc.calculation_steps.substring(0, 300)}{sc.calculation_steps.length > 300 ? '...' : ''}
</Text>
)}
{sc.checks.map((chk, i) => (
<View key={i} style={styles.checkRow}>
<Text style={[styles.statusBadge, { color: statusColor(chk.status) }]}>{chk.status}</Text>
@@ -118,7 +143,8 @@ function AuditReportDocument({ report }: ReportPDFProps) {
</View>
))}
</View>
))}
);
})}
</View>
))}
@@ -134,8 +160,13 @@ export async function exportAuditReportToPDF(report: AuditReport): Promise<void>
const blob = await pdf(<AuditReportDocument report={report} />).toBlob();
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
const dateStr = new Date(report.timestamp).toLocaleDateString('pt-BR').replace(/\//g, '-');
const safeModel = report.model.split('/').pop()?.replace(/[^a-zA-Z0-9_-]/g, '-') || 'LLM';
const filename = `Audit-${safeModel}_${dateStr}.pdf`;
link.setAttribute('href', url);
link.setAttribute('download', `auditoria-${report.id}.pdf`);
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);