import { useState } from 'react' import { Button, Card, Label, Icon, Spinner, Input } from '../components/primitives' import Dropzone from '../components/Dropzone' import ResultsTable from '../components/ResultsTable' import { StatCard } from '../components/FeatureCard' import { analyzeBatch } from '../api/client' export default function BatchScreen({ onOpenRow }) { const [files, setFiles] = useState([]) const [results, setResults] = useState([]) const [summary, setSummary] = useState(null) const [loading, setLoading] = useState(false) const [progress, setProgress] = useState(0) const [error, setError] = useState(null) const [search, setSearch] = useState('') const handleFiles = (fileList) => { const arr = Array.from(fileList) setFiles(arr); setResults([]); setSummary(null); setError(null) } const runBatch = async () => { if (!files.length) return setLoading(true); setError(null); setProgress(0) const submissions = await Promise.all(files.map(async (f) => ({ id: f.name.replace(/\.[^.]+$/, ''), file: f.name, code: await f.text(), }))) try { const data = await analyzeBatch(submissions) // Uz file naziv priložimo i originalni kod da ga DetailScreen može prikazati const withFile = data.results.map((r, i) => ({ ...r, file: submissions[i]?.file || r.id, code: submissions[i]?.code || '', // ← ovo je bio problem, nedostajalo })) setResults(withFile) setSummary(data.summary) setProgress(100) } catch (e) { setError(e.message) } finally { setLoading(false) } } const exportCSV = () => { if (!results.length) return const headers = ['ID', 'Datoteka', 'Jezik', 'AI vjerojatnost (%)', 'Zakljucak'] const keys = ['id', 'file', 'detected_language', 'ai_probability', 'verdict'] // Escapiranje polja — ako polje sadrži točku-zarez, navodnike ili novi red, // omotamo ga navodnicima i udvostručimo unutarnje navodnike const escapeCell = (val) => { const s = String(val ?? '') if (s.includes(';') || s.includes('"') || s.includes('\n')) { return '"' + s.replace(/"/g, '""') + '"' } return s } const rows = results.map(r => keys.map(h => { if (h === 'ai_probability') return escapeCell(Math.round((r[h] || 0) * 100) + '%') return escapeCell(r[h] || '') })) // Točka-zarez (;) kao separator — Excel u europskim regijama koristi ; ne , // UTF-8 BOM (\ufeff) na početku — Excel tada ispravno čita čšćžđ i sl. const sep = ';' const csvContent = [ headers.map(escapeCell).join(sep), ...rows.map(r => r.join(sep)), ].join('\r\n') const BOM = '\uFEFF' const blob = new Blob([BOM + csvContent], { type: 'text/csv;charset=utf-8;' }) const a = Object.assign(document.createElement('a'), { href: URL.createObjectURL(blob), download: 'codesentinel_rezultati.csv', }) a.click() } const filtered = results.filter(r => !search || r.id?.toLowerCase().includes(search.toLowerCase()) || r.file?.toLowerCase().includes(search.toLowerCase()) ) return (
Drop a folder of submissions, then sort by AI probability to triage your grading queue.