Spaces:
Sleeping
Sleeping
"use client" | |
import { useState, ComponentType } from 'react' | |
import FileUpload from './FileUpload' | |
import { | |
Box, | |
Container, | |
Typography, | |
TextField, | |
Button, | |
CircularProgress, | |
Paper, | |
Fade, | |
} from '@mui/material' | |
import QuestionAnswerIcon from '@mui/icons-material/QuestionAnswer' | |
import { motion } from 'framer-motion' | |
interface Document { | |
text: string | |
} | |
const MotionContainer = motion(Container as any) | |
const MotionPaper = motion(Paper as any) | |
export default function QASystem() { | |
const [query, setQuery] = useState('') | |
const [answer, setAnswer] = useState('') | |
const [loading, setLoading] = useState(false) | |
const [documents, setDocuments] = useState<Document[]>([]) | |
const handleDocumentsLoaded = (newDocuments: Document[]) => { | |
setDocuments(newDocuments) | |
} | |
const handleSubmit = async (e: React.FormEvent) => { | |
e.preventDefault() | |
if (documents.length === 0) { | |
alert('Please upload some documents first') | |
return | |
} | |
setLoading(true) | |
try { | |
const response = await fetch('/api/qa', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ query, documents }), | |
}) | |
const data = await response.json() | |
setAnswer(data.answer) | |
} catch (error) { | |
console.error('Error:', error) | |
setAnswer('Failed to get answer. Please try again.') | |
} finally { | |
setLoading(false) | |
} | |
} | |
return ( | |
<Box | |
sx={{ | |
minHeight: '100vh', | |
background: 'linear-gradient(135deg, #f6f8fc 0%, #f0f4f8 100%)', | |
py: 8 | |
}} | |
> | |
<MotionContainer | |
maxWidth="lg" | |
initial={{ opacity: 0, y: 20 }} | |
animate={{ opacity: 1, y: 0 }} | |
transition={{ duration: 0.5 }} | |
> | |
<Box sx={{ textAlign: 'center', mb: 8 }}> | |
<Typography | |
variant="h1" | |
component="h1" | |
sx={{ | |
mb: 3, | |
fontSize: { xs: '2rem', md: '3rem' }, | |
fontWeight: 800, | |
background: 'linear-gradient(135deg, #2563eb 0%, #7c3aed 100%)', | |
backgroundClip: 'text', | |
WebkitBackgroundClip: 'text', | |
color: 'transparent', | |
textShadow: '0 2px 10px rgba(37, 99, 235, 0.1)', | |
}} | |
> | |
AI Document Assistant | |
</Typography> | |
<Typography | |
variant="h6" | |
sx={{ | |
color: 'text.secondary', | |
maxWidth: '600px', | |
mx: 'auto', | |
lineHeight: 1.6 | |
}} | |
> | |
Upload your documents and get instant, AI-powered answers to your questions | |
</Typography> | |
</Box> | |
<MotionPaper | |
elevation={0} | |
initial={{ opacity: 0, y: 20 }} | |
animate={{ opacity: 1, y: 0 }} | |
transition={{ duration: 0.5, delay: 0.2 }} | |
sx={{ | |
p: { xs: 3, md: 5 }, | |
mb: 4, | |
border: '1px solid', | |
borderColor: 'grey.100', | |
backgroundColor: 'rgba(255, 255, 255, 0.9)', | |
backdropFilter: 'blur(10px)', | |
borderRadius: 3, | |
boxShadow: '0 4px 20px rgba(0, 0, 0, 0.05)', | |
}} | |
> | |
<FileUpload onDocumentsLoaded={handleDocumentsLoaded} /> | |
<Box component="form" onSubmit={handleSubmit} sx={{ mt: 4 }}> | |
<TextField | |
fullWidth | |
multiline | |
rows={3} | |
label="What would you like to know?" | |
value={query} | |
onChange={(e) => setQuery(e.target.value)} | |
sx={{ | |
mb: 3, | |
'& .MuiOutlinedInput-root': { | |
backgroundColor: 'white', | |
borderRadius: 2, | |
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.05)', | |
} | |
}} | |
variant="outlined" | |
/> | |
<Button | |
fullWidth | |
type="submit" | |
disabled={loading || documents.length === 0} | |
variant="contained" | |
size="large" | |
sx={{ | |
py: 2, | |
background: 'linear-gradient(135deg, #2563eb 0%, #7c3aed 100%)', | |
borderRadius: 2, | |
transition: 'all 0.3s ease', | |
'&:hover': { | |
transform: 'translateY(-2px)', | |
boxShadow: '0 6px 20px rgba(37, 99, 235, 0.2)', | |
background: 'linear-gradient(135deg, #1d4ed8 0%, #6d28d9 100%)', | |
}, | |
'&:disabled': { | |
background: '#e2e8f0', | |
color: '#94a3b8', | |
} | |
}} | |
startIcon={loading ? <CircularProgress size={20} color="inherit" /> : <QuestionAnswerIcon />} | |
> | |
{loading ? 'Processing...' : 'Ask Question'} | |
</Button> | |
</Box> | |
</MotionPaper> | |
<Fade in={!!answer}> | |
<MotionPaper | |
elevation={0} | |
initial={{ opacity: 0, y: 20 }} | |
animate={{ opacity: 1, y: 0 }} | |
transition={{ duration: 0.5 }} | |
sx={{ | |
p: { xs: 3, md: 5 }, | |
border: '1px solid', | |
borderColor: 'grey.100', | |
backgroundColor: 'rgba(255, 255, 255, 0.9)', | |
backdropFilter: 'blur(10px)', | |
borderRadius: 3, | |
boxShadow: '0 4px 20px rgba(0, 0, 0, 0.05)', | |
}} | |
> | |
<Typography | |
variant="h6" | |
sx={{ | |
mb: 3, | |
fontWeight: 700, | |
color: 'text.primary', | |
fontSize: '1.25rem', | |
}} | |
> | |
Answer | |
</Typography> | |
<Box | |
sx={{ | |
p: 4, | |
backgroundColor: '#f8fafc', | |
borderRadius: 2, | |
border: '1px solid', | |
borderColor: 'grey.100', | |
}} | |
> | |
<Typography sx={{ | |
color: 'text.secondary', | |
lineHeight: 1.8, | |
fontSize: '1.1rem' | |
}}> | |
{answer} | |
</Typography> | |
</Box> | |
</MotionPaper> | |
</Fade> | |
</MotionContainer> | |
</Box> | |
) | |
} |