Spaces:
Build error
Build error
Enhance follow-up detection logic in RecommendationService - Added checks to differentiate between follow-up queries and new primary artist queries based on current and previous artist mentions. Updated context handling rules in ContextAwareIntentAnalyzer to clarify follow-up criteria and improve intent management. This update aims to refine user experience by ensuring accurate query handling and maintaining session context effectively.
Browse files
src/services/components/context_handler.py
CHANGED
|
@@ -132,45 +132,33 @@ class ContextAwareIntentAnalyzer:
|
|
| 132 |
|
| 133 |
Previous query: "{recent_query}"
|
| 134 |
Previous artists mentioned: {previous_artists}
|
| 135 |
-
Original session intent: {original_intent}
|
| 136 |
-
Artist-focused session: {was_artist_focused}
|
| 137 |
Current query: "{query}"
|
|
|
|
|
|
|
| 138 |
|
| 139 |
-
|
| 140 |
-
1. If
|
| 141 |
-
2.
|
| 142 |
-
3.
|
|
|
|
| 143 |
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
|
|
|
|
|
|
|
|
|
| 148 |
|
| 149 |
-
|
| 150 |
-
β
FOLLOW-UP: "More tracks" (after "Music by Kendrick Lamar") β artist_deep_dive
|
| 151 |
-
β
FOLLOW-UP: "More like this" β style_continuation
|
| 152 |
-
β
FOLLOW-UP: "More Kendrick tracks" (same artist) β artist_deep_dive
|
| 153 |
-
β NOT FOLLOW-UP: "Music by Kendrick Lamar" (new primary query, even if different from previous)
|
| 154 |
-
β NOT FOLLOW-UP: "Songs by The Beatles" (new primary query)
|
| 155 |
-
β NOT FOLLOW-UP: "Tracks by Drake" (new primary query)
|
| 156 |
-
|
| 157 |
-
π¨ IMPORTANT: If current query is a complete standalone request about a different artist,
|
| 158 |
-
it should ALWAYS be is_followup=false, regardless of conversation history!
|
| 159 |
-
|
| 160 |
-
Return JSON:
|
| 161 |
{{
|
| 162 |
-
"is_followup":
|
| 163 |
-
"followup_type": "artist_deep_dive" | "
|
| 164 |
-
"target_entity": "
|
| 165 |
-
"style_modifier":
|
| 166 |
-
"confidence":
|
| 167 |
-
"reasoning":
|
| 168 |
}}
|
| 169 |
-
|
| 170 |
-
Follow-up types:
|
| 171 |
-
- "artist_deep_dive": More tracks from SAME artist OR generic "more" in artist-focused session
|
| 172 |
-
- "style_continuation": More of same style without artist reference in non-artist sessions
|
| 173 |
-
- "artist_style_refinement": More tracks from SAME artist with style constraint
|
| 174 |
"""
|
| 175 |
|
| 176 |
response = await self.llm_utils.call_llm_with_json_response(
|
|
@@ -280,6 +268,15 @@ class ContextAwareIntentAnalyzer:
|
|
| 280 |
'genres': [],
|
| 281 |
'moods': []
|
| 282 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 283 |
elif followup_type == 'artist_similarity_continuation':
|
| 284 |
# For artist similarity continuation, extract entities from history
|
| 285 |
entities = self._extract_complete_entities_from_history(history)
|
|
|
|
| 132 |
|
| 133 |
Previous query: "{recent_query}"
|
| 134 |
Previous artists mentioned: {previous_artists}
|
|
|
|
|
|
|
| 135 |
Current query: "{query}"
|
| 136 |
+
Original intent: {original_intent}
|
| 137 |
+
Was artist-focused: {was_artist_focused}
|
| 138 |
|
| 139 |
+
CRITICAL RULES:
|
| 140 |
+
1. If query mentions "like [Artist Name]" or "similar to [Artist]", this is NEVER a follow-up - it's a new primary query for that specific artist's style.
|
| 141 |
+
2. Follow-ups modify existing context (e.g., "more upbeat", "different genre", "more tracks") without introducing NEW primary entities.
|
| 142 |
+
3. When you detect a similarity query like "Songs like Mk.gee", set target_entity to the mentioned artist ("Mk.gee"), NOT None.
|
| 143 |
+
4. Only set is_followup=true if the query modifies the CURRENT/RECENT context without naming a different primary artist.
|
| 144 |
|
| 145 |
+
EXAMPLES:
|
| 146 |
+
β
FOLLOW-UP: "Make them more upbeat" (after any query) β is_followup: true, intent should remain same
|
| 147 |
+
β
FOLLOW-UP: "More tracks like this" (after any query) β is_followup: true, target_entity: null
|
| 148 |
+
β
FOLLOW-UP: "Different genre please" (after any query) β is_followup: true, target_entity: null
|
| 149 |
+
β NOT FOLLOW-UP: "Songs like Mk.gee" (after discussing The Beatles) β is_followup: false, target_entity: "Mk.gee", intent should be artist_similarity
|
| 150 |
+
β NOT FOLLOW-UP: "Music by Radiohead" (after any query) β is_followup: false, target_entity: "Radiohead", intent should be by_artist
|
| 151 |
+
β NOT FOLLOW-UP: "Jazz music" (after any query) β is_followup: false, target_entity: null, intent should be genre_mood
|
| 152 |
|
| 153 |
+
Return JSON with:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
{{
|
| 155 |
+
"is_followup": boolean,
|
| 156 |
+
"followup_type": "style_continuation" | "artist_deep_dive" | "genre_shift" | "mood_shift" | "preference_refinement" | "none",
|
| 157 |
+
"target_entity": string or null (IMPORTANT: For "Songs like X" queries, set this to X, not null),
|
| 158 |
+
"style_modifier": string or null,
|
| 159 |
+
"confidence": float,
|
| 160 |
+
"reasoning": string
|
| 161 |
}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 162 |
"""
|
| 163 |
|
| 164 |
response = await self.llm_utils.call_llm_with_json_response(
|
|
|
|
| 268 |
'genres': [],
|
| 269 |
'moods': []
|
| 270 |
}
|
| 271 |
+
elif target_entity and followup_type in ['style_continuation', 'artist_similarity']:
|
| 272 |
+
# π§ CRITICAL FIX: For similarity queries with explicit target entity (like "Songs like Mk.gee")
|
| 273 |
+
# Use the target entity as the primary artist, don't fall back to history
|
| 274 |
+
entities = {
|
| 275 |
+
'artists': [target_entity],
|
| 276 |
+
'tracks': [],
|
| 277 |
+
'genres': [],
|
| 278 |
+
'moods': []
|
| 279 |
+
}
|
| 280 |
elif followup_type == 'artist_similarity_continuation':
|
| 281 |
# For artist similarity continuation, extract entities from history
|
| 282 |
entities = self._extract_complete_entities_from_history(history)
|
src/services/recommendation_service.py
CHANGED
|
@@ -10,6 +10,7 @@ Target: 72KB β ~30KB (60% reduction)
|
|
| 10 |
import asyncio
|
| 11 |
from typing import Dict, List, Any, Optional
|
| 12 |
from dataclasses import dataclass
|
|
|
|
| 13 |
|
| 14 |
import structlog
|
| 15 |
import uuid
|
|
@@ -483,6 +484,33 @@ class RecommendationService:
|
|
| 483 |
query_lower = request.query.lower().strip()
|
| 484 |
is_likely_followup = any(indicator in query_lower for indicator in followup_indicators)
|
| 485 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 486 |
if is_likely_followup:
|
| 487 |
self.logger.info(
|
| 488 |
"π Follow-up query detected - preserving session",
|
|
@@ -630,8 +658,6 @@ class RecommendationService:
|
|
| 630 |
Returns:
|
| 631 |
Tuple of (artists_set, genres_set)
|
| 632 |
"""
|
| 633 |
-
import re
|
| 634 |
-
|
| 635 |
query_lower = query.lower()
|
| 636 |
artists = set()
|
| 637 |
genres = set()
|
|
|
|
| 10 |
import asyncio
|
| 11 |
from typing import Dict, List, Any, Optional
|
| 12 |
from dataclasses import dataclass
|
| 13 |
+
import re # Add this import for regex pattern matching
|
| 14 |
|
| 15 |
import structlog
|
| 16 |
import uuid
|
|
|
|
| 484 |
query_lower = request.query.lower().strip()
|
| 485 |
is_likely_followup = any(indicator in query_lower for indicator in followup_indicators)
|
| 486 |
|
| 487 |
+
# Additional check: avoid detecting new artist queries as follow-ups
|
| 488 |
+
# If query explicitly mentions a different artist than previous, it's NOT a follow-up
|
| 489 |
+
if not is_likely_followup:
|
| 490 |
+
# Extract entities from current query to detect new artist mentions
|
| 491 |
+
current_artists, _ = self._extract_entities_from_query(request.query)
|
| 492 |
+
last_entities = last_interaction.get('entities', {})
|
| 493 |
+
last_artists = set()
|
| 494 |
+
|
| 495 |
+
# Get previous artists from last interaction
|
| 496 |
+
if 'target_artists' in last_entities:
|
| 497 |
+
last_artists.update([a.lower().strip() for a in last_entities['target_artists']])
|
| 498 |
+
if 'target_artist' in last_entities:
|
| 499 |
+
last_artists.add(last_entities['target_artist'].lower().strip())
|
| 500 |
+
|
| 501 |
+
# If current query mentions different artists, it's definitely NOT a follow-up
|
| 502 |
+
if current_artists and last_artists:
|
| 503 |
+
artist_overlap = last_artists.intersection(current_artists)
|
| 504 |
+
if not artist_overlap:
|
| 505 |
+
self.logger.info(
|
| 506 |
+
"π― Different artist detected - treating as new primary query",
|
| 507 |
+
last_artists=list(last_artists),
|
| 508 |
+
current_artists=list(current_artists),
|
| 509 |
+
query=request.query
|
| 510 |
+
)
|
| 511 |
+
# Force new session for different artist queries
|
| 512 |
+
return True
|
| 513 |
+
|
| 514 |
if is_likely_followup:
|
| 515 |
self.logger.info(
|
| 516 |
"π Follow-up query detected - preserving session",
|
|
|
|
| 658 |
Returns:
|
| 659 |
Tuple of (artists_set, genres_set)
|
| 660 |
"""
|
|
|
|
|
|
|
| 661 |
query_lower = query.lower()
|
| 662 |
artists = set()
|
| 663 |
genres = set()
|