Add skip tracking, compressed heatmap, listening log, docs, tests, and OpenAI support

Major changes:
- Add skip tracking: poll currently-playing every 15s, detect skips (<30s listened)
- Add listening-log and sessions API endpoints
- Fix ReccoBeats client to extract spotify_id from href response
- Compress heatmap from 24 hours to 6 x 4-hour blocks
- Add OpenAI support in narrative service (use max_completion_tokens for new models)
- Add ListeningLog component with timeline and list views
- Update all frontend components to use real data (album art, play counts)
- Add docker-compose external network (dockernet) support
- Add comprehensive documentation (API, DATA_MODEL, ARCHITECTURE, FRONTEND)
- Add unit tests for ingest and API endpoints
This commit is contained in:
bnair123
2025-12-30 00:15:01 +04:00
parent faee830545
commit 887e78bf47
26 changed files with 1942 additions and 662 deletions

View File

@@ -3,16 +3,30 @@ from typing import List, Dict, Any
RECCOBEATS_API_URL = "https://api.reccobeats.com/v1/audio-features"
class ReccoBeatsClient:
async def get_audio_features(self, spotify_ids: List[str]) -> List[Dict[str, Any]]:
if not spotify_ids:
return []
ids_param = ",".join(spotify_ids)
async with httpx.AsyncClient() as client:
async with httpx.AsyncClient(timeout=30.0) as client:
try:
response = await client.get(RECCOBEATS_API_URL, params={"ids": ids_param})
response = await client.get(
RECCOBEATS_API_URL, params={"ids": ids_param}
)
if response.status_code != 200:
print(f"ReccoBeats API returned status {response.status_code}")
return []
return response.json().get("content", [])
except Exception:
content = response.json().get("content", [])
for item in content:
href = item.get("href", "")
if "spotify.com/track/" in href:
spotify_id = href.split("/track/")[-1].split("?")[0]
item["spotify_id"] = spotify_id
return content
except Exception as e:
print(f"ReccoBeats API error: {e}")
return []