| 415 | } |
| 416 | |
| 417 | std::vector<ModelMarketItem> ModelRepository::SearchModels(const std::string& keyword) { |
| 418 | std::vector<ModelMarketItem> searchResults; |
| 419 | |
| 420 | if (keyword.empty()) { |
| 421 | LOG_DEBUG_TAG("Search keyword is empty, returning all LLM models", kTag); |
| 422 | // Return all LLM models filtered by current source |
| 423 | return ProcessModels(GetModels()); |
| 424 | } |
| 425 | |
| 426 | try { |
| 427 | auto data = GetModelMarketData(); |
| 428 | if (!data) { |
| 429 | LOG_DEBUG_TAG("No model market data available for search", kTag); |
| 430 | return searchResults; |
| 431 | } |
| 432 | |
| 433 | LOG_DEBUG_TAG("Searching for models with keyword: '" + keyword + "'", kTag); |
| 434 | LOG_DEBUG_TAG("Current download provider: " + current_download_provider_, kTag); |
| 435 | |
| 436 | // Helper function to check if text contains keyword (case-insensitive) |
| 437 | auto containsKeyword = [&keyword](const std::string& text) -> bool { |
| 438 | if (text.empty()) return false; |
| 439 | std::string lowerText = text; |
| 440 | std::string lowerKeyword = keyword; |
| 441 | |
| 442 | // Convert to lowercase for case-insensitive comparison |
| 443 | std::transform(lowerText.begin(), lowerText.end(), lowerText.begin(), ::tolower); |
| 444 | std::transform(lowerKeyword.begin(), lowerKeyword.end(), lowerKeyword.begin(), ::tolower); |
| 445 | |
| 446 | return lowerText.find(lowerKeyword) != std::string::npos; |
| 447 | }; |
| 448 | |
| 449 | // Helper function to check if model supports current source |
| 450 | auto supportsCurrentSource = [this](const ModelMarketItem& model) -> bool { |
| 451 | for (const auto& [source, repoPath] : model.sources) { |
| 452 | if (CaseInsensitiveEquals(source, current_download_provider_)) { |
| 453 | return true; |
| 454 | } |
| 455 | } |
| 456 | return false; |
| 457 | }; |
| 458 | |
| 459 | // Search only in LLM models (not TTS or ASR) |
| 460 | for (const auto& model : data->models) { |
| 461 | // First check if model supports current source |
| 462 | if (!supportsCurrentSource(model)) { |
| 463 | LOG_DEBUG_TAG("Model '" + model.modelName + "' does not support current source '" + current_download_provider_ + "', skipping", kTag); |
| 464 | continue; |
| 465 | } |
| 466 | |
| 467 | // Check if model name contains keyword |
| 468 | bool nameMatches = containsKeyword(model.modelName); |
| 469 | |
| 470 | // Check if vendor contains keyword |
| 471 | bool vendorMatches = containsKeyword(model.vendor); |
| 472 | |
| 473 | // Only match model name and vendor (ignore categories and tags) |
| 474 | if (nameMatches || vendorMatches) { |
no test coverage detected