"""
Utility functions for the vibe-reader application
"""
import json
import re
from typing import Dict, Any, Optional
def parse_json_response(response: str) -> Optional[Dict[str, Any]]:
"""
Parse JSON from LLM response, handling various formats
Args:
response: Raw LLM response that may contain JSON
Returns:
Parsed JSON dict, or None if parsing fails
"""
# Remove markdown code blocks if present
cleaned = re.sub(r'```json\s*|\s*```', '', response, flags=re.IGNORECASE)
cleaned = cleaned.strip()
# Try to find JSON object in the response
json_match = re.search(r'\{.*\}', cleaned, re.DOTALL)
if json_match:
try:
return json.loads(json_match.group(0))
except json.JSONDecodeError as e:
print(f"JSON parsing error: {e}")
return None
return None
def extract_vibe_components(vibe_json: Dict[str, Any]) -> Dict[str, Any]:
"""
Extract and validate vibe components from parsed JSON
Args:
vibe_json: Parsed JSON from vibe extraction
Returns:
Dictionary with validated vibe components
"""
return {
"aesthetic_genre_keywords": vibe_json.get("aesthetic_genre_keywords", []),
"mood_atmosphere": vibe_json.get("mood_atmosphere", []),
"core_themes": vibe_json.get("core_themes", []),
"tropes": vibe_json.get("tropes", []),
"feels_like": vibe_json.get("feels_like", "")
}
def strip_thinking_tags(text: str) -> str:
"""
Remove ... tags and any reasoning content from text
Qwen3 uses standard XML format: ...
Args:
text: Text that may contain thinking tags
Returns:
Clean text without thinking tags
"""
# Remove ... blocks
cleaned = re.sub(r'.*?', '', text, flags=re.DOTALL | re.IGNORECASE)
# Remove any leftover tags
cleaned = re.sub(r'?think>', '', cleaned, flags=re.IGNORECASE)
return cleaned.strip()