linked-liszt's picture
Upload folder using huggingface_hub
6d08d46 verified
import React, { useRef, useState } from 'react'
import {
Title,
Text,
Button,
Anchor,
Slider,
Switch,
Divider,
Stack,
Box,
Loader,
Select,
NumberInput,
Badge,
Alert,
Group,
} from '@mantine/core'
import { IconCloudUpload, IconChartBar, IconAlertCircle } from '@tabler/icons-react'
import { useXRD } from '../context/XRDContext'
import ExampleDataPanel from './ExampleDataPanel'
const Controls = () => {
const {
rawData,
isLoading,
detectedWavelength,
userWavelength,
setUserWavelength,
wavelengthSource,
dataWarnings,
baselineCorrection,
setBaselineCorrection,
interpolationEnabled,
setInterpolationEnabled,
scalingEnabled,
setScalingEnabled,
interpolationStrategy,
setInterpolationStrategy,
handleFileUpload,
runInference,
MODEL_WAVELENGTH,
MODEL_MIN_2THETA,
MODEL_MAX_2THETA,
} = useXRD()
const fileInputRef = useRef(null)
const [showExamples, setShowExamples] = useState(true)
const handleFileChange = async (event) => {
const file = event.target.files?.[0]
if (file) {
const success = await handleFileUpload(file)
if (success) setShowExamples(false)
// Reset file input so the same file can be uploaded again
if (fileInputRef.current) {
fileInputRef.current.value = ''
}
}
}
const handleUploadClick = () => {
fileInputRef.current?.click()
}
return (
<Stack gap="md">
{/* File Upload */}
<Box>
<input
ref={fileInputRef}
type="file"
accept=".xy,.csv,.txt,.cif,.dif"
onChange={handleFileChange}
style={{ display: 'none' }}
/>
<Button
fullWidth
leftSection={<IconCloudUpload size={20} />}
onClick={handleUploadClick}
size="md"
>
Upload XRD Data
</Button>
<Group justify="space-between" mt="xs">
<Text size="sm" c="dimmed">
Formats: .xy, .cif, .dif
</Text>
<Anchor
size="sm"
component="button"
type="button"
onClick={() => setShowExamples((v) => !v)}
>
{showExamples ? 'Hide samples' : 'Try samples'}
</Anchor>
</Group>
</Box>
{showExamples && <ExampleDataPanel onSelect={() => setShowExamples(false)} />}
{rawData && (
<>
<Divider />
{/* Data Info */}
<Box p="md" style={{ backgroundColor: '#f8f9fa', borderRadius: '8px' }}>
<Stack gap="xs">
<Text size="sm" c="dimmed">
Data Points: {rawData.x.length}
</Text>
<Text size="sm" c="dimmed">
Range: {Math.min(...rawData.x).toFixed(2)}° - {Math.max(...rawData.x).toFixed(2)}°
</Text>
</Stack>
</Box>
{/* Warnings */}
{dataWarnings.length > 0 && (
<Alert icon={<IconAlertCircle size={16} />} color="yellow" variant="light">
<Stack gap="xs">
{dataWarnings.map((warning, idx) => (
<Text key={idx} size="xs">{warning}</Text>
))}
</Stack>
</Alert>
)}
<Divider />
{/* Wavelength Configuration */}
<Title order={4}>Wavelength</Title>
{detectedWavelength && (
<Badge color="blue" variant="light" size="sm" mb="xs">
Detected: {detectedWavelength.toFixed(4)} Å
</Badge>
)}
<NumberInput
label="Wavelength (Å)"
description="Cu Kα=1.5406, Mo Kα=0.7107, Synch=0.6199"
value={userWavelength}
onChange={(value) => setUserWavelength(value || MODEL_WAVELENGTH)}
min={0.1}
max={3.0}
step={0.0001}
precision={4}
size="sm"
decimalScale={4}
/>
<Group gap="xs" mt="xs">
<Button size="xs" variant="light" onClick={() => setUserWavelength(1.5406)}>Cu Kα</Button>
<Button size="xs" variant="light" onClick={() => setUserWavelength(0.7107)}>Mo Kα</Button>
<Button size="xs" variant="light" onClick={() => setUserWavelength(0.6199)}>Synch</Button>
</Group>
<Box mt="md" p="md" style={{ backgroundColor: '#e7f5ff', borderRadius: '8px', border: '1px solid #91a7ff' }}>
<Text size="sm" fw={600} c="#1864ab" mb={4}>
Training Data Specs:
</Text>
<Text size="sm" c="#364fc7" style={{ lineHeight: 1.6 }}>
• λ: {MODEL_WAVELENGTH} Å (20 keV)<br/>
• 2θ: {MODEL_MIN_2THETA}°-{MODEL_MAX_2THETA}° (8192 pts)<br/>
• Intensity: 0-100 scaled
</Text>
</Box>
<Divider />
{/* Preprocessing Controls */}
<Title order={4}>Preprocessing</Title>
<Switch
label="Baseline Correction"
checked={baselineCorrection}
onChange={(event) => setBaselineCorrection(event.currentTarget.checked)}
/>
<Switch
label="Signal Scaling (0-100)"
description="Normalize to model input range"
checked={scalingEnabled}
onChange={(event) => setScalingEnabled(event.currentTarget.checked)}
/>
<Select
label="Interpolation Strategy"
description="Resampling method for 8192 points"
value={interpolationStrategy}
onChange={(value) => {
if (value) setInterpolationStrategy(value)
}}
data={[
{ value: 'linear', label: 'Linear' },
{ value: 'cubic', label: 'Cubic Spline' },
]}
size="sm"
allowDeselect={false}
/>
<Divider />
</>
)}
{/* Analysis Button - Always visible when data loaded */}
{rawData && (
<Button
fullWidth
color="violet"
leftSection={isLoading ? <Loader size={18} color="white" /> : <IconChartBar size={20} />}
onClick={runInference}
disabled={isLoading}
size="lg"
style={{ marginTop: 'auto' }}
>
{isLoading ? 'Analyzing...' : 'Run Analysis'}
</Button>
)}
</Stack>
)
}
export default Controls