| from __future__ import annotations |
|
|
| from dataclasses import asdict, dataclass, field |
| from typing import List |
|
|
|
|
| @dataclass |
| class SpaceItem: |
| repo_id: str |
| title: str |
| summary: str |
| url: str |
| zone: str |
| track: str = "" |
| tags: List[str] = field(default_factory=list) |
| difficulty: str = "casual" |
| quest: str = "" |
| likes: int = 0 |
| sdk: str = "unknown" |
| status: str = "unknown" |
| last_modified: str = "" |
| emoji: str = "π" |
| readme_text: str = "" |
|
|
| @classmethod |
| def from_dict(cls, data: dict) -> "SpaceItem": |
| tags = data.get("tags", []) or [] |
| if isinstance(tags, str): |
| tags = [tags] |
| return cls( |
| repo_id=str(data.get("repo_id", "")), |
| title=str(data.get("title", "")), |
| summary=str(data.get("summary", "")), |
| url=str(data.get("url", "")), |
| zone=str(data.get("zone", "Experiment Lab")), |
| track=str(data.get("track", "")), |
| tags=[str(tag) for tag in tags if str(tag).strip()], |
| difficulty=str(data.get("difficulty", "casual")), |
| quest=str(data.get("quest", "")), |
| likes=int(data.get("likes", 0) or 0), |
| sdk=str(data.get("sdk", "unknown")), |
| status=str(data.get("status", "unknown")), |
| last_modified=str(data.get("last_modified", "")), |
| emoji=str(data.get("emoji", "π")), |
| readme_text=str(data.get("readme_text", "")), |
| ) |
|
|
| def to_dict(self) -> dict: |
| return asdict(self) |
|
|
|
|
| @dataclass |
| class RecommendationResult: |
| space: SpaceItem |
| score: float |
| reason: str |
| summary: str = "" |
|
|
|
|
| @dataclass |
| class PassportState: |
| completed_repo_ids: list[str] = field(default_factory=list) |
| favorite_repo_ids: list[str] = field(default_factory=list) |
| tracks_explored: list[str] = field(default_factory=list) |
| zones_explored: list[str] = field(default_factory=list) |
|
|
| @classmethod |
| def from_dict(cls, data: dict | None) -> "PassportState": |
| data = data or {} |
| completed_repo_ids = data.get("completed_repo_ids", []) or [] |
| favorite_repo_ids = data.get("favorite_repo_ids", []) or [] |
| tracks_explored = data.get("tracks_explored", []) or [] |
| zones_explored = data.get("zones_explored", []) or [] |
| if isinstance(completed_repo_ids, str): |
| completed_repo_ids = [completed_repo_ids] |
| if isinstance(favorite_repo_ids, str): |
| favorite_repo_ids = [favorite_repo_ids] |
| if isinstance(tracks_explored, str): |
| tracks_explored = [tracks_explored] |
| if isinstance(zones_explored, str): |
| zones_explored = [zones_explored] |
| return cls( |
| completed_repo_ids=[str(item) for item in completed_repo_ids if str(item).strip()], |
| favorite_repo_ids=[str(item) for item in favorite_repo_ids if str(item).strip()], |
| tracks_explored=[str(item) for item in tracks_explored if str(item).strip()], |
| zones_explored=[str(item) for item in zones_explored if str(item).strip()], |
| ) |
|
|
| def to_dict(self) -> dict: |
| return asdict(self) |
|
|