AleksanderObuchowski's picture
Initial commit for Hugging Face Spaces
e4f1db2
raw
history blame
6.72 kB
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;