from __future__ import annotations import html from collections import Counter from backend.models import SpaceItem from backend.passport import PassportState, get_badges, get_next_track, get_rank from backend.storage import get_recent_feedback from backend.tracks import TRACK_NAMES, get_track_metadata ABOUT_TEXT = """ # About Build Small Quest Finder This app is a community discovery layer for the Build Small Hackathon Spaces. It does not own or modify the original Spaces. ## How recommendations work - The app scores your query against each Space's title, summary, tags, track, difficulty, and README text when available. - The LLM sharpens the query intent and helps explain why a Space is a confident match. - Results are ordered by a lightweight relevance score. ## How quests work - Each Space gets a short, track-based mission. - You can mark quests complete locally during your session. - Shared comments are saved in the SQLite database so everyone can read them. - Your progress lives in `gr.State`, not a database. ## How data is fetched - The app first tries live Hugging Face Hub fetching. - If that is unavailable, it falls back to `data/spaces_cache.json`. - If no cache exists, it uses `data/sample_spaces.json`. ## What builders get - A more fun way to discover hackathon demos - Quest cards that explain why a Space matches - Comment modals that let you read community notes - A simple passport with badges and progress - Shared reflections saved for the community """ def _escape(text: str) -> str: return html.escape(text or "") def render_passport(state: dict, spaces: list[SpaceItem]) -> str: passport = PassportState.from_dict(state) space_lookup = {space.repo_id: space for space in spaces} completed_spaces = [space_lookup[repo_id] for repo_id in passport.completed_repo_ids if repo_id in space_lookup] track_counts = Counter(space.track or "Unassigned" for space in completed_spaces) badges = get_badges(state, spaces) rank = get_rank(len(passport.completed_repo_ids)) next_track = get_next_track(state, spaces) explored = len(passport.tracks_explored) total_tracks = len(TRACK_NAMES) completed_list = "".join( f"