Spaces:
Running
Running
import React, { useState } from 'react'; | |
import { Search as SearchIcon, ExternalLink, FileText, Loader2 } from 'lucide-react'; | |
import api from '../services/api'; | |
import AlgorithmCard from '../components/AlgorithmCard'; | |
interface SearchResult { | |
algorithm: string; | |
name: string; | |
category: string; | |
description: string; | |
count: number; | |
sampleIds: string[]; | |
} | |
interface SearchResponse { | |
problem: string; | |
totalAlgorithms: number; | |
results: SearchResult[]; | |
allResults: SearchResult[]; | |
} | |
const Search: React.FC = () => { | |
const [problem, setProblem] = useState(''); | |
const [results, setResults] = useState<SearchResponse | null>(null); | |
const [loading, setLoading] = useState(false); | |
const [error, setError] = useState<string | null>(null); | |
const handleSearch = async (e: React.FormEvent) => { | |
e.preventDefault(); | |
if (!problem.trim()) return; | |
try { | |
setLoading(true); | |
setError(null); | |
const response = await api.post('/search/problem', { problem: problem.trim() }); | |
setResults(response.data); | |
} catch (err) { | |
setError('Failed to search for algorithms. Please try again.'); | |
} finally { | |
setLoading(false); | |
} | |
}; | |
const handleSeeMorePapers = async (algorithm: string) => { | |
try { | |
const response = await api.get('/search/pubmed-link', { | |
params: { problem, algorithm } | |
}); | |
window.open(response.data.url, '_blank'); | |
} catch (err) { | |
console.error('Failed to generate PubMed link:', err); | |
} | |
}; | |
return ( | |
<div className="max-w-6xl mx-auto space-y-8"> | |
<div className="text-center"> | |
<h1 className="text-4xl font-bold text-gray-900 mb-2"> | |
Algorithm Search | |
</h1> | |
<p className="text-xl text-gray-600"> | |
Search for AI algorithms used in specific medical problems | |
</p> | |
</div> | |
<div className="bg-white p-6 rounded-lg shadow-lg"> | |
<form onSubmit={handleSearch} className="space-y-4"> | |
<div> | |
<label htmlFor="problem" className="block text-sm font-medium text-gray-700 mb-2"> | |
Medical Problem or Condition | |
</label> | |
<div className="relative"> | |
<input | |
type="text" | |
id="problem" | |
value={problem} | |
onChange={(e) => setProblem(e.target.value)} | |
placeholder="e.g., breast cancer detection, diabetes prediction, alzheimer's disease" | |
className="w-full px-4 py-3 pl-10 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500" | |
disabled={loading} | |
/> | |
<SearchIcon className="absolute left-3 top-3.5 h-5 w-5 text-gray-400" /> | |
</div> | |
</div> | |
<button | |
type="submit" | |
disabled={loading || !problem.trim()} | |
className="w-full bg-blue-600 text-white py-3 px-4 rounded-md hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center" | |
> | |
{loading ? ( | |
<> | |
<Loader2 className="animate-spin h-5 w-5 mr-2" /> | |
Searching... | |
</> | |
) : ( | |
<> | |
<SearchIcon className="h-5 w-5 mr-2" /> | |
Search Algorithms | |
</> | |
)} | |
</button> | |
</form> | |
</div> | |
{error && ( | |
<div className="bg-red-50 border border-red-200 rounded-md p-4"> | |
<p className="text-red-800">{error}</p> | |
</div> | |
)} | |
{results && ( | |
<div className="space-y-6"> | |
<div className="bg-white p-6 rounded-lg shadow-lg"> | |
<h2 className="text-2xl font-bold text-gray-900 mb-2"> | |
Results for "{results.problem}" | |
</h2> | |
<p className="text-gray-600"> | |
Found {results.results.length} algorithms with published research | |
</p> | |
</div> | |
{results.results.length > 0 ? ( | |
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 auto-rows-fr"> | |
{results.results.map((result) => ( | |
<AlgorithmCard | |
key={result.algorithm} | |
algorithm={result} | |
problem={results.problem} | |
onSeeMorePapers={handleSeeMorePapers} | |
/> | |
))} | |
</div> | |
) : ( | |
<div className="bg-gray-50 p-8 rounded-lg text-center"> | |
<FileText className="h-12 w-12 text-gray-400 mx-auto mb-4" /> | |
<h3 className="text-lg font-medium text-gray-900 mb-2">No Results Found</h3> | |
<p className="text-gray-600"> | |
No algorithms found for this medical problem. Try searching with different terms. | |
</p> | |
</div> | |
)} | |
{results.allResults.some(r => r.count === 0) && ( | |
<div className="bg-white p-6 rounded-lg shadow-lg"> | |
<h3 className="text-lg font-medium text-gray-900 mb-4"> | |
Algorithms with No Results | |
</h3> | |
<div className="grid grid-cols-2 md:grid-cols-4 gap-2"> | |
{results.allResults | |
.filter(r => r.count === 0) | |
.map(result => ( | |
<span | |
key={result.algorithm} | |
className="px-3 py-1 bg-gray-100 text-gray-600 rounded-full text-sm" | |
> | |
{result.name} | |
</span> | |
))} | |
</div> | |
</div> | |
)} | |
</div> | |
)} | |
</div> | |
); | |
}; | |
export default Search; |