Spaces:
Runtime error
Runtime error
Upload utils.py with huggingface_hub
Browse files
utils.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
from typing import Any, Dict, List, Optional
|
| 3 |
+
import time
|
| 4 |
+
|
| 5 |
+
def safe_get(data: Dict, key: str, default: Any = None) -> Any:
|
| 6 |
+
"""Safely get nested dictionary values"""
|
| 7 |
+
try:
|
| 8 |
+
for k in key.split('.'):
|
| 9 |
+
data = data[k]
|
| 10 |
+
return data
|
| 11 |
+
except (KeyError, TypeError):
|
| 12 |
+
return default
|
| 13 |
+
|
| 14 |
+
def format_duration(ms: int) -> str:
|
| 15 |
+
"""Convert milliseconds to MM:SS format"""
|
| 16 |
+
seconds = ms // 1000
|
| 17 |
+
minutes = seconds // 60
|
| 18 |
+
seconds = seconds % 60
|
| 19 |
+
return f"{minutes}:{seconds:02d}"
|
| 20 |
+
|
| 21 |
+
def parse_spotify_url(url: str) -> tuple:
|
| 22 |
+
"""Parse Spotify URL to get type and ID"""
|
| 23 |
+
if 'track' in url:
|
| 24 |
+
parts = url.split('/track/')
|
| 25 |
+
if len(parts) > 1:
|
| 26 |
+
track_id = parts[1].split('?')[0]
|
| 27 |
+
return 'track', track_id
|
| 28 |
+
elif 'playlist' in url:
|
| 29 |
+
parts = url.split('/playlist/')
|
| 30 |
+
if len(parts) > 1:
|
| 31 |
+
playlist_id = parts[1].split('?')[0]
|
| 32 |
+
return 'playlist', playlist_id
|
| 33 |
+
elif 'artist' in url:
|
| 34 |
+
parts = url.split('/artist/')
|
| 35 |
+
if len(parts) > 1:
|
| 36 |
+
artist_id = parts[1].split('?')[0]
|
| 37 |
+
return 'artist', artist_id
|
| 38 |
+
elif 'album' in url:
|
| 39 |
+
parts = url.split('/album/')
|
| 40 |
+
if len(parts) > 1:
|
| 41 |
+
album_id = parts[1].split('?')[0]
|
| 42 |
+
return 'album', album_id
|
| 43 |
+
return None, None
|
| 44 |
+
|
| 45 |
+
def validate_api_keys() -> bool:
|
| 46 |
+
"""Check if required API keys are set"""
|
| 47 |
+
provider = st.session_state.ai_provider
|
| 48 |
+
if provider == "OpenAI" and st.session_state.openai_api_key:
|
| 49 |
+
return True
|
| 50 |
+
elif provider == "Anthropic" and st.session_state.anthropic_api_key:
|
| 51 |
+
return True
|
| 52 |
+
elif provider == "OpenRouter" and st.session_state.openrouter_api_key:
|
| 53 |
+
return True
|
| 54 |
+
return False
|
| 55 |
+
|
| 56 |
+
def get_spotify_image_url(item: Dict, size: str = 'medium') -> str:
|
| 57 |
+
"""Get image URL from Spotify item"""
|
| 58 |
+
images = safe_get(item, 'images', [])
|
| 59 |
+
if not images:
|
| 60 |
+
images = safe_get(item, 'album.images', [])
|
| 61 |
+
|
| 62 |
+
if not images:
|
| 63 |
+
return ""
|
| 64 |
+
|
| 65 |
+
if size == 'large':
|
| 66 |
+
return images[0]['url']
|
| 67 |
+
elif size == 'medium':
|
| 68 |
+
return images[len(images)//2]['url'] if len(images) > 1 else images[0]['url']
|
| 69 |
+
else:
|
| 70 |
+
return images[-1]['url']
|
| 71 |
+
|
| 72 |
+
def create_track_uri(track_id: str) -> str:
|
| 73 |
+
"""Create Spotify track URI from ID"""
|
| 74 |
+
return f"spotify:track:{track_id}"
|
| 75 |
+
|
| 76 |
+
def create_playlist_uri(playlist_id: str) -> str:
|
| 77 |
+
"""Create Spotify playlist URI from ID"""
|
| 78 |
+
return f"spotify:playlist:{playlist_id}"
|
| 79 |
+
|
| 80 |
+
def chunk_list(lst: List, chunk_size: int) -> List[List]:
|
| 81 |
+
"""Split list into chunks"""
|
| 82 |
+
return [lst[i:i + chunk_size] for i in range(0, len(lst), chunk_size)]
|
| 83 |
+
|
| 84 |
+
def retry_with_backoff(func, max_retries=3, initial_delay=1):
|
| 85 |
+
"""Retry function with exponential backoff"""
|
| 86 |
+
for i in range(max_retries):
|
| 87 |
+
try:
|
| 88 |
+
return func()
|
| 89 |
+
except Exception as e:
|
| 90 |
+
if i == max_retries - 1:
|
| 91 |
+
raise e
|
| 92 |
+
delay = initial_delay * (2 ** i)
|
| 93 |
+
time.sleep(delay)
|
| 94 |
+
return None
|