Remove duplicate h1, fix avatar gender caching, blacklist Celeste voice
- Hide h1 (sr-only) on homepage — banner already shows show name - Promote tagline as visual lead after banner - Fix avatar gender: add .gender marker files, re-fetch on mismatch - Clear stale avatar cache so all re-fetch with correct gender - Blacklist Celeste voice from caller pool Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -147,7 +147,7 @@ ELEVENLABS_MALE_VOICES.append("SAz9YHcvj6GT2YYXdXww") # River - Neutral
|
|||||||
ELEVENLABS_FEMALE_VOICES.append("SAz9YHcvj6GT2YYXdXww") # River - Neutral
|
ELEVENLABS_FEMALE_VOICES.append("SAz9YHcvj6GT2YYXdXww") # River - Neutral
|
||||||
|
|
||||||
# Voices to never assign to callers (annoying, bad quality, etc.)
|
# Voices to never assign to callers (annoying, bad quality, etc.)
|
||||||
BLACKLISTED_VOICES = {"Evelyn", "Sebastian"} # Sebastian reserved for Silas
|
BLACKLISTED_VOICES = {"Evelyn", "Sebastian", "Celeste"} # Sebastian reserved for Silas
|
||||||
|
|
||||||
|
|
||||||
def _get_voice_pools():
|
def _get_voice_pools():
|
||||||
|
|||||||
@@ -25,14 +25,19 @@ class AvatarService:
|
|||||||
|
|
||||||
async def get_or_fetch(self, name: str, gender: str = "male") -> Path:
|
async def get_or_fetch(self, name: str, gender: str = "male") -> Path:
|
||||||
"""Get cached avatar or fetch from randomuser.me. Returns file path."""
|
"""Get cached avatar or fetch from randomuser.me. Returns file path."""
|
||||||
|
g = "female" if gender.lower().startswith("f") else "male"
|
||||||
path = AVATAR_DIR / f"{name}.jpg"
|
path = AVATAR_DIR / f"{name}.jpg"
|
||||||
|
# Check for gender mismatch marker — re-fetch if gender changed
|
||||||
|
marker = AVATAR_DIR / f"{name}.gender"
|
||||||
if path.exists():
|
if path.exists():
|
||||||
return path
|
cached_gender = marker.read_text().strip() if marker.exists() else None
|
||||||
|
if cached_gender == g:
|
||||||
|
return path
|
||||||
|
# Gender mismatch or no marker — re-fetch
|
||||||
|
path.unlink(missing_ok=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Seed includes gender so same name + different gender = different face
|
seed = f"{name.lower().replace(' ', '_')}_{g}"
|
||||||
seed = f"{name.lower().replace(' ', '_')}_{gender.lower()}"
|
|
||||||
g = "female" if gender.lower().startswith("f") else "male"
|
|
||||||
resp = await self.client.get(
|
resp = await self.client.get(
|
||||||
"https://randomuser.me/api/",
|
"https://randomuser.me/api/",
|
||||||
params={"gender": g, "seed": seed},
|
params={"gender": g, "seed": seed},
|
||||||
@@ -42,11 +47,11 @@ class AvatarService:
|
|||||||
data = resp.json()
|
data = resp.json()
|
||||||
photo_url = data["results"][0]["picture"]["large"]
|
photo_url = data["results"][0]["picture"]["large"]
|
||||||
|
|
||||||
# Download the photo
|
|
||||||
photo_resp = await self.client.get(photo_url, timeout=8.0)
|
photo_resp = await self.client.get(photo_url, timeout=8.0)
|
||||||
photo_resp.raise_for_status()
|
photo_resp.raise_for_status()
|
||||||
|
|
||||||
path.write_bytes(photo_resp.content)
|
path.write_bytes(photo_resp.content)
|
||||||
|
marker.write_text(g)
|
||||||
print(f"[Avatar] Fetched avatar for {name} ({g})")
|
print(f"[Avatar] Fetched avatar for {name} ({g})")
|
||||||
return path
|
return path
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -184,6 +184,13 @@ a:hover {
|
|||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tagline--hero {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
color: var(--text);
|
||||||
|
font-weight: 600;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
.phone {
|
.phone {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
+2
-2
@@ -119,8 +119,8 @@
|
|||||||
<section class="hero">
|
<section class="hero">
|
||||||
<div class="hero-inner hero-inner--full">
|
<div class="hero-inner hero-inner--full">
|
||||||
<div class="hero-info hero-info--centered">
|
<div class="hero-info hero-info--centered">
|
||||||
<h1>Luke at the Roost</h1>
|
<h1 class="sr-only">Luke at the Roost</h1>
|
||||||
<p class="tagline">The call-in talk show where Luke gives life advice to biologically questionable organisms.</p>
|
<p class="tagline tagline--hero">The call-in talk show where Luke gives life advice to biologically questionable organisms.</p>
|
||||||
<div class="phone" id="phone-section">
|
<div class="phone" id="phone-section">
|
||||||
<div class="on-air-badge" id="on-air-badge">
|
<div class="on-air-badge" id="on-air-badge">
|
||||||
<span class="on-air-dot"></span>
|
<span class="on-air-dot"></span>
|
||||||
|
|||||||
Reference in New Issue
Block a user