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
180 lines
5.9 KiB
Python
180 lines
5.9 KiB
Python
"""
|
|
LLM-powered naming suggestions for Trends and Forge tabs.
|
|
Uses simple prompts for focused tasks - no complex agent loop.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import re
|
|
from typing import Optional
|
|
|
|
from app.config import get_settings
|
|
from app.services.llm_gateway import chat_completions
|
|
|
|
settings = get_settings()
|
|
|
|
|
|
async def expand_trend_keywords(trend: str, geo: str = "US") -> list[str]:
|
|
"""
|
|
Given a trending topic, generate related domain-friendly keywords.
|
|
Returns a list of 5-10 short, brandable keywords.
|
|
"""
|
|
prompt = f"""You are a domain naming expert. Given the trending topic "{trend}" (trending in {geo}),
|
|
suggest 8-10 short, memorable keywords that would make good domain names.
|
|
|
|
Rules:
|
|
- Each keyword should be 4-10 characters
|
|
- No spaces, hyphens, or special characters
|
|
- Mix of: related words, abbreviations, creative variations
|
|
- Think like a domain investor looking for valuable names
|
|
|
|
Return ONLY a JSON array of lowercase strings, nothing else.
|
|
Example: ["swiftie", "erastour", "taylormerch", "tswift"]"""
|
|
|
|
try:
|
|
res = await chat_completions({
|
|
"model": settings.llm_default_model,
|
|
"messages": [{"role": "user", "content": prompt}],
|
|
"temperature": 0.8,
|
|
"stream": False,
|
|
})
|
|
content = res.get("choices", [{}])[0].get("message", {}).get("content", "")
|
|
|
|
# Extract JSON array from response
|
|
match = re.search(r'\[.*?\]', content, re.DOTALL)
|
|
if match:
|
|
keywords = json.loads(match.group(0))
|
|
# Filter and clean
|
|
return [
|
|
kw.lower().strip()[:15]
|
|
for kw in keywords
|
|
if isinstance(kw, str) and 3 <= len(kw.strip()) <= 15 and kw.isalnum()
|
|
][:10]
|
|
except Exception as e:
|
|
print(f"LLM keyword expansion failed: {e}")
|
|
|
|
return []
|
|
|
|
|
|
async def analyze_trend(trend: str, geo: str = "US") -> str:
|
|
"""
|
|
Provide a brief analysis of why a trend is relevant for domain investors.
|
|
Returns 2-3 sentences max.
|
|
"""
|
|
prompt = f"""You are a domain investing analyst. The topic "{trend}" is currently trending in {geo}.
|
|
|
|
In 2-3 short sentences, explain:
|
|
1. Why this is trending (if obvious)
|
|
2. What domain opportunity this presents
|
|
|
|
Be concise and actionable. No fluff."""
|
|
|
|
try:
|
|
res = await chat_completions({
|
|
"model": settings.llm_default_model,
|
|
"messages": [{"role": "user", "content": prompt}],
|
|
"temperature": 0.5,
|
|
"stream": False,
|
|
})
|
|
content = res.get("choices", [{}])[0].get("message", {}).get("content", "")
|
|
# Clean up and limit length
|
|
content = content.strip()[:500]
|
|
return content
|
|
except Exception as e:
|
|
print(f"LLM trend analysis failed: {e}")
|
|
|
|
return ""
|
|
|
|
|
|
async def generate_brandable_names(
|
|
concept: str,
|
|
style: Optional[str] = None,
|
|
count: int = 15
|
|
) -> list[str]:
|
|
"""
|
|
Generate brandable domain names based on a concept description.
|
|
|
|
Args:
|
|
concept: Description like "AI startup for legal documents"
|
|
style: Optional style hint like "professional", "playful", "tech"
|
|
count: Number of names to generate
|
|
|
|
Returns list of brandable name suggestions (without TLD).
|
|
"""
|
|
style_hint = f" The style should be {style}." if style else ""
|
|
|
|
prompt = f"""You are an expert brand naming consultant. Generate {count} unique, brandable domain names for: "{concept}"{style_hint}
|
|
|
|
Rules:
|
|
- Names must be 4-8 characters (shorter is better)
|
|
- Easy to spell and pronounce
|
|
- Memorable and unique
|
|
- No dictionary words (invented names only)
|
|
- Mix of patterns: CVCVC (Zalor), CVCCV (Bento), short words (Lyft)
|
|
|
|
Return ONLY a JSON array of lowercase strings, nothing else.
|
|
Example: ["zenix", "klaro", "voxly", "nimbl", "brivv"]"""
|
|
|
|
try:
|
|
res = await chat_completions({
|
|
"model": settings.llm_default_model,
|
|
"messages": [{"role": "user", "content": prompt}],
|
|
"temperature": 0.9, # Higher creativity
|
|
"stream": False,
|
|
})
|
|
content = res.get("choices", [{}])[0].get("message", {}).get("content", "")
|
|
|
|
# Extract JSON array
|
|
match = re.search(r'\[.*?\]', content, re.DOTALL)
|
|
if match:
|
|
names = json.loads(match.group(0))
|
|
# Filter and clean
|
|
return [
|
|
name.lower().strip()
|
|
for name in names
|
|
if isinstance(name, str) and 3 <= len(name.strip()) <= 12 and name.isalnum()
|
|
][:count]
|
|
except Exception as e:
|
|
print(f"LLM brandable generation failed: {e}")
|
|
|
|
return []
|
|
|
|
|
|
async def generate_similar_names(brand: str, count: int = 12) -> list[str]:
|
|
"""
|
|
Generate names similar to an existing brand.
|
|
Useful for finding alternatives or inspired names.
|
|
"""
|
|
prompt = f"""You are a brand naming expert. Generate {count} new brandable names INSPIRED BY (but not copying) "{brand}".
|
|
|
|
The names should:
|
|
- Have similar length and rhythm to "{brand}"
|
|
- Feel like they belong in the same industry
|
|
- Be completely original (not existing brands)
|
|
- Be 4-8 characters, easy to spell
|
|
|
|
Return ONLY a JSON array of lowercase strings, nothing else."""
|
|
|
|
try:
|
|
res = await chat_completions({
|
|
"model": settings.llm_default_model,
|
|
"messages": [{"role": "user", "content": prompt}],
|
|
"temperature": 0.85,
|
|
"stream": False,
|
|
})
|
|
content = res.get("choices", [{}])[0].get("message", {}).get("content", "")
|
|
|
|
match = re.search(r'\[.*?\]', content, re.DOTALL)
|
|
if match:
|
|
names = json.loads(match.group(0))
|
|
return [
|
|
name.lower().strip()
|
|
for name in names
|
|
if isinstance(name, str) and 3 <= len(name.strip()) <= 12 and name.isalnum()
|
|
][:count]
|
|
except Exception as e:
|
|
print(f"LLM similar names failed: {e}")
|
|
|
|
return []
|
|
|