SPARKNET / frontend /app /upload /page.tsx
MHamdan's picture
Initial commit: SPARKNET framework
a9dc537
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { motion } from 'framer-motion';
import { PatentUpload } from '@/components/PatentUpload';
import { uploadPatent, executeWorkflow } from '@/lib/api';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Sparkles } from 'lucide-react';
import { toast } from 'sonner';
export default function UploadPage() {
const router = useRouter();
const [uploading, setUploading] = useState(false);
const [error, setError] = useState<string | null>(null);
const handleUpload = async (file: File) => {
console.log('🎯 Parent handleUpload called with file:', file);
try {
setUploading(true);
setError(null);
// Step 1: Upload patent
console.log('πŸ“€ Uploading patent:', file.name);
toast.info('Uploading patent...', {
description: `Uploading ${file.name}`,
});
console.log('🌐 Calling uploadPatent API...');
const uploadResponse = await uploadPatent(file);
console.log('βœ… Upload response:', uploadResponse);
toast.success('Patent uploaded successfully!', {
description: `Patent ID: ${uploadResponse.patent_id.slice(0, 8)}...`,
});
// Step 2: Start workflow
console.log('πŸš€ About to execute workflow for patent:', uploadResponse.patent_id);
toast.info('Starting analysis...', {
description: 'Initializing Patent Wake-Up workflow',
});
console.log('πŸ“ž Calling executeWorkflow API...');
const workflowResponse = await executeWorkflow(uploadResponse.patent_id);
console.log('βœ… Workflow response:', workflowResponse);
toast.success('Analysis started!', {
description: 'Redirecting to progress page...',
});
// Step 3: Redirect to workflow progress page
setTimeout(() => {
router.push(`/workflow/${workflowResponse.workflow_id}`);
}, 1500);
} catch (err: any) {
console.error('❌ Error in handleUpload:', err);
console.error('Error details:', {
message: err.message,
response: err.response?.data,
stack: err.stack
});
const errorMessage =
err.response?.data?.detail || err.message || 'Failed to upload patent';
setError(errorMessage);
toast.error('Upload failed', {
description: errorMessage,
duration: 10000, // Show error for 10 seconds
});
} finally {
setUploading(false);
}
};
return (
<div className="min-h-screen py-12">
<div className="container mx-auto px-4">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="max-w-4xl mx-auto"
>
{/* Header */}
<div className="text-center mb-12">
<div className="flex justify-center mb-4">
<div className="flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-blue-600 to-purple-600">
<Sparkles className="h-8 w-8 text-white" />
</div>
</div>
<h1 className="text-4xl sm:text-5xl font-bold mb-4">
<span className="bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
Upload Your Patent
</span>
</h1>
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
Upload a patent PDF to begin the AI-powered analysis process. We'll identify
market opportunities and match you with relevant partners.
</p>
</div>
{/* Upload Component */}
<PatentUpload onUpload={handleUpload} uploading={uploading} error={error} />
{/* Info Cards */}
<div className="grid md:grid-cols-3 gap-6 mt-12">
<Card>
<CardHeader>
<CardTitle className="text-lg">πŸ“„ File Requirements</CardTitle>
</CardHeader>
<CardContent>
<ul className="text-sm text-gray-600 space-y-2">
<li>β€’ PDF format only</li>
<li>β€’ Maximum 50MB</li>
<li>β€’ Clear, readable text</li>
</ul>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="text-lg">⚑ Processing Time</CardTitle>
</CardHeader>
<CardContent>
<ul className="text-sm text-gray-600 space-y-2">
<li>β€’ Patent Analysis: ~30s</li>
<li>β€’ Market Research: ~1min</li>
<li>β€’ Partner Matching: ~2min</li>
<li>β€’ Total: 2-5 minutes</li>
</ul>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="text-lg">🎯 What You'll Get</CardTitle>
</CardHeader>
<CardContent>
<ul className="text-sm text-gray-600 space-y-2">
<li>β€’ TRL Assessment</li>
<li>β€’ Market Opportunities</li>
<li>β€’ Partner Matches</li>
<li>β€’ Valorization Brief</li>
</ul>
</CardContent>
</Card>
</div>
{/* Features List */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.2 }}
className="mt-12"
>
<Card className="bg-gradient-to-br from-blue-50 to-purple-50 border-blue-200">
<CardContent className="p-8">
<h3 className="text-xl font-semibold mb-4 text-center">
πŸ€– Powered by Multi-Agent AI System
</h3>
<div className="grid sm:grid-cols-2 gap-4 text-sm text-gray-700">
<div className="flex items-start space-x-2">
<span className="text-blue-600">βœ“</span>
<span>PlannerAgent orchestrates the workflow</span>
</div>
<div className="flex items-start space-x-2">
<span className="text-blue-600">βœ“</span>
<span>CriticAgent ensures quality</span>
</div>
<div className="flex items-start space-x-2">
<span className="text-purple-600">βœ“</span>
<span>DocumentAnalysisAgent extracts innovations</span>
</div>
<div className="flex items-start space-x-2">
<span className="text-purple-600">βœ“</span>
<span>MarketAnalysisAgent finds opportunities</span>
</div>
<div className="flex items-start space-x-2">
<span className="text-green-600">βœ“</span>
<span>MatchmakingAgent finds partners</span>
</div>
<div className="flex items-start space-x-2">
<span className="text-green-600">βœ“</span>
<span>OutreachAgent generates brief</span>
</div>
</div>
</CardContent>
</Card>
</motion.div>
</motion.div>
</div>
</div>
);
}