pounce/backend/app/services/hunt/brandables.py
Yves Gugger 3485668b5e
Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
feat: add Alpha Terminal HUNT/CFO modules and Analyze framework
Adds HUNT (Sniper/Trend/Forge), CFO dashboard (burn rate + kill list), and a plugin-based Analyze side panel with caching and SSRF hardening.
2025-12-15 16:15:58 +01:00

77 lines
2.0 KiB
Python

"""
Brandable generator (no external APIs).
Generates pronounceable strings and checks availability via internal DomainChecker.
"""
from __future__ import annotations
import asyncio
import secrets
from dataclasses import dataclass
from app.services.domain_checker import domain_checker
VOWELS = "aeiou"
CONSONANTS = "bcdfghjklmnpqrstvwxz"
def _rand_choice(alphabet: str) -> str:
return alphabet[secrets.randbelow(len(alphabet))]
def generate_cvcvc() -> str:
return (
_rand_choice(CONSONANTS)
+ _rand_choice(VOWELS)
+ _rand_choice(CONSONANTS)
+ _rand_choice(VOWELS)
+ _rand_choice(CONSONANTS)
)
def generate_cvccv() -> str:
return (
_rand_choice(CONSONANTS)
+ _rand_choice(VOWELS)
+ _rand_choice(CONSONANTS)
+ _rand_choice(CONSONANTS)
+ _rand_choice(VOWELS)
)
HUMAN_SUFFIXES = ["ly", "ri", "ro", "na", "no", "mi", "li", "sa", "ta", "ya"]
def generate_human() -> str:
# two syllable-ish: CV + CV + suffix
base = _rand_choice(CONSONANTS) + _rand_choice(VOWELS) + _rand_choice(CONSONANTS) + _rand_choice(VOWELS)
return base + HUMAN_SUFFIXES[secrets.randbelow(len(HUMAN_SUFFIXES))]
@dataclass(frozen=True)
class AvailabilityResult:
domain: str
is_available: bool | None
status: str
async def check_domains(domains: list[str], *, concurrency: int = 25) -> list[AvailabilityResult]:
sem = asyncio.Semaphore(concurrency)
async def _one(d: str) -> AvailabilityResult:
async with sem:
try:
res = await domain_checker.check_domain(d, quick=True)
return AvailabilityResult(
domain=d,
is_available=bool(res.is_available),
status="available" if res.is_available else "taken",
)
except Exception:
return AvailabilityResult(domain=d, is_available=None, status="unknown")
return list(await asyncio.gather(*[_one(d) for d in domains]))