import os import json import google.generativeai as genai from typing import Dict, Any class NarrativeService: def __init__(self, model_name: str = "gemini-2.5-flash"): self.api_key = os.getenv("GEMINI_API_KEY") if not self.api_key: print("WARNING: GEMINI_API_KEY not found. LLM features will fail.") else: genai.configure(api_key=self.api_key) self.model_name = model_name def generate_narrative(self, stats_json: Dict[str, Any]) -> Dict[str, str]: if not self.api_key: return {"error": "Missing API Key"} prompt = f""" You are a witty, insightful, and slightly snarky music critic analyzing a user's listening history. Below is a JSON summary of their listening data. Your goal is to generate a report that feels like a 'Spotify Wrapped' but deeper and more honest. Please output your response in strict JSON format with the following keys: 1. "vibe_check": (String) 2-3 paragraphs describing their overall listening personality. 2. "patterns": (List of Strings) 3-5 specific observations based on the data (e.g., "You listen to sad music on Tuesdays", "Your Whiplash Score is high"). 3. "persona": (String) A creative label for the user (e.g., "The Genre Chameleon", "Nostalgic Dad-Rocker", "Algorithm Victim"). 4. "roast": (String) A playful, harmlessly mean roast about their taste (1-2 sentences). 5. "era_insight": (String) A specific comment on their 'Musical Age' and 'Nostalgia Gap'. GUIDELINES: - **Use the Metrics:** Do not just say "You like pop." Say "Your Mainstream Score of 85% suggests you live on the Top 40." - **Whiplash Score:** If 'whiplash' > 20, comment on their chaotic transitions. - **Hipster Score:** If 'hipster_score' > 50, call them pretentious; if < 10, call them basic. - **Comparison:** Use the 'comparison' block to mention if they are listening more/less or if their mood (valence/energy) has shifted. - **Tone:** Conversational, fun, slightly judgmental but good-natured. DATA: {json.dumps(stats_json, indent=2)} OUTPUT (JSON): """ try: model = genai.GenerativeModel(self.model_name) response = model.generate_content(prompt) # Clean up response to ensure valid JSON text = response.text.strip() if text.startswith("```json"): text = text.replace("```json", "").replace("```", "") elif text.startswith("```"): text = text.replace("```", "") return json.loads(text) except Exception as e: return {"error": str(e), "raw_response": "Error generating narrative."}