@@ -306,7 +306,7 @@ def _decompress_content(self, content: bytes, headers: Dict[str, str]) -> bytes:
306306 return content
307307
308308 async def search_package (self , name : str ) -> List [RepositoryPackage ]:
309- """Search for specific package."""
309+ """Search for specific package with relevance scoring ."""
310310 search_url = self .endpoints .get ("search" )
311311
312312 if search_url :
@@ -316,16 +316,17 @@ async def search_package(self, name: str) -> List[RepositoryPackage]:
316316 url = search_url .replace ("{query}" , name ).replace ("{package}" , name )
317317 packages = await self ._download_and_parse (session , url )
318318
319- # Filter results to match search query
319+ # Filter and score results
320320 name_lower = name .lower ()
321- matching_packages = []
321+ scored_packages = []
322322 for package in packages :
323- if name_lower in package .name .lower () or (
324- package .description and name_lower in package .description .lower ()
325- ):
326- matching_packages .append (package )
323+ score = self ._calculate_relevance_score (package , name_lower )
324+ if score > 0 :
325+ scored_packages .append ((score , package ))
327326
328- return matching_packages
327+ # Sort by relevance score (highest first)
328+ scored_packages .sort (key = lambda x : x [0 ], reverse = True )
329+ return [pkg for _ , pkg in scored_packages ]
329330
330331 except Exception as e :
331332 logger .debug (f"Search endpoint failed for { name } : { e } " )
@@ -336,20 +337,47 @@ async def search_package(self, name: str) -> List[RepositoryPackage]:
336337 all_packages = await self .download_package_list ()
337338
338339 name_lower = name .lower ()
339- matching_packages = []
340+ scored_packages = []
340341
341342 for package in all_packages :
342- if name_lower in package .name .lower () or (
343- package .description and name_lower in package .description .lower ()
344- ):
345- matching_packages .append (package )
343+ score = self ._calculate_relevance_score (package , name_lower )
344+ if score > 0 :
345+ scored_packages .append ((score , package ))
346346
347- return matching_packages
347+ # Sort by relevance score (highest first)
348+ scored_packages .sort (key = lambda x : x [0 ], reverse = True )
349+ return [pkg for _ , pkg in scored_packages ]
348350
349351 except Exception as e :
350352 logger .error (f"Failed to search packages in { self .repository_info .name } : { e } " )
351353 return []
352354
355+ def _calculate_relevance_score (self , package : RepositoryPackage , query : str ) -> float :
356+ """Calculate relevance score for search results.
357+
358+ Scoring:
359+ - Exact name match: 100
360+ - Name starts with query: 50
361+ - Name contains query: 25
362+ - Description contains query: 5
363+ """
364+ score = 0.0
365+ pkg_name_lower = package .name .lower ()
366+
367+ # Name matching (highest priority)
368+ if pkg_name_lower == query :
369+ score += 100
370+ elif pkg_name_lower .startswith (query ):
371+ score += 50
372+ elif query in pkg_name_lower :
373+ score += 25
374+
375+ # Description matching (lower priority)
376+ if package .description and query in package .description .lower ():
377+ score += 5
378+
379+ return score
380+
353381 async def get_package_details (
354382 self , name : str , version : Optional [str ] = None
355383 ) -> Optional [RepositoryPackage ]:
0 commit comments