Spaces:
Running on Zero
Running on Zero
| from __future__ import annotations | |
| from dataclasses import dataclass | |
| from hackathon_advisor.data import ProjectIndex, SearchHit, tokenize | |
| class ScoreCard: | |
| originality: int | |
| delight: int | |
| ai_necessity: int | |
| feasibility: int | |
| goal_fit: int | |
| verdict: str | |
| echoes: tuple[SearchHit, ...] | |
| def overall(self) -> float: | |
| return round( | |
| ( | |
| self.originality * 0.30 | |
| + self.delight * 0.20 | |
| + self.ai_necessity * 0.20 | |
| + self.feasibility * 0.15 | |
| + self.goal_fit * 0.15 | |
| ), | |
| 1, | |
| ) | |
| def to_dict(self) -> dict: | |
| return { | |
| "originality": self.originality, | |
| "delight": self.delight, | |
| "ai_necessity": self.ai_necessity, | |
| "feasibility": self.feasibility, | |
| "goal_fit": self.goal_fit, | |
| "overall": self.overall, | |
| "verdict": self.verdict, | |
| "echoes": [ | |
| { | |
| "score": round(hit.score, 3), | |
| "page_number": hit.page_number, | |
| "matched_terms": list(hit.matched_terms), | |
| "project": hit.project.to_public_dict(), | |
| } | |
| for hit in self.echoes | |
| ], | |
| } | |
| def score_idea(index: ProjectIndex, title: str, pitch: str, goals: list[str] | None = None) -> ScoreCard: | |
| text = f"{title} {pitch}".strip() | |
| hits = index.search(text, limit=4) | |
| top_overlap = hits[0].score if hits else 0.0 | |
| tokens = set(tokenize(text)) | |
| goals = goals or [] | |
| originality = clamp_score(10 - round(top_overlap * 18)) | |
| delight = clamp_score(4 + _keyword_count(tokens, {"story", "visual", "game", "ritual", "share", "voice"}) * 2) | |
| ai_necessity = clamp_score( | |
| 3 | |
| + _keyword_count(tokens, {"agent", "model", "embed", "search", "personal", "speech", "local"}) * 2 | |
| ) | |
| complexity_penalty = _keyword_count(tokens, {"realtime", "video", "multiplayer", "payments", "social"}) | |
| feasibility = clamp_score(8 - complexity_penalty) | |
| goal_fit = clamp_score( | |
| 4 | |
| + _keyword_count(tokens, {"local", "offline", "small", "llama", "fine", "trace", "gradio"}) * 2 | |
| + min(len(goals), 3) | |
| ) | |
| verdict = "UNWRITTEN" if top_overlap < 0.16 else f"ECHO x{sum(1 for hit in hits if hit.score >= 0.12)}" | |
| return ScoreCard( | |
| originality=originality, | |
| delight=delight, | |
| ai_necessity=ai_necessity, | |
| feasibility=feasibility, | |
| goal_fit=goal_fit, | |
| verdict=verdict, | |
| echoes=tuple(hits), | |
| ) | |
| def clamp_score(value: int) -> int: | |
| return max(1, min(10, value)) | |
| def _keyword_count(tokens: set[str], keywords: set[str]) -> int: | |
| return sum(1 for keyword in keywords if any(token.startswith(keyword) for token in tokens)) | |