Spaces:
Running
Running
| /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| AMDMigrationPanel β CUDA β ROCm Migration Advisor | |
| Shows compatibility score + per-finding migration guidance | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| import { useState } from 'react'; | |
| import './AMDMigrationPanel.css'; | |
| function ScoreCircle({ score }) { | |
| const radius = 58; | |
| const circumference = 2 * Math.PI * radius; | |
| const offset = circumference - (score / 100) * circumference; | |
| let colorClass = 'score-red'; | |
| let strokeClass = 'stroke-red'; | |
| if (score >= 90) { colorClass = 'score-green'; strokeClass = 'stroke-green'; } | |
| else if (score >= 70) { colorClass = 'score-yellow'; strokeClass = 'stroke-yellow'; } | |
| else if (score >= 50) { colorClass = 'score-orange'; strokeClass = 'stroke-orange'; } | |
| return ( | |
| <div className="amd-score-circle"> | |
| <svg viewBox="0 0 140 140"> | |
| <circle className="amd-score-circle-bg" cx="70" cy="70" r={radius} /> | |
| <circle | |
| className={`amd-score-circle-fill ${strokeClass}`} | |
| cx="70" | |
| cy="70" | |
| r={radius} | |
| strokeDasharray={circumference} | |
| strokeDashoffset={offset} | |
| /> | |
| </svg> | |
| <div className="amd-score-value"> | |
| <span className={`amd-score-number ${colorClass}`}>{score}</span> | |
| <span className="amd-score-pct">%</span> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| function MigrationFinding({ finding }) { | |
| const [expanded, setExpanded] = useState(false); | |
| const sevClass = `sev-${finding.severity}`; | |
| return ( | |
| <div className="amd-mig-finding"> | |
| <div className="amd-mig-finding-header" onClick={() => setExpanded(!expanded)}> | |
| <span className={`amd-mig-sev-badge ${sevClass}`}>{finding.severity}</span> | |
| <span className="amd-mig-finding-id">{finding.id}</span> | |
| <span className="amd-mig-finding-title">{finding.title}</span> | |
| <button className="amd-mig-expand-btn" aria-label="Toggle details"> | |
| {expanded ? 'βΎ' : 'βΈ'} | |
| </button> | |
| </div> | |
| {expanded && ( | |
| <div className="amd-mig-finding-detail"> | |
| {finding.file && ( | |
| <div className="amd-mig-file-loc"> | |
| <span>π</span> | |
| <span>{finding.file}{finding.line ? `:${finding.line}` : ''}</span> | |
| </div> | |
| )} | |
| <p className="amd-mig-description">{finding.description}</p> | |
| <div className="amd-mig-fix-section"> | |
| <div className="amd-mig-fix-label">π§ ROCm Fix</div> | |
| <p className="amd-mig-fix-text">{finding.rocm_fix}</p> | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| } | |
| export default function AMDMigrationPanel({ migrationData }) { | |
| if (!migrationData) return null; | |
| const { | |
| compatibility_score = 100, | |
| compatibility_label = 'Fully ROCm Ready', | |
| findings = [], | |
| total_cuda_patterns_found = 0, | |
| summary = '', | |
| } = migrationData; | |
| let labelColor = 'score-red'; | |
| if (compatibility_score >= 90) labelColor = 'score-green'; | |
| else if (compatibility_score >= 70) labelColor = 'score-yellow'; | |
| else if (compatibility_score >= 50) labelColor = 'score-orange'; | |
| const handleExport = () => { | |
| let md = `# AMD ROCm Migration Guide β CodeSentry\n\n`; | |
| md += `## Compatibility Score: ${compatibility_score}% β ${compatibility_label}\n\n`; | |
| md += `## Found ${total_cuda_patterns_found} CUDA-Specific Pattern(s)\n\n`; | |
| if (summary) { | |
| md += `> ${summary}\n\n`; | |
| } | |
| md += `---\n\n`; | |
| findings.forEach((f) => { | |
| md += `### ${f.id}: ${f.title}\n\n`; | |
| md += `**Severity:** ${f.severity.toUpperCase()}\n\n`; | |
| if (f.file) { | |
| md += `**File:** \`${f.file}${f.line ? ':' + f.line : ''}\`\n\n`; | |
| } | |
| md += `**Issue:** ${f.description}\n\n`; | |
| md += `**ROCm Fix:** ${f.rocm_fix}\n\n`; | |
| if (f.code_snippet) { | |
| md += `**Code:**\n\`\`\`python\n${f.code_snippet}\n\`\`\`\n\n`; | |
| } | |
| md += `---\n\n`; | |
| }); | |
| md += `\n*Generated by CodeSentry AMD Migration Advisor*\n`; | |
| const blob = new Blob([md], { type: 'text/markdown' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'AMD_MIGRATION_GUIDE.md'; | |
| a.click(); | |
| URL.revokeObjectURL(url); | |
| }; | |
| return ( | |
| <div className="amd-migration-panel" id="amd-migration-panel"> | |
| {/* Header */} | |
| <div className="amd-mig-header"> | |
| <span style={{ fontSize: '1.4rem' }}>π΄</span> | |
| <h3>AMD ROCm Migration Advisor</h3> | |
| </div> | |
| {/* Score */} | |
| <div className="amd-score-section"> | |
| <ScoreCircle score={compatibility_score} /> | |
| <span className={`amd-score-label ${labelColor}`}>{compatibility_label}</span> | |
| </div> | |
| {/* Findings */} | |
| {findings.length > 0 ? ( | |
| <div className="amd-mig-findings"> | |
| {findings.map((f, idx) => ( | |
| <MigrationFinding key={`${f.id}-${idx}`} finding={f} /> | |
| ))} | |
| </div> | |
| ) : ( | |
| <div className="amd-no-findings"> | |
| β No CUDA-specific patterns detected | |
| <div className="amd-no-findings-sub">This codebase is fully AMD ROCm compatible</div> | |
| </div> | |
| )} | |
| {/* Footer */} | |
| <div className="amd-mig-footer"> | |
| <button className="btn btn-secondary btn-sm" onClick={handleExport} style={{ marginBottom: '8px' }}> | |
| π΄ Export AMD Migration Guide | |
| </button> | |
| <div className="amd-mig-footer-text"> | |
| {total_cuda_patterns_found > 0 | |
| ? `Apply all AMD fixes β Generate ROCm-optimized patch` | |
| : `Codebase verified for AMD MI300X deployment`} | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |