""" Current Occasions – AI-driven trending context for ad generation. Uses the LLM to infer relevant occasions from the current date (holidays, cultural moments, seasonal themes). No fallbacks; results are cached per day. """ from datetime import date from typing import List, Dict, Any # Daily cache: date.isoformat() -> list of occasion dicts (title, summary, category, relevance_window) _OCCASIONS_CACHE: Dict[str, List[Dict]] = {} def _normalize_ai_occasions(raw: Any) -> List[Dict]: """Parse and normalize LLM output to our occasion shape.""" if not raw: return [] items = raw.get("occasions") if isinstance(raw, dict) else raw if not isinstance(items, list): return [] normalized: List[Dict] = [] for o in items: if not isinstance(o, dict): continue title = o.get("title") or o.get("name") summary = o.get("summary") or o.get("description") if not title or not summary: continue normalized.append({ "title": str(title).strip(), "summary": str(summary).strip(), "category": str(o.get("category", "Occasion")).strip() or "Occasion", "relevance_window": str(o.get("relevance_window", "week")).strip() or "week", }) return normalized async def get_current_occasions(today: date | None = None) -> List[Dict]: """ Return current occasions for ad trending context. Results are cached per day. Returns: List of dicts: title, summary, category, relevance_window (empty if AI fails). """ if today is None: today = date.today() cache_key = today.isoformat() if cache_key in _OCCASIONS_CACHE: return _OCCASIONS_CACHE[cache_key] try: from services.llm import llm_service except Exception: _OCCASIONS_CACHE[cache_key] = [] return [] system_prompt = """You are an expert in global holidays, cultural moments, and seasonal themes used for advertising and marketing. Given a date, list 4–6 occasions that are relevant RIGHT NOW or in the next few days for that date. Include: - Official holidays (US, India, global where relevant) - Cultural/seasonal moments (e.g. Valentine's Week with daily themes like Rose Day, Teddy Day; Black Friday; back-to-school) - Awareness days/weeks/months (e.g. Black History Month, Earth Day) - Shopping or behavior moments (Singles' Day, Prime Day, etc.) Be specific to the exact date when it matters (e.g. "Teddy Day" on Feb 10, "Valentine's Day" on Feb 14). Respond with valid JSON only, in this exact shape (no extra fields): {"occasions": [{"title": "...", "summary": "One sentence on why it matters for ads.", "category": "Occasion", "relevance_window": "day"|"week"|"month"}]} Use relevance_window: "day" for single-day events, "week" for a week-long moment, "month" for month-long themes.""" user_prompt = f"""Today's date is {today.isoformat()} ({today.strftime('%A, %B %d, %Y')}). List 4–6 current or upcoming occasions that are relevant for advertising and marketing on or around this date. Consider global and regional relevance. Output JSON only.""" try: response = await llm_service.generate_json( prompt=user_prompt, system_prompt=system_prompt, temperature=0.3, ) occasions = _normalize_ai_occasions(response) except Exception as e: print(f"⚠️ AI occasions failed: {e}") occasions = [] _OCCASIONS_CACHE[cache_key] = occasions return occasions def clear_occasions_cache() -> None: """Clear the occasions cache (e.g. for tests).""" global _OCCASIONS_CACHE _OCCASIONS_CACHE = {}