File size: 6,724 Bytes
e4f1db2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
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;