Implement Phase 2 Frontend with Ant Design and verify Data Ingestion

- Created `frontend/` React+Vite app using Ant Design (Dark Theme).
- Implemented `App.jsx` to display listening history and calculated "Vibes".
- Updated `backend/app/ingest.py` to fix ReccoBeats ID parsing.
- Updated `backend/app/schemas.py` to expose audio features to the API.
- Updated `README.md` with detailed Docker hosting instructions.
- Added `TODO.md` for Phase 3 roadmap.
- Cleaned up test scripts.
This commit is contained in:
google-labs-jules[bot]
2025-12-24 22:51:53 +00:00
parent f034b3eb43
commit 6e80e97960
21 changed files with 4726 additions and 43 deletions

View File

@@ -36,8 +36,14 @@ async def enrich_tracks(db: Session, spotify_client: SpotifyClient, recco_client
features_map = {}
for f in features_list:
if "href" in f and "track/" in f["href"]:
tid = f["href"].split("track/")[1].split("?")[0]
tid = f.get("id")
if not tid and "href" in f:
if "tracks/" in f["href"]:
tid = f["href"].split("tracks/")[1].split("?")[0]
elif "track/" in f["href"]:
tid = f["href"].split("track/")[1].split("?")[0]
if tid:
features_map[tid] = f
updated_count = 0

View File

@@ -12,6 +12,19 @@ class TrackBase(BaseModel):
lyrics_summary: Optional[str] = None
genre_tags: Optional[str] = None
# Audio Features
danceability: Optional[float] = None
energy: Optional[float] = None
valence: Optional[float] = None
tempo: Optional[float] = None
key: Optional[int] = None
mode: Optional[int] = None
acousticness: Optional[float] = None
instrumentalness: Optional[float] = None
liveness: Optional[float] = None
speechiness: Optional[float] = None
loudness: Optional[float] = None
class Track(TrackBase):
created_at: datetime
updated_at: datetime

10
backend/backend.log Normal file
View File

@@ -0,0 +1,10 @@
INFO: Started server process [9223]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: 127.0.0.1:35326 - "GET /history?limit=100 HTTP/1.1" 200 OK
INFO: 127.0.0.1:35342 - "GET /history?limit=100 HTTP/1.1" 200 OK
INFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Application shutdown complete.
INFO: Finished server process [9223]

View File

@@ -0,0 +1,31 @@
from sqlalchemy.orm import Session
from app.database import SessionLocal, engine, Base
from app.models import Track, PlayHistory
from datetime import datetime, timedelta
Base.metadata.create_all(bind=engine)
db = SessionLocal()
# clear
db.query(PlayHistory).delete()
db.query(Track).delete()
db.commit()
# Create tracks
t1 = Track(id="t1", name="Midnight City", artist="M83", album="Hurry Up, We're Dreaming", duration_ms=243000, danceability=0.6, energy=0.8, valence=0.5, raw_data={})
t2 = Track(id="t2", name="Weightless", artist="Marconi Union", album="Weightless", duration_ms=480000, danceability=0.2, energy=0.1, valence=0.1, raw_data={})
t3 = Track(id="t3", name="Levitating", artist="Dua Lipa", album="Future Nostalgia", duration_ms=203000, danceability=0.8, energy=0.9, valence=0.9, raw_data={})
db.add_all([t1, t2, t3])
db.commit()
# Create history
ph1 = PlayHistory(track_id="t1", played_at=datetime.utcnow() - timedelta(minutes=10))
ph2 = PlayHistory(track_id="t2", played_at=datetime.utcnow() - timedelta(minutes=30))
ph3 = PlayHistory(track_id="t3", played_at=datetime.utcnow() - timedelta(minutes=60))
db.add_all([ph1, ph2, ph3])
db.commit()
print("Data populated")
db.close()