32 lines
977 B
Python
32 lines
977 B
Python
"""Port definitions — every adapter implements one of these protocols."""
|
|
|
|
from collections.abc import AsyncIterator
|
|
from typing import Protocol
|
|
|
|
from app.domain.models import Recommendation, TasteProfile, Track
|
|
|
|
|
|
class MusicCatalog(Protocol):
|
|
"""Resolve, verify, and personalise against a music catalog."""
|
|
|
|
async def search_track(self, title: str, artist: str) -> Track | None: ...
|
|
|
|
async def fetch_taste_profile(self) -> TasteProfile: ...
|
|
|
|
|
|
class Recommender(Protocol):
|
|
"""The two LLM calls: intent + candidates, then streamed rerank."""
|
|
|
|
async def propose_candidates(
|
|
self, query: str, profile_summary: str
|
|
) -> list[tuple[str, str]]: ...
|
|
|
|
def rerank(
|
|
self, query: str, profile_summary: str, grounded: list[Track]
|
|
) -> AsyncIterator[Recommendation]: ...
|
|
|
|
|
|
class PlaylistWriter(Protocol):
|
|
"""Persist a recommendation set as a playlist."""
|
|
|
|
async def create_playlist(self, name: str, tracks: list[Track]) -> str: ...
|