|
"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> |
|
) |
|
} |