feat(ai): split settings into Provider and Generation tabs, add searchable selector, LYRICS prompt type; perf: optimize library init#2497
Open
VoidX3D wants to merge 20 commits into
Open
Conversation
…path - Merge migrateTabOrder, ensureLibrarySortDefaults, and legacy favorite migration into a single deferred coroutine (2s delay) - Defer loadPersistedDailyMix and loadSearchHistory to after first frame (1.5s delay) - This prevents DataStore first() calls and DB queries from blocking the critical init path that feeds first-frame rendering
…storage - Load songs first (most critical tab, needed for Songs tab rendering) - Chain albums after songs, artists after albums, folders after artists using Job.join() to prevent 4 simultaneous Room queries from competing for limited I/O bandwidth on eMMC storage (Redmi) - Reduces GC pressure from concurrent heap allocations
…om queries - Replace songCountFlow (Room query) with allSongsFlow (in-memory) - Now all 3 flows in the combine are in-memory StateFlows, not Room queries - Eliminates redundant SELECT COUNT(*) query that re-emitted on every songs table write during sync
- Remove individual _isLoadingCategories toggles from albums and artists jobs (they no longer manage their own loading state) - Add a single watcher coroutine that sets _isLoadingCategories = true when songs complete, then false when all sequential jobs finish - Prevents 3 redundant recompositions of LibraryScreen through playerUiState during initial data load
- Library folders/loading combine: skip update when Triple unchanged - Sort options combine: skip update when SortOptionsSnapshot unchanged - AiUiSnapshot combine: skip update when snapshot unchanged - Prevents cascading recompositions of LibraryScreen from redundant playerUiState emissions during multiple rapid state changes
…quests - Add LYRICS to AiSystemPromptType enum - Add LYRICS case to AiSystemPromptEngine.buildPrompt with role/strategy - Update translateLyrics in AiStateHolder to use AiSystemPromptType.LYRICS - Add 'Lyrics' display label to formatPromptType in AiUsageComponents - Lyrics translation requests now appear distinctly in AI activity logs
… Parameters tab - Add GENERATION_PARAMETERS category to SettingsCategory enum with Tune icon - AI Integration tab now keeps only: provider selection, API key entry, model selection, base URL, and activity logs - New Generation Parameters tab gets: system prompt editor, temperature, top P, top K, max tokens, presence/frequency penalty, sample size, digest mode, and extended song fields - Add English string resources for the new category
…earch - Add description field to AiProvider enum entries - Create SearchableProviderSelector composable similar to SearchableModelSelector with search, filtering, and count label - Replace ThemeSelectorItem in AI_INTEGRATION settings with SearchableProviderSelector for provider selection - Search covers name, displayName, and description fields
- Update AI subtitle to reflect model selection and activity logs - Add GENERATION_PARAMETERS category strings to all locales - All new strings use English as fallback pending translator contributions
… method - Remove dead hasGeminiApiKey StateFlow in PlayerViewModel - Remove dead songCountFlow StateFlow in PlayerViewModel - Remove unused getSongCountFlow() from MusicRepository interface and impl - Remove corresponding mock from PlayerViewModelTest
…pressions - Add LYRICS case to temperature selection in AiHandler.kt - Add GENERATION_PARAMETERS case to category colors in SettingsScreen.kt (both dark and light color schemes)
- Increase toast buffer from 1 to 5 to prevent rapid status/error drops
- Add status display card to CreateAiPlaylistDialog showing real-time
AI progress ("Analyzing...", "Selecting...", etc.)
- Pass aiStatus from LibraryScreen to CreateAiPlaylistDialog
- Fix missing import for RoundedCornerShape
…layerUiState - Expose searchResults, selectedSearchFilter, searchHistory directly from PlayerViewModel instead of deriving from 40-field playerUiState - Defer genre loading to LaunchedEffect gated by showGenreBrowse, avoiding heavy SELECT DISTINCT genre query on every navigation - Guard LaunchedEffect to skip performSearch for empty queries - Remove unused SearchUiSlice wrapper and flow imports
…ault models - Update AiProvider descriptions to reflect latest model families - Ollama: change to requiresApiKey=true with configurable URL (cloud) - DeepSeek: update endpoint to /v1, default deepseek-chat - Groq: update default to llama-3.3-70b-versatile - Mistral: update default to mistral-large-2411 - NVIDIA: update default to nemotron-70b-instruct - Kimi: update default to moonshot-v1-auto - GLM: update default to glm-4-plus - OpenRouter: update default to gemini-2.5-flash-preview free - Ollama: clear default URL (user configures their endpoint) - Allow empty API key for providers with requiresApiKey=false
… cooldowns - Replace mutableMapOf with ConcurrentHashMap for thread-safe cooldown tracking - Clean up expired cooldown entries on each generateContent call to prevent stale entries accumulating over time and blocking all providers - Reduce cooldown from 5 minutes to 2 minutes for faster recovery - Skip API key check for providers that don't require one
…and streamline base URL handling in settings
…lly scale maxTokens - Enhanced AiResponseCleaner.cleanTextResponse to strip paired **text**/__text__ markers - Strip conversational framing lines prepended by AI (Here is, Sure!, etc.) - Apply cleaning in AiStateHolder.translateLyrics before returning response - Dynamically scale maxTokens for LYRICS type based on input size (2x+ output, 4096 min, 16384 max) - Prevents aggressive cut-off and formatting markers in AI-translated lyrics
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR: AI Provider Overhaul + Performance Optimization + Bug Fixes
Overview
This comprehensive PR (20 commits, 33 files modified, +527/-221 lines) delivers major performance improvements, AI architecture consolidation, and critical bug fixes across the application.
📊 Impact Summary
🚀 Performance Optimizations
Library Loading Overhaul (6 commits)
Deferred Non-Critical Operations
migrateTabOrder,ensureLibrarySortDefaults, favorite migrationloadPersistedDailyMix,loadSearchHistorySerialized Data Loading
songs → albums → artists → foldersJob.join()to prevent 4 simultaneous Room queriesIn-Memory State Optimization
songCountFlow(RoomSELECT COUNT(*)) withallSongsFlow(in-memoryStateFlow)Loading State Stability
isLoadingCategoriesdistinctUntilChangedtoplayerUiStatecombinesSearch Tab Performance (1 commit)
Decoupled from Monolithic State
PlayerUiStatesearchResults,selectedSearchFilter,searchHistorydirectly fromSearchStateHolderLazy Genre Query
SELECT DISTINCT genre FROM songstriggered viaLaunchedEffectGuarded Empty Query
performSearch("")on navigation🤖 AI Provider System Overhaul
Provider Expansion
requiresApiKey=true,hasConfigurableUrl=true)Architecture Consolidation (3 redundant classes removed)
DeepSeekClient,GroqClient,MistralClient→GenericOpenAiClientUnifiedModelFilterfor consistent model filtering across all 11 providersUpdated Provider Data
api.deepseek.com/v1api.groq.com/openai/v1api.mistral.ai/v1integrate.api.nvidia.com/v1api.moonshot.cn/v1open.bigmodel.cn/api/paas/v4openrouter.ai/api/v1api.ollama.ai/v1AI Settings UI Refactor
Split into Two Tabs
New Components
SearchableProviderSelector- Live search across provider name, displayName, descriptionThemeSelectorItemfor provider selectionAI Response & Stability Fixes
Response Cleaning
AiResponseCleanerstrips**bold**/__underline__paired markersDynamic Token Scaling
Live Status Feedback
CreateAiPlaylistDialogshows real-time status cardToast System Enhancement
Provider Cooldown Improvements
mutableMapOfwithConcurrentHashMapConfiguration Fixes
CUSTOM)AiHandleruses user-configured base URL forhasConfigurableUrlprovidershasActiveAiProviderApiKeynow explicitly handles all providers🐛 Bug Fixes
Exhaustive
whenExpressionsLYRICSandGENERATION_PARAMETERSbranchesExperimental API Compliance
@OptIn(ExperimentalMaterial3Api::class)on searchable selectors🗑️ Dead Code Removal
AiMetadataGenerator(unused)hasGeminiApiKeysongCountFlowand repository method🌍 Localization
🧪 Recommended Testing Checklist
Performance
AI Integration
AI Responses
UI/UX
📁 Files Changed Summary
Packages Modified
data/ai/- Provider models, clients, handlersdata/repository/- Library loading, search optimizationpresentation/viewmodel/- PlayerUiState, SearchStateHolderpresentation/screens/- SearchScreen, CreateAiPlaylistDialogpresentation/components/- SearchableProviderSelectorres/values-*/- All 11 locale filesKey File Changes
~31 files modified, ~527 insertions, ~221 deletions