Add playlist export and SEO meta tags

Add text/CSV export endpoints for playlists and saved recommendations.
Add export buttons to PlaylistDetail and Recommendations pages.
Add Open Graph and Twitter meta tags to index.html for better SEO.
This commit is contained in:
root
2026-03-31 20:49:07 -05:00
parent 957a66bbd0
commit 5215e8c792
6 changed files with 138 additions and 6 deletions

View File

@@ -1,9 +1,13 @@
import hashlib
import json
import logging
from urllib.parse import quote_plus
import anthropic
api_logger = logging.getLogger("app")
from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import PlainTextResponse
from pydantic import BaseModel
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
@@ -77,6 +81,24 @@ async def history(
return result.scalars().all()
@router.get("/saved/export")
async def export_saved(user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
result = await db.execute(
select(Recommendation).where(Recommendation.user_id == user.id, Recommendation.saved == True)
.order_by(Recommendation.created_at.desc())
)
recs = result.scalars().all()
lines = ["My Saved Discoveries - Vynl", "=" * 30, ""]
for i, r in enumerate(recs, 1):
lines.append(f"{i}. {r.artist} - {r.title}")
if r.youtube_url:
lines.append(f" {r.youtube_url}")
lines.append(f" {r.reason}")
lines.append("")
return PlainTextResponse("\n".join(lines), media_type="text/plain",
headers={"Content-Disposition": 'attachment; filename="vynl-discoveries.txt"'})
@router.get("/saved", response_model=list[RecommendationItem])
async def saved(
user: User = Depends(get_current_user),
@@ -132,6 +154,12 @@ Return ONLY the JSON object."""
messages=[{"role": "user", "content": prompt}],
)
# Track API cost (Haiku: $0.80/M input, $4/M output)
input_tokens = message.usage.input_tokens
output_tokens = message.usage.output_tokens
cost = (input_tokens * 0.80 / 1_000_000) + (output_tokens * 4 / 1_000_000)
api_logger.info(f"API_COST|model=claude-haiku|input={input_tokens}|output={output_tokens}|cost=${cost:.4f}|user={user.id}|endpoint=analyze")
response_text = message.content[0].text.strip()
if response_text.startswith("```"):
response_text = response_text.split("\n", 1)[1]