pounce/backend/app/services/pounce_score.py

117 lines
2.6 KiB
Python

"""
Pounce Score calculation.
Used across:
- Market feed scoring
- Auction scraper (persist score for DB-level sorting)
- Listings (optional)
"""
from __future__ import annotations
from typing import Optional
def calculate_pounce_score_v2(
domain: str,
tld: Optional[str] = None,
*,
num_bids: int = 0,
age_years: int = 0,
is_pounce: bool = False,
) -> int:
"""
Pounce Score v2.0 - Enhanced scoring algorithm.
Factors:
- Length (shorter = more valuable)
- TLD premium
- Market activity (bids)
- Age bonus
- Pounce Direct bonus (verified listings)
- Penalties (hyphens, numbers, etc.)
"""
score = 50 # Baseline
domain = (domain or "").strip().lower()
if not domain:
return score
name = domain.rsplit(".", 1)[0] if "." in domain else domain
tld_clean = (tld or (domain.rsplit(".", 1)[-1] if "." in domain else "")).strip().lower().lstrip(".")
# A) LENGTH BONUS (exponential for short domains)
length_scores = {1: 50, 2: 45, 3: 40, 4: 30, 5: 20, 6: 15, 7: 10}
score += length_scores.get(len(name), max(0, 15 - len(name)))
# B) TLD PREMIUM
tld_scores = {
"com": 20,
"ai": 25,
"io": 18,
"co": 12,
"ch": 15,
"de": 10,
"net": 8,
"org": 8,
"app": 10,
"dev": 10,
"xyz": 5,
}
score += tld_scores.get(tld_clean, 0)
# C) MARKET ACTIVITY (bids = demand signal)
try:
bids = int(num_bids or 0)
except Exception:
bids = 0
if bids >= 20:
score += 15
elif bids >= 10:
score += 10
elif bids >= 5:
score += 5
elif bids >= 2:
score += 2
# D) AGE BONUS (established domains)
try:
age = int(age_years or 0)
except Exception:
age = 0
if age > 15:
score += 10
elif age > 10:
score += 7
elif age > 5:
score += 3
# E) POUNCE DIRECT BONUS (verified = trustworthy)
if is_pounce:
score += 10
# F) PENALTIES
if "-" in name:
score -= 25
if any(c.isdigit() for c in name) and len(name) > 3:
score -= 20
if len(name) > 15:
score -= 15
# G) CONSONANT CHECK (no gibberish like "xkqzfgh")
consonants = "bcdfghjklmnpqrstvwxyz"
max_streak = 0
current_streak = 0
for c in name.lower():
if c in consonants:
current_streak += 1
max_streak = max(max_streak, current_streak)
else:
current_streak = 0
if max_streak > 4:
score -= 15
return max(0, min(100, score))