Spaces:
Running
Running
| import React, { useState, useEffect } from 'react'; | |
| import { ExternalLink, FileText, Loader2, Brain, Cpu, MessageSquare } from 'lucide-react'; | |
| import { Link } from 'react-router-dom'; | |
| import api from '../services/api'; | |
| interface Algorithm { | |
| algorithm: string; | |
| name: string; | |
| category: string; | |
| description: string; | |
| count: number; | |
| sampleIds: string[]; | |
| } | |
| interface Paper { | |
| pmid: string; | |
| title: string; | |
| authors: string[]; | |
| journal: string; | |
| pubDate: string; | |
| } | |
| interface AlgorithmCardProps { | |
| algorithm: Algorithm; | |
| problem: string; | |
| onSeeMorePapers: (algorithm: string) => void; | |
| } | |
| const AlgorithmCard: React.FC<AlgorithmCardProps> = ({ algorithm, problem, onSeeMorePapers }) => { | |
| const [samplePapers, setSamplePapers] = useState<Paper[]>([]); | |
| const [loadingPapers, setLoadingPapers] = useState(false); | |
| useEffect(() => { | |
| // Temporarily disabled to avoid PubMed API rate limiting issues | |
| // if (algorithm.sampleIds.length > 0) { | |
| // fetchSamplePapers(); | |
| // } | |
| }, [algorithm.sampleIds]); | |
| const fetchSamplePapers = async () => { | |
| try { | |
| setLoadingPapers(true); | |
| console.log(`[${algorithm.name}] Fetching sample papers for IDs:`, algorithm.sampleIds); | |
| const papers = []; | |
| // Fetch papers sequentially with delays to avoid rate limiting | |
| for (let i = 0; i < algorithm.sampleIds.length && i < 2; i++) { | |
| try { | |
| console.log(`[${algorithm.name}] Fetching paper ${i + 1}/${Math.min(algorithm.sampleIds.length, 2)}: ${algorithm.sampleIds[i]}`); | |
| if (i > 0) { | |
| // Add delay between requests to avoid rate limiting | |
| await new Promise(resolve => setTimeout(resolve, 500)); | |
| } | |
| const response = await api.get(`/pubmed/paper/${algorithm.sampleIds[i]}`); | |
| console.log(`[${algorithm.name}] Response for ${algorithm.sampleIds[i]}:`, response.status, response.data); | |
| if (response.data && response.data.title) { | |
| papers.push(response.data); | |
| console.log(`[${algorithm.name}] Successfully added paper: ${response.data.title}`); | |
| } else { | |
| console.log(`[${algorithm.name}] Invalid paper data for ${algorithm.sampleIds[i]}:`, response.data); | |
| } | |
| } catch (error) { | |
| console.error(`[${algorithm.name}] Failed to fetch paper ${algorithm.sampleIds[i]}:`, { | |
| status: error.response?.status, | |
| statusText: error.response?.statusText, | |
| data: error.response?.data, | |
| message: error.message | |
| }); | |
| // Continue with next paper if one fails | |
| } | |
| } | |
| console.log(`[${algorithm.name}] Final fetched papers:`, papers); | |
| setSamplePapers(papers); | |
| } catch (error) { | |
| console.error(`[${algorithm.name}] Failed to fetch sample papers:`, error); | |
| } finally { | |
| setLoadingPapers(false); | |
| } | |
| }; | |
| const getCategoryIcon = (category: string) => { | |
| switch (category) { | |
| case 'deep_learning': | |
| return <Cpu className="h-5 w-5 text-purple-600" />; | |
| case 'llms': | |
| return <MessageSquare className="h-5 w-5 text-green-600" />; | |
| default: | |
| return <Brain className="h-5 w-5 text-blue-600" />; | |
| } | |
| }; | |
| const getCategoryColor = (category: string) => { | |
| switch (category) { | |
| case 'deep_learning': | |
| return 'bg-purple-100 text-purple-800'; | |
| case 'llms': | |
| return 'bg-green-100 text-green-800'; | |
| default: | |
| return 'bg-blue-100 text-blue-800'; | |
| } | |
| }; | |
| return ( | |
| <div className="bg-white rounded-lg shadow-md hover:shadow-lg transition-shadow duration-200 overflow-hidden h-full flex flex-col"> | |
| <div className="p-6 flex-grow"> | |
| <div className="flex items-start justify-between mb-4"> | |
| <div className="flex items-center space-x-3"> | |
| {getCategoryIcon(algorithm.category)} | |
| <Link | |
| to={`/algorithm/${algorithm.algorithm}`} | |
| className="text-lg font-semibold text-gray-900 leading-tight hover:text-blue-600 transition-colors" | |
| > | |
| {algorithm.name} | |
| </Link> | |
| </div> | |
| <span className={`px-3 py-1 rounded-full text-xs font-semibold ${getCategoryColor(algorithm.category)} whitespace-nowrap ml-2`}> | |
| {algorithm.category === 'deep_learning' ? 'Deep Learning' : algorithm.category === 'llms' ? 'LLMs' : 'Classical ML'} | |
| </span> | |
| </div> | |
| <p className="text-gray-600 text-sm mb-4">{algorithm.description}</p> | |
| <div className="mb-4"> | |
| <div className="text-center bg-gray-50 rounded-lg p-4"> | |
| <div className="text-3xl font-bold text-gray-900">{algorithm.count.toLocaleString()}</div> | |
| <div className="text-sm text-gray-500 font-medium">Papers Found</div> | |
| </div> | |
| </div> | |
| {algorithm.sampleIds.length > 0 && ( | |
| <div className="mb-4"> | |
| <h4 className="text-sm font-medium text-gray-900 mb-2">Sample Papers:</h4> | |
| {loadingPapers ? ( | |
| <div className="flex items-center justify-center py-4"> | |
| <Loader2 className="h-4 w-4 animate-spin text-gray-400" /> | |
| <span className="ml-2 text-sm text-gray-500">Loading papers...</span> | |
| </div> | |
| ) : samplePapers.length > 0 ? ( | |
| <div className="space-y-3"> | |
| {samplePapers.slice(0, 2).map((paper) => ( | |
| <div key={paper.pmid} className="p-3 bg-gray-50 rounded-lg border border-gray-100"> | |
| <p className="font-medium text-gray-900 text-sm line-clamp-2 mb-1">{paper.title}</p> | |
| <p className="text-gray-500 text-xs"> | |
| {paper.journal} {paper.pubDate && `(${paper.pubDate})`} | |
| </p> | |
| </div> | |
| ))} | |
| </div> | |
| ) : ( | |
| <div className="p-3 bg-blue-50 rounded-lg border border-blue-100"> | |
| <p className="text-xs text-blue-600 text-center"> | |
| {algorithm.count} papers found - Click "See More Papers on PubMed" to view | |
| </p> | |
| </div> | |
| )} | |
| </div> | |
| )} | |
| </div> | |
| <div className="p-6 pt-0 mt-auto"> | |
| <button | |
| onClick={() => onSeeMorePapers(algorithm.algorithm)} | |
| className="w-full bg-blue-600 text-white py-3 px-4 rounded-lg hover:bg-blue-700 transition-colors flex items-center justify-center text-sm font-medium shadow-sm" | |
| > | |
| <ExternalLink className="h-4 w-4 mr-2" /> | |
| See More Papers on PubMed | |
| </button> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default AlgorithmCard; |